@danielsimonjr/mathts-matrix 0.1.13 → 0.1.14
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/index.js +163 -20
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6544,6 +6544,84 @@ function handleZero(d, e, _U, V, zeroIdx, isDiagonal, _tolerance) {
|
|
|
6544
6544
|
}
|
|
6545
6545
|
}
|
|
6546
6546
|
}
|
|
6547
|
+
function jacobiSVD(A) {
|
|
6548
|
+
const m = A.length;
|
|
6549
|
+
const n = A[0].length;
|
|
6550
|
+
const W = A.map((row2) => row2.slice());
|
|
6551
|
+
const V = eye(n);
|
|
6552
|
+
const EPS = 1e-15;
|
|
6553
|
+
const MAX_SWEEPS = 60;
|
|
6554
|
+
for (let sweep = 0; sweep < MAX_SWEEPS; sweep++) {
|
|
6555
|
+
let rotated = false;
|
|
6556
|
+
for (let p = 0; p < n - 1; p++) {
|
|
6557
|
+
for (let q = p + 1; q < n; q++) {
|
|
6558
|
+
let alpha = 0;
|
|
6559
|
+
let beta = 0;
|
|
6560
|
+
let gamma = 0;
|
|
6561
|
+
for (let i = 0; i < m; i++) {
|
|
6562
|
+
alpha += W[i][p] * W[i][p];
|
|
6563
|
+
gamma += W[i][q] * W[i][q];
|
|
6564
|
+
beta += W[i][p] * W[i][q];
|
|
6565
|
+
}
|
|
6566
|
+
if (Math.abs(beta) <= EPS * Math.sqrt(alpha * gamma) || alpha === 0 && gamma === 0) {
|
|
6567
|
+
continue;
|
|
6568
|
+
}
|
|
6569
|
+
rotated = true;
|
|
6570
|
+
const zeta = (gamma - alpha) / (2 * beta);
|
|
6571
|
+
const sign = zeta >= 0 ? 1 : -1;
|
|
6572
|
+
const t = sign / (Math.abs(zeta) + Math.sqrt(1 + zeta * zeta));
|
|
6573
|
+
const c = 1 / Math.sqrt(1 + t * t);
|
|
6574
|
+
const s = c * t;
|
|
6575
|
+
for (let i = 0; i < m; i++) {
|
|
6576
|
+
const wip = W[i][p];
|
|
6577
|
+
const wiq = W[i][q];
|
|
6578
|
+
W[i][p] = c * wip - s * wiq;
|
|
6579
|
+
W[i][q] = s * wip + c * wiq;
|
|
6580
|
+
}
|
|
6581
|
+
for (let i = 0; i < n; i++) {
|
|
6582
|
+
const vip = V[i][p];
|
|
6583
|
+
const viq = V[i][q];
|
|
6584
|
+
V[i][p] = c * vip - s * viq;
|
|
6585
|
+
V[i][q] = s * vip + c * viq;
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
if (!rotated) break;
|
|
6590
|
+
}
|
|
6591
|
+
const d = new Array(n).fill(0);
|
|
6592
|
+
const U = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
6593
|
+
for (let j = 0; j < n; j++) {
|
|
6594
|
+
let norm4 = 0;
|
|
6595
|
+
for (let i = 0; i < m; i++) norm4 += W[i][j] * W[i][j];
|
|
6596
|
+
norm4 = Math.sqrt(norm4);
|
|
6597
|
+
d[j] = norm4;
|
|
6598
|
+
if (norm4 > 1e-300) {
|
|
6599
|
+
for (let i = 0; i < m; i++) U[i][j] = W[i][j] / norm4;
|
|
6600
|
+
}
|
|
6601
|
+
}
|
|
6602
|
+
for (let j = 0; j < n; j++) {
|
|
6603
|
+
if (d[j] > 1e-300) continue;
|
|
6604
|
+
const col = new Array(m).fill(0);
|
|
6605
|
+
for (let seed = 0; seed < m; seed++) {
|
|
6606
|
+
col.fill(0);
|
|
6607
|
+
col[seed] = 1;
|
|
6608
|
+
for (let c = 0; c < n; c++) {
|
|
6609
|
+
if (c === j) continue;
|
|
6610
|
+
let dot = 0;
|
|
6611
|
+
for (let i = 0; i < m; i++) dot += col[i] * U[i][c];
|
|
6612
|
+
for (let i = 0; i < m; i++) col[i] -= dot * U[i][c];
|
|
6613
|
+
}
|
|
6614
|
+
let nrm = 0;
|
|
6615
|
+
for (let i = 0; i < m; i++) nrm += col[i] * col[i];
|
|
6616
|
+
nrm = Math.sqrt(nrm);
|
|
6617
|
+
if (nrm > 1e-8) {
|
|
6618
|
+
for (let i = 0; i < m; i++) U[i][j] = col[i] / nrm;
|
|
6619
|
+
break;
|
|
6620
|
+
}
|
|
6621
|
+
}
|
|
6622
|
+
}
|
|
6623
|
+
return { d, U, V };
|
|
6624
|
+
}
|
|
6547
6625
|
function svd(matrix2, options = {}) {
|
|
6548
6626
|
const {
|
|
6549
6627
|
maxIterations = DEFAULT_MAX_ITERATIONS,
|
|
@@ -6615,19 +6693,29 @@ function svd(matrix2, options = {}) {
|
|
|
6615
6693
|
}
|
|
6616
6694
|
svdStep(d, e, U, V, start, end);
|
|
6617
6695
|
}
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6696
|
+
let dFinal = d;
|
|
6697
|
+
let uFinal = U;
|
|
6698
|
+
let vFinal = V;
|
|
6699
|
+
const maxAbsD = d.reduce((mx, x) => Math.max(mx, Math.abs(x)), 0);
|
|
6700
|
+
if (maxAbsD > 0 && d.some((x) => Math.abs(x) <= rankTolerance * maxAbsD)) {
|
|
6701
|
+
const jac = jacobiSVD(A);
|
|
6702
|
+
dFinal = jac.d;
|
|
6703
|
+
uFinal = jac.U;
|
|
6704
|
+
vFinal = jac.V;
|
|
6705
|
+
}
|
|
6706
|
+
for (let i = 0; i < dFinal.length; i++) {
|
|
6707
|
+
if (dFinal[i] < 0) {
|
|
6708
|
+
dFinal[i] = -dFinal[i];
|
|
6709
|
+
for (let j = 0; j < vFinal.length; j++) {
|
|
6710
|
+
vFinal[j][i] = -vFinal[j][i];
|
|
6711
|
+
}
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
const indices = Array.from({ length: dFinal.length }, (_, i) => i);
|
|
6715
|
+
indices.sort((a, b) => dFinal[b] - dFinal[a]);
|
|
6716
|
+
const sortedS = indices.map((i) => dFinal[i]);
|
|
6717
|
+
const sortedU = uFinal.map((row2) => indices.map((i) => row2[i]));
|
|
6718
|
+
const sortedV = vFinal.map((row2) => indices.map((i) => row2[i]));
|
|
6631
6719
|
const maxS = sortedS[0] || 0;
|
|
6632
6720
|
let rank = 0;
|
|
6633
6721
|
for (const s of sortedS) {
|
|
@@ -7111,8 +7199,7 @@ function hessenbergReduce(A) {
|
|
|
7111
7199
|
applyHouseholderRight(Q, v, beta, 0, k + 1);
|
|
7112
7200
|
}
|
|
7113
7201
|
}
|
|
7114
|
-
for (let i = 0; i < n; i++)
|
|
7115
|
-
for (let j = 0; j < i - 1; j++) H[i][j] = 0;
|
|
7202
|
+
for (let i = 0; i < n; i++) for (let j = 0; j < i - 1; j++) H[i][j] = 0;
|
|
7116
7203
|
return { H, Q };
|
|
7117
7204
|
}
|
|
7118
7205
|
function givensParams(a, b) {
|
|
@@ -7217,6 +7304,57 @@ function qrStepDouble(H, Q, start, end) {
|
|
|
7217
7304
|
applyGivensRight(H, gc, gs, end - 1, end, 0);
|
|
7218
7305
|
applyGivensRight(Q, gc, gs, end - 1, end, 0);
|
|
7219
7306
|
}
|
|
7307
|
+
function qrStepSingleShift(H, Q, start, end, shift) {
|
|
7308
|
+
let x = H[start][start] - shift;
|
|
7309
|
+
let y = H[start + 1][start];
|
|
7310
|
+
for (let k = start; k < end; k++) {
|
|
7311
|
+
const { c: gc, s: gs } = givensParams(x, y);
|
|
7312
|
+
applyGivensLeft(H, gc, gs, k, k + 1, Math.max(0, k - 1));
|
|
7313
|
+
applyGivensRight(H, gc, gs, k, k + 1, 0);
|
|
7314
|
+
applyGivensRight(Q, gc, gs, k, k + 1, 0);
|
|
7315
|
+
if (k < end - 1) {
|
|
7316
|
+
x = H[k + 1][k];
|
|
7317
|
+
y = H[k + 2][k];
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7320
|
+
}
|
|
7321
|
+
function exceptionalShift(H, start, end) {
|
|
7322
|
+
const sub1 = Math.abs(H[end][end - 1]);
|
|
7323
|
+
const sub2 = end - 1 > start ? Math.abs(H[end - 1][end - 2]) : 0;
|
|
7324
|
+
return H[end][end] + 0.75 * (sub1 + sub2);
|
|
7325
|
+
}
|
|
7326
|
+
function standardize2x2Block(H, Q, p) {
|
|
7327
|
+
const q = p + 1;
|
|
7328
|
+
const a = H[p][p];
|
|
7329
|
+
const b = H[p][q];
|
|
7330
|
+
const c = H[q][p];
|
|
7331
|
+
const d = H[q][q];
|
|
7332
|
+
if (c === 0) return;
|
|
7333
|
+
const half = (a - d) / 2;
|
|
7334
|
+
const disc = half * half + b * c;
|
|
7335
|
+
if (disc < 0) return;
|
|
7336
|
+
const z = Math.sqrt(disc);
|
|
7337
|
+
const lambda = (a + d) / 2 + (half >= 0 ? z : -z);
|
|
7338
|
+
const r0 = Math.hypot(a - lambda, b);
|
|
7339
|
+
const r1 = Math.hypot(c, d - lambda);
|
|
7340
|
+
let u0;
|
|
7341
|
+
let u1;
|
|
7342
|
+
if (r0 >= r1) {
|
|
7343
|
+
u0 = b;
|
|
7344
|
+
u1 = lambda - a;
|
|
7345
|
+
} else {
|
|
7346
|
+
u0 = lambda - d;
|
|
7347
|
+
u1 = c;
|
|
7348
|
+
}
|
|
7349
|
+
const norm4 = Math.hypot(u0, u1);
|
|
7350
|
+
if (norm4 === 0) return;
|
|
7351
|
+
const cs = u0 / norm4;
|
|
7352
|
+
const sn = -u1 / norm4;
|
|
7353
|
+
applyGivensLeft(H, cs, sn, p, q, 0);
|
|
7354
|
+
applyGivensRight(H, cs, sn, p, q, 0);
|
|
7355
|
+
applyGivensRight(Q, cs, sn, p, q, 0);
|
|
7356
|
+
H[q][p] = 0;
|
|
7357
|
+
}
|
|
7220
7358
|
function schurRaw(A, maxIterations, tolerance) {
|
|
7221
7359
|
const n = A.length;
|
|
7222
7360
|
if (n === 1) {
|
|
@@ -7225,7 +7363,10 @@ function schurRaw(A, maxIterations, tolerance) {
|
|
|
7225
7363
|
const { H, Q } = hessenbergReduce(A);
|
|
7226
7364
|
let end = n - 1;
|
|
7227
7365
|
let iter = 0;
|
|
7366
|
+
let iterSinceDeflation = 0;
|
|
7367
|
+
const EXCEPTIONAL_EVERY = 10;
|
|
7228
7368
|
while (end > 0 && iter < maxIterations) {
|
|
7369
|
+
const endBefore = end;
|
|
7229
7370
|
let start = end;
|
|
7230
7371
|
while (start > 0) {
|
|
7231
7372
|
const scale2 = Math.abs(H[start - 1][start - 1]) + Math.abs(H[start][start]);
|
|
@@ -7238,14 +7379,16 @@ function schurRaw(A, maxIterations, tolerance) {
|
|
|
7238
7379
|
if (start === end) {
|
|
7239
7380
|
end--;
|
|
7240
7381
|
} else if (start === end - 1) {
|
|
7382
|
+
standardize2x2Block(H, Q, start);
|
|
7241
7383
|
end -= 2;
|
|
7384
|
+
} else if (iterSinceDeflation > 0 && iterSinceDeflation % EXCEPTIONAL_EVERY === 0) {
|
|
7385
|
+
qrStepSingleShift(H, Q, start, end, exceptionalShift(H, start, end));
|
|
7386
|
+
} else if (end - start >= 2) {
|
|
7387
|
+
qrStepDouble(H, Q, start, end);
|
|
7242
7388
|
} else {
|
|
7243
|
-
|
|
7244
|
-
qrStepDouble(H, Q, start, end);
|
|
7245
|
-
} else {
|
|
7246
|
-
qrStepSingle(H, Q, start, end);
|
|
7247
|
-
}
|
|
7389
|
+
qrStepSingle(H, Q, start, end);
|
|
7248
7390
|
}
|
|
7391
|
+
iterSinceDeflation = end < endBefore ? 0 : iterSinceDeflation + 1;
|
|
7249
7392
|
iter++;
|
|
7250
7393
|
}
|
|
7251
7394
|
return { H, Q };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielsimonjr/mathts-matrix",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Matrix operations for MathTS with WASM/WebGPU backend support",
|
|
5
5
|
"author": "Daniel Simon Jr.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build:prod": "tsup src/index.ts --format esm --dts --clean --minify --treeshake && node scripts/copy-wasm.mjs"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@danielsimonjr/mathts-core": "^0.
|
|
35
|
+
"@danielsimonjr/mathts-core": "^0.4.0",
|
|
36
36
|
"@danielsimonjr/mathts-parallel": "^0.3.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|