@tensor-cad/engine 0.1.0

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/types.d.ts ADDED
@@ -0,0 +1,782 @@
1
+ /**
2
+ * What the engine's JSON means.
3
+ *
4
+ * These are a description of the wire, not a second model of the domain: each
5
+ * one names a shape the Go engine marshals, and nothing here computes. The Go
6
+ * side is where a field's meaning is decided; this is how TypeScript reads it.
7
+ */
8
+ export declare const DOC_VERSION = 1;
9
+ /** Symbols that stay indeterminate through shape checking. */
10
+ export declare const RUNTIME_SYMBOLS: readonly ["B", "T"];
11
+ /** The generated entry and exit nodes of a container's subgraph. */
12
+ export declare const BOUNDARY_IN = "_in";
13
+ export declare const BOUNDARY_OUT = "_out";
14
+ /** A parameter as the document writes it: a number, a flag, or an expression. */
15
+ export type ParamValue = number | string | boolean | null | ParamObject | ParamValue[];
16
+ export interface ParamObject {
17
+ [key: string]: ParamValue;
18
+ }
19
+ /**
20
+ * A symbol, in any of the four spellings a document uses: a bare number, a bare
21
+ * expression, or an object tagged "runtime" or "design".
22
+ */
23
+ export type SymbolDef = number | string | {
24
+ kind: "runtime";
25
+ default?: number;
26
+ doc?: string;
27
+ } | {
28
+ kind: "design";
29
+ value: number | string;
30
+ doc?: string;
31
+ };
32
+ /** One block in a graph. */
33
+ export interface NodeDef {
34
+ id: string;
35
+ type: string;
36
+ params?: Record<string, ParamValue>;
37
+ /** The subgraph of a container such as `repeat`. */
38
+ graph?: Graph;
39
+ /** Named subgraph alternatives, for hybrid repeat patterns. */
40
+ variants?: Record<string, Graph>;
41
+ /** Free text shown on the canvas instead of the id. */
42
+ label?: string;
43
+ }
44
+ /** An edge, `"nodeId:portName"` on both ends. */
45
+ export type Edge = [from: string, to: string];
46
+ export interface Graph {
47
+ nodes: NodeDef[];
48
+ edges: Edge[];
49
+ }
50
+ /** The reference numbers a preset is checked against. */
51
+ export interface Published {
52
+ params?: number;
53
+ activeParams?: number;
54
+ kvBytesPerToken?: number;
55
+ source?: string;
56
+ /**
57
+ * Allowed relative difference, defaulting to 0.5%. Set wider only where the
58
+ * published figure is itself a rounded headline number.
59
+ */
60
+ tolerance?: number;
61
+ }
62
+ export interface DocMeta {
63
+ name: string;
64
+ family?: string;
65
+ notes?: string;
66
+ published?: Published;
67
+ }
68
+ /** The editor's view of a document, carried along with it. */
69
+ export interface UiState {
70
+ positions?: Record<string, [number, number]>;
71
+ collapsed?: string[];
72
+ }
73
+ /** A design. */
74
+ /** One named set of symbol values. */
75
+ export interface Configuration {
76
+ doc?: string;
77
+ /**
78
+ * Overrides the document's own symbols, by name. A symbol it does not
79
+ * mention keeps whatever the design says, so an expression over one that is
80
+ * overridden follows it.
81
+ */
82
+ symbols: Record<string, SymbolDef>;
83
+ }
84
+ export interface Doc {
85
+ version: number;
86
+ meta: DocMeta;
87
+ symbols: Record<string, SymbolDef>;
88
+ graph: Graph;
89
+ /**
90
+ * What this design has decided the design rules mean to it, keyed by rule id.
91
+ *
92
+ * A rule that is right in general is sometimes wrong here, and the
93
+ * alternative to recording that is people learning to read past a warning.
94
+ * It lives in the document because it is a decision about the design, so it
95
+ * travels with the file and shows up in review. Suppression is never silent:
96
+ * `ValidationReport.overridden` says what it did.
97
+ */
98
+ rules?: Record<string, RuleSeverity>;
99
+ /**
100
+ * Named sets of symbol values this design can be built at.
101
+ *
102
+ * Four GPT-2 presets are the same architecture at four sizes, and holding
103
+ * them apart means an architectural change has to be made four times. A
104
+ * configuration overrides symbols and nothing else: a variant that changed
105
+ * the graph would be a different design.
106
+ */
107
+ configurations?: Record<string, Configuration>;
108
+ /**
109
+ * The configuration in force. Absent or unknown means the symbols as
110
+ * written, which is what a design without configurations always has.
111
+ *
112
+ * In the document rather than in the editor, because it changes what the
113
+ * design *is*. The operating point is editor state for the opposite reason:
114
+ * it only changes what the design is measured under.
115
+ */
116
+ active?: string;
117
+ /** Blocks this design defines for itself, keyed by type name. */
118
+ defs?: Record<string, UserBlockDef>;
119
+ ui?: UiState;
120
+ }
121
+ /** What a document may ask a rule to be. `off` drops its findings. */
122
+ export type RuleSeverity = Severity | "off";
123
+ /** A composite a design defines for itself, written as data. */
124
+ export interface UserBlockDef {
125
+ type?: string;
126
+ category?: string;
127
+ params?: Record<string, ParamSpec>;
128
+ ports: {
129
+ in: Record<string, string | PortSpec>;
130
+ out: Record<string, string | PortSpec>;
131
+ };
132
+ graph: Graph;
133
+ docs?: BlockDocs;
134
+ }
135
+ export type ParamKind = "int" | "num" | "bool" | "enum" | "str" | "pattern" | "obj";
136
+ /** One declared parameter of a block. */
137
+ export interface ParamSpec {
138
+ type: ParamKind;
139
+ default?: ParamValue;
140
+ min?: number;
141
+ max?: number;
142
+ /** The permitted strings of an enum. */
143
+ values?: string[];
144
+ doc?: string;
145
+ /**
146
+ * The heading this field belongs under, for a block with enough parameters
147
+ * that one list is unreadable. Absent puts it with the rest.
148
+ */
149
+ group?: string;
150
+ /**
151
+ * The condition under which this parameter means anything.
152
+ *
153
+ * A dense block has no `expert_hidden`, grouped-query attention has no
154
+ * `kv_lora`, an RMSNorm has no bias. The block carries a value either way —
155
+ * this is what lets a panel say so rather than showing them all alike.
156
+ */
157
+ when?: ParamWhen;
158
+ }
159
+ /** One parameter's value deciding whether another is meaningful. */
160
+ export interface ParamWhen {
161
+ /** The other parameter to look at. */
162
+ param: string;
163
+ /** The values of it under which this parameter is meaningful. */
164
+ is: string[];
165
+ }
166
+ /** What a pin declares. See docs/reference/ports.md. */
167
+ export interface PortSpec {
168
+ shape: string;
169
+ /** What the tensor carries; "inherit" takes it from the producer. */
170
+ dtype?: string;
171
+ /** A port that may legitimately dangle. */
172
+ optional?: boolean;
173
+ /** "flow" or "side": which edge of the symbol a wire leaves by. */
174
+ anchor?: "flow" | "side";
175
+ showName?: boolean;
176
+ doc?: string;
177
+ }
178
+ export interface BlockDocs {
179
+ summary?: string;
180
+ formula?: string;
181
+ refs?: string[];
182
+ }
183
+ /**
184
+ * One block, as the palette and the inspector need it.
185
+ *
186
+ * Parameters by name with the order beside them: a panel looks one up far more
187
+ * often than it walks them all, and a Go map has no order to inherit.
188
+ */
189
+ export interface CatalogEntry {
190
+ type: string;
191
+ kind: "primitive" | "composite" | "container";
192
+ category: string;
193
+ docs: BlockDocs;
194
+ params: Record<string, ParamSpec>;
195
+ /** The order the block declares them in, which is how they are laid out. */
196
+ paramOrder: string[];
197
+ /**
198
+ * The pins declared before any parameter is known. A block whose pins depend
199
+ * on its parameters reports none here; ask the analysis for those.
200
+ */
201
+ ports: {
202
+ in: Record<string, string>;
203
+ out: Record<string, string>;
204
+ };
205
+ }
206
+ export type Dtype = "fp32" | "bf16" | "fp16" | "fp8";
207
+ export type OptimizerKind = "adamw" | "adamw8bit" | "muon" | "sgd_momentum" | "sgd" | "bf16_adam";
208
+ export type Recompute = "none" | "selective" | "full";
209
+ /** How the model is spread over the devices. */
210
+ export interface ParallelPlan {
211
+ dp: number;
212
+ tp: number;
213
+ pp: number;
214
+ ep: number;
215
+ /** ZeRO/FSDP stage, 0 to 3. */
216
+ zero: 0 | 1 | 2 | 3;
217
+ /** Shard activations along the sequence across the tensor-parallel group. */
218
+ sequenceParallel: boolean;
219
+ }
220
+ export declare const DEFAULT_PARALLEL: ParallelPlan;
221
+ export declare const DEFAULT_HARDWARE = "h100-sxm";
222
+ export declare const DTYPE_BYTES: Record<Dtype, number>;
223
+ /**
224
+ * The conditions a design is measured under.
225
+ *
226
+ * Not properties of the design: batch, sequence length, dtype, device and
227
+ * sharding belong to the question, not to the model.
228
+ */
229
+ export interface AnalysisOptions {
230
+ T?: number;
231
+ B?: number;
232
+ dtype?: Dtype;
233
+ inferenceDtype?: Dtype;
234
+ kvDtype?: Dtype;
235
+ /** A profile id from `hardware()`. */
236
+ hardware?: string;
237
+ gpus?: number;
238
+ parallel?: Partial<ParallelPlan>;
239
+ optimizer?: OptimizerKind;
240
+ recompute?: Recompute;
241
+ /** Assume a memory-efficient attention kernel. */
242
+ flash?: boolean;
243
+ tokens?: number;
244
+ mfu?: number;
245
+ decodeEfficiency?: number;
246
+ concurrency?: number;
247
+ }
248
+ export interface HardwareProfile {
249
+ id: string;
250
+ name: string;
251
+ peakBf16: number;
252
+ peakFp8: number;
253
+ memory: number;
254
+ bandwidth: number;
255
+ pricePerHour: number;
256
+ mfuHint: [low: number, high: number];
257
+ notes?: string;
258
+ }
259
+ export interface SymbolTable {
260
+ order: string[];
261
+ values: Record<string, number>;
262
+ /** Concrete design symbols only; runtime symbols excluded. */
263
+ designValues: Record<string, number>;
264
+ docs: Record<string, string>;
265
+ errors: string[];
266
+ }
267
+ export interface ParamsResult {
268
+ total: number;
269
+ /** Weights a single token uses. Differs from total only for a mixture. */
270
+ active: number;
271
+ embedding: number;
272
+ head: number;
273
+ nonEmbedding: number;
274
+ /** The N in the 2N rule. */
275
+ nonEmbeddingActive: number;
276
+ byPath: Record<string, number>;
277
+ byCategory: Record<string, number>;
278
+ byType: Record<string, number>;
279
+ errors: string[];
280
+ }
281
+ export interface FlopsResult {
282
+ fwdDense: number;
283
+ fwdAttention: number;
284
+ /** The attention term as a profiler counts it, with nothing masked. */
285
+ fwdAttentionUnmasked: number;
286
+ fwdTotal: number;
287
+ fwdTotalUnmasked: number;
288
+ /** Norms, activations, RoPE and adds: memory-bound, excluded above. */
289
+ elementwise: number;
290
+ trainPerToken: number;
291
+ attentionShare: number;
292
+ ruleOfThumb2N: number;
293
+ ruleOfThumb6N: number;
294
+ byPath: Record<string, number>;
295
+ byCategory: Record<string, number>;
296
+ errors: string[];
297
+ }
298
+ export interface KvResult {
299
+ bytesPerToken: number;
300
+ bytesPerSequenceFixed: number;
301
+ /**
302
+ * The same cache under an engine that does not absorb the weights latent
303
+ * attention compressed against. Equal to `bytesPerToken` for every design
304
+ * that has no latent attention in it; 57x it for DeepSeek-V3.
305
+ */
306
+ bytesPerTokenDecompressed: number;
307
+ byPath: Record<string, number>;
308
+ errors: string[];
309
+ }
310
+ export interface MemoryResult {
311
+ weightsBytes: number;
312
+ train: {
313
+ weights: number;
314
+ grads: number;
315
+ optimizer: number;
316
+ activations: number;
317
+ /** The part of `activations` that is the vocabulary logits. */
318
+ logits: number;
319
+ total: number;
320
+ perGpu: TrainPerGpu;
321
+ activationsByPath: Record<string, number>;
322
+ /**
323
+ * The same bytes charged to the tensor rather than to the block that
324
+ * produced it, keyed `"path:port"`.
325
+ *
326
+ * Not a reformatting of the line above. They agree row for row in a plain
327
+ * transformer, where every block that holds an activation holds exactly
328
+ * one; they diverge wherever a block fans out. Nemotron-H's `split` holds
329
+ * three tensors from 2 MiB to 167 MiB, and one number for the block
330
+ * answers neither which of them is the big one nor what dropping one would
331
+ * save.
332
+ */
333
+ activationsByTensor: Record<string, number>;
334
+ };
335
+ infer: {
336
+ weights: number;
337
+ kv: number;
338
+ overhead: number;
339
+ total: number;
340
+ };
341
+ optimizerLabel: string;
342
+ notes: string[];
343
+ errors: string[];
344
+ }
345
+ export interface ThroughputResult {
346
+ /** FLOP per byte above which the device is compute-bound. */
347
+ ridgePoint: number;
348
+ decodeBytesPerStep: number;
349
+ /**
350
+ * The weights of that, which for a mixture of experts is neither the active
351
+ * count nor the resident one: a batch reads the union of what its tokens
352
+ * routed to, and that reaches nearly every expert well before the batch
353
+ * reaches the expert count.
354
+ */
355
+ decodeWeightBytes: number;
356
+ /** Every weight the device holds, whether or not a given step reads it. */
357
+ residentWeightBytes: number;
358
+ decodeFlopsPerStep: number;
359
+ decodeSecondsPerStep: number;
360
+ decodeTokensPerSecond: number;
361
+ memoryBound: boolean;
362
+ prefillSeconds: number;
363
+ notes: string[];
364
+ }
365
+ export interface CostResult {
366
+ totalFlops: number;
367
+ gpuHours: number;
368
+ wallClockHours: number;
369
+ dollars: number;
370
+ tokens: number;
371
+ mfu: number;
372
+ }
373
+ export interface ChinchillaResult {
374
+ optimalTokens: number;
375
+ tokensPerParam: number;
376
+ /** The meaningful ratio for a sparse model. */
377
+ tokensPerActiveParam: number;
378
+ overTrainingRatio: number;
379
+ predictedLoss: Record<string, number>;
380
+ verdict: string;
381
+ }
382
+ /** The operating point with every default filled in. */
383
+ export interface ResolvedAnalysisOptions {
384
+ T: number;
385
+ B: number;
386
+ dtype: Dtype;
387
+ inferenceDtype: Dtype;
388
+ kvDtype: Dtype;
389
+ hardware: HardwareProfile;
390
+ gpus: number;
391
+ parallel: ParallelPlan;
392
+ optimizer: OptimizerKind;
393
+ recompute: Recompute;
394
+ flash: boolean;
395
+ tokens: number;
396
+ tokensWereDefaulted: boolean;
397
+ mfu: number;
398
+ decodeEfficiency: number;
399
+ concurrency: number;
400
+ }
401
+ export interface AnalysisResult {
402
+ name: string;
403
+ options: ResolvedAnalysisOptions;
404
+ symbols: SymbolTable;
405
+ params: ParamsResult;
406
+ flops: FlopsResult;
407
+ kv: KvResult;
408
+ memory: MemoryResult;
409
+ throughput: ThroughputResult;
410
+ cost: CostResult;
411
+ chinchilla: ChinchillaResult;
412
+ errors: string[];
413
+ }
414
+ export type Severity = "error" | "warning" | "info";
415
+ export interface Finding {
416
+ /** Stable rule identifier, e.g. "flash-head-dim". */
417
+ rule: string;
418
+ severity: Severity;
419
+ path?: string;
420
+ port?: string;
421
+ /** The parameter that caused it, so the inspector can point at the field. */
422
+ param?: string;
423
+ message: string;
424
+ hint?: string;
425
+ }
426
+ export interface ValidationReport {
427
+ name: string;
428
+ findings: Finding[];
429
+ counts: Record<Severity, number>;
430
+ /** True when nothing blocks building this design. */
431
+ ok: boolean;
432
+ analysis: AnalysisResult;
433
+ /**
434
+ * What the document's own severities did, so suppression is never silent: a
435
+ * design cannot drop a finding without the report saying which and from what.
436
+ */
437
+ overridden: RuleOverride[];
438
+ }
439
+ /** One finding whose severity the document changed. */
440
+ export interface RuleOverride {
441
+ rule: string;
442
+ path?: string;
443
+ /** What the rule produced, and what the document asked for. */
444
+ from: Severity;
445
+ /** `off` means the finding was dropped. An unreadable value arrives as `?x`. */
446
+ to: string;
447
+ }
448
+ export interface ExplainedParam {
449
+ /** The expression as written, when it was an expression. */
450
+ expression?: string;
451
+ value: unknown;
452
+ doc?: string;
453
+ }
454
+ export interface Explanation {
455
+ path: string;
456
+ type: string;
457
+ kind: "primitive" | "composite" | "container";
458
+ label?: string;
459
+ docs: BlockDocs;
460
+ /** How many copies exist, and how many a token passes through. */
461
+ copies: {
462
+ total: number;
463
+ active: number;
464
+ };
465
+ params: Record<string, ExplainedParam>;
466
+ /** The order the block declares its parameters in. */
467
+ paramOrder: string[];
468
+ shapes: {
469
+ in: Record<string, string>;
470
+ out: Record<string, string>;
471
+ };
472
+ contributes: {
473
+ params: number;
474
+ activeParams: number;
475
+ shareOfParams: number;
476
+ flopsPerToken: number;
477
+ shareOfFlops: number;
478
+ activationBytes: number;
479
+ cacheBytesPerToken: number;
480
+ cacheBytesPerSequence: number;
481
+ };
482
+ /** The primitives this block expands into, largest first. */
483
+ breakdown: {
484
+ path: string;
485
+ type: string;
486
+ params: number;
487
+ }[];
488
+ notFound?: boolean;
489
+ }
490
+ export interface TorchOptions {
491
+ className?: string;
492
+ includeSmokeTest?: boolean;
493
+ /**
494
+ * How a mixture-of-experts layer routes. "sparse" is faster but cannot be
495
+ * traced by `torch.export`; "dense" computes the same thing at
496
+ * `experts / top_k` times the cost and traces cleanly.
497
+ */
498
+ moeDispatch?: "sparse" | "dense";
499
+ /** 0 leaves PyTorch's own initialization alone. */
500
+ initStd?: number;
501
+ }
502
+ export interface GeneratedFile {
503
+ path: string;
504
+ contents: string;
505
+ }
506
+ export interface GeneratedCode {
507
+ files: GeneratedFile[];
508
+ warnings: string[];
509
+ }
510
+ export interface ScaleOptions {
511
+ targetParams: number;
512
+ widthSymbols?: string[];
513
+ depthSymbols?: string[];
514
+ widthMultiple?: number;
515
+ vocab?: number;
516
+ /** Whether `targetParams` counts the embedding tables. */
517
+ targetBasis?: "total" | "non-embedding";
518
+ tieHead?: boolean;
519
+ minHeads?: number;
520
+ keepDepth?: boolean;
521
+ maxIterations?: number;
522
+ }
523
+ /** The training footprint on one device. */
524
+ export interface TrainPerGpu {
525
+ weights: number;
526
+ grads: number;
527
+ optimizer: number;
528
+ activations: number;
529
+ total: number;
530
+ }
531
+ /** One named value that moved between two designs. */
532
+ export interface DiffChange {
533
+ name: string;
534
+ from?: unknown;
535
+ to?: unknown;
536
+ }
537
+ /** A block as it stands in one of the two designs. */
538
+ export interface DiffBlock {
539
+ path: string;
540
+ type: string;
541
+ label?: string;
542
+ params: Record<string, ParamValue>;
543
+ }
544
+ /** One parameter that moved on a block that exists in both. */
545
+ export interface DiffParamChange {
546
+ key: string;
547
+ from?: ParamValue;
548
+ to?: ParamValue;
549
+ }
550
+ export interface DiffBlockChange {
551
+ path: string;
552
+ /** Set when the block became a different kind of block. */
553
+ type?: DiffChange;
554
+ label?: DiffChange;
555
+ params: DiffParamChange[];
556
+ }
557
+ export interface DiffEdge {
558
+ /** The graph the wire sits in; `<root>` is the top level. */
559
+ graph: string;
560
+ from: string;
561
+ to: string;
562
+ }
563
+ /** One number that moved. */
564
+ export interface DiffDelta {
565
+ metric: string;
566
+ a: number;
567
+ b: number;
568
+ delta: number;
569
+ /** Null when `a` is zero, because the ratio says nothing then. */
570
+ ratio: number | null;
571
+ }
572
+ /**
573
+ * What changed between two designs.
574
+ *
575
+ * Structure and numbers together, because either alone is misleading: that `F`
576
+ * went from 11008 to 14336 does not tell you the model grew by 1.3B
577
+ * parameters, and that it grew by 1.3B does not tell you where.
578
+ */
579
+ export interface DesignDiff {
580
+ a: string;
581
+ b: string;
582
+ symbols: {
583
+ added: DiffChange[];
584
+ removed: DiffChange[];
585
+ changed: DiffChange[];
586
+ };
587
+ blocks: {
588
+ added: DiffBlock[];
589
+ removed: DiffBlock[];
590
+ changed: DiffBlockChange[];
591
+ };
592
+ edges: {
593
+ added: DiffEdge[];
594
+ removed: DiffEdge[];
595
+ };
596
+ metrics: DiffDelta[];
597
+ /** The operating point both sides were measured under. */
598
+ at: {
599
+ T: number;
600
+ B: number;
601
+ hardware: string;
602
+ };
603
+ /**
604
+ * True when nothing structural moved. The numbers may still differ, because
605
+ * they are measured at an operating point.
606
+ */
607
+ identical: boolean;
608
+ }
609
+ /** The cluster a design is being fitted to. */
610
+ export interface ClusterRequest {
611
+ /** How many devices there are. */
612
+ gpus: number;
613
+ /**
614
+ * Bounds the tensor-parallel degree: splitting a matrix across a slower link
615
+ * than NVLink is rarely worth it. Defaults to 8.
616
+ */
617
+ gpusPerNode?: number;
618
+ /**
619
+ * The fraction of device memory left free for fragmentation, the allocator
620
+ * and the communication buffers. Defaults to 0.1.
621
+ */
622
+ headroom?: number;
623
+ /** Micro-batch sizes to try. Defaults to the one the analysis options give. */
624
+ microBatch?: number[];
625
+ /** Recompute settings to try. Defaults to all three. */
626
+ recompute?: Recompute[];
627
+ /** How many plans to return. Defaults to 8. */
628
+ limit?: number;
629
+ }
630
+ /** One way of splitting the work, and what it costs to hold. */
631
+ export interface ClusterPlan {
632
+ parallel: ParallelPlan;
633
+ recompute: Recompute;
634
+ microBatch: number;
635
+ perGpu: TrainPerGpu;
636
+ /** The fraction of the budget this plan takes; over 1 does not fit. */
637
+ used: number;
638
+ /** The plan as a person would say it: "DP 8 x TP 2, ZeRO-1". */
639
+ summary: string;
640
+ /** What this plan asks of whoever runs it. */
641
+ notes: string[];
642
+ }
643
+ /** Every plan that fits, least demanding first. */
644
+ export interface ClusterResult {
645
+ fits: ClusterPlan[];
646
+ /** The nearest miss, when nothing fits. */
647
+ closest?: ClusterPlan;
648
+ /** How many combinations were priced. */
649
+ considered: number;
650
+ /** Bytes each device may use, after headroom. */
651
+ budget: number;
652
+ /** The device's own memory, before headroom. */
653
+ memory: number;
654
+ hardware: string;
655
+ notes: string[];
656
+ }
657
+ export interface ScaleResult {
658
+ doc: Doc;
659
+ achieved: number;
660
+ target: number;
661
+ changes: Record<string, {
662
+ from: number;
663
+ to: number;
664
+ }>;
665
+ notes: string[];
666
+ }
667
+ /** Which row of Tensor Programs V's Table 3 a weight belongs to. */
668
+ export type MupClass = "input" | "hidden" | "output";
669
+ /** What to multiply one class's settings by, against the base rung. */
670
+ export interface MupScaling {
671
+ class: MupClass;
672
+ /** Multiplies the base model's initialization standard deviation. */
673
+ initStd: number;
674
+ /** Multiplies the base model's learning rate. */
675
+ adamLr: number;
676
+ /** The blocks in this class, so the grouping can be checked against the design. */
677
+ paths: string[];
678
+ why: string;
679
+ }
680
+ /** One model in the ladder. */
681
+ export interface MupRung {
682
+ /** What the width came out as: a width is held to a whole number of heads. */
683
+ width: number;
684
+ /** `width` over the base width: the m every rule is written in. */
685
+ multiplier: number;
686
+ heads: number;
687
+ params: number;
688
+ doc: Doc;
689
+ /** The rung the hyperparameters are tuned at, where the multiplier is 1. */
690
+ base: boolean;
691
+ scaling: MupScaling[];
692
+ notes: string[];
693
+ }
694
+ export interface MupLadder {
695
+ /** What the ladder moved, normally D. */
696
+ widthSymbol: string;
697
+ baseWidth: number;
698
+ /** What was held fixed while the width moved. */
699
+ headDim: number;
700
+ rungs: MupRung[];
701
+ notes: string[];
702
+ }
703
+ export interface MupOptions {
704
+ /** The rungs. Empty halves the design's own width down to a width worth sweeping at. */
705
+ widths?: number[];
706
+ /** The width the sweep happens at. Omitted takes the narrowest rung. */
707
+ baseWidth?: number;
708
+ /** Symbols that move with the width beyond D. Omitted takes the same set scaling uses. */
709
+ widthSymbols?: string[];
710
+ }
711
+ export interface ImportResult {
712
+ doc: Doc;
713
+ /** What the import could not represent faithfully. */
714
+ warnings: string[];
715
+ }
716
+ /**
717
+ * One tensor shape, in both the forms the editor shows.
718
+ *
719
+ * Symbolic is the honest one: `B T D` says the residual stream is D wide
720
+ * whatever D is. Numeric substitutes the design symbols and leaves the runtime
721
+ * ones alone, which is the quickest way to watch a symbol edit travel through a
722
+ * design. Both come from the engine, because only it holds the polynomial.
723
+ */
724
+ export interface Shape {
725
+ symbolic: string;
726
+ numeric: string;
727
+ }
728
+ /** One pin, as the canvas draws it. */
729
+ export interface ResolvedPort {
730
+ shape: string;
731
+ dtype: string;
732
+ anchor: "flow" | "side";
733
+ optional?: boolean;
734
+ showName?: boolean;
735
+ doc?: string;
736
+ }
737
+ export interface ResolvedPorts {
738
+ in: Record<string, ResolvedPort>;
739
+ out: Record<string, ResolvedPort>;
740
+ }
741
+ /** A node's parameters after evaluation. */
742
+ export interface Resolved {
743
+ type: string;
744
+ /** The concrete value of each parameter. */
745
+ p: Record<string, ParamValue>;
746
+ /** The symbolic form, so a width can be labelled "D" rather than 4096. */
747
+ s: Record<string, string>;
748
+ }
749
+ /** Something wrong with the wiring, addressed to a node. */
750
+ export interface InferIssue {
751
+ path: string;
752
+ port?: string;
753
+ message: string;
754
+ severity: "error" | "warning";
755
+ /** The block's own rule id, when the issue came from a block constraint. */
756
+ rule?: string;
757
+ param?: string;
758
+ }
759
+ /** Every shape in a design, keyed by `"path:port"`. */
760
+ export interface Inference {
761
+ outputs: Record<string, Shape>;
762
+ inputs: Record<string, Shape>;
763
+ /** Consumer `"path:port"` to producer `"path:port"`. */
764
+ producerOf: Record<string, string>;
765
+ ports: Record<string, ResolvedPorts>;
766
+ resolved: Record<string, Resolved>;
767
+ /**
768
+ * The subgraph each composite stood for, by path.
769
+ *
770
+ * The walk builds these anyway, so the editor draws the inside of a block
771
+ * from what the analysis already saw rather than expanding it a second time
772
+ * with its own copy of the rules.
773
+ */
774
+ expansions: Record<string, Graph>;
775
+ issues: InferIssue[];
776
+ }
777
+ /** Everything the editor needs for one document at one operating point. */
778
+ export interface Derived {
779
+ report: ValidationReport;
780
+ /** Shape inference with composites expanded, so interiors can be opened. */
781
+ infer: Inference;
782
+ }