@danielsimonjr/mathts-matrix 0.1.8 → 0.1.10
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 +1 -1
- package/dist/chunk-HT4ZF3LN.js +886 -0
- package/dist/{eig-A5GJGSJJ.js → eig-G72TLEBA.js} +1 -1
- package/dist/index.d.ts +42 -337
- package/dist/index.js +192 -1190
- package/dist/wasm/mathts-as.wasm +0 -0
- package/dist/wasm/wasm-manifest.json +1 -1
- package/package.json +61 -61
- package/dist/chunk-VCPLE6ED.js +0 -473
package/dist/wasm/mathts-as.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@danielsimonjr/mathts-matrix",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Matrix operations for MathTS with WASM/WebGPU backend support",
|
|
5
|
-
"author": "Daniel Simon Jr.",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "./dist/index.js",
|
|
9
|
-
"module": "./dist/index.js",
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"import": "./dist/index.js",
|
|
14
|
-
"types": "./dist/index.d.ts"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"README.md"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsup src/index.ts --format esm --dts --clean && node scripts/copy-wasm.mjs",
|
|
23
|
-
"copy:wasm": "node scripts/copy-wasm.mjs",
|
|
24
|
-
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
25
|
-
"test": "vitest run",
|
|
26
|
-
"test:watch": "vitest",
|
|
27
|
-
"test:coverage": "vitest run --coverage",
|
|
28
|
-
"typecheck": "tsc --noEmit",
|
|
29
|
-
"lint": "eslint src --ext .ts",
|
|
30
|
-
"lint:fix": "eslint src --ext .ts --fix",
|
|
31
|
-
"clean": "rm -rf dist",
|
|
32
|
-
"build:prod": "tsup src/index.ts --format esm --dts --clean --minify --treeshake && node scripts/copy-wasm.mjs"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@danielsimonjr/mathts-core": "^0.1.4",
|
|
36
|
-
"@danielsimonjr/mathts-parallel": "^0.
|
|
37
|
-
},
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"@types/node": "^25.5.2",
|
|
40
|
-
"@webgpu/types": "^0.1.67",
|
|
41
|
-
"tsup": "^8.0.0",
|
|
42
|
-
"typescript": "^5.3.0",
|
|
43
|
-
"vitest": "^4.1.5"
|
|
44
|
-
},
|
|
45
|
-
"publishConfig": {
|
|
46
|
-
"access": "public"
|
|
47
|
-
},
|
|
48
|
-
"repository": {
|
|
49
|
-
"type": "git",
|
|
50
|
-
"url": "https://github.com/danielsimonjr/mathts",
|
|
51
|
-
"directory": "matrix"
|
|
52
|
-
},
|
|
53
|
-
"keywords": [
|
|
54
|
-
"math",
|
|
55
|
-
"matrix",
|
|
56
|
-
"linear-algebra",
|
|
57
|
-
"typescript",
|
|
58
|
-
"wasm",
|
|
59
|
-
"webgpu"
|
|
60
|
-
]
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@danielsimonjr/mathts-matrix",
|
|
3
|
+
"version": "0.1.10",
|
|
4
|
+
"description": "Matrix operations for MathTS with WASM/WebGPU backend support",
|
|
5
|
+
"author": "Daniel Simon Jr.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup src/index.ts --format esm --dts --clean && node scripts/copy-wasm.mjs",
|
|
23
|
+
"copy:wasm": "node scripts/copy-wasm.mjs",
|
|
24
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:coverage": "vitest run --coverage",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"lint": "eslint src --ext .ts",
|
|
30
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
31
|
+
"clean": "rm -rf dist",
|
|
32
|
+
"build:prod": "tsup src/index.ts --format esm --dts --clean --minify --treeshake && node scripts/copy-wasm.mjs"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@danielsimonjr/mathts-core": "^0.1.4",
|
|
36
|
+
"@danielsimonjr/mathts-parallel": "^0.3.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^25.5.2",
|
|
40
|
+
"@webgpu/types": "^0.1.67",
|
|
41
|
+
"tsup": "^8.0.0",
|
|
42
|
+
"typescript": "^5.3.0",
|
|
43
|
+
"vitest": "^4.1.5"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/danielsimonjr/mathts",
|
|
51
|
+
"directory": "matrix"
|
|
52
|
+
},
|
|
53
|
+
"keywords": [
|
|
54
|
+
"math",
|
|
55
|
+
"matrix",
|
|
56
|
+
"linear-algebra",
|
|
57
|
+
"typescript",
|
|
58
|
+
"wasm",
|
|
59
|
+
"webgpu"
|
|
60
|
+
]
|
|
61
|
+
}
|
package/dist/chunk-VCPLE6ED.js
DELETED
|
@@ -1,473 +0,0 @@
|
|
|
1
|
-
// src/operations/eig.ts
|
|
2
|
-
var DEFAULT_MAX_ITERATIONS = 1e3;
|
|
3
|
-
var DEFAULT_TOLERANCE = 1e-12;
|
|
4
|
-
function isSymmetric(matrix, tolerance = 1e-10) {
|
|
5
|
-
const n = matrix.length;
|
|
6
|
-
if (n === 0) return true;
|
|
7
|
-
if (matrix[0].length !== n) return false;
|
|
8
|
-
for (let i = 0; i < n; i++) {
|
|
9
|
-
for (let j = i + 1; j < n; j++) {
|
|
10
|
-
if (Math.abs(matrix[i][j] - matrix[j][i]) > tolerance) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
function eye(n) {
|
|
18
|
-
const I = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
19
|
-
for (let i = 0; i < n; i++) {
|
|
20
|
-
I[i][i] = 1;
|
|
21
|
-
}
|
|
22
|
-
return I;
|
|
23
|
-
}
|
|
24
|
-
function cloneMatrix(A) {
|
|
25
|
-
return A.map((row) => [...row]);
|
|
26
|
-
}
|
|
27
|
-
function householder(x) {
|
|
28
|
-
const n = x.length;
|
|
29
|
-
let sigma = 0;
|
|
30
|
-
for (let i = 1; i < n; i++) {
|
|
31
|
-
sigma += x[i] * x[i];
|
|
32
|
-
}
|
|
33
|
-
const v = [...x];
|
|
34
|
-
v[0] = 1;
|
|
35
|
-
if (sigma === 0 && x[0] >= 0) {
|
|
36
|
-
return { v, beta: 0 };
|
|
37
|
-
} else if (sigma === 0 && x[0] < 0) {
|
|
38
|
-
return { v, beta: -2 };
|
|
39
|
-
} else {
|
|
40
|
-
const mu = Math.sqrt(x[0] * x[0] + sigma);
|
|
41
|
-
if (x[0] <= 0) {
|
|
42
|
-
v[0] = x[0] - mu;
|
|
43
|
-
} else {
|
|
44
|
-
v[0] = -sigma / (x[0] + mu);
|
|
45
|
-
}
|
|
46
|
-
const beta = 2 * v[0] * v[0] / (sigma + v[0] * v[0]);
|
|
47
|
-
const v0 = v[0];
|
|
48
|
-
for (let i = 0; i < n; i++) {
|
|
49
|
-
v[i] /= v0;
|
|
50
|
-
}
|
|
51
|
-
return { v, beta };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function applyHouseholderLeft(A, v, beta, startRow, startCol) {
|
|
55
|
-
const n = A[0].length;
|
|
56
|
-
const len = v.length;
|
|
57
|
-
for (let j = startCol; j < n; j++) {
|
|
58
|
-
let dot = 0;
|
|
59
|
-
for (let i = 0; i < len; i++) {
|
|
60
|
-
dot += v[i] * A[startRow + i][j];
|
|
61
|
-
}
|
|
62
|
-
dot *= beta;
|
|
63
|
-
for (let i = 0; i < len; i++) {
|
|
64
|
-
A[startRow + i][j] -= dot * v[i];
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function applyHouseholderRight(A, v, beta, startRow, startCol) {
|
|
69
|
-
const m = A.length;
|
|
70
|
-
const len = v.length;
|
|
71
|
-
for (let i = startRow; i < m; i++) {
|
|
72
|
-
let dot = 0;
|
|
73
|
-
for (let j = 0; j < len; j++) {
|
|
74
|
-
dot += A[i][startCol + j] * v[j];
|
|
75
|
-
}
|
|
76
|
-
dot *= beta;
|
|
77
|
-
for (let j = 0; j < len; j++) {
|
|
78
|
-
A[i][startCol + j] -= dot * v[j];
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function hessenberg(A) {
|
|
83
|
-
const n = A.length;
|
|
84
|
-
const H = cloneMatrix(A);
|
|
85
|
-
const Q = eye(n);
|
|
86
|
-
for (let k = 0; k < n - 2; k++) {
|
|
87
|
-
const x = [];
|
|
88
|
-
for (let i = k + 1; i < n; i++) {
|
|
89
|
-
x.push(H[i][k]);
|
|
90
|
-
}
|
|
91
|
-
const { v, beta } = householder(x);
|
|
92
|
-
if (beta !== 0) {
|
|
93
|
-
applyHouseholderLeft(H, v, beta, k + 1, k);
|
|
94
|
-
applyHouseholderRight(H, v, beta, 0, k + 1);
|
|
95
|
-
applyHouseholderRight(Q, v, beta, 0, k + 1);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
for (let i = 0; i < n; i++) {
|
|
99
|
-
for (let j = 0; j < i - 1; j++) {
|
|
100
|
-
H[i][j] = 0;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return { H, Q };
|
|
104
|
-
}
|
|
105
|
-
function givens(a, b) {
|
|
106
|
-
if (b === 0) {
|
|
107
|
-
return { c: 1, s: 0 };
|
|
108
|
-
} else if (Math.abs(b) > Math.abs(a)) {
|
|
109
|
-
const t = -a / b;
|
|
110
|
-
const s = 1 / Math.sqrt(1 + t * t);
|
|
111
|
-
return { c: s * t, s };
|
|
112
|
-
} else {
|
|
113
|
-
const t = -b / a;
|
|
114
|
-
const c = 1 / Math.sqrt(1 + t * t);
|
|
115
|
-
return { c, s: c * t };
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
function applyGivensLeft(A, c, s, i, k, startCol) {
|
|
119
|
-
const n = A[0].length;
|
|
120
|
-
for (let j = startCol; j < n; j++) {
|
|
121
|
-
const temp = c * A[i][j] - s * A[k][j];
|
|
122
|
-
A[k][j] = s * A[i][j] + c * A[k][j];
|
|
123
|
-
A[i][j] = temp;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function applyGivensRight(A, c, s, i, k, startRow) {
|
|
127
|
-
const m = A.length;
|
|
128
|
-
for (let j = startRow; j < m; j++) {
|
|
129
|
-
const temp = c * A[j][i] - s * A[j][k];
|
|
130
|
-
A[j][k] = s * A[j][i] + c * A[j][k];
|
|
131
|
-
A[j][i] = temp;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
function qrStep(H, Q, start, end) {
|
|
135
|
-
const n = end - start + 1;
|
|
136
|
-
if (n < 2) return;
|
|
137
|
-
const a = H[end - 1][end - 1];
|
|
138
|
-
const b = H[end - 1][end];
|
|
139
|
-
const c = H[end][end - 1];
|
|
140
|
-
const d = H[end][end];
|
|
141
|
-
const trace = a + d;
|
|
142
|
-
const det = a * d - b * c;
|
|
143
|
-
const disc = trace * trace - 4 * det;
|
|
144
|
-
let shift;
|
|
145
|
-
if (disc >= 0) {
|
|
146
|
-
const sqrtDisc = Math.sqrt(disc);
|
|
147
|
-
const e1 = (trace + sqrtDisc) / 2;
|
|
148
|
-
const e2 = (trace - sqrtDisc) / 2;
|
|
149
|
-
shift = Math.abs(e1 - d) < Math.abs(e2 - d) ? e1 : e2;
|
|
150
|
-
} else {
|
|
151
|
-
shift = d;
|
|
152
|
-
}
|
|
153
|
-
let x = H[start][start] - shift;
|
|
154
|
-
let y = H[start + 1][start];
|
|
155
|
-
for (let k = start; k < end; k++) {
|
|
156
|
-
const { c: c2, s } = givens(x, y);
|
|
157
|
-
applyGivensLeft(H, c2, s, k, k + 1, Math.max(0, k - 1));
|
|
158
|
-
applyGivensRight(H, c2, s, k, k + 1, 0);
|
|
159
|
-
applyGivensRight(Q, c2, s, k, k + 1, 0);
|
|
160
|
-
if (k < end - 1) {
|
|
161
|
-
x = H[k + 1][k];
|
|
162
|
-
y = H[k + 2][k];
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function doubleShiftQR(H, Q, start, end) {
|
|
167
|
-
const n = H.length;
|
|
168
|
-
const a = H[end - 1][end - 1];
|
|
169
|
-
const b = H[end - 1][end];
|
|
170
|
-
const c = H[end][end - 1];
|
|
171
|
-
const d = H[end][end];
|
|
172
|
-
const s = a + d;
|
|
173
|
-
const t = a * d - b * c;
|
|
174
|
-
let x = H[start][start] * H[start][start] + H[start][start + 1] * H[start + 1][start] - s * H[start][start] + t;
|
|
175
|
-
let y = H[start + 1][start] * (H[start][start] + H[start + 1][start + 1] - s);
|
|
176
|
-
let z = H[start + 1][start] * H[start + 2][start + 1];
|
|
177
|
-
for (let k = start; k <= end - 2; k++) {
|
|
178
|
-
const { v, beta } = householder([x, y, z]);
|
|
179
|
-
const q = Math.max(start, k - 1);
|
|
180
|
-
for (let j = q; j < n; j++) {
|
|
181
|
-
let dot = v[0] * H[k][j] + v[1] * H[k + 1][j] + v[2] * H[k + 2][j];
|
|
182
|
-
dot *= beta;
|
|
183
|
-
H[k][j] -= dot * v[0];
|
|
184
|
-
H[k + 1][j] -= dot * v[1];
|
|
185
|
-
H[k + 2][j] -= dot * v[2];
|
|
186
|
-
}
|
|
187
|
-
const r = Math.min(k + 4, end + 1);
|
|
188
|
-
for (let i = 0; i < r; i++) {
|
|
189
|
-
let dot = v[0] * H[i][k] + v[1] * H[i][k + 1] + v[2] * H[i][k + 2];
|
|
190
|
-
dot *= beta;
|
|
191
|
-
H[i][k] -= dot * v[0];
|
|
192
|
-
H[i][k + 1] -= dot * v[1];
|
|
193
|
-
H[i][k + 2] -= dot * v[2];
|
|
194
|
-
}
|
|
195
|
-
for (let i = 0; i < n; i++) {
|
|
196
|
-
let dot = v[0] * Q[i][k] + v[1] * Q[i][k + 1] + v[2] * Q[i][k + 2];
|
|
197
|
-
dot *= beta;
|
|
198
|
-
Q[i][k] -= dot * v[0];
|
|
199
|
-
Q[i][k + 1] -= dot * v[1];
|
|
200
|
-
Q[i][k + 2] -= dot * v[2];
|
|
201
|
-
}
|
|
202
|
-
x = H[k + 1][k];
|
|
203
|
-
y = H[k + 2][k];
|
|
204
|
-
if (k < end - 2) {
|
|
205
|
-
z = H[k + 3][k];
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
const { c: cFinal, s: sFinal } = givens(x, y);
|
|
209
|
-
applyGivensLeft(H, cFinal, sFinal, end - 1, end, end - 2);
|
|
210
|
-
applyGivensRight(H, cFinal, sFinal, end - 1, end, 0);
|
|
211
|
-
applyGivensRight(Q, cFinal, sFinal, end - 1, end, 0);
|
|
212
|
-
}
|
|
213
|
-
function extractEigenvalues(H, tolerance) {
|
|
214
|
-
const n = H.length;
|
|
215
|
-
const eigenvalues = [];
|
|
216
|
-
let i = 0;
|
|
217
|
-
while (i < n) {
|
|
218
|
-
if (i === n - 1 || Math.abs(H[i + 1][i]) <= tolerance) {
|
|
219
|
-
eigenvalues.push({ re: H[i][i], im: 0 });
|
|
220
|
-
i++;
|
|
221
|
-
} else {
|
|
222
|
-
const a = H[i][i];
|
|
223
|
-
const b = H[i][i + 1];
|
|
224
|
-
const c = H[i + 1][i];
|
|
225
|
-
const d = H[i + 1][i + 1];
|
|
226
|
-
const trace = a + d;
|
|
227
|
-
const det = a * d - b * c;
|
|
228
|
-
const disc = trace * trace - 4 * det;
|
|
229
|
-
if (disc >= 0) {
|
|
230
|
-
const sqrtDisc = Math.sqrt(disc);
|
|
231
|
-
eigenvalues.push({ re: (trace + sqrtDisc) / 2, im: 0 });
|
|
232
|
-
eigenvalues.push({ re: (trace - sqrtDisc) / 2, im: 0 });
|
|
233
|
-
} else {
|
|
234
|
-
const realPart = trace / 2;
|
|
235
|
-
const imagPart = Math.sqrt(-disc) / 2;
|
|
236
|
-
eigenvalues.push({ re: realPart, im: imagPart });
|
|
237
|
-
eigenvalues.push({ re: realPart, im: -imagPart });
|
|
238
|
-
}
|
|
239
|
-
i += 2;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return eigenvalues;
|
|
243
|
-
}
|
|
244
|
-
function inverseIteration(A, eigenvalue, tolerance, maxIterations) {
|
|
245
|
-
const n = A.length;
|
|
246
|
-
if (eigenvalue.im !== 0) {
|
|
247
|
-
return new Array(n).fill(0);
|
|
248
|
-
}
|
|
249
|
-
const lambda = eigenvalue.re;
|
|
250
|
-
const shifted = cloneMatrix(A);
|
|
251
|
-
for (let i = 0; i < n; i++) {
|
|
252
|
-
shifted[i][i] -= lambda;
|
|
253
|
-
}
|
|
254
|
-
for (let i = 0; i < n; i++) {
|
|
255
|
-
shifted[i][i] += tolerance * 1e3;
|
|
256
|
-
}
|
|
257
|
-
const LU = cloneMatrix(shifted);
|
|
258
|
-
const perm = Array.from({ length: n }, (_, i) => i);
|
|
259
|
-
for (let k = 0; k < n; k++) {
|
|
260
|
-
let maxVal = Math.abs(LU[k][k]);
|
|
261
|
-
let maxIdx = k;
|
|
262
|
-
for (let i = k + 1; i < n; i++) {
|
|
263
|
-
if (Math.abs(LU[i][k]) > maxVal) {
|
|
264
|
-
maxVal = Math.abs(LU[i][k]);
|
|
265
|
-
maxIdx = i;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
if (maxIdx !== k) {
|
|
269
|
-
[LU[k], LU[maxIdx]] = [LU[maxIdx], LU[k]];
|
|
270
|
-
[perm[k], perm[maxIdx]] = [perm[maxIdx], perm[k]];
|
|
271
|
-
}
|
|
272
|
-
if (Math.abs(LU[k][k]) < tolerance) {
|
|
273
|
-
LU[k][k] = tolerance;
|
|
274
|
-
}
|
|
275
|
-
for (let i = k + 1; i < n; i++) {
|
|
276
|
-
LU[i][k] /= LU[k][k];
|
|
277
|
-
for (let j = k + 1; j < n; j++) {
|
|
278
|
-
LU[i][j] -= LU[i][k] * LU[k][j];
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
const v = new Array(n).fill(1);
|
|
283
|
-
let prevNorm = 0;
|
|
284
|
-
for (let iter = 0; iter < maxIterations; iter++) {
|
|
285
|
-
const y = new Array(n).fill(0);
|
|
286
|
-
const b = new Array(n);
|
|
287
|
-
for (let i = 0; i < n; i++) {
|
|
288
|
-
b[i] = v[perm[i]];
|
|
289
|
-
}
|
|
290
|
-
for (let i = 0; i < n; i++) {
|
|
291
|
-
y[i] = b[i];
|
|
292
|
-
for (let j = 0; j < i; j++) {
|
|
293
|
-
y[i] -= LU[i][j] * y[j];
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
const x = new Array(n).fill(0);
|
|
297
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
298
|
-
x[i] = y[i];
|
|
299
|
-
for (let j = i + 1; j < n; j++) {
|
|
300
|
-
x[i] -= LU[i][j] * x[j];
|
|
301
|
-
}
|
|
302
|
-
x[i] /= LU[i][i];
|
|
303
|
-
}
|
|
304
|
-
let norm = 0;
|
|
305
|
-
for (let i = 0; i < n; i++) {
|
|
306
|
-
norm += x[i] * x[i];
|
|
307
|
-
}
|
|
308
|
-
norm = Math.sqrt(norm);
|
|
309
|
-
if (norm < tolerance) {
|
|
310
|
-
return x;
|
|
311
|
-
}
|
|
312
|
-
for (let i = 0; i < n; i++) {
|
|
313
|
-
v[i] = x[i] / norm;
|
|
314
|
-
}
|
|
315
|
-
if (Math.abs(norm - prevNorm) < tolerance * norm) {
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
prevNorm = norm;
|
|
319
|
-
}
|
|
320
|
-
return v;
|
|
321
|
-
}
|
|
322
|
-
function eig(matrix, options = {}) {
|
|
323
|
-
const {
|
|
324
|
-
maxIterations = DEFAULT_MAX_ITERATIONS,
|
|
325
|
-
tolerance = DEFAULT_TOLERANCE,
|
|
326
|
-
computeVectors = true
|
|
327
|
-
} = options;
|
|
328
|
-
let A;
|
|
329
|
-
if (matrix instanceof Float64Array) {
|
|
330
|
-
const n2 = Math.sqrt(matrix.length);
|
|
331
|
-
if (n2 !== Math.floor(n2)) {
|
|
332
|
-
throw new Error("Float64Array length must be a perfect square");
|
|
333
|
-
}
|
|
334
|
-
A = Array.from({ length: n2 }, (_, i) => Array.from({ length: n2 }, (_2, j) => matrix[i * n2 + j]));
|
|
335
|
-
} else {
|
|
336
|
-
A = matrix;
|
|
337
|
-
}
|
|
338
|
-
const n = A.length;
|
|
339
|
-
if (n === 0) {
|
|
340
|
-
return { values: [], vectors: [], isSymmetric: true };
|
|
341
|
-
}
|
|
342
|
-
for (let i = 0; i < n; i++) {
|
|
343
|
-
if (A[i].length !== n) {
|
|
344
|
-
throw new Error("Matrix must be square");
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
const symmetric = isSymmetric(A);
|
|
348
|
-
if (n === 1) {
|
|
349
|
-
return {
|
|
350
|
-
values: [{ re: A[0][0], im: 0 }],
|
|
351
|
-
vectors: [[1]],
|
|
352
|
-
isSymmetric: symmetric
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
if (n === 2) {
|
|
356
|
-
const a = A[0][0], b = A[0][1], c = A[1][0], d = A[1][1];
|
|
357
|
-
const trace = a + d;
|
|
358
|
-
const det = a * d - b * c;
|
|
359
|
-
const disc = trace * trace - 4 * det;
|
|
360
|
-
let values2;
|
|
361
|
-
let vectors2;
|
|
362
|
-
if (disc >= 0) {
|
|
363
|
-
const sqrtDisc = Math.sqrt(disc);
|
|
364
|
-
const e1 = (trace + sqrtDisc) / 2;
|
|
365
|
-
const e2 = (trace - sqrtDisc) / 2;
|
|
366
|
-
values2 = [
|
|
367
|
-
{ re: e1, im: 0 },
|
|
368
|
-
{ re: e2, im: 0 }
|
|
369
|
-
];
|
|
370
|
-
if (computeVectors) {
|
|
371
|
-
vectors2 = [];
|
|
372
|
-
for (const e of [e1, e2]) {
|
|
373
|
-
if (Math.abs(b) > tolerance) {
|
|
374
|
-
const v = [b, e - a];
|
|
375
|
-
const norm = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
376
|
-
vectors2.push([v[0] / norm, v[1] / norm]);
|
|
377
|
-
} else if (Math.abs(c) > tolerance) {
|
|
378
|
-
const v = [e - d, c];
|
|
379
|
-
const norm = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
380
|
-
vectors2.push([v[0] / norm, v[1] / norm]);
|
|
381
|
-
} else {
|
|
382
|
-
vectors2.push(e === a ? [1, 0] : [0, 1]);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
} else {
|
|
386
|
-
vectors2 = eye(2);
|
|
387
|
-
}
|
|
388
|
-
} else {
|
|
389
|
-
const realPart = trace / 2;
|
|
390
|
-
const imagPart = Math.sqrt(-disc) / 2;
|
|
391
|
-
values2 = [
|
|
392
|
-
{ re: realPart, im: imagPart },
|
|
393
|
-
{ re: realPart, im: -imagPart }
|
|
394
|
-
];
|
|
395
|
-
vectors2 = eye(2);
|
|
396
|
-
}
|
|
397
|
-
return { values: values2, vectors: vectors2, isSymmetric: symmetric };
|
|
398
|
-
}
|
|
399
|
-
const { H, Q } = hessenberg(A);
|
|
400
|
-
let end = n - 1;
|
|
401
|
-
let iter = 0;
|
|
402
|
-
while (end > 0 && iter < maxIterations) {
|
|
403
|
-
let start = end;
|
|
404
|
-
while (start > 0) {
|
|
405
|
-
const scale = Math.abs(H[start - 1][start - 1]) + Math.abs(H[start][start]);
|
|
406
|
-
if (Math.abs(H[start][start - 1]) <= tolerance * scale) {
|
|
407
|
-
H[start][start - 1] = 0;
|
|
408
|
-
break;
|
|
409
|
-
}
|
|
410
|
-
start--;
|
|
411
|
-
}
|
|
412
|
-
if (start === end) {
|
|
413
|
-
end--;
|
|
414
|
-
} else if (start === end - 1) {
|
|
415
|
-
end -= 2;
|
|
416
|
-
} else {
|
|
417
|
-
if (iter % 30 === 29) {
|
|
418
|
-
qrStep(H, Q, start, end);
|
|
419
|
-
} else if (symmetric) {
|
|
420
|
-
qrStep(H, Q, start, end);
|
|
421
|
-
} else {
|
|
422
|
-
doubleShiftQR(H, Q, start, end);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
iter++;
|
|
426
|
-
}
|
|
427
|
-
const values = extractEigenvalues(H, tolerance);
|
|
428
|
-
let vectors;
|
|
429
|
-
if (computeVectors) {
|
|
430
|
-
vectors = [];
|
|
431
|
-
for (const eigenvalue of values) {
|
|
432
|
-
const v = inverseIteration(A, eigenvalue, tolerance, 100);
|
|
433
|
-
vectors.push(v);
|
|
434
|
-
}
|
|
435
|
-
} else {
|
|
436
|
-
vectors = eye(n);
|
|
437
|
-
}
|
|
438
|
-
return { values, vectors, isSymmetric: symmetric };
|
|
439
|
-
}
|
|
440
|
-
function eigvals(matrix, options) {
|
|
441
|
-
return eig(matrix, { ...options, computeVectors: false }).values;
|
|
442
|
-
}
|
|
443
|
-
function powerIteration(matrix, options = {}) {
|
|
444
|
-
const { maxIterations = 1e3, tolerance = 1e-12 } = options;
|
|
445
|
-
const n = matrix.length;
|
|
446
|
-
let v = Array.from({ length: n }, () => Math.random() - 0.5);
|
|
447
|
-
let norm = Math.sqrt(v.reduce((sum, x) => sum + x * x, 0));
|
|
448
|
-
v = v.map((x) => x / norm);
|
|
449
|
-
let eigenvalue = 0;
|
|
450
|
-
let prevEigenvalue = 0;
|
|
451
|
-
for (let iter = 0; iter < maxIterations; iter++) {
|
|
452
|
-
const w = new Array(n).fill(0);
|
|
453
|
-
for (let i = 0; i < n; i++) {
|
|
454
|
-
for (let j = 0; j < n; j++) {
|
|
455
|
-
w[i] += matrix[i][j] * v[j];
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
eigenvalue = v.reduce((sum, vi, i) => sum + vi * w[i], 0);
|
|
459
|
-
norm = Math.sqrt(w.reduce((sum, x) => sum + x * x, 0));
|
|
460
|
-
v = w.map((x) => x / norm);
|
|
461
|
-
if (Math.abs(eigenvalue - prevEigenvalue) < tolerance * Math.abs(eigenvalue)) {
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
prevEigenvalue = eigenvalue;
|
|
465
|
-
}
|
|
466
|
-
return { value: eigenvalue, vector: v };
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
export {
|
|
470
|
-
eig,
|
|
471
|
-
eigvals,
|
|
472
|
-
powerIteration
|
|
473
|
-
};
|