@danielsimonjr/mathts-matrix 0.4.6 → 0.6.0

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.d.ts CHANGED
@@ -1986,8 +1986,24 @@ interface EigResult {
1986
1986
  re: number;
1987
1987
  im: number;
1988
1988
  }>;
1989
- /** Eigenvectors as columns (each column is an eigenvector) */
1989
+ /**
1990
+ * Eigenvectors as columns (each column is an eigenvector). For a real
1991
+ * eigenvalue this is the full (real) eigenvector, unit-normalised. For a
1992
+ * complex-conjugate eigenvalue pair this holds the REAL PART of the
1993
+ * corresponding complex eigenvector — see {@link vectorsIm} for the
1994
+ * imaginary part.
1995
+ */
1990
1996
  vectors: number[][];
1997
+ /**
1998
+ * Imaginary parts of the eigenvector columns (same shape as {@link vectors}).
1999
+ * All-zero for real eigenvalues. For a complex-conjugate eigenvalue pair at
2000
+ * indices `j`/`j+1`, the full complex eigenvectors are
2001
+ * `vectors[j] + i*vectorsIm[j]` (for `values[j]`) and
2002
+ * `vectors[j+1] - i*vectorsIm[j] === vectors[j+1] + i*vectorsIm[j+1]` (for
2003
+ * the conjugate `values[j+1]`), each unit-normalised by the complex 2-norm
2004
+ * `sqrt(sum(re_i^2 + im_i^2))`.
2005
+ */
2006
+ vectorsIm: number[][];
1991
2007
  /** Whether the matrix was symmetric */
1992
2008
  isSymmetric: boolean;
1993
2009
  }
@@ -2507,6 +2523,124 @@ interface SchurOptions {
2507
2523
  */
2508
2524
  declare function matrixSchur(A: DenseMatrix, opts?: SchurOptions): SchurResult;
2509
2525
 
2526
+ /**
2527
+ * Rank-Revealing Pivoted QR Decomposition (Businger-Golub column pivoting)
2528
+ *
2529
+ * Computes `A[:, P] = Q · R` via Householder reflections, choosing at each
2530
+ * step the remaining column of largest norm as the next pivot. This is the
2531
+ * classical column-pivoted QR (LAPACK `dgeqp3`'s algorithm, simplified —
2532
+ * exact remaining-column-norm recomputation rather than the cheaper
2533
+ * downdating formula, since these matrices are small): it guarantees
2534
+ * `|R[0,0]| ≥ |R[1,1]| ≥ … ≥ |R[k-1,k-1]|`, which makes `R`'s diagonal a
2535
+ * reliable numerical-rank indicator — unlike the plain (unpivoted)
2536
+ * Gram-Schmidt `qr()` in this directory, whose diagonal can be small for an
2537
+ * early column purely by column order, not by rank deficiency.
2538
+ *
2539
+ * Reuses the Householder helpers in `./common.js` (already exercised by
2540
+ * `svd.ts`/`schur.ts`) rather than re-deriving reflection algebra here.
2541
+ */
2542
+
2543
+ interface QRPivotedResult {
2544
+ /** Orthonormal Q factor (m × k, k = min(m, n)). */
2545
+ Q: DenseMatrix;
2546
+ /** Upper-triangular R factor (k × n) with |diag(R)| non-increasing. */
2547
+ R: DenseMatrix;
2548
+ /** Column permutation: `P[j]` is the original column index now at position `j`, so `A[:, P] = Q · R`. */
2549
+ P: number[];
2550
+ /** Numerical rank: count of `i` with `|R[i,i]| > tolerance · |R[0,0]|`. */
2551
+ rank: number;
2552
+ }
2553
+ interface QRPivotedOptions {
2554
+ /** Relative rank tolerance (default `1e-10`). */
2555
+ tolerance?: number;
2556
+ }
2557
+ /**
2558
+ * Compute the column-pivoted rank-revealing QR decomposition of `A`.
2559
+ *
2560
+ * @param A - Input matrix (m × n).
2561
+ * @param opts - Optional rank tolerance.
2562
+ */
2563
+ declare function qrPivoted(A: DenseMatrix, opts?: QRPivotedOptions): QRPivotedResult;
2564
+
2565
+ /**
2566
+ * QR-family decompositions: LQ, RQ, QL
2567
+ *
2568
+ * Each is derived from the existing Gram-Schmidt `qr()` primitive in this
2569
+ * directory via the standard flip/transpose reductions (Golub & Van Loan,
2570
+ * *Matrix Computations*, §5.2):
2571
+ *
2572
+ * - **LQ** (`A = L·Q`, L lower-triangular): `qr(Aᵀ)` transposed — no flips
2573
+ * needed. If `Aᵀ = Q₁·R₁` then `A = R₁ᵀ·Q₁ᵀ`, so `L = R₁ᵀ`, `Q = Q₁ᵀ`.
2574
+ * - **RQ** (`A = R·Q`, R upper-triangular): reverse `A`'s row order,
2575
+ * transpose, run `qr()`, then un-flip the resulting factors.
2576
+ * - **QL** (`A = Q·L`, L lower-triangular): reverse `A`'s column order,
2577
+ * run `qr()`, then un-flip the resulting factors.
2578
+ *
2579
+ * All three share `qr()`'s reduced-QR convention: for an m×n input the thin
2580
+ * factor pairing is (m×k, k×n) with k = min(m, n).
2581
+ */
2582
+
2583
+ interface LQResult {
2584
+ /** Lower-triangular (trapezoidal) factor. m × k, k = min(m, n). */
2585
+ L: DenseMatrix;
2586
+ /** Orthonormal-row factor (Q · Qᵀ = I). k × n. */
2587
+ Q: DenseMatrix;
2588
+ }
2589
+ interface RQResult {
2590
+ /** Upper-triangular (trapezoidal) factor. m × k, k = min(m, n). */
2591
+ R: DenseMatrix;
2592
+ /** Orthonormal-row factor (Q · Qᵀ = I). k × n. */
2593
+ Q: DenseMatrix;
2594
+ }
2595
+ interface QLResult {
2596
+ /** Orthonormal-column factor (Qᵀ · Q = I). m × k, k = min(m, n). */
2597
+ Q: DenseMatrix;
2598
+ /** Lower-triangular (trapezoidal) factor. k × n. */
2599
+ L: DenseMatrix;
2600
+ }
2601
+ /**
2602
+ * LQ decomposition: `A = L · Q` with `L` lower-triangular and `Q` having
2603
+ * orthonormal rows (`Q · Qᵀ = I`).
2604
+ */
2605
+ declare function lq(A: DenseMatrix): LQResult;
2606
+ /**
2607
+ * RQ decomposition: `A = R · Q` with `R` upper-triangular and `Q` having
2608
+ * orthonormal rows (`Q · Qᵀ = I`).
2609
+ */
2610
+ declare function rq(A: DenseMatrix): RQResult;
2611
+ /**
2612
+ * QL decomposition: `A = Q · L` with `Q` having orthonormal columns
2613
+ * (`Qᵀ · Q = I`) and `L` lower-triangular.
2614
+ */
2615
+ declare function ql(A: DenseMatrix): QLResult;
2616
+
2617
+ /**
2618
+ * Condition-number ESTIMATE (Hager/Higham 1-norm power-iteration estimator)
2619
+ *
2620
+ * Estimates `‖A‖₁ · ‖A⁻¹‖₁` without ever forming `A⁻¹` explicitly — Hager's
2621
+ * algorithm (Hager 1984; Higham 1988's practical refinement) needs only the
2622
+ * ability to apply `A⁻¹` and `A⁻ᵀ` to a vector, which is done here via the
2623
+ * existing `lu()` primitive's triangular factors (forward/back substitution,
2624
+ * O(n²) per application vs. O(n³) to form `A⁻¹` or run the SVD-based exact
2625
+ * `cond()` in `svd.ts`). The result is an ESTIMATE — typically a lower bound
2626
+ * on the true `‖A⁻¹‖₁`, usually within a small constant factor — not the
2627
+ * exact value.
2628
+ */
2629
+
2630
+ /**
2631
+ * Estimate the 1-norm condition number `‖A‖₁ · ‖A⁻¹‖₁` of a square matrix.
2632
+ *
2633
+ * This is an ESTIMATE (Hager/Higham power iteration), not the exact
2634
+ * condition number that `cond()` (in `svd.ts`) computes via a full SVD —
2635
+ * `condest` is O(n²)-per-iteration and avoids forming `A⁻¹`, at the cost of
2636
+ * being a (typically close) lower-bound estimate rather than an exact value.
2637
+ *
2638
+ * @param A - Square input matrix.
2639
+ * @param p - Only the 1-norm (`p = 1`, the default) is currently implemented.
2640
+ * @throws {Error} if `A` is not square, or `p !== 1`.
2641
+ */
2642
+ declare function condest(A: DenseMatrix, p?: number): number;
2643
+
2510
2644
  /**
2511
2645
  * Typed Matrix Operations
2512
2646
  *
@@ -2890,4 +3024,4 @@ declare function initializeParallelMatrix(): Promise<void>;
2890
3024
  */
2891
3025
  declare function terminateParallelMatrix(): Promise<void>;
2892
3026
 
2893
- export { BUILTIN_SHADERS, type BackendHints, BackendManager, BackendRegistry, type BackendType, BatchExecutor, type CholeskyResult, DEFAULT_BACKEND_HINTS, DEFAULT_EXTENDED_HINTS, DenseMatrix, type EigOptions, type EigResult, type ExpmOptions, type ExtendedBackendHints, GPUBackend, type GPUBackendOptions, type GPUBackendStatus, GPUMatrixBackend, type GPUMatrixBackendConfig, JSBackend, type LUResult, type LogmOptions, Matrix, type MatrixBackend, type MatrixDimensions, type MatrixEntry, type MatrixIndex, type MatrixType, type OperationType, ParallelBackend, type ParallelBackendConfig, type PinvOptions, type QROptions, type QRResult, type SVDOptions, type SVDResult, type SchurOptions, type SchurResult, type SliceSpec, SparseMatrix, type SqrtmOptions, type SyncConfig, SyncManager, type SyncStrategy, WASMBackend, type WASMBackendConfig, type WasmFeatures, abs, add, backendManager, backendRegistry, cholesky, clearFeatureCache, column, cond, createBackendManager, createGPUMatrixBackend, createParallelBackend, createSyncManager, createWASMBackend, destroyGlobalGPUBackend, detectWasmFeatures, diag, diagonal, divide, dotMultiply, eig, eigWasm, eigvals, eigvalsWasm, exp, getCachedFeatures, getGlobalGPUBackend, gpuMatrixBackend, identity, initializeGlobalGPUBackend, initializeParallelMatrix, isAtomicsAvailable, isDenseMatrix, isMatrix, isSharedMemoryAvailable, isSparseMatrix, isWasmAvailable, jsBackend, log, lowRankApprox, lu, matrix, matrixExpm, matrixLogm, pinv as matrixPinv, matrixSchur, matrixSqrtm, max, mean, min, multiply, norm, norm2, normFro, ones, parallelBackend, parallelDiag, parallelDotMultiply, parallelIdentity, parallelMatrix, parallelMatrixAbs, parallelMatrixAdd, parallelMatrixColumn, parallelMatrixCos, parallelMatrixDiagonal, parallelMatrixDistance, parallelMatrixDivide, parallelMatrixDot, parallelMatrixExp, parallelMatrixHistogram, parallelMatrixLog, parallelMatrixMatvec, parallelMatrixMax, parallelMatrixMean, parallelMatrixMin, parallelMatrixMultiply, parallelMatrixNorm, parallelMatrixOperations, parallelMatrixOuter, parallelMatrixRow, parallelMatrixSin, parallelMatrixSize, parallelMatrixSqrt, parallelMatrixSquare, parallelMatrixStd, parallelMatrixSubset, parallelMatrixSubtract, parallelMatrixSum, parallelMatrixTan, parallelMatrixTrace, parallelMatrixTranspose, parallelMatrixVariance, parallelOnes, parallelRandom, parallelUnaryMinus, parallelZeros, pinv$1 as pinv, pow, powerIteration, qr, random, row, singularValues, size, spectralRadiusWasm, sqrt, square, subset, subtract, sum, svd, svdWasm, terminateParallelMatrix, trace, transpose, typedMatrixOperations, unaryMinus, wasmBackend, zeros };
3027
+ export { BUILTIN_SHADERS, type BackendHints, BackendManager, BackendRegistry, type BackendType, BatchExecutor, type CholeskyResult, DEFAULT_BACKEND_HINTS, DEFAULT_EXTENDED_HINTS, DenseMatrix, type EigOptions, type EigResult, type ExpmOptions, type ExtendedBackendHints, GPUBackend, type GPUBackendOptions, type GPUBackendStatus, GPUMatrixBackend, type GPUMatrixBackendConfig, JSBackend, type LQResult, type LUResult, type LogmOptions, Matrix, type MatrixBackend, type MatrixDimensions, type MatrixEntry, type MatrixIndex, type MatrixType, type OperationType, ParallelBackend, type ParallelBackendConfig, type PinvOptions, type QLResult, type QROptions, type QRPivotedOptions, type QRPivotedResult, type QRResult, type RQResult, type SVDOptions, type SVDResult, type SchurOptions, type SchurResult, type SliceSpec, SparseMatrix, type SqrtmOptions, type SyncConfig, SyncManager, type SyncStrategy, WASMBackend, type WASMBackendConfig, type WasmFeatures, abs, add, backendManager, backendRegistry, cholesky, clearFeatureCache, column, cond, condest, createBackendManager, createGPUMatrixBackend, createParallelBackend, createSyncManager, createWASMBackend, destroyGlobalGPUBackend, detectWasmFeatures, diag, diagonal, divide, dotMultiply, eig, eigWasm, eigvals, eigvalsWasm, exp, getCachedFeatures, getGlobalGPUBackend, gpuMatrixBackend, identity, initializeGlobalGPUBackend, initializeParallelMatrix, isAtomicsAvailable, isDenseMatrix, isMatrix, isSharedMemoryAvailable, isSparseMatrix, isWasmAvailable, jsBackend, log, lowRankApprox, lq, lu, matrix, matrixExpm, matrixLogm, pinv as matrixPinv, matrixSchur, matrixSqrtm, max, mean, min, multiply, norm, norm2, normFro, ones, parallelBackend, parallelDiag, parallelDotMultiply, parallelIdentity, parallelMatrix, parallelMatrixAbs, parallelMatrixAdd, parallelMatrixColumn, parallelMatrixCos, parallelMatrixDiagonal, parallelMatrixDistance, parallelMatrixDivide, parallelMatrixDot, parallelMatrixExp, parallelMatrixHistogram, parallelMatrixLog, parallelMatrixMatvec, parallelMatrixMax, parallelMatrixMean, parallelMatrixMin, parallelMatrixMultiply, parallelMatrixNorm, parallelMatrixOperations, parallelMatrixOuter, parallelMatrixRow, parallelMatrixSin, parallelMatrixSize, parallelMatrixSqrt, parallelMatrixSquare, parallelMatrixStd, parallelMatrixSubset, parallelMatrixSubtract, parallelMatrixSum, parallelMatrixTan, parallelMatrixTrace, parallelMatrixTranspose, parallelMatrixVariance, parallelOnes, parallelRandom, parallelUnaryMinus, parallelZeros, pinv$1 as pinv, pow, powerIteration, ql, qr, qrPivoted, random, row, rq, singularValues, size, spectralRadiusWasm, sqrt, square, subset, subtract, sum, svd, svdWasm, terminateParallelMatrix, trace, transpose, typedMatrixOperations, unaryMinus, wasmBackend, zeros };
package/dist/index.js CHANGED
@@ -5740,11 +5740,13 @@ function eigGeneral(A, computeVectors, symmetric) {
5740
5740
  const values = [];
5741
5741
  for (let j = 0; j < nn; j++) values.push({ re: d[j], im: e[j] });
5742
5742
  let vectors;
5743
+ let vectorsIm;
5743
5744
  if (computeVectors) {
5744
5745
  vectors = [];
5745
- for (let j = 0; j < nn; j++) {
5746
- const vec = new Array(nn).fill(0);
5746
+ vectorsIm = [];
5747
+ for (let j = 0; j < nn; ) {
5747
5748
  if (e[j] === 0) {
5749
+ const vec = new Array(nn).fill(0);
5748
5750
  let colNorm = 0;
5749
5751
  for (let i = 0; i < nn; i++) colNorm += V[i * nn + j] * V[i * nn + j];
5750
5752
  colNorm = Math.sqrt(colNorm);
@@ -5753,13 +5755,42 @@ function eigGeneral(A, computeVectors, symmetric) {
5753
5755
  } else {
5754
5756
  for (let i = 0; i < nn; i++) vec[i] = V[i * nn + j];
5755
5757
  }
5758
+ vectors.push(vec);
5759
+ vectorsIm.push(new Array(nn).fill(0));
5760
+ j++;
5761
+ } else {
5762
+ const vecRe = new Array(nn).fill(0);
5763
+ const vecIm = new Array(nn).fill(0);
5764
+ let colNorm = 0;
5765
+ for (let i = 0; i < nn; i++) {
5766
+ const re = V[i * nn + j];
5767
+ const im = V[i * nn + (j + 1)];
5768
+ colNorm += re * re + im * im;
5769
+ }
5770
+ colNorm = Math.sqrt(colNorm);
5771
+ if (colNorm > 1e-300) {
5772
+ for (let i = 0; i < nn; i++) {
5773
+ vecRe[i] = V[i * nn + j] / colNorm;
5774
+ vecIm[i] = V[i * nn + (j + 1)] / colNorm;
5775
+ }
5776
+ } else {
5777
+ for (let i = 0; i < nn; i++) {
5778
+ vecRe[i] = V[i * nn + j];
5779
+ vecIm[i] = V[i * nn + (j + 1)];
5780
+ }
5781
+ }
5782
+ vectors.push(vecRe);
5783
+ vectorsIm.push(vecIm);
5784
+ vectors.push(vecRe.slice());
5785
+ vectorsIm.push(vecIm.map((x2) => -x2));
5786
+ j += 2;
5756
5787
  }
5757
- vectors.push(vec);
5758
5788
  }
5759
5789
  } else {
5760
5790
  vectors = eye(nn);
5791
+ vectorsIm = Array.from({ length: nn }, () => new Array(nn).fill(0));
5761
5792
  }
5762
- return { values, vectors, isSymmetric: symmetric };
5793
+ return { values, vectors, vectorsIm, isSymmetric: symmetric };
5763
5794
  }
5764
5795
  function eig(matrix2, options = {}) {
5765
5796
  const { computeVectors = true } = options;
@@ -5775,7 +5806,7 @@ function eig(matrix2, options = {}) {
5775
5806
  }
5776
5807
  const n = A.length;
5777
5808
  if (n === 0) {
5778
- return { values: [], vectors: [], isSymmetric: true };
5809
+ return { values: [], vectors: [], vectorsIm: [], isSymmetric: true };
5779
5810
  }
5780
5811
  for (let i = 0; i < n; i++) {
5781
5812
  if (A[i].length !== n) {
@@ -5787,6 +5818,7 @@ function eig(matrix2, options = {}) {
5787
5818
  return {
5788
5819
  values: [{ re: A[0][0], im: 0 }],
5789
5820
  vectors: [[1]],
5821
+ vectorsIm: [[0]],
5790
5822
  isSymmetric: symmetric
5791
5823
  };
5792
5824
  }
@@ -6224,7 +6256,7 @@ function normFro(matrix2) {
6224
6256
  async function eigWasm(matrix2, options) {
6225
6257
  const n = matrix2.length;
6226
6258
  if (n === 0) {
6227
- return { values: [], vectors: [], isSymmetric: true };
6259
+ return { values: [], vectors: [], vectorsIm: [], isSymmetric: true };
6228
6260
  }
6229
6261
  for (let i = 0; i < n; i++) {
6230
6262
  if (matrix2[i].length !== n) {
@@ -7391,6 +7423,236 @@ function isSymmetricMatrix(A, tol = 1e-8) {
7391
7423
  return true;
7392
7424
  }
7393
7425
 
7426
+ // src/operations/qr-pivoted.ts
7427
+ init_DenseMatrix();
7428
+ function qrPivoted(A, opts) {
7429
+ const m = A.rows;
7430
+ const n = A.cols;
7431
+ const tol = opts?.tolerance ?? 1e-10;
7432
+ const k = Math.min(m, n);
7433
+ if (m === 0 || n === 0) {
7434
+ return {
7435
+ Q: DenseMatrix.identity(m),
7436
+ R: DenseMatrix.zeros(k, n),
7437
+ P: Array.from({ length: n }, (_, i) => i),
7438
+ rank: 0
7439
+ };
7440
+ }
7441
+ const W = A.toArray();
7442
+ const Qacc = eye(m);
7443
+ const perm = Array.from({ length: n }, (_, i) => i);
7444
+ const colNormSq = new Array(n).fill(0);
7445
+ for (let j = 0; j < n; j++) {
7446
+ let s = 0;
7447
+ for (let i = 0; i < m; i++) s += W[i][j] * W[i][j];
7448
+ colNormSq[j] = s;
7449
+ }
7450
+ for (let c = 0; c < k; c++) {
7451
+ let pivotCol = c;
7452
+ let maxNorm = colNormSq[c];
7453
+ for (let j = c + 1; j < n; j++) {
7454
+ if (colNormSq[j] > maxNorm) {
7455
+ maxNorm = colNormSq[j];
7456
+ pivotCol = j;
7457
+ }
7458
+ }
7459
+ if (pivotCol !== c) {
7460
+ for (let i = 0; i < m; i++) {
7461
+ const t = W[i][c];
7462
+ W[i][c] = W[i][pivotCol];
7463
+ W[i][pivotCol] = t;
7464
+ }
7465
+ const tn = colNormSq[c];
7466
+ colNormSq[c] = colNormSq[pivotCol];
7467
+ colNormSq[pivotCol] = tn;
7468
+ const tp = perm[c];
7469
+ perm[c] = perm[pivotCol];
7470
+ perm[pivotCol] = tp;
7471
+ }
7472
+ const col = [];
7473
+ for (let i = c; i < m; i++) col.push(W[i][c]);
7474
+ const { v, beta } = householder(col, 2);
7475
+ if (beta !== 0) {
7476
+ applyHouseholderLeft(W, v, beta, c, c);
7477
+ applyHouseholderRight(Qacc, v, beta, 0, c);
7478
+ }
7479
+ for (let j = c + 1; j < n; j++) {
7480
+ let s = 0;
7481
+ for (let i = c + 1; i < m; i++) s += W[i][j] * W[i][j];
7482
+ colNormSq[j] = s;
7483
+ }
7484
+ }
7485
+ for (let i = 0; i < m; i++) {
7486
+ for (let j = 0; j < Math.min(i, n); j++) {
7487
+ W[i][j] = 0;
7488
+ }
7489
+ }
7490
+ const rData = new Float64Array(k * n);
7491
+ for (let i = 0; i < k; i++) {
7492
+ for (let j = 0; j < n; j++) rData[i * n + j] = W[i][j];
7493
+ }
7494
+ const qData = new Float64Array(m * k);
7495
+ for (let i = 0; i < m; i++) {
7496
+ for (let j = 0; j < k; j++) qData[i * k + j] = Qacc[i][j];
7497
+ }
7498
+ const r00 = Math.abs(rData[0] ?? 0);
7499
+ let rank = 0;
7500
+ if (r00 > 0) {
7501
+ for (let i = 0; i < k; i++) {
7502
+ if (Math.abs(rData[i * n + i]) > tol * r00) rank++;
7503
+ }
7504
+ }
7505
+ return {
7506
+ Q: new DenseMatrix(m, k, qData),
7507
+ R: new DenseMatrix(k, n, rData),
7508
+ P: perm,
7509
+ rank
7510
+ };
7511
+ }
7512
+
7513
+ // src/operations/qr-family.ts
7514
+ init_DenseMatrix();
7515
+ function flipRows(M) {
7516
+ const m = M.rows;
7517
+ const n = M.cols;
7518
+ const src = M.toFloat64Array();
7519
+ const data = new Float64Array(m * n);
7520
+ for (let i = 0; i < m; i++) {
7521
+ for (let j = 0; j < n; j++) {
7522
+ data[i * n + j] = src[(m - 1 - i) * n + j];
7523
+ }
7524
+ }
7525
+ return new DenseMatrix(m, n, data);
7526
+ }
7527
+ function flipCols(M) {
7528
+ const m = M.rows;
7529
+ const n = M.cols;
7530
+ const src = M.toFloat64Array();
7531
+ const data = new Float64Array(m * n);
7532
+ for (let i = 0; i < m; i++) {
7533
+ for (let j = 0; j < n; j++) {
7534
+ data[i * n + j] = src[i * n + (n - 1 - j)];
7535
+ }
7536
+ }
7537
+ return new DenseMatrix(m, n, data);
7538
+ }
7539
+ function lq(A) {
7540
+ const { Q: Q1, R: R1 } = qr(A.transpose(), { mode: "reduced" });
7541
+ return { L: R1.transpose(), Q: Q1.transpose() };
7542
+ }
7543
+ function rq(A) {
7544
+ const B2 = flipRows(A).transpose();
7545
+ const { Q: Q1, R: R1 } = qr(B2, { mode: "reduced" });
7546
+ const R = flipCols(flipRows(R1.transpose()));
7547
+ const Q = flipRows(Q1.transpose());
7548
+ return { R, Q };
7549
+ }
7550
+ function ql(A) {
7551
+ const B2 = flipCols(A);
7552
+ const { Q: Q1, R: R1 } = qr(B2, { mode: "reduced" });
7553
+ const L = flipCols(flipRows(R1));
7554
+ const Q = flipCols(Q1);
7555
+ return { Q, L };
7556
+ }
7557
+
7558
+ // src/operations/condest.ts
7559
+ function luSolve(L, U, perm, n, b) {
7560
+ const pb = new Array(n);
7561
+ for (let i = 0; i < n; i++) pb[i] = b[perm[i]];
7562
+ const y = new Array(n);
7563
+ for (let i = 0; i < n; i++) {
7564
+ let s = pb[i];
7565
+ for (let j = 0; j < i; j++) s -= L[i * n + j] * y[j];
7566
+ y[i] = s;
7567
+ }
7568
+ const x = new Array(n);
7569
+ for (let i = n - 1; i >= 0; i--) {
7570
+ let s = y[i];
7571
+ for (let j = i + 1; j < n; j++) s -= U[i * n + j] * x[j];
7572
+ x[i] = s / U[i * n + i];
7573
+ }
7574
+ return x;
7575
+ }
7576
+ function luSolveTranspose(L, U, perm, n, b) {
7577
+ const z = new Array(n);
7578
+ for (let i = 0; i < n; i++) {
7579
+ let s = b[i];
7580
+ for (let j = 0; j < i; j++) s -= U[j * n + i] * z[j];
7581
+ z[i] = s / U[i * n + i];
7582
+ }
7583
+ const w = new Array(n);
7584
+ for (let i = n - 1; i >= 0; i--) {
7585
+ let s = z[i];
7586
+ for (let j = i + 1; j < n; j++) s -= L[j * n + i] * w[j];
7587
+ w[i] = s;
7588
+ }
7589
+ const x = new Array(n);
7590
+ for (let i = 0; i < n; i++) x[perm[i]] = w[i];
7591
+ return x;
7592
+ }
7593
+ function hagerNormEstimate(applyB, applyBT, n) {
7594
+ let x = new Array(n).fill(1 / n);
7595
+ let gamma = 0;
7596
+ let lastIndex = -1;
7597
+ for (let iter = 0; iter < 5; iter++) {
7598
+ const y = applyB(x);
7599
+ let newGamma = 0;
7600
+ for (const v of y) newGamma += Math.abs(v);
7601
+ if (iter > 0 && newGamma <= gamma) break;
7602
+ gamma = newGamma;
7603
+ const xi = y.map((v) => v >= 0 ? 1 : -1);
7604
+ const z = applyBT(xi);
7605
+ let maxIndex = 0;
7606
+ let maxAbs = Math.abs(z[0]);
7607
+ for (let i = 1; i < n; i++) {
7608
+ if (Math.abs(z[i]) > maxAbs) {
7609
+ maxAbs = Math.abs(z[i]);
7610
+ maxIndex = i;
7611
+ }
7612
+ }
7613
+ if (iter > 0 && maxIndex === lastIndex) break;
7614
+ lastIndex = maxIndex;
7615
+ x = new Array(n).fill(0);
7616
+ x[maxIndex] = 1;
7617
+ }
7618
+ return gamma;
7619
+ }
7620
+ function condest(A, p = 1) {
7621
+ if (p !== 1) {
7622
+ throw new Error(`condest: only the 1-norm estimator (p=1) is implemented (got p=${p})`);
7623
+ }
7624
+ const n = A.rows;
7625
+ if (A.cols !== n) {
7626
+ throw new Error(`condest: matrix must be square (got ${A.rows}\xD7${A.cols})`);
7627
+ }
7628
+ if (n === 0) return 0;
7629
+ const flat2 = A.toFloat64Array();
7630
+ let norm1A = 0;
7631
+ for (let j = 0; j < n; j++) {
7632
+ let colSum = 0;
7633
+ for (let i = 0; i < n; i++) colSum += Math.abs(flat2[i * n + j]);
7634
+ if (colSum > norm1A) norm1A = colSum;
7635
+ }
7636
+ if (norm1A === 0) return 0;
7637
+ let L;
7638
+ let U;
7639
+ let perm;
7640
+ try {
7641
+ const factors = lu(A);
7642
+ L = factors.L.toFloat64Array();
7643
+ U = factors.U.toFloat64Array();
7644
+ perm = factors.P;
7645
+ } catch {
7646
+ return Infinity;
7647
+ }
7648
+ const norm1Inv = hagerNormEstimate(
7649
+ (v) => luSolve(L, U, perm, n, v),
7650
+ (v) => luSolveTranspose(L, U, perm, n, v),
7651
+ n
7652
+ );
7653
+ return norm1A * norm1Inv;
7654
+ }
7655
+
7394
7656
  // src/typed-operations.ts
7395
7657
  init_DenseMatrix();
7396
7658
  import { mathTyped } from "@danielsimonjr/mathts-core";
@@ -8243,6 +8505,7 @@ export {
8243
8505
  clearFeatureCache,
8244
8506
  column,
8245
8507
  cond,
8508
+ condest,
8246
8509
  createBackendManager,
8247
8510
  createGPUMatrixBackend,
8248
8511
  createParallelBackend,
@@ -8279,6 +8542,7 @@ export {
8279
8542
  jsBackend,
8280
8543
  log,
8281
8544
  lowRankApprox,
8545
+ lq,
8282
8546
  lu,
8283
8547
  matrix,
8284
8548
  matrixExpm,
@@ -8338,9 +8602,12 @@ export {
8338
8602
  pinv,
8339
8603
  pow,
8340
8604
  powerIteration,
8605
+ ql,
8341
8606
  qr,
8607
+ qrPivoted,
8342
8608
  random,
8343
8609
  row,
8610
+ rq,
8344
8611
  singularValues,
8345
8612
  size,
8346
8613
  spectralRadiusWasm,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielsimonjr/mathts-matrix",
3
- "version": "0.4.6",
3
+ "version": "0.6.0",
4
4
  "description": "Matrix operations for MathTS with WASM/WebGPU backend support",
5
5
  "author": "Daniel Simon Jr.",
6
6
  "license": "MIT",