@danielsimonjr/mathts-matrix 0.1.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 +66 -0
- package/dist/chunk-I6QDZ7SC.js +497 -0
- package/dist/eig-YRLUBCGK.js +10 -0
- package/dist/index.d.ts +2837 -0
- package/dist/index.js +7404 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @danielsimonjr/mathts-matrix
|
|
2
|
+
|
|
3
|
+
High-performance matrix operations with multi-backend support (JS/WASM/GPU).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @danielsimonjr/mathts-matrix
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Matrix, DenseMatrix, backends } from '@danielsimonjr/mathts-matrix';
|
|
15
|
+
|
|
16
|
+
// Create a matrix from a 2D array
|
|
17
|
+
const A = Matrix.from([
|
|
18
|
+
[1, 2, 3],
|
|
19
|
+
[4, 5, 6],
|
|
20
|
+
[7, 8, 9]
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
// Basic operations (coming soon)
|
|
24
|
+
const det = A.determinant();
|
|
25
|
+
const inv = A.inverse();
|
|
26
|
+
const eig = A.eigenvalues();
|
|
27
|
+
|
|
28
|
+
// Configure backend
|
|
29
|
+
backends.configure({
|
|
30
|
+
backend: 'wasm', // Force WASM backend
|
|
31
|
+
autoBackend: true, // Or let it auto-select
|
|
32
|
+
wasmThreshold: 1000, // Switch to WASM above 1000 elements
|
|
33
|
+
gpuThreshold: 100000, // Switch to GPU above 100K elements
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Backends
|
|
38
|
+
|
|
39
|
+
| Backend | Trigger | Performance |
|
|
40
|
+
|---------|---------|-------------|
|
|
41
|
+
| **JS** | Default | 1x baseline |
|
|
42
|
+
| **WASM** | >1K elements | ~10x faster |
|
|
43
|
+
| **GPU** | >100K elements | ~100x faster |
|
|
44
|
+
|
|
45
|
+
## Matrix Types
|
|
46
|
+
|
|
47
|
+
- `DenseMatrix` - Standard dense storage (row-major)
|
|
48
|
+
- `SparseMatrix` - CSR format for sparse data
|
|
49
|
+
|
|
50
|
+
## Status
|
|
51
|
+
|
|
52
|
+
This package is under active development. Currently implemented:
|
|
53
|
+
|
|
54
|
+
- [x] Type definitions
|
|
55
|
+
- [x] Backend infrastructure
|
|
56
|
+
- [x] Dense matrix structure
|
|
57
|
+
- [x] Sparse matrix (CSR) structure
|
|
58
|
+
- [ ] Matrix operations (add, multiply, etc.)
|
|
59
|
+
- [ ] WASM backend
|
|
60
|
+
- [ ] GPU backend
|
|
61
|
+
- [ ] LU/QR/SVD decompositions
|
|
62
|
+
- [ ] Eigenvalue solvers
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/operations/eig.ts
|
|
23
|
+
var DEFAULT_MAX_ITERATIONS = 1e3;
|
|
24
|
+
var DEFAULT_TOLERANCE = 1e-12;
|
|
25
|
+
function isSymmetric(matrix, tolerance = 1e-10) {
|
|
26
|
+
const n = matrix.length;
|
|
27
|
+
if (n === 0) return true;
|
|
28
|
+
if (matrix[0].length !== n) return false;
|
|
29
|
+
for (let i = 0; i < n; i++) {
|
|
30
|
+
for (let j = i + 1; j < n; j++) {
|
|
31
|
+
if (Math.abs(matrix[i][j] - matrix[j][i]) > tolerance) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
function eye(n) {
|
|
39
|
+
const I = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
40
|
+
for (let i = 0; i < n; i++) {
|
|
41
|
+
I[i][i] = 1;
|
|
42
|
+
}
|
|
43
|
+
return I;
|
|
44
|
+
}
|
|
45
|
+
function cloneMatrix(A) {
|
|
46
|
+
return A.map((row) => [...row]);
|
|
47
|
+
}
|
|
48
|
+
function householder(x) {
|
|
49
|
+
const n = x.length;
|
|
50
|
+
let sigma = 0;
|
|
51
|
+
for (let i = 1; i < n; i++) {
|
|
52
|
+
sigma += x[i] * x[i];
|
|
53
|
+
}
|
|
54
|
+
const v = [...x];
|
|
55
|
+
v[0] = 1;
|
|
56
|
+
if (sigma === 0 && x[0] >= 0) {
|
|
57
|
+
return { v, beta: 0 };
|
|
58
|
+
} else if (sigma === 0 && x[0] < 0) {
|
|
59
|
+
return { v, beta: -2 };
|
|
60
|
+
} else {
|
|
61
|
+
const mu = Math.sqrt(x[0] * x[0] + sigma);
|
|
62
|
+
if (x[0] <= 0) {
|
|
63
|
+
v[0] = x[0] - mu;
|
|
64
|
+
} else {
|
|
65
|
+
v[0] = -sigma / (x[0] + mu);
|
|
66
|
+
}
|
|
67
|
+
const beta = 2 * v[0] * v[0] / (sigma + v[0] * v[0]);
|
|
68
|
+
const v0 = v[0];
|
|
69
|
+
for (let i = 0; i < n; i++) {
|
|
70
|
+
v[i] /= v0;
|
|
71
|
+
}
|
|
72
|
+
return { v, beta };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function applyHouseholderLeft(A, v, beta, startRow, startCol) {
|
|
76
|
+
const n = A[0].length;
|
|
77
|
+
const len = v.length;
|
|
78
|
+
for (let j = startCol; j < n; j++) {
|
|
79
|
+
let dot = 0;
|
|
80
|
+
for (let i = 0; i < len; i++) {
|
|
81
|
+
dot += v[i] * A[startRow + i][j];
|
|
82
|
+
}
|
|
83
|
+
dot *= beta;
|
|
84
|
+
for (let i = 0; i < len; i++) {
|
|
85
|
+
A[startRow + i][j] -= dot * v[i];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function applyHouseholderRight(A, v, beta, startRow, startCol) {
|
|
90
|
+
const m = A.length;
|
|
91
|
+
const len = v.length;
|
|
92
|
+
for (let i = startRow; i < m; i++) {
|
|
93
|
+
let dot = 0;
|
|
94
|
+
for (let j = 0; j < len; j++) {
|
|
95
|
+
dot += A[i][startCol + j] * v[j];
|
|
96
|
+
}
|
|
97
|
+
dot *= beta;
|
|
98
|
+
for (let j = 0; j < len; j++) {
|
|
99
|
+
A[i][startCol + j] -= dot * v[j];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function hessenberg(A) {
|
|
104
|
+
const n = A.length;
|
|
105
|
+
const H = cloneMatrix(A);
|
|
106
|
+
let Q = eye(n);
|
|
107
|
+
for (let k = 0; k < n - 2; k++) {
|
|
108
|
+
const x = [];
|
|
109
|
+
for (let i = k + 1; i < n; i++) {
|
|
110
|
+
x.push(H[i][k]);
|
|
111
|
+
}
|
|
112
|
+
const { v, beta } = householder(x);
|
|
113
|
+
if (beta !== 0) {
|
|
114
|
+
applyHouseholderLeft(H, v, beta, k + 1, k);
|
|
115
|
+
applyHouseholderRight(H, v, beta, 0, k + 1);
|
|
116
|
+
applyHouseholderRight(Q, v, beta, 0, k + 1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (let i = 0; i < n; i++) {
|
|
120
|
+
for (let j = 0; j < i - 1; j++) {
|
|
121
|
+
H[i][j] = 0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { H, Q };
|
|
125
|
+
}
|
|
126
|
+
function givens(a, b) {
|
|
127
|
+
if (b === 0) {
|
|
128
|
+
return { c: 1, s: 0 };
|
|
129
|
+
} else if (Math.abs(b) > Math.abs(a)) {
|
|
130
|
+
const t = -a / b;
|
|
131
|
+
const s = 1 / Math.sqrt(1 + t * t);
|
|
132
|
+
return { c: s * t, s };
|
|
133
|
+
} else {
|
|
134
|
+
const t = -b / a;
|
|
135
|
+
const c = 1 / Math.sqrt(1 + t * t);
|
|
136
|
+
return { c, s: c * t };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function applyGivensLeft(A, c, s, i, k, startCol) {
|
|
140
|
+
const n = A[0].length;
|
|
141
|
+
for (let j = startCol; j < n; j++) {
|
|
142
|
+
const temp = c * A[i][j] - s * A[k][j];
|
|
143
|
+
A[k][j] = s * A[i][j] + c * A[k][j];
|
|
144
|
+
A[i][j] = temp;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function applyGivensRight(A, c, s, i, k, startRow) {
|
|
148
|
+
const m = A.length;
|
|
149
|
+
for (let j = startRow; j < m; j++) {
|
|
150
|
+
const temp = c * A[j][i] - s * A[j][k];
|
|
151
|
+
A[j][k] = s * A[j][i] + c * A[j][k];
|
|
152
|
+
A[j][i] = temp;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function qrStep(H, Q, start, end) {
|
|
156
|
+
const n = end - start + 1;
|
|
157
|
+
if (n < 2) return;
|
|
158
|
+
const a = H[end - 1][end - 1];
|
|
159
|
+
const b = H[end - 1][end];
|
|
160
|
+
const c = H[end][end - 1];
|
|
161
|
+
const d = H[end][end];
|
|
162
|
+
const trace = a + d;
|
|
163
|
+
const det = a * d - b * c;
|
|
164
|
+
const disc = trace * trace - 4 * det;
|
|
165
|
+
let shift;
|
|
166
|
+
if (disc >= 0) {
|
|
167
|
+
const sqrtDisc = Math.sqrt(disc);
|
|
168
|
+
const e1 = (trace + sqrtDisc) / 2;
|
|
169
|
+
const e2 = (trace - sqrtDisc) / 2;
|
|
170
|
+
shift = Math.abs(e1 - d) < Math.abs(e2 - d) ? e1 : e2;
|
|
171
|
+
} else {
|
|
172
|
+
shift = d;
|
|
173
|
+
}
|
|
174
|
+
let x = H[start][start] - shift;
|
|
175
|
+
let y = H[start + 1][start];
|
|
176
|
+
for (let k = start; k < end; k++) {
|
|
177
|
+
const { c: c2, s } = givens(x, y);
|
|
178
|
+
applyGivensLeft(H, c2, s, k, k + 1, Math.max(0, k - 1));
|
|
179
|
+
applyGivensRight(H, c2, s, k, k + 1, 0);
|
|
180
|
+
applyGivensRight(Q, c2, s, k, k + 1, 0);
|
|
181
|
+
if (k < end - 1) {
|
|
182
|
+
x = H[k + 1][k];
|
|
183
|
+
y = H[k + 2][k];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function doubleShiftQR(H, Q, start, end) {
|
|
188
|
+
const n = H.length;
|
|
189
|
+
const a = H[end - 1][end - 1];
|
|
190
|
+
const b = H[end - 1][end];
|
|
191
|
+
const c = H[end][end - 1];
|
|
192
|
+
const d = H[end][end];
|
|
193
|
+
const s = a + d;
|
|
194
|
+
const t = a * d - b * c;
|
|
195
|
+
let x = H[start][start] * H[start][start] + H[start][start + 1] * H[start + 1][start] - s * H[start][start] + t;
|
|
196
|
+
let y = H[start + 1][start] * (H[start][start] + H[start + 1][start + 1] - s);
|
|
197
|
+
let z = H[start + 1][start] * H[start + 2][start + 1];
|
|
198
|
+
for (let k = start; k <= end - 2; k++) {
|
|
199
|
+
const { v, beta } = householder([x, y, z]);
|
|
200
|
+
const q = Math.max(start, k - 1);
|
|
201
|
+
for (let j = q; j < n; j++) {
|
|
202
|
+
let dot = v[0] * H[k][j] + v[1] * H[k + 1][j] + v[2] * H[k + 2][j];
|
|
203
|
+
dot *= beta;
|
|
204
|
+
H[k][j] -= dot * v[0];
|
|
205
|
+
H[k + 1][j] -= dot * v[1];
|
|
206
|
+
H[k + 2][j] -= dot * v[2];
|
|
207
|
+
}
|
|
208
|
+
const r = Math.min(k + 4, end + 1);
|
|
209
|
+
for (let i = 0; i < r; i++) {
|
|
210
|
+
let dot = v[0] * H[i][k] + v[1] * H[i][k + 1] + v[2] * H[i][k + 2];
|
|
211
|
+
dot *= beta;
|
|
212
|
+
H[i][k] -= dot * v[0];
|
|
213
|
+
H[i][k + 1] -= dot * v[1];
|
|
214
|
+
H[i][k + 2] -= dot * v[2];
|
|
215
|
+
}
|
|
216
|
+
for (let i = 0; i < n; i++) {
|
|
217
|
+
let dot = v[0] * Q[i][k] + v[1] * Q[i][k + 1] + v[2] * Q[i][k + 2];
|
|
218
|
+
dot *= beta;
|
|
219
|
+
Q[i][k] -= dot * v[0];
|
|
220
|
+
Q[i][k + 1] -= dot * v[1];
|
|
221
|
+
Q[i][k + 2] -= dot * v[2];
|
|
222
|
+
}
|
|
223
|
+
x = H[k + 1][k];
|
|
224
|
+
y = H[k + 2][k];
|
|
225
|
+
if (k < end - 2) {
|
|
226
|
+
z = H[k + 3][k];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const { c: cFinal, s: sFinal } = givens(x, y);
|
|
230
|
+
applyGivensLeft(H, cFinal, sFinal, end - 1, end, end - 2);
|
|
231
|
+
applyGivensRight(H, cFinal, sFinal, end - 1, end, 0);
|
|
232
|
+
applyGivensRight(Q, cFinal, sFinal, end - 1, end, 0);
|
|
233
|
+
}
|
|
234
|
+
function extractEigenvalues(H, tolerance) {
|
|
235
|
+
const n = H.length;
|
|
236
|
+
const eigenvalues = [];
|
|
237
|
+
let i = 0;
|
|
238
|
+
while (i < n) {
|
|
239
|
+
if (i === n - 1 || Math.abs(H[i + 1][i]) <= tolerance) {
|
|
240
|
+
eigenvalues.push({ re: H[i][i], im: 0 });
|
|
241
|
+
i++;
|
|
242
|
+
} else {
|
|
243
|
+
const a = H[i][i];
|
|
244
|
+
const b = H[i][i + 1];
|
|
245
|
+
const c = H[i + 1][i];
|
|
246
|
+
const d = H[i + 1][i + 1];
|
|
247
|
+
const trace = a + d;
|
|
248
|
+
const det = a * d - b * c;
|
|
249
|
+
const disc = trace * trace - 4 * det;
|
|
250
|
+
if (disc >= 0) {
|
|
251
|
+
const sqrtDisc = Math.sqrt(disc);
|
|
252
|
+
eigenvalues.push({ re: (trace + sqrtDisc) / 2, im: 0 });
|
|
253
|
+
eigenvalues.push({ re: (trace - sqrtDisc) / 2, im: 0 });
|
|
254
|
+
} else {
|
|
255
|
+
const realPart = trace / 2;
|
|
256
|
+
const imagPart = Math.sqrt(-disc) / 2;
|
|
257
|
+
eigenvalues.push({ re: realPart, im: imagPart });
|
|
258
|
+
eigenvalues.push({ re: realPart, im: -imagPart });
|
|
259
|
+
}
|
|
260
|
+
i += 2;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return eigenvalues;
|
|
264
|
+
}
|
|
265
|
+
function inverseIteration(A, eigenvalue, tolerance, maxIterations) {
|
|
266
|
+
const n = A.length;
|
|
267
|
+
if (eigenvalue.im !== 0) {
|
|
268
|
+
return new Array(n).fill(0);
|
|
269
|
+
}
|
|
270
|
+
const lambda = eigenvalue.re;
|
|
271
|
+
const shifted = cloneMatrix(A);
|
|
272
|
+
for (let i = 0; i < n; i++) {
|
|
273
|
+
shifted[i][i] -= lambda;
|
|
274
|
+
}
|
|
275
|
+
for (let i = 0; i < n; i++) {
|
|
276
|
+
shifted[i][i] += tolerance * 1e3;
|
|
277
|
+
}
|
|
278
|
+
const LU = cloneMatrix(shifted);
|
|
279
|
+
const perm = Array.from({ length: n }, (_, i) => i);
|
|
280
|
+
for (let k = 0; k < n; k++) {
|
|
281
|
+
let maxVal = Math.abs(LU[k][k]);
|
|
282
|
+
let maxIdx = k;
|
|
283
|
+
for (let i = k + 1; i < n; i++) {
|
|
284
|
+
if (Math.abs(LU[i][k]) > maxVal) {
|
|
285
|
+
maxVal = Math.abs(LU[i][k]);
|
|
286
|
+
maxIdx = i;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (maxIdx !== k) {
|
|
290
|
+
[LU[k], LU[maxIdx]] = [LU[maxIdx], LU[k]];
|
|
291
|
+
[perm[k], perm[maxIdx]] = [perm[maxIdx], perm[k]];
|
|
292
|
+
}
|
|
293
|
+
if (Math.abs(LU[k][k]) < tolerance) {
|
|
294
|
+
LU[k][k] = tolerance;
|
|
295
|
+
}
|
|
296
|
+
for (let i = k + 1; i < n; i++) {
|
|
297
|
+
LU[i][k] /= LU[k][k];
|
|
298
|
+
for (let j = k + 1; j < n; j++) {
|
|
299
|
+
LU[i][j] -= LU[i][k] * LU[k][j];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
let v = new Array(n).fill(1);
|
|
304
|
+
let prevNorm = 0;
|
|
305
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
306
|
+
const y = new Array(n).fill(0);
|
|
307
|
+
const b = new Array(n);
|
|
308
|
+
for (let i = 0; i < n; i++) {
|
|
309
|
+
b[i] = v[perm[i]];
|
|
310
|
+
}
|
|
311
|
+
for (let i = 0; i < n; i++) {
|
|
312
|
+
y[i] = b[i];
|
|
313
|
+
for (let j = 0; j < i; j++) {
|
|
314
|
+
y[i] -= LU[i][j] * y[j];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const x = new Array(n).fill(0);
|
|
318
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
319
|
+
x[i] = y[i];
|
|
320
|
+
for (let j = i + 1; j < n; j++) {
|
|
321
|
+
x[i] -= LU[i][j] * x[j];
|
|
322
|
+
}
|
|
323
|
+
x[i] /= LU[i][i];
|
|
324
|
+
}
|
|
325
|
+
let norm = 0;
|
|
326
|
+
for (let i = 0; i < n; i++) {
|
|
327
|
+
norm += x[i] * x[i];
|
|
328
|
+
}
|
|
329
|
+
norm = Math.sqrt(norm);
|
|
330
|
+
if (norm < tolerance) {
|
|
331
|
+
return x;
|
|
332
|
+
}
|
|
333
|
+
for (let i = 0; i < n; i++) {
|
|
334
|
+
v[i] = x[i] / norm;
|
|
335
|
+
}
|
|
336
|
+
if (Math.abs(norm - prevNorm) < tolerance * norm) {
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
prevNorm = norm;
|
|
340
|
+
}
|
|
341
|
+
return v;
|
|
342
|
+
}
|
|
343
|
+
function eig(matrix, options = {}) {
|
|
344
|
+
const {
|
|
345
|
+
maxIterations = DEFAULT_MAX_ITERATIONS,
|
|
346
|
+
tolerance = DEFAULT_TOLERANCE,
|
|
347
|
+
computeVectors = true
|
|
348
|
+
} = options;
|
|
349
|
+
let A;
|
|
350
|
+
if (matrix instanceof Float64Array) {
|
|
351
|
+
const n2 = Math.sqrt(matrix.length);
|
|
352
|
+
if (n2 !== Math.floor(n2)) {
|
|
353
|
+
throw new Error("Float64Array length must be a perfect square");
|
|
354
|
+
}
|
|
355
|
+
A = Array.from(
|
|
356
|
+
{ length: n2 },
|
|
357
|
+
(_, i) => Array.from({ length: n2 }, (_2, j) => matrix[i * n2 + j])
|
|
358
|
+
);
|
|
359
|
+
} else {
|
|
360
|
+
A = matrix;
|
|
361
|
+
}
|
|
362
|
+
const n = A.length;
|
|
363
|
+
if (n === 0) {
|
|
364
|
+
return { values: [], vectors: [], isSymmetric: true };
|
|
365
|
+
}
|
|
366
|
+
for (let i = 0; i < n; i++) {
|
|
367
|
+
if (A[i].length !== n) {
|
|
368
|
+
throw new Error("Matrix must be square");
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const symmetric = isSymmetric(A);
|
|
372
|
+
if (n === 1) {
|
|
373
|
+
return {
|
|
374
|
+
values: [{ re: A[0][0], im: 0 }],
|
|
375
|
+
vectors: [[1]],
|
|
376
|
+
isSymmetric: symmetric
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
if (n === 2) {
|
|
380
|
+
const a = A[0][0], b = A[0][1], c = A[1][0], d = A[1][1];
|
|
381
|
+
const trace = a + d;
|
|
382
|
+
const det = a * d - b * c;
|
|
383
|
+
const disc = trace * trace - 4 * det;
|
|
384
|
+
let values2;
|
|
385
|
+
let vectors2;
|
|
386
|
+
if (disc >= 0) {
|
|
387
|
+
const sqrtDisc = Math.sqrt(disc);
|
|
388
|
+
const e1 = (trace + sqrtDisc) / 2;
|
|
389
|
+
const e2 = (trace - sqrtDisc) / 2;
|
|
390
|
+
values2 = [{ re: e1, im: 0 }, { re: e2, im: 0 }];
|
|
391
|
+
if (computeVectors) {
|
|
392
|
+
vectors2 = [];
|
|
393
|
+
for (const e of [e1, e2]) {
|
|
394
|
+
if (Math.abs(b) > tolerance) {
|
|
395
|
+
const v = [b, e - a];
|
|
396
|
+
const norm = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
397
|
+
vectors2.push([v[0] / norm, v[1] / norm]);
|
|
398
|
+
} else if (Math.abs(c) > tolerance) {
|
|
399
|
+
const v = [e - d, c];
|
|
400
|
+
const norm = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
401
|
+
vectors2.push([v[0] / norm, v[1] / norm]);
|
|
402
|
+
} else {
|
|
403
|
+
vectors2.push(e === a ? [1, 0] : [0, 1]);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
vectors2 = eye(2);
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
const realPart = trace / 2;
|
|
411
|
+
const imagPart = Math.sqrt(-disc) / 2;
|
|
412
|
+
values2 = [
|
|
413
|
+
{ re: realPart, im: imagPart },
|
|
414
|
+
{ re: realPart, im: -imagPart }
|
|
415
|
+
];
|
|
416
|
+
vectors2 = eye(2);
|
|
417
|
+
}
|
|
418
|
+
return { values: values2, vectors: vectors2, isSymmetric: symmetric };
|
|
419
|
+
}
|
|
420
|
+
const { H, Q } = hessenberg(A);
|
|
421
|
+
let end = n - 1;
|
|
422
|
+
let iter = 0;
|
|
423
|
+
while (end > 0 && iter < maxIterations) {
|
|
424
|
+
let start = end;
|
|
425
|
+
while (start > 0) {
|
|
426
|
+
const scale = Math.abs(H[start - 1][start - 1]) + Math.abs(H[start][start]);
|
|
427
|
+
if (Math.abs(H[start][start - 1]) <= tolerance * scale) {
|
|
428
|
+
H[start][start - 1] = 0;
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
start--;
|
|
432
|
+
}
|
|
433
|
+
if (start === end) {
|
|
434
|
+
end--;
|
|
435
|
+
} else if (start === end - 1) {
|
|
436
|
+
end -= 2;
|
|
437
|
+
} else {
|
|
438
|
+
if (iter % 30 === 29) {
|
|
439
|
+
qrStep(H, Q, start, end);
|
|
440
|
+
} else if (symmetric) {
|
|
441
|
+
qrStep(H, Q, start, end);
|
|
442
|
+
} else {
|
|
443
|
+
doubleShiftQR(H, Q, start, end);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
iter++;
|
|
447
|
+
}
|
|
448
|
+
const values = extractEigenvalues(H, tolerance);
|
|
449
|
+
let vectors;
|
|
450
|
+
if (computeVectors) {
|
|
451
|
+
vectors = [];
|
|
452
|
+
for (const eigenvalue of values) {
|
|
453
|
+
const v = inverseIteration(A, eigenvalue, tolerance, 100);
|
|
454
|
+
vectors.push(v);
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
vectors = eye(n);
|
|
458
|
+
}
|
|
459
|
+
return { values, vectors, isSymmetric: symmetric };
|
|
460
|
+
}
|
|
461
|
+
function eigvals(matrix, options) {
|
|
462
|
+
return eig(matrix, { ...options, computeVectors: false }).values;
|
|
463
|
+
}
|
|
464
|
+
function powerIteration(matrix, options = {}) {
|
|
465
|
+
const { maxIterations = 1e3, tolerance = 1e-12 } = options;
|
|
466
|
+
const n = matrix.length;
|
|
467
|
+
let v = Array.from({ length: n }, () => Math.random() - 0.5);
|
|
468
|
+
let norm = Math.sqrt(v.reduce((sum, x) => sum + x * x, 0));
|
|
469
|
+
v = v.map((x) => x / norm);
|
|
470
|
+
let eigenvalue = 0;
|
|
471
|
+
let prevEigenvalue = 0;
|
|
472
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
473
|
+
const w = new Array(n).fill(0);
|
|
474
|
+
for (let i = 0; i < n; i++) {
|
|
475
|
+
for (let j = 0; j < n; j++) {
|
|
476
|
+
w[i] += matrix[i][j] * v[j];
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
eigenvalue = v.reduce((sum, vi, i) => sum + vi * w[i], 0);
|
|
480
|
+
norm = Math.sqrt(w.reduce((sum, x) => sum + x * x, 0));
|
|
481
|
+
v = w.map((x) => x / norm);
|
|
482
|
+
if (Math.abs(eigenvalue - prevEigenvalue) < tolerance * Math.abs(eigenvalue)) {
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
prevEigenvalue = eigenvalue;
|
|
486
|
+
}
|
|
487
|
+
return { value: eigenvalue, vector: v };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export {
|
|
491
|
+
__esm,
|
|
492
|
+
__export,
|
|
493
|
+
__toCommonJS,
|
|
494
|
+
eig,
|
|
495
|
+
eigvals,
|
|
496
|
+
powerIteration
|
|
497
|
+
};
|