--promote-failures: reroute with the connections that failed moved first
Each round routes every connection that has failed so far ahead of the rest, which keep their order. The promoted set only grows, so two groups cannot take turns failing; the best round is kept.
This commit is contained in:
@@ -95,6 +95,7 @@ def route_board_exact(
|
||||
resolution: int = 1,
|
||||
heuristic_weight: float = 1.0,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> ExactRouteResult:
|
||||
"""Route ``board`` orthogonally and verify the result with exact geometry.
|
||||
|
||||
@@ -124,6 +125,7 @@ def route_board_exact(
|
||||
resolution=resolution,
|
||||
heuristic_weight=heuristic_weight,
|
||||
seed=seed,
|
||||
route_first=route_first,
|
||||
)
|
||||
edge = 0 if edge_clearance is None else edge_clearance
|
||||
outline = board.outline
|
||||
|
||||
@@ -156,11 +156,14 @@ class GridRouter:
|
||||
resolution: int = 1,
|
||||
heuristic_weight: float = 1.0,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> None:
|
||||
self.board = board
|
||||
# None keeps the deterministic order; a seed shuffles which connection
|
||||
# routes first, to measure how much a result owes to the order
|
||||
self.seed = seed
|
||||
# connections, as (net_no, one end, other end), to route before the rest
|
||||
self.route_first = frozenset(route_first or ())
|
||||
# how far (in cells) an escape stub may run to leave a walled-in pin
|
||||
self._escape_cells = 12
|
||||
self._crowded_cache: dict = {}
|
||||
@@ -828,6 +831,9 @@ class GridRouter:
|
||||
order = list(conns)
|
||||
if self.seed is not None:
|
||||
random.Random(self.seed).shuffle(order)
|
||||
if self.route_first:
|
||||
# stable: the promoted keep their order among themselves, as do the rest
|
||||
order.sort(key=lambda c: (c.net_no, *_ends_of(c)) not in self.route_first)
|
||||
for _ in range(passes):
|
||||
changed = False
|
||||
for conn in order:
|
||||
@@ -1060,6 +1066,7 @@ def route_board(
|
||||
resolution: int = 1,
|
||||
heuristic_weight: float = 1.0,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> RouteResult:
|
||||
"""Convenience wrapper: build a :class:`GridRouter` and route the board."""
|
||||
router = GridRouter(
|
||||
@@ -1076,5 +1083,6 @@ def route_board(
|
||||
resolution=resolution,
|
||||
heuristic_weight=heuristic_weight,
|
||||
seed=seed,
|
||||
route_first=route_first,
|
||||
)
|
||||
return router.route()
|
||||
|
||||
@@ -65,3 +65,34 @@ def best_of_orders(
|
||||
scores = [score(r) for r in results]
|
||||
best = min(range(len(seeds)), key=lambda i: (scores[i], i))
|
||||
return results[best], seeds[best], list(zip(seeds, scores, strict=True))
|
||||
|
||||
|
||||
def promote_failures(
|
||||
dsn_text: str,
|
||||
engine: str,
|
||||
options: dict,
|
||||
*,
|
||||
rounds: int,
|
||||
seed: int | None = None,
|
||||
) -> tuple[RoutingResult, list[tuple[int, int]]]:
|
||||
"""Route, then route again with every connection that has failed so far
|
||||
moved to the front, keeping the rest in their order. Returns the best
|
||||
round's result and every round's score.
|
||||
|
||||
The promoted set only grows, so a connection that failed once keeps its
|
||||
early place and two groups cannot take turns failing. Stops early when a
|
||||
round routes everything or fails nothing new."""
|
||||
numbers = {n.name: i + 1 for i, n in enumerate(parse_dsn(dsn_text).nets)}
|
||||
first: frozenset = frozenset()
|
||||
best: RoutingResult | None = None
|
||||
scores: list[tuple[int, int]] = []
|
||||
for _ in range(max(int(rounds), 1)):
|
||||
result = route_once(dsn_text, engine, {**options, "route_first": first}, seed)
|
||||
scores.append(score(result))
|
||||
if best is None or scores[-1] < score(best):
|
||||
best = result
|
||||
failed = {(numbers.get(name), a, b) for name, a, b, zone in result.unrouted if not zone}
|
||||
if not failed or failed <= first:
|
||||
break
|
||||
first = first | failed
|
||||
return best, scores
|
||||
|
||||
@@ -81,6 +81,7 @@ def route_dsn_board(
|
||||
rip_up: bool = True,
|
||||
max_passes: int = 10,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> tuple[RouteResult, int, list[str]]:
|
||||
"""Route a parsed :class:`DsnBoard`; return the board-unit result, the scale,
|
||||
and the layer names. ``layers`` restricts routing to those signal-layer
|
||||
@@ -102,6 +103,7 @@ def route_dsn_board(
|
||||
rip_up=rip_up,
|
||||
max_passes=max_passes,
|
||||
seed=seed,
|
||||
route_first=route_first,
|
||||
)
|
||||
return result, scale, [layer.name for layer in dsn.layers]
|
||||
|
||||
@@ -143,11 +145,13 @@ def build_routing_result(
|
||||
max_passes: int = 10,
|
||||
edge_clearance_mm: float | None = None,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> RoutingResult:
|
||||
"""Route ``dsn`` (grid track) and convert to a DSN-unit RoutingResult."""
|
||||
route, scale, layer_names = route_dsn_board(
|
||||
dsn, layers=layers, rip_up=rip_up, max_passes=max_passes,
|
||||
edge_clearance_mm=edge_clearance_mm, resolution=resolution, seed=seed,
|
||||
route_first=route_first,
|
||||
)
|
||||
return _to_routing_result(route, dsn, scale, layer_names)
|
||||
|
||||
@@ -164,6 +168,7 @@ def route_dsn_board_exact(
|
||||
shove: bool = False,
|
||||
diagonal: bool = False,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> tuple[ExactRouteResult, int, list[str]]:
|
||||
"""Route a parsed :class:`DsnBoard` with the exact-geometry (orthogonal,
|
||||
DRC-verified) track; return the exact result, the scale, and layer names.
|
||||
@@ -189,6 +194,7 @@ def route_dsn_board_exact(
|
||||
shove=shove,
|
||||
diagonal=diagonal,
|
||||
seed=seed,
|
||||
route_first=route_first,
|
||||
)
|
||||
return exact, scale, [layer.name for layer in dsn.layers]
|
||||
|
||||
@@ -205,6 +211,7 @@ def build_exact_routing_result(
|
||||
max_passes: int = 10,
|
||||
edge_clearance_mm: float | None = None,
|
||||
seed: int | None = None,
|
||||
route_first: frozenset | None = None,
|
||||
) -> RoutingResult:
|
||||
"""Route ``dsn`` (exact track) and convert to a DSN-unit RoutingResult."""
|
||||
exact, scale, layer_names = route_dsn_board_exact(
|
||||
@@ -218,6 +225,7 @@ def build_exact_routing_result(
|
||||
resolution=resolution,
|
||||
heuristic_weight=heuristic_weight,
|
||||
seed=seed,
|
||||
route_first=route_first,
|
||||
)
|
||||
return _to_routing_result(exact.result, dsn, scale, layer_names)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user