From 9bae0ffdac995d4f518db8ba29bd2dc2425d5202 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Sun, 8 Feb 2026 15:33:23 -0500 Subject: [PATCH] fix: don't create traces for net-label-only connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Net connections (netConnections) represent virtual connections shown via net labels — they should NOT produce physical traces. Only direct connections (directConnections) should generate MSP pairs and traces. Root cause: ConnectivityMap shared its netMap by reference between directConnMap and netConnMap, causing net-label connections to pollute the direct connection map. Both MspConnectionPairSolver and LongDistancePairSolver then used the polluted global map to create trace pairs for net-label-only pins. Three fixes: 1. Clone netMap in getConnectivityMapsFromInputProblem to prevent directConnMap pollution 2. MspConnectionPairSolver: iterate over directConnMap nets and use directConnMap to find connected pins 3. LongDistancePairSolver: use directConnMap for candidate pair generation instead of netConnMap Closes #79 Co-Authored-By: Claude Opus 4.6 --- .../LongDistancePairSolver.ts | 7 +- .../MspConnectionPairSolver.ts | 4 +- .../getConnectivityMapFromInputProblem.ts | 8 +- .../examples/__snapshots__/example01.snap.svg | 64 +- .../examples/__snapshots__/example03.snap.svg | 137 ++-- .../examples/__snapshots__/example07.snap.svg | 19 +- .../examples/__snapshots__/example10.snap.svg | 54 +- .../examples/__snapshots__/example12.snap.svg | 63 +- .../examples/__snapshots__/example13.snap.svg | 186 +++--- .../examples/__snapshots__/example15.snap.svg | 614 ++++++++++-------- .../examples/__snapshots__/example16.snap.svg | 60 +- .../examples/__snapshots__/example18.snap.svg | 120 ++-- .../examples/__snapshots__/example20.snap.svg | 120 ++-- .../examples/__snapshots__/example21.snap.svg | 148 +++-- .../examples/__snapshots__/example22.snap.svg | 49 +- .../examples/__snapshots__/example23.snap.svg | 49 +- .../examples/__snapshots__/example24.snap.svg | 53 +- .../examples/__snapshots__/example26.snap.svg | 64 +- .../examples/__snapshots__/example27.snap.svg | 5 +- .../MspConnectionPairSolver_repro1.test.ts | 3 +- ...elineSolver_repro04_net_label_only.test.ts | 56 ++ 21 files changed, 1050 insertions(+), 833 deletions(-) create mode 100644 tests/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver_repro04_net_label_only.test.ts diff --git a/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts b/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts index 31e0df3..887e1c3 100644 --- a/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +++ b/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts @@ -56,7 +56,8 @@ export class LongDistancePairSolver extends BaseSolver { primaryConnectedPinIds.add(pair.pins[1].pinId) } - const { netConnMap } = getConnectivityMapsFromInputProblem(inputProblem) + const { directConnMap, netConnMap } = + getConnectivityMapsFromInputProblem(inputProblem) this.netConnMap = netConnMap const pinMap = new Map() for (const chip of inputProblem.chips) { @@ -72,8 +73,8 @@ export class LongDistancePairSolver extends BaseSolver { > = [] const addedPairKeys = new Set() - for (const netId of Object.keys(netConnMap.netMap)) { - const allPinIdsInNet = netConnMap.getIdsConnectedToNet(netId) + for (const netId of Object.keys(directConnMap.netMap)) { + const allPinIdsInNet = directConnMap.getIdsConnectedToNet(netId) if (allPinIdsInNet.length < 2) continue const unconnectedPinIds = allPinIdsInNet.filter( diff --git a/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts b/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts index 48b46c9..e85021d 100644 --- a/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +++ b/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts @@ -74,7 +74,7 @@ export class MspConnectionPairSolver extends BaseSolver { } } - this.queuedDcNetIds = Object.keys(netConnMap.netMap) + this.queuedDcNetIds = Object.keys(directConnMap.netMap) } override getConstructorParams(): ConstructorParameters< @@ -93,7 +93,7 @@ export class MspConnectionPairSolver extends BaseSolver { const dcNetId = this.queuedDcNetIds.shift()! - const allIds = this.globalConnMap.getIdsConnectedToNet(dcNetId) as string[] + const allIds = this.dcConnMap.getIdsConnectedToNet(dcNetId) as string[] const directlyConnectedPins = allIds.filter((id) => !!this.pinMap[id]) if (directlyConnectedPins.length <= 1) { diff --git a/lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem.ts b/lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem.ts index d3a098c..2225b64 100644 --- a/lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem.ts +++ b/lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem.ts @@ -14,7 +14,13 @@ export const getConnectivityMapsFromInputProblem = ( ]) } - const netConnMap = new ConnectivityMap(directConnMap.netMap) + // Clone the netMap to prevent netConnMap additions from polluting directConnMap + const clonedNetMap: Record = {} + for (const [k, v] of Object.entries(directConnMap.netMap)) { + clonedNetMap[k] = [...v] + } + + const netConnMap = new ConnectivityMap(clonedNetMap) for (const netConn of inputProblem.netConnections) { netConnMap.addConnections([[netConn.netId, ...netConn.pinIds]]) diff --git a/tests/examples/__snapshots__/example01.snap.svg b/tests/examples/__snapshots__/example01.snap.svg index 293bf05..b596f08 100644 --- a/tests/examples/__snapshots__/example01.snap.svg +++ b/tests/examples/__snapshots__/example01.snap.svg @@ -2,97 +2,103 @@ +x-" data-x="-0.8" data-y="0.2" cx="422.5742574257426" cy="289.44950495049505" r="3" fill="hsl(319, 100%, 50%, 0.8)" /> +x-" data-x="-0.8" data-y="0" cx="422.5742574257426" cy="311.62772277227725" r="3" fill="hsl(320, 100%, 50%, 0.8)" /> +x-" data-x="-0.8" data-y="-0.2" cx="422.5742574257426" cy="333.80594059405945" r="3" fill="hsl(321, 100%, 50%, 0.8)" /> +x+" data-x="0.8" data-y="-0.2" cx="600" cy="333.80594059405945" r="3" fill="hsl(322, 100%, 50%, 0.8)" /> +x+" data-x="0.8" data-y="0" cx="600" cy="311.62772277227725" r="3" fill="hsl(323, 100%, 50%, 0.8)" /> +x+" data-x="0.8" data-y="0.2" cx="600" cy="289.44950495049505" r="3" fill="hsl(324, 100%, 50%, 0.8)" /> +y+" data-x="-2" data-y="0.5" cx="289.50495049504957" cy="256.1821782178218" r="3" fill="hsl(121, 100%, 50%, 0.8)" /> +y-" data-x="-2" data-y="-0.5" cx="289.50495049504957" cy="367.0732673267327" r="3" fill="hsl(122, 100%, 50%, 0.8)" /> +y+" data-x="-4" data-y="0.5" cx="67.72277227722776" cy="256.1821782178218" r="3" fill="hsl(2, 100%, 50%, 0.8)" /> +y-" data-x="-4" data-y="-0.5" cx="67.72277227722776" cy="367.0732673267327" r="3" fill="hsl(3, 100%, 50%, 0.8)" /> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + +