@danielsimonjr/mathts-matrix 0.1.7 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/chunk-HT4ZF3LN.js +886 -0
- package/dist/{eig-A5GJGSJJ.js → eig-G72TLEBA.js} +1 -1
- package/dist/index.d.ts +42 -337
- package/dist/index.js +192 -1190
- package/dist/wasm/mathts-as.wasm +0 -0
- package/dist/wasm/wasm-manifest.json +1 -1
- package/package.json +2 -2
- package/dist/chunk-VCPLE6ED.js +0 -473
package/dist/index.js
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
+
applyHouseholderLeft,
|
|
3
|
+
applyHouseholderRight,
|
|
4
|
+
cloneMatrix,
|
|
2
5
|
eig,
|
|
3
6
|
eigvals,
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
eye,
|
|
8
|
+
householder,
|
|
9
|
+
isSymmetric,
|
|
10
|
+
matAdd,
|
|
11
|
+
matMul,
|
|
12
|
+
matScale,
|
|
13
|
+
matSub,
|
|
14
|
+
norm1,
|
|
15
|
+
normInf,
|
|
16
|
+
powerIteration,
|
|
17
|
+
transpose
|
|
18
|
+
} from "./chunk-HT4ZF3LN.js";
|
|
6
19
|
import {
|
|
7
20
|
__esm,
|
|
8
21
|
__export,
|
|
@@ -183,7 +196,7 @@ function scale(a, scalar) {
|
|
|
183
196
|
for (let i = 0; i < ad.length; i++) result[i] = ad[i] * scalar;
|
|
184
197
|
return result;
|
|
185
198
|
}
|
|
186
|
-
function
|
|
199
|
+
function transpose2(a) {
|
|
187
200
|
const ad = flat(a);
|
|
188
201
|
const rows = a.rows;
|
|
189
202
|
const cols = a.cols;
|
|
@@ -1288,7 +1301,7 @@ var init_DenseMatrix = __esm({
|
|
|
1288
1301
|
* Matrix transpose
|
|
1289
1302
|
*/
|
|
1290
1303
|
transpose() {
|
|
1291
|
-
return new _DenseMatrix(this.cols, this.rows,
|
|
1304
|
+
return new _DenseMatrix(this.cols, this.rows, transpose2(this));
|
|
1292
1305
|
}
|
|
1293
1306
|
/**
|
|
1294
1307
|
* Negate all elements
|
|
@@ -2474,7 +2487,7 @@ var WASMBackend = class {
|
|
|
2474
2487
|
const loaded = await this.loadAsModule(path);
|
|
2475
2488
|
if (typeof loaded.__new !== "function" || typeof loaded.matrix_multiply !== "function") {
|
|
2476
2489
|
console.warn(
|
|
2477
|
-
"WASMBackend: loaded module is not the AssemblyScript artifact; falling back to JS. Pass an explicit wasmPath
|
|
2490
|
+
"WASMBackend: loaded module is not the AssemblyScript artifact; falling back to JS. Pass an explicit wasmPath (the AS binary, mathts-as.wasm)."
|
|
2478
2491
|
);
|
|
2479
2492
|
this.wasmModule = null;
|
|
2480
2493
|
return;
|
|
@@ -2506,7 +2519,7 @@ var WASMBackend = class {
|
|
|
2506
2519
|
/**
|
|
2507
2520
|
* Compile + instantiate the AssemblyScript WASM artifact. Each
|
|
2508
2521
|
* WASMBackend instance owns its own instance — this is intentional so
|
|
2509
|
-
* tests and
|
|
2522
|
+
* tests and multiple backend instances can coexist in the same process.
|
|
2510
2523
|
*/
|
|
2511
2524
|
async loadAsModule(path) {
|
|
2512
2525
|
const imports = {
|
|
@@ -2754,7 +2767,7 @@ var WASMBackend = class {
|
|
|
2754
2767
|
// =========================================================================
|
|
2755
2768
|
// LU / QR / Cholesky / Inverse / Determinant
|
|
2756
2769
|
// -------------------------------------------------------------------------
|
|
2757
|
-
// AssemblyScript
|
|
2770
|
+
// AssemblyScript exports these (see
|
|
2758
2771
|
// assembly/src/algebra/decomposition.ts). Each method dispatches to
|
|
2759
2772
|
// the AS export when the loaded module exposes it; otherwise it falls
|
|
2760
2773
|
// back to the in-process JS implementation that previously handled
|
|
@@ -4990,620 +5003,8 @@ function createGPUMatrixBackend(config) {
|
|
|
4990
5003
|
return new GPUMatrixBackend(config);
|
|
4991
5004
|
}
|
|
4992
5005
|
|
|
4993
|
-
// src/backends/RustWASMBackend.ts
|
|
4994
|
-
init_DenseMatrix();
|
|
4995
|
-
|
|
4996
|
-
// src/backends/RustWasmLoader.ts
|
|
4997
|
-
var BumpAllocator = class {
|
|
4998
|
-
/** Next free byte offset in WASM memory */
|
|
4999
|
-
offset;
|
|
5000
|
-
/** Minimum offset (base of allocatable region) */
|
|
5001
|
-
base;
|
|
5002
|
-
constructor(baseOffset) {
|
|
5003
|
-
this.base = baseOffset;
|
|
5004
|
-
this.offset = baseOffset;
|
|
5005
|
-
}
|
|
5006
|
-
/**
|
|
5007
|
-
* Allocate `byteLength` bytes, aligned to 8-byte boundary.
|
|
5008
|
-
* Returns the byte offset (pointer) into WASM memory.
|
|
5009
|
-
*/
|
|
5010
|
-
alloc(byteLength, memory) {
|
|
5011
|
-
const aligned = this.offset + 7 & ~7;
|
|
5012
|
-
const end = aligned + byteLength;
|
|
5013
|
-
const currentBytes = memory.buffer.byteLength;
|
|
5014
|
-
if (end > currentBytes) {
|
|
5015
|
-
const pagesNeeded = Math.ceil((end - currentBytes) / 65536);
|
|
5016
|
-
memory.grow(pagesNeeded);
|
|
5017
|
-
}
|
|
5018
|
-
this.offset = end;
|
|
5019
|
-
return aligned;
|
|
5020
|
-
}
|
|
5021
|
-
/**
|
|
5022
|
-
* Reset the allocator, reclaiming all temporary memory.
|
|
5023
|
-
* Call between independent operations.
|
|
5024
|
-
*/
|
|
5025
|
-
reset() {
|
|
5026
|
-
this.offset = this.base;
|
|
5027
|
-
}
|
|
5028
|
-
/** Current high-water mark */
|
|
5029
|
-
get highWaterMark() {
|
|
5030
|
-
return this.offset;
|
|
5031
|
-
}
|
|
5032
|
-
};
|
|
5033
|
-
var RustWasmLoader = class _RustWasmLoader {
|
|
5034
|
-
static instance = null;
|
|
5035
|
-
wasmInstance = null;
|
|
5036
|
-
wasmMemory = null;
|
|
5037
|
-
allocator = null;
|
|
5038
|
-
_isLoaded = false;
|
|
5039
|
-
loading = null;
|
|
5040
|
-
lastMetrics = null;
|
|
5041
|
-
constructor() {
|
|
5042
|
-
}
|
|
5043
|
-
static getInstance() {
|
|
5044
|
-
if (!_RustWasmLoader.instance) {
|
|
5045
|
-
_RustWasmLoader.instance = new _RustWasmLoader();
|
|
5046
|
-
}
|
|
5047
|
-
return _RustWasmLoader.instance;
|
|
5048
|
-
}
|
|
5049
|
-
get isLoaded() {
|
|
5050
|
-
return this._isLoaded;
|
|
5051
|
-
}
|
|
5052
|
-
/**
|
|
5053
|
-
* Load the Rust WASM module.
|
|
5054
|
-
* Returns true on success, false if the binary is not available.
|
|
5055
|
-
* Safe to call multiple times (idempotent).
|
|
5056
|
-
*/
|
|
5057
|
-
async load(wasmPath) {
|
|
5058
|
-
if (this._isLoaded) return true;
|
|
5059
|
-
if (this.loading) return this.loading;
|
|
5060
|
-
this.loading = this.doLoad(wasmPath);
|
|
5061
|
-
const result = await this.loading;
|
|
5062
|
-
this.loading = null;
|
|
5063
|
-
return result;
|
|
5064
|
-
}
|
|
5065
|
-
async doLoad(wasmPath) {
|
|
5066
|
-
const totalStart = performance.now();
|
|
5067
|
-
try {
|
|
5068
|
-
const path = wasmPath || await this.findWasmPath();
|
|
5069
|
-
const isNode = typeof process !== "undefined" && process.versions?.node !== void 0;
|
|
5070
|
-
const { loadWasmManifest, verifyWasmIntegrity } = await import("./integrity-X3CLNVGW.js");
|
|
5071
|
-
let binarySize = 0;
|
|
5072
|
-
if (isNode) {
|
|
5073
|
-
const loadStart = performance.now();
|
|
5074
|
-
const fs = await import("fs");
|
|
5075
|
-
const buffer = fs.readFileSync(path);
|
|
5076
|
-
binarySize = buffer.byteLength;
|
|
5077
|
-
const loadEnd = performance.now();
|
|
5078
|
-
await verifyWasmIntegrity(buffer, path);
|
|
5079
|
-
const compileStart = performance.now();
|
|
5080
|
-
const module = await WebAssembly.compile(buffer);
|
|
5081
|
-
const compileEnd = performance.now();
|
|
5082
|
-
const instStart = performance.now();
|
|
5083
|
-
this.wasmInstance = await WebAssembly.instantiate(module, this.getImports());
|
|
5084
|
-
const instEnd = performance.now();
|
|
5085
|
-
this.lastMetrics = {
|
|
5086
|
-
loadMs: loadEnd - loadStart,
|
|
5087
|
-
compileMs: compileEnd - compileStart,
|
|
5088
|
-
instantiateMs: instEnd - instStart,
|
|
5089
|
-
totalMs: performance.now() - totalStart,
|
|
5090
|
-
binarySize
|
|
5091
|
-
};
|
|
5092
|
-
} else {
|
|
5093
|
-
const manifest = await loadWasmManifest(path);
|
|
5094
|
-
const instStart = performance.now();
|
|
5095
|
-
if (!manifest && typeof WebAssembly.instantiateStreaming === "function") {
|
|
5096
|
-
const result = await WebAssembly.instantiateStreaming(fetch(path), this.getImports());
|
|
5097
|
-
this.wasmInstance = result.instance;
|
|
5098
|
-
} else {
|
|
5099
|
-
const response = await fetch(path);
|
|
5100
|
-
const buffer = await response.arrayBuffer();
|
|
5101
|
-
binarySize = buffer.byteLength;
|
|
5102
|
-
await verifyWasmIntegrity(buffer, path, { manifest });
|
|
5103
|
-
const module = await WebAssembly.compile(buffer);
|
|
5104
|
-
this.wasmInstance = await WebAssembly.instantiate(module, this.getImports());
|
|
5105
|
-
}
|
|
5106
|
-
this.lastMetrics = {
|
|
5107
|
-
loadMs: 0,
|
|
5108
|
-
compileMs: 0,
|
|
5109
|
-
instantiateMs: performance.now() - instStart,
|
|
5110
|
-
totalMs: performance.now() - totalStart,
|
|
5111
|
-
binarySize
|
|
5112
|
-
};
|
|
5113
|
-
}
|
|
5114
|
-
this.wasmMemory = this.wasmInstance.exports.memory;
|
|
5115
|
-
const heapBaseGlobal = this.wasmInstance.exports.__heap_base;
|
|
5116
|
-
const heapBase = heapBaseGlobal && typeof heapBaseGlobal.value === "number" ? heapBaseGlobal.value : 65536;
|
|
5117
|
-
this.allocator = new BumpAllocator(heapBase);
|
|
5118
|
-
this._isLoaded = true;
|
|
5119
|
-
return true;
|
|
5120
|
-
} catch (e) {
|
|
5121
|
-
console.warn("Rust WASM not available, using JS fallback:", e.message);
|
|
5122
|
-
return false;
|
|
5123
|
-
}
|
|
5124
|
-
}
|
|
5125
|
-
/**
|
|
5126
|
-
* Resolve the WASM binary path.
|
|
5127
|
-
* Checks several locations relative to the project root.
|
|
5128
|
-
*/
|
|
5129
|
-
async findWasmPath() {
|
|
5130
|
-
const isNode = typeof process !== "undefined" && process.versions?.node !== void 0;
|
|
5131
|
-
const resolvedUrl = new URL(`../../../lib/wasm/mathts.wasm`, import.meta.url);
|
|
5132
|
-
if (isNode) {
|
|
5133
|
-
const { fileURLToPath } = await import("url");
|
|
5134
|
-
return fileURLToPath(resolvedUrl);
|
|
5135
|
-
}
|
|
5136
|
-
return resolvedUrl.href;
|
|
5137
|
-
}
|
|
5138
|
-
getImports() {
|
|
5139
|
-
return {
|
|
5140
|
-
env: {
|
|
5141
|
-
abort: () => {
|
|
5142
|
-
throw new Error("Rust WASM abort");
|
|
5143
|
-
}
|
|
5144
|
-
}
|
|
5145
|
-
};
|
|
5146
|
-
}
|
|
5147
|
-
/**
|
|
5148
|
-
* Get the typed exports from the WASM instance.
|
|
5149
|
-
*/
|
|
5150
|
-
getExports() {
|
|
5151
|
-
if (!this.wasmInstance) return null;
|
|
5152
|
-
return this.wasmInstance.exports;
|
|
5153
|
-
}
|
|
5154
|
-
/**
|
|
5155
|
-
* Get WASM linear memory.
|
|
5156
|
-
*/
|
|
5157
|
-
getMemory() {
|
|
5158
|
-
return this.wasmMemory;
|
|
5159
|
-
}
|
|
5160
|
-
/**
|
|
5161
|
-
* Get loading metrics.
|
|
5162
|
-
*/
|
|
5163
|
-
getLoadingMetrics() {
|
|
5164
|
-
return this.lastMetrics;
|
|
5165
|
-
}
|
|
5166
|
-
// =========================================================================
|
|
5167
|
-
// Memory Management (Bump Allocator)
|
|
5168
|
-
// =========================================================================
|
|
5169
|
-
/**
|
|
5170
|
-
* Write a Float64Array into WASM memory and return the pointer.
|
|
5171
|
-
*/
|
|
5172
|
-
writeF64(data) {
|
|
5173
|
-
if (!this.wasmMemory || !this.allocator) {
|
|
5174
|
-
throw new Error("Rust WASM not loaded");
|
|
5175
|
-
}
|
|
5176
|
-
const byteLength = (Array.isArray(data) ? data.length : data.length) * 8;
|
|
5177
|
-
const ptr = this.allocator.alloc(byteLength, this.wasmMemory);
|
|
5178
|
-
const view = new Float64Array(
|
|
5179
|
-
this.wasmMemory.buffer,
|
|
5180
|
-
ptr,
|
|
5181
|
-
Array.isArray(data) ? data.length : data.length
|
|
5182
|
-
);
|
|
5183
|
-
view.set(data);
|
|
5184
|
-
return ptr;
|
|
5185
|
-
}
|
|
5186
|
-
/**
|
|
5187
|
-
* Allocate an empty Float64Array in WASM memory (for output buffers).
|
|
5188
|
-
* Returns the pointer.
|
|
5189
|
-
*/
|
|
5190
|
-
allocF64(length) {
|
|
5191
|
-
if (!this.wasmMemory || !this.allocator) {
|
|
5192
|
-
throw new Error("Rust WASM not loaded");
|
|
5193
|
-
}
|
|
5194
|
-
return this.allocator.alloc(length * 8, this.wasmMemory);
|
|
5195
|
-
}
|
|
5196
|
-
/**
|
|
5197
|
-
* Write an Int32Array into WASM memory and return the pointer.
|
|
5198
|
-
*/
|
|
5199
|
-
writeI32(data) {
|
|
5200
|
-
if (!this.wasmMemory || !this.allocator) {
|
|
5201
|
-
throw new Error("Rust WASM not loaded");
|
|
5202
|
-
}
|
|
5203
|
-
const length = Array.isArray(data) ? data.length : data.length;
|
|
5204
|
-
const byteLength = length * 4;
|
|
5205
|
-
const ptr = this.allocator.alloc(byteLength, this.wasmMemory);
|
|
5206
|
-
const view = new Int32Array(this.wasmMemory.buffer, ptr, length);
|
|
5207
|
-
view.set(data);
|
|
5208
|
-
return ptr;
|
|
5209
|
-
}
|
|
5210
|
-
/**
|
|
5211
|
-
* Allocate an empty Int32Array in WASM memory.
|
|
5212
|
-
*/
|
|
5213
|
-
allocI32(length) {
|
|
5214
|
-
if (!this.wasmMemory || !this.allocator) {
|
|
5215
|
-
throw new Error("Rust WASM not loaded");
|
|
5216
|
-
}
|
|
5217
|
-
return this.allocator.alloc(length * 4, this.wasmMemory);
|
|
5218
|
-
}
|
|
5219
|
-
/**
|
|
5220
|
-
* Read a Float64Array from WASM memory.
|
|
5221
|
-
* Note: the returned array is a *copy* (safe after memory reset).
|
|
5222
|
-
*/
|
|
5223
|
-
readF64(ptr, length) {
|
|
5224
|
-
if (!this.wasmMemory) {
|
|
5225
|
-
throw new Error("Rust WASM not loaded");
|
|
5226
|
-
}
|
|
5227
|
-
const view = new Float64Array(this.wasmMemory.buffer, ptr, length);
|
|
5228
|
-
return new Float64Array(view);
|
|
5229
|
-
}
|
|
5230
|
-
/**
|
|
5231
|
-
* Read an Int32Array from WASM memory.
|
|
5232
|
-
*/
|
|
5233
|
-
readI32(ptr, length) {
|
|
5234
|
-
if (!this.wasmMemory) {
|
|
5235
|
-
throw new Error("Rust WASM not loaded");
|
|
5236
|
-
}
|
|
5237
|
-
const view = new Int32Array(this.wasmMemory.buffer, ptr, length);
|
|
5238
|
-
return new Int32Array(view);
|
|
5239
|
-
}
|
|
5240
|
-
/**
|
|
5241
|
-
* Reset the bump allocator. Call between independent operations
|
|
5242
|
-
* to reclaim temporary memory.
|
|
5243
|
-
*/
|
|
5244
|
-
resetAllocator() {
|
|
5245
|
-
this.allocator?.reset();
|
|
5246
|
-
}
|
|
5247
|
-
/**
|
|
5248
|
-
* Reset the loader (for testing).
|
|
5249
|
-
*/
|
|
5250
|
-
reset() {
|
|
5251
|
-
this.wasmInstance = null;
|
|
5252
|
-
this.wasmMemory = null;
|
|
5253
|
-
this.allocator = null;
|
|
5254
|
-
this._isLoaded = false;
|
|
5255
|
-
this.loading = null;
|
|
5256
|
-
this.lastMetrics = null;
|
|
5257
|
-
}
|
|
5258
|
-
/**
|
|
5259
|
-
* Reset the singleton (for testing).
|
|
5260
|
-
*/
|
|
5261
|
-
static resetInstance() {
|
|
5262
|
-
if (_RustWasmLoader.instance) {
|
|
5263
|
-
_RustWasmLoader.instance.reset();
|
|
5264
|
-
}
|
|
5265
|
-
_RustWasmLoader.instance = null;
|
|
5266
|
-
}
|
|
5267
|
-
};
|
|
5268
|
-
var rustWasmLoader = RustWasmLoader.getInstance();
|
|
5269
|
-
async function initRustWasm(wasmPath) {
|
|
5270
|
-
return rustWasmLoader.load(wasmPath);
|
|
5271
|
-
}
|
|
5272
|
-
|
|
5273
|
-
// src/backends/RustWASMBackend.ts
|
|
5274
|
-
var DEFAULT_CONFIG3 = {
|
|
5275
|
-
minElements: 1e3,
|
|
5276
|
-
wasmPath: ""
|
|
5277
|
-
};
|
|
5278
|
-
var RustWASMBackend = class {
|
|
5279
|
-
/**
|
|
5280
|
-
* Backend type identifier.
|
|
5281
|
-
* Uses 'rust-wasm' to distinguish from the AssemblyScript WASMBackend.
|
|
5282
|
-
*/
|
|
5283
|
-
type = "rust-wasm";
|
|
5284
|
-
config;
|
|
5285
|
-
exports = null;
|
|
5286
|
-
initPromise = null;
|
|
5287
|
-
constructor(config = {}) {
|
|
5288
|
-
this.config = { ...DEFAULT_CONFIG3, ...config };
|
|
5289
|
-
}
|
|
5290
|
-
/**
|
|
5291
|
-
* Check if WebAssembly is available in the current environment.
|
|
5292
|
-
*/
|
|
5293
|
-
isAvailable() {
|
|
5294
|
-
return typeof WebAssembly !== "undefined";
|
|
5295
|
-
}
|
|
5296
|
-
/**
|
|
5297
|
-
* Initialize the Rust WASM backend.
|
|
5298
|
-
* Loads the WASM binary and caches the exports.
|
|
5299
|
-
*/
|
|
5300
|
-
async initialize() {
|
|
5301
|
-
if (this.exports) return;
|
|
5302
|
-
if (this.initPromise) return this.initPromise;
|
|
5303
|
-
this.initPromise = this.doInitialize();
|
|
5304
|
-
return this.initPromise;
|
|
5305
|
-
}
|
|
5306
|
-
async doInitialize() {
|
|
5307
|
-
if (!this.isAvailable()) {
|
|
5308
|
-
throw new Error("WebAssembly is not available in this environment");
|
|
5309
|
-
}
|
|
5310
|
-
const loaded = await rustWasmLoader.load(this.config.wasmPath || void 0);
|
|
5311
|
-
if (loaded) {
|
|
5312
|
-
this.exports = rustWasmLoader.getExports();
|
|
5313
|
-
} else {
|
|
5314
|
-
console.warn("Rust WASM binary not available, RustWASMBackend will use JS fallback");
|
|
5315
|
-
}
|
|
5316
|
-
}
|
|
5317
|
-
/**
|
|
5318
|
-
* Whether to use Rust WASM for this operation size.
|
|
5319
|
-
*/
|
|
5320
|
-
shouldUseRustWasm(elementCount) {
|
|
5321
|
-
return this.exports !== null && elementCount >= this.config.minElements;
|
|
5322
|
-
}
|
|
5323
|
-
/**
|
|
5324
|
-
* Whether the Rust WASM module is loaded and ready.
|
|
5325
|
-
*/
|
|
5326
|
-
get isRustLoaded() {
|
|
5327
|
-
return this.exports !== null;
|
|
5328
|
-
}
|
|
5329
|
-
// =========================================================================
|
|
5330
|
-
// Element-wise Operations
|
|
5331
|
-
// =========================================================================
|
|
5332
|
-
add(a, b) {
|
|
5333
|
-
const n = a.rows * a.cols;
|
|
5334
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.add(a, b);
|
|
5335
|
-
try {
|
|
5336
|
-
rustWasmLoader.resetAllocator();
|
|
5337
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5338
|
-
const bPtr = rustWasmLoader.writeF64(b.toFloat64Array());
|
|
5339
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5340
|
-
this.exports.simdAddF64(aPtr, bPtr, outPtr, n);
|
|
5341
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5342
|
-
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
5343
|
-
} catch {
|
|
5344
|
-
return jsBackend.add(a, b);
|
|
5345
|
-
}
|
|
5346
|
-
}
|
|
5347
|
-
subtract(a, b) {
|
|
5348
|
-
const n = a.rows * a.cols;
|
|
5349
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.subtract(a, b);
|
|
5350
|
-
try {
|
|
5351
|
-
rustWasmLoader.resetAllocator();
|
|
5352
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5353
|
-
const bPtr = rustWasmLoader.writeF64(b.toFloat64Array());
|
|
5354
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5355
|
-
this.exports.simdSubF64(aPtr, bPtr, outPtr, n);
|
|
5356
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5357
|
-
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
5358
|
-
} catch {
|
|
5359
|
-
return jsBackend.subtract(a, b);
|
|
5360
|
-
}
|
|
5361
|
-
}
|
|
5362
|
-
multiplyElementwise(a, b) {
|
|
5363
|
-
const n = a.rows * a.cols;
|
|
5364
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.multiplyElementwise(a, b);
|
|
5365
|
-
try {
|
|
5366
|
-
rustWasmLoader.resetAllocator();
|
|
5367
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5368
|
-
const bPtr = rustWasmLoader.writeF64(b.toFloat64Array());
|
|
5369
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5370
|
-
this.exports.simdMulF64(aPtr, bPtr, outPtr, n);
|
|
5371
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5372
|
-
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
5373
|
-
} catch {
|
|
5374
|
-
return jsBackend.multiplyElementwise(a, b);
|
|
5375
|
-
}
|
|
5376
|
-
}
|
|
5377
|
-
divideElementwise(a, b) {
|
|
5378
|
-
return jsBackend.divideElementwise(a, b);
|
|
5379
|
-
}
|
|
5380
|
-
scale(a, scalar) {
|
|
5381
|
-
const n = a.rows * a.cols;
|
|
5382
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.scale(a, scalar);
|
|
5383
|
-
try {
|
|
5384
|
-
rustWasmLoader.resetAllocator();
|
|
5385
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5386
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5387
|
-
this.exports.simdScaleF64(aPtr, scalar, outPtr, n);
|
|
5388
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5389
|
-
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
5390
|
-
} catch {
|
|
5391
|
-
return jsBackend.scale(a, scalar);
|
|
5392
|
-
}
|
|
5393
|
-
}
|
|
5394
|
-
abs(a) {
|
|
5395
|
-
const n = a.rows * a.cols;
|
|
5396
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.abs(a);
|
|
5397
|
-
try {
|
|
5398
|
-
rustWasmLoader.resetAllocator();
|
|
5399
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5400
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5401
|
-
this.exports.simdAbsF64(aPtr, outPtr, n);
|
|
5402
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5403
|
-
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
5404
|
-
} catch {
|
|
5405
|
-
return jsBackend.abs(a);
|
|
5406
|
-
}
|
|
5407
|
-
}
|
|
5408
|
-
negate(a) {
|
|
5409
|
-
const n = a.rows * a.cols;
|
|
5410
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.negate(a);
|
|
5411
|
-
try {
|
|
5412
|
-
rustWasmLoader.resetAllocator();
|
|
5413
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5414
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5415
|
-
this.exports.simdScaleF64(aPtr, -1, outPtr, n);
|
|
5416
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5417
|
-
return DenseMatrix.fromFlat(a.rows, a.cols, Array.from(result));
|
|
5418
|
-
} catch {
|
|
5419
|
-
return jsBackend.negate(a);
|
|
5420
|
-
}
|
|
5421
|
-
}
|
|
5422
|
-
// =========================================================================
|
|
5423
|
-
// Matrix Operations
|
|
5424
|
-
// =========================================================================
|
|
5425
|
-
multiply(a, b) {
|
|
5426
|
-
const elementCount = a.rows * a.cols + b.rows * b.cols;
|
|
5427
|
-
if (!this.shouldUseRustWasm(elementCount)) return jsBackend.multiply(a, b);
|
|
5428
|
-
try {
|
|
5429
|
-
rustWasmLoader.resetAllocator();
|
|
5430
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5431
|
-
const bPtr = rustWasmLoader.writeF64(b.toFloat64Array());
|
|
5432
|
-
const resultSize = a.rows * b.cols;
|
|
5433
|
-
const outPtr = rustWasmLoader.allocF64(resultSize);
|
|
5434
|
-
this.exports.multiplyDenseSIMD(aPtr, a.rows, a.cols, bPtr, b.rows, b.cols, outPtr);
|
|
5435
|
-
const result = rustWasmLoader.readF64(outPtr, resultSize);
|
|
5436
|
-
return DenseMatrix.fromFlat(a.rows, b.cols, Array.from(result));
|
|
5437
|
-
} catch {
|
|
5438
|
-
return jsBackend.multiply(a, b);
|
|
5439
|
-
}
|
|
5440
|
-
}
|
|
5441
|
-
transpose(a) {
|
|
5442
|
-
const n = a.rows * a.cols;
|
|
5443
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.transpose(a);
|
|
5444
|
-
try {
|
|
5445
|
-
rustWasmLoader.resetAllocator();
|
|
5446
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5447
|
-
const outPtr = rustWasmLoader.allocF64(n);
|
|
5448
|
-
this.exports.transpose(aPtr, a.rows, a.cols, outPtr);
|
|
5449
|
-
const result = rustWasmLoader.readF64(outPtr, n);
|
|
5450
|
-
return DenseMatrix.fromFlat(a.cols, a.rows, Array.from(result));
|
|
5451
|
-
} catch {
|
|
5452
|
-
return jsBackend.transpose(a);
|
|
5453
|
-
}
|
|
5454
|
-
}
|
|
5455
|
-
// =========================================================================
|
|
5456
|
-
// Reduction Operations
|
|
5457
|
-
// =========================================================================
|
|
5458
|
-
sum(a) {
|
|
5459
|
-
const n = a.rows * a.cols;
|
|
5460
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.sum(a);
|
|
5461
|
-
try {
|
|
5462
|
-
rustWasmLoader.resetAllocator();
|
|
5463
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5464
|
-
return this.exports.simdSumF64(aPtr, n);
|
|
5465
|
-
} catch {
|
|
5466
|
-
return jsBackend.sum(a);
|
|
5467
|
-
}
|
|
5468
|
-
}
|
|
5469
|
-
sumAxis(a, axis) {
|
|
5470
|
-
return jsBackend.sumAxis(a, axis);
|
|
5471
|
-
}
|
|
5472
|
-
norm(a) {
|
|
5473
|
-
const n = a.rows * a.cols;
|
|
5474
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.norm(a);
|
|
5475
|
-
try {
|
|
5476
|
-
rustWasmLoader.resetAllocator();
|
|
5477
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5478
|
-
return this.exports.simdNormF64(aPtr, n);
|
|
5479
|
-
} catch {
|
|
5480
|
-
return jsBackend.norm(a);
|
|
5481
|
-
}
|
|
5482
|
-
}
|
|
5483
|
-
dot(a, b) {
|
|
5484
|
-
const n = a.rows * a.cols;
|
|
5485
|
-
if (!this.shouldUseRustWasm(n)) return jsBackend.dot(a, b);
|
|
5486
|
-
try {
|
|
5487
|
-
rustWasmLoader.resetAllocator();
|
|
5488
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5489
|
-
const bPtr = rustWasmLoader.writeF64(b.toFloat64Array());
|
|
5490
|
-
return this.exports.simdDotF64(aPtr, bPtr, n);
|
|
5491
|
-
} catch {
|
|
5492
|
-
return jsBackend.dot(a, b);
|
|
5493
|
-
}
|
|
5494
|
-
}
|
|
5495
|
-
// =========================================================================
|
|
5496
|
-
// Heavy Operations (unique to Rust backend)
|
|
5497
|
-
// =========================================================================
|
|
5498
|
-
/**
|
|
5499
|
-
* LU Decomposition using Rust WASM.
|
|
5500
|
-
*/
|
|
5501
|
-
async luDecomposition(a) {
|
|
5502
|
-
const n = a.rows;
|
|
5503
|
-
if (n !== a.cols) {
|
|
5504
|
-
throw new Error("LU decomposition requires a square matrix");
|
|
5505
|
-
}
|
|
5506
|
-
if (!this.exports) {
|
|
5507
|
-
throw new Error("Rust WASM not loaded");
|
|
5508
|
-
}
|
|
5509
|
-
rustWasmLoader.resetAllocator();
|
|
5510
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5511
|
-
const permPtr = rustWasmLoader.allocI32(n);
|
|
5512
|
-
const success = this.exports.luDecomposition(aPtr, n, permPtr);
|
|
5513
|
-
return {
|
|
5514
|
-
lu: DenseMatrix.fromFlat(n, n, Array.from(rustWasmLoader.readF64(aPtr, n * n))),
|
|
5515
|
-
perm: rustWasmLoader.readI32(permPtr, n),
|
|
5516
|
-
singular: success === 0
|
|
5517
|
-
};
|
|
5518
|
-
}
|
|
5519
|
-
/**
|
|
5520
|
-
* Eigenvalue decomposition for symmetric matrices using Rust WASM.
|
|
5521
|
-
*/
|
|
5522
|
-
async eigsSymmetric(a, precision = 1e-12) {
|
|
5523
|
-
const n = a.rows;
|
|
5524
|
-
if (n !== a.cols) {
|
|
5525
|
-
throw new Error("Eigendecomposition requires a square matrix");
|
|
5526
|
-
}
|
|
5527
|
-
if (!this.exports) {
|
|
5528
|
-
throw new Error("Rust WASM not loaded");
|
|
5529
|
-
}
|
|
5530
|
-
rustWasmLoader.resetAllocator();
|
|
5531
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5532
|
-
const eigvalsPtr = rustWasmLoader.allocF64(n);
|
|
5533
|
-
const eigvecsPtr = rustWasmLoader.allocF64(n * n);
|
|
5534
|
-
const workPtr = rustWasmLoader.allocF64(n * n);
|
|
5535
|
-
const iterations = this.exports.eigsSymmetric(
|
|
5536
|
-
aPtr,
|
|
5537
|
-
n,
|
|
5538
|
-
precision,
|
|
5539
|
-
eigvalsPtr,
|
|
5540
|
-
eigvecsPtr,
|
|
5541
|
-
workPtr
|
|
5542
|
-
);
|
|
5543
|
-
return {
|
|
5544
|
-
eigenvalues: rustWasmLoader.readF64(eigvalsPtr, n),
|
|
5545
|
-
eigenvectors: DenseMatrix.fromFlat(
|
|
5546
|
-
n,
|
|
5547
|
-
n,
|
|
5548
|
-
Array.from(rustWasmLoader.readF64(eigvecsPtr, n * n))
|
|
5549
|
-
),
|
|
5550
|
-
iterations
|
|
5551
|
-
};
|
|
5552
|
-
}
|
|
5553
|
-
/**
|
|
5554
|
-
* Matrix inversion using Rust WASM.
|
|
5555
|
-
*/
|
|
5556
|
-
async inverse(a) {
|
|
5557
|
-
const n = a.rows;
|
|
5558
|
-
if (n !== a.cols) {
|
|
5559
|
-
throw new Error("Matrix inversion requires a square matrix");
|
|
5560
|
-
}
|
|
5561
|
-
if (!this.exports) {
|
|
5562
|
-
throw new Error("Rust WASM not loaded");
|
|
5563
|
-
}
|
|
5564
|
-
rustWasmLoader.resetAllocator();
|
|
5565
|
-
const aPtr = rustWasmLoader.writeF64(a.toFloat64Array());
|
|
5566
|
-
const resultPtr = rustWasmLoader.allocF64(n * n);
|
|
5567
|
-
const workPtr = rustWasmLoader.allocF64(n * n);
|
|
5568
|
-
const success = this.exports.laInv(aPtr, n, resultPtr, workPtr);
|
|
5569
|
-
return {
|
|
5570
|
-
inverse: DenseMatrix.fromFlat(n, n, Array.from(rustWasmLoader.readF64(resultPtr, n * n))),
|
|
5571
|
-
singular: success === 0
|
|
5572
|
-
};
|
|
5573
|
-
}
|
|
5574
|
-
/**
|
|
5575
|
-
* FFT using Rust WASM (rustfft).
|
|
5576
|
-
* Data is interleaved complex: [re0, im0, re1, im1, ...].
|
|
5577
|
-
*/
|
|
5578
|
-
fft(data, n, inverse = false) {
|
|
5579
|
-
if (!this.exports) {
|
|
5580
|
-
throw new Error("Rust WASM not loaded");
|
|
5581
|
-
}
|
|
5582
|
-
rustWasmLoader.resetAllocator();
|
|
5583
|
-
const dataPtr = rustWasmLoader.writeF64(data);
|
|
5584
|
-
this.exports.fft(dataPtr, n, inverse ? 1 : 0);
|
|
5585
|
-
return rustWasmLoader.readF64(dataPtr, n * 2);
|
|
5586
|
-
}
|
|
5587
|
-
/**
|
|
5588
|
-
* Update configuration.
|
|
5589
|
-
*/
|
|
5590
|
-
updateConfig(config) {
|
|
5591
|
-
this.config = { ...this.config, ...config };
|
|
5592
|
-
}
|
|
5593
|
-
/**
|
|
5594
|
-
* Get current configuration.
|
|
5595
|
-
*/
|
|
5596
|
-
getConfig() {
|
|
5597
|
-
return { ...this.config };
|
|
5598
|
-
}
|
|
5599
|
-
};
|
|
5600
|
-
var rustWasmBackend = new RustWASMBackend();
|
|
5601
|
-
function createRustWASMBackend(config) {
|
|
5602
|
-
return new RustWASMBackend(config);
|
|
5603
|
-
}
|
|
5604
|
-
|
|
5605
5006
|
// src/config.ts
|
|
5606
|
-
var
|
|
5007
|
+
var DEFAULT_CONFIG3 = {
|
|
5607
5008
|
backends: {
|
|
5608
5009
|
js: {
|
|
5609
5010
|
enabled: true,
|
|
@@ -5651,7 +5052,7 @@ var DEFAULT_CONFIG4 = {
|
|
|
5651
5052
|
precision: "double",
|
|
5652
5053
|
debug: false
|
|
5653
5054
|
};
|
|
5654
|
-
var currentConfig = { ...
|
|
5055
|
+
var currentConfig = { ...DEFAULT_CONFIG3 };
|
|
5655
5056
|
var listeners = /* @__PURE__ */ new Set();
|
|
5656
5057
|
function getConfig() {
|
|
5657
5058
|
return currentConfig;
|
|
@@ -5663,22 +5064,18 @@ function onConfigChange(listener) {
|
|
|
5663
5064
|
|
|
5664
5065
|
// src/backends/register-backends.ts
|
|
5665
5066
|
backendRegistry.register(jsBackend);
|
|
5666
|
-
backendRegistry.register(rustWasmBackend);
|
|
5667
5067
|
backendRegistry.register(wasmBackend);
|
|
5668
5068
|
|
|
5669
5069
|
// src/backends/BackendManager.ts
|
|
5670
5070
|
var DEFAULT_EXTENDED_HINTS = {
|
|
5671
5071
|
...DEFAULT_BACKEND_HINTS,
|
|
5672
5072
|
operationThresholds: {
|
|
5673
|
-
multiply: { wasm: 500, gpu: 5e4
|
|
5674
|
-
decomposition: { wasm: 100, gpu: 1e4
|
|
5675
|
-
transpose: { wasm: 2e3, gpu: 2e5
|
|
5073
|
+
multiply: { wasm: 500, gpu: 5e4 },
|
|
5074
|
+
decomposition: { wasm: 100, gpu: 1e4 },
|
|
5075
|
+
transpose: { wasm: 2e3, gpu: 2e5 }
|
|
5676
5076
|
},
|
|
5677
5077
|
autoSIMD: true,
|
|
5678
|
-
fallbackOnError: true
|
|
5679
|
-
rustWasmThreshold: 1e3,
|
|
5680
|
-
/** Heavy operations that always prefer Rust WASM (faer/rustfft) when available */
|
|
5681
|
-
rustWasmPreferredOps: ["fft", "eig", "svd", "decomposition"]
|
|
5078
|
+
fallbackOnError: true
|
|
5682
5079
|
};
|
|
5683
5080
|
var BackendManager = class {
|
|
5684
5081
|
hints;
|
|
@@ -5756,48 +5153,29 @@ var BackendManager = class {
|
|
|
5756
5153
|
*
|
|
5757
5154
|
* Selection priority:
|
|
5758
5155
|
* 1. Preferred backend (if explicitly set)
|
|
5759
|
-
* 2.
|
|
5760
|
-
* 3. Elements >
|
|
5761
|
-
* 4.
|
|
5762
|
-
* 5. Elements > wasmThreshold -> AS WASM (if loaded)
|
|
5763
|
-
* 6. JS fallback
|
|
5156
|
+
* 2. Elements > gpuThreshold -> GPU (if available)
|
|
5157
|
+
* 3. Elements > wasmThreshold -> AS WASM (if loaded)
|
|
5158
|
+
* 4. JS fallback
|
|
5764
5159
|
*/
|
|
5765
5160
|
selectBackend(elementCount, operation) {
|
|
5766
|
-
const {
|
|
5767
|
-
preferredBackend,
|
|
5768
|
-
operationThresholds,
|
|
5769
|
-
wasmThreshold,
|
|
5770
|
-
gpuThreshold,
|
|
5771
|
-
rustWasmThreshold,
|
|
5772
|
-
rustWasmPreferredOps
|
|
5773
|
-
} = this.hints;
|
|
5161
|
+
const { preferredBackend, operationThresholds, wasmThreshold, gpuThreshold } = this.hints;
|
|
5774
5162
|
if (preferredBackend !== "js" && backendRegistry.has(preferredBackend)) {
|
|
5775
5163
|
const backend = backendRegistry.get(preferredBackend);
|
|
5776
5164
|
if (backend) {
|
|
5777
5165
|
return backend;
|
|
5778
5166
|
}
|
|
5779
5167
|
}
|
|
5780
|
-
if (operation && rustWasmPreferredOps?.includes(operation) && backendRegistry.has("rust-wasm")) {
|
|
5781
|
-
const rustBackend = backendRegistry.get("rust-wasm");
|
|
5782
|
-
if (rustBackend) return rustBackend;
|
|
5783
|
-
}
|
|
5784
5168
|
let wasmThresh = wasmThreshold;
|
|
5785
5169
|
let gpuThresh = gpuThreshold;
|
|
5786
|
-
let rustWasmThresh = rustWasmThreshold;
|
|
5787
5170
|
if (operation && operationThresholds?.[operation]) {
|
|
5788
5171
|
const opThresh = operationThresholds[operation];
|
|
5789
5172
|
if (opThresh?.wasm !== void 0) wasmThresh = opThresh.wasm;
|
|
5790
5173
|
if (opThresh?.gpu !== void 0) gpuThresh = opThresh.gpu;
|
|
5791
|
-
if (opThresh?.rustWasm !== void 0) rustWasmThresh = opThresh.rustWasm;
|
|
5792
5174
|
}
|
|
5793
5175
|
if (elementCount >= gpuThresh && backendRegistry.has("gpu")) {
|
|
5794
5176
|
const gpuBackend = backendRegistry.get("gpu");
|
|
5795
5177
|
if (gpuBackend) return gpuBackend;
|
|
5796
5178
|
}
|
|
5797
|
-
if (elementCount >= rustWasmThresh && backendRegistry.has("rust-wasm")) {
|
|
5798
|
-
const rustBackend = backendRegistry.get("rust-wasm");
|
|
5799
|
-
if (rustBackend) return rustBackend;
|
|
5800
|
-
}
|
|
5801
5179
|
if (elementCount >= wasmThresh && backendRegistry.has("wasm")) {
|
|
5802
5180
|
const wasmBackend2 = backendRegistry.get("wasm");
|
|
5803
5181
|
if (wasmBackend2) return wasmBackend2;
|
|
@@ -6102,7 +5480,6 @@ var BackendManager = class {
|
|
|
6102
5480
|
const backendUsage = {
|
|
6103
5481
|
js: 0,
|
|
6104
5482
|
wasm: 0,
|
|
6105
|
-
"rust-wasm": 0,
|
|
6106
5483
|
gpu: 0,
|
|
6107
5484
|
parallel: 0
|
|
6108
5485
|
};
|
|
@@ -6140,31 +5517,6 @@ var AS_ID_ARRAY_BUFFER2 = 1;
|
|
|
6140
5517
|
var AS_ID_INT32_ARRAY2 = 4;
|
|
6141
5518
|
var AS_ID_FLOAT64_ARRAY2 = 5;
|
|
6142
5519
|
var AS_HEADER_BYTES2 = 12;
|
|
6143
|
-
var RustBumpAllocator = class {
|
|
6144
|
-
offset;
|
|
6145
|
-
base;
|
|
6146
|
-
constructor(baseOffset) {
|
|
6147
|
-
this.base = baseOffset;
|
|
6148
|
-
this.offset = baseOffset;
|
|
6149
|
-
}
|
|
6150
|
-
alloc(byteLength, memory) {
|
|
6151
|
-
const aligned = this.offset + 7 & ~7;
|
|
6152
|
-
const end = aligned + byteLength;
|
|
6153
|
-
const currentBytes = memory.buffer.byteLength;
|
|
6154
|
-
if (end > currentBytes) {
|
|
6155
|
-
const pagesNeeded = Math.ceil((end - currentBytes) / 65536);
|
|
6156
|
-
memory.grow(pagesNeeded);
|
|
6157
|
-
}
|
|
6158
|
-
this.offset = end;
|
|
6159
|
-
return aligned;
|
|
6160
|
-
}
|
|
6161
|
-
reset() {
|
|
6162
|
-
this.offset = this.base;
|
|
6163
|
-
}
|
|
6164
|
-
get highWaterMark() {
|
|
6165
|
-
return this.offset;
|
|
6166
|
-
}
|
|
6167
|
-
};
|
|
6168
5520
|
var WasmLoader = class _WasmLoader {
|
|
6169
5521
|
static instance = null;
|
|
6170
5522
|
wasmModule = null;
|
|
@@ -6172,11 +5524,7 @@ var WasmLoader = class _WasmLoader {
|
|
|
6172
5524
|
loading = null;
|
|
6173
5525
|
isNode;
|
|
6174
5526
|
lastMetrics = null;
|
|
6175
|
-
//
|
|
6176
|
-
allocatorKind = null;
|
|
6177
|
-
// Rust path: a bump allocator anchored at __heap_base.
|
|
6178
|
-
rustAllocator = null;
|
|
6179
|
-
// Memory pool for AS allocations (Rust does not use these pools).
|
|
5527
|
+
// Memory pool for AS allocations.
|
|
6180
5528
|
float64Pool = [];
|
|
6181
5529
|
int32Pool = [];
|
|
6182
5530
|
poolSizeThreshold = 1024 * 1024;
|
|
@@ -6202,7 +5550,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6202
5550
|
}
|
|
6203
5551
|
this.loading = this.loadModule(wasmPath);
|
|
6204
5552
|
this.wasmModule = await this.loading;
|
|
6205
|
-
this.detectAllocatorKind(this.wasmModule);
|
|
6206
5553
|
return this.wasmModule;
|
|
6207
5554
|
}
|
|
6208
5555
|
/**
|
|
@@ -6262,15 +5609,15 @@ var WasmLoader = class _WasmLoader {
|
|
|
6262
5609
|
}
|
|
6263
5610
|
}
|
|
6264
5611
|
/**
|
|
6265
|
-
* Get the WASM binary path
|
|
6266
|
-
*
|
|
6267
|
-
*
|
|
5612
|
+
* Get the WASM binary path. AssemblyScript is the sole WASM backend
|
|
5613
|
+
* (`mathts-as.wasm`); the legacy second toolchain was removed in the
|
|
5614
|
+
* WASM-backend migration (complete 2026-06-26).
|
|
6268
5615
|
*
|
|
6269
5616
|
* The path is resolved relative to this source file's location so it is
|
|
6270
5617
|
* CWD-independent. This file lives at:
|
|
6271
5618
|
* <repo-root>/matrix/src/backends/WasmLoader.ts
|
|
6272
5619
|
* so the repo root is three directories up, and the artifact is at
|
|
6273
|
-
* <repo-root>/lib/wasm/mathts
|
|
5620
|
+
* <repo-root>/lib/wasm/mathts-as.wasm
|
|
6274
5621
|
*
|
|
6275
5622
|
* Both branches use `new URL(relative, import.meta.url)` to resolve a
|
|
6276
5623
|
* file: URL. In Node we convert via `fileURLToPath` (which correctly
|
|
@@ -6278,8 +5625,7 @@ var WasmLoader = class _WasmLoader {
|
|
|
6278
5625
|
* doubled); in the browser we keep the full `.href` for fetch().
|
|
6279
5626
|
*/
|
|
6280
5627
|
async getDefaultWasmPath() {
|
|
6281
|
-
const
|
|
6282
|
-
const wasmFile = useAS ? "mathts-as.wasm" : "mathts.wasm";
|
|
5628
|
+
const wasmFile = "mathts-as.wasm";
|
|
6283
5629
|
if (this.isNode) {
|
|
6284
5630
|
const { resolvePackagedWasm } = await import("./resolve-JRHDDNVQ.js");
|
|
6285
5631
|
const found = await resolvePackagedWasm(import.meta.url, wasmFile);
|
|
@@ -6364,30 +5710,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6364
5710
|
Date
|
|
6365
5711
|
};
|
|
6366
5712
|
}
|
|
6367
|
-
/**
|
|
6368
|
-
* Inspect a freshly loaded module and set up the allocator path.
|
|
6369
|
-
*
|
|
6370
|
-
* Discriminant: the AssemblyScript managed runtime exports `__new`. The
|
|
6371
|
-
* Rust artifact does not. We branch on that exactly once at load time and
|
|
6372
|
-
* cache the result so the hot path doesn't have to re-detect.
|
|
6373
|
-
*/
|
|
6374
|
-
detectAllocatorKind(module) {
|
|
6375
|
-
const hasManagedRuntime = typeof module.__new === "function";
|
|
6376
|
-
if (hasManagedRuntime) {
|
|
6377
|
-
this.allocatorKind = "as";
|
|
6378
|
-
this.rustAllocator = null;
|
|
6379
|
-
return;
|
|
6380
|
-
}
|
|
6381
|
-
this.allocatorKind = "rust";
|
|
6382
|
-
const heapBaseGlobal = module.__heap_base;
|
|
6383
|
-
let heapBase = 65536;
|
|
6384
|
-
if (typeof heapBaseGlobal === "number") {
|
|
6385
|
-
heapBase = heapBaseGlobal;
|
|
6386
|
-
} else if (heapBaseGlobal && typeof heapBaseGlobal.value === "number") {
|
|
6387
|
-
heapBase = heapBaseGlobal.value;
|
|
6388
|
-
}
|
|
6389
|
-
this.rustAllocator = new RustBumpAllocator(heapBase);
|
|
6390
|
-
}
|
|
6391
5713
|
/**
|
|
6392
5714
|
* Get the loaded WASM module
|
|
6393
5715
|
*/
|
|
@@ -6412,28 +5734,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6412
5734
|
isPrecompiled() {
|
|
6413
5735
|
return this.compiledModule !== null;
|
|
6414
5736
|
}
|
|
6415
|
-
/**
|
|
6416
|
-
* Allocator kind (rust/as) chosen at load-time.
|
|
6417
|
-
* Returns null before load() has resolved.
|
|
6418
|
-
*/
|
|
6419
|
-
getAllocatorKind() {
|
|
6420
|
-
return this.allocatorKind;
|
|
6421
|
-
}
|
|
6422
|
-
/**
|
|
6423
|
-
* Reset the Rust bump allocator's high-water mark.
|
|
6424
|
-
*
|
|
6425
|
-
* This is a coarse batch-free for the Rust path: every previously
|
|
6426
|
-
* allocated pointer becomes invalid. Use only when no pointers are still
|
|
6427
|
-
* in flight (e.g. between matrix operations that explicitly free their
|
|
6428
|
-
* own scratch).
|
|
6429
|
-
*
|
|
6430
|
-
* No-op on the AS path; AS uses per-allocation pin/unpin via release().
|
|
6431
|
-
*/
|
|
6432
|
-
resetRustAllocator() {
|
|
6433
|
-
if (this.allocatorKind === "rust" && this.rustAllocator) {
|
|
6434
|
-
this.rustAllocator.reset();
|
|
6435
|
-
}
|
|
6436
|
-
}
|
|
6437
5737
|
/**
|
|
6438
5738
|
* Get loading performance metrics
|
|
6439
5739
|
*/
|
|
@@ -6443,35 +5743,48 @@ var WasmLoader = class _WasmLoader {
|
|
|
6443
5743
|
// ===========================================================================
|
|
6444
5744
|
// Allocation API
|
|
6445
5745
|
// ---------------------------------------------------------------------------
|
|
6446
|
-
//
|
|
6447
|
-
//
|
|
5746
|
+
// The returned handle's `ptr` is the header pointer to pass to WASM
|
|
5747
|
+
// functions (AssemblyScript managed runtime).
|
|
6448
5748
|
// ===========================================================================
|
|
6449
5749
|
/**
|
|
6450
5750
|
* Allocate Float64Array in WASM memory and copy `data` into it.
|
|
6451
|
-
* Uses memory pooling
|
|
5751
|
+
* Uses memory pooling.
|
|
6452
5752
|
*/
|
|
6453
5753
|
allocateFloat64Array(data) {
|
|
6454
5754
|
const module = this.wasmModule;
|
|
6455
5755
|
if (!module) throw new Error("WASM module not loaded");
|
|
6456
5756
|
const length = data.length;
|
|
6457
|
-
if (this.allocatorKind === "rust") {
|
|
6458
|
-
const alloc2 = this.allocateRustFloat64(module, length);
|
|
6459
|
-
alloc2.array.set(data);
|
|
6460
|
-
return alloc2;
|
|
6461
|
-
}
|
|
6462
5757
|
const alloc = this.allocateAsFloat64(module, length);
|
|
6463
5758
|
alloc.array.set(data);
|
|
6464
5759
|
return alloc;
|
|
6465
5760
|
}
|
|
5761
|
+
/**
|
|
5762
|
+
* Decode a managed Float64Array RETURNED by an AssemblyScript export
|
|
5763
|
+
* (e.g. `matrix_svd`, `matrix_eig_symmetric`) into a fresh JS copy.
|
|
5764
|
+
*
|
|
5765
|
+
* AS exports that return a `Float64Array` hand back the typed-array
|
|
5766
|
+
* *header* pointer. The header is a 12-byte block laid out as
|
|
5767
|
+
* `[buffer, dataStart, byteLength]` (little-endian u32s) — the same shape
|
|
5768
|
+
* the loader writes in `makeAsFloat64`. We read `dataStart`/`byteLength`
|
|
5769
|
+
* and copy the data region out so it survives any later reuse of WASM
|
|
5770
|
+
* memory.
|
|
5771
|
+
*/
|
|
5772
|
+
readReturnedFloat64Array(headerPtr) {
|
|
5773
|
+
const module = this.wasmModule;
|
|
5774
|
+
if (!module) throw new Error("WASM module not loaded");
|
|
5775
|
+
const hdr = headerPtr >>> 0;
|
|
5776
|
+
const dv = new DataView(module.memory.buffer);
|
|
5777
|
+
const dataStart = dv.getUint32(hdr + 4, true);
|
|
5778
|
+
const byteLength = dv.getUint32(hdr + 8, true);
|
|
5779
|
+
const view = new Float64Array(module.memory.buffer, dataStart, byteLength >>> 3);
|
|
5780
|
+
return new Float64Array(view);
|
|
5781
|
+
}
|
|
6466
5782
|
/**
|
|
6467
5783
|
* Allocate Float64Array without copying data (for output buffers)
|
|
6468
5784
|
*/
|
|
6469
5785
|
allocateFloat64ArrayEmpty(length) {
|
|
6470
5786
|
const module = this.wasmModule;
|
|
6471
5787
|
if (!module) throw new Error("WASM module not loaded");
|
|
6472
|
-
if (this.allocatorKind === "rust") {
|
|
6473
|
-
return this.allocateRustFloat64(module, length);
|
|
6474
|
-
}
|
|
6475
5788
|
return this.allocateAsFloat64(module, length);
|
|
6476
5789
|
}
|
|
6477
5790
|
/**
|
|
@@ -6481,11 +5794,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6481
5794
|
const module = this.wasmModule;
|
|
6482
5795
|
if (!module) throw new Error("WASM module not loaded");
|
|
6483
5796
|
const length = data.length;
|
|
6484
|
-
if (this.allocatorKind === "rust") {
|
|
6485
|
-
const alloc2 = this.allocateRustInt32(module, length);
|
|
6486
|
-
alloc2.array.set(data);
|
|
6487
|
-
return alloc2;
|
|
6488
|
-
}
|
|
6489
5797
|
const alloc = this.allocateAsInt32(module, length);
|
|
6490
5798
|
alloc.array.set(data);
|
|
6491
5799
|
return alloc;
|
|
@@ -6496,29 +5804,9 @@ var WasmLoader = class _WasmLoader {
|
|
|
6496
5804
|
allocateInt32ArrayEmpty(length) {
|
|
6497
5805
|
const module = this.wasmModule;
|
|
6498
5806
|
if (!module) throw new Error("WASM module not loaded");
|
|
6499
|
-
if (this.allocatorKind === "rust") {
|
|
6500
|
-
return this.allocateRustInt32(module, length);
|
|
6501
|
-
}
|
|
6502
5807
|
return this.allocateAsInt32(module, length);
|
|
6503
5808
|
}
|
|
6504
|
-
// ----
|
|
6505
|
-
allocateRustFloat64(module, length) {
|
|
6506
|
-
const allocator = this.rustAllocator;
|
|
6507
|
-
if (!allocator) throw new Error("Rust allocator not initialized");
|
|
6508
|
-
const byteLength = length * 8;
|
|
6509
|
-
const ptr = allocator.alloc(byteLength, module.memory);
|
|
6510
|
-
const array = new Float64Array(module.memory.buffer, ptr, length);
|
|
6511
|
-
return { kind: "rust", ptr, dataPtr: ptr, array, length };
|
|
6512
|
-
}
|
|
6513
|
-
allocateRustInt32(module, length) {
|
|
6514
|
-
const allocator = this.rustAllocator;
|
|
6515
|
-
if (!allocator) throw new Error("Rust allocator not initialized");
|
|
6516
|
-
const byteLength = length * 4;
|
|
6517
|
-
const ptr = allocator.alloc(byteLength, module.memory);
|
|
6518
|
-
const array = new Int32Array(module.memory.buffer, ptr, length);
|
|
6519
|
-
return { kind: "rust", ptr, dataPtr: ptr, array, length };
|
|
6520
|
-
}
|
|
6521
|
-
// ---- AS path (managed runtime + header pointers) -----------------------
|
|
5809
|
+
// ---- AS managed runtime (header pointers) ------------------------------
|
|
6522
5810
|
allocateAsFloat64(module, length) {
|
|
6523
5811
|
const byteLength = length * 8;
|
|
6524
5812
|
if (byteLength <= this.poolSizeThreshold) {
|
|
@@ -6526,7 +5814,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6526
5814
|
if (recycled) {
|
|
6527
5815
|
const array = new Float64Array(module.memory.buffer, recycled.dataPtr, length);
|
|
6528
5816
|
return {
|
|
6529
|
-
kind: "as",
|
|
6530
5817
|
ptr: recycled.ptr,
|
|
6531
5818
|
dataPtr: recycled.dataPtr,
|
|
6532
5819
|
array,
|
|
@@ -6543,7 +5830,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6543
5830
|
if (recycled) {
|
|
6544
5831
|
const array = new Int32Array(module.memory.buffer, recycled.dataPtr, length);
|
|
6545
5832
|
return {
|
|
6546
|
-
kind: "as",
|
|
6547
5833
|
ptr: recycled.ptr,
|
|
6548
5834
|
dataPtr: recycled.dataPtr,
|
|
6549
5835
|
array,
|
|
@@ -6563,7 +5849,7 @@ var WasmLoader = class _WasmLoader {
|
|
|
6563
5849
|
dv.setUint32(headerPtr + 4, bufferPtr, true);
|
|
6564
5850
|
dv.setUint32(headerPtr + 8, byteLength, true);
|
|
6565
5851
|
const array = new Float64Array(module.memory.buffer, bufferPtr, length);
|
|
6566
|
-
return {
|
|
5852
|
+
return { ptr: headerPtr, dataPtr: bufferPtr, array, length };
|
|
6567
5853
|
}
|
|
6568
5854
|
makeAsInt32(module, length) {
|
|
6569
5855
|
const byteLength = length * 4;
|
|
@@ -6575,7 +5861,7 @@ var WasmLoader = class _WasmLoader {
|
|
|
6575
5861
|
dv.setUint32(headerPtr + 4, bufferPtr, true);
|
|
6576
5862
|
dv.setUint32(headerPtr + 8, byteLength, true);
|
|
6577
5863
|
const array = new Int32Array(module.memory.buffer, bufferPtr, length);
|
|
6578
|
-
return {
|
|
5864
|
+
return { ptr: headerPtr, dataPtr: bufferPtr, array, length };
|
|
6579
5865
|
}
|
|
6580
5866
|
/**
|
|
6581
5867
|
* Find a pool entry whose data region is large enough; returns null when
|
|
@@ -6605,9 +5891,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6605
5891
|
* automatically.
|
|
6606
5892
|
*/
|
|
6607
5893
|
release(ptr, isFloat64 = true) {
|
|
6608
|
-
if (this.allocatorKind === "rust") {
|
|
6609
|
-
return;
|
|
6610
|
-
}
|
|
6611
5894
|
const pool = isFloat64 ? this.float64Pool : this.int32Pool;
|
|
6612
5895
|
const entry = pool.find((e) => e.ptr === ptr);
|
|
6613
5896
|
if (entry) {
|
|
@@ -6617,17 +5900,11 @@ var WasmLoader = class _WasmLoader {
|
|
|
6617
5900
|
this.free(ptr);
|
|
6618
5901
|
}
|
|
6619
5902
|
/**
|
|
6620
|
-
* Free allocated memory (immediate, bypasses pool).
|
|
6621
|
-
*
|
|
6622
|
-
* - Rust path: no-op (use `resetRustAllocator`).
|
|
6623
|
-
* - AS path: unpin the header pointer.
|
|
5903
|
+
* Free allocated memory (immediate, bypasses pool): unpin the header pointer.
|
|
6624
5904
|
*/
|
|
6625
5905
|
free(ptr) {
|
|
6626
5906
|
const module = this.wasmModule;
|
|
6627
5907
|
if (!module) return;
|
|
6628
|
-
if (this.allocatorKind === "rust") {
|
|
6629
|
-
return;
|
|
6630
|
-
}
|
|
6631
5908
|
this.float64Pool = this.float64Pool.filter((e) => e.ptr !== ptr);
|
|
6632
5909
|
this.int32Pool = this.int32Pool.filter((e) => e.ptr !== ptr);
|
|
6633
5910
|
if (typeof module.__unpin === "function") {
|
|
@@ -6640,7 +5917,7 @@ var WasmLoader = class _WasmLoader {
|
|
|
6640
5917
|
clearPool() {
|
|
6641
5918
|
const module = this.wasmModule;
|
|
6642
5919
|
if (!module) return;
|
|
6643
|
-
if (
|
|
5920
|
+
if (typeof module.__unpin === "function") {
|
|
6644
5921
|
for (const entry of this.float64Pool) {
|
|
6645
5922
|
module.__unpin(entry.ptr);
|
|
6646
5923
|
}
|
|
@@ -6650,9 +5927,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6650
5927
|
}
|
|
6651
5928
|
this.float64Pool = [];
|
|
6652
5929
|
this.int32Pool = [];
|
|
6653
|
-
if (this.allocatorKind === "rust" && this.rustAllocator) {
|
|
6654
|
-
this.rustAllocator.reset();
|
|
6655
|
-
}
|
|
6656
5930
|
}
|
|
6657
5931
|
/**
|
|
6658
5932
|
* Get pool statistics
|
|
@@ -6676,12 +5950,12 @@ var WasmLoader = class _WasmLoader {
|
|
|
6676
5950
|
};
|
|
6677
5951
|
}
|
|
6678
5952
|
/**
|
|
6679
|
-
* Run garbage collection
|
|
5953
|
+
* Run garbage collection.
|
|
6680
5954
|
*/
|
|
6681
5955
|
collect() {
|
|
6682
5956
|
const module = this.wasmModule;
|
|
6683
5957
|
if (!module) return;
|
|
6684
|
-
if (
|
|
5958
|
+
if (typeof module.__collect === "function") {
|
|
6685
5959
|
module.__collect();
|
|
6686
5960
|
}
|
|
6687
5961
|
}
|
|
@@ -6694,8 +5968,6 @@ var WasmLoader = class _WasmLoader {
|
|
|
6694
5968
|
this.compiledModule = null;
|
|
6695
5969
|
this.loading = null;
|
|
6696
5970
|
this.lastMetrics = null;
|
|
6697
|
-
this.allocatorKind = null;
|
|
6698
|
-
this.rustAllocator = null;
|
|
6699
5971
|
}
|
|
6700
5972
|
};
|
|
6701
5973
|
var wasmLoader = WasmLoader.getInstance();
|
|
@@ -6703,69 +5975,6 @@ var wasmLoader = WasmLoader.getInstance();
|
|
|
6703
5975
|
// src/operations/svd.ts
|
|
6704
5976
|
var DEFAULT_MAX_ITERATIONS = 1e3;
|
|
6705
5977
|
var DEFAULT_TOLERANCE = 1e-12;
|
|
6706
|
-
function eye(n) {
|
|
6707
|
-
const I = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
6708
|
-
for (let i = 0; i < n; i++) {
|
|
6709
|
-
I[i][i] = 1;
|
|
6710
|
-
}
|
|
6711
|
-
return I;
|
|
6712
|
-
}
|
|
6713
|
-
function cloneMatrix(A) {
|
|
6714
|
-
return A.map((row2) => [...row2]);
|
|
6715
|
-
}
|
|
6716
|
-
function householder(x) {
|
|
6717
|
-
const n = x.length;
|
|
6718
|
-
let sigma = 0;
|
|
6719
|
-
for (let i = 1; i < n; i++) {
|
|
6720
|
-
sigma += x[i] * x[i];
|
|
6721
|
-
}
|
|
6722
|
-
const v = [...x];
|
|
6723
|
-
v[0] = 1;
|
|
6724
|
-
if (sigma === 0 && x[0] >= 0) {
|
|
6725
|
-
return { v, beta: 0 };
|
|
6726
|
-
} else if (sigma === 0 && x[0] < 0) {
|
|
6727
|
-
return { v, beta: -2 };
|
|
6728
|
-
} else {
|
|
6729
|
-
const mu = Math.sqrt(x[0] * x[0] + sigma);
|
|
6730
|
-
if (x[0] <= 0) {
|
|
6731
|
-
v[0] = x[0] - mu;
|
|
6732
|
-
} else {
|
|
6733
|
-
v[0] = -sigma / (x[0] + mu);
|
|
6734
|
-
}
|
|
6735
|
-
const beta = 2 * v[0] * v[0] / (sigma + v[0] * v[0]);
|
|
6736
|
-
const v0 = v[0];
|
|
6737
|
-
for (let i = 0; i < n; i++) {
|
|
6738
|
-
v[i] /= v0;
|
|
6739
|
-
}
|
|
6740
|
-
return { v, beta };
|
|
6741
|
-
}
|
|
6742
|
-
}
|
|
6743
|
-
function applyHouseholderLeft(A, v, beta, startRow, startCol, _endRow, endCol) {
|
|
6744
|
-
const len = v.length;
|
|
6745
|
-
for (let j = startCol; j < endCol; j++) {
|
|
6746
|
-
let dot = 0;
|
|
6747
|
-
for (let i = 0; i < len; i++) {
|
|
6748
|
-
dot += v[i] * A[startRow + i][j];
|
|
6749
|
-
}
|
|
6750
|
-
dot *= beta;
|
|
6751
|
-
for (let i = 0; i < len; i++) {
|
|
6752
|
-
A[startRow + i][j] -= dot * v[i];
|
|
6753
|
-
}
|
|
6754
|
-
}
|
|
6755
|
-
}
|
|
6756
|
-
function applyHouseholderRight(A, v, beta, startRow, startCol, endRow, _endCol) {
|
|
6757
|
-
const len = v.length;
|
|
6758
|
-
for (let i = startRow; i < endRow; i++) {
|
|
6759
|
-
let dot = 0;
|
|
6760
|
-
for (let j = 0; j < len; j++) {
|
|
6761
|
-
dot += A[i][startCol + j] * v[j];
|
|
6762
|
-
}
|
|
6763
|
-
dot *= beta;
|
|
6764
|
-
for (let j = 0; j < len; j++) {
|
|
6765
|
-
A[i][startCol + j] -= dot * v[j];
|
|
6766
|
-
}
|
|
6767
|
-
}
|
|
6768
|
-
}
|
|
6769
5978
|
function bidiagonalize(A) {
|
|
6770
5979
|
const m = A.length;
|
|
6771
5980
|
const n = A[0].length;
|
|
@@ -6781,8 +5990,8 @@ function bidiagonalize(A) {
|
|
|
6781
5990
|
}
|
|
6782
5991
|
const { v, beta } = householder(col);
|
|
6783
5992
|
if (beta !== 0) {
|
|
6784
|
-
applyHouseholderLeft(B2, v, beta, k, k
|
|
6785
|
-
applyHouseholderRight(U, v, beta, 0, k
|
|
5993
|
+
applyHouseholderLeft(B2, v, beta, k, k);
|
|
5994
|
+
applyHouseholderRight(U, v, beta, 0, k);
|
|
6786
5995
|
}
|
|
6787
5996
|
}
|
|
6788
5997
|
if (k < n - 2) {
|
|
@@ -6792,8 +6001,8 @@ function bidiagonalize(A) {
|
|
|
6792
6001
|
}
|
|
6793
6002
|
const { v, beta } = householder(row2);
|
|
6794
6003
|
if (beta !== 0) {
|
|
6795
|
-
applyHouseholderRight(B2, v, beta, k, k + 1
|
|
6796
|
-
applyHouseholderRight(V, v, beta, 0, k + 1
|
|
6004
|
+
applyHouseholderRight(B2, v, beta, k, k + 1);
|
|
6005
|
+
applyHouseholderRight(V, v, beta, 0, k + 1);
|
|
6797
6006
|
}
|
|
6798
6007
|
}
|
|
6799
6008
|
}
|
|
@@ -7055,19 +6264,6 @@ function normFro(matrix2) {
|
|
|
7055
6264
|
|
|
7056
6265
|
// src/operations/eig-wasm.ts
|
|
7057
6266
|
var WASM_EIG_THRESHOLD = 8;
|
|
7058
|
-
function isSymmetric(matrix2, tolerance = 1e-10) {
|
|
7059
|
-
const n = matrix2.length;
|
|
7060
|
-
if (n === 0) return true;
|
|
7061
|
-
if (matrix2[0].length !== n) return false;
|
|
7062
|
-
for (let i = 0; i < n; i++) {
|
|
7063
|
-
for (let j = i + 1; j < n; j++) {
|
|
7064
|
-
if (Math.abs(matrix2[i][j] - matrix2[j][i]) > tolerance) {
|
|
7065
|
-
return false;
|
|
7066
|
-
}
|
|
7067
|
-
}
|
|
7068
|
-
}
|
|
7069
|
-
return true;
|
|
7070
|
-
}
|
|
7071
6267
|
function flattenMatrix(matrix2) {
|
|
7072
6268
|
const n = matrix2.length;
|
|
7073
6269
|
const flat2 = new Float64Array(n * n);
|
|
@@ -7088,72 +6284,81 @@ async function eigWasm(matrix2, options) {
|
|
|
7088
6284
|
throw new Error("Matrix must be square");
|
|
7089
6285
|
}
|
|
7090
6286
|
}
|
|
7091
|
-
|
|
6287
|
+
let module = wasmLoader.getModule();
|
|
6288
|
+
if (!module) {
|
|
6289
|
+
try {
|
|
6290
|
+
module = await wasmLoader.load();
|
|
6291
|
+
} catch {
|
|
6292
|
+
module = null;
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
7092
6295
|
const symmetric = isSymmetric(matrix2);
|
|
7093
|
-
|
|
6296
|
+
const useSymWasm = !!module && n >= WASM_EIG_THRESHOLD && symmetric && typeof module.matrix_eig_symmetric === "function";
|
|
6297
|
+
const useGenWasm = !!module && n >= WASM_EIG_THRESHOLD && !symmetric && typeof module.matrix_eig_general === "function";
|
|
6298
|
+
if (!useSymWasm && !useGenWasm) {
|
|
7094
6299
|
return eig(matrix2, options);
|
|
7095
6300
|
}
|
|
7096
|
-
const tolerance = options?.tolerance ?? 1e-12;
|
|
7097
6301
|
const computeVectors = options?.computeVectors ?? true;
|
|
6302
|
+
const identityVectors = () => Array.from({ length: n }, (_, i) => {
|
|
6303
|
+
const row2 = new Array(n).fill(0);
|
|
6304
|
+
row2[i] = 1;
|
|
6305
|
+
return row2;
|
|
6306
|
+
});
|
|
7098
6307
|
const flatMatrix = flattenMatrix(matrix2);
|
|
7099
6308
|
const matrixAlloc = wasmLoader.allocateFloat64Array(Array.from(flatMatrix));
|
|
7100
|
-
const eigenvaluesAlloc = wasmLoader.allocateFloat64ArrayEmpty(n);
|
|
7101
|
-
const eigenvectorsAlloc = computeVectors ? wasmLoader.allocateFloat64ArrayEmpty(n * n) : { ptr: 0, array: new Float64Array(0) };
|
|
7102
|
-
const workAlloc = wasmLoader.allocateFloat64ArrayEmpty(2 * n);
|
|
7103
6309
|
try {
|
|
7104
|
-
|
|
7105
|
-
matrixAlloc.ptr,
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
6310
|
+
if (useSymWasm) {
|
|
6311
|
+
const packedPtr2 = module.matrix_eig_symmetric(matrixAlloc.ptr, n);
|
|
6312
|
+
const packed2 = wasmLoader.readReturnedFloat64Array(packedPtr2);
|
|
6313
|
+
if (packed2.length < n + n * n) {
|
|
6314
|
+
return eig(matrix2, options);
|
|
6315
|
+
}
|
|
6316
|
+
const values2 = [];
|
|
6317
|
+
for (let j = 0; j < n; j++) {
|
|
6318
|
+
values2.push({ re: packed2[j], im: 0 });
|
|
6319
|
+
}
|
|
6320
|
+
let vectors2;
|
|
6321
|
+
if (computeVectors) {
|
|
6322
|
+
vectors2 = [];
|
|
6323
|
+
for (let j = 0; j < n; j++) {
|
|
6324
|
+
const vec = [];
|
|
6325
|
+
for (let i = 0; i < n; i++) {
|
|
6326
|
+
vec.push(packed2[n + i * n + j]);
|
|
6327
|
+
}
|
|
6328
|
+
vectors2.push(vec);
|
|
6329
|
+
}
|
|
6330
|
+
} else {
|
|
6331
|
+
vectors2 = identityVectors();
|
|
6332
|
+
}
|
|
6333
|
+
return { values: values2, vectors: vectors2, isSymmetric: true };
|
|
6334
|
+
}
|
|
6335
|
+
const packedPtr = module.matrix_eig_general(matrixAlloc.ptr, n);
|
|
6336
|
+
const packed = wasmLoader.readReturnedFloat64Array(packedPtr);
|
|
6337
|
+
if (packed.length < 2 * n + n * n) {
|
|
7113
6338
|
return eig(matrix2, options);
|
|
7114
6339
|
}
|
|
7115
|
-
const module = wasmLoader.getModule();
|
|
7116
|
-
const eigenvaluesResult = new Float64Array(module.memory.buffer, eigenvaluesAlloc.ptr, n);
|
|
7117
6340
|
const values = [];
|
|
7118
|
-
for (let
|
|
7119
|
-
values.push({ re:
|
|
6341
|
+
for (let j = 0; j < n; j++) {
|
|
6342
|
+
values.push({ re: packed[j], im: packed[n + j] });
|
|
7120
6343
|
}
|
|
7121
6344
|
let vectors;
|
|
7122
6345
|
if (computeVectors) {
|
|
7123
|
-
const eigenvectorsResult = new Float64Array(
|
|
7124
|
-
module.memory.buffer,
|
|
7125
|
-
eigenvectorsAlloc.ptr,
|
|
7126
|
-
n * n
|
|
7127
|
-
);
|
|
7128
6346
|
vectors = [];
|
|
7129
|
-
for (let
|
|
6347
|
+
for (let j = 0; j < n; j++) {
|
|
7130
6348
|
const vec = [];
|
|
7131
|
-
for (let
|
|
7132
|
-
vec.push(
|
|
6349
|
+
for (let i = 0; i < n; i++) {
|
|
6350
|
+
vec.push(packed[2 * n + i * n + j]);
|
|
7133
6351
|
}
|
|
7134
6352
|
vectors.push(vec);
|
|
7135
6353
|
}
|
|
7136
6354
|
} else {
|
|
7137
|
-
vectors =
|
|
7138
|
-
const row2 = new Array(n).fill(0);
|
|
7139
|
-
row2[i] = 1;
|
|
7140
|
-
return row2;
|
|
7141
|
-
});
|
|
6355
|
+
vectors = identityVectors();
|
|
7142
6356
|
}
|
|
7143
|
-
return {
|
|
7144
|
-
values,
|
|
7145
|
-
vectors,
|
|
7146
|
-
isSymmetric: true
|
|
7147
|
-
};
|
|
6357
|
+
return { values, vectors, isSymmetric: false };
|
|
7148
6358
|
} catch {
|
|
7149
6359
|
return eig(matrix2, options);
|
|
7150
6360
|
} finally {
|
|
7151
6361
|
wasmLoader.free(matrixAlloc.ptr);
|
|
7152
|
-
wasmLoader.free(eigenvaluesAlloc.ptr);
|
|
7153
|
-
if (computeVectors && eigenvectorsAlloc.ptr !== 0) {
|
|
7154
|
-
wasmLoader.free(eigenvectorsAlloc.ptr);
|
|
7155
|
-
}
|
|
7156
|
-
wasmLoader.free(workAlloc.ptr);
|
|
7157
6362
|
}
|
|
7158
6363
|
}
|
|
7159
6364
|
async function eigvalsWasm(matrix2, options) {
|
|
@@ -7162,33 +6367,29 @@ async function eigvalsWasm(matrix2, options) {
|
|
|
7162
6367
|
}
|
|
7163
6368
|
async function spectralRadiusWasm(matrix2, options) {
|
|
7164
6369
|
const n = matrix2.length;
|
|
7165
|
-
|
|
7166
|
-
if (!
|
|
7167
|
-
|
|
6370
|
+
let module = wasmLoader.getModule();
|
|
6371
|
+
if (!module) {
|
|
6372
|
+
try {
|
|
6373
|
+
module = await wasmLoader.load();
|
|
6374
|
+
} catch {
|
|
6375
|
+
module = null;
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
if (!module || n < WASM_EIG_THRESHOLD || typeof module.matrix_spectral_radius !== "function") {
|
|
6379
|
+
const { powerIteration: powerIteration2 } = await import("./eig-G72TLEBA.js");
|
|
7168
6380
|
const result = powerIteration2(matrix2, options);
|
|
7169
6381
|
return Math.abs(result.value);
|
|
7170
6382
|
}
|
|
7171
|
-
const maxIterations = options?.maxIterations ?? 1e3;
|
|
7172
|
-
const tolerance = options?.tolerance ?? 1e-12;
|
|
7173
6383
|
const flatMatrix = flattenMatrix(matrix2);
|
|
7174
6384
|
const matrixAlloc = wasmLoader.allocateFloat64Array(Array.from(flatMatrix));
|
|
7175
|
-
const workAlloc = wasmLoader.allocateFloat64ArrayEmpty(2 * n);
|
|
7176
6385
|
try {
|
|
7177
|
-
|
|
7178
|
-
matrixAlloc.ptr,
|
|
7179
|
-
n,
|
|
7180
|
-
workAlloc.ptr,
|
|
7181
|
-
maxIterations,
|
|
7182
|
-
tolerance
|
|
7183
|
-
);
|
|
7184
|
-
return radius;
|
|
6386
|
+
return module.matrix_spectral_radius(matrixAlloc.ptr, n);
|
|
7185
6387
|
} catch {
|
|
7186
|
-
const { powerIteration: powerIteration2 } = await import("./eig-
|
|
6388
|
+
const { powerIteration: powerIteration2 } = await import("./eig-G72TLEBA.js");
|
|
7187
6389
|
const result = powerIteration2(matrix2, options);
|
|
7188
6390
|
return Math.abs(result.value);
|
|
7189
6391
|
} finally {
|
|
7190
6392
|
wasmLoader.free(matrixAlloc.ptr);
|
|
7191
|
-
wasmLoader.free(workAlloc.ptr);
|
|
7192
6393
|
}
|
|
7193
6394
|
}
|
|
7194
6395
|
|
|
@@ -7217,30 +6418,31 @@ async function svdWasm(matrix2, options) {
|
|
|
7217
6418
|
}
|
|
7218
6419
|
const k = Math.min(m, n);
|
|
7219
6420
|
const rankTolerance = options?.rankTolerance ?? 1e-10;
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
6421
|
+
let module = wasmLoader.getModule();
|
|
6422
|
+
if (!module) {
|
|
6423
|
+
try {
|
|
6424
|
+
module = await wasmLoader.load();
|
|
6425
|
+
} catch {
|
|
6426
|
+
module = null;
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6429
|
+
if (!module || typeof module.matrix_svd !== "function") {
|
|
7224
6430
|
return toThin(svd(matrix2, options), k, rankTolerance);
|
|
7225
6431
|
}
|
|
6432
|
+
const flat2 = new Float64Array(m * n);
|
|
6433
|
+
for (let i = 0; i < m; i++) {
|
|
6434
|
+
for (let j = 0; j < n; j++) flat2[i * n + j] = matrix2[i][j];
|
|
6435
|
+
}
|
|
6436
|
+
const aAlloc = wasmLoader.allocateFloat64Array(flat2);
|
|
7226
6437
|
try {
|
|
7227
|
-
|
|
7228
|
-
const
|
|
7229
|
-
|
|
7230
|
-
for (let j = 0; j < n; j++) flat2[i * n + j] = matrix2[i][j];
|
|
7231
|
-
}
|
|
7232
|
-
const aPtr = loader.writeF64(flat2);
|
|
7233
|
-
const uPtr = loader.allocF64(m * k);
|
|
7234
|
-
const sPtr = loader.allocF64(k);
|
|
7235
|
-
const vPtr = loader.allocF64(n * k);
|
|
7236
|
-
const workPtr = loader.allocF64(wasm.svdWorkSize(m, n));
|
|
7237
|
-
const status = wasm.svd(aPtr, m, n, uPtr, sPtr, vPtr, workPtr);
|
|
7238
|
-
if (status < 0) {
|
|
6438
|
+
const packedPtr = module.matrix_svd(aAlloc.ptr, m, n);
|
|
6439
|
+
const packed = wasmLoader.readReturnedFloat64Array(packedPtr);
|
|
6440
|
+
if (packed.length < m * k + k + n * k) {
|
|
7239
6441
|
return toThin(svd(matrix2, options), k, rankTolerance);
|
|
7240
6442
|
}
|
|
7241
|
-
const uFlat =
|
|
7242
|
-
const sFlat =
|
|
7243
|
-
const vFlat =
|
|
6443
|
+
const uFlat = packed.subarray(0, m * k);
|
|
6444
|
+
const sFlat = packed.subarray(m * k, m * k + k);
|
|
6445
|
+
const vFlat = packed.subarray(m * k + k, m * k + k + n * k);
|
|
7244
6446
|
const U = [];
|
|
7245
6447
|
for (let i = 0; i < m; i++) {
|
|
7246
6448
|
U.push(Array.from(uFlat.subarray(i * k, i * k + k)));
|
|
@@ -7253,6 +6455,8 @@ async function svdWasm(matrix2, options) {
|
|
|
7253
6455
|
return { U, S, V, rank: estimateRank(S, rankTolerance) };
|
|
7254
6456
|
} catch {
|
|
7255
6457
|
return toThin(svd(matrix2, options), k, rankTolerance);
|
|
6458
|
+
} finally {
|
|
6459
|
+
wasmLoader.free(aAlloc.ptr);
|
|
7256
6460
|
}
|
|
7257
6461
|
}
|
|
7258
6462
|
|
|
@@ -7499,55 +6703,6 @@ var B = [
|
|
|
7499
6703
|
182,
|
|
7500
6704
|
1
|
|
7501
6705
|
];
|
|
7502
|
-
function eye2(n) {
|
|
7503
|
-
return Array.from(
|
|
7504
|
-
{ length: n },
|
|
7505
|
-
(_, i) => Array.from({ length: n }, (_2, j) => i === j ? 1 : 0)
|
|
7506
|
-
);
|
|
7507
|
-
}
|
|
7508
|
-
function matMul(A, B2) {
|
|
7509
|
-
const m = A.length;
|
|
7510
|
-
const p = A[0].length;
|
|
7511
|
-
const n = B2[0].length;
|
|
7512
|
-
const C = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
7513
|
-
for (let i = 0; i < m; i++) {
|
|
7514
|
-
for (let k = 0; k < p; k++) {
|
|
7515
|
-
const aik = A[i][k];
|
|
7516
|
-
if (aik === 0) continue;
|
|
7517
|
-
for (let j = 0; j < n; j++) C[i][j] += aik * B2[k][j];
|
|
7518
|
-
}
|
|
7519
|
-
}
|
|
7520
|
-
return C;
|
|
7521
|
-
}
|
|
7522
|
-
function matAdd(A, B2) {
|
|
7523
|
-
const n = A.length;
|
|
7524
|
-
const r = Array.from(
|
|
7525
|
-
{ length: n },
|
|
7526
|
-
(_, i) => Array.from({ length: n }, (_2, j) => A[i][j] + B2[i][j])
|
|
7527
|
-
);
|
|
7528
|
-
return r;
|
|
7529
|
-
}
|
|
7530
|
-
function matSub(A, B2) {
|
|
7531
|
-
const n = A.length;
|
|
7532
|
-
return Array.from(
|
|
7533
|
-
{ length: n },
|
|
7534
|
-
(_, i) => Array.from({ length: n }, (_2, j) => A[i][j] - B2[i][j])
|
|
7535
|
-
);
|
|
7536
|
-
}
|
|
7537
|
-
function matScale(A, c) {
|
|
7538
|
-
return A.map((row2) => row2.map((v) => v * c));
|
|
7539
|
-
}
|
|
7540
|
-
function norm1(A) {
|
|
7541
|
-
const m = A.length;
|
|
7542
|
-
const n = A[0].length;
|
|
7543
|
-
let maxColSum = 0;
|
|
7544
|
-
for (let j = 0; j < n; j++) {
|
|
7545
|
-
let colSum = 0;
|
|
7546
|
-
for (let i = 0; i < m; i++) colSum += Math.abs(A[i][j]);
|
|
7547
|
-
if (colSum > maxColSum) maxColSum = colSum;
|
|
7548
|
-
}
|
|
7549
|
-
return maxColSum;
|
|
7550
|
-
}
|
|
7551
6706
|
function matSolve(M, N) {
|
|
7552
6707
|
const n = M.length;
|
|
7553
6708
|
const cols = N[0].length;
|
|
@@ -7576,7 +6731,7 @@ function matSolve(M, N) {
|
|
|
7576
6731
|
}
|
|
7577
6732
|
function pade13(A) {
|
|
7578
6733
|
const n = A.length;
|
|
7579
|
-
const I =
|
|
6734
|
+
const I = eye(n);
|
|
7580
6735
|
const A2 = matMul(A, A);
|
|
7581
6736
|
const A4 = matMul(A2, A2);
|
|
7582
6737
|
const A6 = matMul(A2, A4);
|
|
@@ -7637,63 +6792,18 @@ init_DenseMatrix();
|
|
|
7637
6792
|
|
|
7638
6793
|
// src/operations/schur.ts
|
|
7639
6794
|
init_DenseMatrix();
|
|
7640
|
-
function eye3(n) {
|
|
7641
|
-
return Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_2, j) => i === j ? 1 : 0));
|
|
7642
|
-
}
|
|
7643
|
-
function cloneMatrix2(A) {
|
|
7644
|
-
return A.map((row2) => [...row2]);
|
|
7645
|
-
}
|
|
7646
|
-
function householder2(x) {
|
|
7647
|
-
const n = x.length;
|
|
7648
|
-
let sigma = 0;
|
|
7649
|
-
for (let i = 1; i < n; i++) sigma += x[i] * x[i];
|
|
7650
|
-
const v = [...x];
|
|
7651
|
-
v[0] = 1;
|
|
7652
|
-
if (sigma === 0 && x[0] >= 0) {
|
|
7653
|
-
return { v, beta: 0 };
|
|
7654
|
-
} else if (sigma === 0 && x[0] < 0) {
|
|
7655
|
-
return { v, beta: 2 };
|
|
7656
|
-
} else {
|
|
7657
|
-
const mu = Math.sqrt(x[0] * x[0] + sigma);
|
|
7658
|
-
v[0] = x[0] <= 0 ? x[0] - mu : -sigma / (x[0] + mu);
|
|
7659
|
-
const beta = 2 * v[0] * v[0] / (sigma + v[0] * v[0]);
|
|
7660
|
-
const v0 = v[0];
|
|
7661
|
-
for (let i = 0; i < n; i++) v[i] /= v0;
|
|
7662
|
-
return { v, beta };
|
|
7663
|
-
}
|
|
7664
|
-
}
|
|
7665
|
-
function applyHouseholderLeft2(A, v, beta, startRow, startCol) {
|
|
7666
|
-
const n = A[0].length;
|
|
7667
|
-
const len = v.length;
|
|
7668
|
-
for (let j = startCol; j < n; j++) {
|
|
7669
|
-
let dot = 0;
|
|
7670
|
-
for (let i = 0; i < len; i++) dot += v[i] * A[startRow + i][j];
|
|
7671
|
-
dot *= beta;
|
|
7672
|
-
for (let i = 0; i < len; i++) A[startRow + i][j] -= dot * v[i];
|
|
7673
|
-
}
|
|
7674
|
-
}
|
|
7675
|
-
function applyHouseholderRight2(A, v, beta, startRow, startCol) {
|
|
7676
|
-
const m = A.length;
|
|
7677
|
-
const len = v.length;
|
|
7678
|
-
for (let i = startRow; i < m; i++) {
|
|
7679
|
-
let dot = 0;
|
|
7680
|
-
for (let j = 0; j < len; j++) dot += A[i][startCol + j] * v[j];
|
|
7681
|
-
dot *= beta;
|
|
7682
|
-
for (let j = 0; j < len; j++) A[i][startCol + j] -= dot * v[j];
|
|
7683
|
-
}
|
|
7684
|
-
}
|
|
7685
6795
|
function hessenbergReduce(A) {
|
|
7686
6796
|
const n = A.length;
|
|
7687
|
-
const H =
|
|
7688
|
-
const Q =
|
|
6797
|
+
const H = cloneMatrix(A);
|
|
6798
|
+
const Q = eye(n);
|
|
7689
6799
|
for (let k = 0; k < n - 2; k++) {
|
|
7690
6800
|
const x = [];
|
|
7691
6801
|
for (let i = k + 1; i < n; i++) x.push(H[i][k]);
|
|
7692
|
-
const { v, beta } =
|
|
6802
|
+
const { v, beta } = householder(x, 2);
|
|
7693
6803
|
if (beta !== 0) {
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
6804
|
+
applyHouseholderLeft(H, v, beta, k + 1, k);
|
|
6805
|
+
applyHouseholderRight(H, v, beta, 0, k + 1);
|
|
6806
|
+
applyHouseholderRight(Q, v, beta, 0, k + 1);
|
|
7697
6807
|
}
|
|
7698
6808
|
}
|
|
7699
6809
|
for (let i = 0; i < n; i++)
|
|
@@ -7769,7 +6879,7 @@ function qrStepDouble(H, Q, start, end) {
|
|
|
7769
6879
|
let y = H[start + 1][start] * (H[start][start] + H[start + 1][start + 1] - s);
|
|
7770
6880
|
let z = H[start + 1][start] * H[start + 2][start + 1];
|
|
7771
6881
|
for (let k = start; k <= end - 2; k++) {
|
|
7772
|
-
const { v, beta } =
|
|
6882
|
+
const { v, beta } = householder([x, y, z], 2);
|
|
7773
6883
|
const q = Math.max(start, k - 1);
|
|
7774
6884
|
for (let j = q; j < n; j++) {
|
|
7775
6885
|
let dot = v[0] * H[k][j] + v[1] * H[k + 1][j] + v[2] * H[k + 2][j];
|
|
@@ -7867,48 +6977,6 @@ function schurInternal(A, maxIterations = 1e3, tolerance = 1e-12) {
|
|
|
7867
6977
|
}
|
|
7868
6978
|
|
|
7869
6979
|
// src/operations/logm.ts
|
|
7870
|
-
function eye4(n) {
|
|
7871
|
-
return Array.from(
|
|
7872
|
-
{ length: n },
|
|
7873
|
-
(_, i) => Array.from({ length: n }, (_2, j) => i === j ? 1 : 0)
|
|
7874
|
-
);
|
|
7875
|
-
}
|
|
7876
|
-
function matMul2(A, B2) {
|
|
7877
|
-
const m = A.length;
|
|
7878
|
-
const p = A[0].length;
|
|
7879
|
-
const n = B2[0].length;
|
|
7880
|
-
const C = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
7881
|
-
for (let i = 0; i < m; i++)
|
|
7882
|
-
for (let k = 0; k < p; k++) {
|
|
7883
|
-
const aik = A[i][k];
|
|
7884
|
-
if (aik === 0) continue;
|
|
7885
|
-
for (let j = 0; j < n; j++) C[i][j] += aik * B2[k][j];
|
|
7886
|
-
}
|
|
7887
|
-
return C;
|
|
7888
|
-
}
|
|
7889
|
-
function transpose2(A) {
|
|
7890
|
-
const m = A.length;
|
|
7891
|
-
const n = A[0].length;
|
|
7892
|
-
return Array.from({ length: n }, (_, j) => Array.from({ length: m }, (_2, i) => A[i][j]));
|
|
7893
|
-
}
|
|
7894
|
-
function matScale2(A, c) {
|
|
7895
|
-
return A.map((row2) => row2.map((v) => v * c));
|
|
7896
|
-
}
|
|
7897
|
-
function normInf(A) {
|
|
7898
|
-
let mx = 0;
|
|
7899
|
-
for (const row2 of A) for (const v of row2) if (Math.abs(v) > mx) mx = Math.abs(v);
|
|
7900
|
-
return mx;
|
|
7901
|
-
}
|
|
7902
|
-
function norm12(A) {
|
|
7903
|
-
const n = A[0].length;
|
|
7904
|
-
let mx = 0;
|
|
7905
|
-
for (let j = 0; j < n; j++) {
|
|
7906
|
-
let s = 0;
|
|
7907
|
-
for (const row2 of A) s += Math.abs(row2[j]);
|
|
7908
|
-
if (s > mx) mx = s;
|
|
7909
|
-
}
|
|
7910
|
-
return mx;
|
|
7911
|
-
}
|
|
7912
6980
|
function matInv(A) {
|
|
7913
6981
|
const n = A.length;
|
|
7914
6982
|
const M = A.map((row2, i) => {
|
|
@@ -7941,11 +7009,11 @@ function matInv(A) {
|
|
|
7941
7009
|
}
|
|
7942
7010
|
function matSqrt(A) {
|
|
7943
7011
|
const n = A.length;
|
|
7944
|
-
let Y =
|
|
7012
|
+
let Y = eye(n);
|
|
7945
7013
|
for (let iter = 0; iter < 150; iter++) {
|
|
7946
7014
|
const Yinv = matInv(Y);
|
|
7947
7015
|
if (Yinv === null) break;
|
|
7948
|
-
const AYinv =
|
|
7016
|
+
const AYinv = matMul(A, Yinv);
|
|
7949
7017
|
const Ynew = Array.from(
|
|
7950
7018
|
{ length: n },
|
|
7951
7019
|
(_, i) => Array.from({ length: n }, (_2, j) => (Y[i][j] + AYinv[i][j]) / 2)
|
|
@@ -8022,7 +7090,7 @@ function solveCol(M, b) {
|
|
|
8022
7090
|
function logPade(X) {
|
|
8023
7091
|
const n = X.length;
|
|
8024
7092
|
const result = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
8025
|
-
const I =
|
|
7093
|
+
const I = eye(n);
|
|
8026
7094
|
for (let q = 0; q < GL16_NODES.length; q++) {
|
|
8027
7095
|
const t = GL16_NODES[q];
|
|
8028
7096
|
const w = GL16_WEIGHTS[q];
|
|
@@ -8055,24 +7123,6 @@ function sqrtUpperTriangular(T) {
|
|
|
8055
7123
|
}
|
|
8056
7124
|
return U;
|
|
8057
7125
|
}
|
|
8058
|
-
function matMulArr(A, B2) {
|
|
8059
|
-
const m = A.length;
|
|
8060
|
-
const p = A[0].length;
|
|
8061
|
-
const n = B2[0].length;
|
|
8062
|
-
const C = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
8063
|
-
for (let i = 0; i < m; i++)
|
|
8064
|
-
for (let k = 0; k < p; k++) {
|
|
8065
|
-
const aik = A[i][k];
|
|
8066
|
-
if (aik === 0) continue;
|
|
8067
|
-
for (let j = 0; j < n; j++) C[i][j] += aik * B2[k][j];
|
|
8068
|
-
}
|
|
8069
|
-
return C;
|
|
8070
|
-
}
|
|
8071
|
-
function transposeArr(A) {
|
|
8072
|
-
const m = A.length;
|
|
8073
|
-
const n = A[0].length;
|
|
8074
|
-
return Array.from({ length: n }, (_, j) => Array.from({ length: m }, (_2, i) => A[i][j]));
|
|
8075
|
-
}
|
|
8076
7126
|
function isStrictlyUpperTriangular(T) {
|
|
8077
7127
|
const n = T.length;
|
|
8078
7128
|
for (let i = 1; i < n; i++) {
|
|
@@ -8092,21 +7142,21 @@ function logmSchur(A, tol) {
|
|
|
8092
7142
|
const maxSqrt = 64;
|
|
8093
7143
|
while (numSqrt < maxSqrt) {
|
|
8094
7144
|
const MminI2 = M.map((row2, i) => row2.map((v, j) => v - (i === j ? 1 : 0)));
|
|
8095
|
-
if (
|
|
7145
|
+
if (norm1(MminI2) < tol) break;
|
|
8096
7146
|
const sqrtM = sqrtUpperTriangular(M);
|
|
8097
7147
|
if (sqrtM === null || !isFinite(normInf(sqrtM))) break;
|
|
8098
7148
|
M = sqrtM;
|
|
8099
7149
|
numSqrt++;
|
|
8100
7150
|
}
|
|
8101
7151
|
const MminI = M.map((row2, i) => row2.map((v, j) => v - (i === j ? 1 : 0)));
|
|
8102
|
-
if (
|
|
7152
|
+
if (norm1(MminI) >= tol) return null;
|
|
8103
7153
|
let logT = logPade(MminI);
|
|
8104
7154
|
if (numSqrt > 0) {
|
|
8105
7155
|
const scale2 = Math.pow(2, numSqrt);
|
|
8106
7156
|
logT = logT.map((row2) => row2.map((v) => v * scale2));
|
|
8107
7157
|
}
|
|
8108
|
-
const Qt =
|
|
8109
|
-
return
|
|
7158
|
+
const Qt = transpose(Q);
|
|
7159
|
+
return matMul(matMul(Q, logT), Qt);
|
|
8110
7160
|
}
|
|
8111
7161
|
function validateEigenvalues(A) {
|
|
8112
7162
|
const { values } = eig(A, { computeVectors: false });
|
|
@@ -8139,16 +7189,16 @@ function logmEig(A) {
|
|
|
8139
7189
|
}
|
|
8140
7190
|
}
|
|
8141
7191
|
const V = vectors;
|
|
8142
|
-
const Q =
|
|
7192
|
+
const Q = transpose(V);
|
|
8143
7193
|
const Qinv = matInv(Q);
|
|
8144
7194
|
if (Qinv === null) {
|
|
8145
7195
|
throw new Error(
|
|
8146
7196
|
"matrixLogm: eigenvector matrix is singular \u2014 matrix appears to be non-diagonalisable (Slice 5.9a limitation; full Schur-based implementation deferred to Slice 5.9b)"
|
|
8147
7197
|
);
|
|
8148
7198
|
}
|
|
8149
|
-
const D =
|
|
7199
|
+
const D = eye(n);
|
|
8150
7200
|
for (let i = 0; i < n; i++) D[i][i] = Math.log(values[i].re);
|
|
8151
|
-
return
|
|
7201
|
+
return matMul(matMul(Q, D), Qinv);
|
|
8152
7202
|
}
|
|
8153
7203
|
function matrixLogm(A, opts) {
|
|
8154
7204
|
const n = A.rows;
|
|
@@ -8168,7 +7218,7 @@ function matrixLogm(A, opts) {
|
|
|
8168
7218
|
const maxSqrt = 64;
|
|
8169
7219
|
while (numSqrt < maxSqrt) {
|
|
8170
7220
|
const MminI2 = M.map((row2, i) => row2.map((v, j) => v - (i === j ? 1 : 0)));
|
|
8171
|
-
if (
|
|
7221
|
+
if (norm1(MminI2) < tol) break;
|
|
8172
7222
|
const sqrtM = matSqrt(M);
|
|
8173
7223
|
if (!isFinite(normInf(sqrtM))) break;
|
|
8174
7224
|
M = sqrtM;
|
|
@@ -8176,14 +7226,14 @@ function matrixLogm(A, opts) {
|
|
|
8176
7226
|
}
|
|
8177
7227
|
let logM;
|
|
8178
7228
|
const MminI = M.map((row2, i) => row2.map((v, j) => v - (i === j ? 1 : 0)));
|
|
8179
|
-
if (
|
|
7229
|
+
if (norm1(MminI) < tol) {
|
|
8180
7230
|
logM = logPade(MminI);
|
|
8181
7231
|
} else {
|
|
8182
7232
|
logM = logmEig(Aarr);
|
|
8183
7233
|
numSqrt = 0;
|
|
8184
7234
|
}
|
|
8185
7235
|
if (numSqrt > 0) {
|
|
8186
|
-
logM =
|
|
7236
|
+
logM = matScale(logM, Math.pow(2, numSqrt));
|
|
8187
7237
|
}
|
|
8188
7238
|
const data = new Float64Array(n * n);
|
|
8189
7239
|
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) data[i * n + j] = logM[i][j];
|
|
@@ -8192,30 +7242,6 @@ function matrixLogm(A, opts) {
|
|
|
8192
7242
|
|
|
8193
7243
|
// src/operations/sqrtm.ts
|
|
8194
7244
|
init_DenseMatrix();
|
|
8195
|
-
function eye5(n) {
|
|
8196
|
-
return Array.from(
|
|
8197
|
-
{ length: n },
|
|
8198
|
-
(_, i) => Array.from({ length: n }, (_2, j) => i === j ? 1 : 0)
|
|
8199
|
-
);
|
|
8200
|
-
}
|
|
8201
|
-
function matMul3(A, B2) {
|
|
8202
|
-
const m = A.length;
|
|
8203
|
-
const p = A[0].length;
|
|
8204
|
-
const n = B2[0].length;
|
|
8205
|
-
const C = Array.from({ length: m }, () => new Array(n).fill(0));
|
|
8206
|
-
for (let i = 0; i < m; i++)
|
|
8207
|
-
for (let k = 0; k < p; k++) {
|
|
8208
|
-
const aik = A[i][k];
|
|
8209
|
-
if (aik === 0) continue;
|
|
8210
|
-
for (let j = 0; j < n; j++) C[i][j] += aik * B2[k][j];
|
|
8211
|
-
}
|
|
8212
|
-
return C;
|
|
8213
|
-
}
|
|
8214
|
-
function transpose3(A) {
|
|
8215
|
-
const m = A.length;
|
|
8216
|
-
const n = A[0].length;
|
|
8217
|
-
return Array.from({ length: n }, (_, j) => Array.from({ length: m }, (_2, i) => A[i][j]));
|
|
8218
|
-
}
|
|
8219
7245
|
function symmetrize(A) {
|
|
8220
7246
|
const n = A.length;
|
|
8221
7247
|
return Array.from(
|
|
@@ -8288,20 +7314,20 @@ function sqrtmSymmetric(A) {
|
|
|
8288
7314
|
}
|
|
8289
7315
|
const Ynewton = sqrtmNewton(Asym);
|
|
8290
7316
|
if (Ynewton !== null) return Ynewton;
|
|
8291
|
-
const Qraw =
|
|
7317
|
+
const Qraw = transpose(vectors);
|
|
8292
7318
|
const Q = gramSchmidt(Qraw);
|
|
8293
|
-
const Qt =
|
|
8294
|
-
const Dsqrt =
|
|
7319
|
+
const Qt = transpose(Q);
|
|
7320
|
+
const Dsqrt = eye(n);
|
|
8295
7321
|
for (let i = 0; i < n; i++) Dsqrt[i][i] = Math.sqrt(Math.max(values[i].re, 0));
|
|
8296
|
-
return
|
|
7322
|
+
return matMul(matMul(Q, Dsqrt), Qt);
|
|
8297
7323
|
}
|
|
8298
7324
|
function sqrtmNewton(A) {
|
|
8299
7325
|
const n = A.length;
|
|
8300
|
-
let Y =
|
|
7326
|
+
let Y = eye(n);
|
|
8301
7327
|
for (let iter = 0; iter < 150; iter++) {
|
|
8302
7328
|
const Yinv = matInv2(Y);
|
|
8303
7329
|
if (Yinv === null) return null;
|
|
8304
|
-
const AYinv =
|
|
7330
|
+
const AYinv = matMul(A, Yinv);
|
|
8305
7331
|
const Ynew = Array.from(
|
|
8306
7332
|
{ length: n },
|
|
8307
7333
|
(_, i) => Array.from({ length: n }, (_2, j) => (Y[i][j] + AYinv[i][j]) / 2)
|
|
@@ -8312,7 +7338,7 @@ function sqrtmNewton(A) {
|
|
|
8312
7338
|
Y = Ynew;
|
|
8313
7339
|
if (diff < 1e-13) return Y;
|
|
8314
7340
|
}
|
|
8315
|
-
const Y2 =
|
|
7341
|
+
const Y2 = matMul(Y, Y);
|
|
8316
7342
|
let err = 0;
|
|
8317
7343
|
for (let i = 0; i < n; i++)
|
|
8318
7344
|
for (let j = 0; j < n; j++) err = Math.max(err, Math.abs(Y2[i][j] - A[i][j]));
|
|
@@ -8336,16 +7362,16 @@ function sqrtmGeneral(A) {
|
|
|
8336
7362
|
const Ynewton = sqrtmNewton(A);
|
|
8337
7363
|
if (Ynewton !== null) return Ynewton;
|
|
8338
7364
|
const V = vectors;
|
|
8339
|
-
const Q =
|
|
7365
|
+
const Q = transpose(V);
|
|
8340
7366
|
const Qinv = matInv2(Q);
|
|
8341
7367
|
if (Qinv === null) {
|
|
8342
7368
|
throw new Error(
|
|
8343
7369
|
"matrixSqrtm: eigenvector matrix is singular \u2014 matrix appears to be non-diagonalisable"
|
|
8344
7370
|
);
|
|
8345
7371
|
}
|
|
8346
|
-
const Dsqrt =
|
|
7372
|
+
const Dsqrt = eye(n);
|
|
8347
7373
|
for (let i = 0; i < n; i++) Dsqrt[i][i] = Math.sqrt(Math.max(values[i].re, 0));
|
|
8348
|
-
return
|
|
7374
|
+
return matMul(matMul(Q, Dsqrt), Qinv);
|
|
8349
7375
|
}
|
|
8350
7376
|
function sqrtmQuasiTriangular(T) {
|
|
8351
7377
|
const n = T.length;
|
|
@@ -8460,30 +7486,12 @@ function solveLinearSystem(A, b) {
|
|
|
8460
7486
|
}
|
|
8461
7487
|
return Aug.map((row2) => row2[n]);
|
|
8462
7488
|
}
|
|
8463
|
-
function matMulArr2(A, B2) {
|
|
8464
|
-
const m = A.length;
|
|
8465
|
-
const p = A[0].length;
|
|
8466
|
-
const n2 = B2[0].length;
|
|
8467
|
-
const C = Array.from({ length: m }, () => new Array(n2).fill(0));
|
|
8468
|
-
for (let i = 0; i < m; i++)
|
|
8469
|
-
for (let k = 0; k < p; k++) {
|
|
8470
|
-
const aik = A[i][k];
|
|
8471
|
-
if (aik === 0) continue;
|
|
8472
|
-
for (let j = 0; j < n2; j++) C[i][j] += aik * B2[k][j];
|
|
8473
|
-
}
|
|
8474
|
-
return C;
|
|
8475
|
-
}
|
|
8476
|
-
function transposeArr2(A) {
|
|
8477
|
-
const m = A.length;
|
|
8478
|
-
const n2 = A[0].length;
|
|
8479
|
-
return Array.from({ length: n2 }, (_, j) => Array.from({ length: m }, (_2, i) => A[i][j]));
|
|
8480
|
-
}
|
|
8481
7489
|
function sqrtmSchur(A) {
|
|
8482
7490
|
const { H: T, Q } = schurInternal(A);
|
|
8483
7491
|
const U = sqrtmQuasiTriangular(T);
|
|
8484
7492
|
if (U === null) return null;
|
|
8485
|
-
const Qt =
|
|
8486
|
-
return
|
|
7493
|
+
const Qt = transpose(Q);
|
|
7494
|
+
return matMul(matMul(Q, U), Qt);
|
|
8487
7495
|
}
|
|
8488
7496
|
function matrixSqrtm(A, opts) {
|
|
8489
7497
|
const n = A.rows;
|
|
@@ -8589,7 +7597,7 @@ var unaryMinus = mathTyped("unaryMinus", {
|
|
|
8589
7597
|
DenseMatrix: (a) => a.negate(),
|
|
8590
7598
|
number: (a) => -a
|
|
8591
7599
|
});
|
|
8592
|
-
var
|
|
7600
|
+
var transpose3 = mathTyped("transpose", {
|
|
8593
7601
|
DenseMatrix: (a) => a.transpose()
|
|
8594
7602
|
});
|
|
8595
7603
|
var sum2 = mathTyped("sum", {
|
|
@@ -8678,7 +7686,7 @@ var typedMatrixOperations = {
|
|
|
8678
7686
|
dotMultiply,
|
|
8679
7687
|
divide,
|
|
8680
7688
|
unaryMinus,
|
|
8681
|
-
transpose:
|
|
7689
|
+
transpose: transpose3,
|
|
8682
7690
|
// Reductions
|
|
8683
7691
|
sum: sum2,
|
|
8684
7692
|
mean: mean2,
|
|
@@ -9359,8 +8367,6 @@ export {
|
|
|
9359
8367
|
JSBackend,
|
|
9360
8368
|
Matrix,
|
|
9361
8369
|
ParallelBackend,
|
|
9362
|
-
RustWASMBackend,
|
|
9363
|
-
RustWasmLoader,
|
|
9364
8370
|
ShaderManager,
|
|
9365
8371
|
SparseMatrix,
|
|
9366
8372
|
SyncManager,
|
|
@@ -9376,7 +8382,6 @@ export {
|
|
|
9376
8382
|
createBackendManager,
|
|
9377
8383
|
createGPUMatrixBackend,
|
|
9378
8384
|
createParallelBackend,
|
|
9379
|
-
createRustWASMBackend,
|
|
9380
8385
|
createSyncManager,
|
|
9381
8386
|
createWASMBackend,
|
|
9382
8387
|
destroyGlobalGPU,
|
|
@@ -9399,7 +8404,6 @@ export {
|
|
|
9399
8404
|
gpuMatrixBackend,
|
|
9400
8405
|
hasWebGPU,
|
|
9401
8406
|
identity,
|
|
9402
|
-
initRustWasm,
|
|
9403
8407
|
initializeGlobalGPUBackend,
|
|
9404
8408
|
initializeParallelMatrix,
|
|
9405
8409
|
isAtomicsAvailable,
|
|
@@ -9473,8 +8477,6 @@ export {
|
|
|
9473
8477
|
qr,
|
|
9474
8478
|
random,
|
|
9475
8479
|
row,
|
|
9476
|
-
rustWasmBackend,
|
|
9477
|
-
rustWasmLoader,
|
|
9478
8480
|
singularValues,
|
|
9479
8481
|
size,
|
|
9480
8482
|
spectralRadiusWasm,
|
|
@@ -9487,7 +8489,7 @@ export {
|
|
|
9487
8489
|
svdWasm,
|
|
9488
8490
|
terminateParallelMatrix,
|
|
9489
8491
|
trace2 as trace,
|
|
9490
|
-
|
|
8492
|
+
transpose3 as transpose,
|
|
9491
8493
|
typedMatrixOperations,
|
|
9492
8494
|
unaryMinus,
|
|
9493
8495
|
wasmBackend,
|