Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import { ComponentDetectionSolver } from "lib/solvers/ComponentDetectionSolver/C
import { MultiTargetNecessaryCrampedPortPointSolver } from "lib/solvers/NecessaryCrampedPortPointSolver/MultiTargetNecessaryCrampedPortPointSolver"
import { NodeDimensionSubdivisionSolver } from "lib/solvers/NodeDimensionSubdivisionSolver/NodeDimensionSubdivisionSolver"
import { buildHyperGraph } from "lib/solvers/PortPointPathingSolver/hgportpointpathingsolver"
import { TinyHypergraphPortPointPathingSolver } from "lib/solvers/PortPointPathingSolver/tinyhypergraph/TinyHypergraphPortPointPathingSolver"
import {
MAX_CONNECTIONS_FOR_DUPLICATE_CONGESTED_PORT_PREPASS,
TinyHypergraphPortPointPathingSolver,
} from "lib/solvers/PortPointPathingSolver/tinyhypergraph/TinyHypergraphPortPointPathingSolver"
import { TopologyMergingSolver } from "lib/solvers/TopologyMergingSolver/TopologyMergingSolver"
import { MultiGraphTopologyPlannerSolver } from "lib/solvers/TopologyPlanningSolver/MultiGraphTopologyPlannerSolver"
import { UniformPortDistributionSolver } from "lib/solvers/UniformPortDistributionSolver/UniformPortDistributionSolver"
Expand Down Expand Up @@ -96,93 +99,6 @@ type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
onSolved?: (instance: AutoroutingPipelineSolver7_MultiGraph) => void
}

/**
* Collects the capacity mesh node ids produced by component-local topology
* generation.
*
* @param capacityMeshNodes Capacity mesh nodes after topology merging and subdivision.
* @returns A set of component-local capacity mesh node ids.
*/
function getComponentCapacityMeshNodeIds(
capacityMeshNodes: CapacityMeshNode[] | null | undefined,
) {
return new Set(
(capacityMeshNodes ?? [])
.filter((node) => node._isComponentTopologyNode)
.map((node) => node.capacityMeshNodeId),
)
}

/**
* Checks whether a shared edge segment touches a component-local mesh node.
*
* @param segment Shared edge segment produced by AvailableSegmentPointSolver.
* @param componentCapacityMeshNodeIds Component-local capacity mesh node ids.
* @returns True when either node on the segment belongs to a component region.
*/
function isComponentSharedEdgeSegment(
segment: SharedEdgeSegment,
componentCapacityMeshNodeIds: Set<string>,
) {
return segment.nodeIds.some((nodeId) =>
componentCapacityMeshNodeIds.has(nodeId),
)
}

/**
* Removes component-region shared edge segments before running the necessary
* cramped port point solver.
*
* @param params.sharedEdgeSegments Candidate shared edge segments.
* @param params.componentCapacityMeshNodeIds Component-local capacity mesh node ids.
* @returns Shared edge segments that do not touch component-local mesh nodes.
*/
function getNonComponentSharedEdgeSegments({
sharedEdgeSegments,
componentCapacityMeshNodeIds,
}: {
sharedEdgeSegments: SharedEdgeSegment[]
componentCapacityMeshNodeIds: Set<string>
}) {
return sharedEdgeSegments.filter(
(segment) =>
!isComponentSharedEdgeSegment(segment, componentCapacityMeshNodeIds),
)
}

/**
* Restores untouched component-region segments after the necessary cramped port
* point solver filters the non-component mesh.
*
* @param params.originalSharedEdgeSegments Original shared edge segments from AvailableSegmentPointSolver.
* @param params.filteredSharedEdgeSegments Solver-filtered shared edge segments for non-component regions.
* @param params.componentCapacityMeshNodeIds Component-local capacity mesh node ids.
* @returns Shared edge segments where component regions are untouched and other regions use solver output.
*/
function mergeComponentSharedEdgeSegments({
originalSharedEdgeSegments,
filteredSharedEdgeSegments,
componentCapacityMeshNodeIds,
}: {
originalSharedEdgeSegments: SharedEdgeSegment[]
filteredSharedEdgeSegments: SharedEdgeSegment[]
componentCapacityMeshNodeIds: Set<string>
}) {
const filteredSegmentsByEdgeId = new Map(
filteredSharedEdgeSegments.map((segment) => [segment.edgeId, segment]),
)

return originalSharedEdgeSegments.map((segment) => {
// Component-local cramped points are intentionally preserved even if they
// would otherwise be filtered by the necessary cramped port point solver.
if (isComponentSharedEdgeSegment(segment, componentCapacityMeshNodeIds)) {
return segment
}

return filteredSegmentsByEdgeId.get(segment.edgeId) ?? segment
})
}

function definePipelineStep<
T extends new (
...args: any[]
Expand Down Expand Up @@ -411,43 +327,19 @@ export class AutoroutingPipelineSolver7_MultiGraph extends BaseSolver {
definePipelineStep(
"necessaryCrampedPortPointSolver",
MultiTargetNecessaryCrampedPortPointSolver,
(cms) => {
const componentCapacityMeshNodeIds = getComponentCapacityMeshNodeIds(
cms.capacityNodes,
)

return [
{
capacityMeshNodes: cms.capacityNodes!.filter(
(node) =>
!componentCapacityMeshNodeIds.has(node.capacityMeshNodeId),
),
// Do not let the cramped-port solver remove component-local port
// points. Those regions are generated by the topology planner and
// remain valid even when the generated port points are cramped.
sharedEdgeSegments: getNonComponentSharedEdgeSegments({
sharedEdgeSegments: cms.availableSegmentPointSolver!.getOutput(),
componentCapacityMeshNodeIds,
}),
simpleRouteJson: cms.srjWithPointPairs!,
numberOfCrampedPortPointsToKeep: 5,
},
]
},
(cms) => [
{
capacityMeshNodes: cms.capacityNodes!,
sharedEdgeSegments: cms.availableSegmentPointSolver!.getOutput(),
simpleRouteJson: cms.srjWithPointPairs!,
numberOfCrampedPortPointsToKeep: 5,
preserveNonNecessaryMultilayerPorts: false,
},
],
{
onSolved: (cms) => {
const componentCapacityMeshNodeIds = getComponentCapacityMeshNodeIds(
cms.capacityNodes,
)

cms.sharedEdgeSegmentsWithNecessaryCrampedPortPoints =
mergeComponentSharedEdgeSegments({
originalSharedEdgeSegments:
cms.availableSegmentPointSolver!.getOutput(),
filteredSharedEdgeSegments:
cms.necessaryCrampedPortPointSolver!.getOutput(),
componentCapacityMeshNodeIds,
})
cms.necessaryCrampedPortPointSolver!.getOutput()
},
},
),
Expand Down Expand Up @@ -481,6 +373,9 @@ export class AutoroutingPipelineSolver7_MultiGraph extends BaseSolver {
FORCE_CENTER_FIRST: true,
RIPPING_ENABLED: true,
USE_SELECTIVE_RERIP_ROUTING: true,
USE_REGION_PATH_CORRIDORS:
connections.length >
MAX_CONNECTIONS_FOR_DUPLICATE_CONGESTED_PORT_PREPASS,
},
weights: {
SHUFFLE_SEED: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export type MultiTargetNecessaryCrampedPortPointSolverInput = {
* Higher values may be beneficial, but can lead to more DRC errors.
*/
numberOfCrampedPortPointsToKeep: number
/** Set to false to prune unused multilayer ports while retaining each boundary. */
preserveNonNecessaryMultilayerPorts?: boolean
}

/**
Expand Down Expand Up @@ -235,14 +237,16 @@ export class MultiTargetNecessaryCrampedPortPointSolver extends BaseSolver {
return this.filteredOutput
}

this.filteredOutput = this.input.sharedEdgeSegments.map((segment) => ({
...segment,
portPoints: segment.portPoints.flatMap((portPoint) => {
this.filteredOutput = this.input.sharedEdgeSegments.map((segment) => {
const portPoints = segment.portPoints.flatMap((portPoint) => {
if (!portPoint.cramped || this.crampedPortPointsToKeep.has(portPoint)) {
return [portPoint]
}

if (this.isMultilayerEscapePort(portPoint)) {
if (
this.input.preserveNonNecessaryMultilayerPorts !== false &&
this.isMultilayerEscapePort(portPoint)
) {
return [
{
...portPoint,
Expand All @@ -252,8 +256,28 @@ export class MultiTargetNecessaryCrampedPortPointSolver extends BaseSolver {
}

return []
}),
}))
})
if (portPoints.length > 0 || segment.portPoints.length === 0) {
return { ...segment, portPoints }
}

// An empty segment would erase a real region adjacency. Keep the
// centermost physical point, but retain the cramped traversal penalty.
const closestPortPoint = segment.portPoints.reduce((closest, current) =>
current.distToCentermostPortOnZ < closest.distToCentermostPortOnZ
? current
: closest,
)
return {
...segment,
portPoints: [
{
...closestPortPoint,
tinyHypergraphPortPenalty: CRAMPED_NON_NECESSARY_PORT_PENALTY,
},
],
}
})
return this.filteredOutput
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export interface HgPortPointPathingSolverParams {
FORCE_CENTER_FIRST: boolean
RIPPING_ENABLED: boolean
USE_SELECTIVE_RERIP_ROUTING?: boolean
USE_REGION_PATH_CORRIDORS?: boolean
}
weights: {
/** Seed used for deterministic shuffling in rip-selection ordering. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const TINY_SECTION_SOLVER_BASE_OPTIONS: TinyHyperGraphSectionSolverOptions = {
}
const DUPLICATE_PORT_TRAVERSAL_PENALTY = 150
const DEFAULT_CRAMPED_PORT_TRAVERSAL_PENALTY = 150
const MAX_CONNECTIONS_FOR_DUPLICATE_CONGESTED_PORT_PREPASS = 180
export const MAX_CONNECTIONS_FOR_DUPLICATE_CONGESTED_PORT_PREPASS = 180

const getEffortScale = (effort: number) => Math.max(effort, 1e-2)

Expand All @@ -154,12 +154,14 @@ const getTinyViaSizeOptions = (
const getTinyHyperGraphSolveGraphOptions = (
effort: number,
minViaPadDiameter?: number,
useRegionPathCorridors = false,
): TinyHyperGraphSolverOptions => {
const effortScale = getEffortScale(effort)
return {
...TINY_SOLVE_GRAPH_BASE_OPTIONS,
...getTinyViaSizeOptions(minViaPadDiameter),
USE_SPARSE_CANDIDATE_STORAGE: true,
USE_REGION_PATH_CORRIDORS: useRegionPathCorridors,
RIP_THRESHOLD_RAMP_ATTEMPTS: Math.ceil(10 * effortScale),
MAX_ITERATIONS: Math.ceil(2_000_000 * effortScale),
}
Expand All @@ -183,12 +185,14 @@ const getTinyHyperGraphPipelineInput = (
serializedHyperGraph: SerializedHyperGraph,
effort: number,
minViaPadDiameter?: number,
useRegionPathCorridors = false,
): TinyHyperGraphSectionPipelineInput => ({
serializedHyperGraph,
createSectionMask: ({ topology }) => new Int8Array(topology.portCount),
solveGraphOptions: getTinyHyperGraphSolveGraphOptions(
effort,
minViaPadDiameter,
useRegionPathCorridors,
),
sectionSolverOptions: getTinyHyperGraphSectionSolverOptions(
effort,
Expand Down Expand Up @@ -955,6 +959,7 @@ export class TinyHypergraphPortPointPathingSolver extends BaseSolver {
},
params.effort,
params.minViaPadDiameter,
params.flags.USE_REGION_PATH_CORRIDORS === true,
)
this.tinyPipelineSolver =
new TinyHyperGraphSectionPipelineWithTerminalNetIds(
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"recharts": "^2.15.1",
"tailwind-merge": "^3.2.0",
"terser": "^5.43.1",
"tiny-hypergraph": "git+https://github.com/tscircuit/tiny-hypergraph.git#1fe25466462dfacf371e15ca494bc8b8f869aa30",
"tiny-hypergraph": "git+https://github.com/tscircuit/tiny-hypergraph.git#51475d8ec5c0b82d7b4b0bdf90e59ecccca9421a",
"tiny-hypergraph-poly": "git+https://github.com/tscircuit/tiny-hypergraph.git#7b93b4c",
"tsup": "^8.3.6",
"typescript": "^5.9.3",
Expand Down
Loading
Loading