@hviana/sema 0.1.4 → 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.
- package/dist/example/demo.js +25 -25
- package/dist/example/train_base.d.ts +21 -19
- package/dist/example/train_base.js +1952 -1684
- package/dist/src/alphabet.d.ts +3 -3
- package/dist/src/alphabet.js +27 -24
- package/dist/src/alu/src/alu.d.ts +194 -169
- package/dist/src/alu/src/alu.js +414 -374
- package/dist/src/alu/src/expr.d.ts +43 -36
- package/dist/src/alu/src/expr.js +278 -252
- package/dist/src/alu/src/index.d.ts +98 -9
- package/dist/src/alu/src/index.js +63 -9
- package/dist/src/alu/src/kernel-arith.d.ts +5 -1
- package/dist/src/alu/src/kernel-arith.js +285 -195
- package/dist/src/alu/src/kernel-bits.d.ts +5 -1
- package/dist/src/alu/src/kernel-bits.js +115 -81
- package/dist/src/alu/src/kernel-logic.js +63 -33
- package/dist/src/alu/src/kernel-nd.js +195 -155
- package/dist/src/alu/src/kernel-numeric.d.ts +80 -16
- package/dist/src/alu/src/kernel-numeric.js +331 -259
- package/dist/src/alu/src/operation.d.ts +132 -112
- package/dist/src/alu/src/operation.js +163 -149
- package/dist/src/alu/src/parser.d.ts +175 -168
- package/dist/src/alu/src/parser.js +421 -382
- package/dist/src/alu/src/resonance.d.ts +25 -16
- package/dist/src/alu/src/resonance.js +56 -49
- package/dist/src/alu/src/text.d.ts +7 -3
- package/dist/src/alu/src/text.js +37 -31
- package/dist/src/alu/src/value.d.ts +14 -14
- package/dist/src/alu/src/value.js +160 -150
- package/dist/src/alu/test/alu.test.js +656 -543
- package/dist/src/bytes.d.ts +5 -1
- package/dist/src/bytes.js +40 -33
- package/dist/src/config.d.ts +102 -102
- package/dist/src/config.js +83 -83
- package/dist/src/derive/src/deduction.d.ts +62 -60
- package/dist/src/derive/src/deduction.js +109 -103
- package/dist/src/derive/src/index.d.ts +7 -1
- package/dist/src/derive/src/priority-queue.d.ts +8 -8
- package/dist/src/derive/src/priority-queue.js +61 -57
- package/dist/src/derive/src/rewrite.d.ts +18 -15
- package/dist/src/derive/src/rewrite.js +67 -59
- package/dist/src/derive/src/trie.d.ts +56 -56
- package/dist/src/derive/src/trie.js +179 -175
- package/dist/src/derive/test/derive.test.js +100 -96
- package/dist/src/extension.d.ts +16 -13
- package/dist/src/geometry.d.ts +42 -17
- package/dist/src/geometry.js +266 -235
- package/dist/src/index.d.ts +17 -2
- package/dist/src/index.js +7 -1
- package/dist/src/ingest-cache.d.ts +30 -25
- package/dist/src/ingest-cache.js +127 -108
- package/dist/src/mind/articulation.d.ts +5 -1
- package/dist/src/mind/articulation.js +112 -77
- package/dist/src/mind/attention.d.ts +108 -40
- package/dist/src/mind/attention.js +871 -749
- package/dist/src/mind/canonical.d.ts +19 -4
- package/dist/src/mind/canonical.js +31 -27
- package/dist/src/mind/graph-search.d.ts +225 -201
- package/dist/src/mind/graph-search.js +821 -742
- package/dist/src/mind/index.d.ts +10 -2
- package/dist/src/mind/junction.d.ts +58 -31
- package/dist/src/mind/junction.js +237 -172
- package/dist/src/mind/learning.d.ts +52 -16
- package/dist/src/mind/learning.js +165 -143
- package/dist/src/mind/match.d.ts +69 -20
- package/dist/src/mind/match.js +318 -259
- package/dist/src/mind/mechanisms/alu.js +16 -16
- package/dist/src/mind/mechanisms/cast.d.ts +13 -9
- package/dist/src/mind/mechanisms/cast.js +456 -363
- package/dist/src/mind/mechanisms/confluence.d.ts +12 -8
- package/dist/src/mind/mechanisms/confluence.js +183 -152
- package/dist/src/mind/mechanisms/cover.d.ts +8 -2
- package/dist/src/mind/mechanisms/cover.js +210 -148
- package/dist/src/mind/mechanisms/extraction.d.ts +34 -8
- package/dist/src/mind/mechanisms/extraction.js +288 -234
- package/dist/src/mind/mechanisms/recall.d.ts +10 -6
- package/dist/src/mind/mechanisms/recall.js +185 -126
- package/dist/src/mind/mind.d.ts +154 -129
- package/dist/src/mind/mind.js +288 -258
- package/dist/src/mind/pipeline-mechanism.d.ts +124 -112
- package/dist/src/mind/pipeline-mechanism.js +172 -161
- package/dist/src/mind/pipeline.d.ts +14 -4
- package/dist/src/mind/pipeline.js +189 -125
- package/dist/src/mind/primitives.d.ts +32 -8
- package/dist/src/mind/primitives.js +117 -99
- package/dist/src/mind/rationale.d.ts +98 -86
- package/dist/src/mind/rationale.js +121 -113
- package/dist/src/mind/reasoning.d.ts +13 -2
- package/dist/src/mind/reasoning.js +166 -129
- package/dist/src/mind/recognition.d.ts +4 -1
- package/dist/src/mind/recognition.js +208 -183
- package/dist/src/mind/resonance.d.ts +22 -5
- package/dist/src/mind/resonance.js +0 -0
- package/dist/src/mind/trace.d.ts +25 -6
- package/dist/src/mind/trace.js +58 -50
- package/dist/src/mind/traverse.d.ts +58 -16
- package/dist/src/mind/traverse.js +357 -304
- package/dist/src/mind/types.d.ts +127 -120
- package/dist/src/mind/types.js +69 -60
- package/dist/src/rabitq-hnsw/src/database.d.ts +179 -177
- package/dist/src/rabitq-hnsw/src/database.js +359 -342
- package/dist/src/rabitq-hnsw/src/heap.d.ts +12 -12
- package/dist/src/rabitq-hnsw/src/heap.js +80 -75
- package/dist/src/rabitq-hnsw/src/hnsw.d.ts +103 -103
- package/dist/src/rabitq-hnsw/src/hnsw.js +454 -428
- package/dist/src/rabitq-hnsw/src/index.d.ts +6 -1
- package/dist/src/rabitq-hnsw/src/prng.d.ts +10 -10
- package/dist/src/rabitq-hnsw/src/prng.js +27 -25
- package/dist/src/rabitq-hnsw/src/rabitq.d.ts +69 -69
- package/dist/src/rabitq-hnsw/src/rabitq.js +262 -246
- package/dist/src/rabitq-hnsw/src/store.d.ts +132 -132
- package/dist/src/rabitq-hnsw/src/store.js +843 -752
- package/dist/src/rabitq-hnsw/test/hnsw.test.js +1054 -805
- package/dist/src/sema.d.ts +13 -9
- package/dist/src/sema.js +40 -26
- package/dist/src/store-sqlite.d.ts +166 -144
- package/dist/src/store-sqlite.js +660 -578
- package/dist/src/store.d.ts +630 -593
- package/dist/src/store.js +1581 -1440
- package/dist/src/vec.d.ts +9 -5
- package/dist/src/vec.js +73 -61
- package/package.json +2 -2
|
@@ -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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
157
|
+
}
|
|
158
|
+
return sum;
|
|
138
159
|
}
|
|
139
160
|
export function cosSeries(x, tol, maxIter) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
264
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
}
|