@tscircuit/matchpack 0.0.5 → 0.0.7

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,309 @@ 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
+
458
+ // lib/utils/networkFiltering.ts
459
+ function createFilteredNetworkMapping(inputProblem) {
460
+ const pinToNetworkMap = /* @__PURE__ */ new Map();
461
+ const filteredPins = /* @__PURE__ */ new Set();
462
+ const strongConnectedChipSides = /* @__PURE__ */ new Map();
463
+ for (const [connKey, connected] of Object.entries(
464
+ inputProblem.pinStrongConnMap
465
+ )) {
466
+ if (!connected) continue;
467
+ const pins = connKey.split("-");
468
+ if (pins.length === 2 && pins[0] && pins[1]) {
469
+ const pin1 = inputProblem.chipPinMap[pins[0]];
470
+ const pin2 = inputProblem.chipPinMap[pins[1]];
471
+ if (pin1 && pin2) {
472
+ const chip1Id = pins[0].split(".")[0];
473
+ const chip2Id = pins[1].split(".")[0];
474
+ if (chip1Id && chip2Id && chip1Id !== chip2Id) {
475
+ const key1 = `${chip1Id}-${chip2Id}`;
476
+ const key2 = `${chip2Id}-${chip1Id}`;
477
+ if (!strongConnectedChipSides.has(key1)) {
478
+ strongConnectedChipSides.set(key1, /* @__PURE__ */ new Set());
479
+ }
480
+ if (!strongConnectedChipSides.has(key2)) {
481
+ strongConnectedChipSides.set(key2, /* @__PURE__ */ new Set());
482
+ }
483
+ strongConnectedChipSides.get(key1).add(pin1.side);
484
+ strongConnectedChipSides.get(key2).add(pin2.side);
485
+ }
486
+ }
487
+ }
488
+ }
489
+ for (const [connKey, connected] of Object.entries(inputProblem.netConnMap)) {
490
+ if (!connected) continue;
491
+ const [pinId, netId] = connKey.split("-");
492
+ if (pinId && netId) {
493
+ const pin = inputProblem.chipPinMap[pinId];
494
+ if (!pin) continue;
495
+ const chipId = pinId.split(".")[0];
496
+ let shouldIncludeInNetwork = true;
497
+ for (const [
498
+ strongKey,
499
+ strongSides
500
+ ] of strongConnectedChipSides.entries()) {
501
+ const [fromChip, toChip] = strongKey.split("-");
502
+ if (fromChip === chipId) {
503
+ for (const [otherConnKey, otherConnected] of Object.entries(
504
+ inputProblem.netConnMap
505
+ )) {
506
+ if (!otherConnected) continue;
507
+ const [otherPinId, otherNetId] = otherConnKey.split("-");
508
+ if (otherNetId === netId && otherPinId && otherPinId !== pinId) {
509
+ const otherPin = inputProblem.chipPinMap[otherPinId];
510
+ if (!otherPin) continue;
511
+ const otherChipId = otherPinId.split(".")[0];
512
+ if (otherChipId === toChip) {
513
+ if (!strongSides.has(otherPin.side)) {
514
+ shouldIncludeInNetwork = false;
515
+ break;
516
+ }
517
+ }
518
+ }
519
+ }
520
+ }
521
+ }
522
+ if (shouldIncludeInNetwork) {
523
+ pinToNetworkMap.set(pinId, netId);
524
+ } else {
525
+ const disconnectedNetworkId = `${pinId}_opposite-strong-side-disconnected`;
526
+ pinToNetworkMap.set(pinId, disconnectedNetworkId);
527
+ filteredPins.add(pinId);
528
+ }
529
+ }
530
+ }
531
+ for (const [connKey, connected] of Object.entries(
532
+ inputProblem.pinStrongConnMap
533
+ )) {
534
+ if (!connected) continue;
535
+ const pins = connKey.split("-");
536
+ if (pins.length === 2 && pins[0] && pins[1]) {
537
+ const existingNet = pinToNetworkMap.get(pins[0]) || pinToNetworkMap.get(pins[1]);
538
+ if (existingNet) {
539
+ pinToNetworkMap.set(pins[0], existingNet);
540
+ pinToNetworkMap.set(pins[1], existingNet);
541
+ } else {
542
+ pinToNetworkMap.set(pins[0], connKey);
543
+ pinToNetworkMap.set(pins[1], connKey);
544
+ }
545
+ }
546
+ }
547
+ return {
548
+ pinToNetworkMap,
549
+ filteredPins
550
+ };
551
+ }
552
+
553
+ // lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts
554
+ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
555
+ inputProblem;
556
+ layout = null;
557
+ phasedPackSolver = null;
558
+ constructor(inputProblem) {
559
+ super();
560
+ this.inputProblem = inputProblem;
561
+ }
562
+ _step() {
563
+ try {
564
+ if (!this.phasedPackSolver) {
565
+ const packInput = this.createPackInput();
566
+ this.phasedPackSolver = new PhasedPackSolver(packInput);
567
+ this.activeSubSolver = this.phasedPackSolver;
568
+ }
569
+ this.phasedPackSolver.step();
570
+ if (this.phasedPackSolver.failed) {
571
+ this.failed = true;
572
+ this.error = `PhasedPackSolver failed: ${this.phasedPackSolver.error}`;
573
+ return;
574
+ }
575
+ if (this.phasedPackSolver.solved) {
576
+ this.layout = this.createLayoutFromPackingResult(
577
+ this.phasedPackSolver.getResult()
578
+ );
579
+ this.solved = true;
580
+ this.activeSubSolver = null;
581
+ }
582
+ } catch (error) {
583
+ this.failed = true;
584
+ this.error = `Failed to pack partition: ${error}`;
585
+ }
586
+ }
587
+ createPackInput() {
588
+ const { pinToNetworkMap } = createFilteredNetworkMapping(this.inputProblem);
589
+ const packComponents = Object.entries(this.inputProblem.chipMap).map(
590
+ ([chipId, chip]) => {
591
+ const pads = [];
592
+ pads.push({
593
+ padId: `${chipId}_body`,
594
+ networkId: `${chipId}_body_disconnected`,
595
+ type: "rect",
596
+ offset: { x: 0, y: 0 },
597
+ size: { x: chip.size.x, y: chip.size.y }
598
+ });
599
+ for (const pinId of chip.pins) {
600
+ const pin = this.inputProblem.chipPinMap[pinId];
601
+ if (!pin) continue;
602
+ const networkId = pinToNetworkMap.get(pinId) || `${pinId}_isolated`;
603
+ pads.push({
604
+ padId: pinId,
605
+ networkId,
606
+ type: "rect",
607
+ offset: { x: pin.offset.x, y: pin.offset.y },
608
+ size: { x: 0.1, y: 0.1 }
609
+ // Small size for pins
610
+ });
611
+ }
612
+ return {
613
+ componentId: chipId,
614
+ pads,
615
+ availableRotationDegrees: chip.availableRotations || [
616
+ 0,
617
+ 90,
618
+ 180,
619
+ 270
620
+ ]
621
+ };
622
+ }
623
+ );
624
+ return {
625
+ components: packComponents,
626
+ minGap: this.inputProblem.chipGap,
627
+ packOrderStrategy: "largest_to_smallest",
628
+ packPlacementStrategy: "minimum_sum_squared_distance_to_network"
629
+ };
630
+ }
631
+ createLayoutFromPackingResult(packedComponents) {
632
+ const chipPlacements = {};
633
+ for (const packedComponent of packedComponents) {
634
+ const chipId = packedComponent.componentId;
635
+ chipPlacements[chipId] = {
636
+ x: packedComponent.center.x,
637
+ y: packedComponent.center.y,
638
+ ccwRotationDegrees: packedComponent.ccwRotationDegrees || 0
639
+ };
640
+ }
641
+ return {
642
+ chipPlacements,
643
+ groupPlacements: {}
644
+ };
645
+ }
646
+ visualize() {
647
+ if (this.phasedPackSolver && !this.solved) {
648
+ return this.phasedPackSolver.visualize();
649
+ }
650
+ if (!this.layout) {
651
+ return super.visualize();
652
+ }
653
+ return visualizeInputProblem(this.inputProblem, this.layout);
654
+ }
655
+ getConstructorParams() {
656
+ return [this.inputProblem];
657
+ }
658
+ };
659
+
660
+ // lib/solvers/PackInnerPartitionsSolver/PackInnerPartitionsSolver.ts
661
+ import { stackGraphicsHorizontally as stackGraphicsHorizontally2 } from "graphics-debug";
662
+ var PackInnerPartitionsSolver = class extends BaseSolver {
663
+ partitions;
664
+ packedPartitions = [];
665
+ completedSolvers = [];
666
+ activeSolver = null;
667
+ currentPartitionIndex = 0;
668
+ constructor(partitions) {
669
+ super();
670
+ this.partitions = partitions;
671
+ }
672
+ _step() {
673
+ if (this.currentPartitionIndex >= this.partitions.length) {
674
+ this.solved = true;
675
+ return;
676
+ }
677
+ if (!this.activeSolver) {
678
+ const currentPartition = this.partitions[this.currentPartitionIndex];
679
+ this.activeSolver = new SingleInnerPartitionPackingSolver(
680
+ currentPartition
681
+ );
682
+ this.activeSubSolver = this.activeSolver;
683
+ }
684
+ this.activeSolver.step();
685
+ if (this.activeSolver.failed) {
686
+ this.failed = true;
687
+ this.error = `Partition ${this.currentPartitionIndex} failed: ${this.activeSolver.error}`;
688
+ return;
689
+ }
690
+ if (this.activeSolver.solved) {
691
+ this.completedSolvers.push(this.activeSolver);
692
+ if (this.activeSolver.layout) {
693
+ this.packedPartitions.push({
694
+ inputProblem: this.partitions[this.currentPartitionIndex],
695
+ layout: this.activeSolver.layout
696
+ });
697
+ } else {
698
+ this.failed = true;
699
+ this.error = `Partition ${this.currentPartitionIndex} completed but has no layout`;
700
+ return;
701
+ }
702
+ this.activeSolver = null;
703
+ this.activeSubSolver = null;
704
+ this.currentPartitionIndex++;
705
+ }
706
+ }
707
+ visualize() {
708
+ if (this.activeSolver) {
709
+ return this.activeSolver.visualize();
710
+ }
711
+ if (this.completedSolvers.length === 0) {
712
+ return super.visualize();
713
+ }
714
+ const partitionVisualizations = this.completedSolvers.map(
715
+ (solver) => solver.visualize()
716
+ );
717
+ const titles = this.completedSolvers.map(
718
+ (_, index) => `packed_partition_${index}`
719
+ );
720
+ return stackGraphicsHorizontally2(partitionVisualizations, { titles });
721
+ }
722
+ getConstructorParams() {
723
+ return [this.partitions];
724
+ }
725
+ };
726
+
727
+ // lib/solvers/PartitionPackingSolver/PartitionPackingSolver.ts
728
+ import { PhasedPackSolver as PhasedPackSolver2 } from "calculate-packing";
488
729
  var PartitionPackingSolver = class extends BaseSolver {
489
- resolvedLayout;
490
- laidOutPartitions;
730
+ packedPartitions;
491
731
  inputProblem;
492
732
  finalLayout = null;
493
733
  phasedPackSolver = null;
494
734
  constructor(input) {
495
735
  super();
496
- this.resolvedLayout = input.resolvedLayout;
497
- this.laidOutPartitions = input.laidOutPartitions;
736
+ this.packedPartitions = input.packedPartitions;
498
737
  this.inputProblem = input.inputProblem;
499
738
  }
500
739
  _step() {
501
740
  try {
502
- if (!this.resolvedLayout) {
503
- this.failed = true;
504
- this.error = "No resolved layout provided";
741
+ if (this.packedPartitions.length === 0) {
742
+ this.finalLayout = {
743
+ chipPlacements: {},
744
+ groupPlacements: {}
745
+ };
746
+ this.solved = true;
505
747
  return;
506
748
  }
507
- const resolvedLayout = this.resolvedLayout;
508
- const partitionGroups = this.organizeComponentsByPartition(resolvedLayout);
509
- if (partitionGroups.length === 0) {
510
- this.finalLayout = resolvedLayout;
749
+ if (this.packedPartitions.length === 1) {
750
+ this.finalLayout = this.packedPartitions[0].layout;
511
751
  this.solved = true;
512
752
  return;
513
753
  }
754
+ const partitionGroups = this.organizePackedPartitions();
514
755
  if (!this.phasedPackSolver) {
515
756
  const packInput = this.createPackInput(partitionGroups);
516
- this.phasedPackSolver = new PhasedPackSolver(packInput);
757
+ this.phasedPackSolver = new PhasedPackSolver2(packInput);
517
758
  this.activeSubSolver = this.phasedPackSolver;
518
759
  }
519
760
  this.phasedPackSolver.step();
@@ -525,8 +766,7 @@ var PartitionPackingSolver = class extends BaseSolver {
525
766
  if (this.phasedPackSolver.solved) {
526
767
  const packedLayout = this.applyPackingResult(
527
768
  this.phasedPackSolver.getResult(),
528
- partitionGroups,
529
- resolvedLayout
769
+ partitionGroups
530
770
  );
531
771
  this.finalLayout = packedLayout;
532
772
  this.solved = true;
@@ -537,29 +777,37 @@ var PartitionPackingSolver = class extends BaseSolver {
537
777
  this.error = `Failed to pack partitions: ${error}`;
538
778
  }
539
779
  }
540
- organizeComponentsByPartition(layout) {
780
+ organizePackedPartitions() {
541
781
  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
- }
782
+ for (let i = 0; i < this.packedPartitions.length; i++) {
783
+ const packedPartition = this.packedPartitions[i];
784
+ const partitionChipIds = Object.keys(
785
+ packedPartition.layout.chipPlacements
786
+ );
550
787
  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
- };
788
+ let minX = Infinity;
789
+ let maxX = -Infinity;
790
+ let minY = Infinity;
791
+ let maxY = -Infinity;
792
+ for (const chipId of partitionChipIds) {
793
+ const placement = packedPartition.layout.chipPlacements[chipId];
794
+ const chip = packedPartition.inputProblem.chipMap[chipId];
795
+ let chipWidth = chip.size.x;
796
+ let chipHeight = chip.size.y;
797
+ if (placement.ccwRotationDegrees === 90 || placement.ccwRotationDegrees === 270) {
798
+ ;
799
+ [chipWidth, chipHeight] = [chipHeight, chipWidth];
800
+ }
801
+ const chipMinX = placement.x - chipWidth / 2;
802
+ const chipMaxX = placement.x + chipWidth / 2;
803
+ const chipMinY = placement.y - chipHeight / 2;
804
+ const chipMaxY = placement.y + chipHeight / 2;
805
+ minX = Math.min(minX, chipMinX);
806
+ maxX = Math.max(maxX, chipMaxX);
807
+ minY = Math.min(minY, chipMinY);
808
+ maxY = Math.max(maxY, chipMaxY);
809
+ }
810
+ const bounds = { minX, maxX, minY, maxY };
563
811
  partitionGroups.push({
564
812
  partitionIndex: i,
565
813
  chipIds: partitionChipIds,
@@ -570,11 +818,10 @@ var PartitionPackingSolver = class extends BaseSolver {
570
818
  return partitionGroups;
571
819
  }
572
820
  createPackInput(partitionGroups) {
573
- const resolvedLayout = this.resolvedLayout;
574
821
  const pinToNetworkMap = /* @__PURE__ */ new Map();
575
- for (const laidOutPartition of this.laidOutPartitions) {
822
+ for (const packedPartition of this.packedPartitions) {
576
823
  for (const [connKey, connected] of Object.entries(
577
- laidOutPartition.netConnMap
824
+ packedPartition.inputProblem.netConnMap
578
825
  )) {
579
826
  if (!connected) continue;
580
827
  const [pinId, netId] = connKey.split("-");
@@ -583,7 +830,7 @@ var PartitionPackingSolver = class extends BaseSolver {
583
830
  }
584
831
  }
585
832
  for (const [connKey, connected] of Object.entries(
586
- laidOutPartition.pinStrongConnMap
833
+ packedPartition.inputProblem.pinStrongConnMap
587
834
  )) {
588
835
  if (!connected) continue;
589
836
  const pins = connKey.split("-");
@@ -600,56 +847,64 @@ var PartitionPackingSolver = class extends BaseSolver {
600
847
  }
601
848
  }
602
849
  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`,
850
+ const packedPartition = this.packedPartitions[group.partitionIndex];
851
+ const partitionWidth = group.bounds.maxX - group.bounds.minX;
852
+ const partitionHeight = group.bounds.maxY - group.bounds.minY;
853
+ const centerX = (group.bounds.minX + group.bounds.maxX) / 2;
854
+ const centerY = (group.bounds.minY + group.bounds.maxY) / 2;
855
+ const pads = [
856
+ {
857
+ padId: `partition_${group.partitionIndex}_body`,
858
+ networkId: `partition_${group.partitionIndex}_disconnected`,
613
859
  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
- });
860
+ offset: { x: 0, y: 0 },
861
+ size: {
862
+ x: Math.max(partitionWidth, 0.1),
863
+ y: Math.max(partitionHeight, 0.1)
864
+ }
631
865
  }
632
- }
633
- let availableRotationDegrees = [
634
- 0,
635
- 90,
636
- 180,
637
- 270
638
866
  ];
867
+ const addedNetworks = /* @__PURE__ */ new Set();
868
+ const pinPositions = /* @__PURE__ */ new Map();
639
869
  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];
870
+ const chipPlacement = packedPartition.layout.chipPlacements[chipId];
871
+ const chip = packedPartition.inputProblem.chipMap[chipId];
872
+ for (const pinId of chip.pins) {
873
+ const chipPin = packedPartition.inputProblem.chipPinMap[pinId];
874
+ if (!chipPin) continue;
875
+ let transformedOffset = { x: chipPin.offset.x, y: chipPin.offset.y };
876
+ const rotation = chipPlacement.ccwRotationDegrees || 0;
877
+ if (rotation === 90) {
878
+ transformedOffset = { x: -chipPin.offset.y, y: chipPin.offset.x };
879
+ } else if (rotation === 180) {
880
+ transformedOffset = { x: -chipPin.offset.x, y: -chipPin.offset.y };
881
+ } else if (rotation === 270) {
882
+ transformedOffset = { x: chipPin.offset.y, y: -chipPin.offset.x };
883
+ }
884
+ const absolutePinX = chipPlacement.x + transformedOffset.x;
885
+ const absolutePinY = chipPlacement.y + transformedOffset.y;
886
+ pinPositions.set(pinId, { x: absolutePinX, y: absolutePinY });
887
+ const networkId = pinToNetworkMap.get(pinId) || `${pinId}_disconnected`;
888
+ if (!addedNetworks.has(networkId)) {
889
+ addedNetworks.add(networkId);
890
+ const padOffsetX = absolutePinX - centerX;
891
+ const padOffsetY = absolutePinY - centerY;
892
+ pads.push({
893
+ padId: `${group.partitionIndex}_pin_${pinId}`,
894
+ networkId,
895
+ type: "rect",
896
+ offset: { x: padOffsetX, y: padOffsetY },
897
+ size: { x: 0.01, y: 0.01 }
898
+ // Small pin pad
899
+ });
900
+ }
901
+ }
648
902
  }
649
903
  return {
650
904
  componentId: `partition_${group.partitionIndex}`,
651
905
  pads,
652
- availableRotationDegrees
906
+ availableRotationDegrees: [0]
907
+ // Keep partitions unrotated
653
908
  };
654
909
  });
655
910
  return {
@@ -660,7 +915,7 @@ var PartitionPackingSolver = class extends BaseSolver {
660
915
  packPlacementStrategy: "minimum_sum_squared_distance_to_network"
661
916
  };
662
917
  }
663
- applyPackingResult(packedComponents, partitionGroups, currentLayout) {
918
+ applyPackingResult(packedComponents, partitionGroups) {
664
919
  const newChipPlacements = {};
665
920
  for (const packedComponent of packedComponents) {
666
921
  const partitionIndex = parseInt(
@@ -669,7 +924,8 @@ var PartitionPackingSolver = class extends BaseSolver {
669
924
  const group = partitionGroups.find(
670
925
  (g) => g.partitionIndex === partitionIndex
671
926
  );
672
- if (group) {
927
+ const packedPartition = this.packedPartitions[partitionIndex];
928
+ if (group && packedPartition) {
673
929
  const currentCenterX = (group.bounds.minX + group.bounds.maxX) / 2;
674
930
  const currentCenterY = (group.bounds.minY + group.bounds.maxY) / 2;
675
931
  const newCenterX = packedComponent.center.x;
@@ -677,7 +933,7 @@ var PartitionPackingSolver = class extends BaseSolver {
677
933
  const offsetX = newCenterX - currentCenterX;
678
934
  const offsetY = newCenterY - currentCenterY;
679
935
  for (const chipId of group.chipIds) {
680
- const originalPlacement = currentLayout.chipPlacements[chipId];
936
+ const originalPlacement = packedPartition.layout.chipPlacements[chipId];
681
937
  newChipPlacements[chipId] = {
682
938
  x: originalPlacement.x + offsetX,
683
939
  y: originalPlacement.y + offsetY,
@@ -688,8 +944,7 @@ var PartitionPackingSolver = class extends BaseSolver {
688
944
  }
689
945
  return {
690
946
  chipPlacements: newChipPlacements,
691
- groupPlacements: { ...currentLayout.groupPlacements }
692
- // Copy group placements unchanged
947
+ groupPlacements: {}
693
948
  };
694
949
  }
695
950
  visualize() {
@@ -701,1169 +956,80 @@ var PartitionPackingSolver = class extends BaseSolver {
701
956
  }
702
957
  const combinedProblem = {
703
958
  chipMap: {},
704
- groupMap: {},
705
959
  chipPinMap: {},
706
- groupPinMap: {},
707
960
  pinStrongConnMap: {},
708
961
  netMap: {},
709
962
  netConnMap: {},
710
963
  chipGap: this.inputProblem.chipGap,
711
964
  partitionGap: this.inputProblem.partitionGap
712
965
  };
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);
966
+ for (const packedPartition of this.packedPartitions) {
967
+ Object.assign(
968
+ combinedProblem.chipMap,
969
+ packedPartition.inputProblem.chipMap
970
+ );
971
+ Object.assign(
972
+ combinedProblem.chipPinMap,
973
+ packedPartition.inputProblem.chipPinMap
974
+ );
718
975
  Object.assign(
719
976
  combinedProblem.pinStrongConnMap,
720
- laidOutPartition.pinStrongConnMap
977
+ packedPartition.inputProblem.pinStrongConnMap
978
+ );
979
+ Object.assign(combinedProblem.netMap, packedPartition.inputProblem.netMap);
980
+ Object.assign(
981
+ combinedProblem.netConnMap,
982
+ packedPartition.inputProblem.netConnMap
721
983
  );
722
- Object.assign(combinedProblem.netMap, laidOutPartition.netMap);
723
- Object.assign(combinedProblem.netConnMap, laidOutPartition.netConnMap);
724
984
  }
725
985
  return visualizeInputProblem(combinedProblem, this.finalLayout);
726
986
  }
727
987
  getConstructorParams() {
728
988
  return {
729
- resolvedLayout: this.resolvedLayout,
730
- laidOutPartitions: this.laidOutPartitions,
989
+ packedPartitions: this.packedPartitions,
731
990
  inputProblem: this.inputProblem
732
991
  };
733
992
  }
734
993
  };
735
994
 
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;
995
+ // lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts
996
+ function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
997
+ return {
998
+ solverName,
999
+ solverClass,
1000
+ getConstructorParams,
1001
+ onSolved: opts.onSolved
1002
+ };
1003
+ }
1004
+ var LayoutPipelineSolver = class extends BaseSolver {
1005
+ chipPartitionsSolver;
1006
+ packInnerPartitionsSolver;
1007
+ partitionPackingSolver;
1008
+ startTimeOfPhase;
1009
+ endTimeOfPhase;
1010
+ timeSpentOnPhase;
1011
+ firstIterationOfPhase;
743
1012
  inputProblem;
744
- layoutApplied = false;
745
- layout = null;
746
- constructor(pinRange, inputProblem) {
747
- super();
748
- this.pinRange = pinRange;
749
- this.inputProblem = inputProblem;
750
- }
751
- _step() {
752
- try {
753
- this.layout = this.createPinRangeLayout();
754
- this.layoutApplied = true;
755
- 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) => {
1013
+ chipPartitions;
1014
+ packedPartitions;
1015
+ pipelineDef = [
1016
+ definePipelineStep(
1017
+ "chipPartitionsSolver",
1018
+ ChipPartitionsSolver,
1019
+ () => [this.inputProblem],
1020
+ {
1021
+ onSolved: (_layoutSolver) => {
1022
+ this.chipPartitions = this.chipPartitionsSolver.partitions;
1855
1023
  }
1856
1024
  }
1857
1025
  ),
1858
1026
  definePipelineStep(
1859
- "pinRangeOverlapSolver",
1860
- PinRangeOverlapSolver,
1861
- () => [
1862
- this.pinRangeLayoutSolver,
1863
- this.chipPartitions || [this.inputProblem]
1864
- ],
1027
+ "packInnerPartitionsSolver",
1028
+ PackInnerPartitionsSolver,
1029
+ () => [this.chipPartitions || [this.inputProblem]],
1865
1030
  {
1866
1031
  onSolved: (_solver) => {
1032
+ this.packedPartitions = this.packInnerPartitionsSolver.packedPartitions;
1867
1033
  }
1868
1034
  }
1869
1035
  ),
@@ -1872,8 +1038,7 @@ var LayoutPipelineSolver = class extends BaseSolver {
1872
1038
  PartitionPackingSolver,
1873
1039
  () => [
1874
1040
  {
1875
- resolvedLayout: this.pinRangeOverlapSolver.resolvedLayout,
1876
- laidOutPartitions: this.chipPartitions || [this.inputProblem],
1041
+ packedPartitions: this.packedPartitions || [],
1877
1042
  inputProblem: this.inputProblem
1878
1043
  }
1879
1044
  ],
@@ -1936,18 +1101,14 @@ var LayoutPipelineSolver = class extends BaseSolver {
1936
1101
  return this.partitionPackingSolver.visualize();
1937
1102
  }
1938
1103
  const chipPartitionsViz = this.chipPartitionsSolver?.visualize();
1939
- const pinRangeMatchViz = this.pinRangeMatchSolver?.visualize();
1940
- const pinRangeLayoutViz = this.pinRangeLayoutSolver?.visualize();
1941
- const pinRangeOverlapViz = this.pinRangeOverlapSolver?.visualize();
1104
+ const packInnerPartitionsViz = this.packInnerPartitionsSolver?.visualize();
1942
1105
  const partitionPackingViz = this.partitionPackingSolver?.visualize();
1943
1106
  const basicLayout = doBasicInputProblemLayout(this.inputProblem);
1944
1107
  const inputViz = visualizeInputProblem(this.inputProblem, basicLayout);
1945
1108
  const visualizations = [
1946
1109
  inputViz,
1947
1110
  chipPartitionsViz,
1948
- pinRangeMatchViz,
1949
- pinRangeLayoutViz,
1950
- pinRangeOverlapViz,
1111
+ packInnerPartitionsViz,
1951
1112
  partitionPackingViz
1952
1113
  ].filter(Boolean).map((viz, stepIndex) => {
1953
1114
  for (const rect of viz.rects ?? []) {
@@ -1987,14 +1148,8 @@ var LayoutPipelineSolver = class extends BaseSolver {
1987
1148
  if (this.partitionPackingSolver?.solved) {
1988
1149
  return this.partitionPackingSolver.visualize();
1989
1150
  }
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();
1151
+ if (this.packInnerPartitionsSolver?.solved) {
1152
+ return this.packInnerPartitionsSolver.visualize();
1998
1153
  }
1999
1154
  if (this.chipPartitionsSolver?.solved) {
2000
1155
  return this.chipPartitionsSolver.visualize();
@@ -2069,31 +1224,6 @@ var LayoutPipelineSolver = class extends BaseSolver {
2069
1224
  let finalLayout;
2070
1225
  if (this.partitionPackingSolver?.solved && this.partitionPackingSolver.finalLayout) {
2071
1226
  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
1227
  } else {
2098
1228
  throw new Error(
2099
1229
  "No layout available. Pipeline may have failed or not progressed far enough."