From 99c3d20de5c7b0a035e9903f0aa742f2fbb90a84 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Mon, 13 Jul 2026 11:34:31 -0600 Subject: [PATCH] Prove shove-in-rooms recovers ordering drops but does not create density Add true_density.dsn: NET_C is a full-height wall on the sole signal layer, so plain room routing drops a net under every net ordering (an order-independent obstruction, verified over all permutations), unlike rooms_shove_channel whose plain drop fits under a reorder. Test that shove recovers nothing on this board (shoves == 0, same routed set as plain) while staying DRC-clean, and that the only difference from the recoverable shove_channel is the wall's span. shove relocates a blocker into existing free space; where the wall leaves no headroom there is nowhere to relocate to, so it cannot manufacture density. The recover/fail boundary is the free-space boundary. --- tests/dsn/fixtures/true_density.dsn | 64 +++++++++++++++++ tests/route/test_room_shove.py | 107 ++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 tests/dsn/fixtures/true_density.dsn diff --git a/tests/dsn/fixtures/true_density.dsn b/tests/dsn/fixtures/true_density.dsn new file mode 100644 index 0000000..22f501b --- /dev/null +++ b/tests/dsn/fixtures/true_density.dsn @@ -0,0 +1,64 @@ +(pcb "true_density.dsn" + (parser + (string_quote ") + (space_in_quoted_tokens on) + (host_cad "freeroute-test") + (host_version "1.0") + ) + (resolution um 10) + (unit um) + (structure + (layer F.Cu + (type signal) + (property + (index 0) + ) + ) + (layer B.Cu + (type power) + (property + (index 1) + ) + ) + (boundary + (path pcb 0 0 0 200000 0 200000 -30000 0 -30000 0 0) + ) + (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 + (place A1 7000 -15000 front 0) + (place A2 193000 -15000 front 0) + (place C1 100000 -500 front 0) + (place C2 100000 -29500 front 0) + ) + ) + (network + (net NET_A + (pins A1-1 A2-1) + ) + (net NET_C + (pins C1-1 C2-1) + ) + (class default + (rule + (width 2000) + (clearance 2000) + ) + ) + ) + (wiring + ) +) diff --git a/tests/route/test_room_shove.py b/tests/route/test_room_shove.py index dce9c82..b127286 100644 --- a/tests/route/test_room_shove.py +++ b/tests/route/test_room_shove.py @@ -15,6 +15,14 @@ Two opt-in (``shove=True``) upgrades to the continuous expansion-room track: see ``test_room_shove_channel_drop_is_ordering_artifact_not_density``), not a genuine density limit. The true sub-cell win is occupancy packing, which the ``rooms_wide_door`` fixture exercises with ``shoves == 0``. + +The ``true_density`` fixture settles the density question the other way and honestly: +plain routing drops a net under EVERY net ordering (an order-independent obstruction, +not a self-inflicted greedy choice), and shove recovers *nothing* there (``shoves == 0``). +shove relocates a blocker into existing free space; it does not compress copper, so it +cannot manufacture density where none exists. The recover/fail boundary is exactly the +free-space boundary -- ``test_true_density_contrast_is_only_the_wall_height`` shows the +two boards differ only in how far the wall spans. """ from __future__ import annotations @@ -67,6 +75,7 @@ SHOVE_CHANNEL = FIXTURES / "rooms_shove_channel.dsn" WIDE_DOOR = FIXTURES / "rooms_wide_door.dsn" MULTIPIN_DESYNC = FIXTURES / "rooms_multipin_desync.dsn" MULTIPIN_DESYNC_CRASH = FIXTURES / "rooms_multipin_desync_crash.dsn" +TRUE_DENSITY = FIXTURES / "true_density.dsn" FOUNDATION = [SIMPLE, CROSSING, KICAD, NARROW] @@ -346,3 +355,101 @@ def test_room_shove_multipin_recovery_does_not_crash(): clearance = _clearance(dsn, scale) assert on.drc_clean assert _emitted_drc_violations(on.result, clearance) == [] + + +# --- honest bound: shove recovers ordering drops, it does NOT create density -- + + +def _net_blocks(text): + import re + + return re.findall(r" \(net [^\n]*\n \(pins [^\n]*\n \)\n", text) + + +def _plain_under_all_orderings(fixture): + """Route ``fixture`` plainly (shove=False) under every permutation of its net + declaration order, returning the routed-net set for each ordering. Net numbers + follow declaration order, so permuting the ``(net ...)`` blocks permutes the + greedy routing order -- the exact knob that turned the shove_channel drop into + an ordering artifact.""" + import itertools + + text = fixture.read_text() + blocks = _net_blocks(text) + joined = "".join(blocks) + assert joined in text and len(blocks) >= 2 + out = [] + for perm in itertools.permutations(range(len(blocks))): + variant = text.replace(joined, "".join(blocks[i] for i in perm), 1) + result, _, _ = route_dsn_board_rooms(parse_dsn(variant), shove=False) + out.append(len(result.routed_net_numbers)) + return out + + +def test_shove_channel_plain_fits_under_some_ordering(): + """Baseline for the contrast: on shove_channel the plain drop is an ORDERING + artifact -- there exists a net order under which plain routing fits both nets + with no shove. This is exactly what makes it *not* a density limit.""" + counts = _plain_under_all_orderings(SHOVE_CHANNEL) + assert max(counts) == 2 # some ordering routes both + assert min(counts) == 1 # the default order drops one + + +def test_true_density_plain_drops_under_every_ordering(): + """The order-independent bar: on true_density plain routing drops >= 1 net + under EVERY net ordering, unlike shove_channel. NET_C is a full-height wall on + the only signal layer, so whichever net is routed first walls off the other -- + no permutation fits both. The drop is a genuine on-layer obstruction, not a + self-inflicted ordering choice.""" + counts = _plain_under_all_orderings(TRUE_DENSITY) + assert len(counts) == 2 # two nets -> two orderings + assert all(k < 2 for k in counts) # every ordering drops at least one net + assert all(k == 1 for k in counts) # exactly one survives each way + + +def test_true_density_shove_cannot_create_space(): + """The honest result: shove does NOT recover the order-independent drop. + + shove_segment RELOCATES a blocking trace into existing free space; it does not + compress copper. NET_C walls the board top-to-bottom on the sole signal layer, + so there is nowhere to relocate NET_A's crossing run to -- every perpendicular + displacement lands on NET_C or outside the board. shove therefore adds zero + shoves and routes no more nets than plain routing. This is the boundary of the + shove mechanism: it recovers ordering-induced drops (free space exists), it + cannot manufacture density (free space absent).""" + dsn = parse_dsn(TRUE_DENSITY.read_text()) + off, _, _ = route_dsn_board_rooms(dsn, shove=False) + on, scale, _ = route_dsn_board_rooms(dsn, shove=True) + clearance = _clearance(dsn, scale) + + assert len(off.routed_net_numbers) == 1 # plain drops one + assert on.routed_net_numbers == off.routed_net_numbers # shove recovers nothing + assert on.shoves == 0 # no clean displacement exists to try + # whatever it does route stays exactly DRC-clean (invariant never traded away) + assert on.drc_clean + assert on.tree.has_violation(clearance) is None + assert _emitted_drc_violations(on.result, clearance) == [] + + +def test_true_density_contrast_is_only_the_wall_height(): + """Pin down *why* shove recovers shove_channel but not true_density: the two + boards share the same NET_A blocker and the same channel geometry; they differ + only in how far NET_C spans. When NET_C leaves headroom (shove_channel) shove + nudges NET_A into it and both fit; when NET_C spans the full height + (true_density) that headroom is gone and shove is powerless. The recover/fail + boundary is the free-space boundary, which is the whole point.""" + short_on, _, _ = route_dsn_board_rooms(parse_dsn(SHOVE_CHANNEL.read_text()), shove=True) + wall_on, _, _ = route_dsn_board_rooms(parse_dsn(TRUE_DENSITY.read_text()), shove=True) + # space exists -> shove recovers both, with real shoves + assert short_on.routed_net_numbers == {1, 2} + assert short_on.shoves >= 1 + # space absent -> shove recovers neither extra net, zero shoves + assert len(wall_on.routed_net_numbers) == 1 + assert wall_on.shoves == 0 + + +def test_true_density_is_deterministic(): + a, _, _ = route_dsn_board_rooms(parse_dsn(TRUE_DENSITY.read_text()), shove=True) + b, _, _ = route_dsn_board_rooms(parse_dsn(TRUE_DENSITY.read_text()), shove=True) + assert _wire_key(a.result) == _wire_key(b.result) + assert a.routed_net_numbers == b.routed_net_numbers