@tscircuit/matchpack 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -77,35 +77,6 @@ type InputProblem = {
77
77
  inferDecouplingCaps?: boolean;
78
78
  };
79
79
 
80
- /**
81
- * Creates partitions (small subset groups) surrounding complex chips.
82
- * Divides the layout problem into manageable sections for more efficient processing.
83
- */
84
-
85
- declare class ChipPartitionsSolver extends BaseSolver {
86
- inputProblem: InputProblem;
87
- partitions: InputProblem[];
88
- constructor(inputProblem: InputProblem);
89
- _step(): void;
90
- /**
91
- * Creates partitions by finding connected components through strong pin connections
92
- */
93
- private createPartitions;
94
- /**
95
- * Finds the owner chip of a given pin
96
- */
97
- private findPinOwner;
98
- /**
99
- * Depth-first search to find connected components
100
- */
101
- private dfs;
102
- /**
103
- * Creates a new InputProblem containing only the components in the given partition
104
- */
105
- private createInputProblemFromPartition;
106
- visualize(): GraphicsObject;
107
- }
108
-
109
80
  /**
110
81
  * Identifies decoupling capacitor groups based on specific criteria:
111
82
  * 1. Component has exactly 2 pins and restricted rotation (0/180 only or no rotation)
@@ -116,6 +87,7 @@ declare class ChipPartitionsSolver extends BaseSolver {
116
87
  interface DecouplingCapGroup {
117
88
  decouplingCapGroupId: string;
118
89
  mainChipId: ChipId;
90
+ netPair: [NetId, NetId];
119
91
  decouplingCapChipIds: ChipId[];
120
92
  }
121
93
  /**
@@ -128,7 +100,7 @@ declare class IdentifyDecouplingCapsSolver extends BaseSolver {
128
100
  inputProblem: InputProblem;
129
101
  queuedChips: Chip[];
130
102
  outputDecouplingCapGroups: DecouplingCapGroup[];
131
- /** Quick lookup of groups by main chip for accumulation */
103
+ /** Quick lookup of groups by main chip and net pair for accumulation */
132
104
  private groupsByMainChipId;
133
105
  constructor(inputProblem: InputProblem);
134
106
  /** Determine if chip is a 2-pin component with restricted rotation */
@@ -139,14 +111,54 @@ declare class IdentifyDecouplingCapsSolver extends BaseSolver {
139
111
  private getStronglyConnectedNeighborChips;
140
112
  /** Find the main chip id for a decoupling capacitor candidate */
141
113
  private findMainChipIdForCap;
142
- /** Adds a decoupling capacitor to the group for the given main chip */
114
+ /** Get all net IDs connected to a pin */
115
+ private getNetIdsForPin;
116
+ /** Get a normalized, sorted pair of net IDs connected across the two pins of a capacitor chip */
117
+ private getNormalizedNetPair;
118
+ /** Adds a decoupling capacitor to the group for the given main chip and net pair */
143
119
  private addToGroup;
120
+ lastChip: Chip | null;
144
121
  _step(): void;
145
122
  visualize(): GraphicsObject;
146
123
  getConstructorParams(): [InputProblem];
147
124
  computeProgress(): number;
148
125
  }
149
126
 
127
+ /**
128
+ * Creates partitions (small subset groups) surrounding complex chips.
129
+ * Divides the layout problem into manageable sections for more efficient processing.
130
+ */
131
+
132
+ declare class ChipPartitionsSolver extends BaseSolver {
133
+ inputProblem: InputProblem;
134
+ partitions: InputProblem[];
135
+ decouplingCapGroups?: DecouplingCapGroup[];
136
+ constructor({ inputProblem, decouplingCapGroups, }: {
137
+ inputProblem: InputProblem;
138
+ decouplingCapGroups?: DecouplingCapGroup[];
139
+ });
140
+ _step(): void;
141
+ /**
142
+ * Creates partitions by:
143
+ * - Separating each decoupling capacitor group into its own partition (caps only, excluding the main chip)
144
+ * - Partitioning remaining chips by connected components through strong pin connections
145
+ */
146
+ private createPartitions;
147
+ /**
148
+ * Finds the owner chip of a given pin
149
+ */
150
+ private findPinOwner;
151
+ /**
152
+ * Depth-first search to find connected components
153
+ */
154
+ private dfs;
155
+ /**
156
+ * Creates a new InputProblem containing only the components in the given partition
157
+ */
158
+ private createInputProblemFromPartition;
159
+ visualize(): GraphicsObject;
160
+ }
161
+
150
162
  type Placement = Point & {
151
163
  ccwRotationDegrees: number;
152
164
  };
package/dist/index.js CHANGED
@@ -317,21 +317,45 @@ function doBasicInputProblemLayout(inputProblem) {
317
317
  var ChipPartitionsSolver = class extends BaseSolver {
318
318
  inputProblem;
319
319
  partitions = [];
320
- constructor(inputProblem) {
320
+ decouplingCapGroups;
321
+ constructor({
322
+ inputProblem,
323
+ decouplingCapGroups
324
+ }) {
321
325
  super();
322
326
  this.inputProblem = inputProblem;
327
+ this.decouplingCapGroups = decouplingCapGroups;
323
328
  }
324
329
  _step() {
325
330
  this.partitions = this.createPartitions(this.inputProblem);
326
331
  this.solved = true;
327
332
  }
328
333
  /**
329
- * Creates partitions by finding connected components through strong pin connections
334
+ * Creates partitions by:
335
+ * - Separating each decoupling capacitor group into its own partition (caps only, excluding the main chip)
336
+ * - Partitioning remaining chips by connected components through strong pin connections
330
337
  */
331
338
  createPartitions(inputProblem) {
332
339
  const chipIds = Object.keys(inputProblem.chipMap);
340
+ const decapChipIdSet = /* @__PURE__ */ new Set();
341
+ const decapGroupPartitions = [];
342
+ if (this.decouplingCapGroups && this.decouplingCapGroups.length > 0) {
343
+ for (const group of this.decouplingCapGroups) {
344
+ const capsOnly = [];
345
+ for (const capId of group.decouplingCapChipIds) {
346
+ if (inputProblem.chipMap[capId]) {
347
+ capsOnly.push(capId);
348
+ decapChipIdSet.add(capId);
349
+ }
350
+ }
351
+ if (capsOnly.length > 0) {
352
+ decapGroupPartitions.push(capsOnly);
353
+ }
354
+ }
355
+ }
356
+ const nonDecapChipIds = chipIds.filter((id) => !decapChipIdSet.has(id));
333
357
  const adjacencyMap = /* @__PURE__ */ new Map();
334
- for (const chipId of chipIds) {
358
+ for (const chipId of nonDecapChipIds) {
335
359
  adjacencyMap.set(chipId, /* @__PURE__ */ new Set());
336
360
  }
337
361
  for (const [connKey, isConnected] of Object.entries(
@@ -341,22 +365,23 @@ var ChipPartitionsSolver = class extends BaseSolver {
341
365
  const [pin1Id, pin2Id] = connKey.split("-");
342
366
  const owner1 = this.findPinOwner(pin1Id, inputProblem);
343
367
  const owner2 = this.findPinOwner(pin2Id, inputProblem);
344
- if (owner1 && owner2 && owner1 !== owner2) {
368
+ if (owner1 && owner2 && owner1 !== owner2 && !decapChipIdSet.has(owner1) && !decapChipIdSet.has(owner2)) {
345
369
  adjacencyMap.get(owner1).add(owner2);
346
370
  adjacencyMap.get(owner2).add(owner1);
347
371
  }
348
372
  }
349
373
  const visited = /* @__PURE__ */ new Set();
350
- const partitions = [];
351
- for (const componentId of chipIds) {
374
+ const nonDecapPartitions = [];
375
+ for (const componentId of nonDecapChipIds) {
352
376
  if (!visited.has(componentId)) {
353
377
  const partition = this.dfs(componentId, adjacencyMap, visited);
354
378
  if (partition.length > 0) {
355
- partitions.push(partition);
379
+ nonDecapPartitions.push(partition);
356
380
  }
357
381
  }
358
382
  }
359
- return partitions.map(
383
+ const allPartitions = [...decapGroupPartitions, ...nonDecapPartitions];
384
+ return allPartitions.map(
360
385
  (partition) => this.createInputProblemFromPartition(partition, inputProblem)
361
386
  );
362
387
  }
@@ -468,10 +493,13 @@ var ChipPartitionsSolver = class extends BaseSolver {
468
493
 
469
494
  // lib/utils/getColorFromString.ts
470
495
  var getColorFromString = (string, alpha = 1) => {
471
- const hash = string.split("").reduce((acc, char) => {
472
- return acc * 31 + char.charCodeAt(0);
473
- }, 0);
474
- return `hsl(${hash % 360}, 100%, 50%, ${alpha})`;
496
+ let hash = 0;
497
+ for (let i = 0; i < string.length; i++) {
498
+ const char = string.charCodeAt(i);
499
+ hash = (hash << 5) - hash + char;
500
+ hash = hash & hash;
501
+ }
502
+ return `hsl(${Math.abs(hash) % 360}, 70%, 50%, ${alpha})`;
475
503
  };
476
504
 
477
505
  // lib/solvers/IdentifyDecouplingCapsSolver/IdentifyDecouplingCapsSolver.ts
@@ -479,7 +507,7 @@ var IdentifyDecouplingCapsSolver = class extends BaseSolver {
479
507
  inputProblem;
480
508
  queuedChips;
481
509
  outputDecouplingCapGroups = [];
482
- /** Quick lookup of groups by main chip for accumulation */
510
+ /** Quick lookup of groups by main chip and net pair for accumulation */
483
511
  groupsByMainChipId = /* @__PURE__ */ new Map();
484
512
  constructor(inputProblem) {
485
513
  super();
@@ -539,33 +567,64 @@ var IdentifyDecouplingCapsSolver = class extends BaseSolver {
539
567
  }
540
568
  return best ? best.id : null;
541
569
  }
542
- /** Adds a decoupling capacitor to the group for the given main chip */
543
- addToGroup(mainChipId, capChipId) {
544
- let group = this.groupsByMainChipId.get(mainChipId);
570
+ /** Get all net IDs connected to a pin */
571
+ getNetIdsForPin(pinId) {
572
+ const nets = /* @__PURE__ */ new Set();
573
+ for (const [connKey, connected] of Object.entries(
574
+ this.inputProblem.netConnMap
575
+ )) {
576
+ if (!connected) continue;
577
+ const [p, n] = connKey.split("-");
578
+ if (p === pinId) nets.add(n);
579
+ }
580
+ return nets;
581
+ }
582
+ /** Get a normalized, sorted pair of net IDs connected across the two pins of a capacitor chip */
583
+ getNormalizedNetPair(capChip) {
584
+ if (capChip.pins.length !== 2) return null;
585
+ const nets = /* @__PURE__ */ new Set();
586
+ for (const pinId of capChip.pins) {
587
+ const pinNets = this.getNetIdsForPin(pinId);
588
+ for (const n of pinNets) nets.add(n);
589
+ }
590
+ if (nets.size !== 2) return null;
591
+ const [a, b] = Array.from(nets).sort();
592
+ return [a, b];
593
+ }
594
+ /** Adds a decoupling capacitor to the group for the given main chip and net pair */
595
+ addToGroup(mainChipId, netPair, capChipId) {
596
+ const [n1, n2] = netPair;
597
+ const groupKey = `${mainChipId}__${n1}__${n2}`;
598
+ let group = this.groupsByMainChipId.get(groupKey);
545
599
  if (!group) {
546
600
  group = {
547
- decouplingCapGroupId: `decap_group_${mainChipId}`,
601
+ decouplingCapGroupId: `decap_group_${mainChipId}__${n1}__${n2}`,
548
602
  mainChipId,
603
+ netPair: [n1, n2],
549
604
  decouplingCapChipIds: []
550
605
  };
551
- this.groupsByMainChipId.set(mainChipId, group);
606
+ this.groupsByMainChipId.set(groupKey, group);
552
607
  this.outputDecouplingCapGroups.push(group);
553
608
  }
554
609
  if (!group.decouplingCapChipIds.includes(capChipId)) {
555
610
  group.decouplingCapChipIds.push(capChipId);
556
611
  }
557
612
  }
613
+ lastChip = null;
558
614
  _step() {
559
615
  const currentChip = this.queuedChips.shift();
616
+ this.lastChip = currentChip ?? null;
560
617
  if (!currentChip) {
561
618
  this.solved = true;
562
619
  return;
563
620
  }
564
- const candidate = this.isTwoPinRestrictedRotation(currentChip) && this.pinsOnOppositeYSides(currentChip);
565
- if (!candidate) return;
621
+ const isDecouplingCap = this.isTwoPinRestrictedRotation(currentChip) && this.pinsOnOppositeYSides(currentChip);
622
+ if (!isDecouplingCap) return;
566
623
  const mainChipId = this.findMainChipIdForCap(currentChip);
567
624
  if (!mainChipId) return;
568
- this.addToGroup(mainChipId, currentChip.chipId);
625
+ const netPair = this.getNormalizedNetPair(currentChip);
626
+ if (!netPair) return;
627
+ this.addToGroup(mainChipId, netPair, currentChip.chipId);
569
628
  }
570
629
  visualize() {
571
630
  const basicLayout = doBasicInputProblemLayout(this.inputProblem);
@@ -573,38 +632,25 @@ var IdentifyDecouplingCapsSolver = class extends BaseSolver {
573
632
  this.inputProblem,
574
633
  basicLayout
575
634
  );
576
- const chipRoleMap = /* @__PURE__ */ new Map();
635
+ const chipDecapGroupMap = /* @__PURE__ */ new Map();
577
636
  for (const group of this.outputDecouplingCapGroups) {
578
- const color = getColorFromString(group.mainChipId, 0.8);
579
- chipRoleMap.set(group.mainChipId, { type: "main", color });
637
+ chipDecapGroupMap.set(group.mainChipId, group);
580
638
  for (const capChipId of group.decouplingCapChipIds) {
581
- chipRoleMap.set(capChipId, { type: "decap", color });
639
+ chipDecapGroupMap.set(capChipId, group);
582
640
  }
583
641
  }
584
642
  for (const rect of graphics.rects || []) {
585
- rect.fill = "rgba(0,0,0,0.5)";
643
+ if (rect.label !== this.lastChip?.chipId) {
644
+ rect.fill = "rgba(0,0,0,0.5)";
645
+ }
586
646
  }
587
647
  for (const rect of graphics.rects || []) {
588
648
  const chipId = rect.label;
589
- const role = chipRoleMap.get(chipId);
590
- if (!role) continue;
591
- const alpha = role.type === "main" ? 0.18 : 0.36;
649
+ const group = chipDecapGroupMap.get(chipId);
650
+ if (!group) continue;
592
651
  rect.label = `${rect.label}
593
- ${role.type}`;
594
- rect.fill = getColorFromString(role.color, alpha);
595
- }
596
- if (!graphics.texts) graphics.texts = [];
597
- for (const rect of graphics.rects || []) {
598
- const chipId = rect.label;
599
- const role = chipRoleMap.get(chipId);
600
- if (!role) continue;
601
- graphics.texts.push({
602
- x: rect.center.x,
603
- y: rect.center.y - (rect.height || 0) / 2,
604
- text: role.type === "main" ? "MAIN" : "DECAP",
605
- fillColor: role.type === "main" ? role.color : "rgba(0,0,0,0.6)",
606
- fontSize: 8
607
- });
652
+ ${group.decouplingCapGroupId}`;
653
+ rect.fill = getColorFromString(group.decouplingCapGroupId, 0.8);
608
654
  }
609
655
  return graphics;
610
656
  }
@@ -1213,7 +1259,12 @@ var LayoutPipelineSolver = class extends BaseSolver {
1213
1259
  definePipelineStep(
1214
1260
  "chipPartitionsSolver",
1215
1261
  ChipPartitionsSolver,
1216
- () => [this.inputProblem],
1262
+ () => [
1263
+ {
1264
+ inputProblem: this.inputProblem,
1265
+ decouplingCapGroups: this.identifyDecouplingCapsSolver?.outputDecouplingCapGroups
1266
+ }
1267
+ ],
1217
1268
  {
1218
1269
  onSolved: (_layoutSolver) => {
1219
1270
  this.chipPartitions = this.chipPartitionsSolver.partitions;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/matchpack",
3
3
  "main": "dist/index.js",
4
4
  "type": "module",
5
- "version": "0.0.13",
5
+ "version": "0.0.14",
6
6
  "files": [
7
7
  "dist"
8
8
  ],
@@ -23,7 +23,7 @@
23
23
  "bpc-graph": "^0.0.66",
24
24
  "calculate-packing": "^0.0.31",
25
25
  "circuit-json": "^0.0.226",
26
- "graphics-debug": "^0.0.62",
26
+ "graphics-debug": "^0.0.64",
27
27
  "react-cosmos": "^7.0.0",
28
28
  "react-cosmos-plugin-vite": "^7.0.0",
29
29
  "tscircuit": "^0.0.593",