@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/LICENSE +21 -0
- package/README.md +0 -3
- package/dist/index.d.ts +38 -128
- package/dist/index.js +434 -1304
- package/package.json +4 -3
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 +
|
|
208
|
-
y: placement.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
|
|
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
|
|
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
|
|
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/
|
|
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
|
-
|
|
490
|
-
laidOutPartitions;
|
|
730
|
+
packedPartitions;
|
|
491
731
|
inputProblem;
|
|
492
732
|
finalLayout = null;
|
|
493
733
|
phasedPackSolver = null;
|
|
494
734
|
constructor(input) {
|
|
495
735
|
super();
|
|
496
|
-
this.
|
|
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 (
|
|
503
|
-
this.
|
|
504
|
-
|
|
741
|
+
if (this.packedPartitions.length === 0) {
|
|
742
|
+
this.finalLayout = {
|
|
743
|
+
chipPlacements: {},
|
|
744
|
+
groupPlacements: {}
|
|
745
|
+
};
|
|
746
|
+
this.solved = true;
|
|
505
747
|
return;
|
|
506
748
|
}
|
|
507
|
-
|
|
508
|
-
|
|
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
|
|
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
|
-
|
|
780
|
+
organizePackedPartitions() {
|
|
541
781
|
const partitionGroups = [];
|
|
542
|
-
for (let i = 0; i < this.
|
|
543
|
-
const
|
|
544
|
-
const partitionChipIds =
|
|
545
|
-
|
|
546
|
-
|
|
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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
|
822
|
+
for (const packedPartition of this.packedPartitions) {
|
|
576
823
|
for (const [connKey, connected] of Object.entries(
|
|
577
|
-
|
|
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
|
-
|
|
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
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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:
|
|
615
|
-
size: {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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: {
|
|
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
|
|
714
|
-
Object.assign(
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
-
|
|
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
|
-
|
|
730
|
-
laidOutPartitions: this.laidOutPartitions,
|
|
989
|
+
packedPartitions: this.packedPartitions,
|
|
731
990
|
inputProblem: this.inputProblem
|
|
732
991
|
};
|
|
733
992
|
}
|
|
734
993
|
};
|
|
735
994
|
|
|
736
|
-
// lib/solvers/
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
-
"
|
|
1860
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
1991
|
-
return this.
|
|
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."
|