regressio 0.0.1 → 1.0.1
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/README.md +19 -12
- package/dist/index.cjs +398 -44
- package/dist/index.d.cts +4 -32
- package/dist/index.d.ts +4 -32
- package/dist/index.js +188 -82
- package/dist/regressio_wasm_bg-vab4kvnm.wasm +0 -0
- package/dist/shared/chunk-0ebx6ns2.js +214 -0
- package/dist/shared/chunk-0sb1tn3y.js +42 -0
- package/package.json +12 -5
package/README.md
CHANGED
|
@@ -297,27 +297,34 @@ console.log(C.trace()); // 5
|
|
|
297
297
|
console.log(C.transpose().toArray());
|
|
298
298
|
```
|
|
299
299
|
|
|
300
|
-
## WASM
|
|
300
|
+
## WASM Acceleration
|
|
301
301
|
|
|
302
|
-
|
|
302
|
+
regressio ships with a pre-compiled Rust/WASM engine that activates automatically — no configuration needed. When the WASM binary is available, heavy computations are dispatched to compiled Rust code for significantly faster execution.
|
|
303
303
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
304
|
+
**Accelerated operations:**
|
|
305
|
+
- Matrix: multiply, transpose, add, subtract, scale, dot product, norm, determinant
|
|
306
|
+
- Decompositions: QR, Cholesky, SVD, eigenvalues
|
|
307
|
+
- Solvers: forward/back substitution
|
|
308
|
+
- Models: Lasso/Elastic Net coordinate descent, softmax, KNN distance matrices
|
|
309
|
+
|
|
310
|
+
If WASM is unavailable (e.g. unsupported runtime), all operations fall back silently to pure TypeScript.
|
|
307
311
|
|
|
308
312
|
```typescript
|
|
309
|
-
import {
|
|
313
|
+
import { isWasmActive } from 'regressio';
|
|
310
314
|
|
|
311
|
-
//
|
|
312
|
-
await useWasmEngine();
|
|
313
|
-
console.log(isWasmActive()); // true
|
|
315
|
+
console.log(isWasmActive()); // true if WASM loaded
|
|
314
316
|
|
|
315
|
-
//
|
|
317
|
+
// Everything just works — WASM is used transparently
|
|
316
318
|
const model = new LinearRegression();
|
|
317
319
|
model.fit(X, y); // QR decomposition runs in Rust
|
|
320
|
+
```
|
|
318
321
|
|
|
319
|
-
|
|
320
|
-
|
|
322
|
+
### Rebuilding WASM
|
|
323
|
+
|
|
324
|
+
The pre-built WASM binary is included in the package. To rebuild from Rust source (requires [Rust](https://rustup.rs/) with `wasm32-unknown-unknown` target):
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
bun run build:wasm
|
|
321
328
|
```
|
|
322
329
|
|
|
323
330
|
## License
|
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,220 @@ var __export = (target, all) => {
|
|
|
38
38
|
};
|
|
39
39
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
40
40
|
|
|
41
|
+
// pkg/regressio_wasm_bg.wasm
|
|
42
|
+
var exports_regressio_wasm_bg = {};
|
|
43
|
+
__export(exports_regressio_wasm_bg, {
|
|
44
|
+
default: () => regressio_wasm_bg_default
|
|
45
|
+
});
|
|
46
|
+
var regressio_wasm_bg_default = "./regressio_wasm_bg-vab4kvnm.wasm";
|
|
47
|
+
var init_regressio_wasm_bg = () => {};
|
|
48
|
+
|
|
49
|
+
// pkg/regressio_wasm_bg.js
|
|
50
|
+
function cholesky(data, n) {
|
|
51
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
52
|
+
const len0 = WASM_VECTOR_LEN;
|
|
53
|
+
const ret = wasm.cholesky(ptr0, len0, n);
|
|
54
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
55
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
56
|
+
return v2;
|
|
57
|
+
}
|
|
58
|
+
function coordinate_descent(x, y, alpha, l1_ratio, max_iter, tolerance, n, p, fit_intercept) {
|
|
59
|
+
const ptr0 = passArrayF64ToWasm0(x, wasm.__wbindgen_malloc);
|
|
60
|
+
const len0 = WASM_VECTOR_LEN;
|
|
61
|
+
const ptr1 = passArrayF64ToWasm0(y, wasm.__wbindgen_malloc);
|
|
62
|
+
const len1 = WASM_VECTOR_LEN;
|
|
63
|
+
const ret = wasm.coordinate_descent(ptr0, len0, ptr1, len1, alpha, l1_ratio, max_iter, tolerance, n, p, fit_intercept);
|
|
64
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
65
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
66
|
+
return v3;
|
|
67
|
+
}
|
|
68
|
+
function determinant(data, n) {
|
|
69
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
70
|
+
const len0 = WASM_VECTOR_LEN;
|
|
71
|
+
const ret = wasm.determinant(ptr0, len0, n);
|
|
72
|
+
return ret;
|
|
73
|
+
}
|
|
74
|
+
function eigenvalues(data, n) {
|
|
75
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
76
|
+
const len0 = WASM_VECTOR_LEN;
|
|
77
|
+
const ret = wasm.eigenvalues(ptr0, len0, n);
|
|
78
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
79
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
80
|
+
return v2;
|
|
81
|
+
}
|
|
82
|
+
function euclidean_distances(train, test, n_train, n_test, dim) {
|
|
83
|
+
const ptr0 = passArrayF64ToWasm0(train, wasm.__wbindgen_malloc);
|
|
84
|
+
const len0 = WASM_VECTOR_LEN;
|
|
85
|
+
const ptr1 = passArrayF64ToWasm0(test, wasm.__wbindgen_malloc);
|
|
86
|
+
const len1 = WASM_VECTOR_LEN;
|
|
87
|
+
const ret = wasm.euclidean_distances(ptr0, len0, ptr1, len1, n_train, n_test, dim);
|
|
88
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
89
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
90
|
+
return v3;
|
|
91
|
+
}
|
|
92
|
+
function forward_substitution(l, b, n) {
|
|
93
|
+
const ptr0 = passArrayF64ToWasm0(l, wasm.__wbindgen_malloc);
|
|
94
|
+
const len0 = WASM_VECTOR_LEN;
|
|
95
|
+
const ptr1 = passArrayF64ToWasm0(b, wasm.__wbindgen_malloc);
|
|
96
|
+
const len1 = WASM_VECTOR_LEN;
|
|
97
|
+
const ret = wasm.forward_substitution(ptr0, len0, ptr1, len1, n);
|
|
98
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
99
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
100
|
+
return v3;
|
|
101
|
+
}
|
|
102
|
+
function frobenius_norm(a) {
|
|
103
|
+
const ptr0 = passArrayF64ToWasm0(a, wasm.__wbindgen_malloc);
|
|
104
|
+
const len0 = WASM_VECTOR_LEN;
|
|
105
|
+
const ret = wasm.frobenius_norm(ptr0, len0);
|
|
106
|
+
return ret;
|
|
107
|
+
}
|
|
108
|
+
function manhattan_distances(train, test, n_train, n_test, dim) {
|
|
109
|
+
const ptr0 = passArrayF64ToWasm0(train, wasm.__wbindgen_malloc);
|
|
110
|
+
const len0 = WASM_VECTOR_LEN;
|
|
111
|
+
const ptr1 = passArrayF64ToWasm0(test, wasm.__wbindgen_malloc);
|
|
112
|
+
const len1 = WASM_VECTOR_LEN;
|
|
113
|
+
const ret = wasm.manhattan_distances(ptr0, len0, ptr1, len1, n_train, n_test, dim);
|
|
114
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
115
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
116
|
+
return v3;
|
|
117
|
+
}
|
|
118
|
+
function matrix_add(a, b) {
|
|
119
|
+
const ptr0 = passArrayF64ToWasm0(a, wasm.__wbindgen_malloc);
|
|
120
|
+
const len0 = WASM_VECTOR_LEN;
|
|
121
|
+
const ptr1 = passArrayF64ToWasm0(b, wasm.__wbindgen_malloc);
|
|
122
|
+
const len1 = WASM_VECTOR_LEN;
|
|
123
|
+
const ret = wasm.matrix_add(ptr0, len0, ptr1, len1);
|
|
124
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
125
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
126
|
+
return v3;
|
|
127
|
+
}
|
|
128
|
+
function matrix_multiply(a, a_rows, a_cols, b, b_rows, b_cols) {
|
|
129
|
+
const ptr0 = passArrayF64ToWasm0(a, wasm.__wbindgen_malloc);
|
|
130
|
+
const len0 = WASM_VECTOR_LEN;
|
|
131
|
+
const ptr1 = passArrayF64ToWasm0(b, wasm.__wbindgen_malloc);
|
|
132
|
+
const len1 = WASM_VECTOR_LEN;
|
|
133
|
+
const ret = wasm.matrix_multiply(ptr0, len0, a_rows, a_cols, ptr1, len1, b_rows, b_cols);
|
|
134
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
135
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
136
|
+
return v3;
|
|
137
|
+
}
|
|
138
|
+
function matrix_scale(a, scalar) {
|
|
139
|
+
const ptr0 = passArrayF64ToWasm0(a, wasm.__wbindgen_malloc);
|
|
140
|
+
const len0 = WASM_VECTOR_LEN;
|
|
141
|
+
const ret = wasm.matrix_scale(ptr0, len0, scalar);
|
|
142
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
143
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
144
|
+
return v2;
|
|
145
|
+
}
|
|
146
|
+
function matrix_subtract(a, b) {
|
|
147
|
+
const ptr0 = passArrayF64ToWasm0(a, wasm.__wbindgen_malloc);
|
|
148
|
+
const len0 = WASM_VECTOR_LEN;
|
|
149
|
+
const ptr1 = passArrayF64ToWasm0(b, wasm.__wbindgen_malloc);
|
|
150
|
+
const len1 = WASM_VECTOR_LEN;
|
|
151
|
+
const ret = wasm.matrix_subtract(ptr0, len0, ptr1, len1);
|
|
152
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
153
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
154
|
+
return v3;
|
|
155
|
+
}
|
|
156
|
+
function matrix_transpose(data, rows, cols) {
|
|
157
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
158
|
+
const len0 = WASM_VECTOR_LEN;
|
|
159
|
+
const ret = wasm.matrix_transpose(ptr0, len0, rows, cols);
|
|
160
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
161
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
162
|
+
return v2;
|
|
163
|
+
}
|
|
164
|
+
function qr_decompose(data, rows, cols) {
|
|
165
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
166
|
+
const len0 = WASM_VECTOR_LEN;
|
|
167
|
+
const ret = wasm.qr_decompose(ptr0, len0, rows, cols);
|
|
168
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
169
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
170
|
+
return v2;
|
|
171
|
+
}
|
|
172
|
+
function softmax_rows(data, rows, cols) {
|
|
173
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
174
|
+
const len0 = WASM_VECTOR_LEN;
|
|
175
|
+
const ret = wasm.softmax_rows(ptr0, len0, rows, cols);
|
|
176
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
177
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
178
|
+
return v2;
|
|
179
|
+
}
|
|
180
|
+
function solve_triangular(r, b, n) {
|
|
181
|
+
const ptr0 = passArrayF64ToWasm0(r, wasm.__wbindgen_malloc);
|
|
182
|
+
const len0 = WASM_VECTOR_LEN;
|
|
183
|
+
const ptr1 = passArrayF64ToWasm0(b, wasm.__wbindgen_malloc);
|
|
184
|
+
const len1 = WASM_VECTOR_LEN;
|
|
185
|
+
const ret = wasm.solve_triangular(ptr0, len0, ptr1, len1, n);
|
|
186
|
+
var v3 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
187
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
188
|
+
return v3;
|
|
189
|
+
}
|
|
190
|
+
function svd(data, rows, cols) {
|
|
191
|
+
const ptr0 = passArrayF64ToWasm0(data, wasm.__wbindgen_malloc);
|
|
192
|
+
const len0 = WASM_VECTOR_LEN;
|
|
193
|
+
const ret = wasm.svd(ptr0, len0, rows, cols);
|
|
194
|
+
var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
|
|
195
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
196
|
+
return v2;
|
|
197
|
+
}
|
|
198
|
+
function vector_dot(a, b) {
|
|
199
|
+
const ptr0 = passArrayF64ToWasm0(a, wasm.__wbindgen_malloc);
|
|
200
|
+
const len0 = WASM_VECTOR_LEN;
|
|
201
|
+
const ptr1 = passArrayF64ToWasm0(b, wasm.__wbindgen_malloc);
|
|
202
|
+
const len1 = WASM_VECTOR_LEN;
|
|
203
|
+
const ret = wasm.vector_dot(ptr0, len0, ptr1, len1);
|
|
204
|
+
return ret;
|
|
205
|
+
}
|
|
206
|
+
function getArrayF64FromWasm0(ptr, len) {
|
|
207
|
+
ptr = ptr >>> 0;
|
|
208
|
+
return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
209
|
+
}
|
|
210
|
+
function getFloat64ArrayMemory0() {
|
|
211
|
+
if (cachedFloat64ArrayMemory0 === null || cachedFloat64ArrayMemory0.byteLength === 0) {
|
|
212
|
+
cachedFloat64ArrayMemory0 = new Float64Array(wasm.memory.buffer);
|
|
213
|
+
}
|
|
214
|
+
return cachedFloat64ArrayMemory0;
|
|
215
|
+
}
|
|
216
|
+
function passArrayF64ToWasm0(arg, malloc) {
|
|
217
|
+
const ptr = malloc(arg.length * 8, 8) >>> 0;
|
|
218
|
+
getFloat64ArrayMemory0().set(arg, ptr / 8);
|
|
219
|
+
WASM_VECTOR_LEN = arg.length;
|
|
220
|
+
return ptr;
|
|
221
|
+
}
|
|
222
|
+
function __wbg_set_wasm(val) {
|
|
223
|
+
wasm = val;
|
|
224
|
+
}
|
|
225
|
+
var cachedFloat64ArrayMemory0 = null, WASM_VECTOR_LEN = 0, wasm;
|
|
226
|
+
|
|
227
|
+
// pkg/regressio_wasm.js
|
|
228
|
+
var exports_regressio_wasm = {};
|
|
229
|
+
__export(exports_regressio_wasm, {
|
|
230
|
+
vector_dot: () => vector_dot,
|
|
231
|
+
svd: () => svd,
|
|
232
|
+
solve_triangular: () => solve_triangular,
|
|
233
|
+
softmax_rows: () => softmax_rows,
|
|
234
|
+
qr_decompose: () => qr_decompose,
|
|
235
|
+
matrix_transpose: () => matrix_transpose,
|
|
236
|
+
matrix_subtract: () => matrix_subtract,
|
|
237
|
+
matrix_scale: () => matrix_scale,
|
|
238
|
+
matrix_multiply: () => matrix_multiply,
|
|
239
|
+
matrix_add: () => matrix_add,
|
|
240
|
+
manhattan_distances: () => manhattan_distances,
|
|
241
|
+
frobenius_norm: () => frobenius_norm,
|
|
242
|
+
forward_substitution: () => forward_substitution,
|
|
243
|
+
euclidean_distances: () => euclidean_distances,
|
|
244
|
+
eigenvalues: () => eigenvalues,
|
|
245
|
+
determinant: () => determinant,
|
|
246
|
+
coordinate_descent: () => coordinate_descent,
|
|
247
|
+
cholesky: () => cholesky
|
|
248
|
+
});
|
|
249
|
+
var init_regressio_wasm = __esm(() => {
|
|
250
|
+
init_regressio_wasm_bg();
|
|
251
|
+
__wbg_set_wasm(exports_regressio_wasm_bg);
|
|
252
|
+
undefined();
|
|
253
|
+
});
|
|
254
|
+
|
|
41
255
|
// src/core/distributions.ts
|
|
42
256
|
var exports_distributions = {};
|
|
43
257
|
__export(exports_distributions, {
|
|
@@ -330,9 +544,6 @@ var init_distributions = __esm(() => {
|
|
|
330
544
|
var exports_src = {};
|
|
331
545
|
__export(exports_src, {
|
|
332
546
|
vif: () => vif,
|
|
333
|
-
useWasmModule: () => useWasmModule,
|
|
334
|
-
useWasmEngine: () => useWasmEngine,
|
|
335
|
-
useTypescriptEngine: () => useTypescriptEngine,
|
|
336
547
|
unstandardize: () => unstandardize,
|
|
337
548
|
unnormalize: () => unnormalize,
|
|
338
549
|
studentizedResiduals: () => studentizedResiduals,
|
|
@@ -348,7 +559,6 @@ __export(exports_src, {
|
|
|
348
559
|
interactionFeatures: () => interactionFeatures,
|
|
349
560
|
imputeMedian: () => imputeMedian,
|
|
350
561
|
imputeMean: () => imputeMean,
|
|
351
|
-
getEngine: () => getEngine,
|
|
352
562
|
durbinWatson: () => durbinWatson,
|
|
353
563
|
dropMissing: () => dropMissing,
|
|
354
564
|
correlationMatrix: () => correlationMatrix,
|
|
@@ -374,26 +584,14 @@ module.exports = __toCommonJS(exports_src);
|
|
|
374
584
|
|
|
375
585
|
// src/core/engine.ts
|
|
376
586
|
var currentEngine = { name: "typescript" };
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
587
|
+
Promise.resolve().then(() => (init_regressio_wasm(), exports_regressio_wasm)).then((wasm2) => {
|
|
588
|
+
if (currentEngine.name === "typescript") {
|
|
589
|
+
currentEngine = { name: "wasm", wasm: wasm2 };
|
|
590
|
+
}
|
|
591
|
+
}).catch(() => {});
|
|
380
592
|
function isWasmActive() {
|
|
381
593
|
return currentEngine.name === "wasm" && currentEngine.wasm != null;
|
|
382
594
|
}
|
|
383
|
-
async function useWasmEngine() {
|
|
384
|
-
try {
|
|
385
|
-
const wasm = await import("../../pkg");
|
|
386
|
-
currentEngine = { name: "wasm", wasm };
|
|
387
|
-
} catch {
|
|
388
|
-
throw new Error("WASM engine not available. Build it with: cd rust && wasm-pack build --target bundler --out-dir ../pkg");
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
function useWasmModule(wasmModule) {
|
|
392
|
-
currentEngine = { name: "wasm", wasm: wasmModule };
|
|
393
|
-
}
|
|
394
|
-
function useTypescriptEngine() {
|
|
395
|
-
currentEngine = { name: "typescript" };
|
|
396
|
-
}
|
|
397
595
|
function engineMatrixMultiply(a, aRows, aCols, b, bRows, bCols) {
|
|
398
596
|
if (currentEngine.wasm) {
|
|
399
597
|
return currentEngine.wasm.matrix_multiply(a, aRows, aCols, b, bRows, bCols);
|
|
@@ -409,28 +607,98 @@ function engineMatrixMultiply(a, aRows, aCols, b, bRows, bCols) {
|
|
|
409
607
|
}
|
|
410
608
|
return result;
|
|
411
609
|
}
|
|
610
|
+
function engineTranspose(data, rows, cols) {
|
|
611
|
+
if (currentEngine.wasm)
|
|
612
|
+
return currentEngine.wasm.matrix_transpose(data, rows, cols);
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
function engineAdd(a, b) {
|
|
616
|
+
if (currentEngine.wasm)
|
|
617
|
+
return currentEngine.wasm.matrix_add(a, b);
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
function engineSubtract(a, b) {
|
|
621
|
+
if (currentEngine.wasm)
|
|
622
|
+
return currentEngine.wasm.matrix_subtract(a, b);
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
function engineScale(a, scalar) {
|
|
626
|
+
if (currentEngine.wasm)
|
|
627
|
+
return currentEngine.wasm.matrix_scale(a, scalar);
|
|
628
|
+
return null;
|
|
629
|
+
}
|
|
630
|
+
function engineDot(a, b) {
|
|
631
|
+
if (currentEngine.wasm)
|
|
632
|
+
return currentEngine.wasm.vector_dot(a, b);
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
function engineNorm(a) {
|
|
636
|
+
if (currentEngine.wasm)
|
|
637
|
+
return currentEngine.wasm.frobenius_norm(a);
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
function engineDeterminant(data, n) {
|
|
641
|
+
if (currentEngine.wasm)
|
|
642
|
+
return currentEngine.wasm.determinant(data, n);
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
412
645
|
function engineQR(data, rows, cols) {
|
|
413
646
|
if (currentEngine.wasm) {
|
|
414
647
|
const result = currentEngine.wasm.qr_decompose(data, rows, cols);
|
|
415
648
|
const qSize = rows * rows;
|
|
416
|
-
|
|
417
|
-
const R = result.slice(qSize);
|
|
418
|
-
return { Q, R };
|
|
649
|
+
return { Q: result.slice(0, qSize), R: result.slice(qSize) };
|
|
419
650
|
}
|
|
420
651
|
return null;
|
|
421
652
|
}
|
|
422
653
|
function engineCholesky(data, n) {
|
|
423
|
-
if (currentEngine.wasm)
|
|
654
|
+
if (currentEngine.wasm)
|
|
424
655
|
return currentEngine.wasm.cholesky(data, n);
|
|
425
|
-
}
|
|
426
656
|
return null;
|
|
427
657
|
}
|
|
428
658
|
function engineSolveTriangular(r, b, n) {
|
|
429
|
-
if (currentEngine.wasm)
|
|
659
|
+
if (currentEngine.wasm)
|
|
430
660
|
return currentEngine.wasm.solve_triangular(r, b, n);
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
function engineForwardSubstitution(l, b, n) {
|
|
664
|
+
if (currentEngine.wasm)
|
|
665
|
+
return currentEngine.wasm.forward_substitution(l, b, n);
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
function engineSVD(data, rows, cols) {
|
|
669
|
+
if (currentEngine.wasm) {
|
|
670
|
+
const k = Math.min(rows, cols);
|
|
671
|
+
const result = currentEngine.wasm.svd(data, rows, cols);
|
|
672
|
+
const uSize = rows * k;
|
|
673
|
+
return {
|
|
674
|
+
U: result.slice(0, uSize),
|
|
675
|
+
S: result.slice(uSize, uSize + k),
|
|
676
|
+
V: result.slice(uSize + k)
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
function engineCoordinateDescent(x, y, alpha, l1Ratio, maxIter, tolerance, n, p, fitIntercept) {
|
|
682
|
+
if (currentEngine.wasm) {
|
|
683
|
+
return currentEngine.wasm.coordinate_descent(x, y, alpha, l1Ratio, maxIter, tolerance, n, p, fitIntercept);
|
|
431
684
|
}
|
|
432
685
|
return null;
|
|
433
686
|
}
|
|
687
|
+
function engineSoftmaxRows(data, rows, cols) {
|
|
688
|
+
if (currentEngine.wasm)
|
|
689
|
+
return currentEngine.wasm.softmax_rows(data, rows, cols);
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
function engineEuclideanDistances(train, test, nTrain, nTest, dim) {
|
|
693
|
+
if (currentEngine.wasm)
|
|
694
|
+
return currentEngine.wasm.euclidean_distances(train, test, nTrain, nTest, dim);
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
function engineManhattanDistances(train, test, nTrain, nTest, dim) {
|
|
698
|
+
if (currentEngine.wasm)
|
|
699
|
+
return currentEngine.wasm.manhattan_distances(train, test, nTrain, nTest, dim);
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
434
702
|
// src/core/matrix.ts
|
|
435
703
|
class Matrix {
|
|
436
704
|
rows;
|
|
@@ -513,6 +781,10 @@ class Matrix {
|
|
|
513
781
|
}
|
|
514
782
|
}
|
|
515
783
|
transpose() {
|
|
784
|
+
const wasmResult = engineTranspose(this.data, this.rows, this.cols);
|
|
785
|
+
if (wasmResult) {
|
|
786
|
+
return new Matrix(this.cols, this.rows, wasmResult);
|
|
787
|
+
}
|
|
516
788
|
const result = new Matrix(this.cols, this.rows);
|
|
517
789
|
for (let i = 0;i < this.rows; i++) {
|
|
518
790
|
for (let j = 0;j < this.cols; j++) {
|
|
@@ -530,6 +802,9 @@ class Matrix {
|
|
|
530
802
|
}
|
|
531
803
|
add(other) {
|
|
532
804
|
this.assertSameDimensions(other, "add");
|
|
805
|
+
const w = engineAdd(this.data, other.data);
|
|
806
|
+
if (w)
|
|
807
|
+
return new Matrix(this.rows, this.cols, w);
|
|
533
808
|
const result = new Matrix(this.rows, this.cols);
|
|
534
809
|
for (let i = 0;i < this.data.length; i++) {
|
|
535
810
|
result.data[i] = this.data[i] + other.data[i];
|
|
@@ -538,6 +813,9 @@ class Matrix {
|
|
|
538
813
|
}
|
|
539
814
|
subtract(other) {
|
|
540
815
|
this.assertSameDimensions(other, "subtract");
|
|
816
|
+
const w = engineSubtract(this.data, other.data);
|
|
817
|
+
if (w)
|
|
818
|
+
return new Matrix(this.rows, this.cols, w);
|
|
541
819
|
const result = new Matrix(this.rows, this.cols);
|
|
542
820
|
for (let i = 0;i < this.data.length; i++) {
|
|
543
821
|
result.data[i] = this.data[i] - other.data[i];
|
|
@@ -545,6 +823,9 @@ class Matrix {
|
|
|
545
823
|
return result;
|
|
546
824
|
}
|
|
547
825
|
scale(scalar) {
|
|
826
|
+
const w = engineScale(this.data, scalar);
|
|
827
|
+
if (w)
|
|
828
|
+
return new Matrix(this.rows, this.cols, w);
|
|
548
829
|
const result = new Matrix(this.rows, this.cols);
|
|
549
830
|
for (let i = 0;i < this.data.length; i++) {
|
|
550
831
|
result.data[i] = this.data[i] * scalar;
|
|
@@ -569,6 +850,9 @@ class Matrix {
|
|
|
569
850
|
}
|
|
570
851
|
}
|
|
571
852
|
norm() {
|
|
853
|
+
const w = engineNorm(this.data);
|
|
854
|
+
if (w !== null)
|
|
855
|
+
return w;
|
|
572
856
|
let sum = 0;
|
|
573
857
|
for (let i = 0;i < this.data.length; i++) {
|
|
574
858
|
sum += this.data[i] * this.data[i];
|
|
@@ -596,6 +880,9 @@ class Matrix {
|
|
|
596
880
|
return this.data[0];
|
|
597
881
|
if (n === 2)
|
|
598
882
|
return this.data[0] * this.data[3] - this.data[1] * this.data[2];
|
|
883
|
+
const wasmResult = engineDeterminant(this.data, n);
|
|
884
|
+
if (wasmResult !== null)
|
|
885
|
+
return wasmResult;
|
|
599
886
|
const a = new Float64Array(this.data);
|
|
600
887
|
let det = 1;
|
|
601
888
|
for (let col = 0;col < n; col++) {
|
|
@@ -658,6 +945,9 @@ class Matrix {
|
|
|
658
945
|
return Array.from(this.data);
|
|
659
946
|
}
|
|
660
947
|
dot(other) {
|
|
948
|
+
const w = engineDot(this.data, other.data);
|
|
949
|
+
if (w !== null)
|
|
950
|
+
return w;
|
|
661
951
|
let sum = 0;
|
|
662
952
|
for (let i = 0;i < this.data.length; i++) {
|
|
663
953
|
sum += this.data[i] * other.data[i];
|
|
@@ -798,6 +1088,15 @@ function choleskyDecomposition(A) {
|
|
|
798
1088
|
}
|
|
799
1089
|
function forwardSubstitution(L, b) {
|
|
800
1090
|
const n = L.rows;
|
|
1091
|
+
if (isWasmActive()) {
|
|
1092
|
+
const bFlat = new Float64Array(n);
|
|
1093
|
+
for (let i = 0;i < n; i++)
|
|
1094
|
+
bFlat[i] = b.get(i, 0);
|
|
1095
|
+
const wasmResult = engineForwardSubstitution(L.data, bFlat, n);
|
|
1096
|
+
if (wasmResult) {
|
|
1097
|
+
return Matrix.columnVector(Array.from(wasmResult));
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
801
1100
|
const y = new Float64Array(n);
|
|
802
1101
|
for (let i = 0;i < n; i++) {
|
|
803
1102
|
let sum = b.get(i, 0);
|
|
@@ -812,10 +1111,20 @@ function solveCholesky(L, b) {
|
|
|
812
1111
|
const y = forwardSubstitution(L, b);
|
|
813
1112
|
return backSubstitution(L.transpose(), y);
|
|
814
1113
|
}
|
|
815
|
-
function
|
|
1114
|
+
function svd2(A) {
|
|
816
1115
|
const m = A.rows;
|
|
817
1116
|
const n = A.cols;
|
|
818
1117
|
const k = Math.min(m, n);
|
|
1118
|
+
if (isWasmActive()) {
|
|
1119
|
+
const wasmResult = engineSVD(A.data, m, n);
|
|
1120
|
+
if (wasmResult) {
|
|
1121
|
+
return {
|
|
1122
|
+
U: new Matrix(m, k, wasmResult.U),
|
|
1123
|
+
S: Array.from(wasmResult.S),
|
|
1124
|
+
V: new Matrix(n, k, wasmResult.V)
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
819
1128
|
const W = A.clone();
|
|
820
1129
|
const V = Matrix.identity(n);
|
|
821
1130
|
const maxIter = 100;
|
|
@@ -1143,7 +1452,7 @@ function correlationMatrix(X) {
|
|
|
1143
1452
|
}
|
|
1144
1453
|
function conditionNumber(X) {
|
|
1145
1454
|
const A = Matrix.fromArray(X);
|
|
1146
|
-
const { S } =
|
|
1455
|
+
const { S } = svd2(A);
|
|
1147
1456
|
const sMax = S[0] ?? 1;
|
|
1148
1457
|
const sMin = S[S.length - 1] ?? 0;
|
|
1149
1458
|
return sMin > 0.000000000000001 ? sMax / sMin : Infinity;
|
|
@@ -1290,6 +1599,18 @@ class LassoRegression extends BaseRegression {
|
|
|
1290
1599
|
this._y = y;
|
|
1291
1600
|
const n = Xmat.length;
|
|
1292
1601
|
const p = Xmat[0].length;
|
|
1602
|
+
const xFlat = new Float64Array(n * p);
|
|
1603
|
+
for (let i = 0;i < n; i++)
|
|
1604
|
+
for (let j = 0;j < p; j++)
|
|
1605
|
+
xFlat[i * p + j] = Xmat[i][j];
|
|
1606
|
+
const wasmResult = engineCoordinateDescent(xFlat, new Float64Array(y), this._alpha, this.getL1Ratio(), this._maxIterations, this._tolerance, n, p, this._fitIntercept);
|
|
1607
|
+
if (wasmResult) {
|
|
1608
|
+
this._intercept = wasmResult[0];
|
|
1609
|
+
this._coefficients = Array.from(wasmResult.slice(1));
|
|
1610
|
+
this._yHat = this.predict(Xmat);
|
|
1611
|
+
this._fitted = true;
|
|
1612
|
+
return this;
|
|
1613
|
+
}
|
|
1293
1614
|
const { Xstd, xMeans, xStds, yMean } = this.standardize(Xmat, y);
|
|
1294
1615
|
const yCentered = y.map((yi) => yi - yMean);
|
|
1295
1616
|
const beta = new Float64Array(p);
|
|
@@ -1331,6 +1652,9 @@ class LassoRegression extends BaseRegression {
|
|
|
1331
1652
|
this._fitted = true;
|
|
1332
1653
|
return this;
|
|
1333
1654
|
}
|
|
1655
|
+
getL1Ratio() {
|
|
1656
|
+
return 1;
|
|
1657
|
+
}
|
|
1334
1658
|
predict(X) {
|
|
1335
1659
|
const Xmat = this.normalizeInput(X);
|
|
1336
1660
|
return Xmat.map((row) => {
|
|
@@ -1394,6 +1718,9 @@ class ElasticNet extends LassoRegression {
|
|
|
1394
1718
|
});
|
|
1395
1719
|
this._l1Ratio = options.l1Ratio ?? 0.5;
|
|
1396
1720
|
}
|
|
1721
|
+
getL1Ratio() {
|
|
1722
|
+
return this._l1Ratio;
|
|
1723
|
+
}
|
|
1397
1724
|
coordinateUpdate(rho, colNormSq, n, _j) {
|
|
1398
1725
|
const l1Penalty = n * this._alpha * this._l1Ratio;
|
|
1399
1726
|
const l2Penalty = n * this._alpha * (1 - this._l1Ratio);
|
|
@@ -1430,6 +1757,24 @@ class KNearestNeighbors {
|
|
|
1430
1757
|
if (!this._fitted)
|
|
1431
1758
|
throw new Error("Model has not been fitted. Call fit() first.");
|
|
1432
1759
|
const Xmat = this.normalizeInput(X);
|
|
1760
|
+
const dim = this._X[0].length;
|
|
1761
|
+
const nTrain = this._X.length;
|
|
1762
|
+
const nTest = Xmat.length;
|
|
1763
|
+
const trainFlat = new Float64Array(nTrain * dim);
|
|
1764
|
+
for (let i = 0;i < nTrain; i++)
|
|
1765
|
+
for (let j = 0;j < dim; j++)
|
|
1766
|
+
trainFlat[i * dim + j] = this._X[i][j];
|
|
1767
|
+
const testFlat = new Float64Array(nTest * dim);
|
|
1768
|
+
for (let i = 0;i < nTest; i++)
|
|
1769
|
+
for (let j = 0;j < dim; j++)
|
|
1770
|
+
testFlat[i * dim + j] = Xmat[i][j];
|
|
1771
|
+
const distMatrix = this._distance === "manhattan" ? engineManhattanDistances(trainFlat, testFlat, nTrain, nTest, dim) : engineEuclideanDistances(trainFlat, testFlat, nTrain, nTest, dim);
|
|
1772
|
+
if (distMatrix) {
|
|
1773
|
+
return Array.from({ length: nTest }, (_, i) => {
|
|
1774
|
+
const indices = Array.from({ length: nTrain }, (_2, j) => j).sort((a, b) => distMatrix[i * nTrain + a] - distMatrix[i * nTrain + b]).slice(0, this._k);
|
|
1775
|
+
return this.voteOrMean(indices);
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1433
1778
|
return Xmat.map((row) => this.predictOne(row));
|
|
1434
1779
|
}
|
|
1435
1780
|
neighbors(point) {
|
|
@@ -1437,17 +1782,16 @@ class KNearestNeighbors {
|
|
|
1437
1782
|
throw new Error("Model has not been fitted. Call fit() first.");
|
|
1438
1783
|
return this.findNeighbors(point).map((n) => n.index);
|
|
1439
1784
|
}
|
|
1440
|
-
|
|
1441
|
-
const nearest = this.findNeighbors(point);
|
|
1785
|
+
voteOrMean(indices) {
|
|
1442
1786
|
if (this._mode === "regression") {
|
|
1443
1787
|
let sum = 0;
|
|
1444
|
-
for (const
|
|
1445
|
-
sum += this._y[
|
|
1446
|
-
return sum /
|
|
1788
|
+
for (const idx of indices)
|
|
1789
|
+
sum += this._y[idx];
|
|
1790
|
+
return sum / indices.length;
|
|
1447
1791
|
}
|
|
1448
1792
|
const votes = new Map;
|
|
1449
|
-
for (const
|
|
1450
|
-
const label = this._y[
|
|
1793
|
+
for (const idx of indices) {
|
|
1794
|
+
const label = this._y[idx];
|
|
1451
1795
|
votes.set(label, (votes.get(label) ?? 0) + 1);
|
|
1452
1796
|
}
|
|
1453
1797
|
let bestLabel = 0;
|
|
@@ -1460,6 +1804,10 @@ class KNearestNeighbors {
|
|
|
1460
1804
|
}
|
|
1461
1805
|
return bestLabel;
|
|
1462
1806
|
}
|
|
1807
|
+
predictOne(point) {
|
|
1808
|
+
const nearest = this.findNeighbors(point);
|
|
1809
|
+
return this.voteOrMean(nearest.map((n) => n.index));
|
|
1810
|
+
}
|
|
1463
1811
|
findNeighbors(point) {
|
|
1464
1812
|
const distances = [];
|
|
1465
1813
|
for (let i = 0;i < this._X.length; i++) {
|
|
@@ -1727,14 +2075,20 @@ class MulticlassLogisticRegression {
|
|
|
1727
2075
|
const XMat = Matrix.fromArray(Xdesign);
|
|
1728
2076
|
for (let iter = 0;iter < this._maxIterations; iter++) {
|
|
1729
2077
|
const scores = XMat.multiply(this._weights);
|
|
1730
|
-
const
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
for (let
|
|
1737
|
-
|
|
2078
|
+
const wasmP = engineSoftmaxRows(scores.data, n, K);
|
|
2079
|
+
let P;
|
|
2080
|
+
if (wasmP) {
|
|
2081
|
+
P = new Matrix(n, K, wasmP);
|
|
2082
|
+
} else {
|
|
2083
|
+
P = Matrix.zeros(n, K);
|
|
2084
|
+
for (let i = 0;i < n; i++) {
|
|
2085
|
+
const logits = [];
|
|
2086
|
+
for (let c = 0;c < K; c++)
|
|
2087
|
+
logits.push(scores.get(i, c));
|
|
2088
|
+
const probs = this.softmax(logits);
|
|
2089
|
+
for (let c = 0;c < K; c++)
|
|
2090
|
+
P.set(i, c, probs[c]);
|
|
2091
|
+
}
|
|
1738
2092
|
}
|
|
1739
2093
|
const diff = P.subtract(Y);
|
|
1740
2094
|
const grad = XMat.transpose().multiply(diff).scale(1 / n);
|