Balance global routing and accelerate detailed routing - #2090
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Benchmark This PRRun benchmarks by commenting on this PR: Comment Everything after Use Any PR whose title contains |
|
/benchmark-all --same-machine |
Same Machine Benchmark ResultsThe paired benchmark ended with failure before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with failure before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with failure before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with failure before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 3 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (3)
Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 4 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (4)
Workflow: View run |
Same Machine Benchmark Results — AggregateAll six
Aggregate measured scenario runtime: 62,829.4s → 61,857.0s, saving 972.4s (16m12s). Outcome changes: 7 improved, 0 regressed. Completion improved 83.5% → 84.3% (+0.9 pp) and relaxed DRC improved 45.3% → 45.7% (+0.3 pp). Selector attribution
AssessmentThis is a meaningful quality win and a modest net speed win, not a dramatic throughput improvement. The guarded strategy behaves as intended: it is inert on datasets that do not meet the congestion gates, and its sparse accepted candidates account for most of the aggregate savings without any observed outcome regression. A repeat paired run would still be prudent before merge because this is one same-machine sample per dataset. |
|
/benchmark-all --same-machine |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with cancelled before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with cancelled before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 1 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (1)
Workflow: View run |
New local optimization results (head
|
|
/benchmark-all --same-machine |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 2 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (2)
Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with cancelled before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsThe paired benchmark ended with cancelled before both reports were produced. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Additional downstream optimizationThe latest head
Across dataset01 samples 32, 37, 39, 49, 58, 67, 73, and 77, every high-density iteration count, via count, DRC result, and byte-for-byte output hash remained identical. The force optimization alone reduced end-to-end time 3.75%; the dense-state switch is another small additive gain. SRJ18 sample 11 remained byte-identical and its force phase improved from 1.328 s to 0.703 s (-47.1%). SRJ23 sample 39 remained byte-identical and served as a control because force projection is only ~0.1 s of its ~32 s runtime. |
|
/benchmark-all --same-machine |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 2 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (2)
Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 11 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (11)
Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 9 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Changed outcomes (9)
Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Same Machine Benchmark ResultsBoth revisions ran sequentially in one Blacksmith job on Dataset:
Outcome changes: 0 improved, 0 regressed. Timing percentiles include solved and timed-out samples; negative timing deltas are faster. Workflow: View run |
Final same-machine aggregate (
|
| Aggregate (587 scenarios) | Main | PR | Change |
|---|---|---|---|
| Completion | 492 (83.8%) | 510 (86.9%) | +18 / +3.1 pp |
| Relaxed DRC pass | 266 (45.3%) | 271 (46.2%) | +5 / +0.9 pp |
| Timeouts | 94 | 76 | -18 |
| Total scenario time | 17.02 h | 14.41 h | -15.3% |
| P50 | 28.5 s | 21.0 s | -26.4% |
| P60 | 58.0 s | 43.1 s | -25.8% |
| P70 | 116.0 s | 84.2 s | -27.5% |
| P80 | 253.2 s | 176.4 s | -30.3% |
Outcome changes: 22 improved, 0 regressed.
| Dataset | Completion | DRC pass | Representative timing |
|---|---|---|---|
| dataset01 | unchanged | unchanged | P50 -17.8%; P95 -36.7% (1.58x) |
| SRJ18 | +12.5 pp | +6.2 pp | P50 -29.8%; P60 -27.4% |
| SRJ19 | +5.5 pp | unchanged | P50 -23.2%; P80 -36.5% |
| SRJ20 | +2.5 pp | +2.0 pp | P50 -37.4%; P70 -30.8% |
| SRJ21 | unchanged | unchanged | P50 -10.3%; P95 -9.3% |
| SRJ23 | unchanged | unchanged | P50 -30.1%; P95 -4.5% |
Region-cost guardrail
The paired-only audit avoids bias from main timeouts that never emitted tiny metrics. Across 492-493 directly comparable cases:
| Tiny-hypergraph metric | Change |
|---|---|
| Summed best max region cost | +0.24% |
| Summed best total region cost | +2.37% |
| Summed final max region occupancy | -0.13% |
| Summed squared region occupancy | -0.54% |
This is comfortably inside the requested ~20% region-cost guardrail. Most paired cases are exact; selected portfolio cases account for the topology changes.
All 8 autorouter test shards, build, type-check, format-check, Vercel build, and the high-density-repair01 dependency's 14 tests/type-check/format-check are green. bugreport88 remained excluded from local trials because of its prior RAM behavior; no timeout was increased.
| @@ -144,3 +185,129 @@ test("Future-cost solver rejects vias that violate future via-to-trace clearance | |||
| const neighbors = solver.getNeighbors(currentNode as any) | |||
| expect(neighbors.some((neighbor) => neighbor.z !== currentNode.z)).toBe(false) | |||
| }) | |||
|
|
|||
| test("Future-cost solver computes combined node costs identically", () => { | |||
| const solver = new SingleHighDensityRouteSolver6_VertHorzLayer_FutureCost({ | |||
| ...baseOpts, | |||
| obstacleRoutes: [], | |||
| futureConnections: [ | |||
| { | |||
| connectionName: "future-conn", | |||
| points: [ | |||
| { x: 2, y: 8, z: 0 }, | |||
| { x: 8, y: 2, z: 1 }, | |||
| ], | |||
| }, | |||
| ], | |||
| }) | |||
| const parent = { x: 3, y: 4, z: 0, g: 2.5, h: 0, f: 0, parent: null } | |||
| for (const node of [ | |||
| { x: 3.5, y: 4.5, z: 0, g: 0, h: 0, f: 0, parent }, | |||
| { x: 3.5, y: 4.5, z: 1, g: 0, h: 0, f: 0, parent }, | |||
| ]) { | |||
| const expectedG = solver.computeG(node as any) | |||
| const expectedH = solver.computeH(node as any) | |||
|
|
|||
| solver.setNodeCosts(node as any) | |||
|
|
|||
| expect(node.g).toBe(expectedG) | |||
| expect(node.h).toBe(expectedH) | |||
| expect(node.f).toBe(solver.computeF(expectedG, expectedH)) | |||
| } | |||
| }) | |||
|
|
|||
| test("Future-cost solver flattens points and caches immutable segments", () => { | |||
| const solver = new SingleHighDensityRouteSolver6_VertHorzLayer_FutureCost({ | |||
| ...baseOpts, | |||
| obstacleRoutes: [], | |||
| futureConnections: [ | |||
| { | |||
| connectionName: "future-conn", | |||
| points: [ | |||
| { x: 2, y: 8, z: 0 }, | |||
| { x: 8, y: 2, z: 1 }, | |||
| ], | |||
| }, | |||
| ], | |||
| }) | |||
| const node = { x: 7.9, y: 2.1, z: 1 } as any | |||
|
|
|||
| expect(solver.futureConnectionPoints).toHaveLength(2) | |||
| expect(solver.getClosestFutureConnectionPoint(node)).toBe( | |||
| solver.futureConnectionPoints[1], | |||
| ) | |||
| const segments = solver.getFutureConnectionSegments() | |||
| expect(solver.getFutureConnectionSegments()).toBe(segments) | |||
| }) | |||
|
|
|||
| test("SingleHighDensityRouteSolver numeric node keys are collision-free across its grid", () => { | |||
| const solver = new SingleHighDensityRouteSolver({ | |||
| ...baseOpts, | |||
| bounds: { minX: -1, maxX: 1, minY: -1, maxY: 1 }, | |||
| A: { x: -1, y: -0.8, z: 0 }, | |||
| B: { x: -1, y: 0.8, z: 0 }, | |||
| obstacleRoutes: [], | |||
| availableZ: [0, 2, 5], | |||
| captureSearchDebug: false, | |||
| }) | |||
| const minXIndex = Math.round(solver.bounds.minX / solver.cellStep) | |||
| const maxXIndex = Math.round(solver.bounds.maxX / solver.cellStep) | |||
| const minYIndex = Math.round(solver.bounds.minY / solver.cellStep) | |||
| const maxYIndex = Math.round(solver.bounds.maxY / solver.cellStep) | |||
| const keys = new Set<number>() | |||
|
|
|||
| for (const z of solver.availableZ) { | |||
| for (let xIndex = minXIndex; xIndex <= maxXIndex; xIndex++) { | |||
| for (let yIndex = minYIndex; yIndex <= maxYIndex; yIndex++) { | |||
| const key = solver.getNodeKey({ | |||
| x: xIndex * solver.cellStep, | |||
| y: yIndex * solver.cellStep, | |||
| z, | |||
| } as any) | |||
| expect(keys.has(key)).toBe(false) | |||
| keys.add(key) | |||
| } | |||
| } | |||
| } | |||
| }) | |||
|
|
|||
| test("SingleHighDensityRouteSolver can skip search visualization history", () => { | |||
| const createSolver = (captureSearchDebug?: boolean) => | |||
| new SingleHighDensityRouteSolver({ | |||
| ...baseOpts, | |||
| A: { x: 0, y: 1, z: 0 }, | |||
| B: { x: 0, y: 9, z: 0 }, | |||
| obstacleRoutes: [], | |||
| captureSearchDebug, | |||
| }) | |||
|
|
|||
| const headlessSolver = createSolver(false) | |||
| headlessSolver.step() | |||
| expect(headlessSolver.debug_exploredNodesOrdered).toHaveLength(0) | |||
|
|
|||
| const debugSolver = createSolver() | |||
| debugSolver.step() | |||
| expect(debugSolver.debug_exploredNodesOrdered.length).toBeGreaterThan(0) | |||
| expect(Number.isNaN(debugSolver.progress)).toBe(true) | |||
| }) | |||
|
|
|||
| test("SingleHighDensityRouteSolver caches immutable via ancestry", () => { | |||
| const solver = new SingleHighDensityRouteSolver({ | |||
| ...baseOpts, | |||
| A: { x: 0, y: 1, z: 0 }, | |||
| B: { x: 0, y: 9, z: 0 }, | |||
| obstacleRoutes: [], | |||
| captureSearchDebug: false, | |||
| }) | |||
| const root = { x: 0, y: 1, z: 0, parent: null } | |||
| const firstVia = { x: 0, y: 1, z: 1, parent: root } | |||
| const sameLayer = { x: 0.2, y: 1, z: 1, parent: firstVia } | |||
| const secondVia = { x: 0.2, y: 1, z: 0, parent: sameLayer } | |||
|
|
|||
| const firstResult = solver.getViasInNodePath(secondVia as any) | |||
| expect(firstResult).toEqual([ | |||
| { x: 0.2, y: 1 }, | |||
| { x: 0, y: 1 }, | |||
| ]) | |||
| expect(solver.getViasInNodePath(secondVia as any)).toBe(firstResult) | |||
| }) | |||
There was a problem hiding this comment.
This test file now contains more than one test(...) call. The rule states that a *.test.ts file may have AT MOST one test(...), and after that the tests should be split into multiple numbered files (e.g., single-high-density-route-solver1.test.ts, single-high-density-route-solver2.test.ts, etc.). The file already had tests before this PR, and this diff adds several more (lines 47, 189, 219, 243, 274, 294), making the total well above one. These new tests should be extracted into separate numbered test files.
Spotted by Graphite (based on custom rule: Custom rule)
Is this helpful? React 👍 or 👎 to let us know.
| test("SingleRouteCandidatePriorityQueue preserves ascending priority", () => { | ||
| const priorities = [8, 3, 5, 1, 9, 2, 7, 4, 6, 0] | ||
| const queue = new SingleRouteCandidatePriorityQueue( | ||
| priorities.map(createNode), | ||
| ) | ||
| const dequeued: number[] = [] | ||
|
|
||
| while (queue.peek()) { | ||
| dequeued.push(queue.dequeue()!.f) | ||
| } | ||
|
|
||
| expect(dequeued).toEqual([...priorities].sort((a, b) => a - b)) | ||
| expect(queue.dequeue()).toBeNull() | ||
| }) | ||
|
|
||
| test("SingleRouteCandidatePriorityQueue handles equal and single priorities", () => { | ||
| const queue = new SingleRouteCandidatePriorityQueue([ | ||
| createNode(2), | ||
| createNode(2), | ||
| createNode(2), | ||
| ]) | ||
|
|
||
| expect(queue.dequeue()?.f).toBe(2) | ||
| expect(queue.dequeue()?.f).toBe(2) | ||
| expect(queue.dequeue()?.f).toBe(2) | ||
| expect(queue.dequeue()).toBeNull() | ||
| }) |
There was a problem hiding this comment.
This new test file contains two test(...) calls (lines 17 and 32). The rule states that a *.test.ts file may have AT MOST one test(...). The second test should be moved to a separate numbered file, e.g., single-route-candidate-priority-queue1.test.ts and single-route-candidate-priority-queue2.test.ts.
| test("SingleRouteCandidatePriorityQueue preserves ascending priority", () => { | |
| const priorities = [8, 3, 5, 1, 9, 2, 7, 4, 6, 0] | |
| const queue = new SingleRouteCandidatePriorityQueue( | |
| priorities.map(createNode), | |
| ) | |
| const dequeued: number[] = [] | |
| while (queue.peek()) { | |
| dequeued.push(queue.dequeue()!.f) | |
| } | |
| expect(dequeued).toEqual([...priorities].sort((a, b) => a - b)) | |
| expect(queue.dequeue()).toBeNull() | |
| }) | |
| test("SingleRouteCandidatePriorityQueue handles equal and single priorities", () => { | |
| const queue = new SingleRouteCandidatePriorityQueue([ | |
| createNode(2), | |
| createNode(2), | |
| createNode(2), | |
| ]) | |
| expect(queue.dequeue()?.f).toBe(2) | |
| expect(queue.dequeue()?.f).toBe(2) | |
| expect(queue.dequeue()?.f).toBe(2) | |
| expect(queue.dequeue()).toBeNull() | |
| }) | |
| test("SingleRouteCandidatePriorityQueue preserves ascending priority", () => { | |
| const priorities = [8, 3, 5, 1, 9, 2, 7, 4, 6, 0] | |
| const queue = new SingleRouteCandidatePriorityQueue( | |
| priorities.map(createNode), | |
| ) | |
| const dequeued: number[] = [] | |
| while (queue.peek()) { | |
| dequeued.push(queue.dequeue()!.f) | |
| } | |
| expect(dequeued).toEqual([...priorities].sort((a, b) => a - b)) | |
| expect(queue.dequeue()).toBeNull() | |
| }) | |
Spotted by Graphite (based on custom rule: Custom rule)
Is this helpful? React 👍 or 👎 to let us know.
|
Thank you for your contribution! 🎉 PR Rating: ⭐⭐⭐ Track your contributions and see the leaderboard at: tscircuit Contribution Tracker |
What changed
5e428bd5e88a5a74afed195c179783896aef4ca0from Add trace-density region cost option tiny-hypergraph#165.g/hscores.Mapstorage.8eaa775e7c7a2c32c12a82da4edef22477549027from Prune remote projection segment pairs high-density-repair01#16, conservatively pruning remote segment pairs before force-projection exact geometry.Why
Minimizing legacy global-region cost in isolation was not a universal win: several configurations shortened high-density routing but shifted more work into exact-geometry DRC repair. The portfolio spends extra global-routing time only when completed-topology diagnostics predict lower total downstream work.
The first six-dataset same-machine run of the global-routing changes improved aggregate runtime by 1.55%, completion from 490/587 to 495/587, DRC passes from 266 to 268, and timeouts from 96 to 91. Every selected candidate won and the selected subset was 30.8% faster, showing that selector recall—not candidate quality—was the limiting factor. That was still too small as a universal performance win, so the final patch also removes detailed-routing hot-loop overhead without changing the search policy.
Follow-up selector tuning
Both candidates were profiled for every evaluated SRJ19/SRJ20 case and every current timeout. End-to-end matched trials used fresh one-worker processes and equal 150 second caps.
The tuned selector adds five candidates across the observed benchmark population. The full audit preserves primary routing for all other rejected candidates, including known regressions.
Negative controls rejected broader policies: SRJ20 sample 6 changed an 81.1 second completion into a timeout, sample 143 slowed 13.7%, SRJ19 sample 173 remained a high-density timeout, SRJ20 sample 119 remained an exact-repair timeout, and SRJ19 sample 121 was neutral.
Detailed-routing speedup
A more aggressive trace-density factor was rejected after it lowered every tiny-stage pressure metric on promising SRJ19 cases but merely moved their timeout into high-density or exact-geometry repair. CPU profiling then identified behavior-independent overhead in the downstream A* loop.
Matched one-worker trials on eight high-density-heavy dataset01 cases retained identical high-density iteration counts, via counts, DRC messages, completion, and DRC status in every case:
The larger SRJ18 sample 11 control retained 206,760 high-density iterations, 179 vias, and zero DRC errors. Its high-density phase fell from 27.48 to 18.23 seconds (-33.7%, 1.51x faster), and total time fell from 54.22 to 44.71 seconds (-17.5%). A same-process memory comparison on dataset01 sample 32 reduced maximum RSS from 858 MB to 842 MB and peak footprint from 662 MB to 625 MB.
The latest follow-up was measured against commit
4b97a6con the same eight cases. It retained byte-identical final output in every case while adding another 13.9% detailed-routing and 5.5% end-to-end reduction. A separate matched panel measured another 1.5% detailed-routing reduction from the progress guard. Applying those ratios to the preceding exact comparison puts the accepted stack at approximately 1.85x faster in detailed A* and 22% faster end-to-end than the original PR baseline.4b97a6cOn SRJ18 sample 11, the follow-up alone reduced detailed routing from 21.65 s to 19.35 s (-10.6%) with the same 206,760 iterations, 179 vias, zero DRC errors, and byte-identical output. The cleaned final sample-32 memory run used 841 MB maximum RSS and a 623 MB peak footprint, slightly below
4b97a6cat 842 MB / 625 MB.The full experiment ledger is checked in at
experiments/tiny-hypergraph-balanced-routing.md.Route-stitching speedup
The next profile found 710 tentative stitches scanning as many as 14,968
segments and 370 vias on dataset01 sample 32, producing 3.56 million same-net
checks. Dynamic R-tree indexes reduce that to 6,086 checks (-99.8%), while all
nearby candidates still run the original exact geometry tests.
Across the same eight dense dataset01 cases, this follow-up preserved iteration
counts, vias, DRC results, and byte-for-byte final output in every case:
125edc34SRJ18 sample 11 was also byte-identical and improved end-to-end from 48.38 s
to 43.24 s (-10.6%), with stitch time falling from 3.35 s to 44 ms (-98.7%).
SRJ23 sample 39 was byte-identical and improved from 31.87 s to 31.56 s, with
stitch time falling from 300 ms to 9 ms. A matched memory pair increased peak
RSS from 833 MB to 864 MB and footprint from 639 MB to 667 MB (about 3-4%, still
below the 1 GB safety ceiling).
Force-projection and compact-state speedups
The final profile found force projection evaluating exact segment-distance
geometry for every same-layer route pair. A live AABB lower bound now rejects
pairs separated by at least their required clearance; remaining pairs retain
the exact original order, distance calculation, and projection behavior.
Across the same eight dense dataset01 cases, force-improvement time fell from
3.536 s to 2.063 s (-41.7%, 1.71x faster) and end-to-end time fell 3.75%. Every
high-density iteration count, via count, DRC result, and output hash remained
identical. SRJ18 sample 11 was also byte-identical and reduced force time from
1.328 s to 0.703 s (-47.1%).
Enabling tiny-hypergraph's merged compact typed candidate storage reduced its
phase by 11.6% on a separate matched dense panel with identical final region
costs and output. It is bounded by legal incident hops, avoiding the memory
hazard of the former dense port-by-region allocation.
Final official same-machine benchmark
The exact final head (
54191bc) completed all six datasets and 587 scenarios.Compared with current main on the same machine, aggregate scenario time fell
15.3%; P50/P60/P70/P80 fell 26.4%/25.8%/27.5%/30.3%; completion increased from
492 to 510; relaxed DRC passes increased from 266 to 271; and timeouts fell
from 94 to 76. There were 22 improved outcomes and zero regressions.
The result is broad: every dataset improved every non-timeout-capped reported
percentile. Dataset01 P95 improved 36.7% (1.58x), SRJ18 completion improved
12.5 percentage points, SRJ19 completion improved 5.5 points, and SRJ20 P50
improved 37.4% while DRC improved 2.0 points.
A paired-only region audit excludes main timeouts that never emitted tiny
metrics. Across 492-493 directly comparable cases, summed best max region cost
changed +0.24%, summed best total region cost +2.37%, final max occupancy
-0.13%, and squared occupancy -0.54%. This stays comfortably inside the ~20%
region-cost guardrail.
Validation
bun test tests/solvers/tinyhypergraph-candidate-portfolio.test.tsbun test tests/single-high-density-route-solver.test.ts tests/data-structures/single-route-candidate-priority-queue.test.ts tests/features/never-fail-growth-high-density/pipeline7-integration.test.ts tests/features/high-density-future-cost-cmn3.test.tsbun test tests/features/pipeline7-full-pipeline-svg-frames.test.ts tests/pipeline-stage-debug-runner.test.ts tests/high-density-solver-failed-node-visualization.test.tsbun test tests/stitch-solver/collision-aware-stitch-selection-visual.test.ts tests/stitch-solver/multilayer-connection-stitch.test.ts tests/stitch-solver/single-high-density-route-stitch-gap-bridge.test.ts tests/bugs/bugreport44-0ec411-source-net-0-stitch.test.ts tests/bugs/bugreport46-ac4337-source-net-23-stitch-repro.test.ts tests/features/pipeline7-dataset01-circuit107-open-stitch-route.test.tsbunx tsc --noEmitbun run buildbun run format:checkgit diff --checkbun test(14 pass),bunx tsc --noEmit,bun run format:checkbugreport88was intentionally excluded from local testing due its prior RAM behavior. All routing trials used one worker; no timeout was increased.