@tscircuit/hypergraph 0.0.67 → 0.0.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +20 -5
- package/dist/index.js +472 -157
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -83,6 +83,10 @@ type SerializedRegionPortAssignment = {
|
|
|
83
83
|
type SerializedHyperGraph = {
|
|
84
84
|
ports: SerializedGraphPort[];
|
|
85
85
|
regions: SerializedGraphRegion[];
|
|
86
|
+
solvedRoutes?: SerializedSolvedRoute[];
|
|
87
|
+
connections?: SerializedConnection[];
|
|
88
|
+
_sectionRouteBindings?: SerializedSectionRouteBinding[];
|
|
89
|
+
_sectionCentralRegionId?: RegionId;
|
|
86
90
|
};
|
|
87
91
|
type SerializedCandidate = {
|
|
88
92
|
portId: PortId;
|
|
@@ -100,8 +104,10 @@ type SerializedSolvedRoute = {
|
|
|
100
104
|
connection: SerializedConnection;
|
|
101
105
|
requiredRip: boolean;
|
|
102
106
|
};
|
|
103
|
-
type
|
|
104
|
-
|
|
107
|
+
type SerializedSectionRouteBinding = {
|
|
108
|
+
connectionId: ConnectionId;
|
|
109
|
+
solvedPathStartIndex: number;
|
|
110
|
+
solvedPathEndIndex: number;
|
|
105
111
|
};
|
|
106
112
|
type Connection = {
|
|
107
113
|
connectionId: ConnectionId;
|
|
@@ -120,11 +126,13 @@ declare const convertConnectionsToSerializedConnections: (connections: Connectio
|
|
|
120
126
|
|
|
121
127
|
declare const convertHyperGraphToSerializedHyperGraph: (graph: HyperGraph) => SerializedHyperGraph;
|
|
122
128
|
|
|
129
|
+
declare const createBlankHyperGraph: (inputGraph: SerializedHyperGraph) => SerializedHyperGraph;
|
|
130
|
+
|
|
123
131
|
declare const extractSectionOfHyperGraph: (input: {
|
|
124
|
-
graph:
|
|
132
|
+
graph: SerializedHyperGraph;
|
|
125
133
|
centralRegionId: RegionId;
|
|
126
134
|
expansionHopsFromCentralRegion: number;
|
|
127
|
-
}) =>
|
|
135
|
+
}) => SerializedHyperGraph;
|
|
128
136
|
|
|
129
137
|
type Node = {
|
|
130
138
|
f: number;
|
|
@@ -335,6 +343,13 @@ declare class HyperGraphSolver<RegionType extends Region = Region, RegionPortTyp
|
|
|
335
343
|
_step(): void;
|
|
336
344
|
}
|
|
337
345
|
|
|
346
|
+
declare const reattachSectionToGraph: (input: {
|
|
347
|
+
fullGraph: SerializedHyperGraph;
|
|
348
|
+
solvedSectionGraph: SerializedHyperGraph;
|
|
349
|
+
}) => SerializedHyperGraph;
|
|
350
|
+
|
|
351
|
+
declare const pruneDeadEndPorts: (graph: HyperGraph, retainedPortIds?: Iterable<PortId>) => HyperGraph;
|
|
352
|
+
|
|
338
353
|
type CreateHyperGraphSolverInput = {
|
|
339
354
|
inputGraph: HyperGraph | SerializedHyperGraph;
|
|
340
355
|
inputConnections: (Connection | SerializedConnection)[];
|
|
@@ -1312,4 +1327,4 @@ declare function generateConvexViaTopologyRegions(opts: {
|
|
|
1312
1327
|
};
|
|
1313
1328
|
};
|
|
1314
1329
|
|
|
1315
|
-
export { type Bounds$1 as Bounds, type BuildOpts, type Candidate, ConnectBuilder, type ConnectOpts, type Connection, type ConnectionId, type ConvexViaGraphFromXYConnectionsResult, type CreateHyperGraphSolver, type CreateHyperGraphSolverInput, type GScore, type GraphEdgeId, type HyperGraph, type HyperGraphSection, HyperGraphSectionOptimizer, HyperGraphSolver, type JPort, type JRegion, JUMPER_GRAPH_SOLVER_DEFAULTS, type JumperGraph, JumperGraphSolver, type JumperGraphWithConnections, type NetworkId, type PortAssignment, PortBuilder, type PortData, type PortId, type PortSpread, type Region, RegionBuilder, type RegionData, type RegionId, type RegionPort, type RegionPortAssignment, type RegionRef, type RouteSegment, type SectionRoute, type SerializedCandidate, type SerializedConnection, type SerializedGraphPort, type SerializedGraphRegion, type SerializedHyperGraph, type
|
|
1330
|
+
export { type Bounds$1 as Bounds, type BuildOpts, type Candidate, ConnectBuilder, type ConnectOpts, type Connection, type ConnectionId, type ConvexViaGraphFromXYConnectionsResult, type CreateHyperGraphSolver, type CreateHyperGraphSolverInput, type GScore, type GraphEdgeId, type HyperGraph, type HyperGraphSection, HyperGraphSectionOptimizer, HyperGraphSolver, type JPort, type JRegion, JUMPER_GRAPH_SOLVER_DEFAULTS, type JumperGraph, JumperGraphSolver, type JumperGraphWithConnections, type NetworkId, type PortAssignment, PortBuilder, type PortData, type PortId, type PortSpread, type Region, RegionBuilder, type RegionData, type RegionId, type RegionPort, type RegionPortAssignment, type RegionRef, type RouteSegment, type SectionRoute, type SerializedCandidate, type SerializedConnection, type SerializedGraphPort, type SerializedGraphRegion, type SerializedHyperGraph, type SerializedRegionPortAssignment, type SerializedSectionRouteBinding, type SerializedSolvedRoute, type SharedBoundary, type SolvedRoute, Topology, TopologyError, VIA_GRAPH_SOLVER_DEFAULTS, type ValidateOpts, type ViaByNet, type ViaData, ViaGraphSolver, type ViaGraphWithConnections, type ViaTile, type ViaTileRecommendation, type ViaTileRecommendationCandidate, type ViaTileRecommendationProblemInput, type XYConnection, applyTransformToGraph, calculateGraphBounds, convertConnectionsToSerializedConnections, convertHyperGraphToSerializedHyperGraph, createBlankHyperGraph, createConvexViaGraphFromXYConnections, createGraphWithConnectionsFromBaseGraph, createViaGraphWithConnections, extractSectionOfHyperGraph, generateConvexViaTopologyRegions, generateDefaultViaTopologyRegions, generateJumperGrid, generateJumperX4Grid, generateViaTopologyRegions, pruneDeadEndPorts, reattachSectionToGraph, recommendViaTileFromGraphInput, rotateGraph90Degrees, viaTile4Regions as viaTile };
|
package/dist/index.js
CHANGED
|
@@ -1497,6 +1497,320 @@ var convertHyperGraphToSerializedHyperGraph = (graph) => {
|
|
|
1497
1497
|
};
|
|
1498
1498
|
};
|
|
1499
1499
|
|
|
1500
|
+
// lib/convertSerializedHyperGraphToHyperGraph.ts
|
|
1501
|
+
var convertSerializedHyperGraphToHyperGraph = (inputGraph) => {
|
|
1502
|
+
if (inputGraph.ports.length > 0 && "region1" in inputGraph.ports[0] && typeof inputGraph.ports[0].region1 === "object") {
|
|
1503
|
+
return inputGraph;
|
|
1504
|
+
}
|
|
1505
|
+
const portMap = /* @__PURE__ */ new Map();
|
|
1506
|
+
const regionMap = /* @__PURE__ */ new Map();
|
|
1507
|
+
for (const region of inputGraph.regions) {
|
|
1508
|
+
const { assignments: _, ...regionWithoutAssignments } = region;
|
|
1509
|
+
regionMap.set(region.regionId, {
|
|
1510
|
+
...regionWithoutAssignments,
|
|
1511
|
+
d: regionWithoutAssignments.d ? structuredClone(regionWithoutAssignments.d) : regionWithoutAssignments.d,
|
|
1512
|
+
ports: [],
|
|
1513
|
+
assignments: void 0
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
for (const port of inputGraph.ports) {
|
|
1517
|
+
const region1 = regionMap.get(port.region1Id ?? port.region1?.regionId);
|
|
1518
|
+
const region2 = regionMap.get(port.region2Id ?? port.region2?.regionId);
|
|
1519
|
+
const deserializedPort = {
|
|
1520
|
+
portId: port.portId,
|
|
1521
|
+
region1,
|
|
1522
|
+
region2,
|
|
1523
|
+
d: port.d
|
|
1524
|
+
};
|
|
1525
|
+
portMap.set(port.portId, deserializedPort);
|
|
1526
|
+
region1.ports.push(deserializedPort);
|
|
1527
|
+
region2.ports.push(deserializedPort);
|
|
1528
|
+
}
|
|
1529
|
+
return {
|
|
1530
|
+
ports: Array.from(portMap.values()),
|
|
1531
|
+
regions: Array.from(regionMap.values())
|
|
1532
|
+
};
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
// lib/convertSerializedConnectionsToConnections.ts
|
|
1536
|
+
var convertSerializedConnectionsToConnections = (inputConnections, graph) => {
|
|
1537
|
+
const connections = [];
|
|
1538
|
+
for (const inputConn of inputConnections) {
|
|
1539
|
+
if ("startRegionId" in inputConn) {
|
|
1540
|
+
connections.push({
|
|
1541
|
+
connectionId: inputConn.connectionId,
|
|
1542
|
+
mutuallyConnectedNetworkId: inputConn.mutuallyConnectedNetworkId ?? inputConn.connectionId,
|
|
1543
|
+
startRegion: graph.regions.find(
|
|
1544
|
+
(region) => region.regionId === inputConn.startRegionId
|
|
1545
|
+
),
|
|
1546
|
+
endRegion: graph.regions.find(
|
|
1547
|
+
(region) => region.regionId === inputConn.endRegionId
|
|
1548
|
+
)
|
|
1549
|
+
});
|
|
1550
|
+
} else {
|
|
1551
|
+
connections.push(inputConn);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
return connections;
|
|
1555
|
+
};
|
|
1556
|
+
|
|
1557
|
+
// lib/convertSerializedSolvedRoutesToSolvedRoutes.ts
|
|
1558
|
+
var convertSerializedSolvedRoutesToSolvedRoutes = (inputSolvedRoutes, graph) => {
|
|
1559
|
+
const portMap = new Map(graph.ports.map((port) => [port.portId, port]));
|
|
1560
|
+
const regionMap = new Map(
|
|
1561
|
+
graph.regions.map((region) => [region.regionId, region])
|
|
1562
|
+
);
|
|
1563
|
+
const connectionMap = new Map(
|
|
1564
|
+
convertSerializedConnectionsToConnections(
|
|
1565
|
+
inputSolvedRoutes.map((route) => route.connection),
|
|
1566
|
+
graph
|
|
1567
|
+
).map((connection) => [connection.connectionId, connection])
|
|
1568
|
+
);
|
|
1569
|
+
return inputSolvedRoutes.map((inputSolvedRoute) => {
|
|
1570
|
+
const path = [];
|
|
1571
|
+
for (const originalCandidate of inputSolvedRoute.path) {
|
|
1572
|
+
const port = portMap.get(originalCandidate.portId);
|
|
1573
|
+
if (!port) {
|
|
1574
|
+
throw new Error(
|
|
1575
|
+
`Port ${originalCandidate.portId} not found while deserializing solved route ${inputSolvedRoute.connection.connectionId}`
|
|
1576
|
+
);
|
|
1577
|
+
}
|
|
1578
|
+
const candidate = {
|
|
1579
|
+
port,
|
|
1580
|
+
g: originalCandidate.g,
|
|
1581
|
+
h: originalCandidate.h,
|
|
1582
|
+
f: originalCandidate.f,
|
|
1583
|
+
hops: originalCandidate.hops,
|
|
1584
|
+
ripRequired: originalCandidate.ripRequired
|
|
1585
|
+
};
|
|
1586
|
+
if (originalCandidate.lastPortId) {
|
|
1587
|
+
candidate.lastPort = getRequiredPort(
|
|
1588
|
+
portMap,
|
|
1589
|
+
originalCandidate.lastPortId,
|
|
1590
|
+
inputSolvedRoute.connection.connectionId
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
if (originalCandidate.lastRegionId) {
|
|
1594
|
+
candidate.lastRegion = getRequiredRegion(
|
|
1595
|
+
regionMap,
|
|
1596
|
+
originalCandidate.lastRegionId,
|
|
1597
|
+
inputSolvedRoute.connection.connectionId
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
if (originalCandidate.nextRegionId) {
|
|
1601
|
+
candidate.nextRegion = getRequiredRegion(
|
|
1602
|
+
regionMap,
|
|
1603
|
+
originalCandidate.nextRegionId,
|
|
1604
|
+
inputSolvedRoute.connection.connectionId
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1607
|
+
const parent = path[path.length - 1];
|
|
1608
|
+
if (parent) candidate.parent = parent;
|
|
1609
|
+
path.push(candidate);
|
|
1610
|
+
}
|
|
1611
|
+
const connection = connectionMap.get(
|
|
1612
|
+
inputSolvedRoute.connection.connectionId
|
|
1613
|
+
);
|
|
1614
|
+
if (!connection) {
|
|
1615
|
+
throw new Error(
|
|
1616
|
+
`Connection ${inputSolvedRoute.connection.connectionId} not found while deserializing solved route`
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
return {
|
|
1620
|
+
path,
|
|
1621
|
+
connection,
|
|
1622
|
+
requiredRip: inputSolvedRoute.requiredRip
|
|
1623
|
+
};
|
|
1624
|
+
});
|
|
1625
|
+
};
|
|
1626
|
+
var getRequiredPort = (portMap, portId, connectionId) => {
|
|
1627
|
+
const port = portMap.get(portId);
|
|
1628
|
+
if (!port) {
|
|
1629
|
+
throw new Error(
|
|
1630
|
+
`Port ${portId} not found while deserializing solved route ${connectionId}`
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
return port;
|
|
1634
|
+
};
|
|
1635
|
+
var getRequiredRegion = (regionMap, regionId, connectionId) => {
|
|
1636
|
+
const region = regionMap.get(regionId);
|
|
1637
|
+
if (!region) {
|
|
1638
|
+
throw new Error(
|
|
1639
|
+
`Region ${regionId} not found while deserializing solved route ${connectionId}`
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
return region;
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
// lib/createBlankHyperGraph.ts
|
|
1646
|
+
var createBlankHyperGraph = (inputGraph) => {
|
|
1647
|
+
const deserializedGraph = convertSerializedHyperGraphToHyperGraph(inputGraph);
|
|
1648
|
+
if (!inputGraph.solvedRoutes) {
|
|
1649
|
+
throw new Error(
|
|
1650
|
+
"createBlankHyperGraph requires graph.solvedRoutes to be present"
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
const solvedRoutes = convertSerializedSolvedRoutesToSolvedRoutes(
|
|
1654
|
+
inputGraph.solvedRoutes,
|
|
1655
|
+
deserializedGraph
|
|
1656
|
+
);
|
|
1657
|
+
const removableLeafRegionIds = getRemovableLeafRegionIds(deserializedGraph);
|
|
1658
|
+
const replacedEndpointRegionIds = getReplacedEndpointRegionIds(solvedRoutes);
|
|
1659
|
+
const blankGraph = cloneGraphExcludingRegions(
|
|
1660
|
+
deserializedGraph,
|
|
1661
|
+
removableLeafRegionIds
|
|
1662
|
+
);
|
|
1663
|
+
const connections = [];
|
|
1664
|
+
for (const solvedRoute of solvedRoutes) {
|
|
1665
|
+
const startRegion = getBlankConnectionEndpointRegion({
|
|
1666
|
+
solvedRoute,
|
|
1667
|
+
blankGraph,
|
|
1668
|
+
replacedEndpointRegionIds,
|
|
1669
|
+
endpoint: "start"
|
|
1670
|
+
});
|
|
1671
|
+
const endRegion = getBlankConnectionEndpointRegion({
|
|
1672
|
+
solvedRoute,
|
|
1673
|
+
blankGraph,
|
|
1674
|
+
replacedEndpointRegionIds,
|
|
1675
|
+
endpoint: "end"
|
|
1676
|
+
});
|
|
1677
|
+
connections.push({
|
|
1678
|
+
connectionId: solvedRoute.connection.connectionId,
|
|
1679
|
+
mutuallyConnectedNetworkId: solvedRoute.connection.mutuallyConnectedNetworkId,
|
|
1680
|
+
startRegion,
|
|
1681
|
+
endRegion
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
return {
|
|
1685
|
+
...convertHyperGraphToSerializedHyperGraph(blankGraph),
|
|
1686
|
+
connections: convertConnectionsToSerializedConnections(connections),
|
|
1687
|
+
_sectionCentralRegionId: inputGraph._sectionCentralRegionId,
|
|
1688
|
+
_sectionRouteBindings: inputGraph._sectionRouteBindings ? structuredClone(inputGraph._sectionRouteBindings) : void 0
|
|
1689
|
+
};
|
|
1690
|
+
};
|
|
1691
|
+
var getRemovableLeafRegionIds = (graph) => {
|
|
1692
|
+
return new Set(
|
|
1693
|
+
graph.regions.filter((region) => region.ports.length === 1).map((region) => region.regionId)
|
|
1694
|
+
);
|
|
1695
|
+
};
|
|
1696
|
+
var getReplacedEndpointRegionIds = (solvedRoutes) => {
|
|
1697
|
+
const replacedEndpointRegionIds = /* @__PURE__ */ new Set();
|
|
1698
|
+
for (const solvedRoute of solvedRoutes) {
|
|
1699
|
+
const startCandidate = solvedRoute.path[0];
|
|
1700
|
+
if (startCandidate && shouldReplaceEndpointRegion(
|
|
1701
|
+
solvedRoute.connection.startRegion,
|
|
1702
|
+
startCandidate
|
|
1703
|
+
)) {
|
|
1704
|
+
replacedEndpointRegionIds.add(solvedRoute.connection.startRegion.regionId);
|
|
1705
|
+
}
|
|
1706
|
+
const endCandidate = solvedRoute.path[solvedRoute.path.length - 1];
|
|
1707
|
+
if (endCandidate && shouldReplaceEndpointRegion(
|
|
1708
|
+
solvedRoute.connection.endRegion,
|
|
1709
|
+
endCandidate
|
|
1710
|
+
)) {
|
|
1711
|
+
replacedEndpointRegionIds.add(solvedRoute.connection.endRegion.regionId);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
return replacedEndpointRegionIds;
|
|
1715
|
+
};
|
|
1716
|
+
var shouldReplaceEndpointRegion = (endpointRegion, endpointCandidate) => {
|
|
1717
|
+
return endpointRegion.ports.length === 1 && endpointRegion.ports[0]?.portId === endpointCandidate.port.portId;
|
|
1718
|
+
};
|
|
1719
|
+
var cloneGraphExcludingRegions = (graph, excludedRegionIds) => {
|
|
1720
|
+
const clonedRegionMap = /* @__PURE__ */ new Map();
|
|
1721
|
+
const clonedPorts = [];
|
|
1722
|
+
for (const region of graph.regions) {
|
|
1723
|
+
if (excludedRegionIds.has(region.regionId)) continue;
|
|
1724
|
+
clonedRegionMap.set(region.regionId, {
|
|
1725
|
+
regionId: region.regionId,
|
|
1726
|
+
ports: [],
|
|
1727
|
+
d: region.d ? structuredClone(region.d) : region.d,
|
|
1728
|
+
assignments: []
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
for (const port of graph.ports) {
|
|
1732
|
+
if (excludedRegionIds.has(port.region1.regionId) || excludedRegionIds.has(port.region2.regionId)) {
|
|
1733
|
+
continue;
|
|
1734
|
+
}
|
|
1735
|
+
const clonedPort = {
|
|
1736
|
+
portId: port.portId,
|
|
1737
|
+
region1: clonedRegionMap.get(port.region1.regionId),
|
|
1738
|
+
region2: clonedRegionMap.get(port.region2.regionId),
|
|
1739
|
+
d: port.d ? structuredClone(port.d) : port.d
|
|
1740
|
+
};
|
|
1741
|
+
clonedPort.region1.ports.push(clonedPort);
|
|
1742
|
+
clonedPort.region2.ports.push(clonedPort);
|
|
1743
|
+
clonedPorts.push(clonedPort);
|
|
1744
|
+
}
|
|
1745
|
+
return {
|
|
1746
|
+
regions: Array.from(clonedRegionMap.values()),
|
|
1747
|
+
ports: clonedPorts
|
|
1748
|
+
};
|
|
1749
|
+
};
|
|
1750
|
+
var getBlankConnectionEndpointRegion = (input) => {
|
|
1751
|
+
const { solvedRoute, blankGraph, replacedEndpointRegionIds, endpoint } = input;
|
|
1752
|
+
const originalRegion = endpoint === "start" ? solvedRoute.connection.startRegion : solvedRoute.connection.endRegion;
|
|
1753
|
+
const existingRegion = blankGraph.regions.find(
|
|
1754
|
+
(region) => region.regionId === originalRegion.regionId
|
|
1755
|
+
);
|
|
1756
|
+
if (existingRegion) return existingRegion;
|
|
1757
|
+
if (!replacedEndpointRegionIds.has(originalRegion.regionId)) {
|
|
1758
|
+
throw new Error(
|
|
1759
|
+
`Connection endpoint region ${originalRegion.regionId} is missing from blank graph`
|
|
1760
|
+
);
|
|
1761
|
+
}
|
|
1762
|
+
const endpointCandidate = endpoint === "start" ? solvedRoute.path[0] : solvedRoute.path[solvedRoute.path.length - 1];
|
|
1763
|
+
if (!endpointCandidate) {
|
|
1764
|
+
throw new Error(
|
|
1765
|
+
`Solved route ${solvedRoute.connection.connectionId} has no path candidates`
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
const attachedRegionId = getAttachedRegionId({
|
|
1769
|
+
port: endpointCandidate.port,
|
|
1770
|
+
originalRegionId: originalRegion.regionId,
|
|
1771
|
+
preferredRegionId: endpoint === "start" ? endpointCandidate.nextRegion?.regionId : endpointCandidate.lastRegion?.regionId
|
|
1772
|
+
});
|
|
1773
|
+
if (!attachedRegionId) {
|
|
1774
|
+
throw new Error(
|
|
1775
|
+
`Could not determine ${endpoint} region for connection ${solvedRoute.connection.connectionId}`
|
|
1776
|
+
);
|
|
1777
|
+
}
|
|
1778
|
+
const attachedRegion = blankGraph.regions.find(
|
|
1779
|
+
(region) => region.regionId === attachedRegionId
|
|
1780
|
+
);
|
|
1781
|
+
if (!attachedRegion) {
|
|
1782
|
+
throw new Error(
|
|
1783
|
+
`Region ${attachedRegionId} not found in blank graph for connection ${solvedRoute.connection.connectionId}`
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
const connectionRegion = {
|
|
1787
|
+
regionId: `connection:${solvedRoute.connection.connectionId}:${endpoint}`,
|
|
1788
|
+
ports: [],
|
|
1789
|
+
d: originalRegion.d ? structuredClone(originalRegion.d) : originalRegion.d,
|
|
1790
|
+
assignments: []
|
|
1791
|
+
};
|
|
1792
|
+
blankGraph.regions.push(connectionRegion);
|
|
1793
|
+
const connectionPort = {
|
|
1794
|
+
portId: `connection:${solvedRoute.connection.connectionId}:${endpoint}-port`,
|
|
1795
|
+
region1: connectionRegion,
|
|
1796
|
+
region2: attachedRegion,
|
|
1797
|
+
d: endpointCandidate.port.d ? structuredClone(endpointCandidate.port.d) : endpointCandidate.port.d
|
|
1798
|
+
};
|
|
1799
|
+
connectionRegion.ports.push(connectionPort);
|
|
1800
|
+
attachedRegion.ports.push(connectionPort);
|
|
1801
|
+
blankGraph.ports.push(connectionPort);
|
|
1802
|
+
return connectionRegion;
|
|
1803
|
+
};
|
|
1804
|
+
var getAttachedRegionId = (input) => {
|
|
1805
|
+
const { port, originalRegionId, preferredRegionId } = input;
|
|
1806
|
+
if (preferredRegionId && preferredRegionId !== originalRegionId) {
|
|
1807
|
+
return preferredRegionId;
|
|
1808
|
+
}
|
|
1809
|
+
if (port.region1.regionId !== originalRegionId) return port.region1.regionId;
|
|
1810
|
+
if (port.region2.regionId !== originalRegionId) return port.region2.regionId;
|
|
1811
|
+
return void 0;
|
|
1812
|
+
};
|
|
1813
|
+
|
|
1500
1814
|
// lib/HyperGraphSectionOptimizer/getOrCreateBoundaryRegion.ts
|
|
1501
1815
|
var getOrCreateBoundaryRegion = ({
|
|
1502
1816
|
port,
|
|
@@ -1543,9 +1857,9 @@ var sliceSolvedRouteIntoLocalSection = (input) => {
|
|
|
1543
1857
|
const nextRegion = port.region1 === currentRegion ? port.region2 : port.region1;
|
|
1544
1858
|
path.push({
|
|
1545
1859
|
port,
|
|
1546
|
-
g:
|
|
1547
|
-
h:
|
|
1548
|
-
f:
|
|
1860
|
+
g: 0,
|
|
1861
|
+
h: 0,
|
|
1862
|
+
f: 0,
|
|
1549
1863
|
hops: index,
|
|
1550
1864
|
ripRequired: originalCandidate.ripRequired,
|
|
1551
1865
|
parent: index > 0 ? path[index - 1] : void 0,
|
|
@@ -1656,14 +1970,30 @@ var getSectionOfHyperGraphAsHyperGraph = (input) => {
|
|
|
1656
1970
|
};
|
|
1657
1971
|
const sectionRoutes = [];
|
|
1658
1972
|
const sectionConnections = [];
|
|
1973
|
+
const sectionRouteSegments = [];
|
|
1974
|
+
for (const solvedRoute of solvedRoutes) {
|
|
1975
|
+
const routePathSegment = getRouteSectionSpan(solvedRoute, sectionRegionIds);
|
|
1976
|
+
if (!routePathSegment) continue;
|
|
1977
|
+
const startCandidate = solvedRoute.path[routePathSegment.startIndex];
|
|
1978
|
+
const endCandidate = solvedRoute.path[routePathSegment.endIndex];
|
|
1979
|
+
sectionRouteSegments.push({
|
|
1980
|
+
solvedRoute,
|
|
1981
|
+
solvedPathStartIndex: routePathSegment.startIndex,
|
|
1982
|
+
solvedPathEndIndex: routePathSegment.endIndex,
|
|
1983
|
+
startCandidate,
|
|
1984
|
+
endCandidate
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1659
1987
|
const sectionRegionMap = new Map(
|
|
1660
1988
|
sectionGraph.regions.map((region) => [region.regionId, region])
|
|
1661
1989
|
);
|
|
1662
|
-
for (const
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1990
|
+
for (const {
|
|
1991
|
+
solvedRoute,
|
|
1992
|
+
solvedPathStartIndex,
|
|
1993
|
+
solvedPathEndIndex,
|
|
1994
|
+
startCandidate,
|
|
1995
|
+
endCandidate
|
|
1996
|
+
} of sectionRouteSegments) {
|
|
1667
1997
|
let startRegionId;
|
|
1668
1998
|
let startRegion;
|
|
1669
1999
|
if (sectionRegionIds.has(solvedRoute.connection.startRegion.regionId)) {
|
|
@@ -1740,13 +2070,16 @@ var getSectionOfHyperGraphAsHyperGraph = (input) => {
|
|
|
1740
2070
|
startRegion,
|
|
1741
2071
|
endRegion
|
|
1742
2072
|
};
|
|
1743
|
-
const rawPath = solvedRoute.path.slice(
|
|
2073
|
+
const rawPath = solvedRoute.path.slice(
|
|
2074
|
+
solvedPathStartIndex,
|
|
2075
|
+
solvedPathEndIndex + 1
|
|
2076
|
+
);
|
|
1744
2077
|
const sectionRouteBase = {
|
|
1745
2078
|
globalRoute: solvedRoute,
|
|
1746
2079
|
globalConnection: solvedRoute.connection,
|
|
1747
2080
|
sectionConnection,
|
|
1748
|
-
sectionStartIndex:
|
|
1749
|
-
sectionEndIndex:
|
|
2081
|
+
sectionStartIndex: solvedPathStartIndex,
|
|
2082
|
+
sectionEndIndex: solvedPathEndIndex
|
|
1750
2083
|
};
|
|
1751
2084
|
sectionRoutes.push({
|
|
1752
2085
|
...sectionRouteBase,
|
|
@@ -1771,151 +2104,6 @@ var getSectionOfHyperGraphAsHyperGraph = (input) => {
|
|
|
1771
2104
|
};
|
|
1772
2105
|
};
|
|
1773
2106
|
|
|
1774
|
-
// lib/convertSerializedHyperGraphToHyperGraph.ts
|
|
1775
|
-
var convertSerializedHyperGraphToHyperGraph = (inputGraph) => {
|
|
1776
|
-
if (inputGraph.ports.length > 0 && "region1" in inputGraph.ports[0] && typeof inputGraph.ports[0].region1 === "object") {
|
|
1777
|
-
return inputGraph;
|
|
1778
|
-
}
|
|
1779
|
-
const portMap = /* @__PURE__ */ new Map();
|
|
1780
|
-
const regionMap = /* @__PURE__ */ new Map();
|
|
1781
|
-
for (const region of inputGraph.regions) {
|
|
1782
|
-
const { assignments: _, ...regionWithoutAssignments } = region;
|
|
1783
|
-
regionMap.set(region.regionId, {
|
|
1784
|
-
...regionWithoutAssignments,
|
|
1785
|
-
d: regionWithoutAssignments.d ? structuredClone(regionWithoutAssignments.d) : regionWithoutAssignments.d,
|
|
1786
|
-
ports: [],
|
|
1787
|
-
assignments: void 0
|
|
1788
|
-
});
|
|
1789
|
-
}
|
|
1790
|
-
for (const port of inputGraph.ports) {
|
|
1791
|
-
const region1 = regionMap.get(port.region1Id ?? port.region1?.regionId);
|
|
1792
|
-
const region2 = regionMap.get(port.region2Id ?? port.region2?.regionId);
|
|
1793
|
-
const deserializedPort = {
|
|
1794
|
-
portId: port.portId,
|
|
1795
|
-
region1,
|
|
1796
|
-
region2,
|
|
1797
|
-
d: port.d
|
|
1798
|
-
};
|
|
1799
|
-
portMap.set(port.portId, deserializedPort);
|
|
1800
|
-
region1.ports.push(deserializedPort);
|
|
1801
|
-
region2.ports.push(deserializedPort);
|
|
1802
|
-
}
|
|
1803
|
-
return {
|
|
1804
|
-
ports: Array.from(portMap.values()),
|
|
1805
|
-
regions: Array.from(regionMap.values())
|
|
1806
|
-
};
|
|
1807
|
-
};
|
|
1808
|
-
|
|
1809
|
-
// lib/convertSerializedConnectionsToConnections.ts
|
|
1810
|
-
var convertSerializedConnectionsToConnections = (inputConnections, graph) => {
|
|
1811
|
-
const connections = [];
|
|
1812
|
-
for (const inputConn of inputConnections) {
|
|
1813
|
-
if ("startRegionId" in inputConn) {
|
|
1814
|
-
connections.push({
|
|
1815
|
-
connectionId: inputConn.connectionId,
|
|
1816
|
-
mutuallyConnectedNetworkId: inputConn.mutuallyConnectedNetworkId ?? inputConn.connectionId,
|
|
1817
|
-
startRegion: graph.regions.find(
|
|
1818
|
-
(region) => region.regionId === inputConn.startRegionId
|
|
1819
|
-
),
|
|
1820
|
-
endRegion: graph.regions.find(
|
|
1821
|
-
(region) => region.regionId === inputConn.endRegionId
|
|
1822
|
-
)
|
|
1823
|
-
});
|
|
1824
|
-
} else {
|
|
1825
|
-
connections.push(inputConn);
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
return connections;
|
|
1829
|
-
};
|
|
1830
|
-
|
|
1831
|
-
// lib/convertSerializedSolvedRoutesToSolvedRoutes.ts
|
|
1832
|
-
var convertSerializedSolvedRoutesToSolvedRoutes = (inputSolvedRoutes, graph) => {
|
|
1833
|
-
const portMap = new Map(graph.ports.map((port) => [port.portId, port]));
|
|
1834
|
-
const regionMap = new Map(
|
|
1835
|
-
graph.regions.map((region) => [region.regionId, region])
|
|
1836
|
-
);
|
|
1837
|
-
const connectionMap = new Map(
|
|
1838
|
-
convertSerializedConnectionsToConnections(
|
|
1839
|
-
inputSolvedRoutes.map((route) => route.connection),
|
|
1840
|
-
graph
|
|
1841
|
-
).map((connection) => [connection.connectionId, connection])
|
|
1842
|
-
);
|
|
1843
|
-
return inputSolvedRoutes.map((inputSolvedRoute) => {
|
|
1844
|
-
const path = [];
|
|
1845
|
-
for (const originalCandidate of inputSolvedRoute.path) {
|
|
1846
|
-
const port = portMap.get(originalCandidate.portId);
|
|
1847
|
-
if (!port) {
|
|
1848
|
-
throw new Error(
|
|
1849
|
-
`Port ${originalCandidate.portId} not found while deserializing solved route ${inputSolvedRoute.connection.connectionId}`
|
|
1850
|
-
);
|
|
1851
|
-
}
|
|
1852
|
-
const candidate = {
|
|
1853
|
-
port,
|
|
1854
|
-
g: originalCandidate.g,
|
|
1855
|
-
h: originalCandidate.h,
|
|
1856
|
-
f: originalCandidate.f,
|
|
1857
|
-
hops: originalCandidate.hops,
|
|
1858
|
-
ripRequired: originalCandidate.ripRequired
|
|
1859
|
-
};
|
|
1860
|
-
if (originalCandidate.lastPortId) {
|
|
1861
|
-
candidate.lastPort = getRequiredPort(
|
|
1862
|
-
portMap,
|
|
1863
|
-
originalCandidate.lastPortId,
|
|
1864
|
-
inputSolvedRoute.connection.connectionId
|
|
1865
|
-
);
|
|
1866
|
-
}
|
|
1867
|
-
if (originalCandidate.lastRegionId) {
|
|
1868
|
-
candidate.lastRegion = getRequiredRegion(
|
|
1869
|
-
regionMap,
|
|
1870
|
-
originalCandidate.lastRegionId,
|
|
1871
|
-
inputSolvedRoute.connection.connectionId
|
|
1872
|
-
);
|
|
1873
|
-
}
|
|
1874
|
-
if (originalCandidate.nextRegionId) {
|
|
1875
|
-
candidate.nextRegion = getRequiredRegion(
|
|
1876
|
-
regionMap,
|
|
1877
|
-
originalCandidate.nextRegionId,
|
|
1878
|
-
inputSolvedRoute.connection.connectionId
|
|
1879
|
-
);
|
|
1880
|
-
}
|
|
1881
|
-
const parent = path[path.length - 1];
|
|
1882
|
-
if (parent) candidate.parent = parent;
|
|
1883
|
-
path.push(candidate);
|
|
1884
|
-
}
|
|
1885
|
-
const connection = connectionMap.get(
|
|
1886
|
-
inputSolvedRoute.connection.connectionId
|
|
1887
|
-
);
|
|
1888
|
-
if (!connection) {
|
|
1889
|
-
throw new Error(
|
|
1890
|
-
`Connection ${inputSolvedRoute.connection.connectionId} not found while deserializing solved route`
|
|
1891
|
-
);
|
|
1892
|
-
}
|
|
1893
|
-
return {
|
|
1894
|
-
path,
|
|
1895
|
-
connection,
|
|
1896
|
-
requiredRip: inputSolvedRoute.requiredRip
|
|
1897
|
-
};
|
|
1898
|
-
});
|
|
1899
|
-
};
|
|
1900
|
-
var getRequiredPort = (portMap, portId, connectionId) => {
|
|
1901
|
-
const port = portMap.get(portId);
|
|
1902
|
-
if (!port) {
|
|
1903
|
-
throw new Error(
|
|
1904
|
-
`Port ${portId} not found while deserializing solved route ${connectionId}`
|
|
1905
|
-
);
|
|
1906
|
-
}
|
|
1907
|
-
return port;
|
|
1908
|
-
};
|
|
1909
|
-
var getRequiredRegion = (regionMap, regionId, connectionId) => {
|
|
1910
|
-
const region = regionMap.get(regionId);
|
|
1911
|
-
if (!region) {
|
|
1912
|
-
throw new Error(
|
|
1913
|
-
`Region ${regionId} not found while deserializing solved route ${connectionId}`
|
|
1914
|
-
);
|
|
1915
|
-
}
|
|
1916
|
-
return region;
|
|
1917
|
-
};
|
|
1918
|
-
|
|
1919
2107
|
// lib/convertSolvedRoutesToSerializedSolvedRoutes.ts
|
|
1920
2108
|
var convertSolvedRoutesToSerializedSolvedRoutes = (solvedRoutes) => {
|
|
1921
2109
|
return solvedRoutes.map((solvedRoute) => ({
|
|
@@ -1948,6 +2136,11 @@ var extractSectionOfHyperGraph = (input) => {
|
|
|
1948
2136
|
`Central region ${input.centralRegionId} not found in hypergraph`
|
|
1949
2137
|
);
|
|
1950
2138
|
}
|
|
2139
|
+
if (!input.graph.solvedRoutes) {
|
|
2140
|
+
throw new Error(
|
|
2141
|
+
"extractSectionOfHyperGraph requires graph.solvedRoutes to be present"
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
1951
2144
|
const solvedRoutes = convertSerializedSolvedRoutesToSolvedRoutes(
|
|
1952
2145
|
input.graph.solvedRoutes,
|
|
1953
2146
|
deserializedGraph
|
|
@@ -1960,9 +2153,16 @@ var extractSectionOfHyperGraph = (input) => {
|
|
|
1960
2153
|
});
|
|
1961
2154
|
return {
|
|
1962
2155
|
...convertHyperGraphToSerializedHyperGraph(section.graph),
|
|
2156
|
+
connections: convertConnectionsToSerializedConnections(section.connections),
|
|
1963
2157
|
solvedRoutes: convertSolvedRoutesToSerializedSolvedRoutes(
|
|
1964
2158
|
section.sectionRoutes.map((route) => route.sectionRoute)
|
|
1965
|
-
)
|
|
2159
|
+
),
|
|
2160
|
+
_sectionCentralRegionId: section.centralRegionId,
|
|
2161
|
+
_sectionRouteBindings: section.sectionRoutes.map((route) => ({
|
|
2162
|
+
connectionId: route.globalConnection.connectionId,
|
|
2163
|
+
solvedPathStartIndex: route.sectionStartIndex,
|
|
2164
|
+
solvedPathEndIndex: route.sectionEndIndex
|
|
2165
|
+
}))
|
|
1966
2166
|
};
|
|
1967
2167
|
};
|
|
1968
2168
|
|
|
@@ -2575,6 +2775,118 @@ var HyperGraphSolver = class extends BaseSolver {
|
|
|
2575
2775
|
}
|
|
2576
2776
|
};
|
|
2577
2777
|
|
|
2778
|
+
// lib/reattachSectionToGraph.ts
|
|
2779
|
+
var reattachSectionToGraph = (input) => {
|
|
2780
|
+
const { fullGraph, solvedSectionGraph } = input;
|
|
2781
|
+
if (!fullGraph.solvedRoutes) {
|
|
2782
|
+
throw new Error("reattachSectionToGraph requires fullGraph.solvedRoutes");
|
|
2783
|
+
}
|
|
2784
|
+
if (!solvedSectionGraph.solvedRoutes) {
|
|
2785
|
+
throw new Error(
|
|
2786
|
+
"reattachSectionToGraph requires solvedSectionGraph.solvedRoutes"
|
|
2787
|
+
);
|
|
2788
|
+
}
|
|
2789
|
+
if (!solvedSectionGraph._sectionRouteBindings) {
|
|
2790
|
+
throw new Error(
|
|
2791
|
+
"reattachSectionToGraph requires solvedSectionGraph._sectionRouteBindings"
|
|
2792
|
+
);
|
|
2793
|
+
}
|
|
2794
|
+
const bindingByConnectionId = new Map(
|
|
2795
|
+
solvedSectionGraph._sectionRouteBindings.map((binding) => [
|
|
2796
|
+
binding.connectionId,
|
|
2797
|
+
binding
|
|
2798
|
+
])
|
|
2799
|
+
);
|
|
2800
|
+
const replacementByConnectionId = new Map(
|
|
2801
|
+
solvedSectionGraph.solvedRoutes.map((route) => [
|
|
2802
|
+
route.connection.connectionId,
|
|
2803
|
+
route
|
|
2804
|
+
])
|
|
2805
|
+
);
|
|
2806
|
+
return {
|
|
2807
|
+
...fullGraph,
|
|
2808
|
+
solvedRoutes: fullGraph.solvedRoutes.map((fullSolvedRoute) => {
|
|
2809
|
+
const binding = bindingByConnectionId.get(
|
|
2810
|
+
fullSolvedRoute.connection.connectionId
|
|
2811
|
+
);
|
|
2812
|
+
if (!binding) return fullSolvedRoute;
|
|
2813
|
+
const replacementSolvedRoute = replacementByConnectionId.get(
|
|
2814
|
+
fullSolvedRoute.connection.connectionId
|
|
2815
|
+
);
|
|
2816
|
+
if (!replacementSolvedRoute) return fullSolvedRoute;
|
|
2817
|
+
const replacementInteriorPath = replacementSolvedRoute.path.slice(1, -1);
|
|
2818
|
+
const replacementPath = binding.solvedPathStartIndex === binding.solvedPathEndIndex ? [fullSolvedRoute.path[binding.solvedPathStartIndex]] : [
|
|
2819
|
+
fullSolvedRoute.path[binding.solvedPathStartIndex],
|
|
2820
|
+
...replacementInteriorPath.map((candidate) => ({
|
|
2821
|
+
...candidate
|
|
2822
|
+
})),
|
|
2823
|
+
fullSolvedRoute.path[binding.solvedPathEndIndex]
|
|
2824
|
+
];
|
|
2825
|
+
return {
|
|
2826
|
+
connection: fullSolvedRoute.connection,
|
|
2827
|
+
requiredRip: fullSolvedRoute.requiredRip || replacementSolvedRoute.requiredRip,
|
|
2828
|
+
path: normalizeSerializedPath(
|
|
2829
|
+
[
|
|
2830
|
+
...fullSolvedRoute.path.slice(0, binding.solvedPathStartIndex),
|
|
2831
|
+
...replacementPath.map((candidate) => ({
|
|
2832
|
+
...candidate
|
|
2833
|
+
})),
|
|
2834
|
+
...fullSolvedRoute.path.slice(binding.solvedPathEndIndex + 1)
|
|
2835
|
+
],
|
|
2836
|
+
fullGraph
|
|
2837
|
+
)
|
|
2838
|
+
};
|
|
2839
|
+
})
|
|
2840
|
+
};
|
|
2841
|
+
};
|
|
2842
|
+
var normalizeSerializedPath = (path, graph) => {
|
|
2843
|
+
const portMap = new Map(graph.ports.map((port) => [port.portId, port]));
|
|
2844
|
+
return path.map((candidate, index) => {
|
|
2845
|
+
const previousCandidate = index > 0 ? path[index - 1] : void 0;
|
|
2846
|
+
const nextCandidate = index < path.length - 1 ? path[index + 1] : void 0;
|
|
2847
|
+
return {
|
|
2848
|
+
...candidate,
|
|
2849
|
+
hops: index,
|
|
2850
|
+
lastPortId: previousCandidate?.portId,
|
|
2851
|
+
lastRegionId: previousCandidate ? getSharedRegionId(portMap, previousCandidate.portId, candidate.portId) : void 0,
|
|
2852
|
+
nextRegionId: nextCandidate ? getSharedRegionId(portMap, candidate.portId, nextCandidate.portId) : void 0
|
|
2853
|
+
};
|
|
2854
|
+
});
|
|
2855
|
+
};
|
|
2856
|
+
var getSharedRegionId = (portMap, firstPortId, secondPortId) => {
|
|
2857
|
+
const firstPort = portMap.get(firstPortId);
|
|
2858
|
+
const secondPort = portMap.get(secondPortId);
|
|
2859
|
+
if (!firstPort || !secondPort) return void 0;
|
|
2860
|
+
const firstRegionIds = [firstPort.region1Id, firstPort.region2Id];
|
|
2861
|
+
return firstRegionIds.find(
|
|
2862
|
+
(regionId) => regionId === secondPort.region1Id || regionId === secondPort.region2Id
|
|
2863
|
+
);
|
|
2864
|
+
};
|
|
2865
|
+
|
|
2866
|
+
// lib/pruneDeadEndPorts.ts
|
|
2867
|
+
var pruneDeadEndPorts = (graph, retainedPortIds = []) => {
|
|
2868
|
+
const retainedPortIdSet = new Set(retainedPortIds);
|
|
2869
|
+
const regionPortCounts = new Map(
|
|
2870
|
+
graph.regions.map((region) => [region.regionId, region.ports.length])
|
|
2871
|
+
);
|
|
2872
|
+
const nextPorts = [];
|
|
2873
|
+
for (const region of graph.regions) {
|
|
2874
|
+
region.ports = [];
|
|
2875
|
+
}
|
|
2876
|
+
for (const port of graph.ports) {
|
|
2877
|
+
const isDeadEndPort = regionPortCounts.get(port.region1.regionId) === 1 || regionPortCounts.get(port.region2.regionId) === 1;
|
|
2878
|
+
if (isDeadEndPort && !retainedPortIdSet.has(port.portId)) {
|
|
2879
|
+
continue;
|
|
2880
|
+
}
|
|
2881
|
+
nextPorts.push(port);
|
|
2882
|
+
port.region1.ports.push(port);
|
|
2883
|
+
port.region2.ports.push(port);
|
|
2884
|
+
}
|
|
2885
|
+
graph.ports = nextPorts;
|
|
2886
|
+
graph.regions = graph.regions.filter((region) => region.ports.length > 0);
|
|
2887
|
+
return graph;
|
|
2888
|
+
};
|
|
2889
|
+
|
|
2578
2890
|
// lib/HyperGraphSectionOptimizer/HyperGraphSectionOptimizer.ts
|
|
2579
2891
|
import { BaseSolver as BaseSolver2 } from "@tscircuit/solver-utils";
|
|
2580
2892
|
|
|
@@ -24732,6 +25044,7 @@ export {
|
|
|
24732
25044
|
calculateGraphBounds,
|
|
24733
25045
|
convertConnectionsToSerializedConnections,
|
|
24734
25046
|
convertHyperGraphToSerializedHyperGraph,
|
|
25047
|
+
createBlankHyperGraph,
|
|
24735
25048
|
createConvexViaGraphFromXYConnections,
|
|
24736
25049
|
createGraphWithConnectionsFromBaseGraph,
|
|
24737
25050
|
createViaGraphWithConnections,
|
|
@@ -24741,6 +25054,8 @@ export {
|
|
|
24741
25054
|
generateJumperGrid,
|
|
24742
25055
|
generateJumperX4Grid,
|
|
24743
25056
|
generateViaTopologyRegions,
|
|
25057
|
+
pruneDeadEndPorts,
|
|
25058
|
+
reattachSectionToGraph,
|
|
24744
25059
|
recommendViaTileFromGraphInput,
|
|
24745
25060
|
rotateGraph90Degrees,
|
|
24746
25061
|
via_tile_4_regions_default as viaTile
|