@tscircuit/matchpack 0.0.4 → 0.0.6

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
@@ -183,8 +183,6 @@ function visualizeInputProblem(inputProblem, basicLayout) {
183
183
  }
184
184
  return chipPin.offset;
185
185
  }
186
- const groupPin = inputProblem.groupPinMap[pinId];
187
- if (groupPin) return groupPin.offset;
188
186
  return null;
189
187
  }).filter(Boolean);
190
188
  for (let i = 0; i < pinPositions.length; i++) {
@@ -203,17 +201,19 @@ function visualizeInputProblem(inputProblem, basicLayout) {
203
201
  if (chip.pins.includes(pinId)) {
204
202
  const placement = basicLayout.chipPlacements[chipId];
205
203
  if (placement) {
204
+ const rotatedOffset = rotatePoint(
205
+ chipPin.offset,
206
+ placement.ccwRotationDegrees
207
+ );
206
208
  return {
207
- x: placement.x + chipPin.offset.x,
208
- y: placement.y + chipPin.offset.y
209
+ x: placement.x + rotatedOffset.x,
210
+ y: placement.y + rotatedOffset.y
209
211
  };
210
212
  }
211
213
  }
212
214
  }
213
215
  return chipPin.offset;
214
216
  }
215
- const groupPin = inputProblem.groupPinMap[pinId];
216
- if (groupPin) return groupPin.offset;
217
217
  return null;
218
218
  };
219
219
  const seenStrongConn = /* @__PURE__ */ new Set();
@@ -316,14 +316,10 @@ var ChipPartitionsSolver = class extends BaseSolver {
316
316
  */
317
317
  createPartitions(inputProblem) {
318
318
  const chipIds = Object.keys(inputProblem.chipMap);
319
- const groupIds = Object.keys(inputProblem.groupMap);
320
319
  const adjacencyMap = /* @__PURE__ */ new Map();
321
320
  for (const chipId of chipIds) {
322
321
  adjacencyMap.set(chipId, /* @__PURE__ */ new Set());
323
322
  }
324
- for (const groupId of groupIds) {
325
- adjacencyMap.set(groupId, /* @__PURE__ */ new Set());
326
- }
327
323
  for (const [connKey, isConnected] of Object.entries(
328
324
  inputProblem.pinStrongConnMap
329
325
  )) {
@@ -338,7 +334,7 @@ var ChipPartitionsSolver = class extends BaseSolver {
338
334
  }
339
335
  const visited = /* @__PURE__ */ new Set();
340
336
  const partitions = [];
341
- for (const componentId of [...chipIds, ...groupIds]) {
337
+ for (const componentId of chipIds) {
342
338
  if (!visited.has(componentId)) {
343
339
  const partition = this.dfs(componentId, adjacencyMap, visited);
344
340
  if (partition.length > 0) {
@@ -351,7 +347,7 @@ var ChipPartitionsSolver = class extends BaseSolver {
351
347
  );
352
348
  }
353
349
  /**
354
- * Finds the owner (chip or group) of a given pin
350
+ * Finds the owner chip of a given pin
355
351
  */
356
352
  findPinOwner(pinId, inputProblem) {
357
353
  const chipPin = inputProblem.chipPinMap[pinId];
@@ -362,14 +358,6 @@ var ChipPartitionsSolver = class extends BaseSolver {
362
358
  }
363
359
  }
364
360
  }
365
- const groupPin = inputProblem.groupPinMap[pinId];
366
- if (groupPin) {
367
- for (const [groupId, group] of Object.entries(inputProblem.groupMap)) {
368
- if (group.pins.includes(pinId)) {
369
- return groupId;
370
- }
371
- }
372
- }
373
361
  return null;
374
362
  }
375
363
  /**
@@ -396,8 +384,7 @@ var ChipPartitionsSolver = class extends BaseSolver {
396
384
  * Creates a new InputProblem containing only the components in the given partition
397
385
  */
398
386
  createInputProblemFromPartition(partition, originalProblem) {
399
- const chipIds = partition.filter((id) => originalProblem.chipMap[id]);
400
- const groupIds = partition.filter((id) => originalProblem.groupMap[id]);
387
+ const chipIds = partition;
401
388
  const relevantPinIds = /* @__PURE__ */ new Set();
402
389
  for (const chipId of chipIds) {
403
390
  const chip = originalProblem.chipMap[chipId];
@@ -405,16 +392,8 @@ var ChipPartitionsSolver = class extends BaseSolver {
405
392
  relevantPinIds.add(pinId);
406
393
  }
407
394
  }
408
- for (const groupId of groupIds) {
409
- const group = originalProblem.groupMap[groupId];
410
- for (const pinId of group.pins) {
411
- relevantPinIds.add(pinId);
412
- }
413
- }
414
395
  const chipMap = {};
415
396
  const chipPinMap = {};
416
- const groupMap = {};
417
- const groupPinMap = {};
418
397
  const netMap = {};
419
398
  const pinStrongConnMap = {};
420
399
  const netConnMap = {};
@@ -426,14 +405,6 @@ var ChipPartitionsSolver = class extends BaseSolver {
426
405
  chipPinMap[pinId] = originalProblem.chipPinMap[pinId];
427
406
  }
428
407
  }
429
- for (const groupId of groupIds) {
430
- groupMap[groupId] = originalProblem.groupMap[groupId];
431
- }
432
- for (const pinId of relevantPinIds) {
433
- if (originalProblem.groupPinMap[pinId]) {
434
- groupPinMap[pinId] = originalProblem.groupPinMap[pinId];
435
- }
436
- }
437
408
  for (const [connKey, isConnected] of Object.entries(
438
409
  originalProblem.pinStrongConnMap
439
410
  )) {
@@ -461,8 +432,6 @@ var ChipPartitionsSolver = class extends BaseSolver {
461
432
  return {
462
433
  chipMap,
463
434
  chipPinMap,
464
- groupMap,
465
- groupPinMap,
466
435
  netMap,
467
436
  pinStrongConnMap,
468
437
  netConnMap,
@@ -483,37 +452,237 @@ var ChipPartitionsSolver = class extends BaseSolver {
483
452
  }
484
453
  };
485
454
 
486
- // lib/solvers/PartitionPackingSolver/PartitionPackingSolver.ts
455
+ // lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts
487
456
  import { PhasedPackSolver } from "calculate-packing";
457
+ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
458
+ inputProblem;
459
+ layout = null;
460
+ phasedPackSolver = null;
461
+ constructor(inputProblem) {
462
+ super();
463
+ this.inputProblem = inputProblem;
464
+ }
465
+ _step() {
466
+ try {
467
+ if (!this.phasedPackSolver) {
468
+ const packInput = this.createPackInput();
469
+ this.phasedPackSolver = new PhasedPackSolver(packInput);
470
+ this.activeSubSolver = this.phasedPackSolver;
471
+ }
472
+ this.phasedPackSolver.step();
473
+ if (this.phasedPackSolver.failed) {
474
+ this.failed = true;
475
+ this.error = `PhasedPackSolver failed: ${this.phasedPackSolver.error}`;
476
+ return;
477
+ }
478
+ if (this.phasedPackSolver.solved) {
479
+ this.layout = this.createLayoutFromPackingResult(
480
+ this.phasedPackSolver.getResult()
481
+ );
482
+ this.solved = true;
483
+ this.activeSubSolver = null;
484
+ }
485
+ } catch (error) {
486
+ this.failed = true;
487
+ this.error = `Failed to pack partition: ${error}`;
488
+ }
489
+ }
490
+ createPackInput() {
491
+ const pinToNetworkMap = /* @__PURE__ */ new Map();
492
+ for (const [connKey, connected] of Object.entries(
493
+ this.inputProblem.netConnMap
494
+ )) {
495
+ if (!connected) continue;
496
+ const [pinId, netId] = connKey.split("-");
497
+ if (pinId && netId) {
498
+ pinToNetworkMap.set(pinId, netId);
499
+ }
500
+ }
501
+ for (const [connKey, connected] of Object.entries(
502
+ this.inputProblem.pinStrongConnMap
503
+ )) {
504
+ if (!connected) continue;
505
+ const pins = connKey.split("-");
506
+ if (pins.length === 2 && pins[0] && pins[1]) {
507
+ const existingNet = pinToNetworkMap.get(pins[0]) || pinToNetworkMap.get(pins[1]);
508
+ if (existingNet) {
509
+ pinToNetworkMap.set(pins[0], existingNet);
510
+ pinToNetworkMap.set(pins[1], existingNet);
511
+ } else {
512
+ pinToNetworkMap.set(pins[0], connKey);
513
+ pinToNetworkMap.set(pins[1], connKey);
514
+ }
515
+ }
516
+ }
517
+ const packComponents = Object.entries(this.inputProblem.chipMap).map(
518
+ ([chipId, chip]) => {
519
+ const pads = [];
520
+ pads.push({
521
+ padId: `${chipId}_body`,
522
+ networkId: `${chipId}_body_disconnected`,
523
+ type: "rect",
524
+ offset: { x: 0, y: 0 },
525
+ size: { x: chip.size.x, y: chip.size.y }
526
+ });
527
+ for (const pinId of chip.pins) {
528
+ const pin = this.inputProblem.chipPinMap[pinId];
529
+ if (!pin) continue;
530
+ const networkId = pinToNetworkMap.get(pinId) || `${pinId}_isolated`;
531
+ pads.push({
532
+ padId: pinId,
533
+ networkId,
534
+ type: "rect",
535
+ offset: { x: pin.offset.x, y: pin.offset.y },
536
+ size: { x: 0.1, y: 0.1 }
537
+ // Small size for pins
538
+ });
539
+ }
540
+ return {
541
+ componentId: chipId,
542
+ pads,
543
+ availableRotationDegrees: chip.availableRotations || [
544
+ 0,
545
+ 90,
546
+ 180,
547
+ 270
548
+ ]
549
+ };
550
+ }
551
+ );
552
+ return {
553
+ components: packComponents,
554
+ minGap: this.inputProblem.chipGap,
555
+ packOrderStrategy: "largest_to_smallest",
556
+ packPlacementStrategy: "minimum_sum_squared_distance_to_network"
557
+ };
558
+ }
559
+ createLayoutFromPackingResult(packedComponents) {
560
+ const chipPlacements = {};
561
+ for (const packedComponent of packedComponents) {
562
+ const chipId = packedComponent.componentId;
563
+ chipPlacements[chipId] = {
564
+ x: packedComponent.center.x,
565
+ y: packedComponent.center.y,
566
+ ccwRotationDegrees: packedComponent.ccwRotationDegrees || 0
567
+ };
568
+ }
569
+ return {
570
+ chipPlacements,
571
+ groupPlacements: {}
572
+ };
573
+ }
574
+ visualize() {
575
+ if (this.phasedPackSolver && !this.solved) {
576
+ return this.phasedPackSolver.visualize();
577
+ }
578
+ if (!this.layout) {
579
+ return super.visualize();
580
+ }
581
+ return visualizeInputProblem(this.inputProblem, this.layout);
582
+ }
583
+ getConstructorParams() {
584
+ return [this.inputProblem];
585
+ }
586
+ };
587
+
588
+ // lib/solvers/PackInnerPartitionsSolver/PackInnerPartitionsSolver.ts
589
+ import { stackGraphicsHorizontally as stackGraphicsHorizontally2 } from "graphics-debug";
590
+ var PackInnerPartitionsSolver = class extends BaseSolver {
591
+ partitions;
592
+ packedPartitions = [];
593
+ completedSolvers = [];
594
+ activeSolver = null;
595
+ currentPartitionIndex = 0;
596
+ constructor(partitions) {
597
+ super();
598
+ this.partitions = partitions;
599
+ }
600
+ _step() {
601
+ if (this.currentPartitionIndex >= this.partitions.length) {
602
+ this.solved = true;
603
+ return;
604
+ }
605
+ if (!this.activeSolver) {
606
+ const currentPartition = this.partitions[this.currentPartitionIndex];
607
+ this.activeSolver = new SingleInnerPartitionPackingSolver(
608
+ currentPartition
609
+ );
610
+ this.activeSubSolver = this.activeSolver;
611
+ }
612
+ this.activeSolver.step();
613
+ if (this.activeSolver.failed) {
614
+ this.failed = true;
615
+ this.error = `Partition ${this.currentPartitionIndex} failed: ${this.activeSolver.error}`;
616
+ return;
617
+ }
618
+ if (this.activeSolver.solved) {
619
+ this.completedSolvers.push(this.activeSolver);
620
+ if (this.activeSolver.layout) {
621
+ this.packedPartitions.push({
622
+ inputProblem: this.partitions[this.currentPartitionIndex],
623
+ layout: this.activeSolver.layout
624
+ });
625
+ } else {
626
+ this.failed = true;
627
+ this.error = `Partition ${this.currentPartitionIndex} completed but has no layout`;
628
+ return;
629
+ }
630
+ this.activeSolver = null;
631
+ this.activeSubSolver = null;
632
+ this.currentPartitionIndex++;
633
+ }
634
+ }
635
+ visualize() {
636
+ if (this.activeSolver) {
637
+ return this.activeSolver.visualize();
638
+ }
639
+ if (this.completedSolvers.length === 0) {
640
+ return super.visualize();
641
+ }
642
+ const partitionVisualizations = this.completedSolvers.map(
643
+ (solver) => solver.visualize()
644
+ );
645
+ const titles = this.completedSolvers.map(
646
+ (_, index) => `packed_partition_${index}`
647
+ );
648
+ return stackGraphicsHorizontally2(partitionVisualizations, { titles });
649
+ }
650
+ getConstructorParams() {
651
+ return [this.partitions];
652
+ }
653
+ };
654
+
655
+ // lib/solvers/PartitionPackingSolver/PartitionPackingSolver.ts
656
+ import { PhasedPackSolver as PhasedPackSolver2 } from "calculate-packing";
488
657
  var PartitionPackingSolver = class extends BaseSolver {
489
- resolvedLayout;
490
- laidOutPartitions;
658
+ packedPartitions;
491
659
  inputProblem;
492
660
  finalLayout = null;
493
661
  phasedPackSolver = null;
494
662
  constructor(input) {
495
663
  super();
496
- this.resolvedLayout = input.resolvedLayout;
497
- this.laidOutPartitions = input.laidOutPartitions;
664
+ this.packedPartitions = input.packedPartitions;
498
665
  this.inputProblem = input.inputProblem;
499
666
  }
500
667
  _step() {
501
668
  try {
502
- if (!this.resolvedLayout) {
503
- this.failed = true;
504
- this.error = "No resolved layout provided";
669
+ if (this.packedPartitions.length === 0) {
670
+ this.finalLayout = {
671
+ chipPlacements: {},
672
+ groupPlacements: {}
673
+ };
674
+ this.solved = true;
505
675
  return;
506
676
  }
507
- const resolvedLayout = this.resolvedLayout;
508
- const partitionGroups = this.organizeComponentsByPartition(resolvedLayout);
509
- if (partitionGroups.length === 0) {
510
- this.finalLayout = resolvedLayout;
677
+ if (this.packedPartitions.length === 1) {
678
+ this.finalLayout = this.packedPartitions[0].layout;
511
679
  this.solved = true;
512
680
  return;
513
681
  }
682
+ const partitionGroups = this.organizePackedPartitions();
514
683
  if (!this.phasedPackSolver) {
515
684
  const packInput = this.createPackInput(partitionGroups);
516
- this.phasedPackSolver = new PhasedPackSolver(packInput);
685
+ this.phasedPackSolver = new PhasedPackSolver2(packInput);
517
686
  this.activeSubSolver = this.phasedPackSolver;
518
687
  }
519
688
  this.phasedPackSolver.step();
@@ -525,8 +694,7 @@ var PartitionPackingSolver = class extends BaseSolver {
525
694
  if (this.phasedPackSolver.solved) {
526
695
  const packedLayout = this.applyPackingResult(
527
696
  this.phasedPackSolver.getResult(),
528
- partitionGroups,
529
- resolvedLayout
697
+ partitionGroups
530
698
  );
531
699
  this.finalLayout = packedLayout;
532
700
  this.solved = true;
@@ -537,29 +705,37 @@ var PartitionPackingSolver = class extends BaseSolver {
537
705
  this.error = `Failed to pack partitions: ${error}`;
538
706
  }
539
707
  }
540
- organizeComponentsByPartition(layout) {
708
+ organizePackedPartitions() {
541
709
  const partitionGroups = [];
542
- for (let i = 0; i < this.laidOutPartitions.length; i++) {
543
- const laidOutPartition = this.laidOutPartitions[i];
544
- const partitionChipIds = [];
545
- for (const chipId of Object.keys(laidOutPartition.chipMap)) {
546
- if (layout.chipPlacements[chipId]) {
547
- partitionChipIds.push(chipId);
548
- }
549
- }
710
+ for (let i = 0; i < this.packedPartitions.length; i++) {
711
+ const packedPartition = this.packedPartitions[i];
712
+ const partitionChipIds = Object.keys(
713
+ packedPartition.layout.chipPlacements
714
+ );
550
715
  if (partitionChipIds.length > 0) {
551
- const xs = partitionChipIds.map(
552
- (chipId) => layout.chipPlacements[chipId].x
553
- );
554
- const ys = partitionChipIds.map(
555
- (chipId) => layout.chipPlacements[chipId].y
556
- );
557
- const bounds = {
558
- minX: Math.min(...xs),
559
- maxX: Math.max(...xs),
560
- minY: Math.min(...ys),
561
- maxY: Math.max(...ys)
562
- };
716
+ let minX = Infinity;
717
+ let maxX = -Infinity;
718
+ let minY = Infinity;
719
+ let maxY = -Infinity;
720
+ for (const chipId of partitionChipIds) {
721
+ const placement = packedPartition.layout.chipPlacements[chipId];
722
+ const chip = packedPartition.inputProblem.chipMap[chipId];
723
+ let chipWidth = chip.size.x;
724
+ let chipHeight = chip.size.y;
725
+ if (placement.ccwRotationDegrees === 90 || placement.ccwRotationDegrees === 270) {
726
+ ;
727
+ [chipWidth, chipHeight] = [chipHeight, chipWidth];
728
+ }
729
+ const chipMinX = placement.x - chipWidth / 2;
730
+ const chipMaxX = placement.x + chipWidth / 2;
731
+ const chipMinY = placement.y - chipHeight / 2;
732
+ const chipMaxY = placement.y + chipHeight / 2;
733
+ minX = Math.min(minX, chipMinX);
734
+ maxX = Math.max(maxX, chipMaxX);
735
+ minY = Math.min(minY, chipMinY);
736
+ maxY = Math.max(maxY, chipMaxY);
737
+ }
738
+ const bounds = { minX, maxX, minY, maxY };
563
739
  partitionGroups.push({
564
740
  partitionIndex: i,
565
741
  chipIds: partitionChipIds,
@@ -570,11 +746,10 @@ var PartitionPackingSolver = class extends BaseSolver {
570
746
  return partitionGroups;
571
747
  }
572
748
  createPackInput(partitionGroups) {
573
- const resolvedLayout = this.resolvedLayout;
574
749
  const pinToNetworkMap = /* @__PURE__ */ new Map();
575
- for (const laidOutPartition of this.laidOutPartitions) {
750
+ for (const packedPartition of this.packedPartitions) {
576
751
  for (const [connKey, connected] of Object.entries(
577
- laidOutPartition.netConnMap
752
+ packedPartition.inputProblem.netConnMap
578
753
  )) {
579
754
  if (!connected) continue;
580
755
  const [pinId, netId] = connKey.split("-");
@@ -583,7 +758,7 @@ var PartitionPackingSolver = class extends BaseSolver {
583
758
  }
584
759
  }
585
760
  for (const [connKey, connected] of Object.entries(
586
- laidOutPartition.pinStrongConnMap
761
+ packedPartition.inputProblem.pinStrongConnMap
587
762
  )) {
588
763
  if (!connected) continue;
589
764
  const pins = connKey.split("-");
@@ -600,56 +775,64 @@ var PartitionPackingSolver = class extends BaseSolver {
600
775
  }
601
776
  }
602
777
  const packComponents = partitionGroups.map((group) => {
603
- const pads = [];
604
- for (const chipId of group.chipIds) {
605
- const chipPlacement = resolvedLayout.chipPlacements[chipId];
606
- const chip = this.laidOutPartitions[group.partitionIndex].chipMap[chipId];
607
- const chipPinMap = this.laidOutPartitions[group.partitionIndex].chipPinMap;
608
- const relativeChipX = chipPlacement.x - group.bounds.minX;
609
- const relativeChipY = chipPlacement.y - group.bounds.minY;
610
- pads.push({
611
- padId: `${chipId}_body`,
612
- networkId: `${chipId}_body_disconnected`,
778
+ const packedPartition = this.packedPartitions[group.partitionIndex];
779
+ const partitionWidth = group.bounds.maxX - group.bounds.minX;
780
+ const partitionHeight = group.bounds.maxY - group.bounds.minY;
781
+ const centerX = (group.bounds.minX + group.bounds.maxX) / 2;
782
+ const centerY = (group.bounds.minY + group.bounds.maxY) / 2;
783
+ const pads = [
784
+ {
785
+ padId: `partition_${group.partitionIndex}_body`,
786
+ networkId: `partition_${group.partitionIndex}_disconnected`,
613
787
  type: "rect",
614
- offset: { x: relativeChipX, y: relativeChipY },
615
- size: { x: chip.size.x, y: chip.size.y }
616
- });
617
- for (const pinId of chip.pins) {
618
- const pin = chipPinMap[pinId];
619
- if (!pin) continue;
620
- const pinX = relativeChipX + pin.offset.x;
621
- const pinY = relativeChipY + pin.offset.y;
622
- const networkId = pinToNetworkMap.get(pinId) || pinId;
623
- pads.push({
624
- padId: pinId,
625
- networkId,
626
- type: "rect",
627
- offset: { x: pinX, y: pinY },
628
- size: { x: 0.2, y: 0.2 }
629
- // Small size for pins
630
- });
788
+ offset: { x: 0, y: 0 },
789
+ size: {
790
+ x: Math.max(partitionWidth, 0.1),
791
+ y: Math.max(partitionHeight, 0.1)
792
+ }
631
793
  }
632
- }
633
- let availableRotationDegrees = [
634
- 0,
635
- 90,
636
- 180,
637
- 270
638
794
  ];
795
+ const addedNetworks = /* @__PURE__ */ new Set();
796
+ const pinPositions = /* @__PURE__ */ new Map();
639
797
  for (const chipId of group.chipIds) {
640
- const chip = this.laidOutPartitions[group.partitionIndex].chipMap[chipId];
641
- const chipRotations = chip.availableRotations || [0, 90, 180, 270];
642
- availableRotationDegrees = availableRotationDegrees.filter(
643
- (rotation) => chipRotations.includes(rotation)
644
- );
645
- }
646
- if (availableRotationDegrees.length === 0) {
647
- availableRotationDegrees = [0];
798
+ const chipPlacement = packedPartition.layout.chipPlacements[chipId];
799
+ const chip = packedPartition.inputProblem.chipMap[chipId];
800
+ for (const pinId of chip.pins) {
801
+ const chipPin = packedPartition.inputProblem.chipPinMap[pinId];
802
+ if (!chipPin) continue;
803
+ let transformedOffset = { x: chipPin.offset.x, y: chipPin.offset.y };
804
+ const rotation = chipPlacement.ccwRotationDegrees || 0;
805
+ if (rotation === 90) {
806
+ transformedOffset = { x: -chipPin.offset.y, y: chipPin.offset.x };
807
+ } else if (rotation === 180) {
808
+ transformedOffset = { x: -chipPin.offset.x, y: -chipPin.offset.y };
809
+ } else if (rotation === 270) {
810
+ transformedOffset = { x: chipPin.offset.y, y: -chipPin.offset.x };
811
+ }
812
+ const absolutePinX = chipPlacement.x + transformedOffset.x;
813
+ const absolutePinY = chipPlacement.y + transformedOffset.y;
814
+ pinPositions.set(pinId, { x: absolutePinX, y: absolutePinY });
815
+ const networkId = pinToNetworkMap.get(pinId) || `${pinId}_disconnected`;
816
+ if (!addedNetworks.has(networkId)) {
817
+ addedNetworks.add(networkId);
818
+ const padOffsetX = absolutePinX - centerX;
819
+ const padOffsetY = absolutePinY - centerY;
820
+ pads.push({
821
+ padId: `${group.partitionIndex}_pin_${pinId}`,
822
+ networkId,
823
+ type: "rect",
824
+ offset: { x: padOffsetX, y: padOffsetY },
825
+ size: { x: 0.01, y: 0.01 }
826
+ // Small pin pad
827
+ });
828
+ }
829
+ }
648
830
  }
649
831
  return {
650
832
  componentId: `partition_${group.partitionIndex}`,
651
833
  pads,
652
- availableRotationDegrees
834
+ availableRotationDegrees: [0]
835
+ // Keep partitions unrotated
653
836
  };
654
837
  });
655
838
  return {
@@ -660,7 +843,7 @@ var PartitionPackingSolver = class extends BaseSolver {
660
843
  packPlacementStrategy: "minimum_sum_squared_distance_to_network"
661
844
  };
662
845
  }
663
- applyPackingResult(packedComponents, partitionGroups, currentLayout) {
846
+ applyPackingResult(packedComponents, partitionGroups) {
664
847
  const newChipPlacements = {};
665
848
  for (const packedComponent of packedComponents) {
666
849
  const partitionIndex = parseInt(
@@ -669,7 +852,8 @@ var PartitionPackingSolver = class extends BaseSolver {
669
852
  const group = partitionGroups.find(
670
853
  (g) => g.partitionIndex === partitionIndex
671
854
  );
672
- if (group) {
855
+ const packedPartition = this.packedPartitions[partitionIndex];
856
+ if (group && packedPartition) {
673
857
  const currentCenterX = (group.bounds.minX + group.bounds.maxX) / 2;
674
858
  const currentCenterY = (group.bounds.minY + group.bounds.maxY) / 2;
675
859
  const newCenterX = packedComponent.center.x;
@@ -677,7 +861,7 @@ var PartitionPackingSolver = class extends BaseSolver {
677
861
  const offsetX = newCenterX - currentCenterX;
678
862
  const offsetY = newCenterY - currentCenterY;
679
863
  for (const chipId of group.chipIds) {
680
- const originalPlacement = currentLayout.chipPlacements[chipId];
864
+ const originalPlacement = packedPartition.layout.chipPlacements[chipId];
681
865
  newChipPlacements[chipId] = {
682
866
  x: originalPlacement.x + offsetX,
683
867
  y: originalPlacement.y + offsetY,
@@ -688,8 +872,7 @@ var PartitionPackingSolver = class extends BaseSolver {
688
872
  }
689
873
  return {
690
874
  chipPlacements: newChipPlacements,
691
- groupPlacements: { ...currentLayout.groupPlacements }
692
- // Copy group placements unchanged
875
+ groupPlacements: {}
693
876
  };
694
877
  }
695
878
  visualize() {
@@ -701,1203 +884,113 @@ var PartitionPackingSolver = class extends BaseSolver {
701
884
  }
702
885
  const combinedProblem = {
703
886
  chipMap: {},
704
- groupMap: {},
705
887
  chipPinMap: {},
706
- groupPinMap: {},
707
888
  pinStrongConnMap: {},
708
889
  netMap: {},
709
890
  netConnMap: {},
710
891
  chipGap: this.inputProblem.chipGap,
711
892
  partitionGap: this.inputProblem.partitionGap
712
893
  };
713
- for (const laidOutPartition of this.laidOutPartitions) {
714
- Object.assign(combinedProblem.chipMap, laidOutPartition.chipMap);
715
- Object.assign(combinedProblem.groupMap, laidOutPartition.groupMap);
716
- Object.assign(combinedProblem.chipPinMap, laidOutPartition.chipPinMap);
717
- Object.assign(combinedProblem.groupPinMap, laidOutPartition.groupPinMap);
894
+ for (const packedPartition of this.packedPartitions) {
895
+ Object.assign(
896
+ combinedProblem.chipMap,
897
+ packedPartition.inputProblem.chipMap
898
+ );
899
+ Object.assign(
900
+ combinedProblem.chipPinMap,
901
+ packedPartition.inputProblem.chipPinMap
902
+ );
718
903
  Object.assign(
719
904
  combinedProblem.pinStrongConnMap,
720
- laidOutPartition.pinStrongConnMap
905
+ packedPartition.inputProblem.pinStrongConnMap
906
+ );
907
+ Object.assign(combinedProblem.netMap, packedPartition.inputProblem.netMap);
908
+ Object.assign(
909
+ combinedProblem.netConnMap,
910
+ packedPartition.inputProblem.netConnMap
721
911
  );
722
- Object.assign(combinedProblem.netMap, laidOutPartition.netMap);
723
- Object.assign(combinedProblem.netConnMap, laidOutPartition.netConnMap);
724
912
  }
725
913
  return visualizeInputProblem(combinedProblem, this.finalLayout);
726
914
  }
727
915
  getConstructorParams() {
728
916
  return {
729
- resolvedLayout: this.resolvedLayout,
730
- laidOutPartitions: this.laidOutPartitions,
917
+ packedPartitions: this.packedPartitions,
731
918
  inputProblem: this.inputProblem
732
919
  };
733
920
  }
734
921
  };
735
922
 
736
- // lib/solvers/PinRangeLayoutSolver/PinRangeLayoutSolver.ts
737
- import { stackGraphicsHorizontally as stackGraphicsHorizontally2 } from "graphics-debug";
738
-
739
- // lib/solvers/PinRangeLayoutSolver/SinglePinRangeLayoutSolver.ts
740
- import { pack as pack2 } from "calculate-packing";
741
- var SinglePinRangeLayoutSolver = class extends BaseSolver {
742
- pinRange;
923
+ // lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts
924
+ function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
925
+ return {
926
+ solverName,
927
+ solverClass,
928
+ getConstructorParams,
929
+ onSolved: opts.onSolved
930
+ };
931
+ }
932
+ var LayoutPipelineSolver = class extends BaseSolver {
933
+ chipPartitionsSolver;
934
+ packInnerPartitionsSolver;
935
+ partitionPackingSolver;
936
+ startTimeOfPhase;
937
+ endTimeOfPhase;
938
+ timeSpentOnPhase;
939
+ firstIterationOfPhase;
743
940
  inputProblem;
744
- layoutApplied = false;
745
- layout = null;
746
- constructor(pinRange, inputProblem) {
941
+ chipPartitions;
942
+ packedPartitions;
943
+ pipelineDef = [
944
+ definePipelineStep(
945
+ "chipPartitionsSolver",
946
+ ChipPartitionsSolver,
947
+ () => [this.inputProblem],
948
+ {
949
+ onSolved: (_layoutSolver) => {
950
+ this.chipPartitions = this.chipPartitionsSolver.partitions;
951
+ }
952
+ }
953
+ ),
954
+ definePipelineStep(
955
+ "packInnerPartitionsSolver",
956
+ PackInnerPartitionsSolver,
957
+ () => [this.chipPartitions || [this.inputProblem]],
958
+ {
959
+ onSolved: (_solver) => {
960
+ this.packedPartitions = this.packInnerPartitionsSolver.packedPartitions;
961
+ }
962
+ }
963
+ ),
964
+ definePipelineStep(
965
+ "partitionPackingSolver",
966
+ PartitionPackingSolver,
967
+ () => [
968
+ {
969
+ packedPartitions: this.packedPartitions || [],
970
+ inputProblem: this.inputProblem
971
+ }
972
+ ],
973
+ {
974
+ onSolved: (_solver) => {
975
+ }
976
+ }
977
+ )
978
+ ];
979
+ constructor(inputProblem) {
747
980
  super();
748
- this.pinRange = pinRange;
749
981
  this.inputProblem = inputProblem;
982
+ this.MAX_ITERATIONS = 1e3;
983
+ this.startTimeOfPhase = {};
984
+ this.endTimeOfPhase = {};
985
+ this.timeSpentOnPhase = {};
986
+ this.firstIterationOfPhase = {};
750
987
  }
988
+ currentPipelineStepIndex = 0;
751
989
  _step() {
752
- try {
753
- this.layout = this.createPinRangeLayout();
754
- this.layoutApplied = true;
990
+ const pipelineStepDef = this.pipelineDef[this.currentPipelineStepIndex];
991
+ if (!pipelineStepDef) {
755
992
  this.solved = true;
756
- } catch (error) {
757
- this.failed = true;
758
- this.error = `Failed to create pin range layout: ${error}`;
759
- }
760
- }
761
- /**
762
- * Build a connectivity map that normalizes network IDs by finding connected components.
763
- * All pins in the same connected component get the same network ID.
764
- */
765
- buildNetworkConnectivityMap(relevantPins) {
766
- const adjacency = /* @__PURE__ */ new Map();
767
- for (const pinId of relevantPins) {
768
- adjacency.set(pinId, /* @__PURE__ */ new Set());
769
- }
770
- for (const [connKey, connected] of Object.entries(
771
- this.inputProblem.pinStrongConnMap
772
- )) {
773
- if (connected) {
774
- const [pin1Id, pin2Id] = connKey.split("-");
775
- if (pin1Id && pin2Id && relevantPins.has(pin1Id) && relevantPins.has(pin2Id)) {
776
- adjacency.get(pin1Id)?.add(pin2Id);
777
- adjacency.get(pin2Id)?.add(pin1Id);
778
- }
779
- }
780
- }
781
- const visited = /* @__PURE__ */ new Set();
782
- const networkMap = /* @__PURE__ */ new Map();
783
- const dfs = (pinId, networkId) => {
784
- if (visited.has(pinId)) return;
785
- visited.add(pinId);
786
- networkMap.set(pinId, networkId);
787
- const neighbors = adjacency.get(pinId);
788
- if (neighbors) {
789
- for (const neighbor of neighbors) {
790
- dfs(neighbor, networkId);
791
- }
792
- }
793
- };
794
- for (const pinId of relevantPins) {
795
- if (!visited.has(pinId)) {
796
- const component = /* @__PURE__ */ new Set();
797
- const findComponent = (id) => {
798
- if (component.has(id)) return;
799
- component.add(id);
800
- const neighbors = adjacency.get(id);
801
- if (neighbors) {
802
- for (const neighbor of neighbors) {
803
- findComponent(neighbor);
804
- }
805
- }
806
- };
807
- findComponent(pinId);
808
- const networkId = Array.from(component).sort()[0] || pinId;
809
- dfs(pinId, networkId);
810
- }
811
- }
812
- return networkMap;
813
- }
814
- createPinRangeLayout() {
815
- const relevantChipIds = /* @__PURE__ */ new Set();
816
- for (const pinId of this.pinRange.pinIds) {
817
- const chipPin = this.inputProblem.chipPinMap[pinId];
818
- if (chipPin) {
819
- for (const [chipId, chip] of Object.entries(
820
- this.inputProblem.chipMap
821
- )) {
822
- if (chip.pins.includes(pinId)) {
823
- relevantChipIds.add(chipId);
824
- break;
825
- }
826
- }
827
- }
828
- }
829
- if (this.pinRange.connectedChips) {
830
- for (const chipId of this.pinRange.connectedChips) {
831
- relevantChipIds.add(chipId);
832
- }
833
- }
834
- const relevantPins = /* @__PURE__ */ new Set();
835
- for (const chipId of relevantChipIds) {
836
- const chip = this.inputProblem.chipMap[chipId];
837
- for (const pinId of chip.pins) {
838
- relevantPins.add(pinId);
839
- }
840
- }
841
- const networkMap = this.buildNetworkConnectivityMap(relevantPins);
842
- const preservedNetworks = /* @__PURE__ */ new Set();
843
- const pinRangePins = new Set(this.pinRange.pinIds);
844
- const connectedChips = new Set(this.pinRange.connectedChips || []);
845
- let pinRangeChipId = null;
846
- for (const pinId of this.pinRange.pinIds) {
847
- const chipPin = this.inputProblem.chipPinMap[pinId];
848
- if (chipPin) {
849
- for (const [chipId, chip] of Object.entries(
850
- this.inputProblem.chipMap
851
- )) {
852
- if (chip.pins.includes(pinId)) {
853
- pinRangeChipId = chipId;
854
- break;
855
- }
856
- }
857
- if (pinRangeChipId) break;
858
- }
859
- }
860
- const networkToPins = /* @__PURE__ */ new Map();
861
- for (const [pinId, networkId] of networkMap.entries()) {
862
- if (!networkToPins.has(networkId)) {
863
- networkToPins.set(networkId, []);
864
- }
865
- networkToPins.get(networkId).push(pinId);
866
- }
867
- for (const [networkId, pinsInNetwork] of networkToPins.entries()) {
868
- const hasPinRangePin = pinsInNetwork.some(
869
- (pinId) => pinRangePins.has(pinId)
870
- );
871
- if (hasPinRangePin) {
872
- const allPinsAllowed = pinsInNetwork.every((pinId) => {
873
- if (pinRangePins.has(pinId)) return true;
874
- for (const [chipId, chip] of Object.entries(
875
- this.inputProblem.chipMap
876
- )) {
877
- if (chip.pins.includes(pinId)) {
878
- return connectedChips.has(chipId);
879
- }
880
- }
881
- return false;
882
- });
883
- if (allPinsAllowed) {
884
- preservedNetworks.add(networkId);
885
- }
886
- }
887
- }
888
- let disconnectedCounter = 0;
889
- const components = Array.from(relevantChipIds).map((chipId) => {
890
- const chip = this.inputProblem.chipMap[chipId];
891
- const chipPins = chip.pins.map(
892
- (pinId) => this.inputProblem.chipPinMap[pinId]
893
- );
894
- const pads = chipPins.map((pin) => {
895
- let networkId = networkMap.get(pin.pinId) || pin.pinId;
896
- const isPinRangePin = pinRangePins.has(pin.pinId);
897
- let pinChipId = null;
898
- for (const [chipId2, chip2] of Object.entries(
899
- this.inputProblem.chipMap
900
- )) {
901
- if (chip2.pins.includes(pin.pinId)) {
902
- pinChipId = chipId2;
903
- break;
904
- }
905
- }
906
- const isConnectedChipPin = pinChipId && connectedChips.has(pinChipId);
907
- let shouldPreserveNetwork = false;
908
- if (isPinRangePin || isConnectedChipPin) {
909
- const pinsInThisNetwork = Array.from(networkMap.entries()).filter(([, netId]) => netId === networkId).map(([pinId]) => pinId);
910
- const hasPinRangePin = pinsInThisNetwork.some(
911
- (pinId) => pinRangePins.has(pinId)
912
- );
913
- const hasConnectedChipPin = pinsInThisNetwork.some((pinId) => {
914
- for (const [chipId2, chip2] of Object.entries(
915
- this.inputProblem.chipMap
916
- )) {
917
- if (chip2.pins.includes(pinId)) {
918
- return connectedChips.has(chipId2);
919
- }
920
- }
921
- return false;
922
- });
923
- if (hasPinRangePin && hasConnectedChipPin && (isPinRangePin || isConnectedChipPin)) {
924
- shouldPreserveNetwork = true;
925
- }
926
- }
927
- if (!shouldPreserveNetwork) {
928
- networkId = `disconnected_${disconnectedCounter++}`;
929
- }
930
- return {
931
- padId: pin.pinId,
932
- networkId,
933
- type: "rect",
934
- offset: pin.offset,
935
- size: { x: 0.05, y: 0.05 }
936
- };
937
- });
938
- pads.push({
939
- padId: `${chipId}-body`,
940
- networkId: `disconnected_${disconnectedCounter++}`,
941
- type: "rect",
942
- offset: { x: 0, y: 0 },
943
- size: { x: chip.size.x, y: chip.size.y }
944
- });
945
- return {
946
- componentId: chipId,
947
- pads,
948
- availableRotationDegrees: chip.availableRotations || [0, 90, 180, 270]
949
- };
950
- });
951
- if (components.length === 0) {
952
- return {
953
- chipPlacements: {},
954
- groupPlacements: {}
955
- };
956
- }
957
- const packInput = {
958
- components,
959
- minGap: this.inputProblem.chipGap,
960
- // Use chipGap from input problem
961
- packOrderStrategy: "largest_to_smallest",
962
- packPlacementStrategy: "minimum_sum_squared_distance_to_network"
963
- };
964
- const packResult = pack2(packInput);
965
- const chipPlacements = {};
966
- for (const component of packResult.components) {
967
- chipPlacements[component.componentId] = {
968
- x: component.center.x,
969
- y: component.center.y,
970
- ccwRotationDegrees: component.ccwRotationOffset
971
- };
972
- }
973
- return {
974
- chipPlacements,
975
- groupPlacements: {}
976
- };
977
- }
978
- visualize() {
979
- if (!this.layoutApplied || !this.layout) {
980
- return super.visualize();
981
- }
982
- const baseViz = visualizeInputProblem(this.inputProblem, this.layout);
983
- const rangePositions = this.pinRange.pinIds.map((pinId) => {
984
- const chipPin = this.inputProblem.chipPinMap[pinId];
985
- const groupPin = this.inputProblem.groupPinMap[pinId];
986
- const offset = chipPin?.offset || groupPin?.offset;
987
- if (offset && chipPin) {
988
- const chipId = Object.entries(this.inputProblem.chipMap).find(
989
- ([, chip]) => chip.pins.includes(pinId)
990
- )?.[0];
991
- if (chipId && this.layout) {
992
- const placement = this.layout.chipPlacements[chipId];
993
- if (placement) {
994
- const angleRad = placement.ccwRotationDegrees * Math.PI / 180;
995
- const cos = Math.cos(angleRad);
996
- const sin = Math.sin(angleRad);
997
- const rotatedOffset = {
998
- x: offset.x * cos - offset.y * sin,
999
- y: offset.x * sin + offset.y * cos
1000
- };
1001
- return {
1002
- x: placement.x + rotatedOffset.x,
1003
- y: placement.y + rotatedOffset.y
1004
- };
1005
- }
1006
- }
1007
- }
1008
- return offset;
1009
- }).filter((pos) => pos !== null && pos !== void 0);
1010
- const highlightRects = [];
1011
- const connectionLines = [];
1012
- if (rangePositions.length > 0) {
1013
- const xs = rangePositions.map((p) => p.x);
1014
- const ys = rangePositions.map((p) => p.y);
1015
- const minX = Math.min(...xs) - 0.1;
1016
- const maxX = Math.max(...xs) + 0.1;
1017
- const minY = Math.min(...ys) - 0.1;
1018
- const maxY = Math.max(...ys) + 0.1;
1019
- const rangeCenterX = (minX + maxX) / 2;
1020
- const rangeCenterY = (minY + maxY) / 2;
1021
- highlightRects.push({
1022
- center: { x: rangeCenterX, y: rangeCenterY },
1023
- width: Math.max(0.2, maxX - minX),
1024
- height: Math.max(0.2, maxY - minY),
1025
- strokeColor: "blue",
1026
- fillColor: "rgba(0, 0, 255, 0.1)",
1027
- label: `Pin Range (${this.pinRange.side})`
1028
- });
1029
- if (this.pinRange.connectedChips && this.pinRange.connectedChips.length > 0 && this.layout) {
1030
- for (const connectedChipId of this.pinRange.connectedChips) {
1031
- const placement = this.layout.chipPlacements[connectedChipId];
1032
- const chip = this.inputProblem.chipMap[connectedChipId];
1033
- if (placement && chip) {
1034
- connectionLines.push({
1035
- points: [
1036
- { x: rangeCenterX, y: rangeCenterY },
1037
- { x: placement.x, y: placement.y }
1038
- ],
1039
- strokeColor: "green",
1040
- strokeDashArray: [5, 5]
1041
- });
1042
- highlightRects.push({
1043
- center: { x: placement.x, y: placement.y },
1044
- width: chip.size.x + 0.2,
1045
- height: chip.size.y + 0.2,
1046
- strokeColor: "green",
1047
- fillColor: "rgba(0, 255, 0, 0.1)",
1048
- strokeDashArray: [3, 3],
1049
- label: `Connected: ${connectedChipId}`
1050
- });
1051
- }
1052
- }
1053
- }
1054
- }
1055
- return {
1056
- ...baseViz,
1057
- rects: [...baseViz.rects || [], ...highlightRects],
1058
- lines: [...baseViz.lines || [], ...connectionLines]
1059
- };
1060
- }
1061
- getConstructorParams() {
1062
- return { pinRange: this.pinRange, inputProblem: this.inputProblem };
1063
- }
1064
- };
1065
-
1066
- // lib/solvers/PinRangeLayoutSolver/PinRangeLayoutSolver.ts
1067
- var PinRangeLayoutSolver = class extends BaseSolver {
1068
- pinRanges;
1069
- inputProblems;
1070
- currentRangeIndex = 0;
1071
- activeSolver = null;
1072
- completedSolvers = [];
1073
- constructor(pinRanges, inputProblems) {
1074
- super();
1075
- this.pinRanges = pinRanges;
1076
- this.inputProblems = inputProblems;
1077
- }
1078
- _step() {
1079
- if (this.currentRangeIndex >= this.pinRanges.length) {
1080
- this.solved = true;
1081
- return;
1082
- }
1083
- if (!this.activeSolver) {
1084
- const currentRange = this.pinRanges[this.currentRangeIndex];
1085
- const inputProblem = this.findInputProblemForRange(currentRange);
1086
- if (!inputProblem) {
1087
- this.failed = true;
1088
- this.error = `Could not find input problem for range ${this.currentRangeIndex}`;
1089
- return;
1090
- }
1091
- this.activeSolver = new SinglePinRangeLayoutSolver(
1092
- currentRange,
1093
- inputProblem
1094
- );
1095
- }
1096
- if (!this.activeSolver.solved && !this.activeSolver.failed) {
1097
- this.activeSolver.step();
1098
- return;
1099
- }
1100
- if (this.activeSolver.failed) {
1101
- this.failed = true;
1102
- this.error = `Pin range ${this.currentRangeIndex} failed: ${this.activeSolver.error}`;
1103
- return;
1104
- }
1105
- if (this.activeSolver.solved) {
1106
- this.completedSolvers.push(this.activeSolver);
1107
- this.currentRangeIndex++;
1108
- this.activeSolver = null;
1109
- }
1110
- }
1111
- findInputProblemForRange(range) {
1112
- for (const inputProblem of this.inputProblems) {
1113
- const hasAllPins = range.pinIds.every(
1114
- (pinId) => inputProblem.chipPinMap[pinId] || inputProblem.groupPinMap[pinId]
1115
- );
1116
- if (hasAllPins) {
1117
- return inputProblem;
1118
- }
1119
- }
1120
- return null;
1121
- }
1122
- visualize() {
1123
- if (this.completedSolvers.length === 0 && !this.activeSolver) {
1124
- return super.visualize();
1125
- }
1126
- const visualizations = [];
1127
- const titles = [];
1128
- for (let i = 0; i < this.completedSolvers.length; i++) {
1129
- const solver = this.completedSolvers[i];
1130
- visualizations.push(solver.visualize());
1131
- titles.push(`Range ${i} (${solver.pinRange.side})`);
1132
- }
1133
- if (this.activeSolver) {
1134
- visualizations.push(this.activeSolver.visualize());
1135
- titles.push(
1136
- `Range ${this.currentRangeIndex} (${this.activeSolver.pinRange.side}) - Active`
1137
- );
1138
- }
1139
- if (visualizations.length === 0) {
1140
- return super.visualize();
1141
- }
1142
- return stackGraphicsHorizontally2(visualizations, { titles });
1143
- }
1144
- getConstructorParams() {
1145
- return { pinRanges: this.pinRanges, inputProblems: this.inputProblems };
1146
- }
1147
- };
1148
-
1149
- // lib/solvers/PinRangeMatchSolver/PinRangeMatchSolver.ts
1150
- import { stackGraphicsHorizontally as stackGraphicsHorizontally3 } from "graphics-debug";
1151
-
1152
- // lib/solvers/PinRangeMatchSolver/PartitionPinRangeMatchSolver/PartitionPinRangeMatchSolver.ts
1153
- var MAX_PIN_RANGE_GAP = 0.2;
1154
- var MAX_PIN_RANGE_SIZE = 3;
1155
- var PartitionPinRangeMatchSolver = class extends BaseSolver {
1156
- inputProblem;
1157
- pinRanges = [];
1158
- constructor(inputProblem) {
1159
- super();
1160
- this.inputProblem = inputProblem;
1161
- }
1162
- _step() {
1163
- this.pinRanges = this.createPinRanges();
1164
- this.solved = true;
1165
- }
1166
- createPinRanges() {
1167
- const pinRanges = [];
1168
- const passiveChips = /* @__PURE__ */ new Set();
1169
- for (const [chipId, chip] of Object.entries(this.inputProblem.chipMap)) {
1170
- if (chip.pins.length === 2) {
1171
- let connectedToLargerChip = false;
1172
- for (const pinId of chip.pins) {
1173
- for (const [connKey, connected] of Object.entries(
1174
- this.inputProblem.pinStrongConnMap
1175
- )) {
1176
- if (!connected) continue;
1177
- const [pin1Id, pin2Id] = connKey.split("-");
1178
- let connectedPinId = null;
1179
- if (pin1Id === pinId) {
1180
- connectedPinId = pin2Id;
1181
- } else if (pin2Id === pinId) {
1182
- connectedPinId = pin1Id;
1183
- }
1184
- if (connectedPinId) {
1185
- for (const [, otherChip] of Object.entries(
1186
- this.inputProblem.chipMap
1187
- )) {
1188
- if (otherChip.pins.includes(connectedPinId) && otherChip.pins.length > 2) {
1189
- connectedToLargerChip = true;
1190
- break;
1191
- }
1192
- }
1193
- }
1194
- if (connectedToLargerChip) break;
1195
- }
1196
- if (connectedToLargerChip) break;
1197
- }
1198
- if (connectedToLargerChip) {
1199
- passiveChips.add(chipId);
1200
- }
1201
- }
1202
- }
1203
- for (const [chipId, chip] of Object.entries(this.inputProblem.chipMap)) {
1204
- if (!passiveChips.has(chipId)) {
1205
- const chipPinRanges = this.createPinRangesForChip(chipId, chip.pins);
1206
- pinRanges.push(...chipPinRanges);
1207
- }
1208
- }
1209
- for (const [groupId, group] of Object.entries(this.inputProblem.groupMap)) {
1210
- const groupPinRanges = this.createPinRangesForGroup(groupId, group.pins);
1211
- pinRanges.push(...groupPinRanges);
1212
- }
1213
- for (const range of pinRanges) {
1214
- const connectedInfo = this.findConnectedPassives(
1215
- range.pinIds,
1216
- passiveChips
1217
- );
1218
- range.connectedPins = connectedInfo.connectedPins;
1219
- range.connectedChips = connectedInfo.connectedChips;
1220
- }
1221
- return pinRanges;
1222
- }
1223
- createPinRangesForChip(chipId, pinIds) {
1224
- const pinsBySide = /* @__PURE__ */ new Map();
1225
- for (const pinId of pinIds) {
1226
- const chipPin = this.inputProblem.chipPinMap[pinId];
1227
- if (!chipPin) continue;
1228
- if (!pinsBySide.has(chipPin.side)) {
1229
- pinsBySide.set(chipPin.side, []);
1230
- }
1231
- pinsBySide.get(chipPin.side).push({ pinId, offset: chipPin.offset });
1232
- }
1233
- const pinRanges = [];
1234
- for (const [side, pins] of pinsBySide.entries()) {
1235
- const ranges = this.createPinRangesForSide(side, pins, chipId);
1236
- pinRanges.push(...ranges);
1237
- }
1238
- return pinRanges;
1239
- }
1240
- createPinRangesForGroup(groupId, pinIds) {
1241
- const pinsWithOffsets = pinIds.map((pinId) => {
1242
- const groupPin = this.inputProblem.groupPinMap[pinId];
1243
- return groupPin ? { pinId, offset: groupPin.offset } : null;
1244
- }).filter((pin) => pin !== null && pin.offset !== void 0);
1245
- if (pinsWithOffsets.length === 0) return [];
1246
- const side = "x+";
1247
- return this.createPinRangesForSide(
1248
- side,
1249
- pinsWithOffsets,
1250
- void 0,
1251
- groupId
1252
- );
1253
- }
1254
- createPinRangesForSide(side, pins, chipId, groupId) {
1255
- if (pins.length === 0) return [];
1256
- const sortedPins = this.sortPinsBySide(pins, side);
1257
- const pinRanges = [];
1258
- let currentRange = [];
1259
- for (let i = 0; i < sortedPins.length; i++) {
1260
- const pin = sortedPins[i];
1261
- if (currentRange.length === 0) {
1262
- currentRange = [pin.pinId];
1263
- } else if (currentRange.length < MAX_PIN_RANGE_SIZE) {
1264
- const prevPin = sortedPins[i - 1];
1265
- const distance = this.calculateDistance(prevPin.offset, pin.offset);
1266
- if (distance <= MAX_PIN_RANGE_GAP) {
1267
- currentRange.push(pin.pinId);
1268
- } else {
1269
- pinRanges.push({
1270
- pinIds: [...currentRange],
1271
- side,
1272
- chipId,
1273
- groupId
1274
- });
1275
- currentRange = [pin.pinId];
1276
- }
1277
- } else {
1278
- pinRanges.push({
1279
- pinIds: [...currentRange],
1280
- side,
1281
- chipId,
1282
- groupId
1283
- });
1284
- currentRange = [pin.pinId];
1285
- }
1286
- }
1287
- if (currentRange.length > 0) {
1288
- pinRanges.push({
1289
- pinIds: [...currentRange],
1290
- side,
1291
- chipId,
1292
- groupId
1293
- });
1294
- }
1295
- return pinRanges;
1296
- }
1297
- sortPinsBySide(pins, side) {
1298
- return pins.sort((a, b) => {
1299
- switch (side) {
1300
- case "x-":
1301
- case "x+":
1302
- return a.offset.y - b.offset.y;
1303
- case "y-":
1304
- case "y+":
1305
- return a.offset.x - b.offset.x;
1306
- default:
1307
- return 0;
1308
- }
1309
- });
1310
- }
1311
- calculateDistance(p1, p2) {
1312
- return Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
1313
- }
1314
- findConnectedPassives(rangePinIds, passiveChips) {
1315
- const connectedPins = [];
1316
- const connectedChips = [];
1317
- for (const rangePinId of rangePinIds) {
1318
- for (const [connKey, connected] of Object.entries(
1319
- this.inputProblem.pinStrongConnMap
1320
- )) {
1321
- if (!connected) continue;
1322
- const [pin1Id, pin2Id] = connKey.split("-");
1323
- let connectedPinId = null;
1324
- if (pin1Id === rangePinId) {
1325
- connectedPinId = pin2Id;
1326
- } else if (pin2Id === rangePinId) {
1327
- connectedPinId = pin1Id;
1328
- }
1329
- if (connectedPinId) {
1330
- for (const [chipId, chip] of Object.entries(
1331
- this.inputProblem.chipMap
1332
- )) {
1333
- if (chip.pins.includes(connectedPinId) && passiveChips.has(chipId)) {
1334
- if (!connectedChips.includes(chipId)) {
1335
- connectedChips.push(chipId);
1336
- connectedPins.push(
1337
- ...chip.pins.filter(
1338
- (pinId) => !connectedPins.includes(pinId)
1339
- )
1340
- );
1341
- }
1342
- break;
1343
- }
1344
- }
1345
- }
1346
- }
1347
- }
1348
- return { connectedPins, connectedChips };
1349
- }
1350
- visualize() {
1351
- return {
1352
- lines: [],
1353
- points: this.pinRanges.flatMap((range) => {
1354
- const rangePinPoints = range.pinIds.map((pinId) => {
1355
- const chipPin = this.inputProblem.chipPinMap[pinId];
1356
- const groupPin = this.inputProblem.groupPinMap[pinId];
1357
- const offset = chipPin?.offset || groupPin?.offset;
1358
- return offset ? { x: offset.x, y: offset.y, color: "blue" } : null;
1359
- }).filter(
1360
- (point) => point !== null
1361
- );
1362
- const connectedPinPoints = (range.connectedPins || []).map((pinId) => {
1363
- const chipPin = this.inputProblem.chipPinMap[pinId];
1364
- const groupPin = this.inputProblem.groupPinMap[pinId];
1365
- const offset = chipPin?.offset || groupPin?.offset;
1366
- return offset ? { x: offset.x, y: offset.y, color: "orange" } : null;
1367
- }).filter(
1368
- (point) => point !== null
1369
- );
1370
- return [...rangePinPoints, ...connectedPinPoints];
1371
- }),
1372
- rects: [],
1373
- circles: []
1374
- };
1375
- }
1376
- getConstructorParams() {
1377
- return { inputProblem: this.inputProblem };
1378
- }
1379
- };
1380
-
1381
- // lib/solvers/PinRangeMatchSolver/PinRangeMatchSolver.ts
1382
- var PinRangeMatchSolver = class extends BaseSolver {
1383
- partitions;
1384
- currentPartitionIndex = 0;
1385
- activeSubSolver = null;
1386
- partitionResults = [];
1387
- constructor(partitions) {
1388
- super();
1389
- this.partitions = partitions;
1390
- }
1391
- _step() {
1392
- if (this.currentPartitionIndex >= this.partitions.length) {
1393
- this.solved = true;
1394
- return;
1395
- }
1396
- if (!this.activeSubSolver) {
1397
- const currentPartition = this.partitions[this.currentPartitionIndex];
1398
- this.activeSubSolver = new PartitionPinRangeMatchSolver(currentPartition);
1399
- }
1400
- if (!this.activeSubSolver.solved && !this.activeSubSolver.failed) {
1401
- this.activeSubSolver.step();
1402
- return;
1403
- }
1404
- if (this.activeSubSolver.failed) {
1405
- this.failed = true;
1406
- this.error = `Partition ${this.currentPartitionIndex} failed: ${this.activeSubSolver.error}`;
1407
- return;
1408
- }
1409
- if (this.activeSubSolver.solved) {
1410
- this.partitionResults.push(this.activeSubSolver.pinRanges);
1411
- this.currentPartitionIndex++;
1412
- this.activeSubSolver = null;
1413
- }
1414
- }
1415
- getAllPinRanges() {
1416
- return this.partitionResults.flat();
1417
- }
1418
- visualize() {
1419
- if (this.activeSubSolver && !this.activeSubSolver.solved) {
1420
- return this.activeSubSolver.visualize();
1421
- }
1422
- if (this.partitions.length === 0) {
1423
- return super.visualize();
1424
- }
1425
- const partitionVisualizations = this.partitions.map(
1426
- (partition, partitionIndex) => {
1427
- const basicLayout = doBasicInputProblemLayout(partition);
1428
- const baseViz = visualizeInputProblem(partition, basicLayout);
1429
- const partitionRanges = this.partitionResults[partitionIndex] || [];
1430
- const highlightRects = [];
1431
- const connectionLines = [];
1432
- for (const [rangeIndex, range] of partitionRanges.entries()) {
1433
- const rangePositions = range.pinIds.map((pinId) => {
1434
- const chipPin = partition.chipPinMap[pinId];
1435
- const groupPin = partition.groupPinMap[pinId];
1436
- const offset = chipPin?.offset || groupPin?.offset;
1437
- if (offset && chipPin) {
1438
- const chipId = Object.entries(partition.chipMap).find(
1439
- ([, chip]) => chip.pins.includes(pinId)
1440
- )?.[0];
1441
- if (chipId) {
1442
- const placement = basicLayout.chipPlacements[chipId];
1443
- if (placement) {
1444
- const angleRad = placement.ccwRotationDegrees * Math.PI / 180;
1445
- const cos = Math.cos(angleRad);
1446
- const sin = Math.sin(angleRad);
1447
- const rotatedOffset = {
1448
- x: offset.x * cos - offset.y * sin,
1449
- y: offset.x * sin + offset.y * cos
1450
- };
1451
- return {
1452
- x: placement.x + rotatedOffset.x,
1453
- y: placement.y + rotatedOffset.y
1454
- };
1455
- }
1456
- }
1457
- }
1458
- return offset;
1459
- }).filter((pos) => pos !== null && pos !== void 0);
1460
- const rangeColor = `hsl(${rangeIndex * 60 % 360}, 70%, 50%)`;
1461
- let rangeCenterX = 0;
1462
- let rangeCenterY = 0;
1463
- if (rangePositions.length > 0) {
1464
- const xs = rangePositions.map((p) => p.x);
1465
- const ys = rangePositions.map((p) => p.y);
1466
- const minX = Math.min(...xs) - 0.05;
1467
- const maxX = Math.max(...xs) + 0.05;
1468
- const minY = Math.min(...ys) - 0.05;
1469
- const maxY = Math.max(...ys) + 0.05;
1470
- rangeCenterX = (minX + maxX) / 2;
1471
- rangeCenterY = (minY + maxY) / 2;
1472
- highlightRects.push({
1473
- center: { x: rangeCenterX, y: rangeCenterY },
1474
- width: Math.max(0.1, maxX - minX),
1475
- height: Math.max(0.1, maxY - minY),
1476
- strokeColor: rangeColor,
1477
- fillColor: `hsla(${rangeIndex * 60 % 360}, 70%, 50%, 0.1)`,
1478
- label: `Range ${rangeIndex} (${range.side})`
1479
- });
1480
- }
1481
- if (range.connectedChips && range.connectedChips.length > 0) {
1482
- const connectedPinRangeName = `Range ${rangeIndex} (${range.side})`;
1483
- for (const connectedChipId of range.connectedChips) {
1484
- const placement = basicLayout.chipPlacements[connectedChipId];
1485
- const chip = partition.chipMap[connectedChipId];
1486
- if (placement && rangePositions.length > 0 && chip) {
1487
- connectionLines.push({
1488
- points: [
1489
- { x: rangeCenterX, y: rangeCenterY },
1490
- { x: placement.x, y: placement.y }
1491
- ],
1492
- strokeColor: rangeColor,
1493
- strokeDashArray: [5, 5]
1494
- });
1495
- highlightRects.push({
1496
- center: { x: placement.x, y: placement.y },
1497
- width: chip.size.x + 0.1,
1498
- height: chip.size.y + 0.1,
1499
- strokeColor: rangeColor,
1500
- fillColor: `hsla(${rangeIndex * 60 % 360}, 70%, 50%, 0.05)`,
1501
- strokeDashArray: [3, 3],
1502
- label: `${connectedChipId}
1503
- ${connectedPinRangeName}`
1504
- });
1505
- }
1506
- }
1507
- }
1508
- }
1509
- return {
1510
- ...baseViz,
1511
- rects: [...baseViz.rects || [], ...highlightRects],
1512
- lines: [...baseViz.lines || [], ...connectionLines]
1513
- };
1514
- }
1515
- );
1516
- const titles = this.partitions.map((_, index) => {
1517
- const ranges = this.partitionResults[index] || [];
1518
- const rangeCount = ranges.length;
1519
- const connectedCount = ranges.reduce(
1520
- (sum, range) => sum + (range.connectedChips?.length || 0),
1521
- 0
1522
- );
1523
- return `Partition ${index} (${rangeCount} ranges, ${connectedCount} passives)`;
1524
- });
1525
- return stackGraphicsHorizontally3(partitionVisualizations, { titles });
1526
- }
1527
- getConstructorParams() {
1528
- return { partitions: this.partitions };
1529
- }
1530
- };
1531
-
1532
- // lib/solvers/PinRangeOverlapSolver/PinRangeOverlapSolver.ts
1533
- import { stackGraphicsHorizontally as stackGraphicsHorizontally4 } from "graphics-debug";
1534
- var PinRangeOverlapSolver = class extends BaseSolver {
1535
- pinRangeLayoutSolver = null;
1536
- inputProblems;
1537
- resolvedLayout = null;
1538
- constructor(pinRangeLayoutSolver, inputProblems) {
1539
- super();
1540
- this.pinRangeLayoutSolver = pinRangeLayoutSolver;
1541
- this.inputProblems = inputProblems;
1542
- }
1543
- _step() {
1544
- try {
1545
- if (!this.pinRangeLayoutSolver?.solved) {
1546
- this.failed = true;
1547
- this.error = "PinRangeLayoutSolver not solved";
1548
- return;
1549
- }
1550
- const partitionLayouts = this.groupPlacementsByPartition();
1551
- const resolvedPartitionLayouts = partitionLayouts.map(
1552
- (partitionLayout) => this.resolvePartitionOverlaps(partitionLayout)
1553
- );
1554
- const finalLayout = this.positionPartitionsHorizontally(
1555
- resolvedPartitionLayouts
1556
- );
1557
- this.resolvedLayout = finalLayout;
1558
- this.solved = true;
1559
- } catch (error) {
1560
- this.failed = true;
1561
- this.error = `Failed to resolve pin range overlaps: ${error}`;
1562
- }
1563
- }
1564
- groupPlacementsByPartition() {
1565
- const partitionLayouts = [];
1566
- for (let i = 0; i < this.inputProblems.length; i++) {
1567
- partitionLayouts.push({
1568
- partitionIndex: i,
1569
- inputProblem: this.inputProblems[i],
1570
- chipPlacements: {},
1571
- groupPlacements: {}
1572
- });
1573
- }
1574
- for (const singleSolver of this.pinRangeLayoutSolver.completedSolvers) {
1575
- if (singleSolver.layout) {
1576
- const partitionIndex = this.findPartitionIndexForSolver(singleSolver);
1577
- if (partitionIndex >= 0) {
1578
- Object.assign(
1579
- partitionLayouts[partitionIndex].chipPlacements,
1580
- singleSolver.layout.chipPlacements
1581
- );
1582
- Object.assign(
1583
- partitionLayouts[partitionIndex].groupPlacements,
1584
- singleSolver.layout.groupPlacements
1585
- );
1586
- }
1587
- }
1588
- }
1589
- if (this.pinRangeLayoutSolver.activeSolver?.layout) {
1590
- const partitionIndex = this.findPartitionIndexForSolver(
1591
- this.pinRangeLayoutSolver.activeSolver
1592
- );
1593
- if (partitionIndex >= 0) {
1594
- Object.assign(
1595
- partitionLayouts[partitionIndex].chipPlacements,
1596
- this.pinRangeLayoutSolver.activeSolver.layout.chipPlacements
1597
- );
1598
- Object.assign(
1599
- partitionLayouts[partitionIndex].groupPlacements,
1600
- this.pinRangeLayoutSolver.activeSolver.layout.groupPlacements
1601
- );
1602
- }
1603
- }
1604
- return partitionLayouts;
1605
- }
1606
- findPartitionIndexForSolver(singleSolver) {
1607
- if (!singleSolver.layout) return -1;
1608
- const layoutChipIds = Object.keys(singleSolver.layout.chipPlacements);
1609
- const layoutGroupIds = Object.keys(singleSolver.layout.groupPlacements);
1610
- for (let i = 0; i < this.inputProblems.length; i++) {
1611
- const inputProblem = this.inputProblems[i];
1612
- const hasAnyChip = layoutChipIds.some(
1613
- (chipId) => inputProblem.chipMap[chipId]
1614
- );
1615
- const hasAnyGroup = layoutGroupIds.some(
1616
- (groupId) => inputProblem.groupMap[groupId]
1617
- );
1618
- if (hasAnyChip || hasAnyGroup) {
1619
- return i;
1620
- }
1621
- }
1622
- return -1;
1623
- }
1624
- resolvePartitionOverlaps(partitionLayout) {
1625
- const resolvedLayout = {
1626
- ...partitionLayout,
1627
- chipPlacements: { ...partitionLayout.chipPlacements },
1628
- groupPlacements: { ...partitionLayout.groupPlacements }
1629
- };
1630
- const overlaps = this.findOverlaps(resolvedLayout.chipPlacements);
1631
- if (overlaps.length > 0) {
1632
- this.resolveOverlaps(resolvedLayout.chipPlacements, overlaps);
1633
- }
1634
- return resolvedLayout;
1635
- }
1636
- positionPartitionsHorizontally(partitionLayouts) {
1637
- const finalChipPlacements = {};
1638
- const finalGroupPlacements = {};
1639
- let currentOffsetX = 0;
1640
- const partitionGap = 5;
1641
- for (const partitionLayout of partitionLayouts) {
1642
- const chipIds = Object.keys(partitionLayout.chipPlacements);
1643
- if (chipIds.length === 0) continue;
1644
- const xs = chipIds.map(
1645
- (chipId) => partitionLayout.chipPlacements[chipId].x
1646
- );
1647
- const partitionMinX = Math.min(...xs);
1648
- const partitionMaxX = Math.max(...xs);
1649
- const partitionWidth = partitionMaxX - partitionMinX;
1650
- const offsetX = currentOffsetX - partitionMinX;
1651
- for (const [chipId, placement] of Object.entries(
1652
- partitionLayout.chipPlacements
1653
- )) {
1654
- finalChipPlacements[chipId] = {
1655
- x: placement.x + offsetX,
1656
- y: placement.y,
1657
- ccwRotationDegrees: placement.ccwRotationDegrees
1658
- };
1659
- }
1660
- for (const [groupId, placement] of Object.entries(
1661
- partitionLayout.groupPlacements
1662
- )) {
1663
- finalGroupPlacements[groupId] = {
1664
- x: placement.x + offsetX,
1665
- y: placement.y,
1666
- ccwRotationDegrees: placement.ccwRotationDegrees
1667
- };
1668
- }
1669
- currentOffsetX += partitionWidth + partitionGap;
1670
- }
1671
- return {
1672
- chipPlacements: finalChipPlacements,
1673
- groupPlacements: finalGroupPlacements
1674
- };
1675
- }
1676
- findOverlaps(chipPlacements) {
1677
- const components = this.getComponentBounds(chipPlacements);
1678
- const overlaps = [];
1679
- for (let i = 0; i < components.length; i++) {
1680
- for (let j = i + 1; j < components.length; j++) {
1681
- const comp1 = components[i];
1682
- const comp2 = components[j];
1683
- if (this.boundsOverlap(comp1.bounds, comp2.bounds)) {
1684
- overlaps.push({
1685
- chip1: comp1.chipId,
1686
- chip2: comp2.chipId,
1687
- bounds1: comp1.bounds,
1688
- bounds2: comp2.bounds
1689
- });
1690
- }
1691
- }
1692
- }
1693
- return overlaps;
1694
- }
1695
- getComponentBounds(chipPlacements) {
1696
- const components = [];
1697
- for (const [chipId, placement] of Object.entries(chipPlacements)) {
1698
- let chipSize = { x: 1, y: 1 };
1699
- for (const inputProblem of this.inputProblems) {
1700
- const chip = inputProblem.chipMap[chipId];
1701
- if (chip) {
1702
- chipSize = chip.size;
1703
- break;
1704
- }
1705
- }
1706
- const halfWidth = chipSize.x / 2;
1707
- const halfHeight = chipSize.y / 2;
1708
- const bounds = {
1709
- minX: placement.x - halfWidth,
1710
- maxX: placement.x + halfWidth,
1711
- minY: placement.y - halfHeight,
1712
- maxY: placement.y + halfHeight
1713
- };
1714
- components.push({
1715
- chipId,
1716
- bounds,
1717
- placement
1718
- });
1719
- }
1720
- return components;
1721
- }
1722
- boundsOverlap(bounds1, bounds2) {
1723
- return !(bounds1.maxX <= bounds2.minX || bounds1.minX >= bounds2.maxX || bounds1.maxY <= bounds2.minY || bounds1.minY >= bounds2.maxY);
1724
- }
1725
- resolveOverlaps(chipPlacements, overlaps) {
1726
- for (const overlap of overlaps) {
1727
- const { chip1, chip2, bounds1, bounds2 } = overlap;
1728
- const overlapX = Math.min(
1729
- bounds1.maxX - bounds2.minX,
1730
- bounds2.maxX - bounds1.minX
1731
- );
1732
- const overlapY = Math.min(
1733
- bounds1.maxY - bounds2.minY,
1734
- bounds2.maxY - bounds1.minY
1735
- );
1736
- const placement1 = chipPlacements[chip1];
1737
- const placement2 = chipPlacements[chip2];
1738
- if (overlapX < overlapY) {
1739
- const separation = overlapX / 2 + 0.1;
1740
- if (placement1.x < placement2.x) {
1741
- placement1.x -= separation;
1742
- placement2.x += separation;
1743
- } else {
1744
- placement1.x += separation;
1745
- placement2.x -= separation;
1746
- }
1747
- } else {
1748
- const separation = overlapY / 2 + 0.1;
1749
- if (placement1.y < placement2.y) {
1750
- placement1.y -= separation;
1751
- placement2.y += separation;
1752
- } else {
1753
- placement1.y += separation;
1754
- placement2.y -= separation;
1755
- }
1756
- }
1757
- }
1758
- }
1759
- visualize() {
1760
- if (!this.resolvedLayout) {
1761
- return super.visualize();
1762
- }
1763
- const partitionLayouts = this.groupPlacementsByPartition();
1764
- const partitionVisualizations = [];
1765
- for (const partitionLayout of partitionLayouts) {
1766
- if (Object.keys(partitionLayout.chipPlacements).length === 0) continue;
1767
- const partitionOutputLayout = {
1768
- chipPlacements: {},
1769
- groupPlacements: {}
1770
- };
1771
- for (const chipId of Object.keys(partitionLayout.chipPlacements)) {
1772
- if (this.resolvedLayout.chipPlacements[chipId]) {
1773
- partitionOutputLayout.chipPlacements[chipId] = this.resolvedLayout.chipPlacements[chipId];
1774
- }
1775
- }
1776
- for (const groupId of Object.keys(partitionLayout.groupPlacements)) {
1777
- if (this.resolvedLayout.groupPlacements[groupId]) {
1778
- partitionOutputLayout.groupPlacements[groupId] = this.resolvedLayout.groupPlacements[groupId];
1779
- }
1780
- }
1781
- const viz = visualizeInputProblem(
1782
- partitionLayout.inputProblem,
1783
- partitionOutputLayout
1784
- );
1785
- partitionVisualizations.push({
1786
- ...viz,
1787
- title: `Partition ${partitionLayout.partitionIndex + 1}`
1788
- });
1789
- }
1790
- if (partitionVisualizations.length === 0) {
1791
- return super.visualize();
1792
- }
1793
- if (partitionVisualizations.length === 1) {
1794
- return partitionVisualizations[0];
1795
- }
1796
- return stackGraphicsHorizontally4(partitionVisualizations);
1797
- }
1798
- getConstructorParams() {
1799
- return {
1800
- pinRangeLayoutSolver: this.pinRangeLayoutSolver,
1801
- inputProblems: this.inputProblems
1802
- };
1803
- }
1804
- };
1805
-
1806
- // lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts
1807
- function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
1808
- return {
1809
- solverName,
1810
- solverClass,
1811
- getConstructorParams,
1812
- onSolved: opts.onSolved
1813
- };
1814
- }
1815
- var LayoutPipelineSolver = class extends BaseSolver {
1816
- chipPartitionsSolver;
1817
- pinRangeMatchSolver;
1818
- pinRangeLayoutSolver;
1819
- pinRangeOverlapSolver;
1820
- partitionPackingSolver;
1821
- startTimeOfPhase;
1822
- endTimeOfPhase;
1823
- timeSpentOnPhase;
1824
- firstIterationOfPhase;
1825
- inputProblem;
1826
- chipPartitions;
1827
- pinRanges;
1828
- pipelineDef = [
1829
- definePipelineStep(
1830
- "chipPartitionsSolver",
1831
- ChipPartitionsSolver,
1832
- () => [this.inputProblem],
1833
- {
1834
- onSolved: (_layoutSolver) => {
1835
- this.chipPartitions = this.chipPartitionsSolver.partitions;
1836
- }
1837
- }
1838
- ),
1839
- definePipelineStep(
1840
- "pinRangeMatchSolver",
1841
- PinRangeMatchSolver,
1842
- () => [this.chipPartitions || []],
1843
- {
1844
- onSolved: (_solver) => {
1845
- this.pinRanges = this.pinRangeMatchSolver.getAllPinRanges();
1846
- }
1847
- }
1848
- ),
1849
- definePipelineStep(
1850
- "pinRangeLayoutSolver",
1851
- PinRangeLayoutSolver,
1852
- () => [this.pinRanges || [], this.chipPartitions || [this.inputProblem]],
1853
- {
1854
- onSolved: (_solver) => {
1855
- }
1856
- }
1857
- ),
1858
- definePipelineStep(
1859
- "pinRangeOverlapSolver",
1860
- PinRangeOverlapSolver,
1861
- () => [
1862
- this.pinRangeLayoutSolver,
1863
- this.chipPartitions || [this.inputProblem]
1864
- ],
1865
- {
1866
- onSolved: (_solver) => {
1867
- }
1868
- }
1869
- ),
1870
- definePipelineStep(
1871
- "partitionPackingSolver",
1872
- PartitionPackingSolver,
1873
- () => [
1874
- {
1875
- resolvedLayout: this.pinRangeOverlapSolver.resolvedLayout,
1876
- laidOutPartitions: this.chipPartitions || [this.inputProblem],
1877
- inputProblem: this.inputProblem
1878
- }
1879
- ],
1880
- {
1881
- onSolved: (_solver) => {
1882
- }
1883
- }
1884
- )
1885
- ];
1886
- constructor(inputProblem) {
1887
- super();
1888
- this.inputProblem = inputProblem;
1889
- this.MAX_ITERATIONS = 1e3;
1890
- this.startTimeOfPhase = {};
1891
- this.endTimeOfPhase = {};
1892
- this.timeSpentOnPhase = {};
1893
- this.firstIterationOfPhase = {};
1894
- }
1895
- currentPipelineStepIndex = 0;
1896
- _step() {
1897
- const pipelineStepDef = this.pipelineDef[this.currentPipelineStepIndex];
1898
- if (!pipelineStepDef) {
1899
- this.solved = true;
1900
- return;
993
+ return;
1901
994
  }
1902
995
  if (this.activeSubSolver) {
1903
996
  this.activeSubSolver.step();
@@ -1936,18 +1029,14 @@ var LayoutPipelineSolver = class extends BaseSolver {
1936
1029
  return this.partitionPackingSolver.visualize();
1937
1030
  }
1938
1031
  const chipPartitionsViz = this.chipPartitionsSolver?.visualize();
1939
- const pinRangeMatchViz = this.pinRangeMatchSolver?.visualize();
1940
- const pinRangeLayoutViz = this.pinRangeLayoutSolver?.visualize();
1941
- const pinRangeOverlapViz = this.pinRangeOverlapSolver?.visualize();
1032
+ const packInnerPartitionsViz = this.packInnerPartitionsSolver?.visualize();
1942
1033
  const partitionPackingViz = this.partitionPackingSolver?.visualize();
1943
1034
  const basicLayout = doBasicInputProblemLayout(this.inputProblem);
1944
1035
  const inputViz = visualizeInputProblem(this.inputProblem, basicLayout);
1945
1036
  const visualizations = [
1946
1037
  inputViz,
1947
1038
  chipPartitionsViz,
1948
- pinRangeMatchViz,
1949
- pinRangeLayoutViz,
1950
- pinRangeOverlapViz,
1039
+ packInnerPartitionsViz,
1951
1040
  partitionPackingViz
1952
1041
  ].filter(Boolean).map((viz, stepIndex) => {
1953
1042
  for (const rect of viz.rects ?? []) {
@@ -1987,14 +1076,8 @@ var LayoutPipelineSolver = class extends BaseSolver {
1987
1076
  if (this.partitionPackingSolver?.solved) {
1988
1077
  return this.partitionPackingSolver.visualize();
1989
1078
  }
1990
- if (this.pinRangeOverlapSolver?.solved) {
1991
- return this.pinRangeOverlapSolver.visualize();
1992
- }
1993
- if (this.pinRangeLayoutSolver?.solved) {
1994
- return this.pinRangeLayoutSolver.visualize();
1995
- }
1996
- if (this.pinRangeMatchSolver?.solved) {
1997
- return this.pinRangeMatchSolver.visualize();
1079
+ if (this.packInnerPartitionsSolver?.solved) {
1080
+ return this.packInnerPartitionsSolver.visualize();
1998
1081
  }
1999
1082
  if (this.chipPartitionsSolver?.solved) {
2000
1083
  return this.chipPartitionsSolver.visualize();
@@ -2069,31 +1152,6 @@ var LayoutPipelineSolver = class extends BaseSolver {
2069
1152
  let finalLayout;
2070
1153
  if (this.partitionPackingSolver?.solved && this.partitionPackingSolver.finalLayout) {
2071
1154
  finalLayout = this.partitionPackingSolver.finalLayout;
2072
- } else if (this.pinRangeOverlapSolver?.solved && this.pinRangeOverlapSolver.resolvedLayout) {
2073
- finalLayout = this.pinRangeOverlapSolver.resolvedLayout;
2074
- } else if (this.pinRangeLayoutSolver?.solved) {
2075
- const allChipPlacements = {};
2076
- const allGroupPlacements = {};
2077
- for (const singleSolver of this.pinRangeLayoutSolver.completedSolvers) {
2078
- if (singleSolver.layout) {
2079
- Object.assign(allChipPlacements, singleSolver.layout.chipPlacements);
2080
- Object.assign(allGroupPlacements, singleSolver.layout.groupPlacements);
2081
- }
2082
- }
2083
- if (this.pinRangeLayoutSolver.activeSolver?.layout) {
2084
- Object.assign(
2085
- allChipPlacements,
2086
- this.pinRangeLayoutSolver.activeSolver.layout.chipPlacements
2087
- );
2088
- Object.assign(
2089
- allGroupPlacements,
2090
- this.pinRangeLayoutSolver.activeSolver.layout.groupPlacements
2091
- );
2092
- }
2093
- finalLayout = {
2094
- chipPlacements: allChipPlacements,
2095
- groupPlacements: allGroupPlacements
2096
- };
2097
1155
  } else {
2098
1156
  throw new Error(
2099
1157
  "No layout available. Pipeline may have failed or not progressed far enough."