@tscircuit/capacity-autorouter 0.0.55 → 0.0.57

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.js CHANGED
@@ -47,6 +47,7 @@ var BaseSolver = class {
47
47
  activeSubSolver;
48
48
  failedSubSolvers;
49
49
  timeToSolve;
50
+ stats = {};
50
51
  /** DO NOT OVERRIDE! Override _step() instead */
51
52
  step() {
52
53
  if (this.solved) return;
@@ -65,6 +66,9 @@ var BaseSolver = class {
65
66
  console.error(this.error);
66
67
  this.failed = true;
67
68
  }
69
+ if ("computeProgress" in this) {
70
+ this.progress = this.computeProgress();
71
+ }
68
72
  }
69
73
  _step() {
70
74
  }
@@ -2902,7 +2906,7 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
2902
2906
  }
2903
2907
  };
2904
2908
 
2905
- // node_modules/@tscircuit/math-utils/dist/chunk-CHQOCSFB.js
2909
+ // node_modules/@tscircuit/math-utils/dist/chunk-3453HRP7.js
2906
2910
  function doSegmentsIntersect(p1, q1, p2, q2) {
2907
2911
  const o1 = orientation(p1, q1, p2);
2908
2912
  const o2 = orientation(p1, q1, q2);
@@ -2941,6 +2945,27 @@ function distance(p1, p2) {
2941
2945
  const dy = p1.y - p2.y;
2942
2946
  return Math.sqrt(dx * dx + dy * dy);
2943
2947
  }
2948
+ function getSegmentIntersection(a, b, u, v) {
2949
+ const dx1 = b.x - a.x;
2950
+ const dy1 = b.y - a.y;
2951
+ const dx2 = v.x - u.x;
2952
+ const dy2 = v.y - u.y;
2953
+ const dx3 = a.x - u.x;
2954
+ const dy3 = a.y - u.y;
2955
+ const denominator = dx1 * dy2 - dy1 * dx2;
2956
+ if (Math.abs(denominator) < 1e-10) {
2957
+ return null;
2958
+ }
2959
+ const t = (dy3 * dx2 - dx3 * dy2) / denominator;
2960
+ const s = (dx1 * dy3 - dy1 * dx3) / denominator;
2961
+ const epsilon = 1e-9;
2962
+ if (t >= -epsilon && t <= 1 + epsilon && s >= -epsilon && s <= 1 + epsilon) {
2963
+ const intersectionX = a.x + t * dx1;
2964
+ const intersectionY = a.y + t * dy1;
2965
+ return { x: intersectionX, y: intersectionY };
2966
+ }
2967
+ return null;
2968
+ }
2944
2969
 
2945
2970
  // node_modules/@tscircuit/math-utils/dist/chunk-MHHTZHOJ.js
2946
2971
  function getBoundingBox(box) {
@@ -2974,7 +2999,7 @@ function clamp(value, min, max) {
2974
2999
  return Math.max(min, Math.min(max, value));
2975
3000
  }
2976
3001
 
2977
- // node_modules/@tscircuit/math-utils/dist/chunk-RNQKFERU.js
3002
+ // node_modules/@tscircuit/math-utils/dist/chunk-FWQGMQBW.js
2978
3003
  function segmentToSegmentMinDistance(a, b, u, v) {
2979
3004
  if (a.x === b.x && a.y === b.y) {
2980
3005
  return pointToSegmentDistance(a, u, v);
@@ -3053,6 +3078,14 @@ function pointToSegmentClosestPoint(p, a, b) {
3053
3078
  return closestPoint;
3054
3079
  }
3055
3080
 
3081
+ // node_modules/@tscircuit/math-utils/dist/chunk-SLG2OU3P.js
3082
+ function midpoint(p1, p2) {
3083
+ return {
3084
+ x: (p1.x + p2.x) / 2,
3085
+ y: (p1.y + p2.y) / 2
3086
+ };
3087
+ }
3088
+
3056
3089
  // lib/data-structures/SingleRouteCandidatePriorityQueue.ts
3057
3090
  var SingleRouteCandidatePriorityQueue = class {
3058
3091
  heap = [];
@@ -4008,12 +4041,15 @@ var HyperParameterSupervisorSolver = class extends BaseSolver {
4008
4041
  }
4009
4042
  return bestSolver;
4010
4043
  }
4044
+ getFailureMessage() {
4045
+ return "All solvers failed in hyper solver.";
4046
+ }
4011
4047
  _step() {
4012
4048
  if (!this.supervisedSolvers) this.initializeSolvers();
4013
4049
  const supervisedSolver = this.getSupervisedSolverWithBestFitness();
4014
4050
  if (!supervisedSolver) {
4015
4051
  this.failed = true;
4016
- this.error = "All solvers failed";
4052
+ this.error = this.getFailureMessage();
4017
4053
  return;
4018
4054
  }
4019
4055
  for (let i = 0; i < this.MIN_SUBSTEPS; i++) {
@@ -6133,6 +6169,23 @@ var SingleTransitionCrossingRouteSolver = class extends BaseSolver {
6133
6169
  }
6134
6170
  };
6135
6171
 
6172
+ // lib/utils/getPortPairs.ts
6173
+ var getPortPairMap = (nodeWithPortPoints) => {
6174
+ const portPairMap = /* @__PURE__ */ new Map();
6175
+ nodeWithPortPoints.portPoints.forEach((portPoint) => {
6176
+ if (!portPairMap.has(portPoint.connectionName)) {
6177
+ portPairMap.set(portPoint.connectionName, {
6178
+ start: portPoint,
6179
+ end: null,
6180
+ connectionName: portPoint.connectionName
6181
+ });
6182
+ } else {
6183
+ portPairMap.get(portPoint.connectionName).end = portPoint;
6184
+ }
6185
+ });
6186
+ return portPairMap;
6187
+ };
6188
+
6136
6189
  // lib/utils/generateColorMapFromNodeWithPortPoints.ts
6137
6190
  var generateColorMapFromNodeWithPortPoints = (nodeWithPortPoints, connMap) => {
6138
6191
  const colorMap = {};
@@ -6142,6 +6195,320 @@ var generateColorMapFromNodeWithPortPoints = (nodeWithPortPoints, connMap) => {
6142
6195
  return colorMap;
6143
6196
  };
6144
6197
 
6198
+ // lib/solvers/ViaPossibilitiesSolver/ViaPossibilitiesSolver2.ts
6199
+ var ViaPossibilitiesSolver2 = class extends BaseSolver {
6200
+ bounds;
6201
+ maxViaCount;
6202
+ portPairMap;
6203
+ colorMap;
6204
+ nodeWidth;
6205
+ availableZ;
6206
+ hyperParameters;
6207
+ VIA_INTERSECTION_BUFFER_DISTANCE = 0.05;
6208
+ PLACEHOLDER_WALL_BUFFER_DISTANCE = 0.1;
6209
+ NEW_HEAD_WALL_BUFFER_DISTANCE = 0.05;
6210
+ unprocessedConnections;
6211
+ completedPaths = /* @__PURE__ */ new Map();
6212
+ placeholderPaths = /* @__PURE__ */ new Map();
6213
+ currentHead;
6214
+ currentConnectionName;
6215
+ currentPath;
6216
+ constructor({
6217
+ nodeWithPortPoints,
6218
+ colorMap,
6219
+ hyperParameters
6220
+ }) {
6221
+ super();
6222
+ this.MAX_ITERATIONS = 1e5;
6223
+ this.colorMap = colorMap ?? generateColorMapFromNodeWithPortPoints(nodeWithPortPoints);
6224
+ this.maxViaCount = 5;
6225
+ this.bounds = getBoundsFromNodeWithPortPoints(nodeWithPortPoints);
6226
+ this.nodeWidth = this.bounds.maxX - this.bounds.minX;
6227
+ this.portPairMap = getPortPairMap(nodeWithPortPoints);
6228
+ this.stats.solutionsFound = 0;
6229
+ this.availableZ = nodeWithPortPoints.availableZ ?? [0, 1];
6230
+ this.hyperParameters = hyperParameters ?? {
6231
+ SHUFFLE_SEED: 0
6232
+ };
6233
+ this.unprocessedConnections = Array.from(this.portPairMap.keys()).sort();
6234
+ if (hyperParameters?.SHUFFLE_SEED) {
6235
+ this.unprocessedConnections = cloneAndShuffleArray(
6236
+ this.unprocessedConnections,
6237
+ hyperParameters.SHUFFLE_SEED
6238
+ );
6239
+ }
6240
+ const nodeCenterX = (this.bounds.minX + this.bounds.maxX) / 2;
6241
+ const nodeCenterY = (this.bounds.minY + this.bounds.maxY) / 2;
6242
+ for (const [connectionName, { start: start2, end }] of this.portPairMap.entries()) {
6243
+ if (start2.z === end.z) {
6244
+ const isVertical = Math.abs(start2.x - end.x) < 1e-9;
6245
+ const isHorizontal = Math.abs(start2.y - end.y) < 1e-9;
6246
+ if (isVertical || isHorizontal) {
6247
+ this.placeholderPaths.set(connectionName, [
6248
+ start2,
6249
+ this._padByPlaceholderWallBuffer(start2),
6250
+ this._padByPlaceholderWallBuffer(end),
6251
+ end
6252
+ ]);
6253
+ } else {
6254
+ this.placeholderPaths.set(connectionName, [start2, end]);
6255
+ }
6256
+ } else {
6257
+ const midX = (start2.x + end.x) / 2;
6258
+ const midY = (start2.y + end.y) / 2;
6259
+ const midStart = this._padByPlaceholderWallBuffer({
6260
+ x: midX,
6261
+ y: midY,
6262
+ z: start2.z
6263
+ });
6264
+ const midEnd = this._padByPlaceholderWallBuffer({
6265
+ x: midX,
6266
+ y: midY,
6267
+ z: end.z
6268
+ });
6269
+ this.placeholderPaths.set(connectionName, [
6270
+ start2,
6271
+ this._padByPlaceholderWallBuffer(start2),
6272
+ midStart,
6273
+ midEnd,
6274
+ this._padByPlaceholderWallBuffer(end),
6275
+ end
6276
+ ]);
6277
+ }
6278
+ }
6279
+ this.currentConnectionName = this.unprocessedConnections.pop();
6280
+ const start = this.portPairMap.get(this.currentConnectionName).start;
6281
+ this.currentHead = this._padByNewHeadWallBuffer(start);
6282
+ this.currentPath = [start, this.currentHead];
6283
+ this.placeholderPaths.delete(this.currentConnectionName);
6284
+ }
6285
+ _padByNewHeadWallBuffer(point) {
6286
+ return {
6287
+ x: clamp(
6288
+ point.x,
6289
+ this.bounds.minX + this.NEW_HEAD_WALL_BUFFER_DISTANCE,
6290
+ this.bounds.maxX - this.NEW_HEAD_WALL_BUFFER_DISTANCE
6291
+ ),
6292
+ y: clamp(
6293
+ point.y,
6294
+ this.bounds.minY + this.NEW_HEAD_WALL_BUFFER_DISTANCE,
6295
+ this.bounds.maxY - this.NEW_HEAD_WALL_BUFFER_DISTANCE
6296
+ ),
6297
+ z: point.z
6298
+ };
6299
+ }
6300
+ _padByPlaceholderWallBuffer(point) {
6301
+ return {
6302
+ x: clamp(
6303
+ point.x,
6304
+ this.bounds.minX + this.PLACEHOLDER_WALL_BUFFER_DISTANCE,
6305
+ this.bounds.maxX - this.PLACEHOLDER_WALL_BUFFER_DISTANCE
6306
+ ),
6307
+ y: clamp(
6308
+ point.y,
6309
+ this.bounds.minY + this.PLACEHOLDER_WALL_BUFFER_DISTANCE,
6310
+ this.bounds.maxY - this.PLACEHOLDER_WALL_BUFFER_DISTANCE
6311
+ ),
6312
+ z: point.z
6313
+ };
6314
+ }
6315
+ _step() {
6316
+ if (this.solved) return;
6317
+ const targetEnd = this.portPairMap.get(this.currentConnectionName).end;
6318
+ const proposedSegment = [this.currentHead, targetEnd];
6319
+ let closestIntersection = null;
6320
+ let intersectedSegmentZ = null;
6321
+ const checkIntersectionsWithPathMap = (pathMap) => {
6322
+ for (const path of pathMap.values()) {
6323
+ for (let i = 0; i < path.length - 1; i++) {
6324
+ const segment = [path[i], path[i + 1]];
6325
+ if (segment[0].x === segment[1].x && segment[0].y === segment[1].y) {
6326
+ continue;
6327
+ }
6328
+ if (segment[0].z !== this.currentHead.z) {
6329
+ continue;
6330
+ }
6331
+ const intersection = getSegmentIntersection(
6332
+ proposedSegment[0],
6333
+ proposedSegment[1],
6334
+ segment[0],
6335
+ segment[1]
6336
+ );
6337
+ if (intersection) {
6338
+ const distToIntersection = distance(this.currentHead, intersection);
6339
+ if (distToIntersection < 1e-6) continue;
6340
+ if (!closestIntersection || distToIntersection < closestIntersection.dist) {
6341
+ closestIntersection = {
6342
+ point: intersection,
6343
+ dist: distToIntersection
6344
+ };
6345
+ intersectedSegmentZ = segment[0].z;
6346
+ }
6347
+ }
6348
+ }
6349
+ }
6350
+ };
6351
+ checkIntersectionsWithPathMap(this.completedPaths);
6352
+ checkIntersectionsWithPathMap(this.placeholderPaths);
6353
+ const needsZChange = this.currentHead.z !== targetEnd.z;
6354
+ if (closestIntersection) {
6355
+ let viaXY;
6356
+ const distToIntersection = closestIntersection.dist;
6357
+ if (distToIntersection < this.VIA_INTERSECTION_BUFFER_DISTANCE) {
6358
+ viaXY = midpoint(this.currentHead, closestIntersection.point);
6359
+ } else {
6360
+ const intersectionPoint = closestIntersection.point;
6361
+ const vectorX = intersectionPoint.x - this.currentHead.x;
6362
+ const vectorY = intersectionPoint.y - this.currentHead.y;
6363
+ const ratio = (distToIntersection - this.VIA_INTERSECTION_BUFFER_DISTANCE) / distToIntersection;
6364
+ viaXY = {
6365
+ x: this.currentHead.x + vectorX * ratio,
6366
+ y: this.currentHead.y + vectorY * ratio
6367
+ };
6368
+ }
6369
+ const nextZ = this.availableZ.find((z) => z !== intersectedSegmentZ);
6370
+ if (nextZ === void 0) {
6371
+ console.error("Could not determine next Z level for via placement!");
6372
+ this.failed = true;
6373
+ return;
6374
+ }
6375
+ const viaPoint1 = { ...viaXY, z: this.currentHead.z };
6376
+ const viaPoint2 = { ...viaXY, z: nextZ };
6377
+ this.currentPath.push(viaPoint1, viaPoint2);
6378
+ this.currentHead = viaPoint2;
6379
+ } else if (needsZChange) {
6380
+ let viaXY;
6381
+ const distToTarget = distance(this.currentHead, targetEnd);
6382
+ if (distToTarget < this.VIA_INTERSECTION_BUFFER_DISTANCE) {
6383
+ viaXY = midpoint(this.currentHead, targetEnd);
6384
+ } else {
6385
+ const vectorX = targetEnd.x - this.currentHead.x;
6386
+ const vectorY = targetEnd.y - this.currentHead.y;
6387
+ const ratio = (distToTarget - this.VIA_INTERSECTION_BUFFER_DISTANCE) / distToTarget;
6388
+ viaXY = {
6389
+ x: this.currentHead.x + vectorX * ratio,
6390
+ y: this.currentHead.y + vectorY * ratio
6391
+ };
6392
+ }
6393
+ const nextZ = targetEnd.z;
6394
+ const viaPoint1 = { ...viaXY, z: this.currentHead.z };
6395
+ const viaPoint2 = { ...viaXY, z: nextZ };
6396
+ this.currentPath.push(viaPoint1, viaPoint2);
6397
+ this.currentHead = viaPoint2;
6398
+ } else {
6399
+ this.currentPath.push(targetEnd);
6400
+ this.completedPaths.set(this.currentConnectionName, this.currentPath);
6401
+ if (this.unprocessedConnections.length === 0) {
6402
+ this.solved = true;
6403
+ this.stats.solutionsFound = 1;
6404
+ } else {
6405
+ this.currentConnectionName = this.unprocessedConnections.pop();
6406
+ const { start } = this.portPairMap.get(this.currentConnectionName);
6407
+ this.currentHead = this._padByNewHeadWallBuffer(start);
6408
+ this.currentPath = [start, this.currentHead];
6409
+ this.placeholderPaths.delete(this.currentConnectionName);
6410
+ }
6411
+ }
6412
+ }
6413
+ visualize() {
6414
+ const graphics = {
6415
+ points: [],
6416
+ lines: [],
6417
+ circles: [],
6418
+ rects: [],
6419
+ title: "Via Possibilities Solver State",
6420
+ coordinateSystem: "cartesian"
6421
+ };
6422
+ const colorMap = this.colorMap;
6423
+ graphics.lines.push({
6424
+ points: [
6425
+ { x: this.bounds.minX, y: this.bounds.minY },
6426
+ { x: this.bounds.maxX, y: this.bounds.minY },
6427
+ { x: this.bounds.maxX, y: this.bounds.maxY },
6428
+ { x: this.bounds.minX, y: this.bounds.maxY },
6429
+ { x: this.bounds.minX, y: this.bounds.minY }
6430
+ ],
6431
+ strokeColor: "gray",
6432
+ strokeWidth: 0.01
6433
+ });
6434
+ for (const [connectionName, { start, end }] of this.portPairMap.entries()) {
6435
+ const color = this.colorMap[connectionName] ?? "black";
6436
+ graphics.points.push({
6437
+ x: start.x,
6438
+ y: start.y,
6439
+ color,
6440
+ label: `Port: ${connectionName} Start (z${start.z})`
6441
+ });
6442
+ graphics.points.push({
6443
+ x: end.x,
6444
+ y: end.y,
6445
+ color,
6446
+ label: `Port: ${connectionName} End (z${end.z})`
6447
+ });
6448
+ }
6449
+ const drawPath = (pathMap, labelPrefix) => {
6450
+ for (const [connectionName, path] of pathMap.entries()) {
6451
+ const color = colorMap[connectionName] ?? "black";
6452
+ for (let i = 0; i < path.length - 1; i++) {
6453
+ const p1 = path[i];
6454
+ const p2 = path[i + 1];
6455
+ if (p1.x === p2.x && p1.y === p2.y && p1.z !== p2.z) {
6456
+ graphics.circles.push({
6457
+ center: { x: p1.x, y: p1.y },
6458
+ radius: 0.3,
6459
+ // Diameter 0.6
6460
+ fill: safeTransparentize(color, 0.5),
6461
+ label: `${labelPrefix}: ${connectionName} Via (z${p1.z}->z${p2.z})`
6462
+ });
6463
+ } else {
6464
+ graphics.lines.push({
6465
+ points: [p1, p2],
6466
+ strokeColor: safeTransparentize(color, 0.5),
6467
+ strokeDash: p1.z === 0 ? void 0 : [0.1, 0.1],
6468
+ strokeWidth: 0.1,
6469
+ label: `${labelPrefix}: ${connectionName} (z${p1.z})`
6470
+ });
6471
+ }
6472
+ }
6473
+ }
6474
+ };
6475
+ drawPath(this.placeholderPaths, "Placeholder");
6476
+ drawPath(this.completedPaths, "Completed");
6477
+ if (this.currentPath && this.currentPath.length > 0) {
6478
+ const color = colorMap[this.currentConnectionName] ?? "orange";
6479
+ for (let i = 0; i < this.currentPath.length - 1; i++) {
6480
+ const p1 = this.currentPath[i];
6481
+ const p2 = this.currentPath[i + 1];
6482
+ if (p1.x === p2.x && p1.y === p2.y && p1.z !== p2.z) {
6483
+ graphics.circles.push({
6484
+ center: { x: p1.x, y: p1.y },
6485
+ radius: 0.3,
6486
+ fill: safeTransparentize(color, 0.5),
6487
+ label: `Current: ${this.currentConnectionName} Via (z${p1.z}->z${p2.z})`
6488
+ });
6489
+ } else {
6490
+ graphics.lines.push({
6491
+ points: [p1, p2],
6492
+ strokeColor: safeTransparentize(color, 0.5),
6493
+ strokeWidth: 0.15,
6494
+ // Thicker
6495
+ strokeDash: "2,2",
6496
+ // Dashed
6497
+ label: `Current: ${this.currentConnectionName} (z${p1.z})`
6498
+ });
6499
+ }
6500
+ }
6501
+ graphics.points.push({
6502
+ x: this.currentHead.x,
6503
+ y: this.currentHead.y,
6504
+ color: "green",
6505
+ label: `Current Head: ${this.currentConnectionName} (z${this.currentHead.z})`
6506
+ });
6507
+ }
6508
+ return graphics;
6509
+ }
6510
+ };
6511
+
6145
6512
  // lib/utils/getIntraNodeCrossings.ts
6146
6513
  var getIntraNodeCrossings = (node) => {
6147
6514
  let numSameLayerCrossings = 0;
@@ -6262,10 +6629,13 @@ var Vertex = class {
6262
6629
  y;
6263
6630
  out;
6264
6631
  // Outgoing half-edge indices
6632
+ connectionNames;
6633
+ // Names of connections passing through this vertex
6265
6634
  constructor(x, y) {
6266
6635
  this.x = x;
6267
6636
  this.y = y;
6268
6637
  this.out = [];
6638
+ this.connectionNames = /* @__PURE__ */ new Set();
6269
6639
  }
6270
6640
  };
6271
6641
  var HalfEdge = class {
@@ -6349,9 +6719,17 @@ function getCentroidsFromInnerBoxIntersections(rectangle, userSegments) {
6349
6719
  return t1 - t2;
6350
6720
  });
6351
6721
  for (let k = 0; k < list.length - 1; ++k) {
6352
- const v1 = getVertexId(list[k]);
6353
- const v2 = getVertexId(list[k + 1]);
6354
- if (v1 !== v2) undirectedEdges.push([v1, v2]);
6722
+ const p1 = list[k];
6723
+ const p2 = list[k + 1];
6724
+ const v1 = getVertexId(p1);
6725
+ const v2 = getVertexId(p2);
6726
+ if (v1 !== v2) {
6727
+ undirectedEdges.push([v1, v2]);
6728
+ if (s.connectionName) {
6729
+ vertices[v1].connectionNames.add(s.connectionName);
6730
+ vertices[v2].connectionNames.add(s.connectionName);
6731
+ }
6732
+ }
6355
6733
  }
6356
6734
  }
6357
6735
  const halfEdges = [];
@@ -6408,8 +6786,11 @@ function getCentroidsFromInnerBoxIntersections(rectangle, userSegments) {
6408
6786
  if (c) {
6409
6787
  centroids.push(c);
6410
6788
  faces.push({
6411
- vertices: poly.map((p) => ({ x: p.x, y: p.y })),
6412
- // Convert Vertex back to simple Point
6789
+ vertices: poly.map((v) => ({
6790
+ x: v.x,
6791
+ y: v.y,
6792
+ connectionNames: v.connectionNames.size > 0 ? v.connectionNames : void 0
6793
+ })),
6413
6794
  centroid: c
6414
6795
  });
6415
6796
  }
@@ -6995,6 +7376,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
6995
7376
  obstacleMargin = 0.1;
6996
7377
  traceWidth = 0.15;
6997
7378
  availableZ = [];
7379
+ uniqueConnections = 0;
6998
7380
  lastCandidate = null;
6999
7381
  maxViaCount;
7000
7382
  minViaCount;
@@ -7022,6 +7404,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
7022
7404
  const uniqueConnections = new Set(
7023
7405
  this.nodeWithPortPoints.portPoints.map((pp) => pp.connectionName)
7024
7406
  ).size;
7407
+ this.uniqueConnections = uniqueConnections;
7025
7408
  const { numSameLayerCrossings, numTransitions } = getIntraNodeCrossings(
7026
7409
  this.nodeWithPortPoints
7027
7410
  );
@@ -7030,11 +7413,6 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
7030
7413
  Math.floor(areaInsideNode / areaPerVia),
7031
7414
  Math.ceil(uniqueConnections * 1.5)
7032
7415
  );
7033
- if (uniqueConnections > 5) {
7034
- this.failed = true;
7035
- this.error = `Limit is currently set to 6 unique connections, ${uniqueConnections} found`;
7036
- return;
7037
- }
7038
7416
  if (this.minViaCount > this.SEGMENTS_PER_POLYLINE * (uniqueConnections / 2)) {
7039
7417
  this.failed = true;
7040
7418
  this.error = `Not possible to solve problem with given SEGMENTS_PER_POLYLINE (${this.SEGMENTS_PER_POLYLINE}), atleast ${this.minViaCount} vias are required`;
@@ -7773,7 +8151,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
7773
8151
  strokeColor: segmentColor,
7774
8152
  strokeWidth: this.traceWidth,
7775
8153
  // TODO: Use actual trace thickness from HighDensityRoute?
7776
- strokeDash: !isLayer0 ? "5,5" : void 0,
8154
+ strokeDash: !isLayer0 ? [0.15, 0.15] : void 0,
7777
8155
  // Dashed for layers > 0
7778
8156
  label: `${polyLine.connectionName} segment (z=${segmentLayer})`
7779
8157
  });
@@ -8259,6 +8637,191 @@ var MultiHeadPolyLineIntraNodeSolver2 = class extends MultiHeadPolyLineIntraNode
8259
8637
  }
8260
8638
  };
8261
8639
 
8640
+ // lib/solvers/HighDensitySolver/MultiHeadPolyLineIntraNodeSolver/MultiHeadPolyLineIntraNodeSolver3_ViaPossibilitiesSolverIntegration.ts
8641
+ var hashPolyLines = (polyLines) => {
8642
+ return polyLines.flatMap(
8643
+ (pl) => `${pl.connectionName}-${pl.mPoints.map((mp) => `${mp.x.toFixed(2)},${mp.y.toFixed(2)},${mp.z1},${mp.z2}`)}`
8644
+ ).sort().join("|");
8645
+ };
8646
+ function factorial(n) {
8647
+ if (!Number.isInteger(n) || n < 0) {
8648
+ throw new RangeError("n must be a non-negative integer");
8649
+ }
8650
+ let result = 1;
8651
+ for (let i = 2; i <= n; i++) {
8652
+ result *= i;
8653
+ }
8654
+ return result;
8655
+ }
8656
+ var MultiHeadPolyLineIntraNodeSolver3 = class extends MultiHeadPolyLineIntraNodeSolver2 {
8657
+ constructor(params) {
8658
+ super(params);
8659
+ this.MAX_ITERATIONS = 1e3;
8660
+ }
8661
+ createInitialCandidateFromSeed(shuffleSeed) {
8662
+ const viaSolver = new ViaPossibilitiesSolver2({
8663
+ nodeWithPortPoints: this.nodeWithPortPoints,
8664
+ colorMap: this.colorMap,
8665
+ // Pass relevant hyperparameters if needed, e.g., shuffle seed
8666
+ hyperParameters: {
8667
+ SHUFFLE_SEED: shuffleSeed
8668
+ }
8669
+ });
8670
+ viaSolver.solve();
8671
+ if (viaSolver.failed || !viaSolver.solved) {
8672
+ this.failed = true;
8673
+ this.error = viaSolver.error ?? "ViaPossibilitiesSolver2 failed to find a solution.";
8674
+ console.error(this.error);
8675
+ return null;
8676
+ }
8677
+ const polyLines = [];
8678
+ let totalViaCount = 0;
8679
+ for (const [
8680
+ connectionName,
8681
+ pathPoints
8682
+ ] of viaSolver.completedPaths.entries()) {
8683
+ if (pathPoints.length < 2) {
8684
+ console.warn(
8685
+ `Skipping connection "${connectionName}" due to insufficient points (${pathPoints.length}) in ViaPossibilitiesSolver2 path.`
8686
+ );
8687
+ continue;
8688
+ }
8689
+ const startPoint = pathPoints[0];
8690
+ const endPoint = pathPoints[pathPoints.length - 1];
8691
+ const middlePointsRaw = pathPoints.slice(1, -1);
8692
+ const mPoints = [];
8693
+ let currentViaCount = 0;
8694
+ let lastZ = startPoint.z;
8695
+ for (let i = 0; i < middlePointsRaw.length; i++) {
8696
+ const currentRawPoint = middlePointsRaw[i];
8697
+ const nextRawPoint = i + 1 < middlePointsRaw.length ? middlePointsRaw[i + 1] : endPoint;
8698
+ const isViaStart = i + 1 < middlePointsRaw.length && currentRawPoint.x === nextRawPoint.x && currentRawPoint.y === nextRawPoint.y && currentRawPoint.z !== nextRawPoint.z;
8699
+ const z1 = lastZ;
8700
+ const z2 = isViaStart ? nextRawPoint.z : currentRawPoint.z;
8701
+ mPoints.push({
8702
+ x: currentRawPoint.x,
8703
+ y: currentRawPoint.y,
8704
+ z1,
8705
+ z2
8706
+ });
8707
+ if (z1 !== z2) {
8708
+ currentViaCount++;
8709
+ i++;
8710
+ lastZ = z2;
8711
+ } else {
8712
+ lastZ = currentRawPoint.z;
8713
+ }
8714
+ }
8715
+ totalViaCount += currentViaCount;
8716
+ const targetSegmentCount = this.SEGMENTS_PER_POLYLINE;
8717
+ let currentSegments = mPoints.length + 1;
8718
+ while (currentSegments < targetSegmentCount) {
8719
+ let longestSegmentLength = -1;
8720
+ let longestSegmentIndex = -1;
8721
+ let p1 = null;
8722
+ let p2 = null;
8723
+ const fullPathPoints = [
8724
+ {
8725
+ ...startPoint,
8726
+ z1: startPoint.z,
8727
+ z2: startPoint.z,
8728
+ connectionName
8729
+ },
8730
+ ...mPoints,
8731
+ { ...endPoint, z1: endPoint.z, z2: endPoint.z, connectionName }
8732
+ ];
8733
+ for (let k = 0; k < fullPathPoints.length - 1; k++) {
8734
+ const segP1 = fullPathPoints[k];
8735
+ const segP2 = fullPathPoints[k + 1];
8736
+ if (segP1.x === segP2.x && segP1.y === segP2.y) {
8737
+ continue;
8738
+ }
8739
+ const len = distance(segP1, segP2);
8740
+ if (len > longestSegmentLength) {
8741
+ longestSegmentLength = len;
8742
+ longestSegmentIndex = k;
8743
+ p1 = segP1;
8744
+ p2 = segP2;
8745
+ }
8746
+ }
8747
+ if (longestSegmentIndex === -1 || !p1 || !p2) {
8748
+ console.warn(
8749
+ `Could not find longest segment for ${connectionName} while trying to reach ${targetSegmentCount} segments.`
8750
+ );
8751
+ break;
8752
+ }
8753
+ const midX = (p1.x + p2.x) / 2;
8754
+ const midY = (p1.y + p2.y) / 2;
8755
+ const segmentZ = p1.z2;
8756
+ const newMPoint = {
8757
+ x: midX,
8758
+ y: midY,
8759
+ z1: segmentZ,
8760
+ // New point is on the same layer
8761
+ z2: segmentZ
8762
+ };
8763
+ mPoints.splice(longestSegmentIndex, 0, newMPoint);
8764
+ currentSegments++;
8765
+ }
8766
+ polyLines.push({
8767
+ connectionName,
8768
+ start: {
8769
+ // Use original start/end points from ViaSolver
8770
+ ...startPoint,
8771
+ z1: startPoint.z,
8772
+ z2: startPoint.z
8773
+ // Start point is not a via itself
8774
+ },
8775
+ end: {
8776
+ ...endPoint,
8777
+ z1: endPoint.z,
8778
+ // End point uses its own Z as z1
8779
+ z2: endPoint.z
8780
+ // End point is not a via itself
8781
+ },
8782
+ mPoints
8783
+ });
8784
+ }
8785
+ if (polyLines.length === 0) {
8786
+ this.failed = true;
8787
+ this.error = "No valid polylines generated from ViaPossibilitiesSolver2.";
8788
+ console.error(this.error);
8789
+ return null;
8790
+ }
8791
+ const minGaps = this.computeMinGapBtwPolyLines(polyLines);
8792
+ const h = this.computeH({ minGaps, forces: [] });
8793
+ const initialCandidate = {
8794
+ polyLines,
8795
+ g: 0,
8796
+ h,
8797
+ f: 0 + h,
8798
+ // f = g + h
8799
+ viaCount: totalViaCount,
8800
+ minGaps
8801
+ };
8802
+ initialCandidate.g = this.computeG(polyLines, initialCandidate);
8803
+ initialCandidate.f = initialCandidate.g + initialCandidate.h;
8804
+ return initialCandidate;
8805
+ }
8806
+ setupInitialPolyLines() {
8807
+ this.candidates = [];
8808
+ const maxCandidatesToGenerate = Math.min(
8809
+ 2e3,
8810
+ factorial(this.uniqueConnections)
8811
+ );
8812
+ const candidatePolylineHashes = /* @__PURE__ */ new Set();
8813
+ for (let i = 0; i < maxCandidatesToGenerate; i++) {
8814
+ const newCandidate = this.createInitialCandidateFromSeed(i);
8815
+ if (!newCandidate) continue;
8816
+ const newCandidatePolylineHash = hashPolyLines(newCandidate.polyLines);
8817
+ if (candidatePolylineHashes.has(newCandidatePolylineHash)) continue;
8818
+ candidatePolylineHashes.add(newCandidatePolylineHash);
8819
+ this.candidates.push(newCandidate);
8820
+ }
8821
+ this.candidates.sort((a, b) => a.f - b.f);
8822
+ }
8823
+ };
8824
+
8262
8825
  // lib/solvers/HyperHighDensitySolver/HyperSingleIntraNodeSolver.ts
8263
8826
  var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
8264
8827
  constructorParams;
@@ -8381,11 +8944,7 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
8381
8944
  possibleValues: [
8382
8945
  {
8383
8946
  MULTI_HEAD_POLYLINE_SOLVER: true,
8384
- SEGMENTS_PER_POLYLINE: 3
8385
- },
8386
- {
8387
- MULTI_HEAD_POLYLINE_SOLVER: true,
8388
- SEGMENTS_PER_POLYLINE: 4
8947
+ SEGMENTS_PER_POLYLINE: 6
8389
8948
  }
8390
8949
  ]
8391
8950
  }
@@ -8412,7 +8971,7 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
8412
8971
  });
8413
8972
  }
8414
8973
  if (hyperParameters.MULTI_HEAD_POLYLINE_SOLVER) {
8415
- return new MultiHeadPolyLineIntraNodeSolver2({
8974
+ return new MultiHeadPolyLineIntraNodeSolver3({
8416
8975
  nodeWithPortPoints: this.nodeWithPortPoints,
8417
8976
  hyperParameters
8418
8977
  });
@@ -8502,7 +9061,7 @@ var HighDensitySolver = class extends BaseSolver {
8502
9061
  if (this.failedSolvers.length > 0) {
8503
9062
  this.solved = false;
8504
9063
  this.failed = true;
8505
- this.error = `Failed to solve ${this.failedSolvers.length} nodes`;
9064
+ this.error = `Failed to solve ${this.failedSolvers.length} nodes, ${this.failedSolvers.slice(0, 5).map((fs) => fs.nodeWithPortPoints.capacityMeshNodeId)}`;
8506
9065
  return;
8507
9066
  }
8508
9067
  this.solved = true;
@@ -8533,6 +9092,7 @@ var HighDensitySolver = class extends BaseSolver {
8533
9092
  points: segment.points,
8534
9093
  label: segment.connectionName,
8535
9094
  strokeColor: segment.z === 0 ? segment.color : safeTransparentize(segment.color, 0.75),
9095
+ layer: `z${segment.z}`,
8536
9096
  strokeWidth: route.traceThickness,
8537
9097
  strokeDash: segment.z !== 0 ? "10, 5" : void 0
8538
9098
  });
@@ -8540,6 +9100,7 @@ var HighDensitySolver = class extends BaseSolver {
8540
9100
  for (const via of route.vias) {
8541
9101
  graphics.circles.push({
8542
9102
  center: via,
9103
+ layer: "z0,1",
8543
9104
  radius: route.viaDiameter / 2,
8544
9105
  fill: this.colorMap[route.connectionName],
8545
9106
  label: `${route.connectionName} via`
@@ -8555,6 +9116,7 @@ var HighDensitySolver = class extends BaseSolver {
8555
9116
  x: node.center.x - rectWidth / 2,
8556
9117
  y: node.center.y - rectHeight / 2
8557
9118
  },
9119
+ layer: "did_not_connect",
8558
9120
  width: rectWidth,
8559
9121
  height: rectHeight,
8560
9122
  fill: "red",
@@ -8574,7 +9136,8 @@ var HighDensitySolver = class extends BaseSolver {
8574
9136
  graphics.lines.push({
8575
9137
  points: [start, end],
8576
9138
  strokeColor: "red",
8577
- strokeDash: "10, 5"
9139
+ strokeDash: "10, 5",
9140
+ layer: "did_not_connect"
8578
9141
  });
8579
9142
  }
8580
9143
  }
@@ -11476,7 +12039,7 @@ ${percent}% (Pf: ${(probabilityOfFailure * 100).toFixed(1)}%)`;
11476
12039
  }
11477
12040
 
11478
12041
  // lib/solvers/CapacityPathingSectionSolver/CapacityPathingSingleSectionPathingSolver.ts
11479
- var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
12042
+ var CapacityPathingSingleSectionSolver = class extends BaseSolver {
11480
12043
  GREEDY_MULTIPLIER = 1.5;
11481
12044
  sectionNodes;
11482
12045
  sectionEdges;
@@ -11488,6 +12051,7 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
11488
12051
  colorMap;
11489
12052
  usedNodeCapacityMap;
11490
12053
  // Tracks capacity usage *within this solver's run*
12054
+ centerNodeId;
11491
12055
  MAX_CANDIDATES_IN_MEMORY = 1e4;
11492
12056
  // A* state
11493
12057
  currentConnectionIndex = 0;
@@ -11501,6 +12065,7 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
11501
12065
  // Default, similar to CapacityPathingSolver5
11502
12066
  constructor(params) {
11503
12067
  super();
12068
+ this.centerNodeId = params.centerNodeId;
11504
12069
  this.sectionNodes = params.sectionNodes;
11505
12070
  this.sectionEdges = params.sectionEdges;
11506
12071
  this.sectionConnectionTerminals = params.sectionConnectionTerminals.map(
@@ -11674,6 +12239,28 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
11674
12239
  candidates.push(newCandidate);
11675
12240
  }
11676
12241
  }
12242
+ computeProgress() {
12243
+ const totalConnections = this.sectionConnectionTerminals.length;
12244
+ if (totalConnections === 0) return 1;
12245
+ const completedConnections = this.currentConnectionIndex;
12246
+ let progress = completedConnections / totalConnections;
12247
+ if (this.currentConnectionIndex < totalConnections && this.candidates && this.candidates.length > 0 && this.activeCandidateStraightLineDistance && this.activeCandidateStraightLineDistance > 0) {
12248
+ const bestCandidate = this.candidates.reduce(
12249
+ (best, current) => current.f < best.f ? current : best
12250
+ );
12251
+ const currentConnectionProgress = Math.max(
12252
+ 0,
12253
+ Math.min(
12254
+ 1,
12255
+ 1 - bestCandidate.h / this.activeCandidateStraightLineDistance
12256
+ )
12257
+ );
12258
+ progress += currentConnectionProgress / totalConnections;
12259
+ } else if (this.solved) {
12260
+ progress = 1;
12261
+ }
12262
+ return Math.min(1, progress);
12263
+ }
11677
12264
  _setupAStar(startNode, endNode) {
11678
12265
  this.candidates = [
11679
12266
  { prevCandidate: null, node: startNode, f: 0, g: 0, h: 0 }
@@ -11778,133 +12365,157 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
11778
12365
  return baseGraphics;
11779
12366
  }
11780
12367
  };
12368
+ var CapacityPathingSingleSectionPathingSolver = CapacityPathingSingleSectionSolver;
11781
12369
 
11782
- // lib/solvers/CapacityPathingSectionSolver/CapacityPathingSingleSectionSolver.ts
11783
- var CapacityPathingSingleSectionSolver = class extends BaseSolver {
11784
- centerNodeId;
11785
- connectionsWithNodes;
11786
- nodes;
11787
- nodeMap;
11788
- edges;
11789
- nodeEdgeMap;
11790
- expansionDegrees;
11791
- colorMap;
11792
- sectionNodes;
11793
- sectionEdges;
11794
- // Added sectionEdges property
11795
- sectionConnectionTerminals;
11796
- activeSubSolver = null;
12370
+ // lib/solvers/CapacityPathingSectionSolver/HyperCapacityPathingSingleSectionSolver.ts
12371
+ var HyperCapacityPathingSingleSectionSolver = class extends HyperParameterSupervisorSolver {
12372
+ constructorParams;
12373
+ winningSolver;
11797
12374
  constructor(params) {
11798
12375
  super();
11799
- this.MAX_ITERATIONS = 1e5;
11800
- this.colorMap = params.colorMap;
11801
- this.centerNodeId = params.centerNodeId;
11802
- this.connectionsWithNodes = params.connectionsWithNodes;
11803
- this.nodes = params.nodes;
11804
- this.nodeMap = new Map(this.nodes.map((n) => [n.capacityMeshNodeId, n]));
11805
- this.edges = params.edges;
11806
- this.nodeEdgeMap = getNodeEdgeMap(this.edges);
11807
- this.expansionDegrees = params.hyperParameters?.EXPANSION_DEGREES ?? 3;
11808
- this.sectionNodes = [];
11809
- this.sectionEdges = [];
11810
- this.sectionConnectionTerminals = [];
11811
- this.computeSectionNodesTerminalsAndEdges();
11812
- this.activeSubSolver = new CapacityPathingSingleSectionPathingSolver({
11813
- sectionConnectionTerminals: this.sectionConnectionTerminals,
11814
- sectionNodes: this.sectionNodes,
11815
- sectionEdges: this.sectionEdges,
11816
- colorMap: this.colorMap,
11817
- hyperParameters: params.hyperParameters
11818
- });
12376
+ this.MAX_ITERATIONS = 1e4;
12377
+ this.constructorParams = params;
11819
12378
  }
11820
- computeSectionNodesTerminalsAndEdges() {
11821
- const sectionNodeIds = /* @__PURE__ */ new Set();
11822
- const queue = [
11823
- { nodeId: this.centerNodeId, depth: 0 }
11824
- ];
11825
- sectionNodeIds.add(this.centerNodeId);
11826
- let head = 0;
11827
- while (head < queue.length) {
11828
- const { nodeId, depth } = queue[head++];
11829
- if (depth >= this.expansionDegrees) continue;
11830
- const neighbors = this.nodeEdgeMap.get(nodeId)?.flatMap((edge) => edge.nodeIds.filter((id) => id !== nodeId)) ?? [];
11831
- for (const neighborId of neighbors) {
11832
- if (!sectionNodeIds.has(neighborId)) {
11833
- sectionNodeIds.add(neighborId);
11834
- queue.push({ nodeId: neighborId, depth: depth + 1 });
11835
- }
11836
- }
11837
- }
11838
- this.sectionNodes = Array.from(sectionNodeIds).map(
11839
- (id) => this.nodeMap.get(id)
11840
- );
11841
- this.sectionEdges = this.edges.filter((edge) => {
11842
- const [nodeIdA, nodeIdB] = edge.nodeIds;
11843
- return sectionNodeIds.has(nodeIdA) && sectionNodeIds.has(nodeIdB);
11844
- });
11845
- this.sectionConnectionTerminals = [];
11846
- for (const conn of this.connectionsWithNodes) {
11847
- if (!conn.path) continue;
11848
- let startNodeId = null;
11849
- let endNodeId = null;
11850
- for (const node of conn.path) {
11851
- if (sectionNodeIds.has(node.capacityMeshNodeId)) {
11852
- startNodeId = node.capacityMeshNodeId;
11853
- break;
11854
- }
11855
- }
11856
- for (let i = conn.path.length - 1; i >= 0; i--) {
11857
- const node = conn.path[i];
11858
- if (sectionNodeIds.has(node.capacityMeshNodeId)) {
11859
- endNodeId = node.capacityMeshNodeId;
11860
- break;
11861
- }
11862
- }
11863
- if (startNodeId && endNodeId) {
11864
- this.sectionConnectionTerminals.push({
11865
- connectionName: conn.connection.name,
11866
- startNodeId,
11867
- endNodeId
11868
- });
11869
- }
11870
- }
12379
+ computeG(solver) {
12380
+ return solver.iterations / 100;
11871
12381
  }
11872
- _step() {
11873
- this.activeSubSolver?.step();
11874
- if (this.activeSubSolver?.solved) {
11875
- this.solved = true;
11876
- return;
11877
- }
11878
- if (this.activeSubSolver?.failed) {
11879
- this.failed = true;
11880
- this.error = this.activeSubSolver.error;
11881
- return;
11882
- }
12382
+ computeH(solver) {
12383
+ return solver.computeProgress();
11883
12384
  }
11884
- getConstructorParams() {
12385
+ getCombinationDefs() {
12386
+ return [["orderings10"]];
12387
+ }
12388
+ getFailureMessage() {
12389
+ return `All CapacityPathingSingleSection solvers failed for "${this.centerNodeId}"`;
12390
+ }
12391
+ getHyperParameterDefs() {
11885
12392
  return [
11886
12393
  {
11887
- centerNodeId: this.centerNodeId,
11888
- connectionsWithNodes: this.connectionsWithNodes,
11889
- nodes: this.nodes,
11890
- edges: this.edges,
11891
- expansionDegrees: this.expansionDegrees
12394
+ name: "orderings10",
12395
+ possibleValues: [
12396
+ {
12397
+ SHUFFLE_SEED: 0
12398
+ },
12399
+ {
12400
+ SHUFFLE_SEED: 1
12401
+ },
12402
+ {
12403
+ SHUFFLE_SEED: 2
12404
+ },
12405
+ {
12406
+ SHUFFLE_SEED: 3
12407
+ },
12408
+ {
12409
+ SHUFFLE_SEED: 4
12410
+ },
12411
+ {
12412
+ SHUFFLE_SEED: 5
12413
+ },
12414
+ {
12415
+ SHUFFLE_SEED: 6
12416
+ },
12417
+ {
12418
+ SHUFFLE_SEED: 7
12419
+ },
12420
+ {
12421
+ SHUFFLE_SEED: 8
12422
+ },
12423
+ {
12424
+ SHUFFLE_SEED: 9
12425
+ }
12426
+ ]
11892
12427
  }
11893
12428
  ];
11894
12429
  }
11895
- visualize() {
11896
- return visualizeSection({
11897
- sectionNodes: this.sectionNodes,
11898
- sectionEdges: this.sectionEdges,
11899
- // Use the computed class property
11900
- sectionConnectionTerminals: this.sectionConnectionTerminals,
11901
- nodeMap: this.nodeMap,
11902
- colorMap: this.colorMap,
11903
- centerNodeId: this.centerNodeId,
11904
- nodeOpacity: 1e-3,
11905
- title: `Section Solver (Center: ${this.centerNodeId}, Hops: ${this.expansionDegrees})`
12430
+ generateSolver(hyperParameters) {
12431
+ return new CapacityPathingSingleSectionPathingSolver({
12432
+ ...this.constructorParams,
12433
+ hyperParameters: {
12434
+ ...this.constructorParams.hyperParameters,
12435
+ ...hyperParameters
12436
+ }
11906
12437
  });
11907
12438
  }
12439
+ onSolve({
12440
+ solver
12441
+ }) {
12442
+ this.winningSolver = solver;
12443
+ }
12444
+ get centerNodeId() {
12445
+ return this.constructorParams.centerNodeId;
12446
+ }
12447
+ get sectionNodes() {
12448
+ return this.constructorParams.sectionNodes;
12449
+ }
12450
+ get sectionConnectionTerminals() {
12451
+ return this.winningSolver?.sectionConnectionTerminals;
12452
+ }
12453
+ };
12454
+
12455
+ // lib/solvers/CapacityPathingSectionSolver/computeSectionNodesTerminalsAndEdges.ts
12456
+ var computeSectionNodesTerminalsAndEdges = (opts) => {
12457
+ const {
12458
+ centerNodeId,
12459
+ connectionsWithNodes,
12460
+ nodeMap,
12461
+ edges,
12462
+ nodeEdgeMap,
12463
+ expansionDegrees
12464
+ } = opts;
12465
+ const sectionNodeIds = /* @__PURE__ */ new Set();
12466
+ const queue = [
12467
+ { nodeId: centerNodeId, depth: 0 }
12468
+ ];
12469
+ sectionNodeIds.add(centerNodeId);
12470
+ let head = 0;
12471
+ while (head < queue.length) {
12472
+ const { nodeId, depth } = queue[head++];
12473
+ if (depth >= expansionDegrees) continue;
12474
+ const neighbors = nodeEdgeMap.get(nodeId)?.flatMap((edge) => edge.nodeIds.filter((id) => id !== nodeId)) ?? [];
12475
+ for (const neighborId of neighbors) {
12476
+ if (!sectionNodeIds.has(neighborId)) {
12477
+ sectionNodeIds.add(neighborId);
12478
+ queue.push({ nodeId: neighborId, depth: depth + 1 });
12479
+ }
12480
+ }
12481
+ }
12482
+ const sectionNodes = Array.from(sectionNodeIds).map((id) => nodeMap.get(id));
12483
+ const sectionEdges = edges.filter((edge) => {
12484
+ const [nodeIdA, nodeIdB] = edge.nodeIds;
12485
+ return sectionNodeIds.has(nodeIdA) && sectionNodeIds.has(nodeIdB);
12486
+ });
12487
+ const sectionConnectionTerminals = [];
12488
+ for (const conn of connectionsWithNodes) {
12489
+ if (!conn.path) continue;
12490
+ let startNodeId = null;
12491
+ let endNodeId = null;
12492
+ for (const node of conn.path) {
12493
+ if (sectionNodeIds.has(node.capacityMeshNodeId)) {
12494
+ startNodeId = node.capacityMeshNodeId;
12495
+ break;
12496
+ }
12497
+ }
12498
+ for (let i = conn.path.length - 1; i >= 0; i--) {
12499
+ const node = conn.path[i];
12500
+ if (sectionNodeIds.has(node.capacityMeshNodeId)) {
12501
+ endNodeId = node.capacityMeshNodeId;
12502
+ break;
12503
+ }
12504
+ }
12505
+ if (startNodeId && endNodeId) {
12506
+ sectionConnectionTerminals.push({
12507
+ connectionName: conn.connection.name,
12508
+ startNodeId,
12509
+ endNodeId
12510
+ });
12511
+ }
12512
+ }
12513
+ return {
12514
+ sectionConnectionTerminals,
12515
+ sectionNodes,
12516
+ sectionEdges,
12517
+ centerNodeId
12518
+ };
11908
12519
  };
11909
12520
 
11910
12521
  // lib/solvers/CapacityPathingSectionSolver/CapacityPathingMultiSectionSolver.ts
@@ -11912,6 +12523,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
11912
12523
  simpleRouteJson;
11913
12524
  nodes;
11914
12525
  edges;
12526
+ nodeEdgeMap;
11915
12527
  connectionsWithNodes = [];
11916
12528
  // Initialize here
11917
12529
  colorMap;
@@ -11923,12 +12535,18 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
11923
12535
  // Added
11924
12536
  nodeCapacityPercentMap = /* @__PURE__ */ new Map();
11925
12537
  nodeOptimizationAttemptCountMap = /* @__PURE__ */ new Map();
12538
+ currentSection = null;
11926
12539
  sectionSolver = null;
11927
- MAX_ATTEMPTS_PER_NODE = 10;
12540
+ MAX_ATTEMPTS_PER_NODE = 1;
11928
12541
  MINIMUM_PROBABILITY_OF_FAILURE_TO_OPTIMIZE = 0.05;
11929
- MAX_EXPANSION_DEGREES = 3;
12542
+ MAX_EXPANSION_DEGREES = 5;
12543
+ stats;
11930
12544
  constructor(params) {
11931
12545
  super();
12546
+ this.stats = {
12547
+ successfulOptimizations: 0,
12548
+ failedOptimizations: 0
12549
+ };
11932
12550
  this.MAX_ITERATIONS = 1e7;
11933
12551
  this.simpleRouteJson = params.simpleRouteJson;
11934
12552
  this.nodes = params.nodes;
@@ -11937,7 +12555,8 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
11937
12555
  this.nodeMap = new Map(
11938
12556
  this.nodes.map((node) => [node.capacityMeshNodeId, node])
11939
12557
  );
11940
- this.initialSolver = new CapacityPathingGreedySolver({
12558
+ this.nodeEdgeMap = getNodeEdgeMap(this.edges);
12559
+ this.initialSolver = params.initialPathingSolver || new CapacityPathingGreedySolver({
11941
12560
  simpleRouteJson: this.simpleRouteJson,
11942
12561
  nodes: this.nodes,
11943
12562
  edges: this.edges,
@@ -12002,16 +12621,21 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12002
12621
  this.solved = true;
12003
12622
  return;
12004
12623
  }
12005
- this.sectionSolver = new CapacityPathingSingleSectionSolver({
12624
+ const section = computeSectionNodesTerminalsAndEdges({
12006
12625
  centerNodeId,
12007
12626
  connectionsWithNodes: this.connectionsWithNodes,
12008
- nodes: this.nodes,
12627
+ nodeMap: this.nodeMap,
12009
12628
  edges: this.edges,
12629
+ expansionDegrees: this.MAX_EXPANSION_DEGREES,
12630
+ nodeEdgeMap: this.nodeEdgeMap
12631
+ });
12632
+ this.currentSection = section;
12633
+ this.sectionSolver = new HyperCapacityPathingSingleSectionSolver({
12634
+ sectionConnectionTerminals: section.sectionConnectionTerminals,
12635
+ sectionEdges: section.sectionEdges,
12636
+ sectionNodes: section.sectionNodes,
12010
12637
  colorMap: this.colorMap,
12011
- hyperParameters: {
12012
- EXPANSION_DEGREES: this.MAX_EXPANSION_DEGREES,
12013
- SHUFFLE_SEED: this.iterations
12014
- }
12638
+ centerNodeId: section.centerNodeId
12015
12639
  });
12016
12640
  this.activeSubSolver = this.sectionSolver;
12017
12641
  this.nodeOptimizationAttemptCountMap.set(
@@ -12022,7 +12646,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12022
12646
  this.sectionSolver.step();
12023
12647
  if (this.sectionSolver.failed) {
12024
12648
  console.warn(
12025
- `Section solver failed for node ${this.sectionSolver.centerNodeId}. Error: ${this.sectionSolver.error}`
12649
+ `Section solver failed for node ${this.currentSection.centerNodeId}. Error: ${this.sectionSolver.error}`
12026
12650
  );
12027
12651
  this.sectionSolver = null;
12028
12652
  this.activeSubSolver = null;
@@ -12030,12 +12654,12 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12030
12654
  }
12031
12655
  if (this.sectionSolver.solved) {
12032
12656
  const solvedSectionSolver = this.sectionSolver;
12033
- const pathingSolver = solvedSectionSolver.activeSubSolver;
12657
+ const pathingSolver = solvedSectionSolver?.activeSubSolver || solvedSectionSolver;
12034
12658
  this.sectionSolver = null;
12035
12659
  this.activeSubSolver = null;
12036
12660
  if (!pathingSolver || !pathingSolver.solved) {
12037
12661
  console.warn(
12038
- `Pathing sub-solver for section ${solvedSectionSolver.centerNodeId} did not complete successfully. Discarding results.`
12662
+ `Pathing sub-solver for section ${this.currentSection.centerNodeId} did not complete successfully. Discarding results.`
12039
12663
  );
12040
12664
  return;
12041
12665
  }
@@ -12085,9 +12709,11 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12085
12709
  sectionNodeIds
12086
12710
  });
12087
12711
  if (afterScore > beforeScore) {
12712
+ this.stats.successfulOptimizations++;
12088
12713
  this._mergeSolvedSectionPaths(solvedSectionSolver);
12089
12714
  this._recalculateNodeCapacityUsage();
12090
12715
  } else {
12716
+ this.stats.failedOptimizations++;
12091
12717
  }
12092
12718
  }
12093
12719
  }
@@ -12096,18 +12722,18 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12096
12722
  * connectionsWithNodes list.
12097
12723
  */
12098
12724
  _mergeSolvedSectionPaths(solvedSectionSolver) {
12099
- const pathingSolver = solvedSectionSolver.activeSubSolver;
12100
- if (!pathingSolver || !pathingSolver.solved) {
12725
+ const centerNodeId = solvedSectionSolver.centerNodeId;
12726
+ if (!solvedSectionSolver || !solvedSectionSolver.solved) {
12101
12727
  console.warn(
12102
- `Pathing sub-solver for section ${solvedSectionSolver.centerNodeId} did not complete successfully. Skipping merge.`
12728
+ `Pathing sub-solver for section ${centerNodeId} did not complete successfully. Skipping merge.`
12103
12729
  );
12104
12730
  return;
12105
12731
  }
12106
- const solvedTerminals = pathingSolver.sectionConnectionTerminals;
12732
+ const solvedTerminals = solvedSectionSolver.sectionConnectionTerminals;
12107
12733
  for (const solvedTerminal of solvedTerminals) {
12108
12734
  if (!solvedTerminal.path) {
12109
12735
  console.warn(
12110
- `No path found for connection ${solvedTerminal.connectionName} in section ${solvedSectionSolver.centerNodeId}`
12736
+ `No path found for connection ${solvedTerminal.connectionName} in section ${centerNodeId}`
12111
12737
  );
12112
12738
  continue;
12113
12739
  }
@@ -12963,13 +13589,13 @@ function minimumDistanceBetweenSegments(A1, A2, B1, B2) {
12963
13589
  if (segmentsIntersect(A1, A2, B1, B2)) {
12964
13590
  return 0;
12965
13591
  }
12966
- const distA1 = pointToSegmentDistance5(A1, B1, B2);
12967
- const distA2 = pointToSegmentDistance5(A2, B1, B2);
12968
- const distB1 = pointToSegmentDistance5(B1, A1, A2);
12969
- const distB2 = pointToSegmentDistance5(B2, A1, A2);
13592
+ const distA1 = pointToSegmentDistance6(A1, B1, B2);
13593
+ const distA2 = pointToSegmentDistance6(A2, B1, B2);
13594
+ const distB1 = pointToSegmentDistance6(B1, A1, A2);
13595
+ const distB2 = pointToSegmentDistance6(B2, A1, A2);
12970
13596
  return Math.min(distA1, distA2, distB1, distB2);
12971
13597
  }
12972
- function pointToSegmentDistance5(P, Q1, Q2) {
13598
+ function pointToSegmentDistance6(P, Q1, Q2) {
12973
13599
  const v = { x: Q2.x - Q1.x, y: Q2.y - Q1.y };
12974
13600
  const w = { x: P.x - Q1.x, y: P.y - Q1.y };
12975
13601
  const c1 = dotProduct(w, v);
@@ -14471,8 +15097,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14471
15097
  nodeSolver;
14472
15098
  nodeTargetMerger;
14473
15099
  edgeSolver;
14474
- pathingSolver;
14475
- // Updated type
15100
+ initialPathingSolver;
15101
+ pathingOptimizer;
14476
15102
  edgeToPortSegmentSolver;
14477
15103
  colorMap;
14478
15104
  segmentToPointSolver;
@@ -14559,12 +15185,28 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14559
15185
  (cms) => [cms.capacityNodes]
14560
15186
  ),
14561
15187
  definePipelineStep(
14562
- "pathingSolver",
15188
+ "initialPathingSolver",
15189
+ CapacityPathingGreedySolver,
15190
+ (cms) => [
15191
+ {
15192
+ simpleRouteJson: cms.srjWithPointPairs,
15193
+ nodes: cms.capacityNodes,
15194
+ edges: cms.edgeSolver?.edges || [],
15195
+ colorMap: cms.colorMap,
15196
+ hyperParameters: {
15197
+ MAX_CAPACITY_FACTOR: 1
15198
+ }
15199
+ }
15200
+ ]
15201
+ ),
15202
+ definePipelineStep(
15203
+ "pathingOptimizer",
14563
15204
  // CapacityPathingSolver5,
14564
15205
  CapacityPathingMultiSectionSolver,
14565
15206
  (cms) => [
14566
15207
  // Replaced solver class
14567
15208
  {
15209
+ initialPathingSolver: cms.initialPathingSolver,
14568
15210
  simpleRouteJson: cms.srjWithPointPairs,
14569
15211
  nodes: cms.capacityNodes,
14570
15212
  edges: cms.edgeSolver?.edges || [],
@@ -14582,7 +15224,7 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14582
15224
  {
14583
15225
  nodes: cms.capacityNodes,
14584
15226
  edges: cms.edgeSolver?.edges || [],
14585
- capacityPaths: cms.pathingSolver?.getCapacityPaths() || [],
15227
+ capacityPaths: cms.pathingOptimizer?.getCapacityPaths() || [],
14586
15228
  colorMap: cms.colorMap
14587
15229
  }
14588
15230
  ]
@@ -14741,7 +15383,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14741
15383
  const singleLayerNodeMergerViz = this.singleLayerNodeMerger?.visualize();
14742
15384
  const strawSolverViz = this.strawSolver?.visualize();
14743
15385
  const edgeViz = this.edgeSolver?.visualize();
14744
- const pathingViz = this.pathingSolver?.visualize();
15386
+ const initialPathingViz = this.initialPathingSolver?.visualize();
15387
+ const pathingOptimizerViz = this.pathingOptimizer?.visualize();
14745
15388
  const edgeToPortSegmentViz = this.edgeToPortSegmentSolver?.visualize();
14746
15389
  const segmentToPointViz = this.segmentToPointSolver?.visualize();
14747
15390
  const segmentOptimizationViz = this.unravelMultiSectionSolver?.visualize() ?? this.segmentToPointOptimizer?.visualize();
@@ -14796,7 +15439,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14796
15439
  singleLayerNodeMergerViz,
14797
15440
  strawSolverViz,
14798
15441
  edgeViz,
14799
- pathingViz,
15442
+ initialPathingViz,
15443
+ pathingOptimizerViz,
14800
15444
  edgeToPortSegmentViz,
14801
15445
  segmentToPointViz,
14802
15446
  segmentOptimizationViz,
@@ -14838,9 +15482,9 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14838
15482
  }
14839
15483
  return { lines };
14840
15484
  }
14841
- if (this.pathingSolver) {
15485
+ if (this.pathingOptimizer) {
14842
15486
  const lines = [];
14843
- for (const connection of this.pathingSolver.connectionsWithNodes) {
15487
+ for (const connection of this.pathingOptimizer.connectionsWithNodes) {
14844
15488
  if (!connection.path) continue;
14845
15489
  lines.push({
14846
15490
  points: connection.path.map((n) => ({