--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:
2026-09-27 22:34:06 -06:00
parent 0f5dacbd88
commit 01ca108831
7 changed files with 105 additions and 4 deletions
+31
View File
@@ -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