Skip to content
Draft
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
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,42 @@ existing ports and contribute to region congestion immediately, but remain
eligible for the normal rip-and-reroute process. They do not create regions or
otherwise change the hypergraph topology.

### Outside-in partial reripping

`SelectiveReripTinyHyperGraphSolver` preserves the unaffected prefix and
suffix of each route that crosses a hot region. Only a bounded window around
the route's hottest affected segment is reopened. The reopened span is searched
from both retained ends, with a hard geometric travel limit on each frontier;
if the frontiers cannot meet within that limit, the span safely falls back to
the regular one-ended search.

The behavior can be tuned through `TinyHyperGraphSolverOptions`:

```ts
const solver = new SelectiveReripTinyHyperGraphSolver(topology, problem, {
PARTIAL_RIP_ENABLED: true,
PARTIAL_RIP_MIN_ROUTE_COUNT: 100,
PARTIAL_RIP_MAX_ROUTE_COUNT: 350,
PARTIAL_RIP_MAX_DISTANCE: 12,
PARTIAL_RIP_QUALITY_MAX_DISTANCE: 24,
PARTIAL_RIP_MAX_ATTEMPTS: 10,
OUTSIDE_IN_ROUTING: true,
OUTSIDE_IN_MAX_DISTANCE: 24,
})
```

Set `PARTIAL_RIP_ENABLED` or `OUTSIDE_IN_ROUTING` to `false` to use the legacy
whole-route or one-ended behavior respectively.
`PARTIAL_RIP_MIN_ROUTE_COUNT` and `PARTIAL_RIP_MAX_ROUTE_COUNT` provide an
inclusive scale window; graphs outside it use the legacy behavior. The solver
exposes aggregate
partial-rip, retained-segment, frontier-expansion, distance-prune, and fallback
counts through `solver.stats`. When the first completed solution is already
within 1.5 times the configured final rip threshold, the solver uses the
quality-recovery distance (twice the normal distance when unspecified) for the
entire partial-rip run; this gives low-cost solutions enough room to remove a
last hotspot without slowing heavily congested cases.

### Export a solved solver back to `SerializedHyperGraph`

`solver.getOutput()` now returns a `SerializedHyperGraph` for a solved
Expand Down
405 changes: 405 additions & 0 deletions experiments/outside-in-partial-rip.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions lib/DuplicateCongestedPortSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const DUPLICATE_PORT_PROXIMITY = 0.05
export interface DuplicateCongestedPortSolverOptions {
duplicatePortProximity?: number
routeSolveOptions?: TinyHyperGraphSolverOptions
/** Ignore serialized port penalties while estimating shared-port use. */
useSerializedPortPenalties?: boolean
}

export interface DuplicatedPortSummary {
Expand Down Expand Up @@ -326,6 +328,9 @@ export class DuplicateCongestedPortSolver extends BaseSolver {
const { topology, problem } = loadSerializedHyperGraph(
this.serializedHyperGraph,
)
if (this.options.useSerializedPortPenalties === false) {
problem.portPenalty = undefined
}
const portUseCounts = new Map<string, number>()

for (let routeId = 0; routeId < problem.routeCount; routeId++) {
Expand Down
136 changes: 133 additions & 3 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,35 @@ export interface TinyHyperGraphSolverOptions {
STATIC_REACHABILITY_PRECHECK_MAX_HOPS?: number
ACCEPT_BEST_SOLUTION_ON_TIMEOUT?: boolean
GREEDY_FINAL_ROUTE_ITERS?: number
/** Preserve route prefixes/suffixes and reopen only a bounded hot span. */
PARTIAL_RIP_ENABLED?: boolean
/** Minimum route count required to enable partial-rip optimization. */
PARTIAL_RIP_MIN_ROUTE_COUNT?: number
/** Maximum route count allowed to use partial-rip optimization. */
PARTIAL_RIP_MAX_ROUTE_COUNT?: number
/** Maximum old-route distance reopened on either side of a hot segment. */
PARTIAL_RIP_MAX_DISTANCE?: number
/** Larger partial-rip window used when the initial solution is near target. */
PARTIAL_RIP_QUALITY_MAX_DISTANCE?: number
/** Maximum completed partial-rip rounds before restoring the best state. */
PARTIAL_RIP_MAX_ATTEMPTS?: number
/** Whole-graph reseeds allowed before subsequent hot-region partial rips. */
PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS?: number
/**
* Minimum route count before route complexity may break region-cost ties
* inside the configured quality envelope.
*/
PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT?: number
/** Stop after improving the initial max region cost by this fraction. */
PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO?: number
/** Max region-cost growth allowed while preferring a simpler route state. */
PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO?: number
/** Maximum total region-cost growth allowed for an early-stop candidate. */
PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO?: number
/** Search from both active route ends instead of only the start end. */
OUTSIDE_IN_ROUTING?: boolean
/** Maximum geometric distance explored by either outside-in frontier. */
OUTSIDE_IN_MAX_DISTANCE?: number
}

export interface TinyHyperGraphSolverOptionTarget {
Expand All @@ -271,6 +300,19 @@ export interface TinyHyperGraphSolverOptionTarget {
STATIC_REACHABILITY_PRECHECK_MAX_HOPS: number
ACCEPT_BEST_SOLUTION_ON_TIMEOUT: boolean
GREEDY_FINAL_ROUTE_ITERS: number
PARTIAL_RIP_ENABLED?: boolean
PARTIAL_RIP_MIN_ROUTE_COUNT?: number
PARTIAL_RIP_MAX_ROUTE_COUNT?: number
PARTIAL_RIP_MAX_DISTANCE?: number
PARTIAL_RIP_QUALITY_MAX_DISTANCE?: number
PARTIAL_RIP_MAX_ATTEMPTS?: number
PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS?: number
PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT?: number
PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO?: number
PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO?: number
PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO?: number
OUTSIDE_IN_ROUTING?: boolean
OUTSIDE_IN_MAX_DISTANCE?: number
}

export const applyTinyHyperGraphSolverOptions = (
Expand Down Expand Up @@ -326,6 +368,51 @@ export const applyTinyHyperGraphSolverOptions = (
if (options.GREEDY_FINAL_ROUTE_ITERS !== undefined) {
solver.GREEDY_FINAL_ROUTE_ITERS = options.GREEDY_FINAL_ROUTE_ITERS
}
if (options.PARTIAL_RIP_ENABLED !== undefined) {
solver.PARTIAL_RIP_ENABLED = options.PARTIAL_RIP_ENABLED
}
if (options.PARTIAL_RIP_MIN_ROUTE_COUNT !== undefined) {
solver.PARTIAL_RIP_MIN_ROUTE_COUNT = options.PARTIAL_RIP_MIN_ROUTE_COUNT
}
if (options.PARTIAL_RIP_MAX_ROUTE_COUNT !== undefined) {
solver.PARTIAL_RIP_MAX_ROUTE_COUNT = options.PARTIAL_RIP_MAX_ROUTE_COUNT
}
if (options.PARTIAL_RIP_MAX_DISTANCE !== undefined) {
solver.PARTIAL_RIP_MAX_DISTANCE = options.PARTIAL_RIP_MAX_DISTANCE
}
if (options.PARTIAL_RIP_QUALITY_MAX_DISTANCE !== undefined) {
solver.PARTIAL_RIP_QUALITY_MAX_DISTANCE =
options.PARTIAL_RIP_QUALITY_MAX_DISTANCE
}
if (options.PARTIAL_RIP_MAX_ATTEMPTS !== undefined) {
solver.PARTIAL_RIP_MAX_ATTEMPTS = options.PARTIAL_RIP_MAX_ATTEMPTS
}
if (options.PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS !== undefined) {
solver.PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS =
options.PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS
}
if (options.PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT !== undefined) {
solver.PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT =
options.PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT
}
if (options.PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO !== undefined) {
solver.PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO =
options.PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO
}
if (options.PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO !== undefined) {
solver.PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO =
options.PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO
}
if (options.PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO !== undefined) {
solver.PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO =
options.PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO
}
if (options.OUTSIDE_IN_ROUTING !== undefined) {
solver.OUTSIDE_IN_ROUTING = options.OUTSIDE_IN_ROUTING
}
if (options.OUTSIDE_IN_MAX_DISTANCE !== undefined) {
solver.OUTSIDE_IN_MAX_DISTANCE = options.OUTSIDE_IN_MAX_DISTANCE
}
}

export const getTinyHyperGraphSolverOptions = (
Expand All @@ -346,6 +433,24 @@ export const getTinyHyperGraphSolverOptions = (
solver.STATIC_REACHABILITY_PRECHECK_MAX_HOPS,
ACCEPT_BEST_SOLUTION_ON_TIMEOUT: solver.ACCEPT_BEST_SOLUTION_ON_TIMEOUT,
GREEDY_FINAL_ROUTE_ITERS: solver.GREEDY_FINAL_ROUTE_ITERS,
PARTIAL_RIP_ENABLED: solver.PARTIAL_RIP_ENABLED,
PARTIAL_RIP_MIN_ROUTE_COUNT: solver.PARTIAL_RIP_MIN_ROUTE_COUNT,
PARTIAL_RIP_MAX_ROUTE_COUNT: solver.PARTIAL_RIP_MAX_ROUTE_COUNT,
PARTIAL_RIP_MAX_DISTANCE: solver.PARTIAL_RIP_MAX_DISTANCE,
PARTIAL_RIP_QUALITY_MAX_DISTANCE: solver.PARTIAL_RIP_QUALITY_MAX_DISTANCE,
PARTIAL_RIP_MAX_ATTEMPTS: solver.PARTIAL_RIP_MAX_ATTEMPTS,
PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS:
solver.PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS,
PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT:
solver.PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT,
PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO:
solver.PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO,
PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO:
solver.PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO,
PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO:
solver.PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO,
OUTSIDE_IN_ROUTING: solver.OUTSIDE_IN_ROUTING,
OUTSIDE_IN_MAX_DISTANCE: solver.OUTSIDE_IN_MAX_DISTANCE,
})

const compareCandidatesByF = (left: Candidate, right: Candidate) =>
Expand Down Expand Up @@ -391,6 +496,19 @@ export class TinyHyperGraphSolver extends BaseSolver {
STATIC_REACHABILITY_PRECHECK_MAX_HOPS = 16
ACCEPT_BEST_SOLUTION_ON_TIMEOUT = true
GREEDY_FINAL_ROUTE_ITERS = 4
PARTIAL_RIP_ENABLED = false
PARTIAL_RIP_MIN_ROUTE_COUNT = 0
PARTIAL_RIP_MAX_ROUTE_COUNT = Number.POSITIVE_INFINITY
PARTIAL_RIP_MAX_DISTANCE = 12
PARTIAL_RIP_QUALITY_MAX_DISTANCE?: number
PARTIAL_RIP_MAX_ATTEMPTS = Number.POSITIVE_INFINITY
PARTIAL_RIP_WARMUP_FULL_RIP_ATTEMPTS = 0
PARTIAL_RIP_COMPLEXITY_SELECTION_MIN_ROUTE_COUNT = Number.POSITIVE_INFINITY
PARTIAL_RIP_TARGET_MAX_COST_IMPROVEMENT_RATIO = 0
PARTIAL_RIP_MAX_REGION_COST_GROWTH_RATIO = 0.2
PARTIAL_RIP_MAX_TOTAL_COST_GROWTH_RATIO = 0.1
OUTSIDE_IN_ROUTING = false
OUTSIDE_IN_MAX_DISTANCE = 24

constructor(
public topology: TinyHyperGraphTopology,
Expand Down Expand Up @@ -541,7 +659,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
this.routeAttemptCountByRouteId[state.currentRouteId!] += 1

this.resetCandidateBestCosts()
const startingPortId = problem.routeStartPort[state.currentRouteId!]
const startingPortId = this.getRouteStartPortId(state.currentRouteId!)
state.candidateQueue.clear()
const startingNextRegionId = this.getStartingNextRegionId(
state.currentRouteId!,
Expand All @@ -565,7 +683,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
g: 0,
h: 0,
})
state.goalPortId = problem.routeEndPort[state.currentRouteId!]
state.goalPortId = this.getRouteEndPortId(state.currentRouteId!)
}

const currentCandidate = state.candidateQueue.dequeue()
Expand Down Expand Up @@ -721,6 +839,14 @@ export class TinyHyperGraphSolver extends BaseSolver {
)
}

protected getRouteStartPortId(routeId: RouteId): PortId {
return this.problem.routeStartPort[routeId]!
}

protected getRouteEndPortId(routeId: RouteId): PortId {
return this.problem.routeEndPort[routeId]!
}

isPortReservedForDifferentNet(portId: PortId): boolean {
const reservedNetId =
this.problemSetup.portEndpointReservationNetId[portId] ?? -1
Expand Down Expand Up @@ -1095,6 +1221,10 @@ export class TinyHyperGraphSolver extends BaseSolver {
return
}

this.replaceBestSolvedState(summary)
}

protected replaceBestSolvedState(summary: RegionCostSummary) {
this.bestSolvedStateSummary = summary
this.bestSolvedStateSnapshot = cloneSolvedStateSnapshot({
portAssignment: this.state.portAssignment,
Expand Down Expand Up @@ -1516,7 +1646,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
]
}

const endPortId = this.problem.routeEndPort[this.state.currentRouteId!]
const endPortId = this.getRouteEndPortId(this.state.currentRouteId!)
const dx =
this.topology.portX[neighborPortId] - this.topology.portX[endPortId]
const dy =
Expand Down
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./core"
export * from "./distance-aware-tiny-hypergraph-solver"
export * from "./outside-in-partial-rip-tiny-hypergraph-solver"
export * from "./DuplicateCongestedPortSolver"
export * from "./find-distinct-owner-blocker-path"
export * from "./indexed-candidate-heap"
Expand Down
Loading
Loading