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 CHANGED
@@ -297,27 +297,34 @@ console.log(C.trace()); // 5
297
297
  console.log(C.transpose().toArray());
298
298
  ```
299
299
 
300
- ## WASM Engine (Optional)
300
+ ## WASM Acceleration
301
301
 
302
- For faster matrix operations on large datasets, build and load the Rust/WASM engine. When active, `Matrix.multiply()`, QR decomposition, Cholesky decomposition, and back-substitution are dispatched to compiled Rust code.
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
- ```bash
305
- cd rust && wasm-pack build --target bundler --out-dir ../pkg
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 { useWasmEngine, useTypescriptEngine, isWasmActive, getEngine } from 'regressio';
313
+ import { isWasmActive } from 'regressio';
310
314
 
311
- // Load WASM engine (async, loads the .wasm file)
312
- await useWasmEngine();
313
- console.log(isWasmActive()); // true
315
+ console.log(isWasmActive()); // true if WASM loaded
314
316
 
315
- // All subsequent matrix operations use WASM
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
- // Switch back to pure TypeScript
320
- useTypescriptEngine();
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
- function getEngine() {
378
- return currentEngine;
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
- const Q = result.slice(0, qSize);
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 svd(A) {
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 } = svd(A);
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
- predictOne(point) {
1441
- const nearest = this.findNeighbors(point);
1785
+ voteOrMean(indices) {
1442
1786
  if (this._mode === "regression") {
1443
1787
  let sum = 0;
1444
- for (const n of nearest)
1445
- sum += this._y[n.index];
1446
- return sum / nearest.length;
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 n of nearest) {
1450
- const label = this._y[n.index];
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 P = Matrix.zeros(n, K);
1731
- for (let i = 0;i < n; i++) {
1732
- const logits = [];
1733
- for (let c = 0;c < K; c++)
1734
- logits.push(scores.get(i, c));
1735
- const probs = this.softmax(logits);
1736
- for (let c = 0;c < K; c++)
1737
- P.set(i, c, probs[c]);
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);