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.
This commit is contained in:
parent
9cf2392c4b
commit
99c3d20de5
64
tests/dsn/fixtures/true_density.dsn
Normal file
64
tests/dsn/fixtures/true_density.dsn
Normal file
@ -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
|
||||
)
|
||||
)
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user