@hviana/sema 0.1.3 → 0.1.5

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 (123) hide show
  1. package/dist/example/demo.js +25 -25
  2. package/dist/example/train_base.d.ts +21 -19
  3. package/dist/example/train_base.js +1952 -1684
  4. package/dist/src/alphabet.d.ts +3 -3
  5. package/dist/src/alphabet.js +27 -24
  6. package/dist/src/alu/src/alu.d.ts +194 -169
  7. package/dist/src/alu/src/alu.js +414 -374
  8. package/dist/src/alu/src/expr.d.ts +43 -36
  9. package/dist/src/alu/src/expr.js +278 -252
  10. package/dist/src/alu/src/index.d.ts +98 -9
  11. package/dist/src/alu/src/index.js +63 -9
  12. package/dist/src/alu/src/kernel-arith.d.ts +5 -1
  13. package/dist/src/alu/src/kernel-arith.js +285 -195
  14. package/dist/src/alu/src/kernel-bits.d.ts +5 -1
  15. package/dist/src/alu/src/kernel-bits.js +115 -81
  16. package/dist/src/alu/src/kernel-logic.js +63 -33
  17. package/dist/src/alu/src/kernel-nd.js +195 -155
  18. package/dist/src/alu/src/kernel-numeric.d.ts +80 -16
  19. package/dist/src/alu/src/kernel-numeric.js +331 -259
  20. package/dist/src/alu/src/operation.d.ts +132 -112
  21. package/dist/src/alu/src/operation.js +163 -149
  22. package/dist/src/alu/src/parser.d.ts +175 -168
  23. package/dist/src/alu/src/parser.js +421 -382
  24. package/dist/src/alu/src/resonance.d.ts +25 -16
  25. package/dist/src/alu/src/resonance.js +56 -49
  26. package/dist/src/alu/src/text.d.ts +7 -3
  27. package/dist/src/alu/src/text.js +37 -31
  28. package/dist/src/alu/src/value.d.ts +14 -14
  29. package/dist/src/alu/src/value.js +160 -150
  30. package/dist/src/alu/test/alu.test.js +656 -543
  31. package/dist/src/bytes.d.ts +5 -1
  32. package/dist/src/bytes.js +40 -33
  33. package/dist/src/config.d.ts +102 -102
  34. package/dist/src/config.js +83 -83
  35. package/dist/src/derive/src/deduction.d.ts +62 -60
  36. package/dist/src/derive/src/deduction.js +109 -103
  37. package/dist/src/derive/src/index.d.ts +7 -1
  38. package/dist/src/derive/src/priority-queue.d.ts +8 -8
  39. package/dist/src/derive/src/priority-queue.js +61 -57
  40. package/dist/src/derive/src/rewrite.d.ts +18 -15
  41. package/dist/src/derive/src/rewrite.js +67 -59
  42. package/dist/src/derive/src/trie.d.ts +56 -56
  43. package/dist/src/derive/src/trie.js +179 -175
  44. package/dist/src/derive/test/derive.test.js +100 -96
  45. package/dist/src/extension.d.ts +16 -13
  46. package/dist/src/geometry.d.ts +42 -17
  47. package/dist/src/geometry.js +266 -235
  48. package/dist/src/index.d.ts +17 -2
  49. package/dist/src/index.js +7 -1
  50. package/dist/src/ingest-cache.d.ts +30 -25
  51. package/dist/src/ingest-cache.js +127 -108
  52. package/dist/src/mind/articulation.d.ts +5 -1
  53. package/dist/src/mind/articulation.js +112 -77
  54. package/dist/src/mind/attention.d.ts +108 -40
  55. package/dist/src/mind/attention.js +871 -749
  56. package/dist/src/mind/canonical.d.ts +19 -4
  57. package/dist/src/mind/canonical.js +31 -27
  58. package/dist/src/mind/graph-search.d.ts +225 -201
  59. package/dist/src/mind/graph-search.js +821 -742
  60. package/dist/src/mind/index.d.ts +10 -2
  61. package/dist/src/mind/junction.d.ts +58 -31
  62. package/dist/src/mind/junction.js +237 -172
  63. package/dist/src/mind/learning.d.ts +52 -16
  64. package/dist/src/mind/learning.js +165 -143
  65. package/dist/src/mind/match.d.ts +69 -20
  66. package/dist/src/mind/match.js +318 -259
  67. package/dist/src/mind/mechanisms/alu.js +16 -16
  68. package/dist/src/mind/mechanisms/cast.d.ts +13 -9
  69. package/dist/src/mind/mechanisms/cast.js +456 -363
  70. package/dist/src/mind/mechanisms/confluence.d.ts +12 -8
  71. package/dist/src/mind/mechanisms/confluence.js +183 -152
  72. package/dist/src/mind/mechanisms/cover.d.ts +8 -2
  73. package/dist/src/mind/mechanisms/cover.js +210 -148
  74. package/dist/src/mind/mechanisms/extraction.d.ts +34 -8
  75. package/dist/src/mind/mechanisms/extraction.js +288 -234
  76. package/dist/src/mind/mechanisms/recall.d.ts +10 -6
  77. package/dist/src/mind/mechanisms/recall.js +185 -126
  78. package/dist/src/mind/mind.d.ts +154 -129
  79. package/dist/src/mind/mind.js +288 -258
  80. package/dist/src/mind/pipeline-mechanism.d.ts +124 -112
  81. package/dist/src/mind/pipeline-mechanism.js +172 -161
  82. package/dist/src/mind/pipeline.d.ts +14 -4
  83. package/dist/src/mind/pipeline.js +189 -125
  84. package/dist/src/mind/primitives.d.ts +32 -8
  85. package/dist/src/mind/primitives.js +117 -99
  86. package/dist/src/mind/rationale.d.ts +98 -86
  87. package/dist/src/mind/rationale.js +121 -113
  88. package/dist/src/mind/reasoning.d.ts +13 -2
  89. package/dist/src/mind/reasoning.js +166 -129
  90. package/dist/src/mind/recognition.d.ts +4 -1
  91. package/dist/src/mind/recognition.js +208 -183
  92. package/dist/src/mind/resonance.d.ts +22 -5
  93. package/dist/src/mind/resonance.js +0 -0
  94. package/dist/src/mind/trace.d.ts +25 -6
  95. package/dist/src/mind/trace.js +58 -50
  96. package/dist/src/mind/traverse.d.ts +58 -16
  97. package/dist/src/mind/traverse.js +357 -304
  98. package/dist/src/mind/types.d.ts +127 -120
  99. package/dist/src/mind/types.js +69 -60
  100. package/dist/src/rabitq-hnsw/src/database.d.ts +179 -177
  101. package/dist/src/rabitq-hnsw/src/database.js +359 -342
  102. package/dist/src/rabitq-hnsw/src/heap.d.ts +12 -12
  103. package/dist/src/rabitq-hnsw/src/heap.js +80 -75
  104. package/dist/src/rabitq-hnsw/src/hnsw.d.ts +103 -103
  105. package/dist/src/rabitq-hnsw/src/hnsw.js +454 -428
  106. package/dist/src/rabitq-hnsw/src/index.d.ts +6 -1
  107. package/dist/src/rabitq-hnsw/src/prng.d.ts +10 -10
  108. package/dist/src/rabitq-hnsw/src/prng.js +27 -25
  109. package/dist/src/rabitq-hnsw/src/rabitq.d.ts +69 -69
  110. package/dist/src/rabitq-hnsw/src/rabitq.js +262 -246
  111. package/dist/src/rabitq-hnsw/src/store.d.ts +132 -132
  112. package/dist/src/rabitq-hnsw/src/store.js +843 -752
  113. package/dist/src/rabitq-hnsw/test/hnsw.test.js +1054 -805
  114. package/dist/src/sema.d.ts +35 -0
  115. package/dist/src/sema.js +77 -0
  116. package/dist/src/store-sqlite.d.ts +166 -144
  117. package/dist/src/store-sqlite.js +660 -578
  118. package/dist/src/store.d.ts +630 -593
  119. package/dist/src/store.js +1581 -1440
  120. package/dist/src/vec.d.ts +9 -5
  121. package/dist/src/vec.js +73 -61
  122. package/package.json +2 -2
  123. package/src/sema.ts +102 -0
@@ -31,336 +31,408 @@ import { linsolve } from "./kernel-arith.js";
31
31
  * `maxIter` is reached. Returns the last iterate — the refinement's fixed
32
32
  * point. This is the single irreducible operator of the numerical layer. */
33
33
  export function converge(step, x0, tol, maxIter) {
34
- let x = x0;
35
- for (let i = 0; i < maxIter; i++) {
36
- const next = step(x);
37
- const scale = Math.max(1, Math.abs(next), Math.abs(x));
38
- if (Math.abs(next - x) <= tol * scale)
39
- return next;
40
- x = next;
34
+ let x = x0;
35
+ for (let i = 0; i < maxIter; i++) {
36
+ const next = step(x);
37
+ const scale = Math.max(1, Math.abs(next), Math.abs(x));
38
+ if (Math.abs(next - x) <= tol * scale) {
39
+ return next;
41
40
  }
42
- return x;
41
+ x = next;
42
+ }
43
+ return x;
43
44
  }
44
45
  /** Numerical derivative f′(a) by a central difference refined as h → 0 — a
45
46
  * `converge` instance over shrinking step sizes (Richardson-style halving). */
46
47
  export function diff(f, a, tol, maxIter) {
47
- let h = Math.max(1e-2, Math.abs(a) * 1e-2) || 1e-2;
48
- let prev = (f(a + h) - f(a - h)) / (2 * h);
49
- for (let i = 0; i < maxIter; i++) {
50
- h /= 2;
51
- const cur = (f(a + h) - f(a - h)) / (2 * h);
52
- const scale = Math.max(1, Math.abs(cur), Math.abs(prev));
53
- if (Math.abs(cur - prev) <= tol * scale)
54
- return cur;
55
- prev = cur;
56
- if (h < 1e-13)
57
- break; // floor: finer steps amplify round-off
48
+ let h = Math.max(1e-2, Math.abs(a) * 1e-2) || 1e-2;
49
+ let prev = (f(a + h) - f(a - h)) / (2 * h);
50
+ for (let i = 0; i < maxIter; i++) {
51
+ h /= 2;
52
+ const cur = (f(a + h) - f(a - h)) / (2 * h);
53
+ const scale = Math.max(1, Math.abs(cur), Math.abs(prev));
54
+ if (Math.abs(cur - prev) <= tol * scale) {
55
+ return cur;
58
56
  }
59
- return prev;
57
+ prev = cur;
58
+ if (h < 1e-13) {
59
+ break; // floor: finer steps amplify round-off
60
+ }
61
+ }
62
+ return prev;
60
63
  }
61
64
  /** A root of f near x0, by Newton's method: converge x − f(x)/f′(x), with f′
62
65
  * from {@link diff}. Falls back to a secant step if the derivative vanishes. */
63
66
  export function solve(f, x0, tol, maxIter) {
64
- return converge((x) => {
65
- const fx = f(x);
66
- let d = diff(f, x, tol, maxIter);
67
+ return converge(
68
+ (x) => {
69
+ const fx = f(x);
70
+ let d = diff(f, x, tol, maxIter);
71
+ if (Math.abs(d) < 1e-14) {
72
+ // Derivative ~0: nudge with a secant over a small offset.
73
+ const h = 1e-6 * (Math.abs(x) + 1);
74
+ d = (f(x + h) - fx) / h;
67
75
  if (Math.abs(d) < 1e-14) {
68
- // Derivative ~0: nudge with a secant over a small offset.
69
- const h = 1e-6 * (Math.abs(x) + 1);
70
- d = (f(x + h) - fx) / h;
71
- if (Math.abs(d) < 1e-14)
72
- return x;
76
+ return x;
73
77
  }
74
- return x - fx / d;
75
- }, x0, tol, maxIter);
78
+ }
79
+ return x - fx / d;
80
+ },
81
+ x0,
82
+ tol,
83
+ maxIter,
84
+ );
76
85
  }
77
86
  /** Definite integral of f over [a, b], by composite Simpson refined until the
78
87
  * estimate stops moving — a `converge` over partition count. */
79
88
  export function integrate(f, a, b, tol, maxIter) {
80
- const simpson = (n) => {
81
- const h = (b - a) / n;
82
- let s = f(a) + f(b);
83
- for (let i = 1; i < n; i++)
84
- s += (i % 2 === 0 ? 2 : 4) * f(a + i * h);
85
- return (s * h) / 3;
86
- };
87
- let n = 2;
88
- let prev = simpson(n);
89
- for (let i = 0; i < maxIter; i++) {
90
- n *= 2;
91
- const cur = simpson(n);
92
- const scale = Math.max(1, Math.abs(cur), Math.abs(prev));
93
- if (Math.abs(cur - prev) <= tol * scale)
94
- return cur;
95
- prev = cur;
89
+ const simpson = (n) => {
90
+ const h = (b - a) / n;
91
+ let s = f(a) + f(b);
92
+ for (let i = 1; i < n; i++) {
93
+ s += (i % 2 === 0 ? 2 : 4) * f(a + i * h);
94
+ }
95
+ return (s * h) / 3;
96
+ };
97
+ let n = 2;
98
+ let prev = simpson(n);
99
+ for (let i = 0; i < maxIter; i++) {
100
+ n *= 2;
101
+ const cur = simpson(n);
102
+ const scale = Math.max(1, Math.abs(cur), Math.abs(prev));
103
+ if (Math.abs(cur - prev) <= tol * scale) {
104
+ return cur;
96
105
  }
97
- return prev;
106
+ prev = cur;
107
+ }
108
+ return prev;
98
109
  }
99
110
  /** e^x by its Taylor series, summed until a term is below tolerance — a
100
111
  * `converge` over partial sums. (Range-reduction-free; adequate for the
101
112
  * arguments a query produces, and exact in the limit.) */
102
113
  export function expSeries(x, tol, maxIter) {
103
- let term = 1;
104
- let sum = 1;
105
- for (let n = 1; n < maxIter; n++) {
106
- term *= x / n;
107
- sum += term;
108
- if (Math.abs(term) <= tol * Math.max(1, Math.abs(sum)))
109
- break;
114
+ let term = 1;
115
+ let sum = 1;
116
+ for (let n = 1; n < maxIter; n++) {
117
+ term *= x / n;
118
+ sum += term;
119
+ if (Math.abs(term) <= tol * Math.max(1, Math.abs(sum))) {
120
+ break;
110
121
  }
111
- return sum;
122
+ }
123
+ return sum;
112
124
  }
113
125
  /** ln(x), x > 0, as the root of e^t − x = 0 (Newton via {@link solve}, with a
114
126
  * good initial guess from the host log to keep iteration counts low). */
115
127
  export function logNewton(x, tol, maxIter) {
116
- if (x <= 0)
117
- return NaN;
118
- return solve((t) => expSeries(t, tol, maxIter) - x, Math.log(x), tol, maxIter);
128
+ if (x <= 0) {
129
+ return NaN;
130
+ }
131
+ return solve(
132
+ (t) => expSeries(t, tol, maxIter) - x,
133
+ Math.log(x),
134
+ tol,
135
+ maxIter,
136
+ );
119
137
  }
120
138
  /** sin / cos by their Taylor series (a `converge` over partial sums), with
121
139
  * argument reduction into [−π, π] for accuracy. */
122
140
  export function sinSeries(x, tol, maxIter) {
123
- const TWO_PI = 2 * Math.PI;
124
- let a = x % TWO_PI;
125
- if (a > Math.PI)
126
- a -= TWO_PI;
127
- if (a < -Math.PI)
128
- a += TWO_PI;
129
- let term = a;
130
- let sum = a;
131
- for (let n = 1; n < maxIter; n++) {
132
- term *= (-a * a) / ((2 * n) * (2 * n + 1));
133
- sum += term;
134
- if (Math.abs(term) <= tol)
135
- break;
141
+ const TWO_PI = 2 * Math.PI;
142
+ let a = x % TWO_PI;
143
+ if (a > Math.PI) {
144
+ a -= TWO_PI;
145
+ }
146
+ if (a < -Math.PI) {
147
+ a += TWO_PI;
148
+ }
149
+ let term = a;
150
+ let sum = a;
151
+ for (let n = 1; n < maxIter; n++) {
152
+ term *= (-a * a) / ((2 * n) * (2 * n + 1));
153
+ sum += term;
154
+ if (Math.abs(term) <= tol) {
155
+ break;
136
156
  }
137
- return sum;
157
+ }
158
+ return sum;
138
159
  }
139
160
  export function cosSeries(x, tol, maxIter) {
140
- const TWO_PI = 2 * Math.PI;
141
- let a = x % TWO_PI;
142
- if (a > Math.PI)
143
- a -= TWO_PI;
144
- if (a < -Math.PI)
145
- a += TWO_PI;
146
- let term = 1;
147
- let sum = 1;
148
- for (let n = 1; n < maxIter; n++) {
149
- term *= (-a * a) / ((2 * n - 1) * (2 * n));
150
- sum += term;
151
- if (Math.abs(term) <= tol)
152
- break;
161
+ const TWO_PI = 2 * Math.PI;
162
+ let a = x % TWO_PI;
163
+ if (a > Math.PI) {
164
+ a -= TWO_PI;
165
+ }
166
+ if (a < -Math.PI) {
167
+ a += TWO_PI;
168
+ }
169
+ let term = 1;
170
+ let sum = 1;
171
+ for (let n = 1; n < maxIter; n++) {
172
+ term *= (-a * a) / ((2 * n - 1) * (2 * n));
173
+ sum += term;
174
+ if (Math.abs(term) <= tol) {
175
+ break;
153
176
  }
154
- return sum;
177
+ }
178
+ return sum;
155
179
  }
156
180
  /** √x as the positive root of t² − x = 0 (Newton via {@link solve}). */
157
181
  export function sqrtNewton(x, tol, maxIter) {
158
- if (x < 0)
159
- return NaN;
160
- if (x === 0)
161
- return 0;
162
- return solve((t) => t * t - x, Math.max(x, 1), tol, maxIter);
182
+ if (x < 0) {
183
+ return NaN;
184
+ }
185
+ if (x === 0) {
186
+ return 0;
187
+ }
188
+ return solve((t) => t * t - x, Math.max(x, 1), tol, maxIter);
163
189
  }
164
190
  /** A local minimum of f near x0: a root of f′ = 0 (optimize = solve(diff f)). */
165
191
  export function optimize(f, x0, tol, maxIter) {
166
- return solve((x) => diff(f, x, tol, maxIter), x0, tol, maxIter);
192
+ return solve((x) => diff(f, x, tol, maxIter), x0, tol, maxIter);
167
193
  }
168
194
  /** Integrate an ODE y′ = f(t, y) from (t0, y0) to t1 by classical RK4 stepping
169
195
  * — explicit stepping is the layer's other use of refinement (here a fixed
170
196
  * fine step; an implicit step would close with {@link solve}). */
171
197
  export function odeSolve(f, t0, y0, t1, steps = 1000) {
172
- const h = (t1 - t0) / steps;
173
- let t = t0;
174
- let y = y0;
175
- for (let i = 0; i < steps; i++) {
176
- const k1 = f(t, y);
177
- const k2 = f(t + h / 2, y + (h / 2) * k1);
178
- const k3 = f(t + h / 2, y + (h / 2) * k2);
179
- const k4 = f(t + h, y + h * k3);
180
- y += (h / 6) * (k1 + 2 * k2 + 2 * k3 + k4);
181
- t += h;
182
- }
183
- return y;
198
+ const h = (t1 - t0) / steps;
199
+ let t = t0;
200
+ let y = y0;
201
+ for (let i = 0; i < steps; i++) {
202
+ const k1 = f(t, y);
203
+ const k2 = f(t + h / 2, y + (h / 2) * k1);
204
+ const k3 = f(t + h / 2, y + (h / 2) * k2);
205
+ const k4 = f(t + h, y + h * k3);
206
+ y += (h / 6) * (k1 + 2 * k2 + 2 * k3 + k4);
207
+ t += h;
208
+ }
209
+ return y;
184
210
  }
185
211
  /** Least-squares polynomial regression of degree `deg` over (x, y) samples:
186
212
  * build the normal equations and solve them with {@link linsolve} — regression
187
213
  * reduces to structured arithmetic. Returns coefficients constant-first. */
188
214
  export function regress(xs, ys, deg) {
189
- const m = deg + 1;
190
- // Vandermonde-style normal matrix AᵀA and vector Aᵀy.
191
- const ata = Array.from({ length: m }, () => new Array(m).fill(0));
192
- const aty = new Array(m).fill(0);
193
- for (let s = 0; s < xs.length; s++) {
194
- const pows = new Array(2 * deg + 1);
195
- pows[0] = 1;
196
- for (let p = 1; p <= 2 * deg; p++)
197
- pows[p] = pows[p - 1] * xs[s];
198
- for (let i = 0; i < m; i++) {
199
- for (let j = 0; j < m; j++)
200
- ata[i][j] += pows[i + j];
201
- aty[i] += pows[i] * ys[s];
202
- }
215
+ const m = deg + 1;
216
+ // Vandermonde-style normal matrix AᵀA and vector Aᵀy.
217
+ const ata = Array.from({ length: m }, () => new Array(m).fill(0));
218
+ const aty = new Array(m).fill(0);
219
+ for (let s = 0; s < xs.length; s++) {
220
+ const pows = new Array(2 * deg + 1);
221
+ pows[0] = 1;
222
+ for (let p = 1; p <= 2 * deg; p++) {
223
+ pows[p] = pows[p - 1] * xs[s];
224
+ }
225
+ for (let i = 0; i < m; i++) {
226
+ for (let j = 0; j < m; j++) {
227
+ ata[i][j] += pows[i + j];
228
+ }
229
+ aty[i] += pows[i] * ys[s];
203
230
  }
204
- return linsolve(ata, aty);
231
+ }
232
+ return linsolve(ata, aty);
205
233
  }
206
234
  /** Linear interpolation of y at `xq` over sorted sample points (xs, ys). */
207
235
  export function interpolate(xs, ys, xq) {
208
- if (xq <= xs[0])
209
- return ys[0];
210
- const n = xs.length;
211
- if (xq >= xs[n - 1])
212
- return ys[n - 1];
213
- for (let i = 0; i < n - 1; i++) {
214
- if (xq >= xs[i] && xq <= xs[i + 1]) {
215
- const t = (xq - xs[i]) / (xs[i + 1] - xs[i]);
216
- return ys[i] + t * (ys[i + 1] - ys[i]);
217
- }
218
- }
236
+ if (xq <= xs[0]) {
237
+ return ys[0];
238
+ }
239
+ const n = xs.length;
240
+ if (xq >= xs[n - 1]) {
219
241
  return ys[n - 1];
242
+ }
243
+ for (let i = 0; i < n - 1; i++) {
244
+ if (xq >= xs[i] && xq <= xs[i + 1]) {
245
+ const t = (xq - xs[i]) / (xs[i + 1] - xs[i]);
246
+ return ys[i] + t * (ys[i + 1] - ys[i]);
247
+ }
248
+ }
249
+ return ys[n - 1];
220
250
  }
221
251
  /** Dominant eigenpair of a (preferably symmetric) matrix by POWER ITERATION —
222
252
  * the canonical "iteration = converge" of this layer. Returns the eigenvalue
223
253
  * (Rayleigh quotient) and its unit eigenvector. */
224
254
  export function powerEig(A, tol, maxIter) {
225
- const n = A.length;
226
- // Start from a normalised all-ones vector: deterministic (no PRNG), and
227
- // generically NOT aligned with any single eigenvector of a diagonal/symmetric
228
- // matrix, so iteration is not trapped on a non-dominant axis (a unit basis
229
- // vector would be, e.g. e₀ is fixed under diag(9,16) and converges to the
230
- // wrong eigenvalue).
231
- let v = new Array(n).fill(1 / Math.sqrt(n));
232
- let lambda = 0;
233
- for (let it = 0; it < maxIter; it++) {
234
- // w = A v
235
- const w = A.map((row) => row.reduce((s, a, j) => s + a * v[j], 0));
236
- const norm = Math.sqrt(w.reduce((s, x) => s + x * x, 0)) || 1;
237
- const vn = w.map((x) => x / norm);
238
- // Rayleigh quotient vᵀAv.
239
- const Av = A.map((row) => row.reduce((s, a, j) => s + a * vn[j], 0));
240
- const lam = vn.reduce((s, x, i) => s + x * Av[i], 0);
241
- if (Math.abs(lam - lambda) <= tol * Math.max(1, Math.abs(lam))) {
242
- return { value: lam, vector: vn };
243
- }
244
- lambda = lam;
245
- v = vn;
255
+ const n = A.length;
256
+ // Start from a normalised all-ones vector: deterministic (no PRNG), and
257
+ // generically NOT aligned with any single eigenvector of a diagonal/symmetric
258
+ // matrix, so iteration is not trapped on a non-dominant axis (a unit basis
259
+ // vector would be, e.g. e₀ is fixed under diag(9,16) and converges to the
260
+ // wrong eigenvalue).
261
+ let v = new Array(n).fill(1 / Math.sqrt(n));
262
+ let lambda = 0;
263
+ for (let it = 0; it < maxIter; it++) {
264
+ // w = A v
265
+ const w = A.map((row) => row.reduce((s, a, j) => s + a * v[j], 0));
266
+ const norm = Math.sqrt(w.reduce((s, x) => s + x * x, 0)) || 1;
267
+ const vn = w.map((x) => x / norm);
268
+ // Rayleigh quotient vᵀAv.
269
+ const Av = A.map((row) => row.reduce((s, a, j) => s + a * vn[j], 0));
270
+ const lam = vn.reduce((s, x, i) => s + x * Av[i], 0);
271
+ if (Math.abs(lam - lambda) <= tol * Math.max(1, Math.abs(lam))) {
272
+ return { value: lam, vector: vn };
246
273
  }
247
- return { value: lambda, vector: v };
274
+ lambda = lam;
275
+ v = vn;
276
+ }
277
+ return { value: lambda, vector: v };
248
278
  }
249
279
  /** Largest singular value of A: √(dominant eigenvalue of AᵀA) — power iteration
250
280
  * again, the prototypical `converge`. */
251
281
  export function topSingular(A, tol, maxIter) {
252
- const n = A[0].length;
253
- // AᵀA (n×n).
254
- const ata = Array.from({ length: n }, () => new Array(n).fill(0));
255
- for (let i = 0; i < n; i++) {
256
- for (let j = 0; j < n; j++) {
257
- let s = 0;
258
- for (let r = 0; r < A.length; r++)
259
- s += A[r][i] * A[r][j];
260
- ata[i][j] = s;
261
- }
282
+ const n = A[0].length;
283
+ // AᵀA (n×n).
284
+ const ata = Array.from({ length: n }, () => new Array(n).fill(0));
285
+ for (let i = 0; i < n; i++) {
286
+ for (let j = 0; j < n; j++) {
287
+ let s = 0;
288
+ for (let r = 0; r < A.length; r++) {
289
+ s += A[r][i] * A[r][j];
290
+ }
291
+ ata[i][j] = s;
262
292
  }
263
- const { value } = powerEig(ata, tol, maxIter);
264
- return Math.sqrt(Math.max(0, value));
293
+ }
294
+ const { value } = powerEig(ata, tol, maxIter);
295
+ return Math.sqrt(Math.max(0, value));
265
296
  }
266
297
  /** Register the scalar transcendentals as ops (they have surface forms). The
267
298
  * matrix routines stay exported functions — there is no infix surface for a
268
299
  * matrix, and auto-firing them from query spans is neither wanted nor safe. */
269
300
  export function registerNumeric(r) {
270
- const one = (name, forms, f) => {
271
- r.derive(name, 1, forms, (args, ctx) => real(f(asReal(args[0]), ctx.rt.tol, ctx.rt.maxIter)));
272
- };
273
- one("exp", ["exp", "e^"], expSeries);
274
- // ── named constants ───────────────────────────────────────────────────────
275
- // Nullary ops, so a constant is RESOLVED like any operation (registry forms),
276
- // never special-cased by a parser: the expression grammar reads "an arity-0
277
- // op" as "a constant" generically.
278
- r.derive("pi", 0, ["pi", "π"], () => real(Math.PI));
279
- r.derive("euler", 0, ["e"], () => real(Math.E));
280
- one("log", ["log", "ln"], logNewton);
281
- one("sin", ["sin"], sinSeries);
282
- one("cos", ["cos"], cosSeries);
283
- one("sqrt", ["sqrt", ""], sqrtNewton);
284
- // ── operations over an EXPRESSION (the recursive-call case) ───────────────
285
- // A derivative, an integral, a limit, an optimisation — these act on a
286
- // FUNCTION, given as a symbol (the expression's bytes) plus point/bounds. The
287
- // function is sampled by ctx.evalExpr, which evaluates the expression by a
288
- // RECURSIVE application of the same ALU (see expr.ts). Their surface `forms`
289
- // are CONCEPT forms words a query might literally carry ("derivative",
290
- // "integral", "limit") but the GENERIC, modality-agnostic recognition is by
291
- // resonance over these same concepts (pipeline.ts's recogniseOp), so an operation
292
- // the bytes do not spell at all is still recognised by meaning. These ops
293
- // decline (return their first operand unchanged is wrong; instead they throw,
294
- // which the Alu facade maps to "rule does not fire") when no evaluator is
295
- // wired or the expression is unparseable synthesis stays evidence-based.
296
- const exprOf = (v) => {
297
- if (v.domain === "symbol")
298
- return v.bytes;
299
- // A bare number is a constant expression encode it back to bytes so the
300
- // evaluator sees a literal.
301
- throw new Error("expression operand expected");
302
- };
303
- const evalAt = (ctx, expr, vbl, at) => {
304
- if (!ctx.evalExpr)
305
- throw new Error("no expression evaluator");
306
- const y = ctx.evalExpr(expr, vbl, at);
307
- if (y === null || !Number.isFinite(y))
308
- throw new Error("expression failed");
309
- return y;
301
+ const one = (name, forms, f) => {
302
+ r.derive(
303
+ name,
304
+ 1,
305
+ forms,
306
+ (args, ctx) => real(f(asReal(args[0]), ctx.rt.tol, ctx.rt.maxIter)),
307
+ );
308
+ };
309
+ one("exp", ["exp", "e^"], expSeries);
310
+ // ── named constants ───────────────────────────────────────────────────────
311
+ // Nullary ops, so a constant is RESOLVED like any operation (registry forms),
312
+ // never special-cased by a parser: the expression grammar reads "an arity-0
313
+ // op" as "a constant" generically.
314
+ r.derive("pi", 0, ["pi", "π"], () => real(Math.PI));
315
+ r.derive("euler", 0, ["e"], () => real(Math.E));
316
+ one("log", ["log", "ln"], logNewton);
317
+ one("sin", ["sin"], sinSeries);
318
+ one("cos", ["cos"], cosSeries);
319
+ one("sqrt", ["sqrt", "√"], sqrtNewton);
320
+ // ── operations over an EXPRESSION (the recursive-call case) ───────────────
321
+ // A derivative, an integral, a limit, an optimisation these act on a
322
+ // FUNCTION, given as a symbol (the expression's bytes) plus point/bounds. The
323
+ // function is sampled by ctx.evalExpr, which evaluates the expression by a
324
+ // RECURSIVE application of the same ALU (see expr.ts). Their surface `forms`
325
+ // are CONCEPT forms words a query might literally carry ("derivative",
326
+ // "integral", "limit") but the GENERIC, modality-agnostic recognition is by
327
+ // resonance over these same concepts (pipeline.ts's recogniseOp), so an operation
328
+ // the bytes do not spell at all is still recognised by meaning. These ops
329
+ // decline (return their first operand unchanged is wrong; instead they throw,
330
+ // which the Alu facade maps to "rule does not fire") when no evaluator is
331
+ // wired or the expression is unparseable — synthesis stays evidence-based.
332
+ const exprOf = (v) => {
333
+ if (v.domain === "symbol") {
334
+ return v.bytes;
335
+ }
336
+ // A bare number is a constant expression — encode it back to bytes so the
337
+ // evaluator sees a literal.
338
+ throw new Error("expression operand expected");
339
+ };
340
+ const evalAt = (ctx, expr, vbl, at) => {
341
+ if (!ctx.evalExpr) {
342
+ throw new Error("no expression evaluator");
343
+ }
344
+ const y = ctx.evalExpr(expr, vbl, at);
345
+ if (y === null || !Number.isFinite(y)) {
346
+ throw new Error("expression failed");
347
+ }
348
+ return y;
349
+ };
350
+ // diff: derivative of f at a point. args = [expr, at].
351
+ r.derive(
352
+ "diff",
353
+ 2,
354
+ ["derivative", "differentiate", "d/dx", "diff"],
355
+ (args, ctx) => {
356
+ const expr = exprOf(args[0]);
357
+ const at = asReal(args[1]);
358
+ return real(
359
+ diff((x) => evalAt(ctx, expr, "", x), at, ctx.rt.tol, ctx.rt.maxIter),
360
+ );
361
+ },
362
+ { expression: true },
363
+ );
364
+ // integrate: definite integral of f over [a, b]. args = [expr, a, b].
365
+ r.derive("integrate", 3, ["integral", "integrate", "∫"], (args, ctx) => {
366
+ const expr = exprOf(args[0]);
367
+ const a = asReal(args[1]);
368
+ const b = asReal(args[2]);
369
+ return real(
370
+ integrate(
371
+ (x) => evalAt(ctx, expr, "", x),
372
+ a,
373
+ b,
374
+ ctx.rt.tol,
375
+ ctx.rt.maxIter,
376
+ ),
377
+ );
378
+ }, { expression: true });
379
+ // solve: a root of f near a guess. args = [expr, guess].
380
+ r.derive("solve", 2, ["solve", "root", "zero"], (args, ctx) => {
381
+ const expr = exprOf(args[0]);
382
+ const guess = asReal(args[1]);
383
+ return real(
384
+ solve((x) => evalAt(ctx, expr, "", x), guess, ctx.rt.tol, ctx.rt.maxIter),
385
+ );
386
+ }, { expression: true });
387
+ // limit: the value f approaches as its variable → a, estimated by sampling
388
+ // ever closer from both sides and converging (a limit IS a converge instance).
389
+ r.derive("limit", 2, ["limit", "lim"], (args, ctx) => {
390
+ const expr = exprOf(args[0]);
391
+ const a = asReal(args[1]);
392
+ const sample = (h) => {
393
+ // average of the two one-sided samples, skirting the point itself
394
+ const left = evalAt(ctx, expr, "", a - h);
395
+ const right = evalAt(ctx, expr, "", a + h);
396
+ return (left + right) / 2;
310
397
  };
311
- // diff: derivative of f at a point. args = [expr, at].
312
- r.derive("diff", 2, ["derivative", "differentiate", "d/dx", "diff"], (args, ctx) => {
313
- const expr = exprOf(args[0]);
314
- const at = asReal(args[1]);
315
- return real(diff((x) => evalAt(ctx, expr, "", x), at, ctx.rt.tol, ctx.rt.maxIter));
316
- }, { expression: true });
317
- // integrate: definite integral of f over [a, b]. args = [expr, a, b].
318
- r.derive("integrate", 3, ["integral", "integrate", "∫"], (args, ctx) => {
319
- const expr = exprOf(args[0]);
320
- const a = asReal(args[1]);
321
- const b = asReal(args[2]);
322
- return real(integrate((x) => evalAt(ctx, expr, "", x), a, b, ctx.rt.tol, ctx.rt.maxIter));
323
- }, { expression: true });
324
- // solve: a root of f near a guess. args = [expr, guess].
325
- r.derive("solve", 2, ["solve", "root", "zero"], (args, ctx) => {
326
- const expr = exprOf(args[0]);
327
- const guess = asReal(args[1]);
328
- return real(solve((x) => evalAt(ctx, expr, "", x), guess, ctx.rt.tol, ctx.rt.maxIter));
329
- }, { expression: true });
330
- // limit: the value f approaches as its variable → a, estimated by sampling
331
- // ever closer from both sides and converging (a limit IS a converge instance).
332
- r.derive("limit", 2, ["limit", "lim"], (args, ctx) => {
333
- const expr = exprOf(args[0]);
334
- const a = asReal(args[1]);
335
- const sample = (h) => {
336
- // average of the two one-sided samples, skirting the point itself
337
- const left = evalAt(ctx, expr, "", a - h);
338
- const right = evalAt(ctx, expr, "", a + h);
339
- return (left + right) / 2;
340
- };
341
- let h = 0.1;
342
- let prev = sample(h);
343
- for (let i = 0; i < ctx.rt.maxIter; i++) {
344
- h /= 2;
345
- const cur = sample(h);
346
- const scale = Math.max(1, Math.abs(cur), Math.abs(prev));
347
- if (Math.abs(cur - prev) <= ctx.rt.tol * scale)
348
- return real(cur);
349
- prev = cur;
350
- if (h < 1e-13)
351
- break;
352
- }
353
- return real(prev);
354
- }, { expression: true });
355
- // optimize: a local minimiser of f near a guess (= solve(diff f)). args =
356
- // [expr, guess].
357
- r.derive("optimize", 2, ["minimize", "minimise", "optimize", "argmin"], (args, ctx) => {
358
- const expr = exprOf(args[0]);
359
- const guess = asReal(args[1]);
360
- return real(optimize((x) => evalAt(ctx, expr, "", x), guess, ctx.rt.tol, ctx.rt.maxIter));
361
- }, { expression: true });
362
- // converge and the matrix routines (regress, eig, svd, interpolate) take
363
- // FUNCTION or ARRAY operands with no flat infix surface; they are offered
364
- // through the pure exports above and used internally (e.g. sqrt = solve(t²−x),
365
- // optimize = solve(diff f)).
398
+ let h = 0.1;
399
+ let prev = sample(h);
400
+ for (let i = 0; i < ctx.rt.maxIter; i++) {
401
+ h /= 2;
402
+ const cur = sample(h);
403
+ const scale = Math.max(1, Math.abs(cur), Math.abs(prev));
404
+ if (Math.abs(cur - prev) <= ctx.rt.tol * scale) {
405
+ return real(cur);
406
+ }
407
+ prev = cur;
408
+ if (h < 1e-13) {
409
+ break;
410
+ }
411
+ }
412
+ return real(prev);
413
+ }, { expression: true });
414
+ // optimize: a local minimiser of f near a guess (= solve(diff f)). args =
415
+ // [expr, guess].
416
+ r.derive(
417
+ "optimize",
418
+ 2,
419
+ ["minimize", "minimise", "optimize", "argmin"],
420
+ (args, ctx) => {
421
+ const expr = exprOf(args[0]);
422
+ const guess = asReal(args[1]);
423
+ return real(
424
+ optimize(
425
+ (x) => evalAt(ctx, expr, "", x),
426
+ guess,
427
+ ctx.rt.tol,
428
+ ctx.rt.maxIter,
429
+ ),
430
+ );
431
+ },
432
+ { expression: true },
433
+ );
434
+ // converge and the matrix routines (regress, eig, svd, interpolate) take
435
+ // FUNCTION or ARRAY operands with no flat infix surface; they are offered
436
+ // through the pure exports above and used internally (e.g. sqrt = solve(t²−x),
437
+ // optimize = solve(diff f)).
366
438
  }