@danielsimonjr/mathts-functions 0.34.0 → 0.35.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 +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1538 -431
- package/dist/numeric/control-equations.d.ts +94 -0
- package/dist/numeric/control-equations.d.ts.map +1 -0
- package/dist/numeric/eigsh.d.ts +60 -0
- package/dist/numeric/eigsh.d.ts.map +1 -0
- package/dist/numeric/krylov.d.ts +83 -0
- package/dist/numeric/krylov.d.ts.map +1 -0
- package/dist/numeric/matrix-functions.d.ts +74 -0
- package/dist/numeric/matrix-functions.d.ts.map +1 -0
- package/dist/numeric/structured-solvers.d.ts +89 -0
- package/dist/numeric/structured-solvers.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control-theory matrix equations — `dlyap`/`care`/`dare`.
|
|
3
|
+
*
|
|
4
|
+
* These solve the algebraic matrix equations that underlie LQR (linear-
|
|
5
|
+
* quadratic regulator) and Kalman-filter design:
|
|
6
|
+
*
|
|
7
|
+
* - {@link dlyap} — discrete Lyapunov equation `A X Aᵀ − X + Q = 0`, solved
|
|
8
|
+
* directly via the Kronecker-product linear system
|
|
9
|
+
* `(I − A⊗A) vec(X) = vec(Q)` (exact for the small `n` this targets;
|
|
10
|
+
* the codebase's `linsolve` does the O(n²)³ = O(n⁶) dense solve).
|
|
11
|
+
* - {@link care} — continuous algebraic Riccati equation
|
|
12
|
+
* `AᵀX + XA − X B R⁻¹ Bᵀ X + Q = 0`, solved via the **matrix sign
|
|
13
|
+
* function** applied to the Hamiltonian `H = [[A, −BR⁻¹Bᵀ], [−Q, −Aᵀ]]`.
|
|
14
|
+
* This avoids both complex eigenvectors (this codebase's `eig` only
|
|
15
|
+
* returns real eigenvector columns — see `matrix-functions.ts` — so a
|
|
16
|
+
* Hamiltonian-eigenvector approach isn't usable here) and the need for a
|
|
17
|
+
* stabilizing initial gain that a Kleinman/Newton iteration would
|
|
18
|
+
* require (the natural starting point `X₀ = 0` is not stabilizing for
|
|
19
|
+
* e.g. the classic double-integrator `A = [[0,1],[0,0]]`, which is only
|
|
20
|
+
* marginally stable). The sign-function Newton iteration converges
|
|
21
|
+
* unconditionally (given the standard stabilizability/detectability
|
|
22
|
+
* assumptions) directly from `H` itself.
|
|
23
|
+
* - {@link dare} — discrete algebraic Riccati equation
|
|
24
|
+
* `AᵀXA − X − AᵀXB(R + BᵀXB)⁻¹BᵀXA + Q = 0`, solved via the
|
|
25
|
+
* **structure-preserving doubling algorithm** (SDA), the discrete-time
|
|
26
|
+
* analogue of the sign-function method above: it iterates a triple
|
|
27
|
+
* `(Aₖ, Gₖ, Hₖ)` with quadratic convergence and, likewise, needs no
|
|
28
|
+
* stabilizing initial gain.
|
|
29
|
+
*
|
|
30
|
+
* All three return the (numerically symmetrized) stabilizing solution `X`.
|
|
31
|
+
* Both `care`/`dare` require `R` invertible and `(A, B)` stabilizable — the
|
|
32
|
+
* standard LQR well-posedness assumptions.
|
|
33
|
+
*
|
|
34
|
+
* @packageDocumentation
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Solve the discrete-time Lyapunov (Stein) equation `A X Aᵀ − X + Q = 0` for
|
|
38
|
+
* `X`, given square `A` and `Q` of the same size.
|
|
39
|
+
*
|
|
40
|
+
* Builds the Kronecker-product linear system `(I − A⊗A) vec(X) = vec(Q)`
|
|
41
|
+
* explicitly (practical for the `n ≲ 20` this targets — the system has
|
|
42
|
+
* `n²` unknowns) and solves it with `linsolve`.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* dlyap([[0.5, 0], [0, 0.5]], [[1, 0], [0, 1]]) // => (4/3) * I (since 0.25x - x + 1 = 0)
|
|
46
|
+
*/
|
|
47
|
+
export declare function dlyap(A: number[][], Q: number[][]): number[][];
|
|
48
|
+
/**
|
|
49
|
+
* Solve the continuous-time algebraic Riccati equation (CARE)
|
|
50
|
+
* `AᵀX + XA − X B R⁻¹ Bᵀ X + Q = 0` for the stabilizing symmetric `X`,
|
|
51
|
+
* given `A` (n×n), `B` (n×m), `Q` (n×n, typically PSD), `R` (m×m, invertible).
|
|
52
|
+
*
|
|
53
|
+
* Method: Newton iteration for the **matrix sign function** of the
|
|
54
|
+
* Hamiltonian `H = [[A, −BR⁻¹Bᵀ], [−Q, −Aᵀ]]` (2n×2n):
|
|
55
|
+
*
|
|
56
|
+
* `Zₖ₊₁ = ½(cₖ Zₖ + cₖ⁻¹ Zₖ⁻¹)`, `Z₀ = H`, `cₖ = √(‖Zₖ⁻¹‖₁ / ‖Zₖ‖₁)`
|
|
57
|
+
*
|
|
58
|
+
* converging quadratically to `S = sign(H)`. The projector `P = ½(I − S)`
|
|
59
|
+
* has range equal to `H`'s stable (Re λ < 0) invariant subspace; taking its
|
|
60
|
+
* first `n` columns `U = [U₁; U₂]` (split at the `n`-th row) gives
|
|
61
|
+
* `X = U₂ U₁⁻¹` (real arithmetic throughout — no complex eigenvectors
|
|
62
|
+
* needed, unlike the classical Hamiltonian-eigenvector construction).
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* care([[0, 1], [0, 0]], [[0], [1]], [[1, 0], [0, 1]], [[1]])
|
|
66
|
+
* // => [[sqrt(3), 1], [1, sqrt(3)]] (pinned vs scipy.linalg.solve_continuous_are)
|
|
67
|
+
*/
|
|
68
|
+
export declare function care(A: number[][], B: number[][], Q: number[][], R: number[][]): number[][];
|
|
69
|
+
/**
|
|
70
|
+
* Solve the discrete-time algebraic Riccati equation (DARE)
|
|
71
|
+
* `AᵀXA − X − AᵀXB(R + BᵀXB)⁻¹BᵀXA + Q = 0` for the stabilizing symmetric
|
|
72
|
+
* `X`, given `A` (n×n), `B` (n×m), `Q` (n×n, typically PSD), `R` (m×m,
|
|
73
|
+
* invertible).
|
|
74
|
+
*
|
|
75
|
+
* Method: the **structure-preserving doubling algorithm** (SDA) — the
|
|
76
|
+
* discrete-time analogue of the sign-function iteration used by {@link care}.
|
|
77
|
+
* Starting from `A₀ = A`, `G₀ = B R⁻¹ Bᵀ`, `H₀ = Q`, it iterates
|
|
78
|
+
*
|
|
79
|
+
* `Aₖ₊₁ = Aₖ(I + GₖHₖ)⁻¹Aₖ`
|
|
80
|
+
* `Gₖ₊₁ = Gₖ + Aₖ(I + GₖHₖ)⁻¹Gₖ Aₖᵀ`
|
|
81
|
+
* `Hₖ₊₁ = Hₖ + Aₖᵀ Hₖ(I + GₖHₖ)⁻¹Aₖ`
|
|
82
|
+
*
|
|
83
|
+
* with `Hₖ → X` quadratically. Like {@link care}'s sign-function method, this
|
|
84
|
+
* needs no stabilizing initial gain (unlike a Kleinman/Newton iteration on
|
|
85
|
+
* the DARE directly) — only the standard stabilizability/detectability
|
|
86
|
+
* assumptions.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* dare([[1, 1], [0, 1]], [[0], [1]], [[1, 0], [0, 1]], [[1]])
|
|
90
|
+
* // => [[2.94712297, 2.36920541], [2.36920541, 4.61313426]]
|
|
91
|
+
* // (pinned vs scipy.linalg.solve_discrete_are)
|
|
92
|
+
*/
|
|
93
|
+
export declare function dare(A: number[][], B: number[][], Q: number[][], R: number[][]): number[][];
|
|
94
|
+
//# sourceMappingURL=control-equations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-equations.d.ts","sourceRoot":"","sources":["../../src/numeric/control-equations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAuJH;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAgB9D;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CA6C3F;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CA+B3F"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iterative symmetric eigensolver — Lanczos tridiagonalization + Rayleigh-Ritz.
|
|
3
|
+
*
|
|
4
|
+
* For large symmetric problems where the dense `eigs` (full O(n^3)
|
|
5
|
+
* eigendecomposition of the whole matrix) is prohibitive, `eigsh` extracts
|
|
6
|
+
* just the `k` largest or smallest eigenpairs. It builds an orthonormal
|
|
7
|
+
* Krylov basis `V` via the Lanczos iteration (with full reorthogonalization
|
|
8
|
+
* against every prior Lanczos vector, for numerical stability at the small
|
|
9
|
+
* sizes this is exercised at), forming the small tridiagonal projection
|
|
10
|
+
* `T = Vᵀ A V`. `T`'s eigenproblem is solved directly (cyclic Jacobi
|
|
11
|
+
* rotations — `T` is dense-symmetric-small by construction) and lifted back
|
|
12
|
+
* through `V` (Rayleigh-Ritz) to approximate `A`'s eigenpairs. Accepts either
|
|
13
|
+
* a dense matrix or a matvec callback (a linear operator, matching the
|
|
14
|
+
* `krylov.ts` convention) — the matvec form never forms `A` and requires
|
|
15
|
+
* `opts.n` since the dimension can't otherwise be inferred.
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
/** A symmetric linear operator: either a dense matrix or a matvec callback `x -> A x`. */
|
|
20
|
+
export type EigshOperatorInput = number[][] | ((x: number[]) => number[]);
|
|
21
|
+
/** Options accepted by {@link eigsh}. */
|
|
22
|
+
export interface EigshOptions {
|
|
23
|
+
/** Which end of the spectrum to return: `'LM'` (largest, default) or `'SM'` (smallest). */
|
|
24
|
+
which?: 'LM' | 'SM';
|
|
25
|
+
/** Dimension of `A` — required when `A` is a matvec callback. */
|
|
26
|
+
n?: number;
|
|
27
|
+
/** Convergence tolerance for diagonalizing the small tridiagonal projection (default 1e-10). */
|
|
28
|
+
tol?: number;
|
|
29
|
+
/** Maximum Lanczos steps (default `min(max(2k + 20, 20), n)`). */
|
|
30
|
+
maxIter?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of {@link eigsh}.
|
|
34
|
+
*
|
|
35
|
+
* `eigenvectors` is an `n x k` matrix with eigenvectors stored as **columns**:
|
|
36
|
+
* `eigenvectors[i][j]` is the `i`-th component of the `j`-th eigenvector,
|
|
37
|
+
* which corresponds to `eigenvalues[j]`.
|
|
38
|
+
*/
|
|
39
|
+
export interface EigshResult {
|
|
40
|
+
/** The `k` selected eigenvalues, ordered by `which` (largest-first for `'LM'`, smallest-first for `'SM'`). */
|
|
41
|
+
eigenvalues: number[];
|
|
42
|
+
/** The `k` corresponding eigenvectors, as columns of an `n x k` matrix. */
|
|
43
|
+
eigenvectors: number[][];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* `eigsh` — the `k` largest or smallest eigenpairs of a **symmetric** matrix
|
|
47
|
+
* via the Lanczos iteration, for problems too large for the dense `eigs`.
|
|
48
|
+
*
|
|
49
|
+
* `A` may be a dense `number[][]` or a matvec callback `x => A x` (in which
|
|
50
|
+
* case `opts.n` is required — the dimension can't be inferred from a
|
|
51
|
+
* function). Eigenvectors are returned as **columns** of an `n x k` matrix:
|
|
52
|
+
* `result.eigenvectors[i][j]` is the `i`-th component of the eigenvector for
|
|
53
|
+
* `result.eigenvalues[j]`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* eigsh([[2, 1, 0], [1, 2, 1], [0, 1, 2]], 1, { which: 'LM' })
|
|
57
|
+
* // => { eigenvalues: [2 + Math.SQRT2], eigenvectors: [[...]] }
|
|
58
|
+
*/
|
|
59
|
+
export declare function eigsh(a: EigshOperatorInput, k?: number, opts?: EigshOptions): EigshResult;
|
|
60
|
+
//# sourceMappingURL=eigsh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eigsh.d.ts","sourceRoot":"","sources":["../../src/numeric/eigsh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,0FAA0F;AAC1F,MAAM,MAAM,kBAAkB,GAAG,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC;AAE1E,yCAAyC;AACzC,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,KAAK,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACpB,iEAAiE;IACjE,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,gGAAgG;IAChG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,8GAA8G;IAC9G,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;CAC1B;AAkKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,SAAI,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,WAAW,CAmDpF"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iterative Krylov-subspace linear solvers.
|
|
3
|
+
*
|
|
4
|
+
* For the large sparse systems a dense factorization (`lusolve`, `qr`, …)
|
|
5
|
+
* can't handle — none of these methods ever form or fill in `A`. Each solver
|
|
6
|
+
* accepts either a dense matrix or a matvec callback (a "linear operator" in
|
|
7
|
+
* the SciPy/Trilinos sense), plus an optional preconditioner:
|
|
8
|
+
*
|
|
9
|
+
* - `cg` — Conjugate Gradient, for symmetric positive-definite `A`.
|
|
10
|
+
* - `minres` — MINRES, for symmetric (possibly indefinite) `A`.
|
|
11
|
+
* - `gmres` — restarted GMRES, for general nonsymmetric `A`.
|
|
12
|
+
* - `bicgstab` — BiCGSTAB, for general nonsymmetric `A`.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
/** A linear operator: either a dense matrix or a matvec callback `x -> A x`. */
|
|
17
|
+
export type LinearOperatorInput = number[][] | ((x: number[]) => number[]);
|
|
18
|
+
/** Preconditioner: `'jacobi'` (diagonal, dense-matrix only) or a custom `M⁻¹` callback. */
|
|
19
|
+
export type Preconditioner = 'jacobi' | ((r: number[]) => number[]);
|
|
20
|
+
/** Common options accepted by every solver in this module. */
|
|
21
|
+
export interface KrylovOptions {
|
|
22
|
+
/** Initial guess (default: the zero vector). */
|
|
23
|
+
x0?: number[];
|
|
24
|
+
/** Relative-residual convergence tolerance (default 1e-10). */
|
|
25
|
+
tol?: number;
|
|
26
|
+
/** Maximum iterations (default `min(10 * n, 1000)`). */
|
|
27
|
+
maxIter?: number;
|
|
28
|
+
/** Preconditioner: `'jacobi'` or a custom `(r) => M⁻¹r` callback. */
|
|
29
|
+
preconditioner?: Preconditioner;
|
|
30
|
+
}
|
|
31
|
+
/** Options for {@link gmres}, adding the restart length. */
|
|
32
|
+
export interface GmresOptions extends KrylovOptions {
|
|
33
|
+
/** Restart length (default 30). */
|
|
34
|
+
restart?: number;
|
|
35
|
+
}
|
|
36
|
+
/** Result returned by every solver in this module. */
|
|
37
|
+
export interface KrylovResult {
|
|
38
|
+
/** Approximate solution. */
|
|
39
|
+
x: number[];
|
|
40
|
+
/** Number of iterations performed. */
|
|
41
|
+
iterations: number;
|
|
42
|
+
/** Whether the relative residual dropped below `tol`. */
|
|
43
|
+
converged: boolean;
|
|
44
|
+
/** Final relative residual `‖b − A x‖₂ / ‖b‖₂`. */
|
|
45
|
+
residual: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Conjugate Gradient (CG) — for symmetric positive-definite `A`.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* cg([[4, 1], [1, 3]], [1, 2]) // => { x: [1/11, 7/11], converged: true, ... }
|
|
52
|
+
*/
|
|
53
|
+
export declare function cg(a: LinearOperatorInput, b: number[], opts?: KrylovOptions): KrylovResult;
|
|
54
|
+
/**
|
|
55
|
+
* MINRES — for symmetric (possibly indefinite) `A`.
|
|
56
|
+
*
|
|
57
|
+
* Builds the preconditioned Lanczos tridiagonalization of `A` and, at each
|
|
58
|
+
* step, solves the growing `(k+1) x k` tridiagonal least-squares problem
|
|
59
|
+
* `min ||beta1 e1 - T_k y||` via a small dense Householder QR. This is the
|
|
60
|
+
* textbook MINRES minimization restated directly (rather than the
|
|
61
|
+
* incrementally-updated Givens-rotation form), which keeps it simple to
|
|
62
|
+
* verify against a closed-form oracle at the cost of some redundant work
|
|
63
|
+
* per iteration — acceptable since `maxIter` is bounded by `min(10n, 1000)`.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* minres([[0, 1], [1, 0]], [1, 2]) // => { x: [2, 1], converged: true, ... }
|
|
67
|
+
*/
|
|
68
|
+
export declare function minres(a: LinearOperatorInput, b: number[], opts?: KrylovOptions): KrylovResult;
|
|
69
|
+
/**
|
|
70
|
+
* Restarted GMRES — for general nonsymmetric `A`.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* gmres([[3, 1], [0, 2]], [4, 2]) // => { x: [1, 1], converged: true, ... }
|
|
74
|
+
*/
|
|
75
|
+
export declare function gmres(a: LinearOperatorInput, b: number[], opts?: GmresOptions): KrylovResult;
|
|
76
|
+
/**
|
|
77
|
+
* BiCGSTAB — for general nonsymmetric `A`.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* bicgstab([[3, 1], [0, 2]], [4, 2]) // => { x: [1, 1], converged: true, ... }
|
|
81
|
+
*/
|
|
82
|
+
export declare function bicgstab(a: LinearOperatorInput, b: number[], opts?: KrylovOptions): KrylovResult;
|
|
83
|
+
//# sourceMappingURL=krylov.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"krylov.d.ts","sourceRoot":"","sources":["../../src/numeric/krylov.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,gFAAgF;AAChF,MAAM,MAAM,mBAAmB,GAAG,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC;AAE3E,2FAA2F;AAC3F,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC;AAEpE,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,4DAA4D;AAC5D,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,CAAC,EAAE,MAAM,EAAE,CAAC;IACZ,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAmGD;;;;;GAKG;AACH,wBAAgB,EAAE,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAwC1F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAyF9F;AA8CD;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,YAAY,CA2F5F;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAqEhG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complex matrix functions — `funm`/`cosm`/`sinm` for a general real matrix.
|
|
3
|
+
*
|
|
4
|
+
* `funm(A, f)` evaluates a scalar analytic function `f` at a square matrix
|
|
5
|
+
* `A`, returning the complex matrix `f(A)`. Unlike `sqrtm`/`matrixLogm`
|
|
6
|
+
* (which only handle real matrices whose spectrum stays on the principal
|
|
7
|
+
* branch — positive reals for sqrt/log), `funm` accepts any real spectrum
|
|
8
|
+
* (negative, complex-conjugate pairs, …) because the result is allowed to be
|
|
9
|
+
* complex-valued.
|
|
10
|
+
*
|
|
11
|
+
* Algorithm (diagonalizable matrices with distinct eigenvalues):
|
|
12
|
+
* - If `A` is diagonal, `f(A)` is exact and trivial: apply `f` to each
|
|
13
|
+
* diagonal entry (handles repeated eigenvalues fine, since a diagonal
|
|
14
|
+
* matrix is always diagonalizable regardless of eigenvalue multiplicity).
|
|
15
|
+
* - Otherwise, compute `A`'s eigenvalues `λ_1, …, λ_n` (via the shared
|
|
16
|
+
* `@danielsimonjr/mathts-matrix` `eig` — Householder + Francis QR) and,
|
|
17
|
+
* when they are all distinct, apply the Lagrange-Sylvester interpolation
|
|
18
|
+
* formula for a diagonalizable matrix with simple spectrum:
|
|
19
|
+
*
|
|
20
|
+
* f(A) = Σ_i f(λ_i) · L_i(A), L_i(A) = Π_{j≠i} (A − λ_j I) / (λ_i − λ_j)
|
|
21
|
+
*
|
|
22
|
+
* evaluated in complex arithmetic (`A` embedded with zero imaginary
|
|
23
|
+
* part). This needs only eigenvalues, not eigenvectors, and is exact for
|
|
24
|
+
* any polynomial or entire function `f` (cos, sin, sqrt, exp, log, …)
|
|
25
|
+
* whenever the spectrum is simple.
|
|
26
|
+
*
|
|
27
|
+
* Limitation (documented, not yet implemented): matrices with repeated (or
|
|
28
|
+
* numerically indistinguishable) eigenvalues that are NOT diagonal — i.e.
|
|
29
|
+
* genuinely defective/non-diagonalizable matrices, or diagonalizable
|
|
30
|
+
* matrices with a repeated eigenvalue and off-diagonal structure — are not
|
|
31
|
+
* supported; `funm` throws rather than silently return a wrong answer. A
|
|
32
|
+
* full Schur-Parlett block recurrence (Higham 2008 Ch. 9) would lift this
|
|
33
|
+
* restriction; that is future work, not required by the current call sites.
|
|
34
|
+
*
|
|
35
|
+
* @packageDocumentation
|
|
36
|
+
*/
|
|
37
|
+
/** A complex number as a plain `{re, im}` pair. */
|
|
38
|
+
export interface ComplexValue {
|
|
39
|
+
re: number;
|
|
40
|
+
im: number;
|
|
41
|
+
}
|
|
42
|
+
/** A complex-valued dense matrix, stored as parallel real/imaginary 2-D arrays. */
|
|
43
|
+
export interface ComplexMatrix {
|
|
44
|
+
re: number[][];
|
|
45
|
+
im: number[][];
|
|
46
|
+
}
|
|
47
|
+
/** A scalar analytic function to be applied to a matrix's spectrum. */
|
|
48
|
+
export type ScalarComplexFunction = (z: ComplexValue) => ComplexValue;
|
|
49
|
+
/**
|
|
50
|
+
* Evaluate the matrix function `f(A)` for a square real matrix `A`, returning
|
|
51
|
+
* a complex matrix `{re, im}`.
|
|
52
|
+
*
|
|
53
|
+
* Supports diagonal matrices unconditionally (exact, elementwise), and
|
|
54
|
+
* general diagonalizable matrices whose eigenvalues are pairwise distinct
|
|
55
|
+
* (Lagrange-Sylvester interpolation on the spectrum — see module docs).
|
|
56
|
+
* Throws for matrices with repeated or numerically indistinguishable
|
|
57
|
+
* eigenvalues that are not diagonal (defective / non-diagonalizable case;
|
|
58
|
+
* not yet supported — see module docs for the Schur-Parlett follow-up).
|
|
59
|
+
*
|
|
60
|
+
* @param A - Square real matrix, as a plain 2-D array.
|
|
61
|
+
* @param f - Scalar function to apply to each eigenvalue, e.g. `cos`, `sin`,
|
|
62
|
+
* `sqrt`, `exp`, `log`, extended to complex arguments.
|
|
63
|
+
* @returns `{ re, im }` — the (possibly complex) matrix `f(A)`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function funm(A: number[][], f: ScalarComplexFunction): ComplexMatrix;
|
|
66
|
+
/** Complex cosine: `cos(z) = cos(re)cosh(im) - i sin(re)sinh(im)`. */
|
|
67
|
+
export declare function complexCos(z: ComplexValue): ComplexValue;
|
|
68
|
+
/** Complex sine: `sin(z) = sin(re)cosh(im) + i cos(re)sinh(im)`. */
|
|
69
|
+
export declare function complexSin(z: ComplexValue): ComplexValue;
|
|
70
|
+
/** Matrix cosine `cos(A)`, via {@link funm} with {@link complexCos}. */
|
|
71
|
+
export declare function cosm(A: number[][]): ComplexMatrix;
|
|
72
|
+
/** Matrix sine `sin(A)`, via {@link funm} with {@link complexSin}. */
|
|
73
|
+
export declare function sinm(A: number[][]): ComplexMatrix;
|
|
74
|
+
//# sourceMappingURL=matrix-functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix-functions.d.ts","sourceRoot":"","sources":["../../src/numeric/matrix-functions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAIH,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;IACf,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;CAChB;AAED,uEAAuE;AACvE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,EAAE,YAAY,KAAK,YAAY,CAAC;AAoHtE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,qBAAqB,GAAG,aAAa,CAuD3E;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,YAAY,CAKxD;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,YAAY,CAKxD;AAED,wEAAwE;AACxE,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,aAAa,CAEjD;AAED,sEAAsE;AACtE,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,aAAa,CAEjD"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured and indefinite direct linear solvers.
|
|
3
|
+
*
|
|
4
|
+
* These exploit matrix structure (tridiagonal, banded, Toeplitz, symmetric
|
|
5
|
+
* indefinite) to solve `Ax = b` in less than the O(n^3) a general dense LU
|
|
6
|
+
* (`lusolve`) would cost, or — for `ldl` — to factor matrices `cholesky`
|
|
7
|
+
* cannot handle because they are not positive-definite (e.g. KKT systems):
|
|
8
|
+
*
|
|
9
|
+
* - `thomasSolve` — the Thomas algorithm, O(n) for tridiagonal systems.
|
|
10
|
+
* - `solveBanded` — banded-aware Gaussian elimination (no pivoting; touches
|
|
11
|
+
* only the O(n(l+u)) entries inside the band), for systems with `l` lower
|
|
12
|
+
* and `u` upper nonzero diagonals.
|
|
13
|
+
* - `toeplitzSolve` — the Levinson–Durbin recursion, O(n^2) for a Toeplitz
|
|
14
|
+
* system given only its first row and column.
|
|
15
|
+
* - `ldl` — Bunch–Kaufman-pivoted LDLᵀ factorization of a symmetric
|
|
16
|
+
* (possibly indefinite) matrix, with 1x1/2x2 diagonal blocks.
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Thomas algorithm — O(n) solve of a tridiagonal system `Ax = d`.
|
|
22
|
+
*
|
|
23
|
+
* `A` is the tridiagonal matrix with subdiagonal `sub` (length n−1),
|
|
24
|
+
* diagonal `diag` (length n), and superdiagonal `sup` (length n−1). No
|
|
25
|
+
* pivoting is performed (as with any tridiagonal Thomas solve); the matrix
|
|
26
|
+
* should be diagonally dominant or otherwise stable without it.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* thomasSolve([-1, -1], [2, 2, 2], [-1, -1], [1, 0, 1]) // => [1, 1, 1]
|
|
30
|
+
*/
|
|
31
|
+
export declare function thomasSolve(sub: number[], diag: number[], sup: number[], d: number[]): number[];
|
|
32
|
+
/**
|
|
33
|
+
* Banded-aware Gaussian elimination — solve `Ax = b` for a matrix with `l`
|
|
34
|
+
* nonzero lower diagonals and `u` nonzero upper diagonals (all other entries
|
|
35
|
+
* are assumed zero, though `A` is passed as a full dense matrix). Only the
|
|
36
|
+
* O(n(l+u)) entries inside the band are touched during elimination and
|
|
37
|
+
* back-substitution. No pivoting is performed — as with {@link thomasSolve},
|
|
38
|
+
* the matrix should be diagonally dominant or otherwise stable without it.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* solveBanded(1, 1, [[2, -1, 0], [-1, 2, -1], [0, -1, 2]], [1, 0, 1]) // => [1, 1, 1]
|
|
42
|
+
*/
|
|
43
|
+
export declare function solveBanded(l: number, u: number, A: number[][], b: number[]): number[];
|
|
44
|
+
/**
|
|
45
|
+
* Levinson–Durbin recursion — O(n²) solve of a Toeplitz system `Tx = b`
|
|
46
|
+
* given only the first column `c` and first row `r` (`c[0]` must equal
|
|
47
|
+
* `r[0]`, the shared diagonal value). `T[i][j] = c[i-j]` for `i >= j`, else
|
|
48
|
+
* `r[j-i]`.
|
|
49
|
+
*
|
|
50
|
+
* Order-recursively builds the solution together with two auxiliary
|
|
51
|
+
* "predictor" vectors — one for `T`, one for `Tᵀ` (mutually coupled via the
|
|
52
|
+
* persymmetry `J T J = Tᵀ` that every Toeplitz matrix has, `J` the
|
|
53
|
+
* reversal/exchange matrix) — which is what makes a general (non-symmetric)
|
|
54
|
+
* Toeplitz system solvable in O(n²) rather than O(n³).
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* toeplitzSolve([2, 1], [2, 1], [1, 2]) // => [0, 1]
|
|
58
|
+
*/
|
|
59
|
+
export declare function toeplitzSolve(c: number[], r: number[], b: number[]): number[];
|
|
60
|
+
/** Result of {@link ldl}. */
|
|
61
|
+
export interface LDLResult {
|
|
62
|
+
/** Unit lower-triangular factor. */
|
|
63
|
+
L: number[][];
|
|
64
|
+
/** Block-diagonal factor (1x1 or 2x2 blocks along the diagonal). */
|
|
65
|
+
D: number[][];
|
|
66
|
+
/**
|
|
67
|
+
* Permutation such that `(P A Pᵀ)[i][j] = A[perm[i]][perm[j]]` and
|
|
68
|
+
* `L D Lᵀ = P A Pᵀ`.
|
|
69
|
+
*/
|
|
70
|
+
perm: number[];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Bunch–Kaufman-pivoted LDLᵀ factorization of a symmetric (possibly
|
|
74
|
+
* indefinite) matrix `A`, useful for symmetric systems `cholesky` can't
|
|
75
|
+
* handle because they aren't positive-definite (e.g. KKT / saddle-point
|
|
76
|
+
* systems from constrained optimization).
|
|
77
|
+
*
|
|
78
|
+
* Reconstruction identity: `L D Lᵀ = P A Pᵀ`, where `P` is the permutation
|
|
79
|
+
* matrix with `P[i][perm[i]] = 1`, i.e. `(P A Pᵀ)[i][j] = A[perm[i]][perm[j]]`.
|
|
80
|
+
* `L` is unit lower-triangular; `D` is block-diagonal with 1x1 or 2x2 blocks
|
|
81
|
+
* (2x2 blocks appear where a pivot would otherwise be too small relative to
|
|
82
|
+
* the rest of its column, per the standard Bunch–Kaufman pivot selection).
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const { L, D, perm } = ldl([[1, 2, 3], [2, 1, 4], [3, 4, 1]]);
|
|
86
|
+
* // L D L^T reconstructs A with rows/cols permuted by perm.
|
|
87
|
+
*/
|
|
88
|
+
export declare function ldl(A: number[][]): LDLResult;
|
|
89
|
+
//# sourceMappingURL=structured-solvers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-solvers.d.ts","sourceRoot":"","sources":["../../src/numeric/structured-solvers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA+B/F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAwCtF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA8E7E;AAED,6BAA6B;AAC7B,MAAM,WAAW,SAAS;IACxB,oCAAoC;IACpC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IACd,oEAAoE;IACpE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IACd;;;OAGG;IACH,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,SAAS,CAwG5C"}
|
package/package.json
CHANGED