@tscircuit/capacity-autorouter 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.
- package/LICENSE +0 -0
- package/README.md +186 -0
- package/dist/index.d.ts +818 -0
- package/dist/index.js +4184 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
import { GraphicsObject } from 'graphics-debug';
|
|
2
|
+
import { ConnectivityMap } from 'circuit-json-to-connectivity-map';
|
|
3
|
+
|
|
4
|
+
type TraceId = string;
|
|
5
|
+
interface SimpleRouteJson {
|
|
6
|
+
layerCount: number;
|
|
7
|
+
minTraceWidth: number;
|
|
8
|
+
obstacles: Obstacle[];
|
|
9
|
+
connections: Array<SimpleRouteConnection>;
|
|
10
|
+
bounds: {
|
|
11
|
+
minX: number;
|
|
12
|
+
maxX: number;
|
|
13
|
+
minY: number;
|
|
14
|
+
maxY: number;
|
|
15
|
+
};
|
|
16
|
+
traces?: SimplifiedPcbTraces;
|
|
17
|
+
}
|
|
18
|
+
interface Obstacle {
|
|
19
|
+
type: "rect";
|
|
20
|
+
layers: string[];
|
|
21
|
+
center: {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
};
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
connectedTo: TraceId[];
|
|
28
|
+
}
|
|
29
|
+
interface SimpleRouteConnection {
|
|
30
|
+
name: string;
|
|
31
|
+
pointsToConnect: Array<{
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
layer: string;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
type SimplifiedPcbTraces = Array<{
|
|
38
|
+
type: "pcb_trace";
|
|
39
|
+
pcb_trace_id: TraceId;
|
|
40
|
+
route: Array<{
|
|
41
|
+
route_type: "wire";
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
width: number;
|
|
45
|
+
layer: string;
|
|
46
|
+
} | {
|
|
47
|
+
route_type: "via";
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
to_layer: string;
|
|
51
|
+
from_layer: string;
|
|
52
|
+
}>;
|
|
53
|
+
}>;
|
|
54
|
+
|
|
55
|
+
type CapacityMeshNodeId = string;
|
|
56
|
+
interface CapacityMeshNode {
|
|
57
|
+
capacityMeshNodeId: string;
|
|
58
|
+
center: {
|
|
59
|
+
x: number;
|
|
60
|
+
y: number;
|
|
61
|
+
};
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
layer: string;
|
|
65
|
+
_depth?: number;
|
|
66
|
+
_completelyInsideObstacle?: boolean;
|
|
67
|
+
_containsObstacle?: boolean;
|
|
68
|
+
_containsTarget?: boolean;
|
|
69
|
+
_targetConnectionName?: string;
|
|
70
|
+
_parent?: CapacityMeshNode;
|
|
71
|
+
}
|
|
72
|
+
interface CapacityMeshEdge {
|
|
73
|
+
capacityMeshEdgeId: string;
|
|
74
|
+
nodeIds: [CapacityMeshNodeId, CapacityMeshNodeId];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type CapacityPathId = string;
|
|
78
|
+
interface CapacityPath {
|
|
79
|
+
capacityPathId: CapacityPathId;
|
|
80
|
+
connectionName: string;
|
|
81
|
+
nodeIds: CapacityMeshNodeId[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
declare class BaseSolver {
|
|
85
|
+
MAX_ITERATIONS: number;
|
|
86
|
+
solved: boolean;
|
|
87
|
+
failed: boolean;
|
|
88
|
+
iterations: number;
|
|
89
|
+
progress: number;
|
|
90
|
+
error: string | null;
|
|
91
|
+
/** DO NOT OVERRIDE! Override _step() instead */
|
|
92
|
+
step(): void;
|
|
93
|
+
_step(): void;
|
|
94
|
+
solve(): void;
|
|
95
|
+
visualize(): GraphicsObject;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
declare class CapacityMeshEdgeSolver extends BaseSolver {
|
|
99
|
+
nodes: CapacityMeshNode[];
|
|
100
|
+
edges: Array<CapacityMeshEdge>;
|
|
101
|
+
constructor(nodes: CapacityMeshNode[]);
|
|
102
|
+
getNextCapacityMeshEdgeId(): string;
|
|
103
|
+
step(): void;
|
|
104
|
+
private areNodesBordering;
|
|
105
|
+
visualize(): GraphicsObject;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface CapacityMeshNodeSolverOptions {
|
|
109
|
+
capacityDepth?: number;
|
|
110
|
+
}
|
|
111
|
+
declare class CapacityMeshNodeSolver extends BaseSolver {
|
|
112
|
+
srj: SimpleRouteJson;
|
|
113
|
+
opts: CapacityMeshNodeSolverOptions;
|
|
114
|
+
unfinishedNodes: CapacityMeshNode[];
|
|
115
|
+
finishedNodes: CapacityMeshNode[];
|
|
116
|
+
nodeToOverlappingObstaclesMap: Map<CapacityMeshNodeId, Obstacle[]>;
|
|
117
|
+
MAX_DEPTH: number;
|
|
118
|
+
constructor(srj: SimpleRouteJson, opts?: CapacityMeshNodeSolverOptions);
|
|
119
|
+
_nextNodeCounter: number;
|
|
120
|
+
getNextNodeId(): string;
|
|
121
|
+
getCapacityFromDepth(depth: number): number;
|
|
122
|
+
getTargetNameIfNodeContainsTarget(node: CapacityMeshNode): string | null;
|
|
123
|
+
getOverlappingObstacles(node: CapacityMeshNode): Obstacle[];
|
|
124
|
+
/**
|
|
125
|
+
* Checks if the given mesh node overlaps with any obstacle.
|
|
126
|
+
* We treat both obstacles and nodes as axis‐aligned rectangles.
|
|
127
|
+
*/
|
|
128
|
+
doesNodeOverlapObstacle(node: CapacityMeshNode): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Checks if the entire node is contained within any obstacle.
|
|
131
|
+
*/
|
|
132
|
+
isNodeCompletelyInsideObstacle(node: CapacityMeshNode): boolean;
|
|
133
|
+
getChildNodes(parent: CapacityMeshNode): CapacityMeshNode[];
|
|
134
|
+
shouldNodeBeSubdivided(node: CapacityMeshNode): boolean;
|
|
135
|
+
_step(): void;
|
|
136
|
+
/**
|
|
137
|
+
* Creates a GraphicsObject to visualize the mesh, its nodes, obstacles, and connection points.
|
|
138
|
+
*
|
|
139
|
+
* - Mesh nodes are rendered as rectangles.
|
|
140
|
+
* - Nodes that have an obstacle intersection are outlined in red.
|
|
141
|
+
* - Other nodes are outlined in green.
|
|
142
|
+
* - Lines are drawn from a node to its parent.
|
|
143
|
+
* - Obstacles are drawn as semi-transparent red rectangles.
|
|
144
|
+
* - Points for each connection’s pointsToConnect are drawn in a unique color.
|
|
145
|
+
*/
|
|
146
|
+
visualize(): GraphicsObject;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface CapacityHyperParameters {
|
|
150
|
+
VIA_DIAMETER: number;
|
|
151
|
+
TRACE_WIDTH: number;
|
|
152
|
+
MAX_CAPACITY_FACTOR: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
type Candidate = {
|
|
156
|
+
prevCandidate: Candidate | null;
|
|
157
|
+
node: CapacityMeshNode;
|
|
158
|
+
f: number;
|
|
159
|
+
g: number;
|
|
160
|
+
h: number;
|
|
161
|
+
};
|
|
162
|
+
declare class CapacityPathingSolver extends BaseSolver {
|
|
163
|
+
connectionsWithNodes: Array<{
|
|
164
|
+
connection: SimpleRouteConnection;
|
|
165
|
+
nodes: CapacityMeshNode[];
|
|
166
|
+
path?: CapacityMeshNode[];
|
|
167
|
+
}>;
|
|
168
|
+
usedNodeCapacityMap: Map<CapacityMeshNodeId, number>;
|
|
169
|
+
simpleRouteJson: SimpleRouteJson;
|
|
170
|
+
nodes: CapacityMeshNode[];
|
|
171
|
+
edges: CapacityMeshEdge[];
|
|
172
|
+
GREEDY_MULTIPLIER: number;
|
|
173
|
+
nodeMap: Map<CapacityMeshNodeId, CapacityMeshNode>;
|
|
174
|
+
nodeEdgeMap: Map<CapacityMeshNodeId, CapacityMeshEdge[]>;
|
|
175
|
+
connectionNameToGoalNodeIds: Map<string, CapacityMeshNodeId[]>;
|
|
176
|
+
colorMap: Record<string, string>;
|
|
177
|
+
maxDepthOfNodes: number;
|
|
178
|
+
activeCandidateStraightLineDistance?: number;
|
|
179
|
+
hyperParameters: Partial<CapacityHyperParameters>;
|
|
180
|
+
constructor({ simpleRouteJson, nodes, edges, colorMap, MAX_ITERATIONS, hyperParameters, }: {
|
|
181
|
+
simpleRouteJson: SimpleRouteJson;
|
|
182
|
+
nodes: CapacityMeshNode[];
|
|
183
|
+
edges: CapacityMeshEdge[];
|
|
184
|
+
colorMap?: Record<string, string>;
|
|
185
|
+
MAX_ITERATIONS?: number;
|
|
186
|
+
hyperParameters?: Partial<CapacityHyperParameters>;
|
|
187
|
+
});
|
|
188
|
+
getTotalCapacity(node: CapacityMeshNode): number;
|
|
189
|
+
getConnectionsWithNodes(): {
|
|
190
|
+
connectionsWithNodes: {
|
|
191
|
+
connection: SimpleRouteConnection;
|
|
192
|
+
nodes: CapacityMeshNode[];
|
|
193
|
+
pathFound: boolean;
|
|
194
|
+
}[];
|
|
195
|
+
connectionNameToGoalNodeIds: Map<string, string[]>;
|
|
196
|
+
};
|
|
197
|
+
currentConnectionIndex: number;
|
|
198
|
+
candidates?: Array<Candidate> | null;
|
|
199
|
+
visitedNodes?: Set<CapacityMeshNodeId> | null;
|
|
200
|
+
computeG(prevCandidate: Candidate, node: CapacityMeshNode, endGoal: CapacityMeshNode): number;
|
|
201
|
+
computeH(prevCandidate: Candidate, node: CapacityMeshNode, endGoal: CapacityMeshNode): number;
|
|
202
|
+
getBacktrackedPath(candidate: Candidate): CapacityMeshNode[];
|
|
203
|
+
getNeighboringNodes(node: CapacityMeshNode): CapacityMeshNode[];
|
|
204
|
+
getCapacityPaths(): CapacityPath[];
|
|
205
|
+
doesNodeHaveCapacityForTrace(node: CapacityMeshNode): boolean;
|
|
206
|
+
canTravelThroughObstacle(node: CapacityMeshNode, connectionName: string): boolean;
|
|
207
|
+
getDistanceBetweenNodes(A: CapacityMeshNode, B: CapacityMeshNode): number;
|
|
208
|
+
reduceCapacityAlongPath(nextConnection: {
|
|
209
|
+
path?: CapacityMeshNode[];
|
|
210
|
+
}): void;
|
|
211
|
+
_step(): void;
|
|
212
|
+
visualize(): GraphicsObject;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface NodePortSegment {
|
|
216
|
+
capacityMeshNodeId: string;
|
|
217
|
+
nodePortSegmentId?: string;
|
|
218
|
+
start: {
|
|
219
|
+
x: number;
|
|
220
|
+
y: number;
|
|
221
|
+
};
|
|
222
|
+
end: {
|
|
223
|
+
x: number;
|
|
224
|
+
y: number;
|
|
225
|
+
};
|
|
226
|
+
connectionNames: string[];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Each Node is a square. The capacity paths indicate the nodes the trace will
|
|
231
|
+
* travel through. We want to find the "Port Segment" that each capacity path
|
|
232
|
+
* will take for each node.
|
|
233
|
+
*/
|
|
234
|
+
declare class CapacityEdgeToPortSegmentSolver extends BaseSolver {
|
|
235
|
+
nodes: CapacityMeshNode[];
|
|
236
|
+
edges: CapacityMeshEdge[];
|
|
237
|
+
capacityPaths: CapacityPath[];
|
|
238
|
+
nodeMap: Map<CapacityMeshNodeId, CapacityMeshNode>;
|
|
239
|
+
nodeEdgeMap: Map<CapacityMeshNodeId, CapacityMeshEdge[]>;
|
|
240
|
+
unprocessedNodeIds: CapacityMeshNodeId[];
|
|
241
|
+
nodePortSegments: Map<CapacityMeshNodeId, NodePortSegment[]>;
|
|
242
|
+
colorMap: Record<string, string>;
|
|
243
|
+
constructor({ nodes, edges, capacityPaths, colorMap, }: {
|
|
244
|
+
nodes: CapacityMeshNode[];
|
|
245
|
+
edges: CapacityMeshEdge[];
|
|
246
|
+
capacityPaths: CapacityPath[];
|
|
247
|
+
colorMap?: Record<string, string>;
|
|
248
|
+
});
|
|
249
|
+
step(): void;
|
|
250
|
+
visualize(): GraphicsObject;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
type PortPoint = {
|
|
254
|
+
connectionName: string;
|
|
255
|
+
x: number;
|
|
256
|
+
y: number;
|
|
257
|
+
z: number;
|
|
258
|
+
};
|
|
259
|
+
type NodeWithPortPoints = {
|
|
260
|
+
capacityMeshNodeId: string;
|
|
261
|
+
center: {
|
|
262
|
+
x: number;
|
|
263
|
+
y: number;
|
|
264
|
+
};
|
|
265
|
+
width: number;
|
|
266
|
+
height: number;
|
|
267
|
+
portPoints: PortPoint[];
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* A path for a wire in high-density intra-node routing.
|
|
271
|
+
*
|
|
272
|
+
* Wires travel along a route, and are placed to avoid other
|
|
273
|
+
* wires at the same z-level. Any time a z level is changed,
|
|
274
|
+
* you must place a via.
|
|
275
|
+
*
|
|
276
|
+
* z is an integer corresponding to the layer index
|
|
277
|
+
*
|
|
278
|
+
* z=0: top layer for 2 layer boards
|
|
279
|
+
* z=1: bottom layer for 2 layer boards
|
|
280
|
+
*
|
|
281
|
+
* z must be an integer
|
|
282
|
+
*/
|
|
283
|
+
type HighDensityIntraNodeRoute = {
|
|
284
|
+
connectionName: string;
|
|
285
|
+
traceThickness: number;
|
|
286
|
+
viaDiameter: number;
|
|
287
|
+
route: Array<{
|
|
288
|
+
x: number;
|
|
289
|
+
y: number;
|
|
290
|
+
z: number;
|
|
291
|
+
}>;
|
|
292
|
+
vias: Array<{
|
|
293
|
+
x: number;
|
|
294
|
+
y: number;
|
|
295
|
+
}>;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
interface SegmentWithAssignedPoints extends NodePortSegment {
|
|
299
|
+
assignedPoints?: {
|
|
300
|
+
connectionName: string;
|
|
301
|
+
point: {
|
|
302
|
+
x: number;
|
|
303
|
+
y: number;
|
|
304
|
+
z: number;
|
|
305
|
+
};
|
|
306
|
+
}[];
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* CapacitySegmentToPointSolver:
|
|
310
|
+
*
|
|
311
|
+
* In each step, the solver iterates over all unsolved segments (segments
|
|
312
|
+
* without points assigned for each connection). For each segment:
|
|
313
|
+
*
|
|
314
|
+
* - If there is only one connection, it assigns the center as the point.
|
|
315
|
+
* - If there are two connections, it attempts to determine the ordering using
|
|
316
|
+
* other segments within the node. If no ordering can be determined, it does nothing.
|
|
317
|
+
*
|
|
318
|
+
* If an iteration produces no new assignments, the solver picks the segment with
|
|
319
|
+
* the fewest connections and assigns points evenly spaced along the segment,
|
|
320
|
+
* ordering them alphabetically.
|
|
321
|
+
*/
|
|
322
|
+
declare class CapacitySegmentToPointSolver extends BaseSolver {
|
|
323
|
+
unsolvedSegments: SegmentWithAssignedPoints[];
|
|
324
|
+
solvedSegments: (NodePortSegment & {
|
|
325
|
+
assignedPoints: {
|
|
326
|
+
connectionName: string;
|
|
327
|
+
point: {
|
|
328
|
+
x: number;
|
|
329
|
+
y: number;
|
|
330
|
+
z: number;
|
|
331
|
+
};
|
|
332
|
+
}[];
|
|
333
|
+
})[];
|
|
334
|
+
nodeMap: Record<string, CapacityMeshNode>;
|
|
335
|
+
colorMap: Record<string, string>;
|
|
336
|
+
constructor({ segments, colorMap, nodes, }: {
|
|
337
|
+
segments: NodePortSegment[];
|
|
338
|
+
colorMap?: Record<string, string>;
|
|
339
|
+
/**
|
|
340
|
+
* This isn't used by the algorithm, but allows associating metadata
|
|
341
|
+
* for the result datatype (the center, width, height of the node)
|
|
342
|
+
*/
|
|
343
|
+
nodes: CapacityMeshNode[];
|
|
344
|
+
});
|
|
345
|
+
/**
|
|
346
|
+
* Perform one iteration step.
|
|
347
|
+
*/
|
|
348
|
+
_step(): void;
|
|
349
|
+
/**
|
|
350
|
+
* Return the assigned points for each segment.
|
|
351
|
+
*/
|
|
352
|
+
getNodesWithPortPoints(): NodeWithPortPoints[];
|
|
353
|
+
/**
|
|
354
|
+
* Return a GraphicsObject that visualizes the segments with assigned points.
|
|
355
|
+
*/
|
|
356
|
+
visualize(): GraphicsObject;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
interface HighDensityHyperParameters {
|
|
360
|
+
FUTURE_CONNECTION_PROX_TRACE_PENALTY_FACTOR: number;
|
|
361
|
+
FUTURE_CONNECTION_PROX_VIA_PENALTY_FACTOR: number;
|
|
362
|
+
FUTURE_CONNECTION_PROXIMITY_VD: number;
|
|
363
|
+
MISALIGNED_DIST_PENALTY_FACTOR: number;
|
|
364
|
+
VIA_PENALTY_FACTOR_2: number;
|
|
365
|
+
SHUFFLE_SEED: number;
|
|
366
|
+
CELL_SIZE_FACTOR: number;
|
|
367
|
+
FLIP_TRACE_ALIGNMENT_DIRECTION: boolean;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
type FutureConnection = {
|
|
371
|
+
connectionName: string;
|
|
372
|
+
points: {
|
|
373
|
+
x: number;
|
|
374
|
+
y: number;
|
|
375
|
+
}[];
|
|
376
|
+
};
|
|
377
|
+
type Node = {
|
|
378
|
+
x: number;
|
|
379
|
+
y: number;
|
|
380
|
+
z: number;
|
|
381
|
+
g: number;
|
|
382
|
+
h: number;
|
|
383
|
+
f: number;
|
|
384
|
+
parent: Node | null;
|
|
385
|
+
};
|
|
386
|
+
declare class SingleHighDensityRouteSolver extends BaseSolver {
|
|
387
|
+
obstacleRoutes: HighDensityIntraNodeRoute[];
|
|
388
|
+
bounds: {
|
|
389
|
+
minX: number;
|
|
390
|
+
maxX: number;
|
|
391
|
+
minY: number;
|
|
392
|
+
maxY: number;
|
|
393
|
+
};
|
|
394
|
+
boundsSize: {
|
|
395
|
+
width: number;
|
|
396
|
+
height: number;
|
|
397
|
+
};
|
|
398
|
+
boundsCenter: {
|
|
399
|
+
x: number;
|
|
400
|
+
y: number;
|
|
401
|
+
};
|
|
402
|
+
A: {
|
|
403
|
+
x: number;
|
|
404
|
+
y: number;
|
|
405
|
+
z: number;
|
|
406
|
+
};
|
|
407
|
+
B: {
|
|
408
|
+
x: number;
|
|
409
|
+
y: number;
|
|
410
|
+
z: number;
|
|
411
|
+
};
|
|
412
|
+
straightLineDistance: number;
|
|
413
|
+
viaDiameter: number;
|
|
414
|
+
traceThickness: number;
|
|
415
|
+
obstacleMargin: number;
|
|
416
|
+
layerCount: number;
|
|
417
|
+
minCellSize: number;
|
|
418
|
+
cellStep: number;
|
|
419
|
+
GREEDY_MULTIPLER: number;
|
|
420
|
+
numRoutes: number;
|
|
421
|
+
VIA_PENALTY_FACTOR: number;
|
|
422
|
+
CELL_SIZE_FACTOR: number;
|
|
423
|
+
exploredNodes: Set<string>;
|
|
424
|
+
candidates: Node[];
|
|
425
|
+
connectionName: string;
|
|
426
|
+
solvedPath: HighDensityIntraNodeRoute | null;
|
|
427
|
+
futureConnections: FutureConnection[];
|
|
428
|
+
hyperParameters: Partial<HighDensityHyperParameters>;
|
|
429
|
+
connMap?: ConnectivityMap;
|
|
430
|
+
/** For debugging/animating the exploration */
|
|
431
|
+
debug_exploredNodesOrdered: string[];
|
|
432
|
+
debug_nodesTooCloseToObstacle: Set<string>;
|
|
433
|
+
debug_nodePathToParentIntersectsObstacle: Set<string>;
|
|
434
|
+
debugEnabled: boolean;
|
|
435
|
+
constructor(opts: {
|
|
436
|
+
connectionName: string;
|
|
437
|
+
obstacleRoutes: HighDensityIntraNodeRoute[];
|
|
438
|
+
minDistBetweenEnteringPoints: number;
|
|
439
|
+
bounds: {
|
|
440
|
+
minX: number;
|
|
441
|
+
maxX: number;
|
|
442
|
+
minY: number;
|
|
443
|
+
maxY: number;
|
|
444
|
+
};
|
|
445
|
+
A: {
|
|
446
|
+
x: number;
|
|
447
|
+
y: number;
|
|
448
|
+
z: number;
|
|
449
|
+
};
|
|
450
|
+
B: {
|
|
451
|
+
x: number;
|
|
452
|
+
y: number;
|
|
453
|
+
z: number;
|
|
454
|
+
};
|
|
455
|
+
viaDiameter?: number;
|
|
456
|
+
traceThickness?: number;
|
|
457
|
+
obstacleMargin?: number;
|
|
458
|
+
layerCount?: number;
|
|
459
|
+
futureConnections?: FutureConnection[];
|
|
460
|
+
hyperParameters?: Partial<HighDensityHyperParameters>;
|
|
461
|
+
connMap?: ConnectivityMap;
|
|
462
|
+
});
|
|
463
|
+
handleSimpleCases(): void;
|
|
464
|
+
get viaPenaltyDistance(): number;
|
|
465
|
+
isNodeTooCloseToObstacle(node: Node, margin?: number, isVia?: boolean): boolean;
|
|
466
|
+
isNodeTooCloseToEdge(node: Node): boolean;
|
|
467
|
+
doesPathToParentIntersectObstacle(node: Node): boolean;
|
|
468
|
+
computeH(node: Node): number;
|
|
469
|
+
computeG(node: Node): number;
|
|
470
|
+
computeF(g: number, h: number): number;
|
|
471
|
+
getNodeKey(node: Node): string;
|
|
472
|
+
getNeighbors(node: Node): Node[];
|
|
473
|
+
getNodePath(node: Node): Node[];
|
|
474
|
+
getViasInNodePath(node: Node): {
|
|
475
|
+
x: number;
|
|
476
|
+
y: number;
|
|
477
|
+
}[];
|
|
478
|
+
setSolvedPath(node: Node): void;
|
|
479
|
+
computeProgress(currentNode: Node, goalDist: number, isOnLayer: boolean): number;
|
|
480
|
+
_step(): void;
|
|
481
|
+
visualize(): GraphicsObject;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
declare class SingleIntraNodeRouteSolver extends BaseSolver {
|
|
485
|
+
nodeWithPortPoints: NodeWithPortPoints;
|
|
486
|
+
colorMap: Record<string, string>;
|
|
487
|
+
unsolvedConnections: {
|
|
488
|
+
connectionName: string;
|
|
489
|
+
points: {
|
|
490
|
+
x: number;
|
|
491
|
+
y: number;
|
|
492
|
+
z: number;
|
|
493
|
+
}[];
|
|
494
|
+
}[];
|
|
495
|
+
totalConnections: number;
|
|
496
|
+
solvedRoutes: HighDensityIntraNodeRoute[];
|
|
497
|
+
failedSolvers: SingleHighDensityRouteSolver[];
|
|
498
|
+
hyperParameters: Partial<HighDensityHyperParameters>;
|
|
499
|
+
minDistBetweenEnteringPoints: number;
|
|
500
|
+
activeSolver: SingleHighDensityRouteSolver | null;
|
|
501
|
+
connMap?: ConnectivityMap;
|
|
502
|
+
constructor(params: {
|
|
503
|
+
nodeWithPortPoints: NodeWithPortPoints;
|
|
504
|
+
colorMap?: Record<string, string>;
|
|
505
|
+
hyperParameters?: Partial<HighDensityHyperParameters>;
|
|
506
|
+
connMap?: ConnectivityMap;
|
|
507
|
+
});
|
|
508
|
+
computeProgress(): number;
|
|
509
|
+
_step(): void;
|
|
510
|
+
visualize(): GraphicsObject;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
type SupervisedSolver<T extends BaseSolver> = {
|
|
514
|
+
hyperParameters: any;
|
|
515
|
+
solver: T;
|
|
516
|
+
h: number;
|
|
517
|
+
g: number;
|
|
518
|
+
f: number;
|
|
519
|
+
};
|
|
520
|
+
type HyperParameterDef = {
|
|
521
|
+
name: string;
|
|
522
|
+
possibleValues: Array<any>;
|
|
523
|
+
};
|
|
524
|
+
/**
|
|
525
|
+
* The HyperParameterSupervisorSolver is a solver that solves a problem by
|
|
526
|
+
* running competing solvers with different hyperparameters.
|
|
527
|
+
*
|
|
528
|
+
* As solvers make progress, the supervisor will allow the best solvers to run
|
|
529
|
+
* for more iterations, prioritizing the solvers that are working the best.
|
|
530
|
+
*/
|
|
531
|
+
declare class HyperParameterSupervisorSolver<T extends BaseSolver> extends BaseSolver {
|
|
532
|
+
GREEDY_MULTIPLIER: number;
|
|
533
|
+
MIN_SUBSTEPS: number;
|
|
534
|
+
supervisedSolvers?: Array<SupervisedSolver<T>>;
|
|
535
|
+
getHyperParameterDefs(): Array<HyperParameterDef>;
|
|
536
|
+
getCombinationDefs(): Array<Array<string>> | null;
|
|
537
|
+
getHyperParameterCombinations(hyperParameterDefs?: Array<HyperParameterDef>): Array<Record<string, any>>;
|
|
538
|
+
initializeSolvers(): void;
|
|
539
|
+
generateSolver(hyperParameters: any): T;
|
|
540
|
+
computeG(solver: T): number;
|
|
541
|
+
computeH(solver: T): number;
|
|
542
|
+
computeF(g: number, h: number): number;
|
|
543
|
+
getSupervisedSolverWithBestFitness(): SupervisedSolver<T> | null;
|
|
544
|
+
_step(): void;
|
|
545
|
+
onSolve(solver: SupervisedSolver<T>): void;
|
|
546
|
+
visualize(): GraphicsObject;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
declare class HyperSingleIntraNodeSolver extends HyperParameterSupervisorSolver<SingleIntraNodeRouteSolver> {
|
|
550
|
+
constructorParams: ConstructorParameters<typeof SingleIntraNodeRouteSolver>[0];
|
|
551
|
+
solvedRoutes: HighDensityIntraNodeRoute[];
|
|
552
|
+
nodeWithPortPoints: NodeWithPortPoints;
|
|
553
|
+
constructor(opts: ConstructorParameters<typeof SingleIntraNodeRouteSolver>[0]);
|
|
554
|
+
getCombinationDefs(): string[][];
|
|
555
|
+
getHyperParameterDefs(): ({
|
|
556
|
+
name: string;
|
|
557
|
+
possibleValues: ({
|
|
558
|
+
FUTURE_CONNECTION_PROX_TRACE_PENALTY_FACTOR: number;
|
|
559
|
+
FUTURE_CONNECTION_PROX_VIA_PENALTY_FACTOR: number;
|
|
560
|
+
FUTURE_CONNECTION_PROXIMITY_VD: number;
|
|
561
|
+
MISALIGNED_DIST_PENALTY_FACTOR: number;
|
|
562
|
+
VIA_PENALTY_FACTOR_2?: undefined;
|
|
563
|
+
} | {
|
|
564
|
+
FUTURE_CONNECTION_PROX_TRACE_PENALTY_FACTOR: number;
|
|
565
|
+
FUTURE_CONNECTION_PROX_VIA_PENALTY_FACTOR: number;
|
|
566
|
+
FUTURE_CONNECTION_PROXIMITY_VD: number;
|
|
567
|
+
MISALIGNED_DIST_PENALTY_FACTOR: number;
|
|
568
|
+
VIA_PENALTY_FACTOR_2: number;
|
|
569
|
+
})[];
|
|
570
|
+
} | {
|
|
571
|
+
name: string;
|
|
572
|
+
possibleValues: {
|
|
573
|
+
SHUFFLE_SEED: number;
|
|
574
|
+
}[];
|
|
575
|
+
} | {
|
|
576
|
+
name: string;
|
|
577
|
+
possibleValues: {
|
|
578
|
+
CELL_SIZE_FACTOR: number;
|
|
579
|
+
}[];
|
|
580
|
+
} | {
|
|
581
|
+
name: string;
|
|
582
|
+
possibleValues: {
|
|
583
|
+
FLIP_TRACE_ALIGNMENT_DIRECTION: boolean;
|
|
584
|
+
}[];
|
|
585
|
+
} | {
|
|
586
|
+
name: string;
|
|
587
|
+
possibleValues: {
|
|
588
|
+
CELL_SIZE_FACTOR: number;
|
|
589
|
+
VIA_PENALTY_FACTOR_2: number;
|
|
590
|
+
}[];
|
|
591
|
+
})[];
|
|
592
|
+
computeG(solver: SingleIntraNodeRouteSolver): number;
|
|
593
|
+
computeH(solver: SingleIntraNodeRouteSolver): number;
|
|
594
|
+
generateSolver(hyperParameters: any): SingleIntraNodeRouteSolver;
|
|
595
|
+
onSolve(solver: SupervisedSolver<SingleIntraNodeRouteSolver>): void;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
declare class HighDensityRouteSolver extends BaseSolver {
|
|
599
|
+
unsolvedNodePortPoints: NodeWithPortPoints[];
|
|
600
|
+
routes: HighDensityIntraNodeRoute[];
|
|
601
|
+
colorMap: Record<string, string>;
|
|
602
|
+
readonly defaultViaDiameter = 0.6;
|
|
603
|
+
readonly defaultTraceThickness = 0.15;
|
|
604
|
+
failedSolvers: (SingleIntraNodeRouteSolver | HyperSingleIntraNodeSolver)[];
|
|
605
|
+
activeSubSolver: SingleIntraNodeRouteSolver | HyperSingleIntraNodeSolver | null;
|
|
606
|
+
connMap?: ConnectivityMap;
|
|
607
|
+
constructor({ nodePortPoints, colorMap, connMap, }: {
|
|
608
|
+
nodePortPoints: NodeWithPortPoints[];
|
|
609
|
+
colorMap?: Record<string, string>;
|
|
610
|
+
connMap?: ConnectivityMap;
|
|
611
|
+
});
|
|
612
|
+
/**
|
|
613
|
+
* Each iteration, pop an unsolved node and attempt to find the routes inside
|
|
614
|
+
* of it.
|
|
615
|
+
*/
|
|
616
|
+
_step(): void;
|
|
617
|
+
visualize(): GraphicsObject;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
declare class CapacityNodeTargetMerger extends BaseSolver {
|
|
621
|
+
nodes: CapacityMeshNode[];
|
|
622
|
+
connMap: ConnectivityMap;
|
|
623
|
+
unprocessedObstacles: Obstacle[];
|
|
624
|
+
newNodes: CapacityMeshNode[];
|
|
625
|
+
removedNodeIds: Set<string>;
|
|
626
|
+
constructor(nodes: CapacityMeshNode[], obstacles: Obstacle[], connMap: ConnectivityMap);
|
|
627
|
+
_step(): void;
|
|
628
|
+
visualize(): GraphicsObject;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
type NodePortSegmentId = string;
|
|
632
|
+
interface ChangeLayerOperation {
|
|
633
|
+
op: "changeLayer";
|
|
634
|
+
segmentId: string;
|
|
635
|
+
pointIndex: number;
|
|
636
|
+
newLayer: number;
|
|
637
|
+
/** Operation is mutated and oldLayer is added to allow reversal */
|
|
638
|
+
oldLayer?: number;
|
|
639
|
+
cost?: number;
|
|
640
|
+
}
|
|
641
|
+
interface SwitchOperation {
|
|
642
|
+
op: "switch";
|
|
643
|
+
segmentId: string;
|
|
644
|
+
point1Index: number;
|
|
645
|
+
point2Index: number;
|
|
646
|
+
cost?: number;
|
|
647
|
+
}
|
|
648
|
+
interface CombinedOperation {
|
|
649
|
+
op: "combined";
|
|
650
|
+
subOperations: Array<SwitchOperation | ChangeLayerOperation>;
|
|
651
|
+
cost?: number;
|
|
652
|
+
}
|
|
653
|
+
type Operation = ChangeLayerOperation | SwitchOperation | CombinedOperation;
|
|
654
|
+
/**
|
|
655
|
+
* Use simulated annealing to try to improve the placement of points (via
|
|
656
|
+
* swapping with points on the same segment) or changing the layer.
|
|
657
|
+
*
|
|
658
|
+
* We have the following pieces of information:
|
|
659
|
+
* - NodePortSegment with nodePortSegmentId
|
|
660
|
+
* - A "neighbor" NodePortSegmentWithAssignedPoints has one change
|
|
661
|
+
* - A change can be flipping a point to the opposite layer
|
|
662
|
+
* - A change can also be switching the position of two points
|
|
663
|
+
* - We represent the operations used to change from an original scene
|
|
664
|
+
* with a list of operations [SEG1_CL(1, 1), SEG1_SW(1, 2), SEG2_CL(2, 0)]
|
|
665
|
+
* - CN indicates the capacity node to edit
|
|
666
|
+
* - The SW operation "switches" the x/y location of two points
|
|
667
|
+
* - The CL operation changes the layer of the point
|
|
668
|
+
* - When choosing edits to make, we are biased to operate on nodes that have a
|
|
669
|
+
* high cost and biased against operating on nodes we've operated on a lot
|
|
670
|
+
* - Each step, we generate an operation and use the standard simulated
|
|
671
|
+
* annealing function to determine if we should perform the operation
|
|
672
|
+
*/
|
|
673
|
+
declare class CapacitySegmentPointOptimizer extends BaseSolver {
|
|
674
|
+
assignedSegments: SegmentWithAssignedPoints[];
|
|
675
|
+
colorMap: Record<string, string>;
|
|
676
|
+
nodeMap: Map<CapacityMeshNodeId, CapacityMeshNode>;
|
|
677
|
+
nodeIdToSegmentIds: Map<string, string[]>;
|
|
678
|
+
segmentIdToNodeIds: Map<string, string[]>;
|
|
679
|
+
currentMutatedSegments: Map<NodePortSegmentId, SegmentWithAssignedPoints>;
|
|
680
|
+
allSegmentIds: string[];
|
|
681
|
+
lastAppliedOperation: Operation | null;
|
|
682
|
+
lastCreatedOperation: Operation | null;
|
|
683
|
+
currentNodeCosts: Map<CapacityMeshNodeId, number>;
|
|
684
|
+
lastAcceptedIteration: number;
|
|
685
|
+
currentCost: number;
|
|
686
|
+
randomSeed: number;
|
|
687
|
+
numNodes: number;
|
|
688
|
+
probabilityOfFailure: number;
|
|
689
|
+
nodesThatCantFitVias: Set<CapacityMeshNodeId>;
|
|
690
|
+
mutableSegments: Set<NodePortSegmentId>;
|
|
691
|
+
VIA_DIAMETER: number;
|
|
692
|
+
OBSTACLE_MARGIN: number;
|
|
693
|
+
MAX_OPERATIONS_PER_MUTATION: number;
|
|
694
|
+
MAX_NODE_CHAIN_PER_MUTATION: number;
|
|
695
|
+
NOOP_ITERATIONS_BEFORE_EARLY_STOP: number;
|
|
696
|
+
constructor({ assignedSegments, colorMap, nodes, }: {
|
|
697
|
+
assignedSegments: NodePortSegment[];
|
|
698
|
+
colorMap?: Record<string, string>;
|
|
699
|
+
/**
|
|
700
|
+
* This isn't used by the algorithm, but allows associating metadata
|
|
701
|
+
* for the result datatype (the center, width, height of the node)
|
|
702
|
+
*/
|
|
703
|
+
nodes: CapacityMeshNode[];
|
|
704
|
+
});
|
|
705
|
+
random(): number;
|
|
706
|
+
/**
|
|
707
|
+
* The cost is the "probability of failure" of the node.
|
|
708
|
+
*/
|
|
709
|
+
computeNodeCost(nodeId: CapacityMeshNodeId): number;
|
|
710
|
+
/**
|
|
711
|
+
* Number of traces that can go through this node if they are completely
|
|
712
|
+
* straight without crossings
|
|
713
|
+
*/
|
|
714
|
+
getUsedTraceCapacity(nodeId: CapacityMeshNodeId): number;
|
|
715
|
+
/**
|
|
716
|
+
* Granular via capacity is a consideration of capacity that includes...
|
|
717
|
+
* - The number of traces
|
|
718
|
+
* - The number of trace crossings (0-2 vias per trace crossing)
|
|
719
|
+
* - Empirically, each crossing typically results in 0.82 vias
|
|
720
|
+
* - e.g. 17 traces would typically have 51 crossings & 42 vias
|
|
721
|
+
* - The number of layer changes (at least 1 via per layer change)
|
|
722
|
+
* - We don't know how a entry/exit being on separated layers effects
|
|
723
|
+
* the capacity/number of vias yet
|
|
724
|
+
*
|
|
725
|
+
* - Generally minimizing the number of crossings is pretty good, if there
|
|
726
|
+
* is no trace crossing you basically don't have any used capacity
|
|
727
|
+
* - If the entry/exit layer is different, you're guaranteed to have at least
|
|
728
|
+
* one via
|
|
729
|
+
*
|
|
730
|
+
* - Total capacity is computed by estimating the number of vias that could
|
|
731
|
+
* be created using the formula (viaFitAcross / 2) ** 1.1
|
|
732
|
+
*/
|
|
733
|
+
getUsedViaCapacity(nodeId: CapacityMeshNodeId): number;
|
|
734
|
+
getRandomWeightedNodeId(): CapacityMeshNodeId;
|
|
735
|
+
getRandomWeightedSegmentId(): string;
|
|
736
|
+
getMutableSegments(): Set<string>;
|
|
737
|
+
isSegmentMutable(segmentId: string): boolean;
|
|
738
|
+
getRandomOperationForSegment(randomSegmentId: string): SwitchOperation | ChangeLayerOperation | null;
|
|
739
|
+
getNodesNearNode(nodeId: CapacityMeshNodeId, hops?: number): CapacityMeshNodeId[];
|
|
740
|
+
getRandomCombinedOperationNearNode(nodeId: CapacityMeshNodeId): CombinedOperation;
|
|
741
|
+
/**
|
|
742
|
+
* A combined operation can perform multiple operations on a single node, this
|
|
743
|
+
* allows it to reach outcomes that may not be beneficial with since
|
|
744
|
+
* operations
|
|
745
|
+
*/
|
|
746
|
+
getRandomCombinedOperationOnSingleNode(max?: number): CombinedOperation;
|
|
747
|
+
getRandomOperation(): Operation;
|
|
748
|
+
/**
|
|
749
|
+
* We compute "overall probability of failure" as our overall cost, then
|
|
750
|
+
* linearize it to make it easier to work with
|
|
751
|
+
*/
|
|
752
|
+
computeCurrentCost(): {
|
|
753
|
+
cost: number;
|
|
754
|
+
nodeCosts: Map<CapacityMeshNodeId, number>;
|
|
755
|
+
probabilityOfFailure: number;
|
|
756
|
+
linearizedCost: number;
|
|
757
|
+
};
|
|
758
|
+
applyOperation(op: Operation): void;
|
|
759
|
+
reverseOperation(op: Operation): void;
|
|
760
|
+
isNewCostAcceptable(oldPf: number, newPf: number): boolean;
|
|
761
|
+
/**
|
|
762
|
+
* FOR OUTPUT: Return the assigned points for each segment.
|
|
763
|
+
*/
|
|
764
|
+
getNodesWithPortPoints(): NodeWithPortPoints[];
|
|
765
|
+
_step(): void;
|
|
766
|
+
visualize(): GraphicsObject;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
interface CapacityMeshSolverOptions {
|
|
770
|
+
capacityDepth?: number;
|
|
771
|
+
targetMinCapacity?: number;
|
|
772
|
+
}
|
|
773
|
+
declare class CapacityMeshSolver extends BaseSolver {
|
|
774
|
+
srj: SimpleRouteJson;
|
|
775
|
+
opts: CapacityMeshSolverOptions;
|
|
776
|
+
nodeSolver: CapacityMeshNodeSolver;
|
|
777
|
+
nodeTargetMerger?: CapacityNodeTargetMerger;
|
|
778
|
+
edgeSolver?: CapacityMeshEdgeSolver;
|
|
779
|
+
pathingSolver?: CapacityPathingSolver;
|
|
780
|
+
edgeToPortSegmentSolver?: CapacityEdgeToPortSegmentSolver;
|
|
781
|
+
colorMap: Record<string, string>;
|
|
782
|
+
segmentToPointSolver?: CapacitySegmentToPointSolver;
|
|
783
|
+
segmentToPointOptimizer?: CapacitySegmentPointOptimizer;
|
|
784
|
+
highDensityRouteSolver?: HighDensityRouteSolver;
|
|
785
|
+
activeSolver?: BaseSolver | null;
|
|
786
|
+
connMap: ConnectivityMap;
|
|
787
|
+
constructor(srj: SimpleRouteJson, opts?: CapacityMeshSolverOptions);
|
|
788
|
+
_step(): void;
|
|
789
|
+
visualize(): GraphicsObject;
|
|
790
|
+
/**
|
|
791
|
+
* Simplifies a route by merging consecutive points along the same line
|
|
792
|
+
*/
|
|
793
|
+
private simplifyRoute;
|
|
794
|
+
/**
|
|
795
|
+
* Returns the SimpleRouteJson with routes converted to SimplifiedPcbTraces
|
|
796
|
+
*/
|
|
797
|
+
getOutputSimpleRouteJson(): SimpleRouteJson;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Calculate the capacity of a node based on its width
|
|
802
|
+
* @param nodeOrWidth The node or width to calculate capacity for
|
|
803
|
+
* @param maxCapacityFactor Optional multiplier to adjust capacity
|
|
804
|
+
* @returns The calculated capacity
|
|
805
|
+
*/
|
|
806
|
+
declare const getTunedTotalCapacity1: (nodeOrWidth: CapacityMeshNode | {
|
|
807
|
+
width: number;
|
|
808
|
+
}, maxCapacityFactor?: number) => number;
|
|
809
|
+
/**
|
|
810
|
+
* Calculate the optimal subdivision depth to reach a target minimum capacity
|
|
811
|
+
* @param initialWidth The initial width of the top-level node
|
|
812
|
+
* @param targetMinCapacity The minimum capacity target (default 0.5)
|
|
813
|
+
* @param maxDepth Maximum allowed depth (default 10)
|
|
814
|
+
* @returns The optimal capacity depth
|
|
815
|
+
*/
|
|
816
|
+
declare const calculateOptimalCapacityDepth: (initialWidth: number, targetMinCapacity?: number, maxDepth?: number) => number;
|
|
817
|
+
|
|
818
|
+
export { CapacityMeshSolver, calculateOptimalCapacityDepth, getTunedTotalCapacity1 };
|