@hviana/sema 0.1.5 → 0.1.6

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 (160) hide show
  1. package/AGENTS.md +6 -5
  2. package/CITATION.cff +49 -0
  3. package/HOW_IT_WORKS.md +11 -12
  4. package/README.md +7 -5
  5. package/dist/example/demo.js +25 -25
  6. package/dist/example/train_base.d.ts +19 -21
  7. package/dist/example/train_base.js +1687 -1952
  8. package/dist/src/alphabet.d.ts +3 -3
  9. package/dist/src/alphabet.js +24 -27
  10. package/dist/src/alu/src/alu.d.ts +169 -194
  11. package/dist/src/alu/src/alu.js +374 -414
  12. package/dist/src/alu/src/expr.d.ts +36 -43
  13. package/dist/src/alu/src/expr.js +252 -278
  14. package/dist/src/alu/src/index.d.ts +9 -98
  15. package/dist/src/alu/src/index.js +10 -64
  16. package/dist/src/alu/src/kernel-arith.d.ts +1 -5
  17. package/dist/src/alu/src/kernel-arith.js +195 -285
  18. package/dist/src/alu/src/kernel-bits.d.ts +1 -5
  19. package/dist/src/alu/src/kernel-bits.js +81 -115
  20. package/dist/src/alu/src/kernel-logic.js +33 -63
  21. package/dist/src/alu/src/kernel-nd.js +155 -195
  22. package/dist/src/alu/src/kernel-numeric.d.ts +16 -80
  23. package/dist/src/alu/src/kernel-numeric.js +259 -331
  24. package/dist/src/alu/src/operation.d.ts +112 -132
  25. package/dist/src/alu/src/operation.js +149 -163
  26. package/dist/src/alu/src/parser.d.ts +168 -175
  27. package/dist/src/alu/src/parser.js +382 -421
  28. package/dist/src/alu/src/resonance.d.ts +16 -25
  29. package/dist/src/alu/src/resonance.js +49 -56
  30. package/dist/src/alu/src/text.d.ts +3 -7
  31. package/dist/src/alu/src/text.js +31 -37
  32. package/dist/src/alu/src/value.d.ts +14 -14
  33. package/dist/src/alu/src/value.js +150 -160
  34. package/dist/src/alu/test/alu.test.js +543 -656
  35. package/dist/src/bytes.d.ts +1 -5
  36. package/dist/src/bytes.js +33 -40
  37. package/dist/src/config.d.ts +99 -102
  38. package/dist/src/config.js +78 -83
  39. package/dist/src/derive/src/deduction.d.ts +60 -62
  40. package/dist/src/derive/src/deduction.js +103 -109
  41. package/dist/src/derive/src/index.d.ts +1 -7
  42. package/dist/src/derive/src/priority-queue.d.ts +8 -8
  43. package/dist/src/derive/src/priority-queue.js +57 -61
  44. package/dist/src/derive/src/rewrite.d.ts +15 -18
  45. package/dist/src/derive/src/rewrite.js +59 -67
  46. package/dist/src/derive/src/trie.d.ts +56 -56
  47. package/dist/src/derive/src/trie.js +175 -179
  48. package/dist/src/derive/test/derive.test.js +96 -100
  49. package/dist/src/extension.d.ts +13 -16
  50. package/dist/src/geometry.d.ts +17 -42
  51. package/dist/src/geometry.js +235 -266
  52. package/dist/src/index.d.ts +2 -17
  53. package/dist/src/index.js +2 -12
  54. package/dist/src/ingest-cache.d.ts +25 -30
  55. package/dist/src/ingest-cache.js +108 -127
  56. package/dist/src/mind/articulation.d.ts +1 -5
  57. package/dist/src/mind/articulation.js +77 -112
  58. package/dist/src/mind/attention.d.ts +40 -108
  59. package/dist/src/mind/attention.js +749 -871
  60. package/dist/src/mind/canonical.d.ts +4 -19
  61. package/dist/src/mind/canonical.js +27 -31
  62. package/dist/src/mind/graph-search.d.ts +201 -225
  63. package/dist/src/mind/graph-search.js +742 -821
  64. package/dist/src/mind/index.d.ts +2 -10
  65. package/dist/src/mind/junction.d.ts +31 -58
  66. package/dist/src/mind/junction.js +172 -237
  67. package/dist/src/mind/learning.d.ts +16 -52
  68. package/dist/src/mind/learning.js +143 -165
  69. package/dist/src/mind/match.d.ts +20 -69
  70. package/dist/src/mind/match.js +259 -318
  71. package/dist/src/mind/mechanisms/alu.js +16 -16
  72. package/dist/src/mind/mechanisms/cast.d.ts +9 -13
  73. package/dist/src/mind/mechanisms/cast.js +363 -456
  74. package/dist/src/mind/mechanisms/confluence.d.ts +8 -12
  75. package/dist/src/mind/mechanisms/confluence.js +152 -183
  76. package/dist/src/mind/mechanisms/cover.d.ts +2 -8
  77. package/dist/src/mind/mechanisms/cover.js +148 -210
  78. package/dist/src/mind/mechanisms/extraction.d.ts +8 -34
  79. package/dist/src/mind/mechanisms/extraction.js +234 -288
  80. package/dist/src/mind/mechanisms/recall.d.ts +6 -10
  81. package/dist/src/mind/mechanisms/recall.js +126 -185
  82. package/dist/src/mind/mind.d.ts +129 -154
  83. package/dist/src/mind/mind.js +258 -288
  84. package/dist/src/mind/pipeline-mechanism.d.ts +112 -124
  85. package/dist/src/mind/pipeline-mechanism.js +161 -172
  86. package/dist/src/mind/pipeline.d.ts +4 -14
  87. package/dist/src/mind/pipeline.js +125 -189
  88. package/dist/src/mind/primitives.d.ts +8 -32
  89. package/dist/src/mind/primitives.js +99 -117
  90. package/dist/src/mind/rationale.d.ts +86 -98
  91. package/dist/src/mind/rationale.js +113 -121
  92. package/dist/src/mind/reasoning.d.ts +2 -13
  93. package/dist/src/mind/reasoning.js +129 -166
  94. package/dist/src/mind/recognition.d.ts +1 -4
  95. package/dist/src/mind/recognition.js +183 -208
  96. package/dist/src/mind/resonance.d.ts +5 -22
  97. package/dist/src/mind/resonance.js +0 -0
  98. package/dist/src/mind/trace.d.ts +6 -25
  99. package/dist/src/mind/trace.js +50 -58
  100. package/dist/src/mind/traverse.d.ts +16 -58
  101. package/dist/src/mind/traverse.js +304 -357
  102. package/dist/src/mind/types.d.ts +120 -127
  103. package/dist/src/mind/types.js +60 -69
  104. package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
  105. package/dist/src/rabitq-ivf/src/database.js +201 -0
  106. package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
  107. package/dist/src/{rabitq-hnsw → rabitq-ivf}/src/index.js +1 -3
  108. package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
  109. package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
  110. package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
  111. package/dist/src/rabitq-ivf/src/prng.js +36 -0
  112. package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
  113. package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
  114. package/dist/src/sema.d.ts +9 -13
  115. package/dist/src/sema.js +26 -40
  116. package/dist/src/store-sqlite.d.ts +169 -166
  117. package/dist/src/store-sqlite.js +762 -662
  118. package/dist/src/store.d.ts +586 -630
  119. package/dist/src/store.js +1423 -1581
  120. package/dist/src/vec.d.ts +5 -9
  121. package/dist/src/vec.js +61 -73
  122. package/example/train_base.ts +13 -10
  123. package/package.json +1 -1
  124. package/src/alu/README.md +1 -1
  125. package/src/alu/src/index.ts +1 -1
  126. package/src/config.ts +19 -27
  127. package/src/index.ts +6 -11
  128. package/src/rabitq-ivf/README.md +56 -0
  129. package/src/rabitq-ivf/src/database.ts +276 -0
  130. package/src/{rabitq-hnsw → rabitq-ivf}/src/index.ts +2 -5
  131. package/src/rabitq-ivf/src/ivf.ts +1330 -0
  132. package/src/{rabitq-hnsw → rabitq-ivf}/src/prng.ts +1 -1
  133. package/src/store-sqlite.ts +196 -9
  134. package/src/store.ts +8 -32
  135. package/test/08-storage.test.mjs +3 -3
  136. package/test/14-scaling.test.mjs +2 -2
  137. package/test/35-ivf.test.mjs +263 -0
  138. package/test/36-bloom.test.mjs +123 -0
  139. package/dist/src/rabitq-hnsw/src/database.d.ts +0 -202
  140. package/dist/src/rabitq-hnsw/src/database.js +0 -405
  141. package/dist/src/rabitq-hnsw/src/heap.d.ts +0 -22
  142. package/dist/src/rabitq-hnsw/src/heap.js +0 -94
  143. package/dist/src/rabitq-hnsw/src/hnsw.d.ts +0 -125
  144. package/dist/src/rabitq-hnsw/src/hnsw.js +0 -500
  145. package/dist/src/rabitq-hnsw/src/index.d.ts +0 -15
  146. package/dist/src/rabitq-hnsw/src/prng.d.ts +0 -19
  147. package/dist/src/rabitq-hnsw/src/prng.js +0 -38
  148. package/dist/src/rabitq-hnsw/src/rabitq.d.ts +0 -95
  149. package/dist/src/rabitq-hnsw/src/rabitq.js +0 -299
  150. package/dist/src/rabitq-hnsw/src/store.d.ts +0 -162
  151. package/dist/src/rabitq-hnsw/src/store.js +0 -916
  152. package/dist/src/rabitq-hnsw/test/hnsw.test.d.ts +0 -1
  153. package/dist/src/rabitq-hnsw/test/hnsw.test.js +0 -1197
  154. package/src/rabitq-hnsw/README.md +0 -303
  155. package/src/rabitq-hnsw/src/database.ts +0 -492
  156. package/src/rabitq-hnsw/src/heap.ts +0 -90
  157. package/src/rabitq-hnsw/src/hnsw.ts +0 -514
  158. package/src/rabitq-hnsw/src/store.ts +0 -994
  159. package/src/rabitq-hnsw/test/hnsw.test.ts +0 -1213
  160. /package/src/{rabitq-hnsw → rabitq-ivf}/src/rabitq.ts +0 -0
@@ -25,30 +25,30 @@
25
25
  // functions, composed from the same scalar primitives, and tested directly.
26
26
  // `linsolve` is Gaussian elimination — structured arithmetic, not a new
27
27
  // primitive.
28
- import { asInt, asReal, bit, int, joinDomain, real } from "./value.js";
28
+ import { asInt, asReal, bit, int, joinDomain, real, } from "./value.js";
29
29
  /** Reduce numeric operands in their join domain: exact bigint when all are
30
30
  * bit/int, native double once any is real. `bigOp` and `realOp` are the same
31
31
  * fold expressed in each carrier. */
32
32
  function reduceNumeric(args, identityBig, bigOp, realOp) {
33
- const d = joinDomain(args);
34
- if (d === "real") {
35
- let acc = Number(identityBig);
33
+ const d = joinDomain(args);
34
+ if (d === "real") {
35
+ let acc = Number(identityBig);
36
+ let first = true;
37
+ for (const a of args) {
38
+ const x = asReal(a);
39
+ acc = first ? x : realOp(acc, x);
40
+ first = false;
41
+ }
42
+ return real(acc);
43
+ }
44
+ let acc = identityBig;
36
45
  let first = true;
37
46
  for (const a of args) {
38
- const x = asReal(a);
39
- acc = first ? x : realOp(acc, x);
40
- first = false;
47
+ const n = asInt(a);
48
+ acc = first ? n : bigOp(acc, n);
49
+ first = false;
41
50
  }
42
- return real(acc);
43
- }
44
- let acc = identityBig;
45
- let first = true;
46
- for (const a of args) {
47
- const n = asInt(a);
48
- acc = first ? n : bigOp(acc, n);
49
- first = false;
50
- }
51
- return int(acc);
51
+ return int(acc);
52
52
  }
53
53
  // The infix binding tiers of arithmetic notation, loosest to tightest. These
54
54
  // are declared ONCE, here, next to the ops they describe; the expression
@@ -61,294 +61,204 @@ const MULTIPLICATIVE = { precedence: 2 };
61
61
  const EXPONENT = { precedence: 3, rightAssoc: true };
62
62
  /** Register the arithmetic layer into `r`. */
63
63
  export function registerArith(r) {
64
- // ── identities ──────────────────────────────────────────────────────────
65
- r.prim("zero", 0, ["0"], () => int(0n));
66
- r.prim("one", 0, ["1"], () => int(1n));
67
- // ── primitives ──────────────────────────────────────────────────────────
68
- // add / multiply are variadic folds (so "sum"/"product" of many is one call);
69
- // the infix path calls them with exactly two operands.
70
- r.prim(
71
- "add",
72
- "variadic",
73
- ["+", "plus", "sum", "add", "total"],
74
- (args) => reduceNumeric(args, 0n, (a, b) => a + b, (a, b) => a + b),
75
- { infix: ADDITIVE },
76
- );
77
- r.prim(
78
- "multiply",
79
- "variadic",
80
- [
81
- "*",
82
- "×",
83
- "·",
84
- "times",
85
- "multiply",
86
- "product",
87
- ],
88
- (args) => reduceNumeric(args, 1n, (a, b) => a * b, (a, b) => a * b),
89
- {
90
- infix: MULTIPLICATIVE,
91
- },
92
- );
93
- r.prim("negate", 1, ["-", "negate", "neg"], (args) => {
94
- const v = args[0];
95
- return v.domain === "real" ? real(-v.x) : int(-asInt(v));
96
- });
97
- // reciprocal lives in the reals: 1/2 = 0.5, so it lifts to a double (an int
98
- // result like 1/1 still formats cleanly through the codec).
99
- r.prim(
100
- "reciprocal",
101
- 1,
102
- ["reciprocal", "recip"],
103
- (args) => real(1 / asReal(args[0])),
104
- );
105
- // sign {−1, 0, +1}, returned exact (int) so comparisons are exact.
106
- r.prim("sign", 1, ["sign", "sgn"], (args) => {
107
- const v = args[0];
108
- if (v.domain === "real") {
109
- return int(v.x > 0 ? 1n : v.x < 0 ? -1n : 0n);
110
- }
111
- const n = asInt(v);
112
- return int(n > 0n ? 1n : n < 0n ? -1n : 0n);
113
- });
114
- // floor / mod the optional integer-number-theory primitives.
115
- r.prim("floor", 1, ["floor"], (args) => {
116
- const v = args[0];
117
- return v.domain === "real" ? int(BigInt(Math.floor(v.x))) : int(asInt(v));
118
- });
119
- // ── derived: the field ─────────────────────────────────────────────────
120
- r.derive(
121
- "subtract",
122
- 2,
123
- ["-", "minus", "subtract", "difference", "less"],
124
- (args, ctx) => ctx.apply("add", [args[0], ctx.apply("negate", [args[1]])]),
125
- { infix: ADDITIVE },
126
- );
127
- r.derive(
128
- "divide",
129
- 2,
130
- ["/", "÷", "divide", "over"],
131
- (args, ctx) =>
132
- ctx.apply("multiply", [args[0], ctx.apply("reciprocal", [args[1]])]),
133
- { infix: MULTIPLICATIVE },
134
- );
135
- // Euclidean-style remainder. Exact for ints; native % for reals.
136
- r.derive("mod", 2, ["mod", "%", "modulo"], (args, ctx) => {
137
- void ctx;
138
- const d = joinDomain(args);
139
- if (d === "real") {
140
- return real(asReal(args[0]) % asReal(args[1]));
141
- }
142
- return int(asInt(args[0]) % asInt(args[1]));
143
- }, { infix: MULTIPLICATIVE });
144
- // ── derived: order (every comparison = sign subtract → a truth bit) ────
145
- const cmpSign = (args, ctx) =>
146
- asInt(ctx.apply("sign", [ctx.apply("subtract", [args[0], args[1]])]));
147
- r.derive(
148
- "eq",
149
- 2,
150
- ["=", "==", "equals", "eq"],
151
- (args, ctx) => bit(cmpSign(args, ctx) === 0n ? 1 : 0),
152
- );
153
- r.derive(
154
- "ne",
155
- 2,
156
- ["!=", "≠", "ne"],
157
- (args, ctx) => bit(cmpSign(args, ctx) !== 0n ? 1 : 0),
158
- );
159
- r.derive(
160
- "lt",
161
- 2,
162
- ["<", "lt"],
163
- (args, ctx) => bit(cmpSign(args, ctx) < 0n ? 1 : 0),
164
- );
165
- r.derive(
166
- "le",
167
- 2,
168
- ["<=", "≤", "le"],
169
- (args, ctx) => bit(cmpSign(args, ctx) <= 0n ? 1 : 0),
170
- );
171
- r.derive(
172
- "gt",
173
- 2,
174
- [">", "gt"],
175
- (args, ctx) => bit(cmpSign(args, ctx) > 0n ? 1 : 0),
176
- );
177
- r.derive(
178
- "ge",
179
- 2,
180
- [">=", "≥", "ge"],
181
- (args, ctx) => bit(cmpSign(args, ctx) >= 0n ? 1 : 0),
182
- );
183
- // ── derived: magnitude / extremes ────────────────────────────────────────
184
- // abs(x) = sign(x)·x branch-free.
185
- r.derive(
186
- "abs",
187
- 1,
188
- ["abs", "|x|"],
189
- (args, ctx) =>
190
- ctx.apply("multiply", [ctx.apply("sign", [args[0]]), args[0]]),
191
- );
192
- // min / max select on the comparison — the control flow layer 1 provides.
193
- r.derive(
194
- "min",
195
- 2,
196
- ["min"],
197
- (args, ctx) => cmpSign(args, ctx) <= 0n ? args[0] : args[1],
198
- );
199
- r.derive(
200
- "max",
201
- 2,
202
- ["max"],
203
- (args, ctx) => cmpSign(args, ctx) >= 0n ? args[0] : args[1],
204
- );
205
- // ── derived: power ───────────────────────────────────────────────────────
206
- // Integer exponent → repeated multiply (exact); non-integer or real → fall to
207
- // the limit layer's exp(e·log b) when it is registered.
208
- r.derive("power", 2, ["^", "**", "pow", "power"], (args, ctx) => {
209
- const base = args[0];
210
- const e = args[1];
211
- // An INTEGER-VALUED exponent → repeated multiply (exact), even if it arrived
212
- // as a real that happens to be whole (a derived call may hand a real 2.0).
213
- // This keeps b^2 exact and avoids exp(e·ln b), which is approximate and
214
- // undefined for a negative base (ln(−3) = NaN). Only a genuinely fractional
215
- // exponent falls to the limit layer.
216
- const eInt = e.domain !== "real"
217
- ? asInt(e)
218
- : Number.isInteger(e.x)
219
- ? BigInt(e.x)
220
- : null;
221
- if (eInt !== null) {
222
- let n = eInt;
223
- const neg = n < 0n;
224
- if (neg) {
225
- n = -n;
226
- }
227
- let acc = int(1n);
228
- for (let i = 0n; i < n; i++) {
229
- acc = ctx.apply("multiply", [acc, base]);
230
- }
231
- return neg ? ctx.apply("reciprocal", [acc]) : acc;
232
- }
233
- // Fractional exponent: b^e = exp(e·ln b), needing the limit layer.
234
- if (ctx.has("exp") && ctx.has("log")) {
235
- return ctx.apply("exp", [
236
- ctx.apply("multiply", [e, ctx.apply("log", [base])]),
237
- ]);
238
- }
239
- return real(Math.pow(asReal(base), asReal(e)));
240
- }, { infix: EXPONENT });
241
- // gcd via Euclid (mod) — number theory standing on the integer primitives.
242
- r.derive("gcd", 2, ["gcd"], (args, ctx) => {
243
- let a = asInt(args[0]);
244
- let b = asInt(args[1]);
245
- a = a < 0n ? -a : a;
246
- b = b < 0n ? -b : b;
247
- while (b !== 0n) {
248
- const t = asInt(ctx.apply("mod", [int(a), int(b)]));
249
- a = b;
250
- b = t < 0n ? -t : t;
251
- }
252
- return int(a);
253
- });
254
- // ── polymorphic inverse (the bridge to the symbol domain) ────────────────
255
- // The additive inverse of a NUMBER is its negation; the inverse of a SYMBOL is
256
- // its RESONANT OPPOSITE — found by the host's resonance and pre-resolved into
257
- // ctx.resonance (see resonance.ts). One op, dispatched on the operand's
258
- // domain: this is "inverse of 3 is −3, inverse of <a learned form> is its
259
- // opposite", in any modality. A bit inverts as logical not.
260
- r.derive("inverse", 1, ["inverse", "opposite", "invert"], (args, ctx) => {
261
- const v = args[0];
262
- if (v.domain === "symbol") {
263
- const opp = ctx.resonance.opposite(v.bytes);
264
- // No known opposite → leave the form unchanged rather than fabricate one
265
- // (faithfulness: ALU never invents meaning resonance did not supply).
266
- return opp ? { domain: "symbol", bytes: opp } : v;
267
- }
268
- if (v.domain === "bit") {
269
- return ctx.apply("not", [v]);
270
- }
271
- return ctx.apply("negate", [v]);
272
- });
273
- // reciprocal already registered as the multiplicative inverse primitive.
64
+ // ── identities ──────────────────────────────────────────────────────────
65
+ r.prim("zero", 0, ["0"], () => int(0n));
66
+ r.prim("one", 0, ["1"], () => int(1n));
67
+ // ── primitives ──────────────────────────────────────────────────────────
68
+ // add / multiply are variadic folds (so "sum"/"product" of many is one call);
69
+ // the infix path calls them with exactly two operands.
70
+ r.prim("add", "variadic", ["+", "plus", "sum", "add", "total"], (args) => reduceNumeric(args, 0n, (a, b) => a + b, (a, b) => a + b), { infix: ADDITIVE });
71
+ r.prim("multiply", "variadic", [
72
+ "*",
73
+ "×",
74
+ "·",
75
+ "times",
76
+ "multiply",
77
+ "product",
78
+ ], (args) => reduceNumeric(args, 1n, (a, b) => a * b, (a, b) => a * b), {
79
+ infix: MULTIPLICATIVE,
80
+ });
81
+ r.prim("negate", 1, ["-", "negate", "neg"], (args) => {
82
+ const v = args[0];
83
+ return v.domain === "real" ? real(-v.x) : int(-asInt(v));
84
+ });
85
+ // reciprocal lives in the reals: 1/2 = 0.5, so it lifts to a double (an int
86
+ // result like 1/1 still formats cleanly through the codec).
87
+ r.prim("reciprocal", 1, ["reciprocal", "recip"], (args) => real(1 / asReal(args[0])));
88
+ // sign ∈ {−1, 0, +1}, returned exact (int) so comparisons are exact.
89
+ r.prim("sign", 1, ["sign", "sgn"], (args) => {
90
+ const v = args[0];
91
+ if (v.domain === "real")
92
+ return int(v.x > 0 ? 1n : v.x < 0 ? -1n : 0n);
93
+ const n = asInt(v);
94
+ return int(n > 0n ? 1n : n < 0n ? -1n : 0n);
95
+ });
96
+ // floor / mod — the optional integer-number-theory primitives.
97
+ r.prim("floor", 1, ["floor"], (args) => {
98
+ const v = args[0];
99
+ return v.domain === "real" ? int(BigInt(Math.floor(v.x))) : int(asInt(v));
100
+ });
101
+ // ── derived: the field ─────────────────────────────────────────────────
102
+ r.derive("subtract", 2, ["-", "minus", "subtract", "difference", "less"], (args, ctx) => ctx.apply("add", [args[0], ctx.apply("negate", [args[1]])]), { infix: ADDITIVE });
103
+ r.derive("divide", 2, ["/", "÷", "divide", "over"], (args, ctx) => ctx.apply("multiply", [args[0], ctx.apply("reciprocal", [args[1]])]), { infix: MULTIPLICATIVE });
104
+ // Euclidean-style remainder. Exact for ints; native % for reals.
105
+ r.derive("mod", 2, ["mod", "%", "modulo"], (args, ctx) => {
106
+ void ctx;
107
+ const d = joinDomain(args);
108
+ if (d === "real")
109
+ return real(asReal(args[0]) % asReal(args[1]));
110
+ return int(asInt(args[0]) % asInt(args[1]));
111
+ }, { infix: MULTIPLICATIVE });
112
+ // ── derived: order (every comparison = sign subtract a truth bit) ────
113
+ const cmpSign = (args, ctx) => asInt(ctx.apply("sign", [ctx.apply("subtract", [args[0], args[1]])]));
114
+ r.derive("eq", 2, ["=", "==", "equals", "eq"], (args, ctx) => bit(cmpSign(args, ctx) === 0n ? 1 : 0));
115
+ r.derive("ne", 2, ["!=", "≠", "ne"], (args, ctx) => bit(cmpSign(args, ctx) !== 0n ? 1 : 0));
116
+ r.derive("lt", 2, ["<", "lt"], (args, ctx) => bit(cmpSign(args, ctx) < 0n ? 1 : 0));
117
+ r.derive("le", 2, ["<=", "≤", "le"], (args, ctx) => bit(cmpSign(args, ctx) <= 0n ? 1 : 0));
118
+ r.derive("gt", 2, [">", "gt"], (args, ctx) => bit(cmpSign(args, ctx) > 0n ? 1 : 0));
119
+ r.derive("ge", 2, [">=", "≥", "ge"], (args, ctx) => bit(cmpSign(args, ctx) >= 0n ? 1 : 0));
120
+ // ── derived: magnitude / extremes ────────────────────────────────────────
121
+ // abs(x) = sign(x)·x — branch-free.
122
+ r.derive("abs", 1, ["abs", "|x|"], (args, ctx) => ctx.apply("multiply", [ctx.apply("sign", [args[0]]), args[0]]));
123
+ // min / max select on the comparison — the control flow layer 1 provides.
124
+ r.derive("min", 2, ["min"], (args, ctx) => cmpSign(args, ctx) <= 0n ? args[0] : args[1]);
125
+ r.derive("max", 2, ["max"], (args, ctx) => cmpSign(args, ctx) >= 0n ? args[0] : args[1]);
126
+ // ── derived: power ───────────────────────────────────────────────────────
127
+ // Integer exponent → repeated multiply (exact); non-integer or real → fall to
128
+ // the limit layer's exp(e·log b) when it is registered.
129
+ r.derive("power", 2, ["^", "**", "pow", "power"], (args, ctx) => {
130
+ const base = args[0];
131
+ const e = args[1];
132
+ // An INTEGER-VALUED exponent → repeated multiply (exact), even if it arrived
133
+ // as a real that happens to be whole (a derived call may hand a real 2.0).
134
+ // This keeps b^2 exact and avoids exp(e·ln b), which is approximate and
135
+ // undefined for a negative base (ln(−3) = NaN). Only a genuinely fractional
136
+ // exponent falls to the limit layer.
137
+ const eInt = e.domain !== "real"
138
+ ? asInt(e)
139
+ : Number.isInteger(e.x)
140
+ ? BigInt(e.x)
141
+ : null;
142
+ if (eInt !== null) {
143
+ let n = eInt;
144
+ const neg = n < 0n;
145
+ if (neg)
146
+ n = -n;
147
+ let acc = int(1n);
148
+ for (let i = 0n; i < n; i++)
149
+ acc = ctx.apply("multiply", [acc, base]);
150
+ return neg ? ctx.apply("reciprocal", [acc]) : acc;
151
+ }
152
+ // Fractional exponent: b^e = exp(e·ln b), needing the limit layer.
153
+ if (ctx.has("exp") && ctx.has("log")) {
154
+ return ctx.apply("exp", [
155
+ ctx.apply("multiply", [e, ctx.apply("log", [base])]),
156
+ ]);
157
+ }
158
+ return real(Math.pow(asReal(base), asReal(e)));
159
+ }, { infix: EXPONENT });
160
+ // gcd via Euclid (mod) — number theory standing on the integer primitives.
161
+ r.derive("gcd", 2, ["gcd"], (args, ctx) => {
162
+ let a = asInt(args[0]);
163
+ let b = asInt(args[1]);
164
+ a = a < 0n ? -a : a;
165
+ b = b < 0n ? -b : b;
166
+ while (b !== 0n) {
167
+ const t = asInt(ctx.apply("mod", [int(a), int(b)]));
168
+ a = b;
169
+ b = t < 0n ? -t : t;
170
+ }
171
+ return int(a);
172
+ });
173
+ // ── polymorphic inverse (the bridge to the symbol domain) ────────────────
174
+ // The additive inverse of a NUMBER is its negation; the inverse of a SYMBOL is
175
+ // its RESONANT OPPOSITE found by the host's resonance and pre-resolved into
176
+ // ctx.resonance (see resonance.ts). One op, dispatched on the operand's
177
+ // domain: this is "inverse of 3 is −3, inverse of <a learned form> is its
178
+ // opposite", in any modality. A bit inverts as logical not.
179
+ r.derive("inverse", 1, ["inverse", "opposite", "invert"], (args, ctx) => {
180
+ const v = args[0];
181
+ if (v.domain === "symbol") {
182
+ const opp = ctx.resonance.opposite(v.bytes);
183
+ // No known opposite leave the form unchanged rather than fabricate one
184
+ // (faithfulness: ALU never invents meaning resonance did not supply).
185
+ return opp ? { domain: "symbol", bytes: opp } : v;
186
+ }
187
+ if (v.domain === "bit")
188
+ return ctx.apply("not", [v]);
189
+ return ctx.apply("negate", [v]);
190
+ });
191
+ // reciprocal already registered as the multiplicative inverse primitive.
274
192
  }
275
193
  // ── exported array routines (derivations whose natural shape is arrays) ──────
276
194
  /** Horner evaluation of a polynomial whose coefficients run constant-first
277
195
  * (`coeffs[0]` is the constant term). Pure arithmetic over add/multiply. */
278
196
  export function polyEval(coeffs, x) {
279
- let acc = 0;
280
- for (let i = coeffs.length - 1; i >= 0; i--) {
281
- acc = acc * x + coeffs[i];
282
- }
283
- return acc;
197
+ let acc = 0;
198
+ for (let i = coeffs.length - 1; i >= 0; i--)
199
+ acc = acc * x + coeffs[i];
200
+ return acc;
284
201
  }
285
202
  /** Dot product of two equal-length vectors — a fold of add over multiply. */
286
203
  export function dot(a, b) {
287
- if (a.length !== b.length) {
288
- throw new Error("dot: length mismatch");
289
- }
290
- let s = 0;
291
- for (let i = 0; i < a.length; i++) {
292
- s += a[i] * b[i];
293
- }
294
- return s;
204
+ if (a.length !== b.length)
205
+ throw new Error("dot: length mismatch");
206
+ let s = 0;
207
+ for (let i = 0; i < a.length; i++)
208
+ s += a[i] * b[i];
209
+ return s;
295
210
  }
296
211
  /** Matrix · vector. */
297
212
  export function matVec(m, v) {
298
- return m.map((row) => dot(row, v));
213
+ return m.map((row) => dot(row, v));
299
214
  }
300
215
  /** Matrix · matrix. */
301
216
  export function matMul(a, b) {
302
- const n = a.length;
303
- const k = b.length;
304
- const p = b[0].length;
305
- const out = Array.from({ length: n }, () => new Array(p).fill(0));
306
- for (let i = 0; i < n; i++) {
307
- for (let j = 0; j < p; j++) {
308
- let s = 0;
309
- for (let t = 0; t < k; t++) {
310
- s += a[i][t] * b[t][j];
311
- }
312
- out[i][j] = s;
217
+ const n = a.length;
218
+ const k = b.length;
219
+ const p = b[0].length;
220
+ const out = Array.from({ length: n }, () => new Array(p).fill(0));
221
+ for (let i = 0; i < n; i++) {
222
+ for (let j = 0; j < p; j++) {
223
+ let s = 0;
224
+ for (let t = 0; t < k; t++)
225
+ s += a[i][t] * b[t][j];
226
+ out[i][j] = s;
227
+ }
313
228
  }
314
- }
315
- return out;
229
+ return out;
316
230
  }
317
231
  /** Solve A·x = b by Gaussian elimination with partial pivoting — structured
318
232
  * arithmetic (add / multiply / divide / compare for the pivot), not a new
319
233
  * primitive. Returns x, or null if A is singular to tolerance `tol`. */
320
234
  export function linsolve(A, b, tol = 1e-12) {
321
- const n = A.length;
322
- // Work on an augmented copy so the inputs are untouched.
323
- const M = A.map((row, i) => [...row, b[i]]);
324
- for (let col = 0; col < n; col++) {
325
- // Partial pivot: the row with the largest |value| in this column.
326
- let piv = col;
327
- for (let r = col + 1; r < n; r++) {
328
- if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) {
329
- piv = r;
330
- }
331
- }
332
- if (Math.abs(M[piv][col]) < tol) {
333
- return null; // singular
334
- }
335
- [M[col], M[piv]] = [M[piv], M[col]];
336
- // Eliminate below.
337
- for (let r = col + 1; r < n; r++) {
338
- const f = M[r][col] / M[col][col];
339
- for (let c = col; c <= n; c++) {
340
- M[r][c] -= f * M[col][c];
341
- }
235
+ const n = A.length;
236
+ // Work on an augmented copy so the inputs are untouched.
237
+ const M = A.map((row, i) => [...row, b[i]]);
238
+ for (let col = 0; col < n; col++) {
239
+ // Partial pivot: the row with the largest |value| in this column.
240
+ let piv = col;
241
+ for (let r = col + 1; r < n; r++) {
242
+ if (Math.abs(M[r][col]) > Math.abs(M[piv][col]))
243
+ piv = r;
244
+ }
245
+ if (Math.abs(M[piv][col]) < tol)
246
+ return null; // singular
247
+ [M[col], M[piv]] = [M[piv], M[col]];
248
+ // Eliminate below.
249
+ for (let r = col + 1; r < n; r++) {
250
+ const f = M[r][col] / M[col][col];
251
+ for (let c = col; c <= n; c++)
252
+ M[r][c] -= f * M[col][c];
253
+ }
342
254
  }
343
- }
344
- // Back-substitute.
345
- const x = new Array(n).fill(0);
346
- for (let i = n - 1; i >= 0; i--) {
347
- let s = M[i][n];
348
- for (let j = i + 1; j < n; j++) {
349
- s -= M[i][j] * x[j];
255
+ // Back-substitute.
256
+ const x = new Array(n).fill(0);
257
+ for (let i = n - 1; i >= 0; i--) {
258
+ let s = M[i][n];
259
+ for (let j = i + 1; j < n; j++)
260
+ s -= M[i][j] * x[j];
261
+ x[i] = s / M[i][i];
350
262
  }
351
- x[i] = s / M[i][i];
352
- }
353
- return x;
263
+ return x;
354
264
  }
@@ -12,11 +12,7 @@ export declare function mulBits(ctx: OpContext, a: bigint, b: bigint): bigint;
12
12
  export declare function signBits(ctx: OpContext, a: bigint): bigint;
13
13
  /** Compare via sign(subtract): −1 if a<b, 0 if a=b, +1 if a>b, where subtract is
14
14
  * add ∘ negate — so comparison is structured arithmetic, not a new primitive. */
15
- export declare function compareBits(
16
- ctx: OpContext,
17
- a: bigint,
18
- b: bigint,
19
- ): bigint;
15
+ export declare function compareBits(ctx: OpContext, a: bigint, b: bigint): bigint;
20
16
  /** Register the bit-bootstrap ops (int domain) into `r`. They have no surface
21
17
  * forms — they are an internal exhibit, exercised by the tests and by anyone
22
18
  * who wants to walk the nand→arithmetic chain, not matched from a query. */