A high density zero-obstacle solver
This is a @tscircuit/solver-utils BaseSolver-compatible solver with the following properties:
- Multi-layer
- Grid-based
- Supports High Density Types from tscircuit-autorouter
- Rip'n'Replace with History (@tscircuit/hypergraph-inspired)
- Via Penalty and Trace Penalty Map
The package exports the solver classes directly:
import {
HighDensitySolverA03,
HighDensitySolverA05,
} from "@tscircuit/high-density-a01"Use HighDensitySolverA03 for the baseline high-density solver:
const solver = new HighDensitySolverA03({
nodeWithPortPoints,
highResolutionCellSize: 0.1,
highResolutionCellThickness: 8,
lowResolutionCellSize: 0.4,
traceThickness: 0.1,
traceMargin: 0.15,
viaDiameter: 0.3,
viaMinDistFromBorder: 0.15,
maxCellCount: 200_000,
stepMultiplier: 4,
hyperParameters: {
shuffleSeed: 0,
ripCost: 8,
ripTracePenalty: 0.5,
ripViaPenalty: 0.75,
viaBaseCost: 0.1,
greedyMultiplier: 1.5,
},
// Optional initial penalty map
// initialPenaltyFn: ({ x, y, px, py, row, col, region }) => ...
})
solver.solve()
const routes = solver.getOutput()Use HighDensitySolverA05 when you want A03-style routing plus route
normalization and force-directed reflow after each solved route:
const solver = new HighDensitySolverA05({
nodeWithPortPoints,
highResolutionCellSize: 0.1,
highResolutionCellThickness: 8,
lowResolutionCellSize: 0.4,
traceThickness: 0.1,
traceMargin: 0.15,
viaDiameter: 0.3,
viaMinDistFromBorder: 0.15,
// A05 defaults
postRouteSegmentCount: 16,
postRouteForceDirectedSteps: 20,
// Initial border-avoidance bias
borderPenaltyStrength: 0.25,
borderPenaltyFalloff: 0.12,
})
solver.solve()
const routes = solver.getOutput()Notes:
HighDensitySolverA05uses the same routing hyperparameters as A03 by default.postRouteSegmentCountcounts vias toward the total segment budget.- The default A05 initial penalty map discourages routing too close to the node
border. Set
borderPenaltyStrength: 0to disable that bias. - Providing
initialPenaltyFnoverrides the built-in A05 border penalty. - The output routes preserve the exact user-provided endpoints.
For A03/A05, we form a two-resolution grid using
highResolutionCellSize, highResolutionCellThickness, and
lowResolutionCellSize.
We compute the initial penalty map from initialPenaltyFn. This function sets
an additional cost of traversal for a cell. It receives x/y in board
coordinates, and px/py in [0,1] relative to the node bounds.
We shuffle the trace order based on the shuffle seed.
We run an A* search for each path from the start to the end. During
exploration, we consider both used and unused cells. Used cells incur rip costs
and trace/via penalties, while vias allow moving between any available layers.
A path that rips the same trace only pays ripCost once, so the search tracks
which traces have already been ripped along that candidate path.
When we reach the end of a path, we mark that route as solved and apply its
occupied cells to the congestion structure. Vias occupy more cells based on
viaDiameter. If a solved route displaced other routes, those routes are ripped
out and added back to the unsolved queue.
For A05, after each solved route we:
- Normalize all solved routes to a fixed total segment count.
- Run a force-directed reflow pass over the solved route set.
- Rebuild occupancy from the updated geometry before routing the next trace.
This creates additional room for later routes at the cost of extra per-route work.
Useful benchmark commands:
bun run scripts/run-dataset02-benchmark-a03.ts --concurrency=4
bun run scripts/run-dataset02-benchmark-a05.ts --concurrency=4A05 tuning examples:
bun run scripts/run-dataset02-benchmark-a05.ts --concurrency=4 --border-penalty-strength=0.25 --border-penalty-falloff=0.12
bun run scripts/run-dataset02-benchmark-a05.ts --concurrency=4 --rip-cost=8 --greedy-multiplier=1.5The high-density-a02 solver is a variant that uses an inner and outer grid to reduce the number of cells while still allowing high density edges

