@tscircuit/matchpack 0.0.17 → 0.0.19

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
@@ -238,7 +238,9 @@ declare class PartitionPackingSolver extends BaseSolver {
238
238
  finalLayout: OutputLayout | null;
239
239
  packSolver2: PackSolver2 | null;
240
240
  constructor(input: PartitionPackingSolverInput);
241
+ private partitionHasFixedChip;
241
242
  _step(): void;
243
+ private buildConnectivityMap;
242
244
  private organizePackedPartitions;
243
245
  private createPackInput;
244
246
  private applyPackingResult;
package/dist/index.js CHANGED
@@ -95,6 +95,10 @@ function getRotatedDimensions(width, height, rotation) {
95
95
  }
96
96
  return { width, height };
97
97
  }
98
+ function getChipLabelFontSize(width, height) {
99
+ const smallerDimension = Math.min(width, height);
100
+ return Math.min(0.35, Math.max(0.08, smallerDimension * 0.22));
101
+ }
98
102
  function visualizeInputProblem(inputProblem, basicLayout) {
99
103
  const inputViz = {
100
104
  points: [],
@@ -138,9 +142,16 @@ function visualizeInputProblem(inputProblem, basicLayout) {
138
142
  center: { x: chipCenterX, y: chipCenterY },
139
143
  width: rotatedDims.width,
140
144
  height: rotatedDims.height,
141
- label: chipId
145
+ label: chipId,
146
+ fill: "rgba(59, 130, 246, 0.12)",
147
+ stroke: "none"
148
+ });
149
+ inputViz.texts.push({
150
+ x: chipCenterX,
151
+ y: chipCenterY,
152
+ text: chipId,
153
+ fontSize: getChipLabelFontSize(rotatedDims.width, rotatedDims.height)
142
154
  });
143
- inputViz.texts.push({ x: chipCenterX, y: chipCenterY, text: chipId });
144
155
  for (const pin of chipPins) {
145
156
  const rotatedOffset = rotatePoint(
146
157
  pin.offset,
@@ -823,9 +834,12 @@ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
823
834
  }
824
835
  _step() {
825
836
  if (!this.activeSubSolver) {
826
- const packInput = this.createPackInput();
837
+ const pinToNetworkMap = createFilteredNetworkMapping({
838
+ inputProblem: this.partitionInputProblem,
839
+ pinIdToStronglyConnectedPins: this.pinIdToStronglyConnectedPins
840
+ }).pinToNetworkMap;
841
+ const packInput = this.createPackInput(pinToNetworkMap);
827
842
  this.activeSubSolver = new PackSolver2(packInput);
828
- this.activeSubSolver = this.activeSubSolver;
829
843
  }
830
844
  this.activeSubSolver.step();
831
845
  if (this.activeSubSolver.failed) {
@@ -841,11 +855,7 @@ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
841
855
  this.activeSubSolver = null;
842
856
  }
843
857
  }
844
- createPackInput() {
845
- const pinToNetworkMap = createFilteredNetworkMapping({
846
- inputProblem: this.partitionInputProblem,
847
- pinIdToStronglyConnectedPins: this.pinIdToStronglyConnectedPins
848
- }).pinToNetworkMap;
858
+ createPackInput(pinToNetworkMap) {
849
859
  const packComponents = Object.entries(
850
860
  this.partitionInputProblem.chipMap
851
861
  ).map(([chipId, chip]) => {
@@ -860,7 +870,6 @@ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
860
870
  type: "rect",
861
871
  offset: { x: pin.offset.x, y: pin.offset.y },
862
872
  size: { x: PIN_SIZE, y: PIN_SIZE }
863
- // Small size for pins
864
873
  });
865
874
  }
866
875
  const padsBoundingBox = getPadsBoundingBox(pads);
@@ -878,10 +887,16 @@ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
878
887
  y: Math.max(padsBoundingBoxSize.y, chip.size.y)
879
888
  }
880
889
  });
890
+ const fixedRotation = chip.availableRotations?.[0] ?? 0;
881
891
  return {
882
892
  componentId: chipId,
883
893
  pads,
884
- availableRotationDegrees: chip.availableRotations || [0, 90, 180, 270]
894
+ availableRotationDegrees: chip.availableRotations ?? [0, 90, 180, 270],
895
+ ...chip.fixedPosition && {
896
+ isStatic: true,
897
+ center: chip.fixedPosition,
898
+ ccwRotationOffset: fixedRotation
899
+ }
885
900
  };
886
901
  });
887
902
  let minGap = this.partitionInputProblem.chipGap;
@@ -902,7 +917,7 @@ var SingleInnerPartitionPackingSolver = class extends BaseSolver {
902
917
  chipPlacements[chipId] = {
903
918
  x: packedComponent.center.x,
904
919
  y: packedComponent.center.y,
905
- ccwRotationDegrees: packedComponent.ccwRotationOffset || packedComponent.ccwRotationDegrees || 0
920
+ ccwRotationDegrees: packedComponent.ccwRotationDegrees ?? packedComponent.ccwRotationOffset ?? 0
906
921
  };
907
922
  }
908
923
  return {
@@ -1007,13 +1022,17 @@ var PartitionPackingSolver = class extends BaseSolver {
1007
1022
  this.packedPartitions = input.packedPartitions;
1008
1023
  this.inputProblem = input.inputProblem;
1009
1024
  }
1025
+ partitionHasFixedChip(partitionIndex) {
1026
+ const packedPartition = this.packedPartitions[partitionIndex];
1027
+ if (!packedPartition) return false;
1028
+ return Object.values(packedPartition.inputProblem.chipMap).some(
1029
+ (chip) => chip.fixedPosition !== void 0
1030
+ );
1031
+ }
1010
1032
  _step() {
1011
1033
  try {
1012
1034
  if (this.packedPartitions.length === 0) {
1013
- this.finalLayout = {
1014
- chipPlacements: {},
1015
- groupPlacements: {}
1016
- };
1035
+ this.finalLayout = { chipPlacements: {}, groupPlacements: {} };
1017
1036
  this.solved = true;
1018
1037
  return;
1019
1038
  }
@@ -1048,6 +1067,35 @@ var PartitionPackingSolver = class extends BaseSolver {
1048
1067
  this.error = `Failed to pack partitions: ${error}`;
1049
1068
  }
1050
1069
  }
1070
+ buildConnectivityMap() {
1071
+ const pinToNetworkMap = /* @__PURE__ */ new Map();
1072
+ for (const packedPartition of this.packedPartitions) {
1073
+ for (const [connKey, connected] of Object.entries(
1074
+ packedPartition.inputProblem.netConnMap
1075
+ )) {
1076
+ if (!connected) continue;
1077
+ const [pinId, netId] = connKey.split("-");
1078
+ if (pinId && netId) pinToNetworkMap.set(pinId, netId);
1079
+ }
1080
+ for (const [connKey, connected] of Object.entries(
1081
+ packedPartition.inputProblem.pinStrongConnMap
1082
+ )) {
1083
+ if (!connected) continue;
1084
+ const pins = connKey.split("-");
1085
+ if (pins.length === 2 && pins[0] && pins[1]) {
1086
+ const existingNet = pinToNetworkMap.get(pins[0]) || pinToNetworkMap.get(pins[1]);
1087
+ if (existingNet) {
1088
+ pinToNetworkMap.set(pins[0], existingNet);
1089
+ pinToNetworkMap.set(pins[1], existingNet);
1090
+ } else {
1091
+ pinToNetworkMap.set(pins[0], connKey);
1092
+ pinToNetworkMap.set(pins[1], connKey);
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+ return pinToNetworkMap;
1098
+ }
1051
1099
  organizePackedPartitions() {
1052
1100
  const partitionGroups = [];
1053
1101
  for (let i = 0; i < this.packedPartitions.length; i++) {
@@ -1078,47 +1126,20 @@ var PartitionPackingSolver = class extends BaseSolver {
1078
1126
  minY = Math.min(minY, chipMinY);
1079
1127
  maxY = Math.max(maxY, chipMaxY);
1080
1128
  }
1081
- const bounds = { minX, maxX, minY, maxY };
1082
1129
  partitionGroups.push({
1083
1130
  partitionIndex: i,
1084
1131
  chipIds: partitionChipIds,
1085
- bounds
1132
+ bounds: { minX, maxX, minY, maxY }
1086
1133
  });
1087
1134
  }
1088
1135
  }
1089
1136
  return partitionGroups;
1090
1137
  }
1091
- createPackInput(partitionGroups) {
1092
- const pinToNetworkMap = /* @__PURE__ */ new Map();
1093
- for (const packedPartition of this.packedPartitions) {
1094
- for (const [connKey, connected] of Object.entries(
1095
- packedPartition.inputProblem.netConnMap
1096
- )) {
1097
- if (!connected) continue;
1098
- const [pinId, netId] = connKey.split("-");
1099
- if (pinId && netId) {
1100
- pinToNetworkMap.set(pinId, netId);
1101
- }
1102
- }
1103
- for (const [connKey, connected] of Object.entries(
1104
- packedPartition.inputProblem.pinStrongConnMap
1105
- )) {
1106
- if (!connected) continue;
1107
- const pins = connKey.split("-");
1108
- if (pins.length === 2 && pins[0] && pins[1]) {
1109
- const existingNet = pinToNetworkMap.get(pins[0]) || pinToNetworkMap.get(pins[1]);
1110
- if (existingNet) {
1111
- pinToNetworkMap.set(pins[0], existingNet);
1112
- pinToNetworkMap.set(pins[1], existingNet);
1113
- } else {
1114
- pinToNetworkMap.set(pins[0], connKey);
1115
- pinToNetworkMap.set(pins[1], connKey);
1116
- }
1117
- }
1118
- }
1119
- }
1120
- const packComponents = partitionGroups.map((group) => {
1138
+ createPackInput(groups) {
1139
+ const pinToNetworkMap = this.buildConnectivityMap();
1140
+ const packComponents = groups.map((group) => {
1121
1141
  const packedPartition = this.packedPartitions[group.partitionIndex];
1142
+ const isFixed = this.partitionHasFixedChip(group.partitionIndex);
1122
1143
  const partitionWidth = group.bounds.maxX - group.bounds.minX;
1123
1144
  const partitionHeight = group.bounds.maxY - group.bounds.minY;
1124
1145
  const centerX = (group.bounds.minX + group.bounds.maxX) / 2;
@@ -1136,37 +1157,32 @@ var PartitionPackingSolver = class extends BaseSolver {
1136
1157
  }
1137
1158
  ];
1138
1159
  const addedNetworks = /* @__PURE__ */ new Set();
1139
- const pinPositions = /* @__PURE__ */ new Map();
1140
1160
  for (const chipId of group.chipIds) {
1141
1161
  const chipPlacement = packedPartition.layout.chipPlacements[chipId];
1142
1162
  const chip = packedPartition.inputProblem.chipMap[chipId];
1143
1163
  for (const pinId of chip.pins) {
1144
1164
  const chipPin = packedPartition.inputProblem.chipPinMap[pinId];
1145
1165
  if (!chipPin) continue;
1146
- let transformedOffset = { x: chipPin.offset.x, y: chipPin.offset.y };
1147
- const rotation = chipPlacement.ccwRotationDegrees || 0;
1148
- if (rotation === 90) {
1149
- transformedOffset = { x: -chipPin.offset.y, y: chipPin.offset.x };
1150
- } else if (rotation === 180) {
1151
- transformedOffset = { x: -chipPin.offset.x, y: -chipPin.offset.y };
1152
- } else if (rotation === 270) {
1153
- transformedOffset = { x: chipPin.offset.y, y: -chipPin.offset.x };
1166
+ let rotatedPinOffset = { x: chipPin.offset.x, y: chipPin.offset.y };
1167
+ const chipRotationDeg = chipPlacement.ccwRotationDegrees ?? 0;
1168
+ if (chipRotationDeg === 90) {
1169
+ rotatedPinOffset = { x: -chipPin.offset.y, y: chipPin.offset.x };
1170
+ } else if (chipRotationDeg === 180) {
1171
+ rotatedPinOffset = { x: -chipPin.offset.x, y: -chipPin.offset.y };
1172
+ } else if (chipRotationDeg === 270) {
1173
+ rotatedPinOffset = { x: chipPin.offset.y, y: -chipPin.offset.x };
1154
1174
  }
1155
- const absolutePinX = chipPlacement.x + transformedOffset.x;
1156
- const absolutePinY = chipPlacement.y + transformedOffset.y;
1157
- pinPositions.set(pinId, { x: absolutePinX, y: absolutePinY });
1158
- const networkId = pinToNetworkMap.get(pinId) || `${pinId}_disconnected`;
1175
+ const absolutePinX = chipPlacement.x + rotatedPinOffset.x;
1176
+ const absolutePinY = chipPlacement.y + rotatedPinOffset.y;
1177
+ const networkId = pinToNetworkMap.get(pinId) ?? `${pinId}_disconnected`;
1159
1178
  if (!addedNetworks.has(networkId)) {
1160
1179
  addedNetworks.add(networkId);
1161
- const padOffsetX = absolutePinX - centerX;
1162
- const padOffsetY = absolutePinY - centerY;
1163
1180
  pads.push({
1164
1181
  padId: `${group.partitionIndex}_pin_${pinId}`,
1165
1182
  networkId,
1166
1183
  type: "rect",
1167
- offset: { x: padOffsetX, y: padOffsetY },
1184
+ offset: { x: absolutePinX - centerX, y: absolutePinY - centerY },
1168
1185
  size: { x: 0.01, y: 0.01 }
1169
- // Small pin pad
1170
1186
  });
1171
1187
  }
1172
1188
  }
@@ -1174,14 +1190,17 @@ var PartitionPackingSolver = class extends BaseSolver {
1174
1190
  return {
1175
1191
  componentId: `partition_${group.partitionIndex}`,
1176
1192
  pads,
1177
- availableRotationDegrees: [0]
1178
- // Keep partitions unrotated
1193
+ availableRotationDegrees: [0],
1194
+ ...isFixed && {
1195
+ isStatic: true,
1196
+ center: { x: centerX, y: centerY },
1197
+ ccwRotationOffset: 0
1198
+ }
1179
1199
  };
1180
1200
  });
1181
1201
  return {
1182
1202
  components: packComponents,
1183
1203
  minGap: this.inputProblem.partitionGap,
1184
- // Use partitionGap from input problem
1185
1204
  packOrderStrategy: "largest_to_smallest",
1186
1205
  packPlacementStrategy: "minimum_sum_squared_distance_to_network"
1187
1206
  };
package/package.json CHANGED
@@ -2,33 +2,35 @@
2
2
  "name": "@tscircuit/matchpack",
3
3
  "main": "dist/index.js",
4
4
  "type": "module",
5
- "version": "0.0.17",
5
+ "version": "0.0.19",
6
6
  "files": [
7
7
  "dist"
8
8
  ],
9
9
  "scripts": {
10
10
  "start": "cosmos",
11
+ "test": "bun test",
11
12
  "build": "tsup-node --format esm --dts --clean ./lib/index.ts",
12
13
  "format": "biome format --write .",
13
14
  "format:check": "biome format .",
14
15
  "build:site": "cosmos-export"
15
16
  },
16
17
  "devDependencies": {
17
- "@biomejs/biome": "^2.1.3",
18
+ "@biomejs/biome": "^2.4.16",
18
19
  "@react-hook/resize-observer": "^2.0.2",
19
- "@tscircuit/circuit-json-util": "^0.0.64",
20
- "@tscircuit/math-utils": "^0.0.19",
21
- "@tscircuit/schematic-viewer": "^2.0.26",
22
- "@types/bun": "latest",
20
+ "@tscircuit/circuit-json-util": "^0.0.95",
21
+ "@tscircuit/math-utils": "^0.0.36",
22
+ "@tscircuit/schematic-viewer": "^2.0.61",
23
+ "@types/bun": "^1.3.14",
24
+ "bun-match-svg": "^0.0.15",
23
25
  "bpc-graph": "^0.0.66",
24
- "calculate-packing": "^0.0.31",
25
- "circuit-json": "^0.0.226",
26
- "graphics-debug": "^0.0.64",
27
- "react-cosmos": "^7.0.0",
28
- "react-cosmos-plugin-vite": "^7.0.0",
29
- "tscircuit": "^0.0.593",
30
- "tsup": "^8.5.0",
31
- "circuit-to-svg": "^0.0.350"
26
+ "calculate-packing": "^0.0.74",
27
+ "circuit-json": "^0.0.432",
28
+ "graphics-debug": "^0.0.95",
29
+ "react-cosmos": "^7.3.0",
30
+ "react-cosmos-plugin-vite": "^7.3.0",
31
+ "tscircuit": "^0.0.1819",
32
+ "tsup": "^8.5.1",
33
+ "circuit-to-svg": "^0.0.351"
32
34
  },
33
35
  "peerDependencies": {
34
36
  "typescript": "^5"