@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 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 SerializedHyperGraphWithSolvedRoutes = SerializedHyperGraph & {
104
- solvedRoutes: SerializedSolvedRoute[];
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: SerializedHyperGraphWithSolvedRoutes;
132
+ graph: SerializedHyperGraph;
125
133
  centralRegionId: RegionId;
126
134
  expansionHopsFromCentralRegion: number;
127
- }) => SerializedHyperGraphWithSolvedRoutes;
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 SerializedHyperGraphWithSolvedRoutes, type SerializedRegionPortAssignment, 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, createConvexViaGraphFromXYConnections, createGraphWithConnectionsFromBaseGraph, createViaGraphWithConnections, extractSectionOfHyperGraph, generateConvexViaTopologyRegions, generateDefaultViaTopologyRegions, generateJumperGrid, generateJumperX4Grid, generateViaTopologyRegions, recommendViaTileFromGraphInput, rotateGraph90Degrees, viaTile4Regions as viaTile };
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: originalCandidate.g,
1547
- h: originalCandidate.h,
1548
- f: originalCandidate.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 solvedRoute of solvedRoutes) {
1663
- const span = getRouteSectionSpan(solvedRoute, sectionRegionIds);
1664
- if (!span) continue;
1665
- const startCandidate = solvedRoute.path[span.startIndex];
1666
- const endCandidate = solvedRoute.path[span.endIndex];
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(span.startIndex, span.endIndex + 1);
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: span.startIndex,
1749
- sectionEndIndex: span.endIndex
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
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/hypergraph",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.67",
4
+ "version": "0.0.69",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",