Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 93 additions & 36 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ interface SegmentGeometryScratch {
export class TinyHyperGraphSolver extends BaseSolver {
state: TinyHyperGraphWorkingState
private _problemSetup?: TinyHyperGraphProblemSetup
private edgeDeltaCostByKey = new Map<number, number>()
protected enableEdgeDeltaCostCache = false
private segmentGeometryScratch: SegmentGeometryScratch = {
lesserAngle: 0,
greaterAngle: 0,
Expand Down Expand Up @@ -318,6 +320,12 @@ export class TinyHyperGraphSolver extends BaseSolver {
void this.problemSetup
}

protected clearEdgeDeltaCostCache() {
if (this.enableEdgeDeltaCostCache) {
this.edgeDeltaCostByKey.clear()
}
}

override _step() {
const { problem, topology, state } = this

Expand All @@ -331,6 +339,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
state.currentRouteNetId = problem.routeNet[state.currentRouteId!]

this.resetCandidateBestCosts()
this.clearEdgeDeltaCostCache()
const startingPortId = problem.routeStartPort[state.currentRouteId!]
state.candidateQueue.clear()
const startingNextRegionId = this.getStartingNextRegionId(
Expand Down Expand Up @@ -377,8 +386,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
return
}

const neighbors =
topology.regionIncidentPorts[currentCandidate.nextRegionId]
const neighbors = topology.regionIncidentPorts[currentCandidate.nextRegionId]

for (const neighborPortId of neighbors) {
const assignedRouteId = state.portAssignment[neighborPortId]
Expand All @@ -399,7 +407,6 @@ export class TinyHyperGraphSolver extends BaseSolver {

const g = this.computeG(currentCandidate, neighborPortId)
if (!Number.isFinite(g)) continue
const h = this.computeH(neighborPortId)

const nextRegionId =
topology.incidentPortRegion[neighborPortId][0] ===
Expand All @@ -414,26 +421,20 @@ export class TinyHyperGraphSolver extends BaseSolver {
continue
}

const newCandidate = {
const candidateHopId = this.getHopId(neighborPortId, nextRegionId)
if (g >= this.getCandidateBestCost(candidateHopId)) continue

const h = this.computeH(neighborPortId)
this.setCandidateBestCost(candidateHopId, g)
state.candidateQueue.queue({
prevRegionId: currentCandidate.nextRegionId,
nextRegionId,
portId: neighborPortId,
g,
h,
f: g + h,
prevCandidate: currentCandidate,
}

if (neighborPortId === state.goalPortId) {
this.onPathFound(newCandidate)
return
}

const candidateHopId = this.getHopId(neighborPortId, nextRegionId)
if (g >= this.getCandidateBestCost(candidateHopId)) continue

this.setCandidateBestCost(candidateHopId, g)
state.candidateQueue.queue(newCandidate)
})
}
}

Expand Down Expand Up @@ -660,6 +661,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
resetRoutingStateForRerip() {
const { topology, problem, state } = this

this.clearEdgeDeltaCostCache()
state.portAssignment.fill(-1)
state.regionSegments = Array.from(
{ length: topology.regionCount },
Expand Down Expand Up @@ -770,60 +772,115 @@ export class TinyHyperGraphSolver extends BaseSolver {
this.appendSegmentToRegionCache(regionId, fromPortId, toPortId)
}

this.clearEdgeDeltaCostCache()
state.candidateQueue.clear()
state.currentRouteNetId = undefined
state.currentRouteId = undefined
}

computeG(currentCandidate: Candidate, neighborPortId: PortId): number {
const { topology, state } = this

const nextRegionId = currentCandidate.nextRegionId

const regionCache = state.regionIntersectionCaches[nextRegionId]
const segmentRegionId = currentCandidate.nextRegionId
const segmentGeometry = this.populateSegmentGeometryScratch(
nextRegionId,
segmentRegionId,
currentCandidate.portId,
neighborPortId,
)
const edgeDeltaCost = this.computeEdgeDeltaCost(
segmentRegionId,
this.getEdgeCostKey(
segmentRegionId,
currentCandidate.portId,
neighborPortId,
),
segmentGeometry.lesserAngle,
segmentGeometry.greaterAngle,
segmentGeometry.layerMask,
segmentGeometry.entryExitLayerChanges,
)

if (!Number.isFinite(edgeDeltaCost)) {
return Number.POSITIVE_INFINITY
}

return (
currentCandidate.g +
edgeDeltaCost +
this.state.regionCongestionCost[segmentRegionId]
)
}

protected getEdgeCostKey(
segmentRegionId: RegionId,
port1Id: PortId,
port2Id: PortId,
) {
const lesserPortId = port1Id < port2Id ? port1Id : port2Id
const greaterPortId = port1Id < port2Id ? port2Id : port1Id

return (
segmentRegionId * this.topology.portCount * this.topology.portCount +
lesserPortId * this.topology.portCount +
greaterPortId
)
}

protected computeEdgeDeltaCost(
segmentRegionId: RegionId,
edgeCostKey: number,
lesserAngle: number,
greaterAngle: number,
layerMask: number,
entryExitLayerChanges: number,
) {
const cachedEdgeDeltaCost = this.enableEdgeDeltaCostCache
? this.edgeDeltaCostByKey.get(edgeCostKey)
: undefined

if (cachedEdgeDeltaCost !== undefined) {
return cachedEdgeDeltaCost
}

const regionCache = this.state.regionIntersectionCaches[segmentRegionId]
const [
newSameLayerIntersections,
newCrossLayerIntersections,
newEntryExitLayerChanges,
] = countNewIntersectionsWithValues(
regionCache,
state.currentRouteNetId!,
segmentGeometry.lesserAngle,
segmentGeometry.greaterAngle,
segmentGeometry.layerMask,
segmentGeometry.entryExitLayerChanges,
this.state.currentRouteNetId!,
lesserAngle,
greaterAngle,
layerMask,
entryExitLayerChanges,
)

if (
newSameLayerIntersections > 0 &&
this.isKnownSingleLayerRegion(nextRegionId)
this.isKnownSingleLayerRegion(segmentRegionId)
) {
if (this.enableEdgeDeltaCostCache) {
this.edgeDeltaCostByKey.set(edgeCostKey, Number.POSITIVE_INFINITY)
}
return Number.POSITIVE_INFINITY
}

const newRegionCost =
computeRegionCost(
topology.regionWidth[nextRegionId],
topology.regionHeight[nextRegionId],
this.topology.regionWidth[segmentRegionId],
this.topology.regionHeight[segmentRegionId],
regionCache.existingSameLayerIntersections + newSameLayerIntersections,
regionCache.existingCrossingLayerIntersections +
newCrossLayerIntersections,
regionCache.existingEntryExitLayerChanges + newEntryExitLayerChanges,
regionCache.existingSegmentCount + 1,
topology.regionAvailableZMask?.[nextRegionId] ?? 0,
this.topology.regionAvailableZMask?.[segmentRegionId] ?? 0,
) - regionCache.existingRegionCost

return (
currentCandidate.g +
newRegionCost +
state.regionCongestionCost[nextRegionId]
)
if (this.enableEdgeDeltaCostCache) {
this.edgeDeltaCostByKey.set(edgeCostKey, newRegionCost)
}

return newRegionCost
}

computeH(neighborPortId: PortId): number {
Expand Down
54 changes: 43 additions & 11 deletions lib/section-solver/TinyHyperGraphSectionPipelineSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import type {
import { TinyHyperGraphSolver } from "../core"
import type { RegionId } from "../types"
import type { TinyHyperGraphSectionSolverOptions } from "./index"
import { getActiveSectionRouteIds, TinyHyperGraphSectionSolver } from "./index"
import {
getActiveSectionRouteIds,
getOrderedRoutePaths,
TinyHyperGraphSectionSolver,
} from "./index"

/**
* Candidate section families used by the automatic section-mask search.
Expand Down Expand Up @@ -89,6 +93,21 @@ const getMaxRegionCost = (solver: TinyHyperGraphSolver) =>
0,
)

const summarizeSolverRegionCosts = (
solver: TinyHyperGraphSolver,
): { maxRegionCost: number; totalRegionCost: number } =>
solver.state.regionIntersectionCaches.reduce(
(summary, regionIntersectionCache) => ({
maxRegionCost: Math.max(
summary.maxRegionCost,
regionIntersectionCache.existingRegionCost,
),
totalRegionCost:
summary.totalRegionCost + regionIntersectionCache.existingRegionCost,
}),
{ maxRegionCost: 0, totalRegionCost: 0 },
)

const getSerializedOutputMaxRegionCost = (
serializedHyperGraph: SerializedHyperGraph,
) => {
Expand Down Expand Up @@ -235,15 +254,13 @@ const findBestAutomaticSectionMask = (
): AutomaticSectionSearchResult => {
const searchStartTime = performance.now()
const baselineEvaluationStartTime = performance.now()
const baselineSectionSolver = new TinyHyperGraphSectionSolver(
topology,
problem,
solution,
sectionSolverOptions,
)
const baselineMaxRegionCost = getMaxRegionCost(
baselineSectionSolver.baselineSolver,
)
const orderedRoutePaths = getOrderedRoutePaths(topology, problem, solution)
const sharedBaseline = {
baselineSolver: solvedSolver,
baselineSummary: summarizeSolverRegionCosts(solvedSolver),
orderedRoutePaths,
}
const baselineMaxRegionCost = sharedBaseline.baselineSummary.maxRegionCost
const baselineEvaluationMs = performance.now() - baselineEvaluationStartTime

let bestFinalMaxRegionCost = baselineMaxRegionCost
Expand Down Expand Up @@ -293,6 +310,7 @@ const findBestAutomaticSectionMask = (
topology,
candidateProblem,
solution,
orderedRoutePaths,
)
candidateEligibilityMs += performance.now() - eligibilityStartTime

Expand All @@ -308,6 +326,7 @@ const findBestAutomaticSectionMask = (
candidateProblem,
solution,
sectionSolverOptions,
sharedBaseline,
)
candidateInitMs += performance.now() - candidateInitStartTime

Expand Down Expand Up @@ -425,6 +444,13 @@ export class TinyHyperGraphSectionPipelineSolver extends BasePipelineSolver<Tiny
TinyHyperGraphProblem,
TinyHyperGraphSolution,
TinyHyperGraphSectionSolverOptions,
{
baselineSolver: TinyHyperGraphSolver
baselineSummary: {
maxRegionCost: number
totalRegionCost: number
}
},
] {
const solvedSerializedHyperGraph =
this.getStageOutput<SerializedHyperGraph>("solveGraph")
Expand All @@ -448,6 +474,12 @@ export class TinyHyperGraphSectionPipelineSolver extends BasePipelineSolver<Tiny
const { topology, problem, solution } = loadSerializedHyperGraph(
solvedSerializedHyperGraph,
)
const orderedRoutePaths = getOrderedRoutePaths(topology, problem, solution)
const sharedBaseline = {
baselineSolver: solvedSolver,
baselineSummary: summarizeSolverRegionCosts(solvedSolver),
orderedRoutePaths,
}

const portSectionMask = this.inputProblem.createSectionMask
? this.inputProblem.createSectionMask({
Expand Down Expand Up @@ -512,7 +544,7 @@ export class TinyHyperGraphSectionPipelineSolver extends BasePipelineSolver<Tiny
.length,
}

return [topology, problem, solution, sectionSolverOptions]
return [topology, problem, solution, sectionSolverOptions, sharedBaseline]
}

getInitialVisualizationSolver() {
Expand Down
Loading
Loading