@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.
- package/AGENTS.md +6 -5
- package/CITATION.cff +49 -0
- package/HOW_IT_WORKS.md +11 -12
- package/README.md +7 -5
- package/dist/example/demo.js +25 -25
- package/dist/example/train_base.d.ts +19 -21
- package/dist/example/train_base.js +1687 -1952
- package/dist/src/alphabet.d.ts +3 -3
- package/dist/src/alphabet.js +24 -27
- package/dist/src/alu/src/alu.d.ts +169 -194
- package/dist/src/alu/src/alu.js +374 -414
- package/dist/src/alu/src/expr.d.ts +36 -43
- package/dist/src/alu/src/expr.js +252 -278
- package/dist/src/alu/src/index.d.ts +9 -98
- package/dist/src/alu/src/index.js +10 -64
- package/dist/src/alu/src/kernel-arith.d.ts +1 -5
- package/dist/src/alu/src/kernel-arith.js +195 -285
- package/dist/src/alu/src/kernel-bits.d.ts +1 -5
- package/dist/src/alu/src/kernel-bits.js +81 -115
- package/dist/src/alu/src/kernel-logic.js +33 -63
- package/dist/src/alu/src/kernel-nd.js +155 -195
- package/dist/src/alu/src/kernel-numeric.d.ts +16 -80
- package/dist/src/alu/src/kernel-numeric.js +259 -331
- package/dist/src/alu/src/operation.d.ts +112 -132
- package/dist/src/alu/src/operation.js +149 -163
- package/dist/src/alu/src/parser.d.ts +168 -175
- package/dist/src/alu/src/parser.js +382 -421
- package/dist/src/alu/src/resonance.d.ts +16 -25
- package/dist/src/alu/src/resonance.js +49 -56
- package/dist/src/alu/src/text.d.ts +3 -7
- package/dist/src/alu/src/text.js +31 -37
- package/dist/src/alu/src/value.d.ts +14 -14
- package/dist/src/alu/src/value.js +150 -160
- package/dist/src/alu/test/alu.test.js +543 -656
- package/dist/src/bytes.d.ts +1 -5
- package/dist/src/bytes.js +33 -40
- package/dist/src/config.d.ts +99 -102
- package/dist/src/config.js +78 -83
- package/dist/src/derive/src/deduction.d.ts +60 -62
- package/dist/src/derive/src/deduction.js +103 -109
- package/dist/src/derive/src/index.d.ts +1 -7
- package/dist/src/derive/src/priority-queue.d.ts +8 -8
- package/dist/src/derive/src/priority-queue.js +57 -61
- package/dist/src/derive/src/rewrite.d.ts +15 -18
- package/dist/src/derive/src/rewrite.js +59 -67
- package/dist/src/derive/src/trie.d.ts +56 -56
- package/dist/src/derive/src/trie.js +175 -179
- package/dist/src/derive/test/derive.test.js +96 -100
- package/dist/src/extension.d.ts +13 -16
- package/dist/src/geometry.d.ts +17 -42
- package/dist/src/geometry.js +235 -266
- package/dist/src/index.d.ts +2 -17
- package/dist/src/index.js +2 -12
- package/dist/src/ingest-cache.d.ts +25 -30
- package/dist/src/ingest-cache.js +108 -127
- package/dist/src/mind/articulation.d.ts +1 -5
- package/dist/src/mind/articulation.js +77 -112
- package/dist/src/mind/attention.d.ts +40 -108
- package/dist/src/mind/attention.js +749 -871
- package/dist/src/mind/canonical.d.ts +4 -19
- package/dist/src/mind/canonical.js +27 -31
- package/dist/src/mind/graph-search.d.ts +201 -225
- package/dist/src/mind/graph-search.js +742 -821
- package/dist/src/mind/index.d.ts +2 -10
- package/dist/src/mind/junction.d.ts +31 -58
- package/dist/src/mind/junction.js +172 -237
- package/dist/src/mind/learning.d.ts +16 -52
- package/dist/src/mind/learning.js +143 -165
- package/dist/src/mind/match.d.ts +20 -69
- package/dist/src/mind/match.js +259 -318
- package/dist/src/mind/mechanisms/alu.js +16 -16
- package/dist/src/mind/mechanisms/cast.d.ts +9 -13
- package/dist/src/mind/mechanisms/cast.js +363 -456
- package/dist/src/mind/mechanisms/confluence.d.ts +8 -12
- package/dist/src/mind/mechanisms/confluence.js +152 -183
- package/dist/src/mind/mechanisms/cover.d.ts +2 -8
- package/dist/src/mind/mechanisms/cover.js +148 -210
- package/dist/src/mind/mechanisms/extraction.d.ts +8 -34
- package/dist/src/mind/mechanisms/extraction.js +234 -288
- package/dist/src/mind/mechanisms/recall.d.ts +6 -10
- package/dist/src/mind/mechanisms/recall.js +126 -185
- package/dist/src/mind/mind.d.ts +129 -154
- package/dist/src/mind/mind.js +258 -288
- package/dist/src/mind/pipeline-mechanism.d.ts +112 -124
- package/dist/src/mind/pipeline-mechanism.js +161 -172
- package/dist/src/mind/pipeline.d.ts +4 -14
- package/dist/src/mind/pipeline.js +125 -189
- package/dist/src/mind/primitives.d.ts +8 -32
- package/dist/src/mind/primitives.js +99 -117
- package/dist/src/mind/rationale.d.ts +86 -98
- package/dist/src/mind/rationale.js +113 -121
- package/dist/src/mind/reasoning.d.ts +2 -13
- package/dist/src/mind/reasoning.js +129 -166
- package/dist/src/mind/recognition.d.ts +1 -4
- package/dist/src/mind/recognition.js +183 -208
- package/dist/src/mind/resonance.d.ts +5 -22
- package/dist/src/mind/resonance.js +0 -0
- package/dist/src/mind/trace.d.ts +6 -25
- package/dist/src/mind/trace.js +50 -58
- package/dist/src/mind/traverse.d.ts +16 -58
- package/dist/src/mind/traverse.js +304 -357
- package/dist/src/mind/types.d.ts +120 -127
- package/dist/src/mind/types.js +60 -69
- package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
- package/dist/src/rabitq-ivf/src/database.js +201 -0
- package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
- package/dist/src/{rabitq-hnsw → rabitq-ivf}/src/index.js +1 -3
- package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
- package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
- package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
- package/dist/src/rabitq-ivf/src/prng.js +36 -0
- package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
- package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
- package/dist/src/sema.d.ts +9 -13
- package/dist/src/sema.js +26 -40
- package/dist/src/store-sqlite.d.ts +169 -166
- package/dist/src/store-sqlite.js +762 -662
- package/dist/src/store.d.ts +586 -630
- package/dist/src/store.js +1423 -1581
- package/dist/src/vec.d.ts +5 -9
- package/dist/src/vec.js +61 -73
- package/example/train_base.ts +13 -10
- package/package.json +1 -1
- package/src/alu/README.md +1 -1
- package/src/alu/src/index.ts +1 -1
- package/src/config.ts +19 -27
- package/src/index.ts +6 -11
- package/src/rabitq-ivf/README.md +56 -0
- package/src/rabitq-ivf/src/database.ts +276 -0
- package/src/{rabitq-hnsw → rabitq-ivf}/src/index.ts +2 -5
- package/src/rabitq-ivf/src/ivf.ts +1330 -0
- package/src/{rabitq-hnsw → rabitq-ivf}/src/prng.ts +1 -1
- package/src/store-sqlite.ts +196 -9
- package/src/store.ts +8 -32
- package/test/08-storage.test.mjs +3 -3
- package/test/14-scaling.test.mjs +2 -2
- package/test/35-ivf.test.mjs +263 -0
- package/test/36-bloom.test.mjs +123 -0
- package/dist/src/rabitq-hnsw/src/database.d.ts +0 -202
- package/dist/src/rabitq-hnsw/src/database.js +0 -405
- package/dist/src/rabitq-hnsw/src/heap.d.ts +0 -22
- package/dist/src/rabitq-hnsw/src/heap.js +0 -94
- package/dist/src/rabitq-hnsw/src/hnsw.d.ts +0 -125
- package/dist/src/rabitq-hnsw/src/hnsw.js +0 -500
- package/dist/src/rabitq-hnsw/src/index.d.ts +0 -15
- package/dist/src/rabitq-hnsw/src/prng.d.ts +0 -19
- package/dist/src/rabitq-hnsw/src/prng.js +0 -38
- package/dist/src/rabitq-hnsw/src/rabitq.d.ts +0 -95
- package/dist/src/rabitq-hnsw/src/rabitq.js +0 -299
- package/dist/src/rabitq-hnsw/src/store.d.ts +0 -162
- package/dist/src/rabitq-hnsw/src/store.js +0 -916
- package/dist/src/rabitq-hnsw/test/hnsw.test.d.ts +0 -1
- package/dist/src/rabitq-hnsw/test/hnsw.test.js +0 -1197
- package/src/rabitq-hnsw/README.md +0 -303
- package/src/rabitq-hnsw/src/database.ts +0 -492
- package/src/rabitq-hnsw/src/heap.ts +0 -90
- package/src/rabitq-hnsw/src/hnsw.ts +0 -514
- package/src/rabitq-hnsw/src/store.ts +0 -994
- package/src/rabitq-hnsw/test/hnsw.test.ts +0 -1213
- /package/src/{rabitq-hnsw → rabitq-ivf}/src/rabitq.ts +0 -0
|
@@ -31,408 +31,336 @@ 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
|
-
|
|
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;
|
|
40
41
|
}
|
|
41
|
-
x
|
|
42
|
-
}
|
|
43
|
-
return x;
|
|
42
|
+
return x;
|
|
44
43
|
}
|
|
45
44
|
/** Numerical derivative f′(a) by a central difference refined as h → 0 — a
|
|
46
45
|
* `converge` instance over shrinking step sizes (Richardson-style halving). */
|
|
47
46
|
export function diff(f, a, tol, maxIter) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
56
58
|
}
|
|
57
|
-
prev
|
|
58
|
-
if (h < 1e-13) {
|
|
59
|
-
break; // floor: finer steps amplify round-off
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return prev;
|
|
59
|
+
return prev;
|
|
63
60
|
}
|
|
64
61
|
/** A root of f near x0, by Newton's method: converge x − f(x)/f′(x), with f′
|
|
65
62
|
* from {@link diff}. Falls back to a secant step if the derivative vanishes. */
|
|
66
63
|
export function solve(f, x0, tol, maxIter) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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;
|
|
64
|
+
return converge((x) => {
|
|
65
|
+
const fx = f(x);
|
|
66
|
+
let d = diff(f, x, tol, maxIter);
|
|
75
67
|
if (Math.abs(d) < 1e-14) {
|
|
76
|
-
|
|
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;
|
|
77
73
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
},
|
|
81
|
-
x0,
|
|
82
|
-
tol,
|
|
83
|
-
maxIter,
|
|
84
|
-
);
|
|
74
|
+
return x - fx / d;
|
|
75
|
+
}, x0, tol, maxIter);
|
|
85
76
|
}
|
|
86
77
|
/** Definite integral of f over [a, b], by composite Simpson refined until the
|
|
87
78
|
* estimate stops moving — a `converge` over partition count. */
|
|
88
79
|
export function integrate(f, a, b, tol, maxIter) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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;
|
|
105
96
|
}
|
|
106
|
-
prev
|
|
107
|
-
}
|
|
108
|
-
return prev;
|
|
97
|
+
return prev;
|
|
109
98
|
}
|
|
110
99
|
/** e^x by its Taylor series, summed until a term is below tolerance — a
|
|
111
100
|
* `converge` over partial sums. (Range-reduction-free; adequate for the
|
|
112
101
|
* arguments a query produces, and exact in the limit.) */
|
|
113
102
|
export function expSeries(x, tol, maxIter) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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;
|
|
121
110
|
}
|
|
122
|
-
|
|
123
|
-
return sum;
|
|
111
|
+
return sum;
|
|
124
112
|
}
|
|
125
113
|
/** ln(x), x > 0, as the root of e^t − x = 0 (Newton via {@link solve}, with a
|
|
126
114
|
* good initial guess from the host log to keep iteration counts low). */
|
|
127
115
|
export function logNewton(x, tol, maxIter) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return solve(
|
|
132
|
-
(t) => expSeries(t, tol, maxIter) - x,
|
|
133
|
-
Math.log(x),
|
|
134
|
-
tol,
|
|
135
|
-
maxIter,
|
|
136
|
-
);
|
|
116
|
+
if (x <= 0)
|
|
117
|
+
return NaN;
|
|
118
|
+
return solve((t) => expSeries(t, tol, maxIter) - x, Math.log(x), tol, maxIter);
|
|
137
119
|
}
|
|
138
120
|
/** sin / cos by their Taylor series (a `converge` over partial sums), with
|
|
139
121
|
* argument reduction into [−π, π] for accuracy. */
|
|
140
122
|
export function sinSeries(x, tol, maxIter) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (Math.abs(term) <= tol) {
|
|
155
|
-
break;
|
|
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;
|
|
156
136
|
}
|
|
157
|
-
|
|
158
|
-
return sum;
|
|
137
|
+
return sum;
|
|
159
138
|
}
|
|
160
139
|
export function cosSeries(x, tol, maxIter) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (Math.abs(term) <= tol) {
|
|
175
|
-
break;
|
|
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;
|
|
176
153
|
}
|
|
177
|
-
|
|
178
|
-
return sum;
|
|
154
|
+
return sum;
|
|
179
155
|
}
|
|
180
156
|
/** √x as the positive root of t² − x = 0 (Newton via {@link solve}). */
|
|
181
157
|
export function sqrtNewton(x, tol, maxIter) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return
|
|
187
|
-
}
|
|
188
|
-
return solve((t) => t * t - x, Math.max(x, 1), 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);
|
|
189
163
|
}
|
|
190
164
|
/** A local minimum of f near x0: a root of f′ = 0 (optimize = solve(diff f)). */
|
|
191
165
|
export function optimize(f, x0, tol, maxIter) {
|
|
192
|
-
|
|
166
|
+
return solve((x) => diff(f, x, tol, maxIter), x0, tol, maxIter);
|
|
193
167
|
}
|
|
194
168
|
/** Integrate an ODE y′ = f(t, y) from (t0, y0) to t1 by classical RK4 stepping
|
|
195
169
|
* — explicit stepping is the layer's other use of refinement (here a fixed
|
|
196
170
|
* fine step; an implicit step would close with {@link solve}). */
|
|
197
171
|
export function odeSolve(f, t0, y0, t1, steps = 1000) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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;
|
|
210
184
|
}
|
|
211
185
|
/** Least-squares polynomial regression of degree `deg` over (x, y) samples:
|
|
212
186
|
* build the normal equations and solve them with {@link linsolve} — regression
|
|
213
187
|
* reduces to structured arithmetic. Returns coefficients constant-first. */
|
|
214
188
|
export function regress(xs, ys, deg) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
aty[i] += pows[i] * ys[s];
|
|
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
|
+
}
|
|
230
203
|
}
|
|
231
|
-
|
|
232
|
-
return linsolve(ata, aty);
|
|
204
|
+
return linsolve(ata, aty);
|
|
233
205
|
}
|
|
234
206
|
/** Linear interpolation of y at `xq` over sorted sample points (xs, ys). */
|
|
235
207
|
export function interpolate(xs, ys, xq) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return ys[i] + t * (ys[i + 1] - ys[i]);
|
|
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
|
+
}
|
|
247
218
|
}
|
|
248
|
-
|
|
249
|
-
return ys[n - 1];
|
|
219
|
+
return ys[n - 1];
|
|
250
220
|
}
|
|
251
221
|
/** Dominant eigenpair of a (preferably symmetric) matrix by POWER ITERATION —
|
|
252
222
|
* the canonical "iteration = converge" of this layer. Returns the eigenvalue
|
|
253
223
|
* (Rayleigh quotient) and its unit eigenvector. */
|
|
254
224
|
export function powerEig(A, tol, maxIter) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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;
|
|
273
246
|
}
|
|
274
|
-
lambda
|
|
275
|
-
v = vn;
|
|
276
|
-
}
|
|
277
|
-
return { value: lambda, vector: v };
|
|
247
|
+
return { value: lambda, vector: v };
|
|
278
248
|
}
|
|
279
249
|
/** Largest singular value of A: √(dominant eigenvalue of AᵀA) — power iteration
|
|
280
250
|
* again, the prototypical `converge`. */
|
|
281
251
|
export function topSingular(A, tol, maxIter) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
+
}
|
|
292
262
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
return Math.sqrt(Math.max(0, value));
|
|
263
|
+
const { value } = powerEig(ata, tol, maxIter);
|
|
264
|
+
return Math.sqrt(Math.max(0, value));
|
|
296
265
|
}
|
|
297
266
|
/** Register the scalar transcendentals as ops (they have surface forms). The
|
|
298
267
|
* matrix routines stay exported functions — there is no infix surface for a
|
|
299
268
|
* matrix, and auto-firing them from query spans is neither wanted nor safe. */
|
|
300
269
|
export function registerNumeric(r) {
|
|
301
|
-
|
|
302
|
-
|
|
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;
|
|
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)));
|
|
397
272
|
};
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
)
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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;
|
|
310
|
+
};
|
|
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)).
|
|
438
366
|
}
|