@danielsimonjr/mathts-matrix 0.7.9 → 0.8.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 +51 -14
- package/dist/backends/BackendManager.d.ts +1 -1
- package/dist/backends/BackendManager.d.ts.map +1 -1
- package/dist/backends/GPUBackend.d.ts.map +1 -1
- package/dist/backends/GPUMatrixBackend.d.ts.map +1 -1
- package/dist/backends/JSBackend.d.ts.map +1 -1
- package/dist/backends/ParallelBackend.d.ts +10 -0
- package/dist/backends/ParallelBackend.d.ts.map +1 -1
- package/dist/backends/WASMBackend.d.ts.map +1 -1
- package/dist/backends/gpu/gpu-or-js.d.ts +5 -0
- package/dist/backends/gpu/gpu-or-js.d.ts.map +1 -0
- package/dist/backends/gpu/run-shader.d.ts +37 -0
- package/dist/backends/gpu/run-shader.d.ts.map +1 -0
- package/dist/backends/wasm/as-typed-array.d.ts +37 -0
- package/dist/backends/wasm/as-typed-array.d.ts.map +1 -0
- package/dist/backends/wasm/index.d.ts +0 -2
- package/dist/backends/wasm/index.d.ts.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +621 -1047
- package/dist/operations/common.d.ts +79 -2
- package/dist/operations/common.d.ts.map +1 -1
- package/dist/operations/expm.d.ts.map +1 -1
- package/dist/operations/givens.d.ts +22 -0
- package/dist/operations/givens.d.ts.map +1 -0
- package/dist/operations/index.d.ts +1 -0
- package/dist/operations/index.d.ts.map +1 -1
- package/dist/operations/logm.d.ts.map +1 -1
- package/dist/operations/qr-family.d.ts +2 -0
- package/dist/operations/qr-family.d.ts.map +1 -1
- package/dist/operations/schur.d.ts.map +1 -1
- package/dist/operations/sqrtm.d.ts.map +1 -1
- package/dist/operations/svd.d.ts.map +1 -1
- package/dist/parallel-matrix.d.ts.map +1 -1
- package/dist/types/DenseMatrix.d.ts +7 -0
- package/dist/types/DenseMatrix.d.ts.map +1 -1
- package/dist/types/SparseMatrix.d.ts +3 -0
- package/dist/types/SparseMatrix.d.ts.map +1 -1
- package/dist/types/dense/arithmetic.d.ts.map +1 -1
- package/dist/wasm/mathts-as.wasm +0 -0
- package/dist/wasm/wasm-manifest.json +1 -1
- package/package.json +3 -3
- package/dist/backends/WasmLoader.d.ts +0 -356
- package/dist/backends/WasmLoader.d.ts.map +0 -1
- package/dist/backends/wasm/fft-wasm.d.ts +0 -120
- package/dist/backends/wasm/fft-wasm.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BufferPool, BufferPool as BufferPool$1, GPUContext, GPUContext as GPUContext$1, GPU_MIN_ELEMENTS, ShaderManager, ShaderManager as ShaderManager$1, destroyGlobalGPU, detectGPUCapabilities, detectGPUCapabilities as detectGPUCapabilities$1, getGlobalGPUContext, getGlobalGPUContext as getGlobalGPUContext$1, getRecommendedWorkgroupSize, getRecommendedWorkgroupSize as getRecommendedWorkgroupSize$1, hasWebGPU, hasWebGPU as hasWebGPU$1 } from "@danielsimonjr/mathts-gpu";
|
|
2
2
|
import { ComputePool, computePool } from "@danielsimonjr/mathts-parallel";
|
|
3
|
+
import { allocAsHeader } from "@danielsimonjr/mathts-core/internal";
|
|
3
4
|
import { mathTyped } from "@danielsimonjr/mathts-core";
|
|
4
5
|
//#region \0rolldown/runtime.js
|
|
5
6
|
var __defProp = Object.defineProperty;
|
|
@@ -136,8 +137,14 @@ function multiply$1(a, b) {
|
|
|
136
137
|
const ri = i * m;
|
|
137
138
|
for (let k = 0; k < p; k++) {
|
|
138
139
|
const aik = ad[ai + k];
|
|
139
|
-
if (aik === 0) continue;
|
|
140
140
|
const bk = k * m;
|
|
141
|
+
if (aik === 0) {
|
|
142
|
+
for (let j = 0; j < m; j++) {
|
|
143
|
+
const bij = bd[bk + j];
|
|
144
|
+
if (bij !== 0 && !Number.isFinite(bij)) result[ri + j] += aik * bij;
|
|
145
|
+
}
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
141
148
|
for (let j = 0; j < m; j++) result[ri + j] += aik * bd[bk + j];
|
|
142
149
|
}
|
|
143
150
|
}
|
|
@@ -680,6 +687,11 @@ var init_SparseMatrix = __esmMin((() => {
|
|
|
680
687
|
function isDenseMatrix(value) {
|
|
681
688
|
return value instanceof DenseMatrix;
|
|
682
689
|
}
|
|
690
|
+
function denseContiguousData(matrix) {
|
|
691
|
+
const m = matrix;
|
|
692
|
+
if (!m.isView && m.offset === 0 && m.rowStride === m.cols) return m.data;
|
|
693
|
+
return m.toFlatFloat64Array();
|
|
694
|
+
}
|
|
683
695
|
var DenseMatrix;
|
|
684
696
|
var init_DenseMatrix = __esmMin((() => {
|
|
685
697
|
init_Matrix();
|
|
@@ -976,6 +988,7 @@ const backendRegistry = new BackendRegistry();
|
|
|
976
988
|
//#endregion
|
|
977
989
|
//#region src/backends/JSBackend.ts
|
|
978
990
|
init_DenseMatrix();
|
|
991
|
+
init_reduction();
|
|
979
992
|
var JSBackend = class {
|
|
980
993
|
type = "js";
|
|
981
994
|
isAvailable() {
|
|
@@ -1024,10 +1037,17 @@ var JSBackend = class {
|
|
|
1024
1037
|
const m = a.rows;
|
|
1025
1038
|
const n = b.cols;
|
|
1026
1039
|
const k = a.cols;
|
|
1040
|
+
const ad = denseContiguousData(a);
|
|
1041
|
+
const bd = denseContiguousData(b);
|
|
1027
1042
|
const result = new Float64Array(m * n);
|
|
1028
|
-
for (let i = 0; i < m; i++)
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1043
|
+
for (let i = 0; i < m; i++) {
|
|
1044
|
+
const ai = i * k;
|
|
1045
|
+
const ri = i * n;
|
|
1046
|
+
for (let p = 0; p < k; p++) {
|
|
1047
|
+
const aip = ad[ai + p];
|
|
1048
|
+
const bp = p * n;
|
|
1049
|
+
for (let j = 0; j < n; j++) result[ri + j] += aip * bd[bp + j];
|
|
1050
|
+
}
|
|
1031
1051
|
}
|
|
1032
1052
|
return new DenseMatrix(m, n, result);
|
|
1033
1053
|
}
|
|
@@ -1053,12 +1073,7 @@ var JSBackend = class {
|
|
|
1053
1073
|
}
|
|
1054
1074
|
}
|
|
1055
1075
|
norm(a) {
|
|
1056
|
-
|
|
1057
|
-
for (let i = 0; i < a.rows; i++) for (let j = 0; j < a.cols; j++) {
|
|
1058
|
-
const val = a.get(i, j);
|
|
1059
|
-
sumSq += val * val;
|
|
1060
|
-
}
|
|
1061
|
-
return Math.sqrt(sumSq);
|
|
1076
|
+
return norm$1(a);
|
|
1062
1077
|
}
|
|
1063
1078
|
dot(a, b) {
|
|
1064
1079
|
if (!a.isVector || !b.isVector) throw new Error("Dot product requires two vectors");
|
|
@@ -1105,51 +1120,24 @@ var ParallelBackend = class {
|
|
|
1105
1120
|
return elementCount >= this.parallelThreshold;
|
|
1106
1121
|
}
|
|
1107
1122
|
async add(a, b) {
|
|
1108
|
-
this.
|
|
1109
|
-
const elementCount = a.rows * a.cols;
|
|
1110
|
-
if (!this.shouldParallelize(elementCount) || !this.isReady()) return a.add(b);
|
|
1111
|
-
const aData = a.toFloat64Array();
|
|
1112
|
-
const bData = b.toFloat64Array();
|
|
1113
|
-
const result = await this.pool.elementwise(aData, bData, "add");
|
|
1114
|
-
return new DenseMatrix(a.rows, a.cols, result.result);
|
|
1123
|
+
return this.parallelBinary(a, b, "add", (x, y) => x.add(y));
|
|
1115
1124
|
}
|
|
1116
1125
|
async subtract(a, b) {
|
|
1117
|
-
this.
|
|
1118
|
-
const elementCount = a.rows * a.cols;
|
|
1119
|
-
if (!this.shouldParallelize(elementCount) || !this.isReady()) return a.subtract(b);
|
|
1120
|
-
const aData = a.toFloat64Array();
|
|
1121
|
-
const bData = b.toFloat64Array();
|
|
1122
|
-
const result = await this.pool.elementwise(aData, bData, "subtract");
|
|
1123
|
-
return new DenseMatrix(a.rows, a.cols, result.result);
|
|
1126
|
+
return this.parallelBinary(a, b, "subtract", (x, y) => x.subtract(y));
|
|
1124
1127
|
}
|
|
1125
1128
|
async multiplyElementwise(a, b) {
|
|
1126
|
-
this.
|
|
1127
|
-
const elementCount = a.rows * a.cols;
|
|
1128
|
-
if (!this.shouldParallelize(elementCount) || !this.isReady()) return a.multiplyElementwise(b);
|
|
1129
|
-
const aData = a.toFloat64Array();
|
|
1130
|
-
const bData = b.toFloat64Array();
|
|
1131
|
-
const result = await this.pool.elementwise(aData, bData, "multiply");
|
|
1132
|
-
return new DenseMatrix(a.rows, a.cols, result.result);
|
|
1129
|
+
return this.parallelBinary(a, b, "multiply", (x, y) => x.multiplyElementwise(y));
|
|
1133
1130
|
}
|
|
1134
1131
|
async divideElementwise(a, b) {
|
|
1135
|
-
this.
|
|
1136
|
-
const elementCount = a.rows * a.cols;
|
|
1137
|
-
if (!this.shouldParallelize(elementCount) || !this.isReady()) {
|
|
1138
|
-
const result = new Float64Array(a.rows * a.cols);
|
|
1139
|
-
for (let i = 0; i < a.rows; i++) for (let j = 0; j < a.cols; j++) result[i * a.cols + j] = a.get(i, j) / b.get(i, j);
|
|
1140
|
-
return new DenseMatrix(a.rows, a.cols, result);
|
|
1141
|
-
}
|
|
1142
|
-
const aData = a.toFloat64Array();
|
|
1143
|
-
const bData = b.toFloat64Array();
|
|
1144
|
-
const result = await this.pool.elementwise(aData, bData, "divide");
|
|
1145
|
-
return new DenseMatrix(a.rows, a.cols, result.result);
|
|
1132
|
+
return this.parallelBinary(a, b, "divide", (x, y) => jsBackend.divideElementwise(x, y));
|
|
1146
1133
|
}
|
|
1147
1134
|
async scale(a, scalar) {
|
|
1148
1135
|
const elementCount = a.rows * a.cols;
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1136
|
+
return this.whenParallel(elementCount, () => a.scale(scalar), async () => {
|
|
1137
|
+
const aData = a.toFloat64Array();
|
|
1138
|
+
const result = await this.pool.scale(aData, scalar);
|
|
1139
|
+
return new DenseMatrix(a.rows, a.cols, result.result);
|
|
1140
|
+
});
|
|
1153
1141
|
}
|
|
1154
1142
|
abs(a) {
|
|
1155
1143
|
return a.map((v) => Math.abs(v));
|
|
@@ -1160,35 +1148,30 @@ var ParallelBackend = class {
|
|
|
1160
1148
|
async multiply(a, b) {
|
|
1161
1149
|
this.checkMultiplyDimensions(a, b);
|
|
1162
1150
|
const resultSize = a.rows * b.cols;
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1151
|
+
return this.whenParallel(resultSize, () => a.multiply(b), async () => {
|
|
1152
|
+
const aData = a.toFloat64Array();
|
|
1153
|
+
const bData = b.toFloat64Array();
|
|
1154
|
+
const result = await this.pool.matmul(aData, a.rows, a.cols, bData, b.cols);
|
|
1155
|
+
return new DenseMatrix(a.rows, b.cols, result.result);
|
|
1156
|
+
});
|
|
1168
1157
|
}
|
|
1169
1158
|
async transpose(a) {
|
|
1170
1159
|
const elementCount = a.rows * a.cols;
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1160
|
+
return this.whenParallel(elementCount, () => a.transpose(), async () => {
|
|
1161
|
+
const aData = a.toFloat64Array();
|
|
1162
|
+
const result = await this.pool.transpose(aData, a.rows, a.cols);
|
|
1163
|
+
return new DenseMatrix(a.cols, a.rows, result.result);
|
|
1164
|
+
});
|
|
1175
1165
|
}
|
|
1176
1166
|
async sum(a) {
|
|
1177
1167
|
const elementCount = a.rows * a.cols;
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1168
|
+
return this.whenParallel(elementCount, () => a.sum(), async () => {
|
|
1169
|
+
const aData = a.toFloat64Array();
|
|
1170
|
+
return (await this.pool.sum(aData)).result;
|
|
1171
|
+
});
|
|
1181
1172
|
}
|
|
1182
1173
|
sumAxis(a, axis) {
|
|
1183
|
-
|
|
1184
|
-
const result = new Float64Array(a.cols);
|
|
1185
|
-
for (let j = 0; j < a.cols; j++) for (let i = 0; i < a.rows; i++) result[j] += a.get(i, j);
|
|
1186
|
-
return new DenseMatrix(1, a.cols, result);
|
|
1187
|
-
} else {
|
|
1188
|
-
const result = new Float64Array(a.rows);
|
|
1189
|
-
for (let i = 0; i < a.rows; i++) for (let j = 0; j < a.cols; j++) result[i] += a.get(i, j);
|
|
1190
|
-
return new DenseMatrix(a.rows, 1, result);
|
|
1191
|
-
}
|
|
1174
|
+
return jsBackend.sumAxis(a, axis);
|
|
1192
1175
|
}
|
|
1193
1176
|
norm(a) {
|
|
1194
1177
|
return a.norm();
|
|
@@ -1197,16 +1180,11 @@ var ParallelBackend = class {
|
|
|
1197
1180
|
if (!a.isVector || !b.isVector) throw new Error("Dot product requires two vectors");
|
|
1198
1181
|
if (a.length !== b.length) throw new Error(`Vector lengths must match: ${a.length} vs ${b.length}`);
|
|
1199
1182
|
const elementCount = a.length;
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
return sum;
|
|
1206
|
-
}
|
|
1207
|
-
const aData = a.toFloat64Array();
|
|
1208
|
-
const bData = b.toFloat64Array();
|
|
1209
|
-
return (await this.pool.dot(aData, bData)).result;
|
|
1183
|
+
return this.whenParallel(elementCount, () => jsBackend.dot(a, b), async () => {
|
|
1184
|
+
const aData = a.toFloat64Array();
|
|
1185
|
+
const bData = b.toFloat64Array();
|
|
1186
|
+
return (await this.pool.dot(aData, bData)).result;
|
|
1187
|
+
});
|
|
1210
1188
|
}
|
|
1211
1189
|
async terminate() {
|
|
1212
1190
|
if (this.initialized) {
|
|
@@ -1217,6 +1195,19 @@ var ParallelBackend = class {
|
|
|
1217
1195
|
getStats() {
|
|
1218
1196
|
return this.pool.stats();
|
|
1219
1197
|
}
|
|
1198
|
+
whenParallel(elementCount, sequential, parallel) {
|
|
1199
|
+
if (!this.shouldParallelize(elementCount) || !this.isReady()) return sequential();
|
|
1200
|
+
return parallel();
|
|
1201
|
+
}
|
|
1202
|
+
async parallelBinary(a, b, op, sequential) {
|
|
1203
|
+
this.checkDimensionsMatch(a, b);
|
|
1204
|
+
const elementCount = a.rows * a.cols;
|
|
1205
|
+
if (!this.shouldParallelize(elementCount) || !this.isReady()) return sequential(a, b);
|
|
1206
|
+
const aData = a.toFloat64Array();
|
|
1207
|
+
const bData = b.toFloat64Array();
|
|
1208
|
+
const result = await this.pool.elementwise(aData, bData, op);
|
|
1209
|
+
return new DenseMatrix(a.rows, a.cols, result.result);
|
|
1210
|
+
}
|
|
1220
1211
|
checkDimensionsMatch(a, b) {
|
|
1221
1212
|
if (a.rows !== b.rows || a.cols !== b.cols) throw new Error(`Matrix dimensions must match: ${a.rows}×${a.cols} vs ${b.rows}×${b.cols}`);
|
|
1222
1213
|
}
|
|
@@ -1489,14 +1480,20 @@ function getCachedFeatures() {
|
|
|
1489
1480
|
return cachedFeatures;
|
|
1490
1481
|
}
|
|
1491
1482
|
//#endregion
|
|
1483
|
+
//#region src/backends/wasm/as-typed-array.ts
|
|
1484
|
+
function allocAsTypedView(module, byteLength, length, typeId, Ctor) {
|
|
1485
|
+
const { headerPtr, bufferPtr } = allocAsHeader(module, byteLength, typeId);
|
|
1486
|
+
return {
|
|
1487
|
+
headerPtr,
|
|
1488
|
+
bufferPtr,
|
|
1489
|
+
view: new Ctor(module.memory.buffer, bufferPtr, length),
|
|
1490
|
+
byteLength,
|
|
1491
|
+
length
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
//#endregion
|
|
1492
1495
|
//#region src/backends/WASMBackend.ts
|
|
1493
1496
|
init_DenseMatrix();
|
|
1494
|
-
const AS_ID_ARRAY_BUFFER$1 = 1;
|
|
1495
|
-
const AS_ID_FLOAT64_ARRAY$1 = 5;
|
|
1496
|
-
const AS_ID_INT32_ARRAY$1 = 6;
|
|
1497
|
-
const AS_F64_ALIGN_SHIFT = 3;
|
|
1498
|
-
const AS_I32_ALIGN_SHIFT = 2;
|
|
1499
|
-
const AS_HEADER_BYTES$1 = 12;
|
|
1500
1497
|
var AsAllocCache = class {
|
|
1501
1498
|
free = /* @__PURE__ */ new Map();
|
|
1502
1499
|
acquire(module, length) {
|
|
@@ -1517,22 +1514,22 @@ var AsAllocCache = class {
|
|
|
1517
1514
|
pool.push(alloc);
|
|
1518
1515
|
}
|
|
1519
1516
|
allocate(module, length) {
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
dv.setUint32(headerPtr + 0, bufferPtr, true);
|
|
1526
|
-
dv.setUint32(headerPtr + 4, bufferPtr, true);
|
|
1527
|
-
dv.setUint32(headerPtr + 8, byteLength, true);
|
|
1528
|
-
return {
|
|
1529
|
-
headerPtr,
|
|
1530
|
-
bufferPtr,
|
|
1531
|
-
view: new Float64Array(module.memory.buffer, bufferPtr, length),
|
|
1532
|
-
length
|
|
1533
|
-
};
|
|
1517
|
+
return allocHeader(module, length, {
|
|
1518
|
+
shift: 3,
|
|
1519
|
+
typeId: 5,
|
|
1520
|
+
Ctor: Float64Array
|
|
1521
|
+
});
|
|
1534
1522
|
}
|
|
1535
1523
|
};
|
|
1524
|
+
function allocHeader(module, length, opts) {
|
|
1525
|
+
const { headerPtr, bufferPtr, view } = allocAsTypedView(module, length << opts.shift, length, opts.typeId, opts.Ctor);
|
|
1526
|
+
return {
|
|
1527
|
+
headerPtr,
|
|
1528
|
+
bufferPtr,
|
|
1529
|
+
view,
|
|
1530
|
+
length
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1536
1533
|
function writeAsFloat64Array(cache, module, data) {
|
|
1537
1534
|
const alloc = cache.acquire(module, data.length);
|
|
1538
1535
|
alloc.view.set(data);
|
|
@@ -1546,20 +1543,11 @@ function readAsFloat64Array(module, alloc) {
|
|
|
1546
1543
|
return new Float64Array(view);
|
|
1547
1544
|
}
|
|
1548
1545
|
function allocAsInt32Array(module, length) {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
dv.setUint32(headerPtr + 0, bufferPtr, true);
|
|
1555
|
-
dv.setUint32(headerPtr + 4, bufferPtr, true);
|
|
1556
|
-
dv.setUint32(headerPtr + 8, byteLength, true);
|
|
1557
|
-
return {
|
|
1558
|
-
headerPtr,
|
|
1559
|
-
bufferPtr,
|
|
1560
|
-
view: new Int32Array(module.memory.buffer, bufferPtr, length),
|
|
1561
|
-
length
|
|
1562
|
-
};
|
|
1546
|
+
return allocHeader(module, length, {
|
|
1547
|
+
shift: 2,
|
|
1548
|
+
typeId: 6,
|
|
1549
|
+
Ctor: Int32Array
|
|
1550
|
+
});
|
|
1563
1551
|
}
|
|
1564
1552
|
function readAsInt32Array(module, alloc) {
|
|
1565
1553
|
const view = new Int32Array(module.memory.buffer, alloc.bufferPtr, alloc.length);
|
|
@@ -2190,6 +2178,165 @@ function registerBuiltinShaders(sm) {
|
|
|
2190
2178
|
for (const [name, code] of Object.entries(BUILTIN_SHADERS)) sm.registerShader(name, code);
|
|
2191
2179
|
}
|
|
2192
2180
|
//#endregion
|
|
2181
|
+
//#region src/backends/gpu/run-shader.ts
|
|
2182
|
+
const UNIFORM_BYTES = 16;
|
|
2183
|
+
function planRunShaderFromAdd(a, b, rows, cols, workgroups) {
|
|
2184
|
+
const size = rows * cols * 4;
|
|
2185
|
+
return {
|
|
2186
|
+
pipeline: "matrixAdd",
|
|
2187
|
+
bytes: [
|
|
2188
|
+
size,
|
|
2189
|
+
size,
|
|
2190
|
+
size
|
|
2191
|
+
],
|
|
2192
|
+
storageLabels: [
|
|
2193
|
+
"matrix-a",
|
|
2194
|
+
"matrix-b",
|
|
2195
|
+
"matrix-result"
|
|
2196
|
+
],
|
|
2197
|
+
writes: [a, b],
|
|
2198
|
+
bindEntries: [
|
|
2199
|
+
{
|
|
2200
|
+
binding: 0,
|
|
2201
|
+
bufferIndex: 0
|
|
2202
|
+
},
|
|
2203
|
+
{
|
|
2204
|
+
binding: 1,
|
|
2205
|
+
bufferIndex: 1
|
|
2206
|
+
},
|
|
2207
|
+
{
|
|
2208
|
+
binding: 2,
|
|
2209
|
+
bufferIndex: 2
|
|
2210
|
+
},
|
|
2211
|
+
{
|
|
2212
|
+
binding: 3,
|
|
2213
|
+
bufferIndex: -1
|
|
2214
|
+
}
|
|
2215
|
+
],
|
|
2216
|
+
params: new Uint32Array([
|
|
2217
|
+
rows,
|
|
2218
|
+
cols,
|
|
2219
|
+
0,
|
|
2220
|
+
0
|
|
2221
|
+
]),
|
|
2222
|
+
workgroups,
|
|
2223
|
+
resultBufferIndex: 2
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function planRunShaderFromMatmul(a, b, M, K, N, workgroups) {
|
|
2227
|
+
return {
|
|
2228
|
+
pipeline: "matmul",
|
|
2229
|
+
bytes: [
|
|
2230
|
+
M * K * 4,
|
|
2231
|
+
K * N * 4,
|
|
2232
|
+
M * N * 4
|
|
2233
|
+
],
|
|
2234
|
+
storageLabels: [
|
|
2235
|
+
"matmul-a",
|
|
2236
|
+
"matmul-b",
|
|
2237
|
+
"matmul-result"
|
|
2238
|
+
],
|
|
2239
|
+
writes: [a, b],
|
|
2240
|
+
bindEntries: [
|
|
2241
|
+
{
|
|
2242
|
+
binding: 0,
|
|
2243
|
+
bufferIndex: 0
|
|
2244
|
+
},
|
|
2245
|
+
{
|
|
2246
|
+
binding: 1,
|
|
2247
|
+
bufferIndex: 1
|
|
2248
|
+
},
|
|
2249
|
+
{
|
|
2250
|
+
binding: 2,
|
|
2251
|
+
bufferIndex: 2
|
|
2252
|
+
},
|
|
2253
|
+
{
|
|
2254
|
+
binding: 3,
|
|
2255
|
+
bufferIndex: -1
|
|
2256
|
+
}
|
|
2257
|
+
],
|
|
2258
|
+
params: new Uint32Array([
|
|
2259
|
+
M,
|
|
2260
|
+
N,
|
|
2261
|
+
K,
|
|
2262
|
+
0
|
|
2263
|
+
]),
|
|
2264
|
+
workgroups,
|
|
2265
|
+
resultBufferIndex: 2
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
function planRunShaderFromTranspose(a, rows, cols, workgroups) {
|
|
2269
|
+
const size = rows * cols * 4;
|
|
2270
|
+
return {
|
|
2271
|
+
pipeline: "transpose",
|
|
2272
|
+
bytes: [size, size],
|
|
2273
|
+
storageLabels: ["transpose-a", "transpose-result"],
|
|
2274
|
+
writes: [a],
|
|
2275
|
+
bindEntries: [
|
|
2276
|
+
{
|
|
2277
|
+
binding: 0,
|
|
2278
|
+
bufferIndex: 0
|
|
2279
|
+
},
|
|
2280
|
+
{
|
|
2281
|
+
binding: 1,
|
|
2282
|
+
bufferIndex: 1
|
|
2283
|
+
},
|
|
2284
|
+
{
|
|
2285
|
+
binding: 2,
|
|
2286
|
+
bufferIndex: -1
|
|
2287
|
+
}
|
|
2288
|
+
],
|
|
2289
|
+
params: new Uint32Array([
|
|
2290
|
+
rows,
|
|
2291
|
+
cols,
|
|
2292
|
+
0,
|
|
2293
|
+
0
|
|
2294
|
+
]),
|
|
2295
|
+
workgroups,
|
|
2296
|
+
resultBufferIndex: 1
|
|
2297
|
+
};
|
|
2298
|
+
}
|
|
2299
|
+
async function runShader(backend, plan) {
|
|
2300
|
+
const ctx = backend.getContext();
|
|
2301
|
+
const pool = backend.getBufferPool();
|
|
2302
|
+
const shaders = backend.getShaderManager();
|
|
2303
|
+
const storageBuffers = [];
|
|
2304
|
+
let bufferParams;
|
|
2305
|
+
try {
|
|
2306
|
+
for (let idx = 0; idx < plan.bytes.length; idx++) {
|
|
2307
|
+
const byteSize = plan.bytes[idx];
|
|
2308
|
+
if (byteSize === void 0) throw new Error(`runShader: missing byte size at index ${idx}`);
|
|
2309
|
+
storageBuffers.push(pool.acquireStorageBuffer(byteSize, plan.storageLabels[idx] ?? `storage-${idx}`, true, idx !== plan.resultBufferIndex));
|
|
2310
|
+
}
|
|
2311
|
+
bufferParams = pool.acquireUniformBuffer(UNIFORM_BYTES, "params");
|
|
2312
|
+
for (let i = 0; i < plan.writes.length; i++) {
|
|
2313
|
+
const target = storageBuffers[i];
|
|
2314
|
+
const payload = plan.writes[i];
|
|
2315
|
+
if (target === void 0 || payload === void 0) throw new Error(`runShader: missing write target at index ${i}`);
|
|
2316
|
+
ctx.writeBuffer(target, payload);
|
|
2317
|
+
}
|
|
2318
|
+
ctx.writeBuffer(bufferParams, plan.params);
|
|
2319
|
+
const pipeline = shaders.getRegisteredPipeline(plan.pipeline);
|
|
2320
|
+
const bindResources = plan.bindEntries.map((entry) => {
|
|
2321
|
+
const buffer = entry.bufferIndex === -1 ? bufferParams : storageBuffers[entry.bufferIndex];
|
|
2322
|
+
if (buffer === void 0) throw new Error(`runShader: missing buffer for binding ${entry.binding}`);
|
|
2323
|
+
return {
|
|
2324
|
+
binding: entry.binding,
|
|
2325
|
+
resource: { buffer }
|
|
2326
|
+
};
|
|
2327
|
+
});
|
|
2328
|
+
const bindGroup = ctx.createBindGroup(pipeline.getBindGroupLayout(0), bindResources);
|
|
2329
|
+
ctx.dispatchCompute(pipeline, [bindGroup], plan.workgroups);
|
|
2330
|
+
const resultBuf = storageBuffers[plan.resultBufferIndex];
|
|
2331
|
+
if (resultBuf === void 0) throw new Error(`runShader: missing result buffer at index ${plan.resultBufferIndex}`);
|
|
2332
|
+
const resultData = await ctx.readBuffer(resultBuf);
|
|
2333
|
+
return new Float32Array(resultData);
|
|
2334
|
+
} finally {
|
|
2335
|
+
for (const buf of storageBuffers) pool.release(buf);
|
|
2336
|
+
if (bufferParams !== void 0) pool.release(bufferParams);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
//#endregion
|
|
2193
2340
|
//#region src/backends/GPUBackend.ts
|
|
2194
2341
|
const DEFAULT_THRESHOLD = 256;
|
|
2195
2342
|
var GPUBackend = class {
|
|
@@ -2283,131 +2430,13 @@ var GPUBackend = class {
|
|
|
2283
2430
|
return this.shaderManager;
|
|
2284
2431
|
}
|
|
2285
2432
|
async add(a, b, rows, cols) {
|
|
2286
|
-
|
|
2287
|
-
const pool = this.getBufferPool();
|
|
2288
|
-
const shaders = this.getShaderManager();
|
|
2289
|
-
const size = rows * cols * 4;
|
|
2290
|
-
const bufferA = pool.acquireStorageBuffer(size, "matrix-a", true, true);
|
|
2291
|
-
const bufferB = pool.acquireStorageBuffer(size, "matrix-b", true, true);
|
|
2292
|
-
const bufferResult = pool.acquireStorageBuffer(size, "matrix-result", true, false);
|
|
2293
|
-
const bufferParams = pool.acquireUniformBuffer(16, "params");
|
|
2294
|
-
ctx.writeBuffer(bufferA, a);
|
|
2295
|
-
ctx.writeBuffer(bufferB, b);
|
|
2296
|
-
ctx.writeBuffer(bufferParams, new Uint32Array([
|
|
2297
|
-
rows,
|
|
2298
|
-
cols,
|
|
2299
|
-
0,
|
|
2300
|
-
0
|
|
2301
|
-
]));
|
|
2302
|
-
const pipeline = shaders.getRegisteredPipeline("matrixAdd");
|
|
2303
|
-
const bindGroup = ctx.createBindGroup(pipeline.getBindGroupLayout(0), [
|
|
2304
|
-
{
|
|
2305
|
-
binding: 0,
|
|
2306
|
-
resource: { buffer: bufferA }
|
|
2307
|
-
},
|
|
2308
|
-
{
|
|
2309
|
-
binding: 1,
|
|
2310
|
-
resource: { buffer: bufferB }
|
|
2311
|
-
},
|
|
2312
|
-
{
|
|
2313
|
-
binding: 2,
|
|
2314
|
-
resource: { buffer: bufferResult }
|
|
2315
|
-
},
|
|
2316
|
-
{
|
|
2317
|
-
binding: 3,
|
|
2318
|
-
resource: { buffer: bufferParams }
|
|
2319
|
-
}
|
|
2320
|
-
]);
|
|
2321
|
-
ctx.dispatchCompute(pipeline, [bindGroup], this.calculateWorkgroups(rows, cols));
|
|
2322
|
-
const resultData = await ctx.readBuffer(bufferResult);
|
|
2323
|
-
pool.release(bufferA);
|
|
2324
|
-
pool.release(bufferB);
|
|
2325
|
-
pool.release(bufferResult);
|
|
2326
|
-
pool.release(bufferParams);
|
|
2327
|
-
return new Float32Array(resultData);
|
|
2433
|
+
return runShader(this, planRunShaderFromAdd(a, b, rows, cols, this.calculateWorkgroups(rows, cols)));
|
|
2328
2434
|
}
|
|
2329
2435
|
async matmul(a, b, M, K, N) {
|
|
2330
|
-
|
|
2331
|
-
const pool = this.getBufferPool();
|
|
2332
|
-
const shaders = this.getShaderManager();
|
|
2333
|
-
const sizeA = M * K * 4;
|
|
2334
|
-
const sizeB = K * N * 4;
|
|
2335
|
-
const sizeResult = M * N * 4;
|
|
2336
|
-
const bufferA = pool.acquireStorageBuffer(sizeA, "matmul-a", true, true);
|
|
2337
|
-
const bufferB = pool.acquireStorageBuffer(sizeB, "matmul-b", true, true);
|
|
2338
|
-
const bufferResult = pool.acquireStorageBuffer(sizeResult, "matmul-result", true, false);
|
|
2339
|
-
const bufferParams = pool.acquireUniformBuffer(16, "params");
|
|
2340
|
-
ctx.writeBuffer(bufferA, a);
|
|
2341
|
-
ctx.writeBuffer(bufferB, b);
|
|
2342
|
-
ctx.writeBuffer(bufferParams, new Uint32Array([
|
|
2343
|
-
M,
|
|
2344
|
-
N,
|
|
2345
|
-
K,
|
|
2346
|
-
0
|
|
2347
|
-
]));
|
|
2348
|
-
const pipeline = shaders.getRegisteredPipeline("matmul");
|
|
2349
|
-
const bindGroup = ctx.createBindGroup(pipeline.getBindGroupLayout(0), [
|
|
2350
|
-
{
|
|
2351
|
-
binding: 0,
|
|
2352
|
-
resource: { buffer: bufferA }
|
|
2353
|
-
},
|
|
2354
|
-
{
|
|
2355
|
-
binding: 1,
|
|
2356
|
-
resource: { buffer: bufferB }
|
|
2357
|
-
},
|
|
2358
|
-
{
|
|
2359
|
-
binding: 2,
|
|
2360
|
-
resource: { buffer: bufferResult }
|
|
2361
|
-
},
|
|
2362
|
-
{
|
|
2363
|
-
binding: 3,
|
|
2364
|
-
resource: { buffer: bufferParams }
|
|
2365
|
-
}
|
|
2366
|
-
]);
|
|
2367
|
-
ctx.dispatchCompute(pipeline, [bindGroup], this.calculateWorkgroups(M, N));
|
|
2368
|
-
const resultData = await ctx.readBuffer(bufferResult);
|
|
2369
|
-
pool.release(bufferA);
|
|
2370
|
-
pool.release(bufferB);
|
|
2371
|
-
pool.release(bufferResult);
|
|
2372
|
-
pool.release(bufferParams);
|
|
2373
|
-
return new Float32Array(resultData);
|
|
2436
|
+
return runShader(this, planRunShaderFromMatmul(a, b, M, K, N, this.calculateWorkgroups(M, N)));
|
|
2374
2437
|
}
|
|
2375
2438
|
async transpose(a, rows, cols) {
|
|
2376
|
-
|
|
2377
|
-
const pool = this.getBufferPool();
|
|
2378
|
-
const shaders = this.getShaderManager();
|
|
2379
|
-
const size = rows * cols * 4;
|
|
2380
|
-
const bufferA = pool.acquireStorageBuffer(size, "transpose-a", true, true);
|
|
2381
|
-
const bufferResult = pool.acquireStorageBuffer(size, "transpose-result", true, false);
|
|
2382
|
-
const bufferParams = pool.acquireUniformBuffer(16, "params");
|
|
2383
|
-
ctx.writeBuffer(bufferA, a);
|
|
2384
|
-
ctx.writeBuffer(bufferParams, new Uint32Array([
|
|
2385
|
-
rows,
|
|
2386
|
-
cols,
|
|
2387
|
-
0,
|
|
2388
|
-
0
|
|
2389
|
-
]));
|
|
2390
|
-
const pipeline = shaders.getRegisteredPipeline("transpose");
|
|
2391
|
-
const bindGroup = ctx.createBindGroup(pipeline.getBindGroupLayout(0), [
|
|
2392
|
-
{
|
|
2393
|
-
binding: 0,
|
|
2394
|
-
resource: { buffer: bufferA }
|
|
2395
|
-
},
|
|
2396
|
-
{
|
|
2397
|
-
binding: 1,
|
|
2398
|
-
resource: { buffer: bufferResult }
|
|
2399
|
-
},
|
|
2400
|
-
{
|
|
2401
|
-
binding: 2,
|
|
2402
|
-
resource: { buffer: bufferParams }
|
|
2403
|
-
}
|
|
2404
|
-
]);
|
|
2405
|
-
ctx.dispatchCompute(pipeline, [bindGroup], this.calculateWorkgroups(rows, cols));
|
|
2406
|
-
const resultData = await ctx.readBuffer(bufferResult);
|
|
2407
|
-
pool.release(bufferA);
|
|
2408
|
-
pool.release(bufferResult);
|
|
2409
|
-
pool.release(bufferParams);
|
|
2410
|
-
return new Float32Array(resultData);
|
|
2439
|
+
return runShader(this, planRunShaderFromTranspose(a, rows, cols, this.calculateWorkgroups(rows, cols)));
|
|
2411
2440
|
}
|
|
2412
2441
|
async scale(a, scalar) {
|
|
2413
2442
|
const ctx = this.getContext();
|
|
@@ -2488,6 +2517,12 @@ function destroyGlobalGPUBackend() {
|
|
|
2488
2517
|
}
|
|
2489
2518
|
}
|
|
2490
2519
|
//#endregion
|
|
2520
|
+
//#region src/backends/gpu/gpu-or-js.ts
|
|
2521
|
+
async function gpuOrJs(useGpu, js, gpu, executeWithFallback) {
|
|
2522
|
+
if (!useGpu) return js();
|
|
2523
|
+
return executeWithFallback(gpu, js);
|
|
2524
|
+
}
|
|
2525
|
+
//#endregion
|
|
2491
2526
|
//#region src/backends/GPUMatrixBackend.ts
|
|
2492
2527
|
init_DenseMatrix();
|
|
2493
2528
|
const DEFAULT_CONFIG$1 = {
|
|
@@ -2557,13 +2592,12 @@ var GPUMatrixBackend = class {
|
|
|
2557
2592
|
}
|
|
2558
2593
|
async addAsync(a, b) {
|
|
2559
2594
|
const elementCount = a.rows * a.cols;
|
|
2560
|
-
|
|
2561
|
-
return this.executeWithFallback(async () => {
|
|
2595
|
+
return gpuOrJs(this.shouldUseGPU(elementCount), () => jsBackend.add(a, b), async () => {
|
|
2562
2596
|
const aData = new Float32Array(a.toFloat64Array());
|
|
2563
2597
|
const bData = new Float32Array(b.toFloat64Array());
|
|
2564
2598
|
const result = await this.backend.add(aData, bData, a.rows, a.cols);
|
|
2565
2599
|
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
2566
|
-
}, () =>
|
|
2600
|
+
}, (gpuOp, fallback) => this.executeWithFallback(gpuOp, fallback));
|
|
2567
2601
|
}
|
|
2568
2602
|
subtract(a, b) {
|
|
2569
2603
|
const elementCount = a.rows * a.cols;
|
|
@@ -2587,12 +2621,11 @@ var GPUMatrixBackend = class {
|
|
|
2587
2621
|
}
|
|
2588
2622
|
async scaleAsync(a, scalar) {
|
|
2589
2623
|
const elementCount = a.rows * a.cols;
|
|
2590
|
-
|
|
2591
|
-
return this.executeWithFallback(async () => {
|
|
2624
|
+
return gpuOrJs(this.shouldUseGPU(elementCount), () => jsBackend.scale(a, scalar), async () => {
|
|
2592
2625
|
const aData = new Float32Array(a.toFloat64Array());
|
|
2593
2626
|
const result = await this.backend.scale(aData, scalar);
|
|
2594
2627
|
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
2595
|
-
}, () =>
|
|
2628
|
+
}, (gpuOp, fallback) => this.executeWithFallback(gpuOp, fallback));
|
|
2596
2629
|
}
|
|
2597
2630
|
abs(a) {
|
|
2598
2631
|
return jsBackend.abs(a);
|
|
@@ -2607,13 +2640,12 @@ var GPUMatrixBackend = class {
|
|
|
2607
2640
|
}
|
|
2608
2641
|
async multiplyAsync(a, b) {
|
|
2609
2642
|
const elementCount = a.rows * b.cols * a.cols;
|
|
2610
|
-
|
|
2611
|
-
return this.executeWithFallback(async () => {
|
|
2643
|
+
return gpuOrJs(this.shouldUseGPU(elementCount), () => jsBackend.multiply(a, b), async () => {
|
|
2612
2644
|
const aData = new Float32Array(a.toFloat64Array());
|
|
2613
2645
|
const bData = new Float32Array(b.toFloat64Array());
|
|
2614
2646
|
const result = await this.backend.matmul(aData, bData, a.rows, a.cols, b.cols);
|
|
2615
2647
|
return DenseMatrix.fromFlat(a.rows, b.cols, Array.from(result));
|
|
2616
|
-
}, () =>
|
|
2648
|
+
}, (gpuOp, fallback) => this.executeWithFallback(gpuOp, fallback));
|
|
2617
2649
|
}
|
|
2618
2650
|
transpose(a) {
|
|
2619
2651
|
const elementCount = a.rows * a.cols;
|
|
@@ -2659,7 +2691,9 @@ const gpuMatrixBackend = new GPUMatrixBackend();
|
|
|
2659
2691
|
function createGPUMatrixBackend(config) {
|
|
2660
2692
|
return new GPUMatrixBackend(config);
|
|
2661
2693
|
}
|
|
2662
|
-
|
|
2694
|
+
//#endregion
|
|
2695
|
+
//#region src/config.ts
|
|
2696
|
+
const DEFAULT_CONFIG = {
|
|
2663
2697
|
backends: {
|
|
2664
2698
|
js: {
|
|
2665
2699
|
enabled: true,
|
|
@@ -2670,21 +2704,21 @@ let currentConfig = {
|
|
|
2670
2704
|
wasm: {
|
|
2671
2705
|
enabled: true,
|
|
2672
2706
|
preference: "auto",
|
|
2673
|
-
threshold:
|
|
2707
|
+
threshold: DEFAULT_BACKEND_HINTS.wasmThreshold,
|
|
2674
2708
|
operationThresholds: {
|
|
2675
|
-
multiply:
|
|
2709
|
+
multiply: 256,
|
|
2676
2710
|
decomposition: 100,
|
|
2677
2711
|
transpose: 2e3
|
|
2678
2712
|
}
|
|
2679
2713
|
},
|
|
2680
2714
|
gpu: {
|
|
2681
|
-
enabled:
|
|
2715
|
+
enabled: false,
|
|
2682
2716
|
preference: "auto",
|
|
2683
|
-
threshold:
|
|
2717
|
+
threshold: DEFAULT_BACKEND_HINTS.gpuThreshold,
|
|
2684
2718
|
operationThresholds: {
|
|
2685
|
-
multiply:
|
|
2686
|
-
decomposition:
|
|
2687
|
-
transpose:
|
|
2719
|
+
multiply: DEFAULT_BACKEND_HINTS.gpuThreshold,
|
|
2720
|
+
decomposition: DEFAULT_BACKEND_HINTS.gpuThreshold,
|
|
2721
|
+
transpose: DEFAULT_BACKEND_HINTS.gpuThreshold
|
|
2688
2722
|
}
|
|
2689
2723
|
}
|
|
2690
2724
|
},
|
|
@@ -2703,6 +2737,7 @@ let currentConfig = {
|
|
|
2703
2737
|
precision: "double",
|
|
2704
2738
|
debug: false
|
|
2705
2739
|
};
|
|
2740
|
+
let currentConfig = { ...DEFAULT_CONFIG };
|
|
2706
2741
|
const listeners = /* @__PURE__ */ new Set();
|
|
2707
2742
|
function getConfig() {
|
|
2708
2743
|
return currentConfig;
|
|
@@ -2717,25 +2752,33 @@ backendRegistry.register(jsBackend);
|
|
|
2717
2752
|
backendRegistry.register(wasmBackend);
|
|
2718
2753
|
//#endregion
|
|
2719
2754
|
//#region src/backends/BackendManager.ts
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
operationThresholds
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2755
|
+
function extendedHintsFromConfig(config) {
|
|
2756
|
+
const { wasm, gpu } = config.backends;
|
|
2757
|
+
const wasmOps = wasm.operationThresholds ?? {};
|
|
2758
|
+
const gpuOps = gpu.operationThresholds ?? {};
|
|
2759
|
+
return {
|
|
2760
|
+
wasmThreshold: wasm.threshold,
|
|
2761
|
+
gpuThreshold: gpu.threshold,
|
|
2762
|
+
preferredBackend: DEFAULT_BACKEND_HINTS.preferredBackend,
|
|
2763
|
+
operationThresholds: {
|
|
2764
|
+
multiply: {
|
|
2765
|
+
wasm: wasmOps.multiply ?? wasm.threshold,
|
|
2766
|
+
gpu: gpuOps.multiply ?? gpu.threshold
|
|
2767
|
+
},
|
|
2768
|
+
decomposition: {
|
|
2769
|
+
wasm: wasmOps.decomposition ?? wasm.threshold,
|
|
2770
|
+
gpu: gpuOps.decomposition ?? gpu.threshold
|
|
2771
|
+
},
|
|
2772
|
+
transpose: {
|
|
2773
|
+
wasm: wasmOps.transpose ?? wasm.threshold,
|
|
2774
|
+
gpu: gpuOps.transpose ?? gpu.threshold
|
|
2775
|
+
}
|
|
2730
2776
|
},
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
autoSIMD: true,
|
|
2737
|
-
fallbackOnError: true
|
|
2738
|
-
};
|
|
2777
|
+
autoSIMD: true,
|
|
2778
|
+
fallbackOnError: true
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
const DEFAULT_EXTENDED_HINTS = extendedHintsFromConfig(DEFAULT_CONFIG);
|
|
2739
2782
|
var BackendManager = class {
|
|
2740
2783
|
hints;
|
|
2741
2784
|
initialized = false;
|
|
@@ -3018,387 +3061,6 @@ function createBackendManager(hints) {
|
|
|
3018
3061
|
return new BackendManager(hints);
|
|
3019
3062
|
}
|
|
3020
3063
|
//#endregion
|
|
3021
|
-
//#region src/backends/WasmLoader.ts
|
|
3022
|
-
const AS_ID_ARRAY_BUFFER = 1;
|
|
3023
|
-
const AS_ID_INT32_ARRAY = 4;
|
|
3024
|
-
const AS_ID_FLOAT64_ARRAY = 5;
|
|
3025
|
-
const AS_HEADER_BYTES = 12;
|
|
3026
|
-
(class WasmLoader {
|
|
3027
|
-
static instance = null;
|
|
3028
|
-
wasmModule = null;
|
|
3029
|
-
compiledModule = null;
|
|
3030
|
-
loading = null;
|
|
3031
|
-
isNode;
|
|
3032
|
-
lastMetrics = null;
|
|
3033
|
-
float64Pool = [];
|
|
3034
|
-
int32Pool = [];
|
|
3035
|
-
poolSizeThreshold = 1048576;
|
|
3036
|
-
constructor() {
|
|
3037
|
-
this.isNode = typeof process !== "undefined" && process.versions?.node !== void 0;
|
|
3038
|
-
}
|
|
3039
|
-
static getInstance() {
|
|
3040
|
-
if (!WasmLoader.instance) WasmLoader.instance = new WasmLoader();
|
|
3041
|
-
return WasmLoader.instance;
|
|
3042
|
-
}
|
|
3043
|
-
async load(wasmPath) {
|
|
3044
|
-
if (this.wasmModule) return this.wasmModule;
|
|
3045
|
-
if (this.loading) return this.loading;
|
|
3046
|
-
this.loading = this.loadModule(wasmPath);
|
|
3047
|
-
try {
|
|
3048
|
-
this.wasmModule = await this.loading;
|
|
3049
|
-
} catch (error) {
|
|
3050
|
-
this.compiledModule = null;
|
|
3051
|
-
throw error;
|
|
3052
|
-
} finally {
|
|
3053
|
-
this.loading = null;
|
|
3054
|
-
}
|
|
3055
|
-
return this.wasmModule;
|
|
3056
|
-
}
|
|
3057
|
-
async precompile(wasmPath) {
|
|
3058
|
-
if (this.compiledModule) return;
|
|
3059
|
-
const path = wasmPath || await this.getDefaultWasmPath();
|
|
3060
|
-
const startTime = performance.now();
|
|
3061
|
-
const { loadWasmManifest, verifyWasmIntegrity } = await import("./integrity-Hbf0W3mK.js");
|
|
3062
|
-
if (this.isNode) {
|
|
3063
|
-
const fs = await import("fs");
|
|
3064
|
-
const { promisify } = await import("util");
|
|
3065
|
-
const buffer = await promisify(fs.readFile)(path);
|
|
3066
|
-
await verifyWasmIntegrity(buffer, path);
|
|
3067
|
-
this.compiledModule = await WebAssembly.compile(buffer);
|
|
3068
|
-
} else {
|
|
3069
|
-
const manifest = await loadWasmManifest(path);
|
|
3070
|
-
if (!manifest && typeof WebAssembly.compileStreaming === "function") this.compiledModule = await WebAssembly.compileStreaming(fetch(path));
|
|
3071
|
-
else {
|
|
3072
|
-
const buffer = await (await fetch(path)).arrayBuffer();
|
|
3073
|
-
await verifyWasmIntegrity(buffer, path, { manifest });
|
|
3074
|
-
this.compiledModule = await WebAssembly.compile(buffer);
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
this.lastMetrics = {
|
|
3078
|
-
fileReadMs: 0,
|
|
3079
|
-
compileMs: performance.now() - startTime,
|
|
3080
|
-
instantiateMs: 0,
|
|
3081
|
-
totalMs: performance.now() - startTime,
|
|
3082
|
-
fromCache: false
|
|
3083
|
-
};
|
|
3084
|
-
}
|
|
3085
|
-
async loadModule(wasmPath) {
|
|
3086
|
-
const path = wasmPath || await this.getDefaultWasmPath();
|
|
3087
|
-
const totalStart = performance.now();
|
|
3088
|
-
if (this.compiledModule) {
|
|
3089
|
-
const instStart = performance.now();
|
|
3090
|
-
const instance = await WebAssembly.instantiate(this.compiledModule, this.getImports());
|
|
3091
|
-
this.lastMetrics = {
|
|
3092
|
-
fileReadMs: 0,
|
|
3093
|
-
compileMs: 0,
|
|
3094
|
-
instantiateMs: performance.now() - instStart,
|
|
3095
|
-
totalMs: performance.now() - totalStart,
|
|
3096
|
-
fromCache: true
|
|
3097
|
-
};
|
|
3098
|
-
return instance.exports;
|
|
3099
|
-
}
|
|
3100
|
-
if (this.isNode) return this.loadNodeWasm(path, totalStart);
|
|
3101
|
-
else return this.loadBrowserWasm(path, totalStart);
|
|
3102
|
-
}
|
|
3103
|
-
async getDefaultWasmPath() {
|
|
3104
|
-
const wasmFile = "mathts-as.wasm";
|
|
3105
|
-
if (this.isNode) {
|
|
3106
|
-
const { resolvePackagedWasm } = await import("./resolve-BzZxSO28.js");
|
|
3107
|
-
const found = await resolvePackagedWasm(import.meta.url, wasmFile);
|
|
3108
|
-
if (found) return found;
|
|
3109
|
-
const { defaultWasmLocation } = await import("./resolve-BzZxSO28.js");
|
|
3110
|
-
return defaultWasmLocation(import.meta.url, wasmFile);
|
|
3111
|
-
}
|
|
3112
|
-
const { defaultWasmLocation } = await import("./resolve-BzZxSO28.js");
|
|
3113
|
-
return defaultWasmLocation(import.meta.url, wasmFile, { browser: true });
|
|
3114
|
-
}
|
|
3115
|
-
async loadNodeWasm(path, totalStart) {
|
|
3116
|
-
const fs = await import("fs");
|
|
3117
|
-
const { promisify } = await import("util");
|
|
3118
|
-
const readFile = promisify(fs.readFile);
|
|
3119
|
-
const { verifyWasmIntegrity } = await import("./integrity-Hbf0W3mK.js");
|
|
3120
|
-
const readStart = performance.now();
|
|
3121
|
-
const buffer = await readFile(path);
|
|
3122
|
-
const readEnd = performance.now();
|
|
3123
|
-
await verifyWasmIntegrity(buffer, path);
|
|
3124
|
-
const compileStart = performance.now();
|
|
3125
|
-
this.compiledModule = await WebAssembly.compile(buffer);
|
|
3126
|
-
const compileEnd = performance.now();
|
|
3127
|
-
const instStart = performance.now();
|
|
3128
|
-
const instance = await WebAssembly.instantiate(this.compiledModule, this.getImports());
|
|
3129
|
-
const instEnd = performance.now();
|
|
3130
|
-
this.lastMetrics = {
|
|
3131
|
-
fileReadMs: readEnd - readStart,
|
|
3132
|
-
compileMs: compileEnd - compileStart,
|
|
3133
|
-
instantiateMs: instEnd - instStart,
|
|
3134
|
-
totalMs: performance.now() - totalStart,
|
|
3135
|
-
fromCache: false
|
|
3136
|
-
};
|
|
3137
|
-
return instance.exports;
|
|
3138
|
-
}
|
|
3139
|
-
async loadBrowserWasm(path, totalStart) {
|
|
3140
|
-
const { loadWasmManifest, verifyWasmIntegrity } = await import("./integrity-Hbf0W3mK.js");
|
|
3141
|
-
const manifest = await loadWasmManifest(path);
|
|
3142
|
-
if (!manifest && typeof WebAssembly.instantiateStreaming === "function") {
|
|
3143
|
-
const instStart = performance.now();
|
|
3144
|
-
const result = await WebAssembly.instantiateStreaming(fetch(path), this.getImports());
|
|
3145
|
-
this.compiledModule = result.module;
|
|
3146
|
-
this.lastMetrics = {
|
|
3147
|
-
fileReadMs: 0,
|
|
3148
|
-
compileMs: 0,
|
|
3149
|
-
instantiateMs: performance.now() - instStart,
|
|
3150
|
-
totalMs: performance.now() - totalStart,
|
|
3151
|
-
fromCache: false
|
|
3152
|
-
};
|
|
3153
|
-
return result.instance.exports;
|
|
3154
|
-
}
|
|
3155
|
-
const readStart = performance.now();
|
|
3156
|
-
const buffer = await (await fetch(path)).arrayBuffer();
|
|
3157
|
-
const readEnd = performance.now();
|
|
3158
|
-
await verifyWasmIntegrity(buffer, path, { manifest });
|
|
3159
|
-
const compileStart = performance.now();
|
|
3160
|
-
this.compiledModule = await WebAssembly.compile(buffer);
|
|
3161
|
-
const compileEnd = performance.now();
|
|
3162
|
-
const instStart = performance.now();
|
|
3163
|
-
const instance = await WebAssembly.instantiate(this.compiledModule, this.getImports());
|
|
3164
|
-
const instEnd = performance.now();
|
|
3165
|
-
this.lastMetrics = {
|
|
3166
|
-
fileReadMs: readEnd - readStart,
|
|
3167
|
-
compileMs: compileEnd - compileStart,
|
|
3168
|
-
instantiateMs: instEnd - instStart,
|
|
3169
|
-
totalMs: performance.now() - totalStart,
|
|
3170
|
-
fromCache: false
|
|
3171
|
-
};
|
|
3172
|
-
return instance.exports;
|
|
3173
|
-
}
|
|
3174
|
-
getImports() {
|
|
3175
|
-
return {
|
|
3176
|
-
env: {
|
|
3177
|
-
abort: (msg, file, line, column) => {
|
|
3178
|
-
console.error("WASM abort", {
|
|
3179
|
-
msg,
|
|
3180
|
-
file,
|
|
3181
|
-
line,
|
|
3182
|
-
column
|
|
3183
|
-
});
|
|
3184
|
-
throw new Error("WASM abort");
|
|
3185
|
-
},
|
|
3186
|
-
seed: () => Date.now()
|
|
3187
|
-
},
|
|
3188
|
-
Math,
|
|
3189
|
-
Date
|
|
3190
|
-
};
|
|
3191
|
-
}
|
|
3192
|
-
getModule() {
|
|
3193
|
-
return this.wasmModule;
|
|
3194
|
-
}
|
|
3195
|
-
getCompiledModule() {
|
|
3196
|
-
return this.compiledModule;
|
|
3197
|
-
}
|
|
3198
|
-
isLoaded() {
|
|
3199
|
-
return this.wasmModule !== null;
|
|
3200
|
-
}
|
|
3201
|
-
isPrecompiled() {
|
|
3202
|
-
return this.compiledModule !== null;
|
|
3203
|
-
}
|
|
3204
|
-
getLoadingMetrics() {
|
|
3205
|
-
return this.lastMetrics;
|
|
3206
|
-
}
|
|
3207
|
-
allocateFloat64Array(data) {
|
|
3208
|
-
const module = this.wasmModule;
|
|
3209
|
-
if (!module) throw new Error("WASM module not loaded");
|
|
3210
|
-
const length = data.length;
|
|
3211
|
-
const alloc = this.allocateAsFloat64(module, length);
|
|
3212
|
-
alloc.array.set(data);
|
|
3213
|
-
return alloc;
|
|
3214
|
-
}
|
|
3215
|
-
readReturnedFloat64Array(headerPtr) {
|
|
3216
|
-
const module = this.wasmModule;
|
|
3217
|
-
if (!module) throw new Error("WASM module not loaded");
|
|
3218
|
-
const hdr = headerPtr >>> 0;
|
|
3219
|
-
const dv = new DataView(module.memory.buffer);
|
|
3220
|
-
const dataStart = dv.getUint32(hdr + 4, true);
|
|
3221
|
-
const byteLength = dv.getUint32(hdr + 8, true);
|
|
3222
|
-
const view = new Float64Array(module.memory.buffer, dataStart, byteLength >>> 3);
|
|
3223
|
-
return new Float64Array(view);
|
|
3224
|
-
}
|
|
3225
|
-
allocateFloat64ArrayEmpty(length) {
|
|
3226
|
-
const module = this.wasmModule;
|
|
3227
|
-
if (!module) throw new Error("WASM module not loaded");
|
|
3228
|
-
const alloc = this.allocateAsFloat64(module, length);
|
|
3229
|
-
alloc.array.fill(0);
|
|
3230
|
-
return alloc;
|
|
3231
|
-
}
|
|
3232
|
-
allocateInt32Array(data) {
|
|
3233
|
-
const module = this.wasmModule;
|
|
3234
|
-
if (!module) throw new Error("WASM module not loaded");
|
|
3235
|
-
const length = data.length;
|
|
3236
|
-
const alloc = this.allocateAsInt32(module, length);
|
|
3237
|
-
alloc.array.set(data);
|
|
3238
|
-
return alloc;
|
|
3239
|
-
}
|
|
3240
|
-
allocateInt32ArrayEmpty(length) {
|
|
3241
|
-
const module = this.wasmModule;
|
|
3242
|
-
if (!module) throw new Error("WASM module not loaded");
|
|
3243
|
-
const alloc = this.allocateAsInt32(module, length);
|
|
3244
|
-
alloc.array.fill(0);
|
|
3245
|
-
return alloc;
|
|
3246
|
-
}
|
|
3247
|
-
allocateAsFloat64(module, length) {
|
|
3248
|
-
const byteLength = length * 8;
|
|
3249
|
-
if (byteLength <= this.poolSizeThreshold) {
|
|
3250
|
-
const recycled = this.acquireFromAsPool(module, this.float64Pool, byteLength);
|
|
3251
|
-
if (recycled) {
|
|
3252
|
-
const array = new Float64Array(module.memory.buffer, recycled.dataPtr, length);
|
|
3253
|
-
return {
|
|
3254
|
-
ptr: recycled.ptr,
|
|
3255
|
-
dataPtr: recycled.dataPtr,
|
|
3256
|
-
array,
|
|
3257
|
-
length
|
|
3258
|
-
};
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
return this.makeAsFloat64(module, length);
|
|
3262
|
-
}
|
|
3263
|
-
allocateAsInt32(module, length) {
|
|
3264
|
-
const byteLength = length * 4;
|
|
3265
|
-
if (byteLength <= this.poolSizeThreshold) {
|
|
3266
|
-
const recycled = this.acquireFromAsPool(module, this.int32Pool, byteLength);
|
|
3267
|
-
if (recycled) {
|
|
3268
|
-
const array = new Int32Array(module.memory.buffer, recycled.dataPtr, length);
|
|
3269
|
-
return {
|
|
3270
|
-
ptr: recycled.ptr,
|
|
3271
|
-
dataPtr: recycled.dataPtr,
|
|
3272
|
-
array,
|
|
3273
|
-
length
|
|
3274
|
-
};
|
|
3275
|
-
}
|
|
3276
|
-
}
|
|
3277
|
-
return this.makeAsInt32(module, length);
|
|
3278
|
-
}
|
|
3279
|
-
makeAsFloat64(module, length) {
|
|
3280
|
-
const byteLength = length * 8;
|
|
3281
|
-
const bufferPtr = module.__pin(module.__new(byteLength, AS_ID_ARRAY_BUFFER)) >>> 0;
|
|
3282
|
-
const headerPtr = module.__new(AS_HEADER_BYTES, AS_ID_FLOAT64_ARRAY) >>> 0;
|
|
3283
|
-
module.__pin(headerPtr);
|
|
3284
|
-
const dv = new DataView(module.memory.buffer);
|
|
3285
|
-
dv.setUint32(headerPtr + 0, bufferPtr, true);
|
|
3286
|
-
dv.setUint32(headerPtr + 4, bufferPtr, true);
|
|
3287
|
-
dv.setUint32(headerPtr + 8, byteLength, true);
|
|
3288
|
-
const array = new Float64Array(module.memory.buffer, bufferPtr, length);
|
|
3289
|
-
this.track(this.float64Pool, headerPtr, bufferPtr, byteLength);
|
|
3290
|
-
return {
|
|
3291
|
-
ptr: headerPtr,
|
|
3292
|
-
dataPtr: bufferPtr,
|
|
3293
|
-
array,
|
|
3294
|
-
length
|
|
3295
|
-
};
|
|
3296
|
-
}
|
|
3297
|
-
makeAsInt32(module, length) {
|
|
3298
|
-
const byteLength = length * 4;
|
|
3299
|
-
const bufferPtr = module.__pin(module.__new(byteLength, AS_ID_ARRAY_BUFFER)) >>> 0;
|
|
3300
|
-
const headerPtr = module.__new(AS_HEADER_BYTES, AS_ID_INT32_ARRAY) >>> 0;
|
|
3301
|
-
module.__pin(headerPtr);
|
|
3302
|
-
const dv = new DataView(module.memory.buffer);
|
|
3303
|
-
dv.setUint32(headerPtr + 0, bufferPtr, true);
|
|
3304
|
-
dv.setUint32(headerPtr + 4, bufferPtr, true);
|
|
3305
|
-
dv.setUint32(headerPtr + 8, byteLength, true);
|
|
3306
|
-
const array = new Int32Array(module.memory.buffer, bufferPtr, length);
|
|
3307
|
-
this.track(this.int32Pool, headerPtr, bufferPtr, byteLength);
|
|
3308
|
-
return {
|
|
3309
|
-
ptr: headerPtr,
|
|
3310
|
-
dataPtr: bufferPtr,
|
|
3311
|
-
array,
|
|
3312
|
-
length
|
|
3313
|
-
};
|
|
3314
|
-
}
|
|
3315
|
-
track(pool, ptr, dataPtr, size) {
|
|
3316
|
-
if (size <= this.poolSizeThreshold) pool.push({
|
|
3317
|
-
ptr,
|
|
3318
|
-
dataPtr,
|
|
3319
|
-
size,
|
|
3320
|
-
inUse: true
|
|
3321
|
-
});
|
|
3322
|
-
}
|
|
3323
|
-
acquireFromAsPool(module, pool, requestedSize) {
|
|
3324
|
-
let bestFit = null;
|
|
3325
|
-
let bestFitWaste = Infinity;
|
|
3326
|
-
for (const entry of pool) if (!entry.inUse && entry.size >= requestedSize) {
|
|
3327
|
-
const waste = entry.size - requestedSize;
|
|
3328
|
-
if (waste < bestFitWaste && entry.size <= requestedSize * 2) {
|
|
3329
|
-
bestFit = entry;
|
|
3330
|
-
bestFitWaste = waste;
|
|
3331
|
-
}
|
|
3332
|
-
}
|
|
3333
|
-
if (bestFit) {
|
|
3334
|
-
bestFit.inUse = true;
|
|
3335
|
-
new DataView(module.memory.buffer).setUint32(bestFit.ptr + 8, requestedSize, true);
|
|
3336
|
-
}
|
|
3337
|
-
return bestFit;
|
|
3338
|
-
}
|
|
3339
|
-
findEntry(ptr) {
|
|
3340
|
-
return this.float64Pool.find((e) => e.ptr === ptr) ?? this.int32Pool.find((e) => e.ptr === ptr);
|
|
3341
|
-
}
|
|
3342
|
-
unpinAllocation(module, ptr, dataPtr) {
|
|
3343
|
-
if (typeof module.__unpin !== "function") return;
|
|
3344
|
-
module.__unpin(ptr);
|
|
3345
|
-
if (dataPtr !== void 0) module.__unpin(dataPtr);
|
|
3346
|
-
}
|
|
3347
|
-
headerDataPtr(module, ptr) {
|
|
3348
|
-
return new DataView(module.memory.buffer).getUint32(ptr + 4, true);
|
|
3349
|
-
}
|
|
3350
|
-
release(ptr, isFloat64 = true) {
|
|
3351
|
-
const entry = this.findEntry(ptr);
|
|
3352
|
-
if (entry) {
|
|
3353
|
-
entry.inUse = false;
|
|
3354
|
-
return;
|
|
3355
|
-
}
|
|
3356
|
-
const module = this.wasmModule;
|
|
3357
|
-
if (!module) return;
|
|
3358
|
-
this.unpinAllocation(module, ptr, this.headerDataPtr(module, ptr));
|
|
3359
|
-
}
|
|
3360
|
-
free(ptr) {
|
|
3361
|
-
this.release(ptr);
|
|
3362
|
-
}
|
|
3363
|
-
clearPool() {
|
|
3364
|
-
const module = this.wasmModule;
|
|
3365
|
-
if (!module) return;
|
|
3366
|
-
for (const entry of [...this.float64Pool, ...this.int32Pool]) if (!entry.inUse) this.unpinAllocation(module, entry.ptr, entry.dataPtr);
|
|
3367
|
-
this.float64Pool = [];
|
|
3368
|
-
this.int32Pool = [];
|
|
3369
|
-
}
|
|
3370
|
-
getPoolStats() {
|
|
3371
|
-
const f64InUse = this.float64Pool.filter((e) => e.inUse).length;
|
|
3372
|
-
const f64Bytes = this.float64Pool.reduce((sum, e) => sum + e.size, 0);
|
|
3373
|
-
const i32InUse = this.int32Pool.filter((e) => e.inUse).length;
|
|
3374
|
-
const i32Bytes = this.int32Pool.reduce((sum, e) => sum + e.size, 0);
|
|
3375
|
-
return {
|
|
3376
|
-
float64: {
|
|
3377
|
-
total: this.float64Pool.length,
|
|
3378
|
-
inUse: f64InUse,
|
|
3379
|
-
totalBytes: f64Bytes
|
|
3380
|
-
},
|
|
3381
|
-
int32: {
|
|
3382
|
-
total: this.int32Pool.length,
|
|
3383
|
-
inUse: i32InUse,
|
|
3384
|
-
totalBytes: i32Bytes
|
|
3385
|
-
}
|
|
3386
|
-
};
|
|
3387
|
-
}
|
|
3388
|
-
collect() {
|
|
3389
|
-
const module = this.wasmModule;
|
|
3390
|
-
if (!module) return;
|
|
3391
|
-
if (typeof module.__collect === "function") module.__collect();
|
|
3392
|
-
}
|
|
3393
|
-
reset() {
|
|
3394
|
-
this.clearPool();
|
|
3395
|
-
this.wasmModule = null;
|
|
3396
|
-
this.compiledModule = null;
|
|
3397
|
-
this.loading = null;
|
|
3398
|
-
this.lastMetrics = null;
|
|
3399
|
-
}
|
|
3400
|
-
}).getInstance();
|
|
3401
|
-
//#endregion
|
|
3402
3064
|
//#region src/backends/gpu/BatchExecutor.ts
|
|
3403
3065
|
var BatchExecutor = class {
|
|
3404
3066
|
context;
|
|
@@ -3833,6 +3495,66 @@ function transpose$1(A) {
|
|
|
3833
3495
|
const n = A[0].length;
|
|
3834
3496
|
return Array.from({ length: n }, (_, j) => Array.from({ length: m }, (_, i) => A[i][j]));
|
|
3835
3497
|
}
|
|
3498
|
+
function matInv(A) {
|
|
3499
|
+
const n = A.length;
|
|
3500
|
+
return gaussJordanSolve(A, Array.from({ length: n }, (_, i) => {
|
|
3501
|
+
const row = new Array(n).fill(0);
|
|
3502
|
+
row[i] = 1;
|
|
3503
|
+
return row;
|
|
3504
|
+
}));
|
|
3505
|
+
}
|
|
3506
|
+
function gaussJordanSolve(a, rhs) {
|
|
3507
|
+
const n = a.length;
|
|
3508
|
+
if (n === 0) return [];
|
|
3509
|
+
const width = rhs[0]?.length ?? 0;
|
|
3510
|
+
const M = a.map((row, i) => {
|
|
3511
|
+
const r = new Array(n + width);
|
|
3512
|
+
for (let j = 0; j < n; j++) r[j] = row[j];
|
|
3513
|
+
const b = rhs[i] ?? [];
|
|
3514
|
+
for (let j = 0; j < width; j++) r[n + j] = b[j] ?? 0;
|
|
3515
|
+
return r;
|
|
3516
|
+
});
|
|
3517
|
+
for (let col = 0; col < n; col++) {
|
|
3518
|
+
let maxRow = col;
|
|
3519
|
+
let maxVal = Math.abs(M[col][col]);
|
|
3520
|
+
for (let row = col + 1; row < n; row++) if (Math.abs(M[row][col]) > maxVal) {
|
|
3521
|
+
maxVal = Math.abs(M[row][col]);
|
|
3522
|
+
maxRow = row;
|
|
3523
|
+
}
|
|
3524
|
+
if (maxRow !== col) [M[col], M[maxRow]] = [M[maxRow], M[col]];
|
|
3525
|
+
const pivot = M[col][col];
|
|
3526
|
+
if (Math.abs(pivot) < 1e-15) return null;
|
|
3527
|
+
for (let j = col; j < n + width; j++) M[col][j] /= pivot;
|
|
3528
|
+
for (let row = 0; row < n; row++) {
|
|
3529
|
+
if (row === col) continue;
|
|
3530
|
+
const f = M[row][col];
|
|
3531
|
+
if (f === 0) continue;
|
|
3532
|
+
for (let j = col; j < n + width; j++) M[row][j] -= f * M[col][j];
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
return M.map((row) => row.slice(n));
|
|
3536
|
+
}
|
|
3537
|
+
function gaussJordanContinue(aug, n, pivotTol) {
|
|
3538
|
+
const width = aug[0].length;
|
|
3539
|
+
for (let col = 0; col < n; col++) {
|
|
3540
|
+
let maxRow = col;
|
|
3541
|
+
let maxVal = Math.abs(aug[col][col]);
|
|
3542
|
+
for (let row = col + 1; row < n; row++) if (Math.abs(aug[row][col]) > maxVal) {
|
|
3543
|
+
maxVal = Math.abs(aug[row][col]);
|
|
3544
|
+
maxRow = row;
|
|
3545
|
+
}
|
|
3546
|
+
if (maxRow !== col) [aug[col], aug[maxRow]] = [aug[maxRow], aug[col]];
|
|
3547
|
+
const pivot = aug[col][col];
|
|
3548
|
+
if (Math.abs(pivot) < pivotTol) continue;
|
|
3549
|
+
for (let j = col; j < width; j++) aug[col][j] /= pivot;
|
|
3550
|
+
for (let row = 0; row < n; row++) {
|
|
3551
|
+
if (row === col) continue;
|
|
3552
|
+
const factor = aug[row][col];
|
|
3553
|
+
if (factor === 0) continue;
|
|
3554
|
+
for (let j = col; j < width; j++) aug[row][j] -= factor * aug[col][j];
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3836
3558
|
function isSymmetric(matrix, tolerance = 1e-10) {
|
|
3837
3559
|
const n = matrix.length;
|
|
3838
3560
|
if (n === 0) return true;
|
|
@@ -4385,6 +4107,38 @@ function powerIteration(matrix, options = {}) {
|
|
|
4385
4107
|
};
|
|
4386
4108
|
}
|
|
4387
4109
|
//#endregion
|
|
4110
|
+
//#region src/operations/givens.ts
|
|
4111
|
+
function givensRotation(a, b) {
|
|
4112
|
+
if (b === 0) return {
|
|
4113
|
+
c: 1,
|
|
4114
|
+
s: 0
|
|
4115
|
+
};
|
|
4116
|
+
if (Math.abs(b) > Math.abs(a)) {
|
|
4117
|
+
const t = -a / b;
|
|
4118
|
+
const s = 1 / Math.sqrt(1 + t * t);
|
|
4119
|
+
return {
|
|
4120
|
+
c: s * t,
|
|
4121
|
+
s
|
|
4122
|
+
};
|
|
4123
|
+
}
|
|
4124
|
+
const t = -b / a;
|
|
4125
|
+
const c = 1 / Math.sqrt(1 + t * t);
|
|
4126
|
+
return {
|
|
4127
|
+
c,
|
|
4128
|
+
s: c * t
|
|
4129
|
+
};
|
|
4130
|
+
}
|
|
4131
|
+
function applyGivensCols(A, c, s, i, k, rowStart, rowEnd) {
|
|
4132
|
+
for (let j = rowStart; j < rowEnd; j++) {
|
|
4133
|
+
const temp = c * A[j][i] - s * A[j][k];
|
|
4134
|
+
A[j][k] = s * A[j][i] + c * A[j][k];
|
|
4135
|
+
A[j][i] = temp;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
function applyGivensRight(A, c, s, i, k, startRow) {
|
|
4139
|
+
applyGivensCols(A, c, s, i, k, startRow, A.length);
|
|
4140
|
+
}
|
|
4141
|
+
//#endregion
|
|
4388
4142
|
//#region src/operations/svd.ts
|
|
4389
4143
|
const DEFAULT_MAX_ITERATIONS = 1e3;
|
|
4390
4144
|
const DEFAULT_TOLERANCE = 1e-12;
|
|
@@ -4422,34 +4176,6 @@ function bidiagonalize(A) {
|
|
|
4422
4176
|
V
|
|
4423
4177
|
};
|
|
4424
4178
|
}
|
|
4425
|
-
function givens(a, b) {
|
|
4426
|
-
if (b === 0) return {
|
|
4427
|
-
c: 1,
|
|
4428
|
-
s: 0
|
|
4429
|
-
};
|
|
4430
|
-
else if (Math.abs(b) > Math.abs(a)) {
|
|
4431
|
-
const t = -a / b;
|
|
4432
|
-
const s = 1 / Math.sqrt(1 + t * t);
|
|
4433
|
-
return {
|
|
4434
|
-
c: s * t,
|
|
4435
|
-
s
|
|
4436
|
-
};
|
|
4437
|
-
} else {
|
|
4438
|
-
const t = -b / a;
|
|
4439
|
-
const c = 1 / Math.sqrt(1 + t * t);
|
|
4440
|
-
return {
|
|
4441
|
-
c,
|
|
4442
|
-
s: c * t
|
|
4443
|
-
};
|
|
4444
|
-
}
|
|
4445
|
-
}
|
|
4446
|
-
function applyGivensCols(A, c, s, i, k, rowStart, rowEnd) {
|
|
4447
|
-
for (let j = rowStart; j < rowEnd; j++) {
|
|
4448
|
-
const temp = c * A[j][i] - s * A[j][k];
|
|
4449
|
-
A[j][k] = s * A[j][i] + c * A[j][k];
|
|
4450
|
-
A[j][i] = temp;
|
|
4451
|
-
}
|
|
4452
|
-
}
|
|
4453
4179
|
function svdStep(d, e, U, V, start, end) {
|
|
4454
4180
|
if (end - start + 1 < 2) return;
|
|
4455
4181
|
const dm1 = d[end - 1];
|
|
@@ -4467,14 +4193,14 @@ function svdStep(d, e, U, V, start, end) {
|
|
|
4467
4193
|
let f = d[start] * d[start] - shift;
|
|
4468
4194
|
let g = d[start] * e[start];
|
|
4469
4195
|
for (let k = start; k < end; k++) {
|
|
4470
|
-
const { c: cs, s: sn } =
|
|
4196
|
+
const { c: cs, s: sn } = givensRotation(f, g);
|
|
4471
4197
|
if (k > start) e[k - 1] = cs * f - sn * g;
|
|
4472
4198
|
f = cs * d[k] - sn * e[k];
|
|
4473
4199
|
e[k] = sn * d[k] + cs * e[k];
|
|
4474
4200
|
g = -sn * d[k + 1];
|
|
4475
4201
|
d[k + 1] = cs * d[k + 1];
|
|
4476
4202
|
applyGivensCols(V, cs, sn, k, k + 1, 0, V.length);
|
|
4477
|
-
const { c: cs2, s: sn2 } =
|
|
4203
|
+
const { c: cs2, s: sn2 } = givensRotation(f, g);
|
|
4478
4204
|
d[k] = cs2 * f - sn2 * g;
|
|
4479
4205
|
f = cs2 * e[k] - sn2 * d[k + 1];
|
|
4480
4206
|
d[k + 1] = sn2 * e[k] + cs2 * d[k + 1];
|
|
@@ -4489,7 +4215,7 @@ function svdStep(d, e, U, V, start, end) {
|
|
|
4489
4215
|
function handleZero(d, e, _U, V, zeroIdx, isDiagonal, _tolerance) {
|
|
4490
4216
|
const n = d.length;
|
|
4491
4217
|
if (isDiagonal) for (let k = zeroIdx; k < n - 1; k++) {
|
|
4492
|
-
const { c, s } =
|
|
4218
|
+
const { c, s } = givensRotation(d[k + 1], e[k]);
|
|
4493
4219
|
d[k + 1] = c * d[k + 1] - s * e[k];
|
|
4494
4220
|
e[k] = 0;
|
|
4495
4221
|
if (k < n - 2) {
|
|
@@ -5009,26 +4735,8 @@ const B = [
|
|
|
5009
4735
|
];
|
|
5010
4736
|
function matSolve(M, N) {
|
|
5011
4737
|
const n = M.length;
|
|
5012
|
-
const cols = N[0].length;
|
|
5013
4738
|
const Aug = M.map((row, i) => [...row, ...N[i]]);
|
|
5014
|
-
|
|
5015
|
-
let maxRow = col;
|
|
5016
|
-
let maxVal = Math.abs(Aug[col][col]);
|
|
5017
|
-
for (let row = col + 1; row < n; row++) if (Math.abs(Aug[row][col]) > maxVal) {
|
|
5018
|
-
maxVal = Math.abs(Aug[row][col]);
|
|
5019
|
-
maxRow = row;
|
|
5020
|
-
}
|
|
5021
|
-
if (maxRow !== col) [Aug[col], Aug[maxRow]] = [Aug[maxRow], Aug[col]];
|
|
5022
|
-
const pivot = Aug[col][col];
|
|
5023
|
-
if (Math.abs(pivot) < 1e-15) continue;
|
|
5024
|
-
for (let j = col; j < n + cols; j++) Aug[col][j] /= pivot;
|
|
5025
|
-
for (let row = 0; row < n; row++) {
|
|
5026
|
-
if (row === col) continue;
|
|
5027
|
-
const factor = Aug[row][col];
|
|
5028
|
-
if (factor === 0) continue;
|
|
5029
|
-
for (let j = col; j < n + cols; j++) Aug[row][j] -= factor * Aug[col][j];
|
|
5030
|
-
}
|
|
5031
|
-
}
|
|
4739
|
+
gaussJordanContinue(Aug, n, 1e-15);
|
|
5032
4740
|
return Aug.map((row) => row.slice(n));
|
|
5033
4741
|
}
|
|
5034
4742
|
function pade13(A) {
|
|
@@ -5090,26 +4798,6 @@ function hessenbergReduce(A) {
|
|
|
5090
4798
|
Q
|
|
5091
4799
|
};
|
|
5092
4800
|
}
|
|
5093
|
-
function givensParams(a, b) {
|
|
5094
|
-
if (b === 0) return {
|
|
5095
|
-
c: 1,
|
|
5096
|
-
s: 0
|
|
5097
|
-
};
|
|
5098
|
-
if (Math.abs(b) > Math.abs(a)) {
|
|
5099
|
-
const t = -a / b;
|
|
5100
|
-
const s = 1 / Math.sqrt(1 + t * t);
|
|
5101
|
-
return {
|
|
5102
|
-
c: s * t,
|
|
5103
|
-
s
|
|
5104
|
-
};
|
|
5105
|
-
}
|
|
5106
|
-
const t = -b / a;
|
|
5107
|
-
const c = 1 / Math.sqrt(1 + t * t);
|
|
5108
|
-
return {
|
|
5109
|
-
c,
|
|
5110
|
-
s: c * t
|
|
5111
|
-
};
|
|
5112
|
-
}
|
|
5113
4801
|
function applyGivensLeft(A, c, s, i, k, startCol) {
|
|
5114
4802
|
const n = A[0].length;
|
|
5115
4803
|
for (let j = startCol; j < n; j++) {
|
|
@@ -5118,14 +4806,6 @@ function applyGivensLeft(A, c, s, i, k, startCol) {
|
|
|
5118
4806
|
A[i][j] = temp;
|
|
5119
4807
|
}
|
|
5120
4808
|
}
|
|
5121
|
-
function applyGivensRight(A, c, s, i, k, startRow) {
|
|
5122
|
-
const m = A.length;
|
|
5123
|
-
for (let j = startRow; j < m; j++) {
|
|
5124
|
-
const temp = c * A[j][i] - s * A[j][k];
|
|
5125
|
-
A[j][k] = s * A[j][i] + c * A[j][k];
|
|
5126
|
-
A[j][i] = temp;
|
|
5127
|
-
}
|
|
5128
|
-
}
|
|
5129
4809
|
function qrStepSingle(H, Q, start, end) {
|
|
5130
4810
|
const a = H[end - 1][end - 1];
|
|
5131
4811
|
const b = H[end - 1][end];
|
|
@@ -5141,18 +4821,7 @@ function qrStepSingle(H, Q, start, end) {
|
|
|
5141
4821
|
const e2 = (trace - sqrtDisc) / 2;
|
|
5142
4822
|
shift = Math.abs(e1 - d) < Math.abs(e2 - d) ? e1 : e2;
|
|
5143
4823
|
} else shift = d;
|
|
5144
|
-
|
|
5145
|
-
let y = H[start + 1][start];
|
|
5146
|
-
for (let k = start; k < end; k++) {
|
|
5147
|
-
const { c: gc, s: gs } = givensParams(x, y);
|
|
5148
|
-
applyGivensLeft(H, gc, gs, k, k + 1, Math.max(0, k - 1));
|
|
5149
|
-
applyGivensRight(H, gc, gs, k, k + 1, 0);
|
|
5150
|
-
applyGivensRight(Q, gc, gs, k, k + 1, 0);
|
|
5151
|
-
if (k < end - 1) {
|
|
5152
|
-
x = H[k + 1][k];
|
|
5153
|
-
y = H[k + 2][k];
|
|
5154
|
-
}
|
|
5155
|
-
}
|
|
4824
|
+
qrStepSingleShift(H, Q, start, end, shift);
|
|
5156
4825
|
}
|
|
5157
4826
|
function qrStepDouble(H, Q, start, end) {
|
|
5158
4827
|
const n = H.length;
|
|
@@ -5198,7 +4867,7 @@ function qrStepDouble(H, Q, start, end) {
|
|
|
5198
4867
|
y = H[k + 2][k];
|
|
5199
4868
|
if (k < end - 2) z = H[k + 3][k];
|
|
5200
4869
|
}
|
|
5201
|
-
const { c: gc, s: gs } =
|
|
4870
|
+
const { c: gc, s: gs } = givensRotation(x, y);
|
|
5202
4871
|
applyGivensLeft(H, gc, gs, end - 1, end, end - 2);
|
|
5203
4872
|
applyGivensRight(H, gc, gs, end - 1, end, 0);
|
|
5204
4873
|
applyGivensRight(Q, gc, gs, end - 1, end, 0);
|
|
@@ -5207,7 +4876,7 @@ function qrStepSingleShift(H, Q, start, end, shift) {
|
|
|
5207
4876
|
let x = H[start][start] - shift;
|
|
5208
4877
|
let y = H[start + 1][start];
|
|
5209
4878
|
for (let k = start; k < end; k++) {
|
|
5210
|
-
const { c: gc, s: gs } =
|
|
4879
|
+
const { c: gc, s: gs } = givensRotation(x, y);
|
|
5211
4880
|
applyGivensLeft(H, gc, gs, k, k + 1, Math.max(0, k - 1));
|
|
5212
4881
|
applyGivensRight(H, gc, gs, k, k + 1, 0);
|
|
5213
4882
|
applyGivensRight(Q, gc, gs, k, k + 1, 0);
|
|
@@ -5317,51 +4986,210 @@ function schurInternal(A, maxIterations = 1e3, tolerance = 1e-12) {
|
|
|
5317
4986
|
return schurRaw(A, maxIterations, tolerance);
|
|
5318
4987
|
}
|
|
5319
4988
|
//#endregion
|
|
5320
|
-
//#region src/operations/
|
|
4989
|
+
//#region src/operations/sqrtm.ts
|
|
5321
4990
|
init_DenseMatrix();
|
|
5322
|
-
function
|
|
4991
|
+
function symmetrize(A) {
|
|
5323
4992
|
const n = A.length;
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
});
|
|
5330
|
-
for (let
|
|
5331
|
-
|
|
5332
|
-
let
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
}
|
|
5337
|
-
if (maxRow !== col) [M[col], M[maxRow]] = [M[maxRow], M[col]];
|
|
5338
|
-
const pivot = M[col][col];
|
|
5339
|
-
if (Math.abs(pivot) < 1e-15) return null;
|
|
5340
|
-
for (let j = 0; j < 2 * n; j++) M[col][j] /= pivot;
|
|
5341
|
-
for (let row = 0; row < n; row++) {
|
|
5342
|
-
if (row === col) continue;
|
|
5343
|
-
const f = M[row][col];
|
|
5344
|
-
if (f === 0) continue;
|
|
5345
|
-
for (let j = 0; j < 2 * n; j++) M[row][j] -= f * M[col][j];
|
|
4993
|
+
return Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => (A[i][j] + A[j][i]) / 2));
|
|
4994
|
+
}
|
|
4995
|
+
function gramSchmidt(A) {
|
|
4996
|
+
const m = A.length;
|
|
4997
|
+
const n = A[0].length;
|
|
4998
|
+
const Q = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
4999
|
+
for (let j = 0; j < n; j++) {
|
|
5000
|
+
const v = A.map((row) => row[j]);
|
|
5001
|
+
for (let k = 0; k < j; k++) {
|
|
5002
|
+
let dot = 0;
|
|
5003
|
+
for (let i = 0; i < m; i++) dot += Q[i][k] * v[i];
|
|
5004
|
+
for (let i = 0; i < m; i++) v[i] -= dot * Q[i][k];
|
|
5346
5005
|
}
|
|
5006
|
+
let norm = 0;
|
|
5007
|
+
for (let i = 0; i < m; i++) norm += v[i] * v[i];
|
|
5008
|
+
norm = Math.sqrt(norm);
|
|
5009
|
+
if (norm < 1e-14) for (let i = 0; i < m; i++) Q[i][j] = i === j ? 1 : 0;
|
|
5010
|
+
else for (let i = 0; i < m; i++) Q[i][j] = v[i] / norm;
|
|
5347
5011
|
}
|
|
5348
|
-
return
|
|
5012
|
+
return Q;
|
|
5349
5013
|
}
|
|
5350
|
-
function
|
|
5014
|
+
function sqrtmSymmetric(A) {
|
|
5015
|
+
const n = A.length;
|
|
5016
|
+
const Asym = symmetrize(A);
|
|
5017
|
+
const { values, vectors } = eig(Asym, { computeVectors: true });
|
|
5018
|
+
for (const v of values) if (v.re < -1e-8) throw new Error(`matrixSqrtm: negative eigenvalue (${v.re}) — matrix is not positive semi-definite`);
|
|
5019
|
+
const Ynewton = sqrtmNewton(Asym);
|
|
5020
|
+
if (Ynewton !== null) return Ynewton;
|
|
5021
|
+
const Q = gramSchmidt(transpose$1(vectors));
|
|
5022
|
+
const Qt = transpose$1(Q);
|
|
5023
|
+
const Dsqrt = eye(n);
|
|
5024
|
+
for (let i = 0; i < n; i++) Dsqrt[i][i] = Math.sqrt(Math.max(values[i].re, 0));
|
|
5025
|
+
return matMul(matMul(Q, Dsqrt), Qt);
|
|
5026
|
+
}
|
|
5027
|
+
function newtonSqrtUpdate(A, Y) {
|
|
5028
|
+
const n = A.length;
|
|
5029
|
+
const Yinv = matInv(Y);
|
|
5030
|
+
if (Yinv === null) return null;
|
|
5031
|
+
const AYinv = matMul(A, Yinv);
|
|
5032
|
+
const next = Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => (Y[i][j] + AYinv[i][j]) / 2));
|
|
5033
|
+
let diff = 0;
|
|
5034
|
+
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) diff = Math.max(diff, Math.abs(next[i][j] - Y[i][j]));
|
|
5035
|
+
return {
|
|
5036
|
+
next,
|
|
5037
|
+
diff
|
|
5038
|
+
};
|
|
5039
|
+
}
|
|
5040
|
+
function sqrtmNewton(A) {
|
|
5351
5041
|
const n = A.length;
|
|
5352
5042
|
let Y = eye(n);
|
|
5353
5043
|
for (let iter = 0; iter < 150; iter++) {
|
|
5354
|
-
const
|
|
5355
|
-
if (
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5044
|
+
const step = newtonSqrtUpdate(A, Y);
|
|
5045
|
+
if (step === null) return null;
|
|
5046
|
+
Y = step.next;
|
|
5047
|
+
if (step.diff < 1e-13) return Y;
|
|
5048
|
+
}
|
|
5049
|
+
const Y2 = matMul(Y, Y);
|
|
5050
|
+
let err = 0;
|
|
5051
|
+
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) err = Math.max(err, Math.abs(Y2[i][j] - A[i][j]));
|
|
5052
|
+
return err < 1e-6 ? Y : null;
|
|
5053
|
+
}
|
|
5054
|
+
function sqrtmGeneral(A) {
|
|
5055
|
+
const n = A.length;
|
|
5056
|
+
const { values, vectors } = eig(A, { computeVectors: true });
|
|
5057
|
+
for (const v of values) {
|
|
5058
|
+
if (Math.abs(v.im) > 1e-7) throw new Error("matrixSqrtm: complex eigenvalues detected — real square root not supported");
|
|
5059
|
+
if (v.re < -1e-7) throw new Error(`matrixSqrtm: negative eigenvalue (${v.re}) — principal square root not real`);
|
|
5060
|
+
}
|
|
5061
|
+
const Ynewton = sqrtmNewton(A);
|
|
5062
|
+
if (Ynewton !== null) return Ynewton;
|
|
5063
|
+
const Q = transpose$1(vectors);
|
|
5064
|
+
const Qinv = matInv(Q);
|
|
5065
|
+
if (Qinv === null) throw new Error("matrixSqrtm: eigenvector matrix is singular — matrix appears to be non-diagonalisable");
|
|
5066
|
+
const Dsqrt = eye(n);
|
|
5067
|
+
for (let i = 0; i < n; i++) Dsqrt[i][i] = Math.sqrt(Math.max(values[i].re, 0));
|
|
5068
|
+
return matMul(matMul(Q, Dsqrt), Qinv);
|
|
5069
|
+
}
|
|
5070
|
+
function sqrtmQuasiTriangular(T) {
|
|
5071
|
+
const n = T.length;
|
|
5072
|
+
const U = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
5073
|
+
const blockStart = [];
|
|
5074
|
+
const blockSize = [];
|
|
5075
|
+
let i = 0;
|
|
5076
|
+
while (i < n) if (i === n - 1 || Math.abs(T[i + 1][i]) < 1e-12) {
|
|
5077
|
+
blockStart.push(i);
|
|
5078
|
+
blockSize.push(1);
|
|
5079
|
+
i++;
|
|
5080
|
+
} else {
|
|
5081
|
+
blockStart.push(i);
|
|
5082
|
+
blockSize.push(2);
|
|
5083
|
+
i += 2;
|
|
5084
|
+
}
|
|
5085
|
+
const numBlocks = blockStart.length;
|
|
5086
|
+
for (let b = 0; b < numBlocks; b++) {
|
|
5087
|
+
const r = blockStart[b];
|
|
5088
|
+
if (blockSize[b] === 1) {
|
|
5089
|
+
if (T[r][r] < 0) return null;
|
|
5090
|
+
U[r][r] = Math.sqrt(T[r][r]);
|
|
5091
|
+
} else {
|
|
5092
|
+
const a = T[r][r];
|
|
5093
|
+
const b2 = T[r][r + 1];
|
|
5094
|
+
const c = T[r + 1][r];
|
|
5095
|
+
const d = T[r + 1][r + 1];
|
|
5096
|
+
const detM = a * d - b2 * c;
|
|
5097
|
+
const trM = a + d;
|
|
5098
|
+
if (detM < 0) return null;
|
|
5099
|
+
const sqrtDet = Math.sqrt(detM);
|
|
5100
|
+
const tauSq = trM + 2 * sqrtDet;
|
|
5101
|
+
if (tauSq < 0) return null;
|
|
5102
|
+
const tau = Math.sqrt(tauSq);
|
|
5103
|
+
if (Math.abs(tau) < 1e-14) return null;
|
|
5104
|
+
U[r][r] = (a + sqrtDet) / tau;
|
|
5105
|
+
U[r][r + 1] = b2 / tau;
|
|
5106
|
+
U[r + 1][r] = c / tau;
|
|
5107
|
+
U[r + 1][r + 1] = (d + sqrtDet) / tau;
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5110
|
+
for (let bj = 1; bj < numBlocks; bj++) for (let bi = bj - 1; bi >= 0; bi--) {
|
|
5111
|
+
const ri = blockStart[bi];
|
|
5112
|
+
const rj = blockStart[bj];
|
|
5113
|
+
const si = blockSize[bi];
|
|
5114
|
+
const sj = blockSize[bj];
|
|
5115
|
+
const RHS = Array.from({ length: si }, (_, ii) => Array.from({ length: sj }, (_, jj) => T[ri + ii][rj + jj]));
|
|
5116
|
+
for (let bk = bi + 1; bk < bj; bk++) {
|
|
5117
|
+
const rk = blockStart[bk];
|
|
5118
|
+
const sk = blockSize[bk];
|
|
5119
|
+
for (let ii = 0; ii < si; ii++) for (let jj = 0; jj < sj; jj++) {
|
|
5120
|
+
let sum = 0;
|
|
5121
|
+
for (let kk = 0; kk < sk; kk++) sum += U[ri + ii][rk + kk] * U[rk + kk][rj + jj];
|
|
5122
|
+
RHS[ii][jj] -= sum;
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
const total = si * sj;
|
|
5126
|
+
const MAT = Array.from({ length: total }, () => new Array(total).fill(0));
|
|
5127
|
+
const rhs = new Array(total).fill(0);
|
|
5128
|
+
for (let ii = 0; ii < si; ii++) for (let jj = 0; jj < sj; jj++) {
|
|
5129
|
+
const eq = ii * sj + jj;
|
|
5130
|
+
for (let kk = 0; kk < si; kk++) MAT[eq][kk * sj + jj] += U[ri + ii][ri + kk];
|
|
5131
|
+
for (let kk = 0; kk < sj; kk++) MAT[eq][ii * sj + kk] += U[rj + kk][rj + jj];
|
|
5132
|
+
rhs[eq] = RHS[ii][jj];
|
|
5133
|
+
}
|
|
5134
|
+
const sol = solveLinearSystem(MAT, rhs);
|
|
5135
|
+
if (sol === null) return null;
|
|
5136
|
+
for (let ii = 0; ii < si; ii++) for (let jj = 0; jj < sj; jj++) U[ri + ii][rj + jj] = sol[ii * sj + jj];
|
|
5137
|
+
}
|
|
5138
|
+
return U;
|
|
5139
|
+
}
|
|
5140
|
+
function solveLinearSystem(A, b) {
|
|
5141
|
+
const solved = gaussJordanSolve(A, b.map((value) => [value]));
|
|
5142
|
+
if (solved === null) return null;
|
|
5143
|
+
return solved.map((row) => row[0]);
|
|
5144
|
+
}
|
|
5145
|
+
function sqrtmSchur(A) {
|
|
5146
|
+
const { H: T, Q } = schurInternal(A);
|
|
5147
|
+
const U = sqrtmQuasiTriangular(T);
|
|
5148
|
+
if (U === null) return null;
|
|
5149
|
+
const Qt = transpose$1(Q);
|
|
5150
|
+
return matMul(matMul(Q, U), Qt);
|
|
5151
|
+
}
|
|
5152
|
+
function matrixSqrtm(A, opts) {
|
|
5153
|
+
const n = A.rows;
|
|
5154
|
+
if (n !== A.cols) throw new Error(`matrixSqrtm: matrix must be square (got ${A.rows}×${A.cols})`);
|
|
5155
|
+
if (n === 0) return DenseMatrix.zeros(0, 0);
|
|
5156
|
+
if (n === 1) {
|
|
5157
|
+
const val = A.get(0, 0);
|
|
5158
|
+
if (val < 0) throw new Error(`matrixSqrtm: negative scalar (${val}) has no real square root`);
|
|
5159
|
+
return DenseMatrix.fromArray([[Math.sqrt(val)]]);
|
|
5160
|
+
}
|
|
5161
|
+
const Aarr = A.toArray();
|
|
5162
|
+
const isSymm = (opts?.assumeSymmetric ?? false) || isSymmetricMatrix(Aarr);
|
|
5163
|
+
let result;
|
|
5164
|
+
if (isSymm) result = sqrtmSymmetric(Aarr);
|
|
5165
|
+
else {
|
|
5166
|
+
const schurResult = sqrtmSchur(Aarr);
|
|
5167
|
+
if (schurResult !== null) result = schurResult;
|
|
5168
|
+
else result = sqrtmGeneral(Aarr);
|
|
5169
|
+
}
|
|
5170
|
+
const data = new Float64Array(n * n);
|
|
5171
|
+
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) data[i * n + j] = result[i][j];
|
|
5172
|
+
return new DenseMatrix(n, n, data);
|
|
5173
|
+
}
|
|
5174
|
+
function isSymmetricMatrix(A, tol = 1e-8) {
|
|
5175
|
+
const n = A.length;
|
|
5176
|
+
for (let i = 0; i < n; i++) for (let j = i + 1; j < n; j++) if (Math.abs(A[i][j] - A[j][i]) > tol) return false;
|
|
5177
|
+
return true;
|
|
5178
|
+
}
|
|
5179
|
+
function matrixSqrtNewtonInternal(A) {
|
|
5180
|
+
const n = A.length;
|
|
5181
|
+
let Y = eye(n);
|
|
5182
|
+
for (let iter = 0; iter < 150; iter++) {
|
|
5183
|
+
const step = newtonSqrtUpdate(A, Y);
|
|
5184
|
+
if (step === null) break;
|
|
5185
|
+
Y = step.next;
|
|
5186
|
+
if (step.diff < 1e-14) break;
|
|
5362
5187
|
}
|
|
5363
5188
|
return Y;
|
|
5364
5189
|
}
|
|
5190
|
+
//#endregion
|
|
5191
|
+
//#region src/operations/logm.ts
|
|
5192
|
+
init_DenseMatrix();
|
|
5365
5193
|
const GL16_NODES = [
|
|
5366
5194
|
.00529953674226076,
|
|
5367
5195
|
.02771248846338012,
|
|
@@ -5401,24 +5229,7 @@ const GL16_WEIGHTS = [
|
|
|
5401
5229
|
function solveCol(M, b) {
|
|
5402
5230
|
const n = M.length;
|
|
5403
5231
|
const Aug = M.map((row, i) => [...row, b[i]]);
|
|
5404
|
-
|
|
5405
|
-
let maxRow = col;
|
|
5406
|
-
let maxVal = Math.abs(Aug[col][col]);
|
|
5407
|
-
for (let row = col + 1; row < n; row++) if (Math.abs(Aug[row][col]) > maxVal) {
|
|
5408
|
-
maxVal = Math.abs(Aug[row][col]);
|
|
5409
|
-
maxRow = row;
|
|
5410
|
-
}
|
|
5411
|
-
if (maxRow !== col) [Aug[col], Aug[maxRow]] = [Aug[maxRow], Aug[col]];
|
|
5412
|
-
const pivot = Aug[col][col];
|
|
5413
|
-
if (Math.abs(pivot) < 1e-30) continue;
|
|
5414
|
-
for (let j = col; j <= n; j++) Aug[col][j] /= pivot;
|
|
5415
|
-
for (let row = 0; row < n; row++) {
|
|
5416
|
-
if (row === col) continue;
|
|
5417
|
-
const f = Aug[row][col];
|
|
5418
|
-
if (f === 0) continue;
|
|
5419
|
-
for (let j = col; j <= n; j++) Aug[row][j] -= f * Aug[col][j];
|
|
5420
|
-
}
|
|
5421
|
-
}
|
|
5232
|
+
gaussJordanContinue(Aug, n, 1e-30);
|
|
5422
5233
|
return Aug.map((row) => row[n]);
|
|
5423
5234
|
}
|
|
5424
5235
|
function logPade(X) {
|
|
@@ -5496,7 +5307,7 @@ function logmEig(A) {
|
|
|
5496
5307
|
if (v.re <= 0) throw new Error("matrixLogm: non-positive eigenvalue detected — principal logarithm is undefined (eigenvalue = " + v.re + ")");
|
|
5497
5308
|
}
|
|
5498
5309
|
const Q = transpose$1(vectors);
|
|
5499
|
-
const Qinv = matInv
|
|
5310
|
+
const Qinv = matInv(Q);
|
|
5500
5311
|
if (Qinv === null) throw new Error("matrixLogm: eigenvector matrix is singular — matrix appears to be non-diagonalisable (Slice 5.9a limitation; full Schur-based implementation deferred to Slice 5.9b)");
|
|
5501
5312
|
const D = eye(n);
|
|
5502
5313
|
for (let i = 0; i < n; i++) D[i][i] = Math.log(values[i].re);
|
|
@@ -5520,7 +5331,7 @@ function matrixLogm(A, opts) {
|
|
|
5520
5331
|
const maxSqrt = 64;
|
|
5521
5332
|
while (numSqrt < maxSqrt) {
|
|
5522
5333
|
if (norm1(M.map((row, i) => row.map((v, j) => v - (i === j ? 1 : 0)))) < tol) break;
|
|
5523
|
-
const sqrtM =
|
|
5334
|
+
const sqrtM = matrixSqrtNewtonInternal(M);
|
|
5524
5335
|
if (!isFinite(normInf(sqrtM))) break;
|
|
5525
5336
|
M = sqrtM;
|
|
5526
5337
|
numSqrt++;
|
|
@@ -5538,234 +5349,6 @@ function matrixLogm(A, opts) {
|
|
|
5538
5349
|
return new DenseMatrix(n, n, data);
|
|
5539
5350
|
}
|
|
5540
5351
|
//#endregion
|
|
5541
|
-
//#region src/operations/sqrtm.ts
|
|
5542
|
-
init_DenseMatrix();
|
|
5543
|
-
function symmetrize(A) {
|
|
5544
|
-
const n = A.length;
|
|
5545
|
-
return Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => (A[i][j] + A[j][i]) / 2));
|
|
5546
|
-
}
|
|
5547
|
-
function matInv(A) {
|
|
5548
|
-
const n = A.length;
|
|
5549
|
-
const M = A.map((row, i) => {
|
|
5550
|
-
const r = new Array(2 * n).fill(0);
|
|
5551
|
-
for (let j = 0; j < n; j++) r[j] = row[j];
|
|
5552
|
-
r[n + i] = 1;
|
|
5553
|
-
return r;
|
|
5554
|
-
});
|
|
5555
|
-
for (let col = 0; col < n; col++) {
|
|
5556
|
-
let maxRow = col;
|
|
5557
|
-
let maxVal = Math.abs(M[col][col]);
|
|
5558
|
-
for (let row = col + 1; row < n; row++) if (Math.abs(M[row][col]) > maxVal) {
|
|
5559
|
-
maxVal = Math.abs(M[row][col]);
|
|
5560
|
-
maxRow = row;
|
|
5561
|
-
}
|
|
5562
|
-
if (maxRow !== col) [M[col], M[maxRow]] = [M[maxRow], M[col]];
|
|
5563
|
-
const pivot = M[col][col];
|
|
5564
|
-
if (Math.abs(pivot) < 1e-15) return null;
|
|
5565
|
-
for (let j = 0; j < 2 * n; j++) M[col][j] /= pivot;
|
|
5566
|
-
for (let row = 0; row < n; row++) {
|
|
5567
|
-
if (row === col) continue;
|
|
5568
|
-
const f = M[row][col];
|
|
5569
|
-
if (f === 0) continue;
|
|
5570
|
-
for (let j = 0; j < 2 * n; j++) M[row][j] -= f * M[col][j];
|
|
5571
|
-
}
|
|
5572
|
-
}
|
|
5573
|
-
return M.map((row) => row.slice(n));
|
|
5574
|
-
}
|
|
5575
|
-
function gramSchmidt(A) {
|
|
5576
|
-
const m = A.length;
|
|
5577
|
-
const n = A[0].length;
|
|
5578
|
-
const Q = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
5579
|
-
for (let j = 0; j < n; j++) {
|
|
5580
|
-
const v = A.map((row) => row[j]);
|
|
5581
|
-
for (let k = 0; k < j; k++) {
|
|
5582
|
-
let dot = 0;
|
|
5583
|
-
for (let i = 0; i < m; i++) dot += Q[i][k] * v[i];
|
|
5584
|
-
for (let i = 0; i < m; i++) v[i] -= dot * Q[i][k];
|
|
5585
|
-
}
|
|
5586
|
-
let norm = 0;
|
|
5587
|
-
for (let i = 0; i < m; i++) norm += v[i] * v[i];
|
|
5588
|
-
norm = Math.sqrt(norm);
|
|
5589
|
-
if (norm < 1e-14) for (let i = 0; i < m; i++) Q[i][j] = i === j ? 1 : 0;
|
|
5590
|
-
else for (let i = 0; i < m; i++) Q[i][j] = v[i] / norm;
|
|
5591
|
-
}
|
|
5592
|
-
return Q;
|
|
5593
|
-
}
|
|
5594
|
-
function sqrtmSymmetric(A) {
|
|
5595
|
-
const n = A.length;
|
|
5596
|
-
const Asym = symmetrize(A);
|
|
5597
|
-
const { values, vectors } = eig(Asym, { computeVectors: true });
|
|
5598
|
-
for (const v of values) if (v.re < -1e-8) throw new Error(`matrixSqrtm: negative eigenvalue (${v.re}) — matrix is not positive semi-definite`);
|
|
5599
|
-
const Ynewton = sqrtmNewton(Asym);
|
|
5600
|
-
if (Ynewton !== null) return Ynewton;
|
|
5601
|
-
const Q = gramSchmidt(transpose$1(vectors));
|
|
5602
|
-
const Qt = transpose$1(Q);
|
|
5603
|
-
const Dsqrt = eye(n);
|
|
5604
|
-
for (let i = 0; i < n; i++) Dsqrt[i][i] = Math.sqrt(Math.max(values[i].re, 0));
|
|
5605
|
-
return matMul(matMul(Q, Dsqrt), Qt);
|
|
5606
|
-
}
|
|
5607
|
-
function sqrtmNewton(A) {
|
|
5608
|
-
const n = A.length;
|
|
5609
|
-
let Y = eye(n);
|
|
5610
|
-
for (let iter = 0; iter < 150; iter++) {
|
|
5611
|
-
const Yinv = matInv(Y);
|
|
5612
|
-
if (Yinv === null) return null;
|
|
5613
|
-
const AYinv = matMul(A, Yinv);
|
|
5614
|
-
const Ynew = Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => (Y[i][j] + AYinv[i][j]) / 2));
|
|
5615
|
-
let diff = 0;
|
|
5616
|
-
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) diff = Math.max(diff, Math.abs(Ynew[i][j] - Y[i][j]));
|
|
5617
|
-
Y = Ynew;
|
|
5618
|
-
if (diff < 1e-13) return Y;
|
|
5619
|
-
}
|
|
5620
|
-
const Y2 = matMul(Y, Y);
|
|
5621
|
-
let err = 0;
|
|
5622
|
-
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) err = Math.max(err, Math.abs(Y2[i][j] - A[i][j]));
|
|
5623
|
-
return err < 1e-6 ? Y : null;
|
|
5624
|
-
}
|
|
5625
|
-
function sqrtmGeneral(A) {
|
|
5626
|
-
const n = A.length;
|
|
5627
|
-
const { values, vectors } = eig(A, { computeVectors: true });
|
|
5628
|
-
for (const v of values) {
|
|
5629
|
-
if (Math.abs(v.im) > 1e-7) throw new Error("matrixSqrtm: complex eigenvalues detected — real square root not supported");
|
|
5630
|
-
if (v.re < -1e-7) throw new Error(`matrixSqrtm: negative eigenvalue (${v.re}) — principal square root not real`);
|
|
5631
|
-
}
|
|
5632
|
-
const Ynewton = sqrtmNewton(A);
|
|
5633
|
-
if (Ynewton !== null) return Ynewton;
|
|
5634
|
-
const Q = transpose$1(vectors);
|
|
5635
|
-
const Qinv = matInv(Q);
|
|
5636
|
-
if (Qinv === null) throw new Error("matrixSqrtm: eigenvector matrix is singular — matrix appears to be non-diagonalisable");
|
|
5637
|
-
const Dsqrt = eye(n);
|
|
5638
|
-
for (let i = 0; i < n; i++) Dsqrt[i][i] = Math.sqrt(Math.max(values[i].re, 0));
|
|
5639
|
-
return matMul(matMul(Q, Dsqrt), Qinv);
|
|
5640
|
-
}
|
|
5641
|
-
function sqrtmQuasiTriangular(T) {
|
|
5642
|
-
const n = T.length;
|
|
5643
|
-
const U = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
5644
|
-
const blockStart = [];
|
|
5645
|
-
const blockSize = [];
|
|
5646
|
-
let i = 0;
|
|
5647
|
-
while (i < n) if (i === n - 1 || Math.abs(T[i + 1][i]) < 1e-12) {
|
|
5648
|
-
blockStart.push(i);
|
|
5649
|
-
blockSize.push(1);
|
|
5650
|
-
i++;
|
|
5651
|
-
} else {
|
|
5652
|
-
blockStart.push(i);
|
|
5653
|
-
blockSize.push(2);
|
|
5654
|
-
i += 2;
|
|
5655
|
-
}
|
|
5656
|
-
const numBlocks = blockStart.length;
|
|
5657
|
-
for (let b = 0; b < numBlocks; b++) {
|
|
5658
|
-
const r = blockStart[b];
|
|
5659
|
-
if (blockSize[b] === 1) {
|
|
5660
|
-
if (T[r][r] < 0) return null;
|
|
5661
|
-
U[r][r] = Math.sqrt(T[r][r]);
|
|
5662
|
-
} else {
|
|
5663
|
-
const a = T[r][r];
|
|
5664
|
-
const b2 = T[r][r + 1];
|
|
5665
|
-
const c = T[r + 1][r];
|
|
5666
|
-
const d = T[r + 1][r + 1];
|
|
5667
|
-
const detM = a * d - b2 * c;
|
|
5668
|
-
const trM = a + d;
|
|
5669
|
-
if (detM < 0) return null;
|
|
5670
|
-
const sqrtDet = Math.sqrt(detM);
|
|
5671
|
-
const tauSq = trM + 2 * sqrtDet;
|
|
5672
|
-
if (tauSq < 0) return null;
|
|
5673
|
-
const tau = Math.sqrt(tauSq);
|
|
5674
|
-
if (Math.abs(tau) < 1e-14) return null;
|
|
5675
|
-
U[r][r] = (a + sqrtDet) / tau;
|
|
5676
|
-
U[r][r + 1] = b2 / tau;
|
|
5677
|
-
U[r + 1][r] = c / tau;
|
|
5678
|
-
U[r + 1][r + 1] = (d + sqrtDet) / tau;
|
|
5679
|
-
}
|
|
5680
|
-
}
|
|
5681
|
-
for (let bj = 1; bj < numBlocks; bj++) for (let bi = bj - 1; bi >= 0; bi--) {
|
|
5682
|
-
const ri = blockStart[bi];
|
|
5683
|
-
const rj = blockStart[bj];
|
|
5684
|
-
const si = blockSize[bi];
|
|
5685
|
-
const sj = blockSize[bj];
|
|
5686
|
-
const RHS = Array.from({ length: si }, (_, ii) => Array.from({ length: sj }, (_, jj) => T[ri + ii][rj + jj]));
|
|
5687
|
-
for (let bk = bi + 1; bk < bj; bk++) {
|
|
5688
|
-
const rk = blockStart[bk];
|
|
5689
|
-
const sk = blockSize[bk];
|
|
5690
|
-
for (let ii = 0; ii < si; ii++) for (let jj = 0; jj < sj; jj++) {
|
|
5691
|
-
let sum = 0;
|
|
5692
|
-
for (let kk = 0; kk < sk; kk++) sum += U[ri + ii][rk + kk] * U[rk + kk][rj + jj];
|
|
5693
|
-
RHS[ii][jj] -= sum;
|
|
5694
|
-
}
|
|
5695
|
-
}
|
|
5696
|
-
const total = si * sj;
|
|
5697
|
-
const MAT = Array.from({ length: total }, () => new Array(total).fill(0));
|
|
5698
|
-
const rhs = new Array(total).fill(0);
|
|
5699
|
-
for (let ii = 0; ii < si; ii++) for (let jj = 0; jj < sj; jj++) {
|
|
5700
|
-
const eq = ii * sj + jj;
|
|
5701
|
-
for (let kk = 0; kk < si; kk++) MAT[eq][kk * sj + jj] += U[ri + ii][ri + kk];
|
|
5702
|
-
for (let kk = 0; kk < sj; kk++) MAT[eq][ii * sj + kk] += U[rj + kk][rj + jj];
|
|
5703
|
-
rhs[eq] = RHS[ii][jj];
|
|
5704
|
-
}
|
|
5705
|
-
const sol = solveLinearSystem(MAT, rhs);
|
|
5706
|
-
if (sol === null) return null;
|
|
5707
|
-
for (let ii = 0; ii < si; ii++) for (let jj = 0; jj < sj; jj++) U[ri + ii][rj + jj] = sol[ii * sj + jj];
|
|
5708
|
-
}
|
|
5709
|
-
return U;
|
|
5710
|
-
}
|
|
5711
|
-
function solveLinearSystem(A, b) {
|
|
5712
|
-
const n = A.length;
|
|
5713
|
-
const Aug = A.map((row, i) => [...row, b[i]]);
|
|
5714
|
-
for (let col = 0; col < n; col++) {
|
|
5715
|
-
let maxRow = col;
|
|
5716
|
-
let maxVal = Math.abs(Aug[col][col]);
|
|
5717
|
-
for (let row = col + 1; row < n; row++) if (Math.abs(Aug[row][col]) > maxVal) {
|
|
5718
|
-
maxVal = Math.abs(Aug[row][col]);
|
|
5719
|
-
maxRow = row;
|
|
5720
|
-
}
|
|
5721
|
-
if (maxRow !== col) [Aug[col], Aug[maxRow]] = [Aug[maxRow], Aug[col]];
|
|
5722
|
-
const pivot = Aug[col][col];
|
|
5723
|
-
if (Math.abs(pivot) < 1e-15) return null;
|
|
5724
|
-
for (let j = col; j <= n; j++) Aug[col][j] /= pivot;
|
|
5725
|
-
for (let row = 0; row < n; row++) {
|
|
5726
|
-
if (row === col) continue;
|
|
5727
|
-
const f = Aug[row][col];
|
|
5728
|
-
if (f === 0) continue;
|
|
5729
|
-
for (let j = col; j <= n; j++) Aug[row][j] -= f * Aug[col][j];
|
|
5730
|
-
}
|
|
5731
|
-
}
|
|
5732
|
-
return Aug.map((row) => row[n]);
|
|
5733
|
-
}
|
|
5734
|
-
function sqrtmSchur(A) {
|
|
5735
|
-
const { H: T, Q } = schurInternal(A);
|
|
5736
|
-
const U = sqrtmQuasiTriangular(T);
|
|
5737
|
-
if (U === null) return null;
|
|
5738
|
-
const Qt = transpose$1(Q);
|
|
5739
|
-
return matMul(matMul(Q, U), Qt);
|
|
5740
|
-
}
|
|
5741
|
-
function matrixSqrtm(A, opts) {
|
|
5742
|
-
const n = A.rows;
|
|
5743
|
-
if (n !== A.cols) throw new Error(`matrixSqrtm: matrix must be square (got ${A.rows}×${A.cols})`);
|
|
5744
|
-
if (n === 0) return DenseMatrix.zeros(0, 0);
|
|
5745
|
-
if (n === 1) {
|
|
5746
|
-
const val = A.get(0, 0);
|
|
5747
|
-
if (val < 0) throw new Error(`matrixSqrtm: negative scalar (${val}) has no real square root`);
|
|
5748
|
-
return DenseMatrix.fromArray([[Math.sqrt(val)]]);
|
|
5749
|
-
}
|
|
5750
|
-
const Aarr = A.toArray();
|
|
5751
|
-
const isSymm = (opts?.assumeSymmetric ?? false) || isSymmetricMatrix(Aarr);
|
|
5752
|
-
let result;
|
|
5753
|
-
if (isSymm) result = sqrtmSymmetric(Aarr);
|
|
5754
|
-
else {
|
|
5755
|
-
const schurResult = sqrtmSchur(Aarr);
|
|
5756
|
-
if (schurResult !== null) result = schurResult;
|
|
5757
|
-
else result = sqrtmGeneral(Aarr);
|
|
5758
|
-
}
|
|
5759
|
-
const data = new Float64Array(n * n);
|
|
5760
|
-
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) data[i * n + j] = result[i][j];
|
|
5761
|
-
return new DenseMatrix(n, n, data);
|
|
5762
|
-
}
|
|
5763
|
-
function isSymmetricMatrix(A, tol = 1e-8) {
|
|
5764
|
-
const n = A.length;
|
|
5765
|
-
for (let i = 0; i < n; i++) for (let j = i + 1; j < n; j++) if (Math.abs(A[i][j] - A[j][i]) > tol) return false;
|
|
5766
|
-
return true;
|
|
5767
|
-
}
|
|
5768
|
-
//#endregion
|
|
5769
5352
|
//#region src/operations/qr-pivoted.ts
|
|
5770
5353
|
init_DenseMatrix();
|
|
5771
5354
|
function qrPivoted(A, opts) {
|
|
@@ -5841,21 +5424,20 @@ function qrPivoted(A, opts) {
|
|
|
5841
5424
|
//#endregion
|
|
5842
5425
|
//#region src/operations/qr-family.ts
|
|
5843
5426
|
init_DenseMatrix();
|
|
5844
|
-
function
|
|
5427
|
+
function flipDense(M, axis) {
|
|
5845
5428
|
const m = M.rows;
|
|
5846
5429
|
const n = M.cols;
|
|
5847
5430
|
const src = M.toFloat64Array();
|
|
5848
5431
|
const data = new Float64Array(m * n);
|
|
5849
|
-
for (let i = 0; i < m; i++) for (let j = 0; j < n; j++) data[i * n + j] = src[(m - 1 - i) * n + j];
|
|
5432
|
+
if (axis === 0) for (let i = 0; i < m; i++) for (let j = 0; j < n; j++) data[i * n + j] = src[(m - 1 - i) * n + j];
|
|
5433
|
+
else for (let i = 0; i < m; i++) for (let j = 0; j < n; j++) data[i * n + j] = src[i * n + (n - 1 - j)];
|
|
5850
5434
|
return new DenseMatrix(m, n, data);
|
|
5851
5435
|
}
|
|
5436
|
+
function flipRows(M) {
|
|
5437
|
+
return flipDense(M, 0);
|
|
5438
|
+
}
|
|
5852
5439
|
function flipCols(M) {
|
|
5853
|
-
|
|
5854
|
-
const n = M.cols;
|
|
5855
|
-
const src = M.toFloat64Array();
|
|
5856
|
-
const data = new Float64Array(m * n);
|
|
5857
|
-
for (let i = 0; i < m; i++) for (let j = 0; j < n; j++) data[i * n + j] = src[i * n + (n - 1 - j)];
|
|
5858
|
-
return new DenseMatrix(m, n, data);
|
|
5440
|
+
return flipDense(M, 1);
|
|
5859
5441
|
}
|
|
5860
5442
|
function lq(A) {
|
|
5861
5443
|
const { Q: Q1, R: R1 } = qr(A.transpose(), { mode: "reduced" });
|
|
@@ -6199,6 +5781,10 @@ function matrixToFloat64(m) {
|
|
|
6199
5781
|
function float64ToMatrix(data, rows, cols) {
|
|
6200
5782
|
return new DenseMatrix(rows, cols, data);
|
|
6201
5783
|
}
|
|
5784
|
+
async function densePair(a, b, op, mismatch) {
|
|
5785
|
+
if (a.rows !== b.rows || a.cols !== b.cols) throw new Error(mismatch(a, b));
|
|
5786
|
+
return float64ToMatrix((await op(matrixToFloat64(a), matrixToFloat64(b))).result, a.rows, a.cols);
|
|
5787
|
+
}
|
|
6202
5788
|
const parallelMatrix = mathTyped("parallelMatrix", {
|
|
6203
5789
|
Array: (arr) => DenseMatrix.fromArray(arr),
|
|
6204
5790
|
"number, number": (rows, cols) => DenseMatrix.zeros(rows, cols),
|
|
@@ -6215,10 +5801,7 @@ const parallelDiag = mathTyped("parallelDiag", {
|
|
|
6215
5801
|
});
|
|
6216
5802
|
const parallelRandom = mathTyped("parallelRandom", { "number, number": (rows, cols) => DenseMatrix.random(rows, cols) });
|
|
6217
5803
|
const parallelMatrixAdd = mathTyped("parallelMatrixAdd", {
|
|
6218
|
-
"DenseMatrix, DenseMatrix":
|
|
6219
|
-
if (a.rows !== b.rows || a.cols !== b.cols) throw new Error(`Matrix dimensions must match: ${a.rows}×${a.cols} vs ${b.rows}×${b.cols}`);
|
|
6220
|
-
return float64ToMatrix((await pAdd(matrixToFloat64(a), matrixToFloat64(b))).result, a.rows, a.cols);
|
|
6221
|
-
},
|
|
5804
|
+
"DenseMatrix, DenseMatrix": (a, b) => densePair(a, b, pAdd, (left, right) => `Matrix dimensions must match: ${left.rows}×${left.cols} vs ${right.rows}×${right.cols}`),
|
|
6222
5805
|
"DenseMatrix, number": async (a, scalar) => {
|
|
6223
5806
|
const dataA = matrixToFloat64(a);
|
|
6224
5807
|
return float64ToMatrix((await pAdd(dataA, new Float64Array(dataA.length).fill(scalar))).result, a.rows, a.cols);
|
|
@@ -6232,10 +5815,7 @@ const parallelMatrixAdd = mathTyped("parallelMatrixAdd", {
|
|
|
6232
5815
|
"number, number": (a, b) => a + b
|
|
6233
5816
|
});
|
|
6234
5817
|
const parallelMatrixSubtract = mathTyped("parallelMatrixSubtract", {
|
|
6235
|
-
"DenseMatrix, DenseMatrix":
|
|
6236
|
-
if (a.rows !== b.rows || a.cols !== b.cols) throw new Error(`Matrix dimensions must match: ${a.rows}×${a.cols} vs ${b.rows}×${b.cols}`);
|
|
6237
|
-
return float64ToMatrix((await pSubtract(matrixToFloat64(a), matrixToFloat64(b))).result, a.rows, a.cols);
|
|
6238
|
-
},
|
|
5818
|
+
"DenseMatrix, DenseMatrix": (a, b) => densePair(a, b, pSubtract, (left, right) => `Matrix dimensions must match: ${left.rows}×${left.cols} vs ${right.rows}×${right.cols}`),
|
|
6239
5819
|
"DenseMatrix, number": async (a, scalar) => {
|
|
6240
5820
|
const dataA = matrixToFloat64(a);
|
|
6241
5821
|
return float64ToMatrix((await pSubtract(dataA, new Float64Array(dataA.length).fill(scalar))).result, a.rows, a.cols);
|
|
@@ -6265,10 +5845,7 @@ const parallelMatrixMultiply = mathTyped("parallelMatrixMultiply", {
|
|
|
6265
5845
|
"number, number": (a, b) => a * b
|
|
6266
5846
|
});
|
|
6267
5847
|
const parallelDotMultiply = mathTyped("parallelDotMultiply", {
|
|
6268
|
-
"DenseMatrix, DenseMatrix":
|
|
6269
|
-
if (a.rows !== b.rows || a.cols !== b.cols) throw new Error(`Matrix dimensions must match for element-wise multiply`);
|
|
6270
|
-
return float64ToMatrix((await pMultiply(matrixToFloat64(a), matrixToFloat64(b))).result, a.rows, a.cols);
|
|
6271
|
-
},
|
|
5848
|
+
"DenseMatrix, DenseMatrix": (a, b) => densePair(a, b, pMultiply, () => `Matrix dimensions must match for element-wise multiply`),
|
|
6272
5849
|
"Float64Array, Float64Array": async (a, b) => {
|
|
6273
5850
|
return (await pMultiply(a, b)).result;
|
|
6274
5851
|
},
|
|
@@ -6282,10 +5859,7 @@ const parallelMatrixDivide = mathTyped("parallelMatrixDivide", {
|
|
|
6282
5859
|
const dataA = matrixToFloat64(a);
|
|
6283
5860
|
return float64ToMatrix((await pDivide(new Float64Array(dataA.length).fill(scalar), dataA)).result, a.rows, a.cols);
|
|
6284
5861
|
},
|
|
6285
|
-
"DenseMatrix, DenseMatrix":
|
|
6286
|
-
if (a.rows !== b.rows || a.cols !== b.cols) throw new Error(`Matrix dimensions must match for element-wise divide`);
|
|
6287
|
-
return float64ToMatrix((await pDivide(matrixToFloat64(a), matrixToFloat64(b))).result, a.rows, a.cols);
|
|
6288
|
-
},
|
|
5862
|
+
"DenseMatrix, DenseMatrix": (a, b) => densePair(a, b, pDivide, () => `Matrix dimensions must match for element-wise divide`),
|
|
6289
5863
|
"Float64Array, Float64Array": async (a, b) => {
|
|
6290
5864
|
return (await pDivide(a, b)).result;
|
|
6291
5865
|
},
|
|
@@ -6584,4 +6158,4 @@ init_Matrix();
|
|
|
6584
6158
|
init_SparseMatrix();
|
|
6585
6159
|
init_DenseMatrix();
|
|
6586
6160
|
//#endregion
|
|
6587
|
-
export { BUILTIN_SHADERS, BackendManager, BackendRegistry, BatchExecutor, BufferPool, DEFAULT_BACKEND_HINTS, DEFAULT_EXTENDED_HINTS, DenseMatrix, GPUBackend, GPUContext, GPUMatrixBackend, JSBackend, Matrix, ParallelBackend, ShaderManager, SparseMatrix, SyncManager, WASMBackend, abs, add, backendManager, backendRegistry, cholesky, clearFeatureCache, column, cond, condest, createBackendManager, createGPUMatrixBackend, createParallelBackend, createSyncManager, createWASMBackend, destroyGlobalGPU, destroyGlobalGPUBackend, detectGPUCapabilities, detectWasmFeatures, diag, diagonal, divide, dotMultiply, eig, eigWasm, eigvals, eigvalsWasm, exp, getCachedFeatures, getGlobalGPUBackend, getGlobalGPUContext, getRecommendedWorkgroupSize, gpuMatrixBackend, hasWebGPU, identity, initializeGlobalGPUBackend, initializeParallelMatrix, isAtomicsAvailable, isDenseMatrix, isMatrix, isSharedMemoryAvailable, isSparseMatrix, isWasmAvailable, jsBackend, log, lowRankApprox, lq, lu, luSolve, 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 };
|
|
6161
|
+
export { BUILTIN_SHADERS, BackendManager, BackendRegistry, BatchExecutor, BufferPool, DEFAULT_BACKEND_HINTS, DEFAULT_EXTENDED_HINTS, DenseMatrix, GPUBackend, GPUContext, GPUMatrixBackend, JSBackend, Matrix, ParallelBackend, ShaderManager, SparseMatrix, SyncManager, WASMBackend, abs, add, backendManager, backendRegistry, cholesky, clearFeatureCache, column, cond, condest, createBackendManager, createGPUMatrixBackend, createParallelBackend, createSyncManager, createWASMBackend, destroyGlobalGPU, destroyGlobalGPUBackend, detectGPUCapabilities, detectWasmFeatures, diag, diagonal, divide, dotMultiply, eig, eigWasm, eigvals, eigvalsWasm, exp, getCachedFeatures, getGlobalGPUBackend, getGlobalGPUContext, getRecommendedWorkgroupSize, gpuMatrixBackend, hasWebGPU, identity, initializeGlobalGPUBackend, initializeParallelMatrix, isAtomicsAvailable, isDenseMatrix, isMatrix, isSharedMemoryAvailable, isSparseMatrix, isWasmAvailable, jsBackend, log, lowRankApprox, lq, lu, luSolve, matMul, 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, transpose$1 as transposeNestedArray, typedMatrixOperations, unaryMinus, wasmBackend, zeros };
|