@vessel-dsp/compiler 0.0.0-stage → 0.3.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.
Files changed (226) hide show
  1. package/README.md +118 -2
  2. package/dist/bake.d.ts +38 -0
  3. package/dist/bake.d.ts.map +1 -0
  4. package/dist/bake.js +101 -0
  5. package/dist/bake.js.map +1 -0
  6. package/dist/bbd-clock.d.ts +171 -0
  7. package/dist/bbd-clock.d.ts.map +1 -0
  8. package/dist/bbd-clock.js +1750 -0
  9. package/dist/bbd-clock.js.map +1 -0
  10. package/dist/block-row.d.ts +51 -0
  11. package/dist/block-row.d.ts.map +1 -0
  12. package/dist/block-row.js +17 -0
  13. package/dist/block-row.js.map +1 -0
  14. package/dist/bypass.d.ts +3 -0
  15. package/dist/bypass.d.ts.map +1 -0
  16. package/dist/bypass.js +228 -0
  17. package/dist/bypass.js.map +1 -0
  18. package/dist/compile.d.ts +24 -0
  19. package/dist/compile.d.ts.map +1 -0
  20. package/dist/compile.js +348 -0
  21. package/dist/compile.js.map +1 -0
  22. package/dist/converter-scale.d.ts +14 -0
  23. package/dist/converter-scale.d.ts.map +1 -0
  24. package/dist/converter-scale.js +133 -0
  25. package/dist/converter-scale.js.map +1 -0
  26. package/dist/couple.d.ts +28 -0
  27. package/dist/couple.d.ts.map +1 -0
  28. package/dist/couple.js +567 -0
  29. package/dist/couple.js.map +1 -0
  30. package/dist/dangling-active-terminal.d.ts +47 -0
  31. package/dist/dangling-active-terminal.d.ts.map +1 -0
  32. package/dist/dangling-active-terminal.js +542 -0
  33. package/dist/dangling-active-terminal.js.map +1 -0
  34. package/dist/declared-program.d.ts +23 -0
  35. package/dist/declared-program.d.ts.map +1 -0
  36. package/dist/declared-program.js +387 -0
  37. package/dist/declared-program.js.map +1 -0
  38. package/dist/denomination.d.ts +48 -0
  39. package/dist/denomination.d.ts.map +1 -0
  40. package/dist/denomination.js +27 -0
  41. package/dist/denomination.js.map +1 -0
  42. package/dist/device-laws.d.ts +237 -0
  43. package/dist/device-laws.d.ts.map +1 -0
  44. package/dist/device-laws.js +3513 -0
  45. package/dist/device-laws.js.map +1 -0
  46. package/dist/diagnostics.d.ts +13 -0
  47. package/dist/diagnostics.d.ts.map +1 -0
  48. package/dist/diagnostics.js +19 -0
  49. package/dist/diagnostics.js.map +1 -0
  50. package/dist/emit.d.ts +8 -0
  51. package/dist/emit.d.ts.map +1 -0
  52. package/dist/emit.js +43 -0
  53. package/dist/emit.js.map +1 -0
  54. package/dist/errors.d.ts +22 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/errors.js +39 -0
  57. package/dist/errors.js.map +1 -0
  58. package/dist/firmware-class.d.ts +69 -0
  59. package/dist/firmware-class.d.ts.map +1 -0
  60. package/dist/firmware-class.js +20 -0
  61. package/dist/firmware-class.js.map +1 -0
  62. package/dist/fixtures/circuits.d.ts +1742 -0
  63. package/dist/fixtures/circuits.d.ts.map +1 -0
  64. package/dist/fixtures/circuits.js +13896 -0
  65. package/dist/fixtures/circuits.js.map +1 -0
  66. package/dist/fixtures/expected.d.ts +261 -0
  67. package/dist/fixtures/expected.d.ts.map +1 -0
  68. package/dist/fixtures/expected.js +315 -0
  69. package/dist/fixtures/expected.js.map +1 -0
  70. package/dist/fixtures/index.d.ts +4 -0
  71. package/dist/fixtures/index.d.ts.map +1 -0
  72. package/dist/fixtures/index.js +8 -0
  73. package/dist/fixtures/index.js.map +1 -0
  74. package/dist/fixtures/registry.d.ts +52 -0
  75. package/dist/fixtures/registry.d.ts.map +1 -0
  76. package/dist/fixtures/registry.js +341 -0
  77. package/dist/fixtures/registry.js.map +1 -0
  78. package/dist/generic-tube-fit.d.ts +12 -0
  79. package/dist/generic-tube-fit.d.ts.map +1 -0
  80. package/dist/generic-tube-fit.js +45 -0
  81. package/dist/generic-tube-fit.js.map +1 -0
  82. package/dist/grounded-clock-supply.d.ts +13 -0
  83. package/dist/grounded-clock-supply.d.ts.map +1 -0
  84. package/dist/grounded-clock-supply.js +45 -0
  85. package/dist/grounded-clock-supply.js.map +1 -0
  86. package/dist/identify.d.ts +50 -0
  87. package/dist/identify.d.ts.map +1 -0
  88. package/dist/identify.js +319 -0
  89. package/dist/identify.js.map +1 -0
  90. package/dist/index.d.ts +10 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +19 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/inert-controls.d.ts +15 -0
  95. package/dist/inert-controls.d.ts.map +1 -0
  96. package/dist/inert-controls.js +266 -0
  97. package/dist/inert-controls.js.map +1 -0
  98. package/dist/latch-seed.d.ts +53 -0
  99. package/dist/latch-seed.d.ts.map +1 -0
  100. package/dist/latch-seed.js +257 -0
  101. package/dist/latch-seed.js.map +1 -0
  102. package/dist/link.d.ts +7 -0
  103. package/dist/link.d.ts.map +1 -0
  104. package/dist/link.js +270 -0
  105. package/dist/link.js.map +1 -0
  106. package/dist/lower.d.ts +79 -0
  107. package/dist/lower.d.ts.map +1 -0
  108. package/dist/lower.js +1855 -0
  109. package/dist/lower.js.map +1 -0
  110. package/dist/netlist.d.ts +79 -0
  111. package/dist/netlist.d.ts.map +1 -0
  112. package/dist/netlist.js +4746 -0
  113. package/dist/netlist.js.map +1 -0
  114. package/dist/non-executable-clock-drivers.d.ts +8 -0
  115. package/dist/non-executable-clock-drivers.d.ts.map +1 -0
  116. package/dist/non-executable-clock-drivers.js +33 -0
  117. package/dist/non-executable-clock-drivers.js.map +1 -0
  118. package/dist/open-category.d.ts +98 -0
  119. package/dist/open-category.d.ts.map +1 -0
  120. package/dist/open-category.js +111 -0
  121. package/dist/open-category.js.map +1 -0
  122. package/dist/over-driven-node.d.ts +33 -0
  123. package/dist/over-driven-node.d.ts.map +1 -0
  124. package/dist/over-driven-node.js +188 -0
  125. package/dist/over-driven-node.js.map +1 -0
  126. package/dist/part-catalog.d.ts +15 -0
  127. package/dist/part-catalog.d.ts.map +1 -0
  128. package/dist/part-catalog.js +6712 -0
  129. package/dist/part-catalog.js.map +1 -0
  130. package/dist/part-number.d.ts +32 -0
  131. package/dist/part-number.d.ts.map +1 -0
  132. package/dist/part-number.js +80 -0
  133. package/dist/part-number.js.map +1 -0
  134. package/dist/partition.d.ts +7 -0
  135. package/dist/partition.d.ts.map +1 -0
  136. package/dist/partition.js +242 -0
  137. package/dist/partition.js.map +1 -0
  138. package/dist/port-full-scale.d.ts +70 -0
  139. package/dist/port-full-scale.d.ts.map +1 -0
  140. package/dist/port-full-scale.js +235 -0
  141. package/dist/port-full-scale.js.map +1 -0
  142. package/dist/pot-orientation.d.ts +114 -0
  143. package/dist/pot-orientation.d.ts.map +1 -0
  144. package/dist/pot-orientation.js +551 -0
  145. package/dist/pot-orientation.js.map +1 -0
  146. package/dist/power-domain-control.d.ts +40 -0
  147. package/dist/power-domain-control.d.ts.map +1 -0
  148. package/dist/power-domain-control.js +142 -0
  149. package/dist/power-domain-control.js.map +1 -0
  150. package/dist/proxy-declaration.d.ts +121 -0
  151. package/dist/proxy-declaration.d.ts.map +1 -0
  152. package/dist/proxy-declaration.js +50 -0
  153. package/dist/proxy-declaration.js.map +1 -0
  154. package/dist/registry.d.ts +323 -0
  155. package/dist/registry.d.ts.map +1 -0
  156. package/dist/registry.js +192 -0
  157. package/dist/registry.js.map +1 -0
  158. package/dist/sparse-schedule.d.ts +65 -0
  159. package/dist/sparse-schedule.d.ts.map +1 -0
  160. package/dist/sparse-schedule.js +421 -0
  161. package/dist/sparse-schedule.js.map +1 -0
  162. package/dist/speaker-load.d.ts +38 -0
  163. package/dist/speaker-load.d.ts.map +1 -0
  164. package/dist/speaker-load.js +97 -0
  165. package/dist/speaker-load.js.map +1 -0
  166. package/dist/stage-coverage.d.ts +21 -0
  167. package/dist/stage-coverage.d.ts.map +1 -0
  168. package/dist/stage-coverage.js +124 -0
  169. package/dist/stage-coverage.js.map +1 -0
  170. package/dist/stamp-partition.d.ts +314 -0
  171. package/dist/stamp-partition.d.ts.map +1 -0
  172. package/dist/stamp-partition.js +472 -0
  173. package/dist/stamp-partition.js.map +1 -0
  174. package/dist/supply-reference.d.ts +19 -0
  175. package/dist/supply-reference.d.ts.map +1 -0
  176. package/dist/supply-reference.js +66 -0
  177. package/dist/supply-reference.js.map +1 -0
  178. package/dist/supply-short.d.ts +32 -0
  179. package/dist/supply-short.d.ts.map +1 -0
  180. package/dist/supply-short.js +118 -0
  181. package/dist/supply-short.js.map +1 -0
  182. package/dist/supply-stamps.d.ts +51 -0
  183. package/dist/supply-stamps.d.ts.map +1 -0
  184. package/dist/supply-stamps.js +363 -0
  185. package/dist/supply-stamps.js.map +1 -0
  186. package/dist/terminal-role.d.ts +109 -0
  187. package/dist/terminal-role.d.ts.map +1 -0
  188. package/dist/terminal-role.js +46 -0
  189. package/dist/terminal-role.js.map +1 -0
  190. package/dist/terminal-roles.d.ts +59 -0
  191. package/dist/terminal-roles.d.ts.map +1 -0
  192. package/dist/terminal-roles.js +92 -0
  193. package/dist/terminal-roles.js.map +1 -0
  194. package/dist/transformer.d.ts +181 -0
  195. package/dist/transformer.d.ts.map +1 -0
  196. package/dist/transformer.js +476 -0
  197. package/dist/transformer.js.map +1 -0
  198. package/dist/types.d.ts +3157 -0
  199. package/dist/types.d.ts.map +1 -0
  200. package/dist/types.js +11 -0
  201. package/dist/types.js.map +1 -0
  202. package/dist/unbounded-operating-point.d.ts +35 -0
  203. package/dist/unbounded-operating-point.d.ts.map +1 -0
  204. package/dist/unbounded-operating-point.js +181 -0
  205. package/dist/unbounded-operating-point.js.map +1 -0
  206. package/dist/unexecuted-region.d.ts +3 -0
  207. package/dist/unexecuted-region.d.ts.map +1 -0
  208. package/dist/unexecuted-region.js +122 -0
  209. package/dist/unexecuted-region.js.map +1 -0
  210. package/dist/unimplemented-control-role.d.ts +3 -0
  211. package/dist/unimplemented-control-role.d.ts.map +1 -0
  212. package/dist/unimplemented-control-role.js +61 -0
  213. package/dist/unimplemented-control-role.js.map +1 -0
  214. package/dist/unreachable-output.d.ts +3 -0
  215. package/dist/unreachable-output.d.ts.map +1 -0
  216. package/dist/unreachable-output.js +97 -0
  217. package/dist/unreachable-output.js.map +1 -0
  218. package/dist/unreadable-terminal-role.d.ts +67 -0
  219. package/dist/unreadable-terminal-role.d.ts.map +1 -0
  220. package/dist/unreadable-terminal-role.js +409 -0
  221. package/dist/unreadable-terminal-role.js.map +1 -0
  222. package/dist/unverified-pinout.d.ts +27 -0
  223. package/dist/unverified-pinout.d.ts.map +1 -0
  224. package/dist/unverified-pinout.js +121 -0
  225. package/dist/unverified-pinout.js.map +1 -0
  226. package/package.json +75 -5
@@ -0,0 +1,124 @@
1
+ // How far down the amplification chain this program's output already is.
2
+ //
3
+ // A chain cannot otherwise know. `mesa-boogie-mark-v` renders 11.7 V and `fender-5e3-deluxe-tweed`
4
+ // renders 7.08 V, and those numbers are not comparable: the first is a preamp monitor tap on a
5
+ // packet that declares no output transformer, the second is a speaker terminal with an 8 ohm load
6
+ // across it. For a day they sat in the same "plausible" column. The same blindness is what lets a
7
+ // signal that already contains a cabinet be sent through another one.
8
+ //
9
+ // Deliberately a small closed vocabulary, ordered from least to most processed, because the useful
10
+ // questions are ordinal: is this a speaker-terminal signal, and does it already contain a cabinet.
11
+ //
12
+ // `miked` is in the vocabulary and is **never derived here**. No compiled circuit contains a
13
+ // microphone; it exists for a NAM profile, whose own metadata is the only thing that can claim it,
14
+ // and for the chain rule that a miked source must not be sent through an IR or the cab simulation.
15
+ import { GROUND } from "./types.js";
16
+ /**
17
+ * Read from the lowered stamps, the same discipline as `supply-reference.ts` and
18
+ * `port-full-scale.ts`.
19
+ *
20
+ * The distinctions available from a program, and nothing finer:
21
+ *
22
+ * - `speaker-electrical` — the output port sits on a winding of a transformer declaring a `ratio`,
23
+ * so it *is* the speaker terminal. **Position, not load quality**: whether a speaker is
24
+ * modelled across it is a different question, answered by Stage A of the output-stage plan and
25
+ * its §4.6 table. An earlier draft here split this by "is something resistive across the node",
26
+ * and `fender-bassman` showed why that fails -- a 27 kOhm network element sits on its secondary
27
+ * and no test at this stage can tell that from an 8 Ohm driver without guessing from magnitude.
28
+ * - `preamp` — no output transformer at all, but the program declares a high-voltage supply
29
+ * winding (`voltsHv`), which only an amp has. `mesa-boogie-mark-v` lands here: its packet hands
30
+ * the transformer and speaker to a companion fixture, so its render is a preamp level.
31
+ * - `instrument` — everything else, which is every pedal: a pedal does not claim to be further
32
+ * along the chain than the instrument feeding it.
33
+ */
34
+ export function stageCoverage(blocks, ports) {
35
+ const windingNodes = new Set();
36
+ let declaresHighVoltageWinding = false;
37
+ for (const block of blocks) {
38
+ if (block.kind !== "mna") {
39
+ continue;
40
+ }
41
+ for (const stamp of block.stamps) {
42
+ if (stamp.kind !== "transformer") {
43
+ continue;
44
+ }
45
+ if (!Number.isFinite(stamp.turnsRatio) || stamp.turnsRatio <= 0) {
46
+ continue;
47
+ }
48
+ for (const row of [
49
+ stamp.primaryPlus,
50
+ stamp.primaryMinus,
51
+ stamp.secondaryPlus,
52
+ stamp.secondaryMinus,
53
+ ]) {
54
+ const node = block.nodeIds[row];
55
+ if (node !== undefined && node !== GROUND) {
56
+ windingNodes.add(node);
57
+ }
58
+ }
59
+ }
60
+ }
61
+ // **Widen through an impedance selector, which is where the speaker actually sits.** An ohms
62
+ // selector stands between a secondary's taps and the speaker jack, so the port is one hop past
63
+ // the winding rather than on it -- `hiwatt-dr103` stamps three selector throws at nodes
64
+ // 130/131/132, all on its output transformer, with their common at node 133 carrying both
65
+ // speaker jacks and the selected load, and `resolvePorts` correctly picks 133. Without this the
66
+ // packet classified as `preamp` while holding a fully stamped power stage, which is the same
67
+ // mistake `output-port-not-transformer-coupled` was making in `netlist.ts` and for the same
68
+ // reason: two tests of one question, only one of which followed the circuit.
69
+ //
70
+ // **One throw on the winding is enough, and the guard that matters is `windingNodes` being
71
+ // non-empty.** A count of two was tried first and does not work here: the unselected taps of an
72
+ // impedance selector are dropped during lowering as open throws, so only the live tap is ever a
73
+ // winding node -- `hiwatt-dr103` reaches this with exactly one. What stops a pedal's footswitch
74
+ // from qualifying is not the count but that a pedal declares no ratio-bearing transformer, so
75
+ // `windingNodes` is empty and no throw can be on it. Measured: exactly one corpus document holds
76
+ // both a ratio-bearing transformer stamp and a selector stamp -- `fender-bassman`, already
77
+ // `speaker-electrical` -- so relaxing the count reclassifies nothing that compiles today. Read
78
+ // off stamps and node ids only; no name, no role.
79
+ for (const block of blocks) {
80
+ if (block.kind !== "mna") {
81
+ continue;
82
+ }
83
+ const throwsByCommon = new Map();
84
+ for (const stamp of block.stamps) {
85
+ if (stamp.kind !== "selector") {
86
+ continue;
87
+ }
88
+ const common = block.nodeIds[stamp.common];
89
+ const thrown = block.nodeIds[stamp.throwNode];
90
+ if (common === undefined || thrown === undefined) {
91
+ continue;
92
+ }
93
+ if (!windingNodes.has(thrown)) {
94
+ continue;
95
+ }
96
+ const seen = throwsByCommon.get(common) ?? new Set();
97
+ seen.add(thrown);
98
+ throwsByCommon.set(common, seen);
99
+ }
100
+ for (const [common, thrown] of throwsByCommon) {
101
+ if (thrown.size >= 1 && common !== GROUND) {
102
+ windingNodes.add(common);
103
+ }
104
+ }
105
+ }
106
+ // A high-voltage winding is a power transformer's, whose windings are lowered as independent
107
+ // sources rather than a ratio — hence a separate pass over the same blocks rather than the
108
+ // loop above.
109
+ for (const block of blocks) {
110
+ if (block.kind !== "mna") {
111
+ continue;
112
+ }
113
+ for (const stamp of block.stamps) {
114
+ if (stamp.kind === "ac-source" && Math.abs(stamp.amplitudeVolts) > 100) {
115
+ declaresHighVoltageWinding = true;
116
+ }
117
+ }
118
+ }
119
+ if (windingNodes.has(ports.output)) {
120
+ return "speaker-electrical";
121
+ }
122
+ return declaresHighVoltageWinding ? "preamp" : "instrument";
123
+ }
124
+ //# sourceMappingURL=stage-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage-coverage.js","sourceRoot":"","sources":["../src/stage-coverage.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,mGAAmG;AACnG,+FAA+F;AAC/F,kGAAkG;AAClG,kGAAkG;AAClG,sEAAsE;AACtE,EAAE;AACF,mGAAmG;AACnG,mGAAmG;AACnG,EAAE;AACF,6FAA6F;AAC7F,mGAAmG;AACnG,mGAAmG;AAEnG,OAAO,EAAE,MAAM,EAAqD,MAAM,SAAS,CAAC;AAEpF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,aAAa,CAC5B,MAAwB,EACxB,KAAY;IAEZ,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,IAAI,0BAA0B,GAAG,KAAK,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,SAAS;QACV,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBAClC,SAAS;YACV,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;gBACjE,SAAS;YACV,CAAC;YACD,KAAK,MAAM,GAAG,IAAI;gBACjB,KAAK,CAAC,WAAW;gBACjB,KAAK,CAAC,YAAY;gBAClB,KAAK,CAAC,aAAa;gBACnB,KAAK,CAAC,cAAc;aACpB,EAAE,CAAC;gBACH,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC3C,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACxB,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IACD,6FAA6F;IAC7F,+FAA+F;IAC/F,wFAAwF;IACxF,0FAA0F;IAC1F,gGAAgG;IAChG,6FAA6F;IAC7F,4FAA4F;IAC5F,6EAA6E;IAC7E,EAAE;IACF,2FAA2F;IAC3F,gGAAgG;IAChG,gGAAgG;IAChG,gGAAgG;IAChG,8FAA8F;IAC9F,iGAAiG;IACjG,2FAA2F;IAC3F,+FAA+F;IAC/F,kDAAkD;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,SAAS;QACV,CAAC;QACD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAuB,CAAC;QACtD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC/B,SAAS;YACV,CAAC;YACD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC9C,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAClD,SAAS;YACV,CAAC;YACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,SAAS;YACV,CAAC;YACD,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;YAC7D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjB,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;YAC/C,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC3C,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC;QACF,CAAC;IACF,CAAC;IACD,6FAA6F;IAC7F,2FAA2F;IAC3F,cAAc;IACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,SAAS;QACV,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,GAAG,EAAE,CAAC;gBACxE,0BAA0B,GAAG,IAAI,CAAC;YACnC,CAAC;QACF,CAAC;IACF,CAAC;IACD,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,OAAO,oBAAoB,CAAC;IAC7B,CAAC;IACD,OAAO,0BAA0B,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,314 @@
1
+ import type { ControlId, NodeId, Stamp, StampPartition } from "./types";
2
+ /**
3
+ * Which fields of each stamp kind hold a node id.
4
+ *
5
+ * One table rather than a switch per consumer. `remapStampNodes` used to restate this as 150
6
+ * lines of `{ ...stamp, anode: row(stamp.anode), cathode: row(stamp.cathode) }`, and
7
+ * `stampTerminals` in `sparse-schedule.ts` restates a near-copy of it again for a different
8
+ * purpose. That is the same fact written twice, and the documented failure mode of getting it
9
+ * wrong is severe: a stamp kind missing a case kept its authored node ids while every other
10
+ * stamp in the block moved to row indices, which is an element quietly wired to the wrong
11
+ * nodes that still renders.
12
+ *
13
+ * `satisfies` checks this harder than the switch did. The mapped type requires **every** stamp
14
+ * kind to appear -- a new kind is a compile error here -- and requires each listed name to be
15
+ * an actual key of that kind's own variant, so a typo or a field moved during a refactor fails
16
+ * to build rather than silently renumbering nothing.
17
+ */
18
+ export declare const STAMP_SHAPES: {
19
+ readonly conductance: {
20
+ readonly nodes: readonly ["a", "b"];
21
+ readonly aux: 0;
22
+ readonly ports: "none";
23
+ readonly newton: false;
24
+ };
25
+ readonly "controlled-conductance": {
26
+ readonly nodes: readonly ["a", "b"];
27
+ readonly aux: 0;
28
+ readonly ports: "none";
29
+ readonly newton: false;
30
+ readonly control: true;
31
+ };
32
+ readonly "controlled-resistance": {
33
+ readonly nodes: readonly ["a", "b"];
34
+ readonly aux: 0;
35
+ readonly ports: "none";
36
+ readonly newton: false;
37
+ readonly control: true;
38
+ };
39
+ readonly capacitor: {
40
+ readonly nodes: readonly ["a", "b"];
41
+ readonly aux: 0;
42
+ readonly ports: "none";
43
+ readonly newton: false;
44
+ readonly dynamic: true;
45
+ };
46
+ readonly inductor: {
47
+ readonly nodes: readonly ["a", "b"];
48
+ readonly aux: 0;
49
+ readonly ports: "none";
50
+ readonly newton: false;
51
+ readonly dynamic: true;
52
+ };
53
+ readonly switch: {
54
+ readonly nodes: readonly ["a", "b"];
55
+ readonly aux: 0;
56
+ readonly ports: "none";
57
+ readonly newton: false;
58
+ readonly control: true;
59
+ };
60
+ readonly selector: {
61
+ readonly nodes: readonly ["common", "throwNode"];
62
+ readonly aux: 0;
63
+ readonly ports: "none";
64
+ readonly newton: false;
65
+ readonly control: true;
66
+ };
67
+ readonly "dc-source": {
68
+ readonly nodes: readonly ["positive", "negative"];
69
+ readonly aux: 1;
70
+ readonly ports: "none";
71
+ readonly newton: false;
72
+ };
73
+ readonly "ac-source": {
74
+ readonly nodes: readonly ["positive", "negative"];
75
+ readonly aux: 1;
76
+ readonly ports: "none";
77
+ readonly newton: false;
78
+ };
79
+ readonly "input-source": {
80
+ readonly nodes: readonly ["node"];
81
+ readonly aux: 1;
82
+ readonly ports: "none";
83
+ readonly newton: false;
84
+ };
85
+ readonly "macro-audio-source": {
86
+ readonly nodes: readonly ["node"];
87
+ readonly aux: 1;
88
+ readonly ports: "none";
89
+ readonly newton: false;
90
+ };
91
+ readonly "logic-divider": {
92
+ readonly nodes: readonly ["clockNode", "qNode", "gndNode"];
93
+ readonly aux: 1;
94
+ readonly ports: "none";
95
+ readonly newton: false;
96
+ readonly dynamic: true;
97
+ };
98
+ readonly vccs: {
99
+ readonly nodes: readonly ["outP", "outN", "inP", "inN"];
100
+ readonly aux: 0;
101
+ readonly ports: "none";
102
+ readonly newton: false;
103
+ };
104
+ readonly transformer: {
105
+ readonly nodes: readonly ["primaryPlus", "primaryMinus", "secondaryPlus", "secondaryMinus"];
106
+ readonly aux: 1;
107
+ readonly ports: "nodes-and-aux";
108
+ readonly newton: false;
109
+ };
110
+ readonly "spring-reverb": {
111
+ readonly nodes: readonly ["inputPlus", "inputMinus", "outputPlus", "outputMinus"];
112
+ readonly aux: 1;
113
+ readonly ports: "nodes";
114
+ readonly newton: false;
115
+ readonly dynamic: true;
116
+ };
117
+ readonly "ideal-opamp": {
118
+ readonly nodes: readonly ["plus", "minus", "output"];
119
+ readonly aux: 1;
120
+ readonly ports: "railed-opamp";
121
+ readonly newton: "railed-opamp";
122
+ };
123
+ readonly diode: {
124
+ readonly nodes: readonly ["anode", "cathode"];
125
+ readonly aux: 0;
126
+ readonly ports: "nodes";
127
+ readonly newton: true;
128
+ };
129
+ readonly "tube-diode": {
130
+ readonly nodes: readonly ["plate", "cathode"];
131
+ readonly aux: 0;
132
+ readonly ports: "nodes";
133
+ readonly newton: true;
134
+ };
135
+ readonly bjt: {
136
+ readonly nodes: readonly ["base", "collector", "emitter"];
137
+ readonly aux: 0;
138
+ readonly ports: "nodes";
139
+ readonly newton: true;
140
+ };
141
+ readonly fet: {
142
+ readonly nodes: readonly ["gate", "drain", "source"];
143
+ readonly aux: 0;
144
+ readonly ports: "nodes";
145
+ readonly newton: true;
146
+ };
147
+ readonly triode: {
148
+ readonly nodes: readonly ["grid", "cathode", "plate"];
149
+ readonly aux: 0;
150
+ readonly ports: "nodes";
151
+ readonly newton: true;
152
+ };
153
+ readonly pentode: {
154
+ readonly nodes: readonly ["grid", "cathode", "plate", "screen"];
155
+ readonly aux: 0;
156
+ readonly ports: "nodes";
157
+ readonly newton: true;
158
+ };
159
+ readonly ota: {
160
+ readonly nodes: readonly ["plus", "minus", "bias", "output", "vee"];
161
+ readonly aux: 0;
162
+ readonly ports: "nodes";
163
+ readonly newton: true;
164
+ };
165
+ readonly optocoupler: {
166
+ readonly nodes: readonly ["ldrA", "ldrB", "ledAnode", "ledCathode"];
167
+ readonly aux: 0;
168
+ readonly ports: "nodes";
169
+ readonly newton: true;
170
+ };
171
+ readonly "analog-switch": {
172
+ readonly nodes: readonly ["a", "b", "control"];
173
+ readonly aux: 0;
174
+ readonly ports: "nodes";
175
+ readonly newton: true;
176
+ };
177
+ readonly compandor: {
178
+ readonly nodes: readonly ["rectIn", "rectCap", "cellIn", "sumNode", "vref"];
179
+ readonly aux: 0;
180
+ readonly ports: "nodes";
181
+ readonly newton: true;
182
+ readonly dynamic: true;
183
+ };
184
+ readonly "clock-driver": {
185
+ readonly nodes: readonly ["cp1", "cp2", "vgg", "vdd", "ox1", "gnd"];
186
+ readonly aux: 3;
187
+ readonly ports: "nodes";
188
+ readonly newton: true;
189
+ };
190
+ readonly comparator: {
191
+ readonly nodes: readonly ["plus", "minus", "output", "vee"];
192
+ readonly aux: 0;
193
+ readonly ports: "nodes";
194
+ readonly newton: true;
195
+ };
196
+ readonly "linear-vca": {
197
+ readonly nodes: readonly ["plus", "minus", "output", "control"];
198
+ readonly aux: 0;
199
+ readonly ports: "nodes";
200
+ readonly newton: true;
201
+ };
202
+ };
203
+ type StampShape = {
204
+ readonly nodes: readonly string[];
205
+ readonly aux: 0 | 1 | 3;
206
+ readonly ports: "none" | "nodes" | "nodes-and-aux" | "railed-opamp";
207
+ readonly newton: boolean | "railed-opamp";
208
+ readonly terminalNodes?: readonly string[];
209
+ readonly terminalsDropGround?: true;
210
+ readonly control?: true;
211
+ readonly dynamic?: true;
212
+ };
213
+ /** The shape entry for a stamp, with the table's per-kind literal types widened away. */
214
+ export declare function stampShape(stamp: Stamp): StampShape;
215
+ /** Read a named node field off a stamp. */
216
+ export declare function stampNodeValue(stamp: Stamp, field: string): number;
217
+ /** The auxiliary rows a stamp owns, as absolute row indices. */
218
+ export declare function stampAuxRows(stamp: Stamp, nodeCount: number): number[];
219
+ /**
220
+ * Rewrite a stamp's node fields through `row`.
221
+ *
222
+ * The spread reassigns keys the stamp already carries, so their position in the object is
223
+ * unchanged -- which matters because a lowered stamp is serialised into the emitted program
224
+ * and key order is part of those bytes.
225
+ */
226
+ export declare function remapStampNodes(stamp: Stamp, row: (node: NodeId) => NodeId): Stamp;
227
+ /**
228
+ * Does this stamp have to be re-evaluated inside a Newton loop?
229
+ *
230
+ * **The stamp-level twin of `partition.ts`'s `lawNeedsNewton`, and deliberately a second fact
231
+ * rather than a reuse of the first.** A law and its stamps are not the same list -- a jack's
232
+ * `port-engage` law lowers to a plain `conductance`, an `ac-source` law lowers to two stamps,
233
+ * an `open` law lowers to none -- and what a solver has to do is decided by what is in the
234
+ * block, not by what was in the document. `Block.linear` is read by the runtime to choose
235
+ * between one pass and an iteration cap, so it has to describe the stamps it will evaluate.
236
+ *
237
+ * The two mistakes are not symmetric, which is why the table has to be exhaustive. Calling a
238
+ * linear stamp nonlinear costs a few iterations; calling a nonlinear stamp linear makes
239
+ * `iterate` run one pass, evaluate the curve once from a zero start, and emit that as a solved
240
+ * answer -- no held sample, no telemetry, no diagnostic.
241
+ */
242
+ export declare function stampNeedsNewton(stamp: Stamp): boolean;
243
+ /**
244
+ * Which runtime control moves a stamp's value, or `null` when it is constant.
245
+ *
246
+ * Read off the shape table's `control` flag. A stamp missing that flag would silently make a
247
+ * block look `controlFree`, and step 4's whole promise is that such a block's matrix is
248
+ * constant -- so the omission would be a factorisation frozen against a knob that still moves.
249
+ */
250
+ export declare function stampControl(stamp: Stamp): ControlId | null;
251
+ /**
252
+ * Which rows a stamp's device law actually writes into the Jacobian / RHS, or `null` when the
253
+ * stamp writes none.
254
+ *
255
+ * Read off the shape table's `ports`, which is a **separate fact from `newton`** and not a
256
+ * synonym for it. `transformer` and `spring-reverb` are both linear within a sample yet
257
+ * declare port rows, so deriving this from `stampNeedsNewton` would drop them.
258
+ *
259
+ * The returned order is not significant: `computeStampPartition` feeds these into a `Set` and
260
+ * sorts it.
261
+ */
262
+ export declare function stampPortRows(stamp: Stamp, nodeCount: number): readonly number[] | null;
263
+ /**
264
+ * Whether a stamp carries dynamic/reactive state (e.g. companion state across time steps).
265
+ */
266
+ export declare function stampIsDynamic(stamp: Stamp): boolean;
267
+ /**
268
+ * Compute the complete stamp partition for an MNA block.
269
+ */
270
+ export declare function computeStampPartition(stamps: readonly Stamp[], nodeCount: number): StampPartition;
271
+ /**
272
+ * Whether a block should carry the eliminated (Schur-complement) solve.
273
+ *
274
+ * Shared by `lower.ts`, which decides it when a region is first lowered, and `couple.ts`,
275
+ * which must re-decide it after adding a stamp. The two carried byte-identical copies of this
276
+ * predicate, so a threshold changed in one and not the other would have made a coupled block
277
+ * disagree with the same block uncoupled.
278
+ */
279
+ export declare function shouldEliminate(unknowns: number, portRowCount: number, linear: boolean,
280
+ /**
281
+ * The document's `convergence-opt-in` flag. Where set, a nonlinear block with port rows is
282
+ * eliminated regardless of the cost rule -- it overrides the cost veto, but not the
283
+ * linear / zero-port guard above, which a portless or linear block cannot use elimination
284
+ * for at all.
285
+ */
286
+ convergenceOptIn?: boolean): boolean;
287
+ /**
288
+ * The derived admission rule, behind `VESSEL_DERIVED_ELIMINATION=1`.
289
+ *
290
+ * **Cost goes as unknowns² × nonlinear count** — fitted across ten packets with WASM-measured cost,
291
+ * `R² = 0.674`. Elimination replaces an `n`-unknown iterated system with a `p`-unknown one, and its
292
+ * own factorisation is prepare-time for a linear interior. What it costs per sample is
293
+ * **densification**: the port system is dense where the original may have been sparse. So:
294
+ *
295
+ * ```
296
+ * admit when MEASURED_DENSIFICATION * p² < n² i.e. n/p > sqrt(7.2) = 2.68
297
+ * ```
298
+ *
299
+ * **No free constant.** `7.2` is the measured on/off of the two solve paths at 72-119 unknowns and
300
+ * the exponent is fitted (~2); neither was chosen to admit or reject any particular packet — which
301
+ * is the failure this replaces. Lowering `2.4` until it admitted the three packets whose saving had
302
+ * been predicted would have made the prediction and the admission one choice, and no later
303
+ * measurement could have separated them.
304
+ *
305
+ * **`ELIMINATE_MIN_UNKNOWNS` is still consulted and is still hand-set.** The model has **no term
306
+ * for fixed per-block overhead**, and without one the inequality admits every block with any
307
+ * interior — 241 of 241, which is not a predicate. The floor stands in for that missing term, and
308
+ * the sample straddling it (15 admitted blocks below, 31 above) is designed to retire it: if a
309
+ * 7-unknown block predicted at 84% delivers nothing, the overhead is the whole saving at that size
310
+ * and the crossover **is** the floor, derived rather than chosen.
311
+ */
312
+ export declare function derivedShouldEliminate(unknowns: number, portRowCount: number): boolean;
313
+ export {};
314
+ //# sourceMappingURL=stamp-partition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stamp-partition.d.ts","sourceRoot":"","sources":["../src/stamp-partition.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGxE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMxB,CAAC;AAEF,KAAK,UAAU,GAAG;IACjB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,eAAe,GAAG,cAAc,CAAC;IACpE,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAAC;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;CACxB,CAAC;AAEF,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,CAEnD;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAMtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAC3B,KAAK,CAMP;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAMtD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAI3D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,MAAM,GACf,SAAS,MAAM,EAAE,GAAG,IAAI,CAa1B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,SAAS,EAAE,MAAM,GACf,cAAc,CAsEhB;AAsBD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,OAAO;AACf;;;;;GAKG;AACH,gBAAgB,UAAQ,GACtB,OAAO,CAeT;AAeD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GAClB,OAAO,CAQT"}