Skip to content

Steps

steps

Classes used for steps in routers.

Left dataclass

Bases: Step

Let the router go left.

If a size is given, the router will continues that amount (including the added bend). If include_bend is true, the router will stop before the next bend needs to bed placed at size's point.

Source code in kfactory/routing/steps.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@dataclass
class Left(Step):
    """Let the router go left.

    If a size is given, the router will continues that amount
    (including the added bend).
    If include_bend is true, the router will stop before the next bend needs to bed
    placed at size's point.
    """

    dist: int | None = None

    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Make the router turn left and go straight if necessary."""
        ib = include_bend if self.include_bend is None else self.include_bend
        router.left()
        if self.dist:
            if ib:
                if (
                    self.dist is not None
                    and self.dist < 2 * router.router.bend90_radius
                ):
                    bend_radius = router.router.bend90_radius
                    raise ValueError(
                        "If the next bend should be avoided the step needs to be bigger"
                        f" than {2 * bend_radius=}"
                    )
                router.straight_nobend(self.dist)
            else:
                if self.dist < router.router.bend90_radius:
                    bend_radius = router.router.bend90_radius
                    raise ValueError(f"The step needs to be bigger than {bend_radius=}")
                router.straight(self.dist)

execute

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Make the router turn left and go straight if necessary.

Source code in kfactory/routing/steps.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Make the router turn left and go straight if necessary."""
    ib = include_bend if self.include_bend is None else self.include_bend
    router.left()
    if self.dist:
        if ib:
            if (
                self.dist is not None
                and self.dist < 2 * router.router.bend90_radius
            ):
                bend_radius = router.router.bend90_radius
                raise ValueError(
                    "If the next bend should be avoided the step needs to be bigger"
                    f" than {2 * bend_radius=}"
                )
            router.straight_nobend(self.dist)
        else:
            if self.dist < router.router.bend90_radius:
                bend_radius = router.router.bend90_radius
                raise ValueError(f"The step needs to be bigger than {bend_radius=}")
            router.straight(self.dist)

Right dataclass

Bases: Step

Let the router go right.

If a size is given, the router will continues that amount (including the added bend). If include_bend is true, the router will stop before the next bend needs to bed placed at size's point.

Source code in kfactory/routing/steps.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
@dataclass
class Right(Step):
    """Let the router go right.

    If a size is given, the router will continues that amount
    (including the added bend).
    If include_bend is true, the router will stop before the next bend needs to bed
    placed at size's point.
    """

    dist: int | None = None

    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Adds the bend and potential straight after."""
        ib = include_bend if self.include_bend is None else self.include_bend
        router.right()
        if self.dist:
            if ib:
                if self.dist < 2 * router.router.bend90_radius:
                    bend_radius = router.router.bend90_radius
                    raise ValueError(
                        "If the next bend should be avoided the step needs to be bigger"
                        f" than {2 * bend_radius=}"
                    )
                router.straight_nobend(self.dist)
            else:
                if self.dist < router.router.bend90_radius:
                    bend_radius = router.router.bend90_radius
                    raise ValueError(f"The step needs to be bigger than {bend_radius=}")
                router.straight(self.dist)

execute

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Adds the bend and potential straight after.

Source code in kfactory/routing/steps.py
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Adds the bend and potential straight after."""
    ib = include_bend if self.include_bend is None else self.include_bend
    router.right()
    if self.dist:
        if ib:
            if self.dist < 2 * router.router.bend90_radius:
                bend_radius = router.router.bend90_radius
                raise ValueError(
                    "If the next bend should be avoided the step needs to be bigger"
                    f" than {2 * bend_radius=}"
                )
            router.straight_nobend(self.dist)
        else:
            if self.dist < router.router.bend90_radius:
                bend_radius = router.router.bend90_radius
                raise ValueError(f"The step needs to be bigger than {bend_radius=}")
            router.straight(self.dist)

Step dataclass

Bases: ABC

Abstract base for a routing step.

Source code in kfactory/routing/steps.py
17
18
19
20
21
22
23
24
25
26
27
28
29
@dataclass
class Step(ABC):
    """Abstract base for a routing step."""

    @abstractmethod
    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Executes the step."""
        ...

    @property
    def include_bend(self) -> bool | None:
        """Whether the execute should leave space at the end of the step for a bend."""
        return None

include_bend property

include_bend: bool | None

Whether the execute should leave space at the end of the step for a bend.

execute abstractmethod

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Executes the step.

Source code in kfactory/routing/steps.py
21
22
23
24
@abstractmethod
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Executes the step."""
    ...

Steps

Bases: RootModel[list[Any]]

Collection of steps. Runs the execution on them.

Source code in kfactory/routing/steps.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
class Steps(RootModel[list[Any]]):
    """Collection of steps. Runs the execution on them."""

    root: list[Any]

    model_config = ConfigDict(arbitrary_types_allowed=True)

    @model_validator(mode="after")
    def _check_steps(self) -> Self:
        for step in self.root:
            if not isinstance(step, Step):
                raise TypeError(
                    "All Steps must implement an "
                    "'execute(self, router: ManhattanRouterSide, include_bend: bool)"
                )
        return self

    def execute(self, router: ManhattanRouterSide) -> None:
        """Run all the steps on the given router."""
        i = 0
        try:
            if self.root:
                for step in self.root[:-1]:
                    step.execute(router, True)
                i += 1
                step = self.root[-1]
                step.execute(router, False)
        except Exception as e:
            raise ValueError(f"Error in step {i}, {step=}. Error: {e!s}") from e

execute

execute(router: ManhattanRouterSide) -> None

Run all the steps on the given router.

Source code in kfactory/routing/steps.py
279
280
281
282
283
284
285
286
287
288
289
290
def execute(self, router: ManhattanRouterSide) -> None:
    """Run all the steps on the given router."""
    i = 0
    try:
        if self.root:
            for step in self.root[:-1]:
                step.execute(router, True)
            i += 1
            step = self.root[-1]
            step.execute(router, False)
    except Exception as e:
        raise ValueError(f"Error in step {i}, {step=}. Error: {e!s}") from e

Straight dataclass

Bases: Step

Adds a straight section to the router.

Source code in kfactory/routing/steps.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
@dataclass
class Straight(Step):
    """Adds a straight section to the router."""

    dist: int | None = None

    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Adds a straight section to the router."""
        ib = include_bend if self.include_bend is None else self.include_bend
        if self.dist:
            if ib:
                router.straight_nobend(self.dist)
            else:
                router.straight(self.dist)

execute

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Adds a straight section to the router.

Source code in kfactory/routing/steps.py
105
106
107
108
109
110
111
112
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Adds a straight section to the router."""
    ib = include_bend if self.include_bend is None else self.include_bend
    if self.dist:
        if ib:
            router.straight_nobend(self.dist)
        else:
            router.straight(self.dist)

X dataclass

Bases: Step

Go to an absolute X coordinate.

Source code in kfactory/routing/steps.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
@dataclass
class X(Step):
    """Go to an absolute X coordinate."""

    x: int

    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Adds a straight section to the router."""
        ib = include_bend if self.include_bend is None else self.include_bend
        if router.t.angle % 2:
            raise ValueError(
                "Cannot go to position {self.x=}, because the router is currently "
                "going in the y direction with position "
                f"{(router.t.disp.x, router.t.disp.y)}"
            )
        if self.x:
            if ib:
                router.straight_nobend(self.x - router.t.disp.x)
            else:
                router.straight(self.x - router.t.disp.x)

execute

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Adds a straight section to the router.

Source code in kfactory/routing/steps.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Adds a straight section to the router."""
    ib = include_bend if self.include_bend is None else self.include_bend
    if router.t.angle % 2:
        raise ValueError(
            "Cannot go to position {self.x=}, because the router is currently "
            "going in the y direction with position "
            f"{(router.t.disp.x, router.t.disp.y)}"
        )
    if self.x:
        if ib:
            router.straight_nobend(self.x - router.t.disp.x)
        else:
            router.straight(self.x - router.t.disp.x)

XY dataclass

Bases: Step

Go to an absolute XY coordinate.

Source code in kfactory/routing/steps.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
@dataclass
class XY(Step):
    """Go to an absolute XY coordinate."""

    x: int
    y: int

    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Executes the step on a router."""
        ib = include_bend if self.include_bend is None else self.include_bend
        dx = self.x - router.t.disp.x
        dy = self.y - router.t.disp.y
        a = router.t.angle
        match a:
            case 0 | 2 if self.y == router.t.disp.x:
                sign = -1 if a == ANGLE_180 else 1
                if sign * dx < 0:
                    raise ValueError(
                        "XY step cannot go back. It is current pointing at 0"
                        " degrees.\n"
                        f"Current position: {router.t.disp!r}.\n"
                        f"Target Position ({self.x},{self.y})"
                    )
                    if ib:
                        router.straight_nobend(abs(dx))
                    else:
                        router.straight(abs(dx))
                if sign * dx < router.t.disp.x + router.router.bend90_radius:
                    raise ValueError("XY step cannot go back")
                router.straight_nobend(abs(dx))
                if self.y > router.t.disp.y:
                    if a == 0:
                        router.left()
                    else:
                        router.right()
                dy = self.y - router.t.disp.y
                if ib:
                    if abs(dy) < 0:
                        raise ValueError(
                            "XY's y-step is too small. It is current pointing"
                            f" at {router.t.angle * 90}"
                            " degrees.\n"
                            f"Current position: {router.t.disp!r}.\n"
                            f"Target Position ({self.x},{self.y})"
                        )
                    router.straight(abs(dy))
                else:
                    if abs(dy) < router.router.bend90_radius:
                        raise ValueError(
                            "XY's y-step is too small. It is current pointing"
                            f" at {router.t.angle * 90}"
                            " degrees.\n"
                            f"Current position: {router.t.disp!r}.\n"
                            f"Target Position ({self.x},{self.y})\n"
                            "Too small distance to place bend of "
                            f"{router.router.bend90_radius} size"
                        )
                    router.straight_nobend(abs(dy))

            case 1 | 3 if self.x == router.t.disp.x:
                sign = -1 if a == ANGLE_270 else 1
                if sign * dy < 0:
                    raise ValueError(
                        "XY step cannot go back. It is current pointing at 0"
                        " degrees.\n"
                        f"Current position: {router.t.disp!r}.\n"
                        f"Target Position ({self.x},{self.y})"
                    )
                if sign * dy < router.t.disp.y + router.router.bend90_radius:
                    raise ValueError("XY step cannot go back")
                router.straight_nobend(abs(dx))
                if self.x > router.t.disp.x:
                    if a == ANGLE_270:
                        router.left()
                    else:
                        router.right()
                dx = self.x - router.t.disp.x
                if ib:
                    if abs(dy) < 0:
                        raise ValueError(
                            "XY's y-step is too small. It is current pointing"
                            f" at {router.t.angle * 90}"
                            " degrees.\n"
                            f"Current position: {router.t.disp!r}.\n"
                            f"Target Position ({self.x},{self.y})"
                        )
                    router.straight(abs(dy))
                else:
                    if abs(dy) < router.router.bend90_radius:
                        raise ValueError(
                            "XY's y-step is too small. It is current pointing"
                            f" at {router.t.angle * 90}"
                            " degrees.\n"
                            f"Current position: {router.t.disp!r}.\n"
                            f"Target Position ({self.x},{self.y})\n"
                            "Too small distance to place bend of "
                            f"{router.router.bend90_radius} size"
                        )
                    router.straight_nobend(abs(dy))
            case _:
                ...

execute

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Executes the step on a router.

Source code in kfactory/routing/steps.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Executes the step on a router."""
    ib = include_bend if self.include_bend is None else self.include_bend
    dx = self.x - router.t.disp.x
    dy = self.y - router.t.disp.y
    a = router.t.angle
    match a:
        case 0 | 2 if self.y == router.t.disp.x:
            sign = -1 if a == ANGLE_180 else 1
            if sign * dx < 0:
                raise ValueError(
                    "XY step cannot go back. It is current pointing at 0"
                    " degrees.\n"
                    f"Current position: {router.t.disp!r}.\n"
                    f"Target Position ({self.x},{self.y})"
                )
                if ib:
                    router.straight_nobend(abs(dx))
                else:
                    router.straight(abs(dx))
            if sign * dx < router.t.disp.x + router.router.bend90_radius:
                raise ValueError("XY step cannot go back")
            router.straight_nobend(abs(dx))
            if self.y > router.t.disp.y:
                if a == 0:
                    router.left()
                else:
                    router.right()
            dy = self.y - router.t.disp.y
            if ib:
                if abs(dy) < 0:
                    raise ValueError(
                        "XY's y-step is too small. It is current pointing"
                        f" at {router.t.angle * 90}"
                        " degrees.\n"
                        f"Current position: {router.t.disp!r}.\n"
                        f"Target Position ({self.x},{self.y})"
                    )
                router.straight(abs(dy))
            else:
                if abs(dy) < router.router.bend90_radius:
                    raise ValueError(
                        "XY's y-step is too small. It is current pointing"
                        f" at {router.t.angle * 90}"
                        " degrees.\n"
                        f"Current position: {router.t.disp!r}.\n"
                        f"Target Position ({self.x},{self.y})\n"
                        "Too small distance to place bend of "
                        f"{router.router.bend90_radius} size"
                    )
                router.straight_nobend(abs(dy))

        case 1 | 3 if self.x == router.t.disp.x:
            sign = -1 if a == ANGLE_270 else 1
            if sign * dy < 0:
                raise ValueError(
                    "XY step cannot go back. It is current pointing at 0"
                    " degrees.\n"
                    f"Current position: {router.t.disp!r}.\n"
                    f"Target Position ({self.x},{self.y})"
                )
            if sign * dy < router.t.disp.y + router.router.bend90_radius:
                raise ValueError("XY step cannot go back")
            router.straight_nobend(abs(dx))
            if self.x > router.t.disp.x:
                if a == ANGLE_270:
                    router.left()
                else:
                    router.right()
            dx = self.x - router.t.disp.x
            if ib:
                if abs(dy) < 0:
                    raise ValueError(
                        "XY's y-step is too small. It is current pointing"
                        f" at {router.t.angle * 90}"
                        " degrees.\n"
                        f"Current position: {router.t.disp!r}.\n"
                        f"Target Position ({self.x},{self.y})"
                    )
                router.straight(abs(dy))
            else:
                if abs(dy) < router.router.bend90_radius:
                    raise ValueError(
                        "XY's y-step is too small. It is current pointing"
                        f" at {router.t.angle * 90}"
                        " degrees.\n"
                        f"Current position: {router.t.disp!r}.\n"
                        f"Target Position ({self.x},{self.y})\n"
                        "Too small distance to place bend of "
                        f"{router.router.bend90_radius} size"
                    )
                router.straight_nobend(abs(dy))
        case _:
            ...

Y dataclass

Bases: Step

Go to an absolute X coordinate.

Source code in kfactory/routing/steps.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
@dataclass
class Y(Step):
    """Go to an absolute X coordinate."""

    y: int

    def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
        """Adds a straight section to the router."""
        ib = include_bend if self.include_bend is None else self.include_bend
        if router.t.angle % 2 == 0:
            raise ValueError(
                "Cannot go to position {self.x=}, because the router is currently "
                "going in the y direction with position "
                f"{(router.t.disp.x, router.t.disp.y)}"
            )
        if self.y:
            if ib:
                router.straight_nobend(self.y - router.t.disp.y)
            else:
                router.straight(self.y - router.t.disp.y)

execute

execute(
    router: ManhattanRouterSide, include_bend: bool
) -> None

Adds a straight section to the router.

Source code in kfactory/routing/steps.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
def execute(self, router: ManhattanRouterSide, include_bend: bool) -> None:
    """Adds a straight section to the router."""
    ib = include_bend if self.include_bend is None else self.include_bend
    if router.t.angle % 2 == 0:
        raise ValueError(
            "Cannot go to position {self.x=}, because the router is currently "
            "going in the y direction with position "
            f"{(router.t.disp.x, router.t.disp.y)}"
        )
    if self.y:
        if ib:
            router.straight_nobend(self.y - router.t.disp.y)
        else:
            router.straight(self.y - router.t.disp.y)