"""Tests for coordinated multi-trace channel packing on the room router. ``pack=True`` is a third opt-in room-track upgrade, independent of ``shove``. The skeptic's finding that motivated it: shove recovers ordering drops but does not create density; the real densifier is lane packing. When several 2-pin nets must cross a common obstacle gap, greedy per-net routing lets each net grab a gate independently, the paths collide, and some nets drop even though the gap is physically wide enough for all of them (``channel_pack.dsn`` -- plain routing, shove on or off, drops a net under *every* net ordering). The packer assigns each net a parallel lane across the gap's usable width (pad-ordered, spaced >= width + clearance) with staggered fan-in trunks, routes them together, and connects all of them DRC-clean. The win is bounded honestly by geometry: the packer succeeds iff the gap is at least ``(N-1)*(width+clearance) + 2*(half_width+clearance)`` wide -- the true feasibility width for N lanes -- and never regresses below greedy below it. """ from __future__ import annotations import itertools from pathlib import Path import pytest from freeroute.dsn import parse_dsn from freeroute.dsn.sexp import parse from freeroute.geometry import Polyline, PolylineShape from freeroute.route import route, route_dsn_board_rooms from freeroute.route.pipeline import _rule_clearance_dsn FIXTURES = Path(__file__).resolve().parent.parent / "dsn" / "fixtures" CHANNEL_PACK = FIXTURES / "channel_pack.dsn" SIMPLE = FIXTURES / "simple_2net.dsn" CROSSING = FIXTURES / "crossing_2net.dsn" def _clearance(dsn, scale): return round(_rule_clearance_dsn(dsn) * scale) def _emitted_drc_violations(result, clearance): """Independent DRC over the emitted route: reconstruct every wire's copper tiles and return different-net, same-layer pairs closer than ``clearance``. Does not consult the search tree, so it catches copper emitted but (via a bug) absent from the tree.""" items = [] for net_no, segments in result.wires.items(): for layer, corners in segments: for box in PolylineShape(Polyline(corners), result.half_width).tiles(): items.append((net_no, layer, box)) bad = [] for i in range(len(items)): n1, l1, b1 = items[i] expanded = b1.offset(clearance) for j in range(i + 1, len(items)): n2, l2, b2 = items[j] if n1 == n2 or l1 != l2: continue if b2.overlaps(expanded): bad.append((n1, n2)) return bad def _net_blocks(text): import re return re.findall(r" \(net [^\n]*\n \(pins [^\n]*\n \)\n", text) def _reorder(text, perm): blocks = _net_blocks(text) return text.replace("".join(blocks), "".join(blocks[i] for i in perm), 1) def _wire_key(result): return { n: [(layer, [(p.x, p.y) for p in pts]) for layer, pts in segs] for n, segs in result.result.wires.items() } def _routed_counts(text, n, *, pack, shove): return [ len( route_dsn_board_rooms(parse_dsn(_reorder(text, p)), shove=shove, pack=pack)[ 0 ].routed_net_numbers ) for p in itertools.permutations(range(n)) ] # --- the genuine gap: current router drops a net under every ordering --------- def test_channel_pack_plain_drops_a_net_under_every_ordering(): """Bar (same methodology as true_density): the current router, shove on OR off, drops >= 1 of the three nets under EVERY net ordering -- an order-independent drop, even though the gap physically fits three lanes.""" text = CHANNEL_PACK.read_text() plain = _routed_counts(text, 3, pack=False, shove=False) shoved = _routed_counts(text, 3, pack=False, shove=True) assert all(k < 3 for k in plain) assert all(k < 3 for k in shoved) # shove buys nothing here: it relocates blockers, it does not pack lanes assert shoved == plain def test_channel_pack_connects_all_drc_clean(): """The packer connects all three nets and the emitted copper is exactly DRC-clean, verified both through the search tree and independently.""" dsn = parse_dsn(CHANNEL_PACK.read_text()) on, scale, _ = route_dsn_board_rooms(dsn, pack=True) clearance = _clearance(dsn, scale) assert on.routed_net_numbers == {1, 2, 3} assert on.drc_clean assert on.tree.has_violation(clearance) is None assert _emitted_drc_violations(on.result, clearance) == [] def test_channel_pack_connects_all_under_every_ordering(): counts = _routed_counts(CHANNEL_PACK.read_text(), 3, pack=True, shove=False) assert counts == [3, 3, 3, 3, 3, 3] def test_channel_pack_is_deterministic(): a, _, _ = route_dsn_board_rooms(parse_dsn(CHANNEL_PACK.read_text()), pack=True) b, _, _ = route_dsn_board_rooms(parse_dsn(CHANNEL_PACK.read_text()), pack=True) assert _wire_key(a) == _wire_key(b) assert a.routed_net_numbers == b.routed_net_numbers def test_channel_pack_endpoints_stay_on_pads(): dsn = parse_dsn(CHANNEL_PACK.read_text()) board_pins: dict[int, set[tuple[int, int]]] = {} from freeroute.board import build_board for pin in build_board(dsn).get_pins(): for net_no in pin.net_nos: board_pins.setdefault(net_no, set()).add((pin.location.x, pin.location.y)) on, _, _ = route_dsn_board_rooms(dsn, pack=True) for net_no, segments in on.result.wires.items(): pts = [(p.x, p.y) for _, run in segments for p in run] assert {pts[0], pts[-1]} == board_pins[net_no] def test_channel_pack_valid_ses(): ses = route(CHANNEL_PACK.read_text(), engine="room", pack=True) top = parse(ses) assert top.head == "session" nets = top.child("routes").child("network_out").children("net") assert {n.values()[0].text for n in nets} == {"NET0", "NET1", "NET2"} # --- additive: pack must not disturb the room-default / non-channel tracks ---- @pytest.mark.parametrize("fixture", [SIMPLE, CROSSING, CHANNEL_PACK]) def test_pack_off_matches_default(fixture): """pack defaults off; passing pack=False must be byte-identical to the foundation room route (no channel behaviour leaks into the default track).""" dsn = parse_dsn(fixture.read_text()) default, _, _ = route_dsn_board_rooms(dsn) off, _, _ = route_dsn_board_rooms(dsn, pack=False) assert _wire_key(default) == _wire_key(off) def test_pack_on_non_channel_board_is_noop(): """On a board with no obstacle gap to pack, pack=True changes nothing: the pre-pass finds no channel group and the greedy loop runs exactly as before.""" dsn = parse_dsn(SIMPLE.read_text()) off, _, _ = route_dsn_board_rooms(dsn, pack=False) on, _, _ = route_dsn_board_rooms(dsn, pack=True) assert _wire_key(off) == _wire_key(on) # --- falsifiable: pack succeeds iff the gap meets the geometric feasibility ---- def _channel_dsn(n, gap, spread, *, width=200000, height=80000): gx0 = (width - gap) // 2 gx1 = (width + gap) // 2 cx = width // 2 xs = [int(round(cx + (i - (n - 1) / 2) * spread)) for i in range(n)] places = "".join( f" (place P{i}a {x} -10000 front 0)\n (place P{i}b {x} -70000 front 0)\n" for i, x in enumerate(xs) ) nets = "".join(f" (net NET{i}\n (pins P{i}a-1 P{i}b-1)\n )\n" for i in range(n)) return f"""(pcb "sweep.dsn" (parser (string_quote ") (space_in_quoted_tokens on) (host_cad "t") (host_version "1")) (resolution um 10) (unit um) (structure (layer F.Cu (type signal) (property (index 0))) (boundary (path pcb 0 0 0 {width} 0 {width} -{height} 0 -{height} 0 0)) (keepout "wl" (rect F.Cu 0 -42000 {gx0} -38000)) (keepout "wr" (rect F.Cu {gx1} -42000 {width} -38000)) (rule (width 2000) (clearance 2000))) (library (padstack Rect_Pad (shape (rect F.Cu -1000 -1000 1000 1000)) (attach off)) (image PAD (pin Rect_Pad 1 0 0))) (placement (component PAD {places} )) (network {nets} (class default (rule (width 2000) (clearance 2000)))) (wiring ) ) """ @pytest.mark.parametrize("n", [3, 4]) def test_channel_pack_boundary_is_geometric_feasibility(n): """Sweep the gap width: the packer connects all N nets iff the gap is at least the geometric feasibility width for N lanes, and never routes fewer than the greedy baseline below it. width=2000, clearance=2000 -> half_width=1000, so lanes need >= 4000 apart and >= 3000 from each gap edge.""" width, clearance, half_width = 2000, 2000, 1000 feasibility = (n - 1) * (width + clearance) + 2 * (half_width + clearance) spread = 40000 step = 1000 for gap in range(feasibility - 4 * step, feasibility + 4 * step + 1, step): text = _channel_dsn(n, gap, spread) plain = len(route_dsn_board_rooms(parse_dsn(text), pack=False)[0].routed_net_numbers) packed_res = route_dsn_board_rooms(parse_dsn(text), pack=True)[0] packed = len(packed_res.routed_net_numbers) assert packed_res.drc_clean assert packed >= plain # never a regression if gap >= feasibility: assert packed == n # packs everything at/above feasibility else: assert packed < n # cannot (and does not falsely) pack below it