@tscircuit/schematic-trace-solver 0.0.1

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.
Files changed (51) hide show
  1. package/.claude/settings.local.json +6 -0
  2. package/.github/workflows/bun-formatcheck.yml +26 -0
  3. package/.github/workflows/bun-pver-release.yml +28 -0
  4. package/.github/workflows/bun-test.yml +28 -0
  5. package/.github/workflows/bun-typecheck.yml +26 -0
  6. package/LICENSE +21 -0
  7. package/README.md +75 -0
  8. package/biome.json +93 -0
  9. package/bunfig.toml +5 -0
  10. package/cosmos.config.json +6 -0
  11. package/cosmos.decorator.tsx +21 -0
  12. package/dist/index.d.ts +420 -0
  13. package/dist/index.js +7863 -0
  14. package/index.html +17 -0
  15. package/lib/data-structures/ChipObstacleSpatialIndex.ts +70 -0
  16. package/lib/index.ts +2 -0
  17. package/lib/solvers/BaseSolver/BaseSolver.ts +83 -0
  18. package/lib/solvers/GuidelinesSolver/GuidelinesSolver.ts +138 -0
  19. package/lib/solvers/GuidelinesSolver/getGeneratorForAllChipPairs.ts +39 -0
  20. package/lib/solvers/GuidelinesSolver/getHorizontalGuidelineY.ts +18 -0
  21. package/lib/solvers/GuidelinesSolver/getInputChipBounds.ts +20 -0
  22. package/lib/solvers/GuidelinesSolver/getVerticalGuidelineX.ts +18 -0
  23. package/lib/solvers/GuidelinesSolver/visualizeGuidelines.ts +45 -0
  24. package/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +156 -0
  25. package/lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem.ts +20 -0
  26. package/lib/solvers/MspConnectionPairSolver/getMspConnectionPairsFromPins.ts +96 -0
  27. package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +192 -0
  28. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +479 -0
  29. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver.ts +127 -0
  30. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver.ts +191 -0
  31. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/generateElbowVariants.ts +132 -0
  32. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection.ts +42 -0
  33. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +244 -0
  34. package/lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts +89 -0
  35. package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts +180 -0
  36. package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +264 -0
  37. package/lib/types/InputProblem.ts +40 -0
  38. package/lib/utils/dir.ts +16 -0
  39. package/lib/utils/getAllPossibleOrderingsGenerator.ts +47 -0
  40. package/lib/utils/getColorFromString.ts +7 -0
  41. package/package.json +29 -0
  42. package/site/components/GenericSolverDebugger.tsx +0 -0
  43. package/site/components/PipelineDebugger.tsx +29 -0
  44. package/site/components/PipelineStageTable.tsx +149 -0
  45. package/site/components/SolverBreadcrumbInputDownloader.tsx +62 -0
  46. package/site/components/SolverToolbar.tsx +128 -0
  47. package/site/examples/example01-basic.page.tsx +104 -0
  48. package/tests/functions/generateElbowVariants.test.ts +98 -0
  49. package/tests/functions/getOrthogonalMinimumSpanningTree.test.ts +23 -0
  50. package/tsconfig.json +37 -0
  51. package/vite.config.ts +12 -0
@@ -0,0 +1,420 @@
1
+ import * as graphics_debug from 'graphics-debug';
2
+ import { GraphicsObject } from 'graphics-debug';
3
+ import { Bounds, Point } from '@tscircuit/math-utils';
4
+ import Flatbush from 'flatbush';
5
+ import { ConnectivityMap } from 'connectivity-map';
6
+
7
+ declare class BaseSolver {
8
+ MAX_ITERATIONS: number;
9
+ solved: boolean;
10
+ failed: boolean;
11
+ iterations: number;
12
+ progress: number;
13
+ error: string | null;
14
+ activeSubSolver?: BaseSolver | null;
15
+ failedSubSolvers?: BaseSolver[];
16
+ timeToSolve?: number;
17
+ stats: Record<string, any>;
18
+ /** DO NOT OVERRIDE! Override _step() instead */
19
+ step(): void;
20
+ _step(): void;
21
+ getConstructorParams(): void;
22
+ solve(): void;
23
+ visualize(): GraphicsObject;
24
+ /**
25
+ * Called when the solver is about to fail, but we want to see if we have an
26
+ * "acceptable" or "passable" solution. Mostly used for optimizers that
27
+ * have an aggressive early stopping criterion.
28
+ */
29
+ tryFinalAcceptance(): void;
30
+ /**
31
+ * A lightweight version of the visualize method that can be used to stream
32
+ * progress
33
+ */
34
+ preview(): GraphicsObject;
35
+ }
36
+
37
+ interface SpatiallyIndexedChip extends InputChip {
38
+ bounds: Bounds;
39
+ spatialIndexId: number;
40
+ }
41
+ declare class ChipObstacleSpatialIndex {
42
+ chips: Array<SpatiallyIndexedChip>;
43
+ spatialIndex: Flatbush;
44
+ spatialIndexIdToChip: Map<number, SpatiallyIndexedChip>;
45
+ constructor(chips: InputChip[]);
46
+ getChipsInBounds(bounds: Bounds): Array<InputChip & {
47
+ bounds: Bounds;
48
+ }>;
49
+ doesOrthogonalLineIntersectChip(line: [Point, Point], opts?: {
50
+ excludeChipIds?: string[];
51
+ }): boolean;
52
+ }
53
+
54
+ type FacingDirection = "x+" | "x-" | "y+" | "y-";
55
+
56
+ type ChipId = string;
57
+ type PinId = string;
58
+ type NetId = string;
59
+ interface InputPin {
60
+ pinId: PinId;
61
+ x: number;
62
+ y: number;
63
+ _facingDirection?: "x+" | "x-" | "y+" | "y-";
64
+ }
65
+ interface InputChip {
66
+ chipId: ChipId;
67
+ center: {
68
+ x: number;
69
+ y: number;
70
+ };
71
+ width: number;
72
+ height: number;
73
+ pins: Array<InputPin>;
74
+ }
75
+ interface InputDirectConnection {
76
+ pinIds: [PinId, PinId];
77
+ netId?: string;
78
+ }
79
+ interface InputNetConnection {
80
+ netId: string;
81
+ pinIds: Array<PinId>;
82
+ }
83
+ interface InputProblem {
84
+ chips: Array<InputChip>;
85
+ directConnections: Array<InputDirectConnection>;
86
+ netConnections: Array<InputNetConnection>;
87
+ availableNetLabelOrientations: Record<NetId, FacingDirection[]>;
88
+ _chipObstacleSpatialIndex?: ChipObstacleSpatialIndex;
89
+ }
90
+
91
+ type MspConnectionPairId = string;
92
+ type MspConnectionPair = {
93
+ mspPairId: MspConnectionPairId;
94
+ dcConnNetId: string;
95
+ globalConnNetId: string;
96
+ userNetId?: string;
97
+ pins: [InputPin & {
98
+ chipId: string;
99
+ }, InputPin & {
100
+ chipId: string;
101
+ }];
102
+ };
103
+ declare class MspConnectionPairSolver extends BaseSolver {
104
+ inputProblem: InputProblem;
105
+ mspConnectionPairs: MspConnectionPair[];
106
+ dcConnMap: ConnectivityMap;
107
+ globalConnMap: ConnectivityMap;
108
+ queuedDcNetIds: string[];
109
+ chipMap: Record<string, InputChip>;
110
+ pinMap: Record<string, InputPin & {
111
+ chipId: string;
112
+ }>;
113
+ userNetIdByPinId: Record<string, string | undefined>;
114
+ constructor({ inputProblem }: {
115
+ inputProblem: InputProblem;
116
+ });
117
+ getConstructorParams(): ConstructorParameters<typeof MspConnectionPairSolver>[0];
118
+ _step(): void;
119
+ visualize(): GraphicsObject;
120
+ }
121
+
122
+ type Guideline = {
123
+ orientation: "horizontal";
124
+ y: number;
125
+ x: undefined;
126
+ } | {
127
+ orientation: "vertical";
128
+ y: undefined;
129
+ x: number;
130
+ };
131
+ declare class GuidelinesSolver extends BaseSolver {
132
+ inputProblem: InputProblem;
133
+ guidelines: Guideline[];
134
+ chipPairsGenerator: Generator<readonly [InputChip, InputChip]>;
135
+ usedXGuidelines: Set<number>;
136
+ usedYGuidelines: Set<number>;
137
+ constructor(params: {
138
+ inputProblem: InputProblem;
139
+ });
140
+ getConstructorParams(): ConstructorParameters<typeof GuidelinesSolver>[0];
141
+ _step(): void;
142
+ visualize(): GraphicsObject;
143
+ }
144
+
145
+ interface MovableSegment {
146
+ start: Point;
147
+ end: Point;
148
+ freedom: "x+" | "x-" | "y+" | "y-";
149
+ dir: {
150
+ x: number;
151
+ y: number;
152
+ };
153
+ }
154
+
155
+ declare class SchematicTraceSingleLineSolver extends BaseSolver {
156
+ pins: MspConnectionPair["pins"];
157
+ inputProblem: InputProblem;
158
+ guidelines: Guideline[];
159
+ chipMap: Record<string, InputChip>;
160
+ movableSegments: Array<MovableSegment>;
161
+ baseElbow: Point[];
162
+ queuedCandidatePaths: Array<Point[]>;
163
+ chipObstacleSpatialIndex: ChipObstacleSpatialIndex;
164
+ solvedTracePath: {
165
+ x: number;
166
+ y: number;
167
+ }[] | null;
168
+ constructor(params: {
169
+ pins: MspConnectionPair["pins"];
170
+ guidelines: Guideline[];
171
+ inputProblem: InputProblem;
172
+ chipMap: Record<string, InputChip>;
173
+ });
174
+ getConstructorParams(): ConstructorParameters<typeof SchematicTraceSingleLineSolver>[0];
175
+ _step(): void;
176
+ visualize(): GraphicsObject;
177
+ }
178
+
179
+ interface SolvedTracePath extends MspConnectionPair {
180
+ tracePath: Point[];
181
+ }
182
+ declare class SchematicTraceLinesSolver extends BaseSolver {
183
+ inputProblem: InputProblem;
184
+ guidelines: Guideline[];
185
+ mspConnectionPairs: MspConnectionPair[];
186
+ dcConnMap: ConnectivityMap;
187
+ globalConnMap: ConnectivityMap;
188
+ queuedConnectionPairs: MspConnectionPair[];
189
+ chipMap: Record<string, InputChip>;
190
+ currentConnectionPair: MspConnectionPair | null;
191
+ solvedTracePaths: Array<SolvedTracePath>;
192
+ activeSubSolver: SchematicTraceSingleLineSolver | null;
193
+ constructor(params: {
194
+ mspConnectionPairs: MspConnectionPair[];
195
+ chipMap: Record<string, InputChip>;
196
+ dcConnMap: ConnectivityMap;
197
+ globalConnMap: ConnectivityMap;
198
+ inputProblem: InputProblem;
199
+ guidelines: Guideline[];
200
+ });
201
+ getConstructorParams(): ConstructorParameters<typeof SchematicTraceLinesSolver>[0];
202
+ _step(): void;
203
+ visualize(): GraphicsObject;
204
+ }
205
+
206
+ type ConnNetId$1 = string;
207
+ interface OverlappingTraceSegmentLocator {
208
+ connNetId: string;
209
+ pathsWithOverlap: Array<{
210
+ solvedTracePathIndex: number;
211
+ traceSegmentIndex: number;
212
+ }>;
213
+ }
214
+ declare class TraceOverlapIssueSolver extends BaseSolver {
215
+ overlappingTraceSegments: OverlappingTraceSegmentLocator[];
216
+ traceNetIslands: Record<ConnNetId$1, Array<SolvedTracePath>>;
217
+ SHIFT_DISTANCE: number;
218
+ correctedTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
219
+ constructor(params: {
220
+ overlappingTraceSegments: OverlappingTraceSegmentLocator[];
221
+ traceNetIslands: Record<ConnNetId$1, Array<SolvedTracePath>>;
222
+ });
223
+ _step(): void;
224
+ visualize(): GraphicsObject;
225
+ }
226
+
227
+ type ConnNetId = string;
228
+ /**
229
+ * This solver finds traces that overlap (coincident and parallel) and aren't
230
+ * connected via the globalConnMap, then shifts them to avoid the overlap in
231
+ * such a way that minimizes the resulting intersections
232
+ *
233
+ * All traces are orthogonal, so for traces to be considered overlapping, they
234
+ * need to each have a segment where both are horizontal or both are vertical
235
+ * AND the segments must be within 1e-6 of each other in X (if vertical) or
236
+ * Y (if horizontal)
237
+ *
238
+ * Each iteration, we find overlapping traces that aren't part of the same net.
239
+ * This is the same as finding two "trace net islands" that have an overlap.
240
+ *
241
+ * We then consider all the possible ways to shift the overlapping traces to
242
+ * minimize the intersections. If there are multiple trace segments within the
243
+ * same net island they shift together.
244
+ */
245
+ declare class TraceOverlapShiftSolver extends BaseSolver {
246
+ inputProblem: InputProblem;
247
+ inputTracePaths: Array<SolvedTracePath>;
248
+ globalConnMap: ConnectivityMap;
249
+ activeSubSolver: TraceOverlapIssueSolver | null;
250
+ /**
251
+ * A traceNetIsland is a set of traces that are connected via the globalConnMap
252
+ */
253
+ traceNetIslands: Record<ConnNetId, Array<SolvedTracePath>>;
254
+ correctedTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
255
+ constructor(params: {
256
+ inputProblem: InputProblem;
257
+ inputTracePaths: Array<SolvedTracePath>;
258
+ globalConnMap: ConnectivityMap;
259
+ });
260
+ getConstructorParams(): ConstructorParameters<typeof TraceOverlapShiftSolver>[0];
261
+ computeTraceNetIslands(): Record<ConnNetId, Array<SolvedTracePath>>;
262
+ findNextOverlapIssue(): {
263
+ overlappingTraceSegments: Array<OverlappingTraceSegmentLocator>;
264
+ } | null;
265
+ _step(): void;
266
+ visualize(): graphics_debug.GraphicsObject;
267
+ }
268
+
269
+ /**
270
+ * Find a location in the overlappingSameNetTraceGroup where a net label should
271
+ * be placed. We do this by looking for the largest chip, and starting our
272
+ * search from the segment directly connected to the largest chip. We then
273
+ * travel along the segment, moving to any connected segment. Each step, we
274
+ * check a specific segment
275
+ *
276
+ * When checking a segment, we check the following locations with each
277
+ * orientation:
278
+ * - The start of the segment
279
+ * - The start of the segment, plus the width of the net label
280
+ * - The end of the segment
281
+ * - The end of the segment, minus the width of the net label
282
+ *
283
+ * When checking a location, we check for the following:
284
+ * 1. Would placing a net label at this location cause a collision with a chip?
285
+ * 2. Would placing a net label at this location cause a collision with ANY
286
+ * trace? (Note: you must offset the anchor point slightly from the trace to
287
+ * avoid counting the point where the net label contacts the trace)
288
+ *
289
+ * The first location that satisfies the above conditions, in our traversal
290
+ * order from the largest chip, is the location we return in netLabelPlacement
291
+ */
292
+ declare class SingleNetLabelPlacementSolver extends BaseSolver {
293
+ inputProblem: InputProblem;
294
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
295
+ overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup;
296
+ availableOrientations: Array<FacingDirection>;
297
+ chipObstacleSpatialIndex: ChipObstacleSpatialIndex;
298
+ netLabelPlacement: NetLabelPlacement | null;
299
+ testedCandidates: Array<{
300
+ center: {
301
+ x: number;
302
+ y: number;
303
+ };
304
+ width: number;
305
+ height: number;
306
+ bounds: {
307
+ minX: number;
308
+ minY: number;
309
+ maxX: number;
310
+ maxY: number;
311
+ };
312
+ anchor: {
313
+ x: number;
314
+ y: number;
315
+ };
316
+ orientation: FacingDirection;
317
+ status: "ok" | "chip-collision" | "trace-collision" | "parallel-to-segment";
318
+ hostSegIndex: number;
319
+ }>;
320
+ constructor(params: {
321
+ inputProblem: InputProblem;
322
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
323
+ overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup;
324
+ availableOrientations: FacingDirection[];
325
+ });
326
+ private getDimsForOrientation;
327
+ private getCenterFromAnchor;
328
+ private getRectBounds;
329
+ private segmentIntersectsRect;
330
+ private rectIntersectsAnyTrace;
331
+ _step(): void;
332
+ visualize(): GraphicsObject;
333
+ }
334
+
335
+ /**
336
+ * A group of traces that have at least one overlapping segment and
337
+ * are part of the same global connectivity net
338
+ */
339
+ type OverlappingSameNetTraceGroup = {
340
+ globalConnNetId: string;
341
+ netId?: string;
342
+ overlappingTraces: SolvedTracePath;
343
+ };
344
+ interface NetLabelPlacement {
345
+ globalConnNetId: string;
346
+ dcConnNetId?: string;
347
+ orientation: FacingDirection;
348
+ /**
349
+ * The anchor point is the point on the trace where the net label connects
350
+ */
351
+ anchorPoint: Point;
352
+ width: number;
353
+ height: number;
354
+ /**
355
+ * The center point is computed from the anchor point, the width and height
356
+ * and the orientation.
357
+ */
358
+ center: Point;
359
+ }
360
+ /**
361
+ * Places net labels in an available orientation along a trace in each group.
362
+ *
363
+ * Trace groups each receive either one net label or no net label if there
364
+ * isn't a netId.
365
+ *
366
+ * The specific placement of the net label is solved for using the
367
+ */
368
+ declare class NetLabelPlacementSolver extends BaseSolver {
369
+ inputProblem: InputProblem;
370
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
371
+ overlappingSameNetTraceGroups: Array<OverlappingSameNetTraceGroup>;
372
+ queuedOverlappingSameNetTraceGroups: Array<OverlappingSameNetTraceGroup>;
373
+ activeSubSolver: SingleNetLabelPlacementSolver | null;
374
+ netLabelPlacements: Array<NetLabelPlacement>;
375
+ constructor(params: {
376
+ inputProblem: InputProblem;
377
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
378
+ });
379
+ computeOverlappingSameNetTraceGroups(): Array<OverlappingSameNetTraceGroup>;
380
+ _step(): void;
381
+ visualize(): GraphicsObject;
382
+ }
383
+
384
+ /**
385
+ * Pipeline solver that runs a series of solvers to find the best schematic layout.
386
+ * Coordinates the entire layout process from chip partitioning through final packing.
387
+ */
388
+
389
+ type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
390
+ solverName: string;
391
+ solverClass: T;
392
+ getConstructorParams: (instance: SchematicTracePipelineSolver) => ConstructorParameters<T>;
393
+ onSolved?: (instance: SchematicTracePipelineSolver) => void;
394
+ };
395
+ declare class SchematicTracePipelineSolver extends BaseSolver {
396
+ mspConnectionPairSolver?: MspConnectionPairSolver;
397
+ guidelinesSolver?: GuidelinesSolver;
398
+ schematicTraceLinesSolver?: SchematicTraceLinesSolver;
399
+ traceOverlapShiftSolver?: TraceOverlapShiftSolver;
400
+ netLabelPlacementSolver?: NetLabelPlacementSolver;
401
+ startTimeOfPhase: Record<string, number>;
402
+ endTimeOfPhase: Record<string, number>;
403
+ timeSpentOnPhase: Record<string, number>;
404
+ firstIterationOfPhase: Record<string, number>;
405
+ inputProblem: InputProblem;
406
+ pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof GuidelinesSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver>)[];
407
+ constructor(inputProblem: InputProblem);
408
+ currentPipelineStepIndex: number;
409
+ _step(): void;
410
+ solveUntilPhase(phase: string): void;
411
+ getCurrentPhase(): string;
412
+ visualize(): GraphicsObject;
413
+ /**
414
+ * A lightweight version of the visualize method that can be used to stream
415
+ * progress
416
+ */
417
+ preview(): GraphicsObject;
418
+ }
419
+
420
+ export { type ChipId, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type PinId, SchematicTracePipelineSolver };