@tscircuit/fanout-solver 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -64,6 +64,9 @@ and treats each bus-layer decision atomically.
64
64
  - `compactBusTracks` bends each bus into a trace/clearance-pitch routing
65
65
  envelope, so a wide pad row does not consume a disproportionately wide
66
66
  breakout corridor.
67
+ - `preferOriginalEndpointTracks` projects boundary tracks onto the original
68
+ downstream pad coordinates and prefers their layer when legal. This lets
69
+ ordered edge-pad buses make direct, visibly continuous pad connections.
67
70
  - Chamfers orthogonal routing corners into 45° segments before validating and
68
71
  emitting the fanout.
69
72
  - Verifies oriented-pad, via, trace, and already-routed fanout clearance on
@@ -77,6 +80,13 @@ and treats each bus-layer decision atomically.
77
80
  opt-in; different electrical nets remain hard obstacles.
78
81
  - Audits route continuity, unique connection coverage, boundary exits, and
79
82
  retained downstream endpoints before marking a solution complete.
83
+ - `completeOriginalEndpoints` adds a bounded fail-first completion stage after
84
+ fanout. It first places DRC-gated interstitial capacitor escapes, then tries
85
+ breakout-to-pad routes with layer transitions at interior points along the
86
+ existing fanout copper, and finally a bounded capacity-router fallback. Vias
87
+ at original or moved routing endpoints are rejected. A candidate is retained
88
+ only when it improves independently proven original endpoint connectivity
89
+ and the complete emitted copper remains DRC-clean.
80
90
  - Emits supplied fanout traces, via obstacles, and moved breakout endpoints in a
81
91
  new `SimpleRouteJson`. The returned problem is ready for a downstream
82
92
  autorouter to finish.
@@ -115,6 +125,7 @@ const fanoutSolver = new FanoutSolver(simpleRouteJson, {
115
125
  availableCornersAndSides: ["top_left", "top", "top_right"],
116
126
  borderDistribution: "even",
117
127
  compactBusTracks: true,
128
+ preferOriginalEndpointTracks: true,
118
129
  buses: [
119
130
  {
120
131
  busId: "ground",
@@ -186,6 +197,10 @@ bus-layer combination search.
186
197
 
187
198
  - `simpleRouteJson`: the downstream routing problem with fanout prefixes
188
199
  - `fanoutTraces`: the newly supplied pad-to-breakout traces
200
+ - `completionTraces`: optional DRC-gated traces from breakouts to original
201
+ endpoints
202
+ - `endpointCompletion`: optional independent connectivity/DRC reports and
203
+ bounded-search diagnostics
189
204
  - `planeTerminations`: the completed local-via connection, layer, and via data
190
205
  - `busLayerAssignments`: the selected layer for every bus
191
206
  - `busDirections`: the direction shared by each bus
@@ -239,10 +254,16 @@ samples in parallel, and `--sample-timeout-seconds 600` prevents a difficult
239
254
  sample from blocking the remaining work. Each run writes the full ordered
240
255
  results to `benchmark-results/srj29.json` and
241
256
  `benchmark-results/srj29.md`. A row is marked solved only when every input
242
- connection has a validated breakout, all downstream endpoints remain attached,
243
- and the independent DRC audit passes. Partial solutions are reported as
244
- benchmark results instead of failing the command, making current completion
245
- rates a baseline for solver improvements. `bun run benchmark:srj29` is an alias
257
+ connection has a validated breakout and an independent physical-copper audit
258
+ proves that the emitted wires, vias, and same-net pads connect every original
259
+ endpoint on compatible layers. A second independent audit checks every emitted
260
+ trace and via against different-net pads, obstacles, traces, and vias on every
261
+ physical layer in its span. Reaching an arbitrary boundary point, retaining an
262
+ unrouted endpoint in the output JSON, or emitting copper with a DRC violation
263
+ does not count. The report separates fanout-prefix completion from physically
264
+ connected original connections so partial progress remains visible without
265
+ overstating it as a solution. Partial solutions are reported as benchmark
266
+ results instead of failing the command. `bun run benchmark:srj29` is an alias
246
267
  for the same command.
247
268
 
248
269
  The `SRJ29 Benchmark` GitHub Actions workflow runs the complete dataset on a
@@ -1,12 +1,14 @@
1
1
  import type { Obstacle, SimpleRouteJson } from "@tscircuit/capacity-autorouter"
2
- import type { FanoutRoutePlan } from "./types"
2
+ import type { FanoutRoutePlan, SimpleRouteJsonWithFanoutPlanes } from "./types"
3
3
 
4
4
  function createViaObstacle(
5
5
  plan: FanoutRoutePlan,
6
6
  layerNames: string[],
7
+ endpoint = false,
7
8
  ): Obstacle | null {
8
- if (!plan.via) return null
9
- const zLayers = plan.via.spanLayers.map((layer) => {
9
+ const via = endpoint ? plan.planeEndpointVia : plan.via
10
+ if (!via) return null
11
+ const zLayers = via.spanLayers.map((layer) => {
10
12
  const layerIndex = layerNames.indexOf(layer)
11
13
  if (layerIndex < 0) {
12
14
  throw new Error(
@@ -16,12 +18,12 @@ function createViaObstacle(
16
18
  return layerIndex
17
19
  })
18
20
  return {
19
- obstacleId: `fanout-via:${plan.connectionName}`,
21
+ obstacleId: `${endpoint ? "fanout-plane-endpoint-via" : "fanout-via"}:${plan.connectionName}`,
20
22
  type: "rect",
21
- center: plan.via.center,
22
- width: plan.via.diameter,
23
- height: plan.via.diameter,
24
- layers: plan.via.spanLayers,
23
+ center: via.center,
24
+ width: via.diameter,
25
+ height: via.diameter,
26
+ layers: via.spanLayers,
25
27
  zLayers,
26
28
  __zLayers: zLayers,
27
29
  connectedTo: [plan.connectionName, plan.trace.pcb_trace_id],
@@ -32,7 +34,7 @@ export function buildOutputSimpleRouteJson(params: {
32
34
  inputSrj: SimpleRouteJson
33
35
  plans: FanoutRoutePlan[]
34
36
  layerNames: string[]
35
- }): SimpleRouteJson {
37
+ }): SimpleRouteJsonWithFanoutPlanes {
36
38
  const { inputSrj, plans, layerNames } = params
37
39
  const outputConnections = inputSrj.connections.map((connection) => ({
38
40
  ...connection,
@@ -62,9 +64,15 @@ export function buildOutputSimpleRouteJson(params: {
62
64
  }
63
65
  const viaObstacle = createViaObstacle(plan, layerNames)
64
66
  if (viaObstacle) viaObstacles.push(viaObstacle)
67
+ const endpointViaObstacle = createViaObstacle(plan, layerNames, true)
68
+ if (endpointViaObstacle) viaObstacles.push(endpointViaObstacle)
65
69
  }
66
- const coordinateRoutePoints = plans.flatMap((plan) =>
67
- plan.trace.route.filter(
70
+ const planTraces = plans.flatMap((plan) => [
71
+ plan.trace,
72
+ ...(plan.planeEndpointTrace ? [plan.planeEndpointTrace] : []),
73
+ ])
74
+ const coordinateRoutePoints = planTraces.flatMap((trace) =>
75
+ trace.route.filter(
68
76
  (
69
77
  routePoint,
70
78
  ): routePoint is Extract<typeof routePoint, { x: number; y: number }> =>
@@ -107,6 +115,16 @@ export function buildOutputSimpleRouteJson(params: {
107
115
 
108
116
  return {
109
117
  ...inputSrj,
118
+ fanoutPlaneConnectivity: plans.flatMap((plan) =>
119
+ plan.termination.type === "plane"
120
+ ? [
121
+ {
122
+ connectionName: plan.connectionName,
123
+ layer: plan.termination.layer,
124
+ },
125
+ ]
126
+ : [],
127
+ ),
110
128
  bounds: outputBounds,
111
129
  connections: outputConnections.filter(
112
130
  (connection) => !planeTerminatedConnectionNames.has(connection.name),
@@ -134,7 +152,7 @@ export function buildOutputSimpleRouteJson(params: {
134
152
  ...trace,
135
153
  route: trace.route.map((routePoint) => ({ ...routePoint })),
136
154
  })),
137
- ...plans.map((plan) => plan.trace),
155
+ ...planTraces,
138
156
  ],
139
157
  }
140
158
  }