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