diff --git a/lib/core.ts b/lib/core.ts index 4d9f13e..58e9004 100644 --- a/lib/core.ts +++ b/lib/core.ts @@ -608,7 +608,17 @@ export class TinyHyperGraphSolver extends BaseSolver { if (assignedNetId !== -1 && assignedNetId !== state.currentRouteNetId) { continue } - this.onPathFound(currentCandidate) + const g = this.computeG(currentCandidate, neighborPortId) + if (!Number.isFinite(g)) continue + this.onPathFound({ + prevRegionId: currentCandidate.nextRegionId, + nextRegionId: currentCandidate.nextRegionId, + portId: neighborPortId, + g, + h: 0, + f: g, + prevCandidate: currentCandidate, + }) return } if (assignedNetId !== -1 && assignedNetId !== state.currentRouteNetId) { @@ -1561,8 +1571,11 @@ export class TinyHyperGraphSolver extends BaseSolver { class GreedyFinalRouteSolver extends TinyHyperGraphSolver { override computeG( currentCandidate: Candidate, - _neighborPortId: PortId, + neighborPortId: PortId, ): number { - return currentCandidate.g + const constrainedCost = super.computeG(currentCandidate, neighborPortId) + return Number.isFinite(constrainedCost) + ? currentCandidate.g + : constrainedCost } } diff --git a/lib/distance-aware-tiny-hypergraph-solver.ts b/lib/distance-aware-tiny-hypergraph-solver.ts index 3064fda..2dfd20e 100644 --- a/lib/distance-aware-tiny-hypergraph-solver.ts +++ b/lib/distance-aware-tiny-hypergraph-solver.ts @@ -46,29 +46,4 @@ export class DistanceAwareTinyHyperGraphSolver extends TinyHyperGraphSolver { this.getPortRoutingCostY(neighborPortId) return baseCost + Math.hypot(dx, dy) * this.DISTANCE_TO_COST } - - override onPathFound(finalCandidate: Candidate): void { - const goalPortId = this.state.goalPortId - if (finalCandidate.portId === goalPortId) { - super.onPathFound(finalCandidate) - return - } - - const g = this.computeG(finalCandidate, goalPortId) - if (!Number.isFinite(g)) return - - const goalHopId = this.getHopId(goalPortId, finalCandidate.nextRegionId) - if (g >= this.getCandidateBestCost(goalHopId)) return - - this.setCandidateBestCost(goalHopId, g) - this.state.candidateQueue.queue({ - prevRegionId: finalCandidate.nextRegionId, - nextRegionId: finalCandidate.nextRegionId, - portId: goalPortId, - g, - h: 0, - f: g, - prevCandidate: finalCandidate, - }) - } } diff --git a/tests/distance-aware-tiny-hypergraph-solver.test.ts b/tests/distance-aware-tiny-hypergraph-solver.test.ts index c8740db..bedee08 100644 --- a/tests/distance-aware-tiny-hypergraph-solver.test.ts +++ b/tests/distance-aware-tiny-hypergraph-solver.test.ts @@ -1,12 +1,31 @@ import { expect, test } from "bun:test" import { + type Candidate, DistanceAwareTinyHyperGraphSolver, type TinyHyperGraphProblem, type TinyHyperGraphTopology, } from "lib/index" import { IndexedCandidateHeap } from "lib/indexed-candidate-heap" -test("queues a costed goal candidate before committing the path", () => { +class ObservedDistanceAwareTinyHyperGraphSolver extends DistanceAwareTinyHyperGraphSolver { + computedHops: Array<{ fromPortId: number; toPortId: number; cost: number }> = + [] + + override computeG( + currentCandidate: Candidate, + neighborPortId: number, + ): number { + const cost = super.computeG(currentCandidate, neighborPortId) + this.computedHops.push({ + fromPortId: currentCandidate.portId, + toPortId: neighborPortId, + cost, + }) + return cost + } +} + +test("costs the final goal hop before committing the path", () => { const topology: TinyHyperGraphTopology = { portCount: 2, regionCount: 2, @@ -33,21 +52,22 @@ test("queues a costed goal candidate before committing the path", () => { routeNet: new Int32Array([0]), regionNetId: new Int32Array([-1, -1]), } - const solver = new DistanceAwareTinyHyperGraphSolver(topology, problem, { - DISTANCE_TO_COST: 2, - STATIC_REACHABILITY_PRECHECK: false, - }) + const solver = new ObservedDistanceAwareTinyHyperGraphSolver( + topology, + problem, + { + DISTANCE_TO_COST: 2, + STATIC_REACHABILITY_PRECHECK: false, + }, + ) solver.step() expect(solver.state.candidateQueue).toBeInstanceOf(IndexedCandidateHeap) - const queuedGoal = solver.state.candidateQueue.toArray()[0] - expect(queuedGoal?.portId).toBe(1) - expect(queuedGoal?.g).toBeGreaterThanOrEqual(20) - expect(solver.state.currentRouteId).toBe(0) - - solver.step() - + const finalHop = solver.computedHops.find( + ({ fromPortId, toPortId }) => fromPortId === 0 && toPortId === 1, + ) + expect(finalHop?.cost).toBeGreaterThanOrEqual(20) expect(solver.state.regionSegments[0]).toEqual([[0, 0, 1]]) expect(solver.state.currentRouteId).toBeUndefined() }) diff --git a/tests/solver/__snapshots__/greedy-final-route-hard-constraints.snap.svg b/tests/solver/__snapshots__/greedy-final-route-hard-constraints.snap.svg index 5a4ae62..075c2a3 100644 --- a/tests/solver/__snapshots__/greedy-final-route-hard-constraints.snap.svg +++ b/tests/solver/__snapshots__/greedy-final-route-hard-constraints.snap.svg @@ -1,14 +1,13 @@