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
67 changes: 62 additions & 5 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {
isKnownSingleLayerMask,
} from "./computeRegionCost"
import { countNewIntersectionsWithValues } from "./countNewIntersections"
import {
createDirectedRouteHopHeuristic,
getDirectedRouteHopCount,
} from "./directed-route-hop-heuristic"
import {
applyInitialAssignments,
type TinyHyperGraphInitialAssignment,
Expand Down Expand Up @@ -167,6 +171,8 @@ export interface TinyHyperGraphProblem {
export interface TinyHyperGraphProblemSetup {
// portHCostToEndOfRoute[portId * routeCount + routeId] = distance from port to end of route
portHCostToEndOfRoute: Float64Array
/** Directed graph distance is only needed for cross-layer routes. */
directedHopCountToEndByRoute: Array<Int32Array | undefined>
portEndpointNetIds: Array<Set<NetId>>
/** -1 for no endpoint, -2 for endpoints from multiple nets, otherwise the sole endpoint net. */
portEndpointReservationNetId: Int32Array
Expand Down Expand Up @@ -486,9 +492,27 @@ export class TinyHyperGraphSolver extends BaseSolver {
const routeNetId = problem.routeNet[routeId]!
recordEndpointNet(problem.routeStartPort[routeId]!, routeNetId)
recordEndpointNet(problem.routeEndPort[routeId]!, routeNetId)
}

const directedHopCountToEndByRoute: Array<Int32Array | undefined> =
new Array(problem.routeCount)

for (let routeId = 0; routeId < problem.routeCount; routeId++) {
const startPortId = problem.routeStartPort[routeId]!
const endPortId = problem.routeEndPort[routeId]!

if (topology.portZ[startPortId] !== topology.portZ[endPortId]) {
directedHopCountToEndByRoute[routeId] = createDirectedRouteHopHeuristic(
{
topology,
problem,
portEndpointReservationNetId,
routeId,
},
)
}

if (portHCostToEndOfRoute) {
const endPortId = problem.routeEndPort[routeId]
const endX = portX[endPortId]
const endY = portY[endPortId]

Expand All @@ -503,6 +527,7 @@ export class TinyHyperGraphSolver extends BaseSolver {

return {
portHCostToEndOfRoute: portHCostToEndOfRoute as Float64Array,
directedHopCountToEndByRoute,
portEndpointNetIds,
portEndpointReservationNetId,
}
Expand Down Expand Up @@ -629,7 +654,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 @@ -644,6 +668,8 @@ export class TinyHyperGraphSolver extends BaseSolver {
continue
}

const h = this.computeH(neighborPortId, nextRegionId)

const newCandidate = {
prevRegionId: currentCandidate.nextRegionId,
nextRegionId,
Expand Down Expand Up @@ -1529,15 +1555,46 @@ export class TinyHyperGraphSolver extends BaseSolver {
this.logNeverSuccessfullyRoutedRoutes()
}

computeH(neighborPortId: PortId): number {
computeH(neighborPortId: PortId, nextRegionId: RegionId): number {
const precomputedHCost = this.problemSetup.portHCostToEndOfRoute
const routeId = this.state.currentRouteId!
const directedHopCountToEnd =
this.problemSetup.directedHopCountToEndByRoute[routeId]
const startPortId = this.problem.routeStartPort[routeId]!

if (
directedHopCountToEnd &&
this.topology.portZ[neighborPortId] === this.topology.portZ[startPortId]
) {
const directedHopCount = getDirectedRouteHopCount(
this.topology,
directedHopCountToEnd,
neighborPortId,
nextRegionId,
)
if (directedHopCount === -1) return Number.POSITIVE_INFINITY

const directDistanceCost = precomputedHCost
? precomputedHCost[neighborPortId * this.problem.routeCount + routeId]!
: this.computeDirectDistanceHeuristic(neighborPortId, routeId)

return directDistanceCost + directedHopCount * this.DISTANCE_TO_COST
}

if (precomputedHCost) {
return precomputedHCost[
neighborPortId * this.problem.routeCount + this.state.currentRouteId!
neighborPortId * this.problem.routeCount + routeId
]
}

const endPortId = this.problem.routeEndPort[this.state.currentRouteId!]
return this.computeDirectDistanceHeuristic(neighborPortId, routeId)
}

private computeDirectDistanceHeuristic(
neighborPortId: PortId,
routeId: RouteId,
): number {
const endPortId = this.problem.routeEndPort[routeId]!
const dx =
this.getPortRoutingCostX(neighborPortId) -
this.getPortRoutingCostX(endPortId)
Expand Down
148 changes: 148 additions & 0 deletions lib/directed-route-hop-heuristic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import type { TinyHyperGraphProblem, TinyHyperGraphTopology } from "./core"
import type { NetId, PortId, RegionId, RouteId } from "./types"

const UNREACHABLE_HOP_COUNT = -1

interface CreateDirectedRouteHopHeuristicContext {
topology: TinyHyperGraphTopology
problem: TinyHyperGraphProblem
portEndpointReservationNetId: Int32Array
routeId: RouteId
}

const getDirectedHopIndex = (
topology: TinyHyperGraphTopology,
portId: PortId,
nextRegionId: RegionId,
) => {
const incidentRegions = topology.incidentPortRegion[portId] ?? []
if (incidentRegions[0] === nextRegionId) return portId * 2
if (incidentRegions[1] === nextRegionId) return portId * 2 + 1
return -1
}

const isRegionAvailableToNet = (
problem: TinyHyperGraphProblem,
routeNetId: NetId,
regionId: RegionId,
) => {
const reservedNetId = problem.regionNetId[regionId]
return reservedNetId === -1 || reservedNetId === routeNetId
}

const isPortAvailableToNet = (
problem: TinyHyperGraphProblem,
portEndpointReservationNetId: Int32Array,
routeNetId: NetId,
portId: PortId,
) => {
if (problem.portSectionMask[portId] === 0) return false

const reservedNetId = portEndpointReservationNetId[portId] ?? -1
return reservedNetId === -1 || reservedNetId === routeNetId
}

/**
* Computes the remaining number of directed region traversals to a route's
* goal. A directed hop is a port together with the region the candidate will
* enter next, matching the state used by the A* candidate queue.
*/
export const createDirectedRouteHopHeuristic = ({
topology,
problem,
portEndpointReservationNetId,
routeId,
}: CreateDirectedRouteHopHeuristicContext): Int32Array => {
const hopCountToGoal = new Int32Array(topology.portCount * 2).fill(
UNREACHABLE_HOP_COUNT,
)
const routeNetId = problem.routeNet[routeId]!
const goalPortId = problem.routeEndPort[routeId]!
const queuedPortIds: PortId[] = []
const queuedNextRegionIds: RegionId[] = []

const queueHop = (
portId: PortId,
nextRegionId: RegionId,
hopCount: number,
) => {
const directedHopIndex = getDirectedHopIndex(topology, portId, nextRegionId)
if (
directedHopIndex === -1 ||
hopCountToGoal[directedHopIndex] !== UNREACHABLE_HOP_COUNT
) {
return
}

hopCountToGoal[directedHopIndex] = hopCount
queuedPortIds.push(portId)
queuedNextRegionIds.push(nextRegionId)
}

for (const goalRegionId of topology.incidentPortRegion[goalPortId] ?? []) {
if (!isRegionAvailableToNet(problem, routeNetId, goalRegionId)) continue

for (const portId of topology.regionIncidentPorts[goalRegionId] ?? []) {
queueHop(portId, goalRegionId, 0)
}
}

const reverseExpansionCountByRegion = new Uint8Array(topology.regionCount)

for (let queueIndex = 0; queueIndex < queuedPortIds.length; queueIndex++) {
const exitPortId = queuedPortIds[queueIndex]!
const nextRegionId = queuedNextRegionIds[queueIndex]!
if (
!isPortAvailableToNet(
problem,
portEndpointReservationNetId,
routeNetId,
exitPortId,
)
) {
continue
}

const incidentRegions = topology.incidentPortRegion[exitPortId] ?? []
const previousRegionId =
incidentRegions[0] === nextRegionId
? incidentRegions[1]
: incidentRegions[0]
if (
previousRegionId === undefined ||
!isRegionAvailableToNet(problem, routeNetId, previousRegionId) ||
reverseExpansionCountByRegion[previousRegionId]! >= 2
) {
continue
}

reverseExpansionCountByRegion[previousRegionId] += 1
const currentHopIndex = getDirectedHopIndex(
topology,
exitPortId,
nextRegionId,
)
const previousHopCount = hopCountToGoal[currentHopIndex]! + 1

for (const previousPortId of topology.regionIncidentPorts[
previousRegionId
] ?? []) {
if (previousPortId === exitPortId) continue
queueHop(previousPortId, previousRegionId, previousHopCount)
}
}

return hopCountToGoal
}

export const getDirectedRouteHopCount = (
topology: TinyHyperGraphTopology,
hopCountToGoal: Int32Array,
portId: PortId,
nextRegionId: RegionId,
) => {
const directedHopIndex = getDirectedHopIndex(topology, portId, nextRegionId)
return directedHopIndex === -1
? UNREACHABLE_HOP_COUNT
: hopCountToGoal[directedHopIndex]!
}
Loading
Loading