numbl 0.1.4 → 0.1.6
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/binding.gyp +2 -1
- package/dist-cli/cli.js +2215 -250
- package/dist-lib/graphics/types.d.ts +22 -0
- package/dist-lib/lib.js +2154 -189
- package/dist-lib/numbl-core/executeCode.d.ts +9 -0
- package/dist-lib/numbl-core/functionResolve.d.ts +4 -0
- package/dist-lib/numbl-core/helpers/gmres.d.ts +51 -0
- package/dist-lib/numbl-core/interpreter/interpreter.d.ts +3 -0
- package/dist-lib/numbl-core/interpreter/interpreterFunctions.d.ts +3 -0
- package/dist-lib/numbl-core/interpreter/interpreterSpecialBuiltins.d.ts +8 -3
- package/dist-lib/numbl-core/interpreter/jit/jitHelpers.d.ts +9 -0
- package/dist-lib/numbl-core/jsUserFunctions.d.ts +25 -10
- package/dist-lib/numbl-core/lowering/loweringContext.d.ts +12 -1
- package/dist-lib/numbl-core/native/lapack-bridge.d.ts +33 -1
- package/dist-lib/numbl-core/runtime/error.d.ts +2 -0
- package/dist-lib/numbl-core/runtime/plotUtils.d.ts +11 -2
- package/dist-lib/numbl-core/runtime/runtime.d.ts +10 -0
- package/dist-lib/numbl-core/runtime/runtimePlot.d.ts +6 -0
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/dist-plot-viewer/assets/index-vtrJ8bml.js +4426 -0
- package/dist-plot-viewer/index.html +1 -1
- package/native/lapack_gmres.cpp +612 -0
- package/native/numbl_addon.cpp +5 -1
- package/native/numbl_addon_common.h +26 -0
- package/package.json +1 -1
- package/dist-plot-viewer/assets/index-BjKyNJgj.js +0 -4426
package/dist-cli/cli.js
CHANGED
|
@@ -196,7 +196,7 @@ var kstr = (value) => {
|
|
|
196
196
|
};
|
|
197
197
|
|
|
198
198
|
// src/numbl-core/native/lapack-bridge.ts
|
|
199
|
-
var NATIVE_ADDON_EXPECTED_VERSION =
|
|
199
|
+
var NATIVE_ADDON_EXPECTED_VERSION = 2;
|
|
200
200
|
var _bridge = null;
|
|
201
201
|
function setLapackBridge(bridge) {
|
|
202
202
|
_bridge = bridge;
|
|
@@ -678,6 +678,9 @@ var RuntimeError = class extends Error {
|
|
|
678
678
|
* Format error with location and snippet context.
|
|
679
679
|
*/
|
|
680
680
|
toString() {
|
|
681
|
+
if (this.callStack != null && this.callStack.length > 0) {
|
|
682
|
+
return this._formatWithCallStack();
|
|
683
|
+
}
|
|
681
684
|
let result = this.name;
|
|
682
685
|
if (this.file && this.line !== null) {
|
|
683
686
|
result += ` at ${this.file}:${this.line}`;
|
|
@@ -692,58 +695,51 @@ var RuntimeError = class extends Error {
|
|
|
692
695
|
result += `
|
|
693
696
|
${this.snippet}`;
|
|
694
697
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
at ${name} (${loc})`;
|
|
728
|
-
if (frameFile && frameLine > 0) {
|
|
729
|
-
const srcLine = this._getSourceLine(frameFile, frameLine);
|
|
730
|
-
if (srcLine) result += `
|
|
731
|
-
${srcLine}`;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
const outermost = this.callStack[0];
|
|
735
|
-
if (outermost.callerFile && outermost.callerLine > 0) {
|
|
736
|
-
result += `
|
|
737
|
-
at ${outermost.callerFile}:${outermost.callerLine}`;
|
|
738
|
-
const srcLine = this._getSourceLine(
|
|
739
|
-
outermost.callerFile,
|
|
740
|
-
outermost.callerLine
|
|
741
|
-
);
|
|
742
|
-
if (srcLine) result += `
|
|
743
|
-
${srcLine}`;
|
|
698
|
+
return result;
|
|
699
|
+
}
|
|
700
|
+
/** Format error with MATLAB-style call stack. */
|
|
701
|
+
_formatWithCallStack() {
|
|
702
|
+
const stack = this.callStack;
|
|
703
|
+
const N = stack.length;
|
|
704
|
+
const parts = [];
|
|
705
|
+
const innerName = stack[N - 1].name;
|
|
706
|
+
const innerFile = this.file;
|
|
707
|
+
const innerLine = this.line ?? 0;
|
|
708
|
+
if (innerFile && innerLine > 0) {
|
|
709
|
+
parts.push(`Error using ${innerName} (${innerFile}:${innerLine})`);
|
|
710
|
+
} else if (innerLine > 0) {
|
|
711
|
+
parts.push(`Error using ${innerName} (line ${innerLine})`);
|
|
712
|
+
} else {
|
|
713
|
+
parts.push(`Error using ${innerName}`);
|
|
714
|
+
}
|
|
715
|
+
parts.push(this.message);
|
|
716
|
+
for (let i = N - 2; i >= 0; i--) {
|
|
717
|
+
const name = stack[i].name;
|
|
718
|
+
const callerFrame = stack[i + 1];
|
|
719
|
+
const file = callerFrame.callerFile;
|
|
720
|
+
const line = callerFrame.callerLine;
|
|
721
|
+
parts.push("");
|
|
722
|
+
if (file && line > 0) {
|
|
723
|
+
parts.push(`Error in ${name} (${file}:${line})`);
|
|
724
|
+
const srcLine = this._getSourceLine(file, line);
|
|
725
|
+
if (srcLine) parts.push(` ${srcLine}`);
|
|
726
|
+
} else if (line > 0) {
|
|
727
|
+
parts.push(`Error in ${name} (line ${line})`);
|
|
728
|
+
} else {
|
|
729
|
+
parts.push(`Error in ${name}`);
|
|
744
730
|
}
|
|
745
731
|
}
|
|
746
|
-
|
|
732
|
+
const outermost = stack[0];
|
|
733
|
+
if (outermost.callerFile && outermost.callerLine > 0) {
|
|
734
|
+
parts.push("");
|
|
735
|
+
parts.push(`Error in ${outermost.callerFile}:${outermost.callerLine}`);
|
|
736
|
+
const srcLine = this._getSourceLine(
|
|
737
|
+
outermost.callerFile,
|
|
738
|
+
outermost.callerLine
|
|
739
|
+
);
|
|
740
|
+
if (srcLine) parts.push(` ${srcLine}`);
|
|
741
|
+
}
|
|
742
|
+
return parts.join("\n");
|
|
747
743
|
}
|
|
748
744
|
/** Look up a single trimmed source line from fileSources. */
|
|
749
745
|
_getSourceLine(file, line) {
|
|
@@ -1584,9 +1580,6 @@ function registerDynamicIBuiltin(b) {
|
|
|
1584
1580
|
registry.set(b.name, b);
|
|
1585
1581
|
_onDynamicRegister?.(b);
|
|
1586
1582
|
}
|
|
1587
|
-
function unregisterIBuiltin(name) {
|
|
1588
|
-
registry.delete(name);
|
|
1589
|
-
}
|
|
1590
1583
|
function getAllIBuiltinNames() {
|
|
1591
1584
|
return Array.from(registry.keys());
|
|
1592
1585
|
}
|
|
@@ -4379,6 +4372,435 @@ function dgetrf(m, n, a, lda, ipiv) {
|
|
|
4379
4372
|
return info;
|
|
4380
4373
|
}
|
|
4381
4374
|
|
|
4375
|
+
// src/numbl-core/helpers/gmres.ts
|
|
4376
|
+
function gmresCore(matvec, precSolve, b, n, restart, tol, maxit, x0) {
|
|
4377
|
+
const x = x0 ? new Float64Array(x0) : new Float64Array(n);
|
|
4378
|
+
if (restart <= 0 || restart > n) restart = n;
|
|
4379
|
+
let r = sub(b, matvec(x), n);
|
|
4380
|
+
if (precSolve) r = precSolve(r);
|
|
4381
|
+
let beta = nrm2(r, n);
|
|
4382
|
+
let normMb;
|
|
4383
|
+
if (precSolve) {
|
|
4384
|
+
normMb = nrm2(precSolve(new Float64Array(b)), n);
|
|
4385
|
+
} else {
|
|
4386
|
+
normMb = nrm2(b, n);
|
|
4387
|
+
}
|
|
4388
|
+
if (normMb === 0) normMb = 1;
|
|
4389
|
+
const resvecList = [beta];
|
|
4390
|
+
if (beta / normMb <= tol) {
|
|
4391
|
+
return {
|
|
4392
|
+
x,
|
|
4393
|
+
flag: 0,
|
|
4394
|
+
relres: beta / normMb,
|
|
4395
|
+
iter: [0, 0],
|
|
4396
|
+
resvec: new Float64Array(resvecList)
|
|
4397
|
+
};
|
|
4398
|
+
}
|
|
4399
|
+
let flag = 1;
|
|
4400
|
+
let outerIter = 0;
|
|
4401
|
+
let innerIter = 0;
|
|
4402
|
+
for (let outer = 1; outer <= maxit; outer++) {
|
|
4403
|
+
outerIter = outer;
|
|
4404
|
+
const V = new Float64Array(n * (restart + 1));
|
|
4405
|
+
for (let i = 0; i < n; i++) V[i] = r[i] / beta;
|
|
4406
|
+
const H2 = new Float64Array((restart + 1) * restart);
|
|
4407
|
+
const cs = new Float64Array(restart);
|
|
4408
|
+
const sn = new Float64Array(restart);
|
|
4409
|
+
const g = new Float64Array(restart + 1);
|
|
4410
|
+
g[0] = beta;
|
|
4411
|
+
let converged = false;
|
|
4412
|
+
for (let j = 0; j < restart; j++) {
|
|
4413
|
+
innerIter = j + 1;
|
|
4414
|
+
let w = matvec(V.subarray(j * n, (j + 1) * n));
|
|
4415
|
+
if (precSolve) w = precSolve(w);
|
|
4416
|
+
const ldh = restart + 1;
|
|
4417
|
+
for (let i = 0; i <= j; i++) {
|
|
4418
|
+
const viOff = i * n;
|
|
4419
|
+
let hij = 0;
|
|
4420
|
+
for (let k = 0; k < n; k++) hij += w[k] * V[viOff + k];
|
|
4421
|
+
H2[i + j * ldh] = hij;
|
|
4422
|
+
for (let k = 0; k < n; k++) w[k] -= hij * V[viOff + k];
|
|
4423
|
+
}
|
|
4424
|
+
const wnorm = nrm2(w, n);
|
|
4425
|
+
H2[j + 1 + j * ldh] = wnorm;
|
|
4426
|
+
if (wnorm > 1e-300) {
|
|
4427
|
+
const vOff = (j + 1) * n;
|
|
4428
|
+
for (let k = 0; k < n; k++) V[vOff + k] = w[k] / wnorm;
|
|
4429
|
+
}
|
|
4430
|
+
for (let i = 0; i < j; i++) {
|
|
4431
|
+
const hi = H2[i + j * ldh];
|
|
4432
|
+
const hi1 = H2[i + 1 + j * ldh];
|
|
4433
|
+
H2[i + j * ldh] = cs[i] * hi + sn[i] * hi1;
|
|
4434
|
+
H2[i + 1 + j * ldh] = -sn[i] * hi + cs[i] * hi1;
|
|
4435
|
+
}
|
|
4436
|
+
const [c, s] = givensRotation(H2[j + j * ldh], H2[j + 1 + j * ldh]);
|
|
4437
|
+
cs[j] = c;
|
|
4438
|
+
sn[j] = s;
|
|
4439
|
+
H2[j + j * ldh] = c * H2[j + j * ldh] + s * H2[j + 1 + j * ldh];
|
|
4440
|
+
H2[j + 1 + j * ldh] = 0;
|
|
4441
|
+
const gj = g[j];
|
|
4442
|
+
g[j] = c * gj;
|
|
4443
|
+
g[j + 1] = -s * gj;
|
|
4444
|
+
const residNorm = Math.abs(g[j + 1]);
|
|
4445
|
+
resvecList.push(residNorm);
|
|
4446
|
+
if (residNorm / normMb <= tol) {
|
|
4447
|
+
const y2 = backSolve(H2, g, j + 1, ldh);
|
|
4448
|
+
for (let k = 0; k < n; k++) {
|
|
4449
|
+
for (let l = 0; l <= j; l++) x[k] += V[k + l * n] * y2[l];
|
|
4450
|
+
}
|
|
4451
|
+
flag = 0;
|
|
4452
|
+
converged = true;
|
|
4453
|
+
break;
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
if (converged) break;
|
|
4457
|
+
const y = backSolve(H2, g, restart, restart + 1);
|
|
4458
|
+
for (let k = 0; k < n; k++) {
|
|
4459
|
+
for (let l = 0; l < restart; l++) x[k] += V[k + l * n] * y[l];
|
|
4460
|
+
}
|
|
4461
|
+
r = sub(b, matvec(x), n);
|
|
4462
|
+
if (precSolve) r = precSolve(r);
|
|
4463
|
+
beta = nrm2(r, n);
|
|
4464
|
+
if (beta / normMb <= tol) {
|
|
4465
|
+
flag = 0;
|
|
4466
|
+
innerIter = 0;
|
|
4467
|
+
break;
|
|
4468
|
+
}
|
|
4469
|
+
}
|
|
4470
|
+
let relres;
|
|
4471
|
+
if (flag === 0) {
|
|
4472
|
+
let finalR = sub(b, matvec(x), n);
|
|
4473
|
+
if (precSolve) finalR = precSolve(finalR);
|
|
4474
|
+
relres = nrm2(finalR, n) / normMb;
|
|
4475
|
+
} else {
|
|
4476
|
+
relres = beta / normMb;
|
|
4477
|
+
}
|
|
4478
|
+
return {
|
|
4479
|
+
x,
|
|
4480
|
+
flag,
|
|
4481
|
+
relres,
|
|
4482
|
+
iter: [outerIter, innerIter],
|
|
4483
|
+
resvec: new Float64Array(resvecList)
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
function nrm2(a, n) {
|
|
4487
|
+
let s = 0;
|
|
4488
|
+
for (let i = 0; i < n; i++) s += a[i] * a[i];
|
|
4489
|
+
return Math.sqrt(s);
|
|
4490
|
+
}
|
|
4491
|
+
function sub(a, b, n) {
|
|
4492
|
+
const r = new Float64Array(n);
|
|
4493
|
+
for (let i = 0; i < n; i++) r[i] = a[i] - b[i];
|
|
4494
|
+
return r;
|
|
4495
|
+
}
|
|
4496
|
+
function givensRotation(a, b) {
|
|
4497
|
+
if (b === 0) return [1, 0];
|
|
4498
|
+
if (Math.abs(b) > Math.abs(a)) {
|
|
4499
|
+
const t2 = a / b;
|
|
4500
|
+
const s = 1 / Math.sqrt(1 + t2 * t2);
|
|
4501
|
+
return [s * t2, s];
|
|
4502
|
+
}
|
|
4503
|
+
const t = b / a;
|
|
4504
|
+
const c = 1 / Math.sqrt(1 + t * t);
|
|
4505
|
+
return [c, c * t];
|
|
4506
|
+
}
|
|
4507
|
+
function backSolve(H2, g, m, ldh) {
|
|
4508
|
+
const y = new Float64Array(m);
|
|
4509
|
+
for (let i = 0; i < m; i++) y[i] = g[i];
|
|
4510
|
+
for (let i = m - 1; i >= 0; i--) {
|
|
4511
|
+
for (let j = i + 1; j < m; j++) y[i] -= H2[i + j * ldh] * y[j];
|
|
4512
|
+
y[i] /= H2[i + i * ldh];
|
|
4513
|
+
}
|
|
4514
|
+
return y;
|
|
4515
|
+
}
|
|
4516
|
+
function gmresCoreComplex(matvec, precSolve, b, n, restart, tol, maxit, x0) {
|
|
4517
|
+
const xRe = x0 ? new Float64Array(x0.re) : new Float64Array(n);
|
|
4518
|
+
const xIm = x0 ? new Float64Array(x0.im) : new Float64Array(n);
|
|
4519
|
+
if (restart <= 0 || restart > n) restart = n;
|
|
4520
|
+
const ax = matvec({ re: xRe, im: xIm });
|
|
4521
|
+
let rRe = new Float64Array(n);
|
|
4522
|
+
let rIm = new Float64Array(n);
|
|
4523
|
+
for (let i = 0; i < n; i++) {
|
|
4524
|
+
rRe[i] = b.re[i] - ax.re[i];
|
|
4525
|
+
rIm[i] = b.im[i] - ax.im[i];
|
|
4526
|
+
}
|
|
4527
|
+
if (precSolve) {
|
|
4528
|
+
const pr = precSolve({ re: rRe, im: rIm });
|
|
4529
|
+
rRe = new Float64Array(pr.re);
|
|
4530
|
+
rIm = new Float64Array(pr.im);
|
|
4531
|
+
}
|
|
4532
|
+
let beta = cnrm2(rRe, rIm, n);
|
|
4533
|
+
let normMb;
|
|
4534
|
+
if (precSolve) {
|
|
4535
|
+
const mb = precSolve({
|
|
4536
|
+
re: new Float64Array(b.re),
|
|
4537
|
+
im: new Float64Array(b.im)
|
|
4538
|
+
});
|
|
4539
|
+
normMb = cnrm2(mb.re, mb.im, n);
|
|
4540
|
+
} else {
|
|
4541
|
+
normMb = cnrm2(b.re, b.im, n);
|
|
4542
|
+
}
|
|
4543
|
+
if (normMb === 0) normMb = 1;
|
|
4544
|
+
const resvecList = [beta];
|
|
4545
|
+
if (beta / normMb <= tol) {
|
|
4546
|
+
return {
|
|
4547
|
+
x: { re: xRe, im: xIm },
|
|
4548
|
+
flag: 0,
|
|
4549
|
+
relres: beta / normMb,
|
|
4550
|
+
iter: [0, 0],
|
|
4551
|
+
resvec: new Float64Array(resvecList)
|
|
4552
|
+
};
|
|
4553
|
+
}
|
|
4554
|
+
let flag = 1;
|
|
4555
|
+
let outerIter = 0;
|
|
4556
|
+
let innerIter = 0;
|
|
4557
|
+
for (let outer = 1; outer <= maxit; outer++) {
|
|
4558
|
+
outerIter = outer;
|
|
4559
|
+
const VRe = new Float64Array(n * (restart + 1));
|
|
4560
|
+
const VIm = new Float64Array(n * (restart + 1));
|
|
4561
|
+
for (let i = 0; i < n; i++) {
|
|
4562
|
+
VRe[i] = rRe[i] / beta;
|
|
4563
|
+
VIm[i] = rIm[i] / beta;
|
|
4564
|
+
}
|
|
4565
|
+
const ldh = restart + 1;
|
|
4566
|
+
const HRe = new Float64Array(ldh * restart);
|
|
4567
|
+
const HIm = new Float64Array(ldh * restart);
|
|
4568
|
+
const cs = new Float64Array(restart);
|
|
4569
|
+
const snRe = new Float64Array(restart);
|
|
4570
|
+
const snIm = new Float64Array(restart);
|
|
4571
|
+
const gRe = new Float64Array(restart + 1);
|
|
4572
|
+
const gIm = new Float64Array(restart + 1);
|
|
4573
|
+
gRe[0] = beta;
|
|
4574
|
+
let converged = false;
|
|
4575
|
+
for (let j = 0; j < restart; j++) {
|
|
4576
|
+
innerIter = j + 1;
|
|
4577
|
+
const vjOff = j * n;
|
|
4578
|
+
let wRe, wIm;
|
|
4579
|
+
const mv = matvec({
|
|
4580
|
+
re: VRe.subarray(vjOff, vjOff + n),
|
|
4581
|
+
im: VIm.subarray(vjOff, vjOff + n)
|
|
4582
|
+
});
|
|
4583
|
+
wRe = mv.re;
|
|
4584
|
+
wIm = mv.im;
|
|
4585
|
+
if (precSolve) {
|
|
4586
|
+
const pw = precSolve({ re: wRe, im: wIm });
|
|
4587
|
+
wRe = pw.re;
|
|
4588
|
+
wIm = pw.im;
|
|
4589
|
+
}
|
|
4590
|
+
if (wRe.length !== n) wRe = new Float64Array(wRe);
|
|
4591
|
+
if (wIm.length !== n) wIm = new Float64Array(wIm);
|
|
4592
|
+
for (let i = 0; i <= j; i++) {
|
|
4593
|
+
const viOff = i * n;
|
|
4594
|
+
let dRe = 0, dIm = 0;
|
|
4595
|
+
for (let k = 0; k < n; k++) {
|
|
4596
|
+
dRe += VRe[viOff + k] * wRe[k] + VIm[viOff + k] * wIm[k];
|
|
4597
|
+
dIm += VRe[viOff + k] * wIm[k] - VIm[viOff + k] * wRe[k];
|
|
4598
|
+
}
|
|
4599
|
+
HRe[i + j * ldh] = dRe;
|
|
4600
|
+
HIm[i + j * ldh] = dIm;
|
|
4601
|
+
for (let k = 0; k < n; k++) {
|
|
4602
|
+
wRe[k] -= dRe * VRe[viOff + k] - dIm * VIm[viOff + k];
|
|
4603
|
+
wIm[k] -= dRe * VIm[viOff + k] + dIm * VRe[viOff + k];
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
const wnorm = cnrm2(wRe, wIm, n);
|
|
4607
|
+
HRe[j + 1 + j * ldh] = wnorm;
|
|
4608
|
+
if (wnorm > 1e-300) {
|
|
4609
|
+
const vOff = (j + 1) * n;
|
|
4610
|
+
for (let k = 0; k < n; k++) {
|
|
4611
|
+
VRe[vOff + k] = wRe[k] / wnorm;
|
|
4612
|
+
VIm[vOff + k] = wIm[k] / wnorm;
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
for (let i = 0; i < j; i++) {
|
|
4616
|
+
const c2 = cs[i], sR2 = snRe[i], sI2 = snIm[i];
|
|
4617
|
+
const hiR = HRe[i + j * ldh], hiI = HIm[i + j * ldh];
|
|
4618
|
+
const hi1R = HRe[i + 1 + j * ldh], hi1I = HIm[i + 1 + j * ldh];
|
|
4619
|
+
HRe[i + j * ldh] = c2 * hiR + (sR2 * hi1R - sI2 * hi1I);
|
|
4620
|
+
HIm[i + j * ldh] = c2 * hiI + (sR2 * hi1I + sI2 * hi1R);
|
|
4621
|
+
HRe[i + 1 + j * ldh] = -(sR2 * hiR + sI2 * hiI) + c2 * hi1R;
|
|
4622
|
+
HIm[i + 1 + j * ldh] = -(-sI2 * hiR + sR2 * hiI) + c2 * hi1I;
|
|
4623
|
+
}
|
|
4624
|
+
const aR = HRe[j + j * ldh], aI = HIm[j + j * ldh];
|
|
4625
|
+
const bR2 = HRe[j + 1 + j * ldh], bI2 = HIm[j + 1 + j * ldh];
|
|
4626
|
+
const {
|
|
4627
|
+
c,
|
|
4628
|
+
sRe: sR,
|
|
4629
|
+
sIm: sI,
|
|
4630
|
+
rRe: rrR,
|
|
4631
|
+
rIm: rrI
|
|
4632
|
+
} = complexGivens(aR, aI, bR2, bI2);
|
|
4633
|
+
cs[j] = c;
|
|
4634
|
+
snRe[j] = sR;
|
|
4635
|
+
snIm[j] = sI;
|
|
4636
|
+
HRe[j + j * ldh] = rrR;
|
|
4637
|
+
HIm[j + j * ldh] = rrI;
|
|
4638
|
+
HRe[j + 1 + j * ldh] = 0;
|
|
4639
|
+
HIm[j + 1 + j * ldh] = 0;
|
|
4640
|
+
const gjR = gRe[j], gjI = gIm[j];
|
|
4641
|
+
const gj1R = gRe[j + 1], gj1I = gIm[j + 1];
|
|
4642
|
+
gRe[j] = c * gjR + (sR * gj1R - sI * gj1I);
|
|
4643
|
+
gIm[j] = c * gjI + (sR * gj1I + sI * gj1R);
|
|
4644
|
+
gRe[j + 1] = -(sR * gjR + sI * gjI) + c * gj1R;
|
|
4645
|
+
gIm[j + 1] = -(-sI * gjR + sR * gjI) + c * gj1I;
|
|
4646
|
+
const residNorm = Math.sqrt(
|
|
4647
|
+
gRe[j + 1] * gRe[j + 1] + gIm[j + 1] * gIm[j + 1]
|
|
4648
|
+
);
|
|
4649
|
+
resvecList.push(residNorm);
|
|
4650
|
+
if (residNorm / normMb <= tol) {
|
|
4651
|
+
const { yRe: yRe2, yIm: yIm2 } = complexBackSolve(HRe, HIm, gRe, gIm, j + 1, ldh);
|
|
4652
|
+
for (let k = 0; k < n; k++) {
|
|
4653
|
+
for (let l = 0; l <= j; l++) {
|
|
4654
|
+
xRe[k] += VRe[k + l * n] * yRe2[l] - VIm[k + l * n] * yIm2[l];
|
|
4655
|
+
xIm[k] += VRe[k + l * n] * yIm2[l] + VIm[k + l * n] * yRe2[l];
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
flag = 0;
|
|
4659
|
+
converged = true;
|
|
4660
|
+
break;
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
if (converged) break;
|
|
4664
|
+
const { yRe, yIm } = complexBackSolve(HRe, HIm, gRe, gIm, restart, ldh);
|
|
4665
|
+
for (let k = 0; k < n; k++) {
|
|
4666
|
+
for (let l = 0; l < restart; l++) {
|
|
4667
|
+
xRe[k] += VRe[k + l * n] * yRe[l] - VIm[k + l * n] * yIm[l];
|
|
4668
|
+
xIm[k] += VRe[k + l * n] * yIm[l] + VIm[k + l * n] * yRe[l];
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
const ax2 = matvec({ re: xRe, im: xIm });
|
|
4672
|
+
rRe = new Float64Array(n);
|
|
4673
|
+
rIm = new Float64Array(n);
|
|
4674
|
+
for (let i = 0; i < n; i++) {
|
|
4675
|
+
rRe[i] = b.re[i] - ax2.re[i];
|
|
4676
|
+
rIm[i] = b.im[i] - ax2.im[i];
|
|
4677
|
+
}
|
|
4678
|
+
if (precSolve) {
|
|
4679
|
+
const pr = precSolve({ re: rRe, im: rIm });
|
|
4680
|
+
rRe = new Float64Array(pr.re);
|
|
4681
|
+
rIm = new Float64Array(pr.im);
|
|
4682
|
+
}
|
|
4683
|
+
beta = cnrm2(rRe, rIm, n);
|
|
4684
|
+
if (beta / normMb <= tol) {
|
|
4685
|
+
flag = 0;
|
|
4686
|
+
innerIter = 0;
|
|
4687
|
+
break;
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
let relres;
|
|
4691
|
+
if (flag === 0) {
|
|
4692
|
+
const ax3 = matvec({ re: xRe, im: xIm });
|
|
4693
|
+
let fRe = new Float64Array(n), fIm = new Float64Array(n);
|
|
4694
|
+
for (let i = 0; i < n; i++) {
|
|
4695
|
+
fRe[i] = b.re[i] - ax3.re[i];
|
|
4696
|
+
fIm[i] = b.im[i] - ax3.im[i];
|
|
4697
|
+
}
|
|
4698
|
+
if (precSolve) {
|
|
4699
|
+
const pr = precSolve({ re: fRe, im: fIm });
|
|
4700
|
+
fRe = new Float64Array(pr.re);
|
|
4701
|
+
fIm = new Float64Array(pr.im);
|
|
4702
|
+
}
|
|
4703
|
+
relres = cnrm2(fRe, fIm, n) / normMb;
|
|
4704
|
+
} else {
|
|
4705
|
+
relres = beta / normMb;
|
|
4706
|
+
}
|
|
4707
|
+
return {
|
|
4708
|
+
x: { re: xRe, im: xIm },
|
|
4709
|
+
flag,
|
|
4710
|
+
relres,
|
|
4711
|
+
iter: [outerIter, innerIter],
|
|
4712
|
+
resvec: new Float64Array(resvecList)
|
|
4713
|
+
};
|
|
4714
|
+
}
|
|
4715
|
+
function cnrm2(re2, im2, n) {
|
|
4716
|
+
let s = 0;
|
|
4717
|
+
for (let i = 0; i < n; i++) s += re2[i] * re2[i] + im2[i] * im2[i];
|
|
4718
|
+
return Math.sqrt(s);
|
|
4719
|
+
}
|
|
4720
|
+
function complexGivens(aRe, aIm, bRe, bIm) {
|
|
4721
|
+
const absB = Math.sqrt(bRe * bRe + bIm * bIm);
|
|
4722
|
+
if (absB === 0) return { c: 1, sRe: 0, sIm: 0, rRe: aRe, rIm: aIm };
|
|
4723
|
+
const absA = Math.sqrt(aRe * aRe + aIm * aIm);
|
|
4724
|
+
if (absA === 0)
|
|
4725
|
+
return { c: 0, sRe: bRe / absB, sIm: -bIm / absB, rRe: absB, rIm: 0 };
|
|
4726
|
+
const norm = Math.sqrt(absA * absA + absB * absB);
|
|
4727
|
+
const c = absA / norm;
|
|
4728
|
+
const alpRe = aRe / absA, alpIm = aIm / absA;
|
|
4729
|
+
const sRe2 = (alpRe * bRe + alpIm * bIm) / norm;
|
|
4730
|
+
const sIm2 = (alpIm * bRe - alpRe * bIm) / norm;
|
|
4731
|
+
return { c, sRe: sRe2, sIm: sIm2, rRe: alpRe * norm, rIm: alpIm * norm };
|
|
4732
|
+
}
|
|
4733
|
+
function complexBackSolve(HRe, HIm, gRe, gIm, m, ldh) {
|
|
4734
|
+
const yRe = new Float64Array(m);
|
|
4735
|
+
const yIm = new Float64Array(m);
|
|
4736
|
+
for (let i = 0; i < m; i++) {
|
|
4737
|
+
yRe[i] = gRe[i];
|
|
4738
|
+
yIm[i] = gIm[i];
|
|
4739
|
+
}
|
|
4740
|
+
for (let i = m - 1; i >= 0; i--) {
|
|
4741
|
+
for (let j = i + 1; j < m; j++) {
|
|
4742
|
+
const hR = HRe[i + j * ldh], hI = HIm[i + j * ldh];
|
|
4743
|
+
yRe[i] -= hR * yRe[j] - hI * yIm[j];
|
|
4744
|
+
yIm[i] -= hR * yIm[j] + hI * yRe[j];
|
|
4745
|
+
}
|
|
4746
|
+
const dR = HRe[i + i * ldh], dI = HIm[i + i * ldh];
|
|
4747
|
+
const dAbs2 = dR * dR + dI * dI;
|
|
4748
|
+
const tmpR = yRe[i], tmpI = yIm[i];
|
|
4749
|
+
yRe[i] = (tmpR * dR + tmpI * dI) / dAbs2;
|
|
4750
|
+
yIm[i] = (tmpI * dR - tmpR * dI) / dAbs2;
|
|
4751
|
+
}
|
|
4752
|
+
return { yRe, yIm };
|
|
4753
|
+
}
|
|
4754
|
+
function complexLuSolveInPlace(n, LURe, LUIm, ipiv, rhsRe, rhsIm) {
|
|
4755
|
+
for (let i = 0; i < n; i++) {
|
|
4756
|
+
const pi = ipiv[i] - 1;
|
|
4757
|
+
if (pi !== i) {
|
|
4758
|
+
let tmp = rhsRe[i];
|
|
4759
|
+
rhsRe[i] = rhsRe[pi];
|
|
4760
|
+
rhsRe[pi] = tmp;
|
|
4761
|
+
tmp = rhsIm[i];
|
|
4762
|
+
rhsIm[i] = rhsIm[pi];
|
|
4763
|
+
rhsIm[pi] = tmp;
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
for (let i = 1; i < n; i++) {
|
|
4767
|
+
for (let j = 0; j < i; j++) {
|
|
4768
|
+
const lR = LURe[i + j * n], lI = LUIm[i + j * n];
|
|
4769
|
+
rhsRe[i] -= lR * rhsRe[j] - lI * rhsIm[j];
|
|
4770
|
+
rhsIm[i] -= lR * rhsIm[j] + lI * rhsRe[j];
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
4774
|
+
for (let j = i + 1; j < n; j++) {
|
|
4775
|
+
const uR = LURe[i + j * n], uI = LUIm[i + j * n];
|
|
4776
|
+
rhsRe[i] -= uR * rhsRe[j] - uI * rhsIm[j];
|
|
4777
|
+
rhsIm[i] -= uR * rhsIm[j] + uI * rhsRe[j];
|
|
4778
|
+
}
|
|
4779
|
+
const dR = LURe[i + i * n], dI = LUIm[i + i * n];
|
|
4780
|
+
const dAbs2 = dR * dR + dI * dI;
|
|
4781
|
+
const tmpR = rhsRe[i], tmpI = rhsIm[i];
|
|
4782
|
+
rhsRe[i] = (tmpR * dR + tmpI * dI) / dAbs2;
|
|
4783
|
+
rhsIm[i] = (tmpI * dR - tmpR * dI) / dAbs2;
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4786
|
+
function luSolveInPlace(n, LU, ipiv, rhs) {
|
|
4787
|
+
for (let i = 0; i < n; i++) {
|
|
4788
|
+
const pi = ipiv[i] - 1;
|
|
4789
|
+
if (pi !== i) {
|
|
4790
|
+
const tmp = rhs[i];
|
|
4791
|
+
rhs[i] = rhs[pi];
|
|
4792
|
+
rhs[pi] = tmp;
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
for (let i = 1; i < n; i++) {
|
|
4796
|
+
for (let j = 0; j < i; j++) rhs[i] -= LU[i + j * n] * rhs[j];
|
|
4797
|
+
}
|
|
4798
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
4799
|
+
for (let j = i + 1; j < n; j++) rhs[i] -= LU[i + j * n] * rhs[j];
|
|
4800
|
+
rhs[i] /= LU[i + i * n];
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4382
4804
|
// src/ts-lapack/src/BLAS/dgemv.ts
|
|
4383
4805
|
function dgemv(trans, m, n, alpha, a, aOff, lda, x, xOff, incx, beta, y, yOff, incy) {
|
|
4384
4806
|
const notrans = trans === NOTRANS;
|
|
@@ -19940,6 +20362,160 @@ function cholComplex(dataRe, dataIm, n, upper) {
|
|
|
19940
20362
|
}
|
|
19941
20363
|
return { RRe: re2, RIm: im2, info };
|
|
19942
20364
|
}
|
|
20365
|
+
function gmres(A, n, b, restart, tol, maxit, M1, M2, x0) {
|
|
20366
|
+
const matvecFn = (x) => {
|
|
20367
|
+
const y = new Float64Array(n);
|
|
20368
|
+
for (let i = 0; i < n; i++) {
|
|
20369
|
+
let s = 0;
|
|
20370
|
+
for (let j = 0; j < n; j++) s += A[i + j * n] * x[j];
|
|
20371
|
+
y[i] = s;
|
|
20372
|
+
}
|
|
20373
|
+
return y;
|
|
20374
|
+
};
|
|
20375
|
+
let precSolveFn = null;
|
|
20376
|
+
if (M1 || M2) {
|
|
20377
|
+
const m1lu = M1 ? new Float64Array(M1) : null;
|
|
20378
|
+
const m1ipiv = M1 ? new Int32Array(n) : null;
|
|
20379
|
+
if (m1lu && m1ipiv) {
|
|
20380
|
+
const info = dgetrf(n, n, m1lu, n, m1ipiv);
|
|
20381
|
+
if (info > 0) throw new Error("gmres: preconditioner M1 is singular");
|
|
20382
|
+
}
|
|
20383
|
+
const m2lu = M2 ? new Float64Array(M2) : null;
|
|
20384
|
+
const m2ipiv = M2 ? new Int32Array(n) : null;
|
|
20385
|
+
if (m2lu && m2ipiv) {
|
|
20386
|
+
const info = dgetrf(n, n, m2lu, n, m2ipiv);
|
|
20387
|
+
if (info > 0) throw new Error("gmres: preconditioner M2 is singular");
|
|
20388
|
+
}
|
|
20389
|
+
precSolveFn = (r) => {
|
|
20390
|
+
const z = new Float64Array(r);
|
|
20391
|
+
if (m1lu && m1ipiv) luSolveInPlace(n, m1lu, m1ipiv, z);
|
|
20392
|
+
if (m2lu && m2ipiv) luSolveInPlace(n, m2lu, m2ipiv, z);
|
|
20393
|
+
return z;
|
|
20394
|
+
};
|
|
20395
|
+
}
|
|
20396
|
+
const result = gmresCore(
|
|
20397
|
+
matvecFn,
|
|
20398
|
+
precSolveFn,
|
|
20399
|
+
b,
|
|
20400
|
+
n,
|
|
20401
|
+
restart,
|
|
20402
|
+
tol,
|
|
20403
|
+
maxit,
|
|
20404
|
+
x0
|
|
20405
|
+
);
|
|
20406
|
+
const iterArr = new Int32Array(2);
|
|
20407
|
+
iterArr[0] = result.iter[0];
|
|
20408
|
+
iterArr[1] = result.iter[1];
|
|
20409
|
+
return {
|
|
20410
|
+
x: result.x,
|
|
20411
|
+
flag: result.flag,
|
|
20412
|
+
relres: result.relres,
|
|
20413
|
+
iter: iterArr,
|
|
20414
|
+
resvec: result.resvec
|
|
20415
|
+
};
|
|
20416
|
+
}
|
|
20417
|
+
function gmresComplex(ARe, AIm, n, bRe, bIm, restart, tol, maxit, M1Re, M1Im, M2Re, M2Im, x0Re, x0Im) {
|
|
20418
|
+
const matvecFn = (x) => {
|
|
20419
|
+
const yRe = new Float64Array(n);
|
|
20420
|
+
const yIm = new Float64Array(n);
|
|
20421
|
+
for (let i = 0; i < n; i++) {
|
|
20422
|
+
let sRe2 = 0, sIm2 = 0;
|
|
20423
|
+
for (let j = 0; j < n; j++) {
|
|
20424
|
+
const aR = ARe[i + j * n], aI = AIm[i + j * n];
|
|
20425
|
+
sRe2 += aR * x.re[j] - aI * x.im[j];
|
|
20426
|
+
sIm2 += aR * x.im[j] + aI * x.re[j];
|
|
20427
|
+
}
|
|
20428
|
+
yRe[i] = sRe2;
|
|
20429
|
+
yIm[i] = sIm2;
|
|
20430
|
+
}
|
|
20431
|
+
return { re: yRe, im: yIm };
|
|
20432
|
+
};
|
|
20433
|
+
let precSolveFn = null;
|
|
20434
|
+
if (M1Re || M2Re) {
|
|
20435
|
+
const m1luRe = M1Re ? new Float64Array(M1Re) : null;
|
|
20436
|
+
const m1luIm = M1Im ? new Float64Array(M1Im) : null;
|
|
20437
|
+
const m1ipiv = M1Re ? new Int32Array(n) : null;
|
|
20438
|
+
if (m1luRe && m1luIm && m1ipiv) {
|
|
20439
|
+
complexLuFactor(n, m1luRe, m1luIm, m1ipiv);
|
|
20440
|
+
}
|
|
20441
|
+
const m2luRe = M2Re ? new Float64Array(M2Re) : null;
|
|
20442
|
+
const m2luIm = M2Im ? new Float64Array(M2Im) : null;
|
|
20443
|
+
const m2ipiv = M2Re ? new Int32Array(n) : null;
|
|
20444
|
+
if (m2luRe && m2luIm && m2ipiv) {
|
|
20445
|
+
complexLuFactor(n, m2luRe, m2luIm, m2ipiv);
|
|
20446
|
+
}
|
|
20447
|
+
precSolveFn = (r) => {
|
|
20448
|
+
const zRe = new Float64Array(r.re);
|
|
20449
|
+
const zIm = new Float64Array(r.im);
|
|
20450
|
+
if (m1luRe && m1luIm && m1ipiv)
|
|
20451
|
+
complexLuSolveInPlace(n, m1luRe, m1luIm, m1ipiv, zRe, zIm);
|
|
20452
|
+
if (m2luRe && m2luIm && m2ipiv)
|
|
20453
|
+
complexLuSolveInPlace(n, m2luRe, m2luIm, m2ipiv, zRe, zIm);
|
|
20454
|
+
return { re: zRe, im: zIm };
|
|
20455
|
+
};
|
|
20456
|
+
}
|
|
20457
|
+
const result = gmresCoreComplex(
|
|
20458
|
+
matvecFn,
|
|
20459
|
+
precSolveFn,
|
|
20460
|
+
{ re: bRe, im: bIm },
|
|
20461
|
+
n,
|
|
20462
|
+
restart,
|
|
20463
|
+
tol,
|
|
20464
|
+
maxit,
|
|
20465
|
+
x0Re && x0Im ? { re: x0Re, im: x0Im } : null
|
|
20466
|
+
);
|
|
20467
|
+
const iterArr = new Int32Array(2);
|
|
20468
|
+
iterArr[0] = result.iter[0];
|
|
20469
|
+
iterArr[1] = result.iter[1];
|
|
20470
|
+
return {
|
|
20471
|
+
xRe: result.x.re,
|
|
20472
|
+
xIm: result.x.im,
|
|
20473
|
+
flag: result.flag,
|
|
20474
|
+
relres: result.relres,
|
|
20475
|
+
iter: iterArr,
|
|
20476
|
+
resvec: result.resvec
|
|
20477
|
+
};
|
|
20478
|
+
}
|
|
20479
|
+
function complexLuFactor(n, re2, im2, ipiv) {
|
|
20480
|
+
for (let k = 0; k < n; k++) {
|
|
20481
|
+
let maxVal = -1;
|
|
20482
|
+
let maxIdx = k;
|
|
20483
|
+
for (let i = k; i < n; i++) {
|
|
20484
|
+
const v = Math.sqrt(
|
|
20485
|
+
re2[i + k * n] * re2[i + k * n] + im2[i + k * n] * im2[i + k * n]
|
|
20486
|
+
);
|
|
20487
|
+
if (v > maxVal) {
|
|
20488
|
+
maxVal = v;
|
|
20489
|
+
maxIdx = i;
|
|
20490
|
+
}
|
|
20491
|
+
}
|
|
20492
|
+
ipiv[k] = maxIdx + 1;
|
|
20493
|
+
if (maxIdx !== k) {
|
|
20494
|
+
for (let j = 0; j < n; j++) {
|
|
20495
|
+
let tmp = re2[k + j * n];
|
|
20496
|
+
re2[k + j * n] = re2[maxIdx + j * n];
|
|
20497
|
+
re2[maxIdx + j * n] = tmp;
|
|
20498
|
+
tmp = im2[k + j * n];
|
|
20499
|
+
im2[k + j * n] = im2[maxIdx + j * n];
|
|
20500
|
+
im2[maxIdx + j * n] = tmp;
|
|
20501
|
+
}
|
|
20502
|
+
}
|
|
20503
|
+
const dR = re2[k + k * n], dI = im2[k + k * n];
|
|
20504
|
+
const dAbs2 = dR * dR + dI * dI;
|
|
20505
|
+
if (dAbs2 === 0) continue;
|
|
20506
|
+
for (let i = k + 1; i < n; i++) {
|
|
20507
|
+
const aR = re2[i + k * n], aI = im2[i + k * n];
|
|
20508
|
+
const lR = (aR * dR + aI * dI) / dAbs2;
|
|
20509
|
+
const lI = (aI * dR - aR * dI) / dAbs2;
|
|
20510
|
+
re2[i + k * n] = lR;
|
|
20511
|
+
im2[i + k * n] = lI;
|
|
20512
|
+
for (let j = k + 1; j < n; j++) {
|
|
20513
|
+
re2[i + j * n] -= lR * re2[k + j * n] - lI * im2[k + j * n];
|
|
20514
|
+
im2[i + j * n] -= lR * im2[k + j * n] + lI * re2[k + j * n];
|
|
20515
|
+
}
|
|
20516
|
+
}
|
|
20517
|
+
}
|
|
20518
|
+
}
|
|
19943
20519
|
var _bridge2 = {
|
|
19944
20520
|
inv,
|
|
19945
20521
|
matmul,
|
|
@@ -19950,7 +20526,9 @@ var _bridge2 = {
|
|
|
19950
20526
|
lu,
|
|
19951
20527
|
svd,
|
|
19952
20528
|
chol,
|
|
19953
|
-
cholComplex
|
|
20529
|
+
cholComplex,
|
|
20530
|
+
gmres,
|
|
20531
|
+
gmresComplex
|
|
19954
20532
|
};
|
|
19955
20533
|
function getTsLapackBridge() {
|
|
19956
20534
|
return _bridge2;
|
|
@@ -22141,11 +22719,27 @@ function catAlongDim(values, dimIdx) {
|
|
|
22141
22719
|
if (tensors.length === 0) return RTV.tensor(new FloatXArray(0), [0, 0]);
|
|
22142
22720
|
if (tensors.length === 1) return tensors[0];
|
|
22143
22721
|
const ndim = Math.max(2, ...tensors.map((t) => t.shape.length));
|
|
22144
|
-
|
|
22722
|
+
let shapes = tensors.map((t) => {
|
|
22145
22723
|
const s = [...t.shape];
|
|
22146
22724
|
while (s.length < ndim) s.push(1);
|
|
22147
22725
|
return s;
|
|
22148
22726
|
});
|
|
22727
|
+
const refIdx = tensors.findIndex((t) => t.data.length > 0);
|
|
22728
|
+
if (refIdx >= 0) {
|
|
22729
|
+
const ref = shapes[refIdx];
|
|
22730
|
+
const keep = tensors.map((t, i) => {
|
|
22731
|
+
if (t.data.length > 0) return true;
|
|
22732
|
+
for (let d = 0; d < ndim; d++) {
|
|
22733
|
+
if (d === dimIdx) continue;
|
|
22734
|
+
if (shapes[i][d] !== ref[d]) return false;
|
|
22735
|
+
}
|
|
22736
|
+
return true;
|
|
22737
|
+
});
|
|
22738
|
+
tensors = tensors.filter((_, i) => keep[i]);
|
|
22739
|
+
shapes = shapes.filter((_, i) => keep[i]);
|
|
22740
|
+
if (tensors.length === 0) return RTV.tensor(new FloatXArray(0), [0, 0]);
|
|
22741
|
+
if (tensors.length === 1) return tensors[0];
|
|
22742
|
+
}
|
|
22149
22743
|
const refShape = shapes[0];
|
|
22150
22744
|
for (let i = 1; i < shapes.length; i++) {
|
|
22151
22745
|
for (let d = 0; d < ndim; d++) {
|
|
@@ -27104,6 +27698,8 @@ function dispatchPlotCall(rt, name, args) {
|
|
|
27104
27698
|
return rt.scatter_call(args.map((a) => ensureRuntimeValue(a)));
|
|
27105
27699
|
case "imagesc":
|
|
27106
27700
|
return rt.imagesc_call(args.map((a) => ensureRuntimeValue(a)));
|
|
27701
|
+
case "pcolor":
|
|
27702
|
+
return rt.pcolor_call(args.map((a) => ensureRuntimeValue(a)));
|
|
27107
27703
|
case "contour":
|
|
27108
27704
|
return rt.contour_call(
|
|
27109
27705
|
args.map((a) => ensureRuntimeValue(a)),
|
|
@@ -28412,10 +29008,10 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
|
|
|
28412
29008
|
let stride = 1;
|
|
28413
29009
|
for (let k = 0; k < nIdx; k++) {
|
|
28414
29010
|
const dimSize = k < s.length ? s[k] : 1;
|
|
28415
|
-
const
|
|
28416
|
-
if (
|
|
29011
|
+
const sub2 = Math.round(indices[k]) - 1;
|
|
29012
|
+
if (sub2 < 0 || sub2 >= dimSize)
|
|
28417
29013
|
throw new RuntimeError("Index exceeds array bounds");
|
|
28418
|
-
lin +=
|
|
29014
|
+
lin += sub2 * stride;
|
|
28419
29015
|
stride *= dimSize;
|
|
28420
29016
|
}
|
|
28421
29017
|
if (t.imag !== void 0) {
|
|
@@ -28612,16 +29208,24 @@ function indexStore(rt, base, indices, rhs, skipSubsasgn = false) {
|
|
|
28612
29208
|
}
|
|
28613
29209
|
return dictInsertSingle(mv, key, rhsMv2);
|
|
28614
29210
|
}
|
|
28615
|
-
if (indices.length === 1 && (isRuntimeStructArray(mv) || isRuntimeTensor(mv) && mv.data.length === 0)) {
|
|
29211
|
+
if (indices.length === 1 && (isRuntimeStructArray(mv) || isRuntimeStruct(mv) || isRuntimeTensor(mv) && mv.data.length === 0)) {
|
|
28616
29212
|
const rhsMv2 = ensureRuntimeValue(rhs);
|
|
28617
29213
|
if (isRuntimeStruct(rhsMv2)) {
|
|
28618
29214
|
const idxVal = ensureRuntimeValue(indices[0]);
|
|
28619
29215
|
const k = Math.round(toNumber(idxVal)) - 1;
|
|
28620
|
-
const existingElements = isRuntimeStructArray(mv) ? [...mv.elements] : [];
|
|
28621
|
-
const existingFieldNames = isRuntimeStructArray(mv) ? mv.fieldNames : [];
|
|
29216
|
+
const existingElements = isRuntimeStructArray(mv) ? [...mv.elements] : isRuntimeStruct(mv) ? [mv] : [];
|
|
29217
|
+
const existingFieldNames = isRuntimeStructArray(mv) ? mv.fieldNames : isRuntimeStruct(mv) ? [...mv.fields.keys()] : [];
|
|
28622
29218
|
const allFieldNames = [
|
|
28623
29219
|
.../* @__PURE__ */ new Set([...existingFieldNames, ...[...rhsMv2.fields.keys()]])
|
|
28624
29220
|
];
|
|
29221
|
+
for (let ei = 0; ei < existingElements.length; ei++) {
|
|
29222
|
+
const el = existingElements[ei];
|
|
29223
|
+
for (const f of allFieldNames) {
|
|
29224
|
+
if (!el.fields.has(f)) {
|
|
29225
|
+
el.fields.set(f, RTV.tensor(new FloatXArray(0), [0, 0]));
|
|
29226
|
+
}
|
|
29227
|
+
}
|
|
29228
|
+
}
|
|
28625
29229
|
while (existingElements.length <= k) {
|
|
28626
29230
|
existingElements.push(
|
|
28627
29231
|
RTV.struct(
|
|
@@ -29123,7 +29727,7 @@ registerIBuiltin({
|
|
|
29123
29727
|
};
|
|
29124
29728
|
}
|
|
29125
29729
|
});
|
|
29126
|
-
for (const name of ["groot", "gcf", "gca", "shg", "newplot"
|
|
29730
|
+
for (const name of ["groot", "gcf", "gca", "shg", "newplot"]) {
|
|
29127
29731
|
registerIBuiltin({
|
|
29128
29732
|
name,
|
|
29129
29733
|
resolve: () => ({
|
|
@@ -29136,7 +29740,32 @@ registerIBuiltin({
|
|
|
29136
29740
|
name: "get",
|
|
29137
29741
|
resolve: () => ({
|
|
29138
29742
|
outputTypes: [{ kind: "unknown" }],
|
|
29139
|
-
apply: () =>
|
|
29743
|
+
apply: (args) => {
|
|
29744
|
+
if (args.length >= 2) {
|
|
29745
|
+
const prop = args[1];
|
|
29746
|
+
const propStr = isRuntimeChar(prop) ? prop.value : isRuntimeString(prop) ? prop : "";
|
|
29747
|
+
if (propStr.toLowerCase() === "colormap") {
|
|
29748
|
+
const n = 64;
|
|
29749
|
+
const data = new Float64Array(n * 3);
|
|
29750
|
+
for (let i = 0; i < n; i++) {
|
|
29751
|
+
const t = i / (n - 1);
|
|
29752
|
+
if (t < 0.5) {
|
|
29753
|
+
const s = t * 2;
|
|
29754
|
+
data[i] = 0.2 * (1 - s);
|
|
29755
|
+
data[n + i] = 0.1 + 0.6 * s;
|
|
29756
|
+
data[2 * n + i] = 0.9 - 0.3 * s;
|
|
29757
|
+
} else {
|
|
29758
|
+
const s = (t - 0.5) * 2;
|
|
29759
|
+
data[i] = 0.2 + 0.8 * s;
|
|
29760
|
+
data[n + i] = 0.7 + 0.3 * s;
|
|
29761
|
+
data[2 * n + i] = 0.6 - 0.5 * s;
|
|
29762
|
+
}
|
|
29763
|
+
}
|
|
29764
|
+
return RTV.tensor(data, [n, 3]);
|
|
29765
|
+
}
|
|
29766
|
+
}
|
|
29767
|
+
return RTV.dummyHandle();
|
|
29768
|
+
}
|
|
29140
29769
|
})
|
|
29141
29770
|
});
|
|
29142
29771
|
registerIBuiltin({
|
|
@@ -29562,13 +30191,7 @@ registerIBuiltin({
|
|
|
29562
30191
|
})
|
|
29563
30192
|
});
|
|
29564
30193
|
function getMexExt() {
|
|
29565
|
-
|
|
29566
|
-
const platform = process.platform;
|
|
29567
|
-
const cpuArch = process.arch;
|
|
29568
|
-
if (platform === "win32") return "mexw64";
|
|
29569
|
-
if (platform === "darwin")
|
|
29570
|
-
return cpuArch === "arm64" ? "mexmaca64" : "mexmaci64";
|
|
29571
|
-
return "mexa64";
|
|
30194
|
+
return "numbl.js";
|
|
29572
30195
|
}
|
|
29573
30196
|
defineBuiltin({
|
|
29574
30197
|
name: "mexext",
|
|
@@ -30115,6 +30738,84 @@ function expandXY(xVal, yVal, rows, cols) {
|
|
|
30115
30738
|
}
|
|
30116
30739
|
return { x, y };
|
|
30117
30740
|
}
|
|
30741
|
+
var PCOLOR_NAME_VALUE_KEYS = /* @__PURE__ */ new Set(["edgecolor", "facealpha"]);
|
|
30742
|
+
function isPcolorNameValueKey(v) {
|
|
30743
|
+
if (!isRuntimeString(v) && !isRuntimeChar(v)) return null;
|
|
30744
|
+
const lower = isRuntimeString(v) ? v.toLocaleLowerCase() : v.value.toLowerCase();
|
|
30745
|
+
if (PCOLOR_NAME_VALUE_KEYS.has(lower)) return lower;
|
|
30746
|
+
return null;
|
|
30747
|
+
}
|
|
30748
|
+
function applyPcolorNameValue(trace, key, value) {
|
|
30749
|
+
switch (key) {
|
|
30750
|
+
case "edgecolor": {
|
|
30751
|
+
const s = getStringValueIfString(value);
|
|
30752
|
+
if (s !== void 0 && s.toLowerCase() === "none") {
|
|
30753
|
+
trace.edgeColor = "none";
|
|
30754
|
+
break;
|
|
30755
|
+
}
|
|
30756
|
+
const c = resolveColor(value);
|
|
30757
|
+
if (c) trace.edgeColor = c;
|
|
30758
|
+
break;
|
|
30759
|
+
}
|
|
30760
|
+
case "facealpha": {
|
|
30761
|
+
const n = typeof value === "number" ? value : toNumber(value);
|
|
30762
|
+
trace.faceAlpha = n;
|
|
30763
|
+
break;
|
|
30764
|
+
}
|
|
30765
|
+
}
|
|
30766
|
+
}
|
|
30767
|
+
function parsePcolorArgs(args) {
|
|
30768
|
+
let pos = 0;
|
|
30769
|
+
let xData;
|
|
30770
|
+
let yData;
|
|
30771
|
+
let cData;
|
|
30772
|
+
let rows;
|
|
30773
|
+
let cols;
|
|
30774
|
+
let numericCount = 0;
|
|
30775
|
+
for (let i = pos; i < args.length; i++) {
|
|
30776
|
+
if (isNumericArg(args[i])) numericCount++;
|
|
30777
|
+
else break;
|
|
30778
|
+
}
|
|
30779
|
+
if (numericCount === 1) {
|
|
30780
|
+
const c = args[pos++];
|
|
30781
|
+
const info = getMatrixInfo(c);
|
|
30782
|
+
rows = info.rows;
|
|
30783
|
+
cols = info.cols;
|
|
30784
|
+
cData = info.data;
|
|
30785
|
+
const gen = generateMeshgrid(rows, cols);
|
|
30786
|
+
xData = gen.x;
|
|
30787
|
+
yData = gen.y;
|
|
30788
|
+
} else if (numericCount >= 3) {
|
|
30789
|
+
const x = args[pos++];
|
|
30790
|
+
const y = args[pos++];
|
|
30791
|
+
const c = args[pos++];
|
|
30792
|
+
const cInfo = getMatrixInfo(c);
|
|
30793
|
+
rows = cInfo.rows;
|
|
30794
|
+
cols = cInfo.cols;
|
|
30795
|
+
cData = cInfo.data;
|
|
30796
|
+
const expanded = expandXY(x, y, rows, cols);
|
|
30797
|
+
xData = expanded.x;
|
|
30798
|
+
yData = expanded.y;
|
|
30799
|
+
} else {
|
|
30800
|
+
throw new Error("pcolor requires 1 or 3 numeric input arguments");
|
|
30801
|
+
}
|
|
30802
|
+
const trace = {
|
|
30803
|
+
x: xData,
|
|
30804
|
+
y: yData,
|
|
30805
|
+
c: cData,
|
|
30806
|
+
rows,
|
|
30807
|
+
cols
|
|
30808
|
+
};
|
|
30809
|
+
while (pos < args.length) {
|
|
30810
|
+
const key = isPcolorNameValueKey(args[pos]);
|
|
30811
|
+
if (!key) break;
|
|
30812
|
+
pos++;
|
|
30813
|
+
if (pos >= args.length) break;
|
|
30814
|
+
const value = args[pos++];
|
|
30815
|
+
applyPcolorNameValue(trace, key, value);
|
|
30816
|
+
}
|
|
30817
|
+
return trace;
|
|
30818
|
+
}
|
|
30118
30819
|
function applySurfNameValue(trace, key, value) {
|
|
30119
30820
|
switch (key) {
|
|
30120
30821
|
case "edgecolor": {
|
|
@@ -31150,24 +31851,38 @@ function plotInstr(plotInstructions, instr) {
|
|
|
31150
31851
|
value: resolveOnOff(instr.value)
|
|
31151
31852
|
});
|
|
31152
31853
|
break;
|
|
31153
|
-
case "set_colorbar":
|
|
31154
|
-
|
|
31854
|
+
case "set_colorbar": {
|
|
31855
|
+
const cbInstr = {
|
|
31155
31856
|
type: "set_colorbar",
|
|
31156
31857
|
value: resolveStr(instr.value)
|
|
31157
|
-
}
|
|
31858
|
+
};
|
|
31859
|
+
if (instr.location !== void 0) {
|
|
31860
|
+
cbInstr.location = resolveStr(instr.location);
|
|
31861
|
+
}
|
|
31862
|
+
plotInstructions.push(cbInstr);
|
|
31158
31863
|
break;
|
|
31159
|
-
|
|
31160
|
-
|
|
31864
|
+
}
|
|
31865
|
+
case "set_colormap": {
|
|
31866
|
+
const cmInstr = {
|
|
31161
31867
|
type: "set_colormap",
|
|
31162
31868
|
name: resolveStr(instr.name).replace(/^"|"$/g, "")
|
|
31163
|
-
}
|
|
31869
|
+
};
|
|
31870
|
+
if (instr.data) cmInstr.data = instr.data;
|
|
31871
|
+
plotInstructions.push(cmInstr);
|
|
31164
31872
|
break;
|
|
31873
|
+
}
|
|
31165
31874
|
case "set_axis":
|
|
31166
31875
|
plotInstructions.push({
|
|
31167
31876
|
type: "set_axis",
|
|
31168
31877
|
value: resolveStr(instr.value).replace(/^"|"$/g, "")
|
|
31169
31878
|
});
|
|
31170
31879
|
break;
|
|
31880
|
+
case "set_caxis":
|
|
31881
|
+
plotInstructions.push({
|
|
31882
|
+
type: "set_caxis",
|
|
31883
|
+
limits: instr.limits
|
|
31884
|
+
});
|
|
31885
|
+
break;
|
|
31171
31886
|
}
|
|
31172
31887
|
}
|
|
31173
31888
|
function viewCall(plotInstructions, args) {
|
|
@@ -31210,6 +31925,10 @@ function imagescCall(plotInstructions, args) {
|
|
|
31210
31925
|
const trace = parseImagescArgs(args);
|
|
31211
31926
|
plotInstructions.push({ type: "imagesc", trace });
|
|
31212
31927
|
}
|
|
31928
|
+
function pcolorCall(plotInstructions, args) {
|
|
31929
|
+
const trace = parsePcolorArgs(args);
|
|
31930
|
+
plotInstructions.push({ type: "pcolor", trace });
|
|
31931
|
+
}
|
|
31213
31932
|
function contourCall(plotInstructions, args, filled) {
|
|
31214
31933
|
const trace = parseContourArgs(args, filled);
|
|
31215
31934
|
plotInstructions.push({ type: "contour", trace });
|
|
@@ -31972,6 +32691,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
31972
32691
|
"surf",
|
|
31973
32692
|
"scatter",
|
|
31974
32693
|
"imagesc",
|
|
32694
|
+
"pcolor",
|
|
31975
32695
|
"contour",
|
|
31976
32696
|
"contourf",
|
|
31977
32697
|
"mesh",
|
|
@@ -32014,6 +32734,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
32014
32734
|
"zlabel",
|
|
32015
32735
|
"colorbar",
|
|
32016
32736
|
"axis",
|
|
32737
|
+
"caxis",
|
|
32017
32738
|
"mfilename",
|
|
32018
32739
|
"addpath",
|
|
32019
32740
|
"rmpath",
|
|
@@ -32039,7 +32760,8 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
32039
32760
|
"ode23",
|
|
32040
32761
|
"deval",
|
|
32041
32762
|
"toc",
|
|
32042
|
-
"quadgk"
|
|
32763
|
+
"quadgk",
|
|
32764
|
+
"gmres"
|
|
32043
32765
|
];
|
|
32044
32766
|
|
|
32045
32767
|
// src/numbl-core/runtime/specialBuiltins.ts
|
|
@@ -33379,6 +34101,53 @@ function registerSpecialBuiltins(rt) {
|
|
|
33379
34101
|
plotInstr(rt.plotInstructions, { type: "clf" });
|
|
33380
34102
|
return nargout >= 1 ? RTV.num(1) : void 0;
|
|
33381
34103
|
});
|
|
34104
|
+
registerSpecial("colorbar", (nargout, args) => {
|
|
34105
|
+
const LOCATIONS = /* @__PURE__ */ new Set([
|
|
34106
|
+
"east",
|
|
34107
|
+
"west",
|
|
34108
|
+
"north",
|
|
34109
|
+
"south",
|
|
34110
|
+
"eastoutside",
|
|
34111
|
+
"westoutside",
|
|
34112
|
+
"northoutside",
|
|
34113
|
+
"southoutside"
|
|
34114
|
+
]);
|
|
34115
|
+
let value = "on";
|
|
34116
|
+
let location;
|
|
34117
|
+
let i = 0;
|
|
34118
|
+
while (i < args.length) {
|
|
34119
|
+
let s;
|
|
34120
|
+
try {
|
|
34121
|
+
s = toString(args[i]);
|
|
34122
|
+
} catch {
|
|
34123
|
+
break;
|
|
34124
|
+
}
|
|
34125
|
+
const lower = s.toLowerCase();
|
|
34126
|
+
if (lower === "off") {
|
|
34127
|
+
value = "off";
|
|
34128
|
+
i++;
|
|
34129
|
+
continue;
|
|
34130
|
+
}
|
|
34131
|
+
if (LOCATIONS.has(lower)) {
|
|
34132
|
+
location = lower;
|
|
34133
|
+
i++;
|
|
34134
|
+
continue;
|
|
34135
|
+
}
|
|
34136
|
+
i += 2;
|
|
34137
|
+
}
|
|
34138
|
+
plotInstr(rt.plotInstructions, {
|
|
34139
|
+
type: "set_colorbar",
|
|
34140
|
+
value,
|
|
34141
|
+
location
|
|
34142
|
+
});
|
|
34143
|
+
if (nargout >= 1) {
|
|
34144
|
+
return RTV.struct({
|
|
34145
|
+
Location: RTV.char(location ?? "eastoutside"),
|
|
34146
|
+
Visible: RTV.char(value === "off" ? "off" : "on")
|
|
34147
|
+
});
|
|
34148
|
+
}
|
|
34149
|
+
return void 0;
|
|
34150
|
+
});
|
|
33382
34151
|
registerSpecial("ode45", (nargout, args) => {
|
|
33383
34152
|
return _ode45Impl(rt, nargout, args, dormandPrince45);
|
|
33384
34153
|
});
|
|
@@ -33388,6 +34157,9 @@ function registerSpecialBuiltins(rt) {
|
|
|
33388
34157
|
registerSpecial("deval", (_nargout, args) => {
|
|
33389
34158
|
return _devalImpl(args);
|
|
33390
34159
|
});
|
|
34160
|
+
registerSpecial("gmres", (nargout, args) => {
|
|
34161
|
+
return _gmresImpl(rt, nargout, args);
|
|
34162
|
+
});
|
|
33391
34163
|
}
|
|
33392
34164
|
function _ode45Impl(rt, nargout, args, tableau = dormandPrince45) {
|
|
33393
34165
|
const solverName = tableau.name;
|
|
@@ -33616,6 +34388,530 @@ function _devalImpl(args) {
|
|
|
33616
34388
|
}
|
|
33617
34389
|
return RTV.tensor(yData, [neq, nPts]);
|
|
33618
34390
|
}
|
|
34391
|
+
function _gmresImpl(rt, nargout, args) {
|
|
34392
|
+
if (args.length < 2)
|
|
34393
|
+
throw new RuntimeError("gmres requires at least 2 arguments (A, b)");
|
|
34394
|
+
const Aarg = ensureRuntimeValue(args[0]);
|
|
34395
|
+
const bArg = ensureRuntimeValue(args[1]);
|
|
34396
|
+
if (!isRuntimeTensor(bArg) && !isRuntimeNumber(bArg) && !isRuntimeComplexNumber(bArg))
|
|
34397
|
+
throw new RuntimeError("gmres: b must be a numeric vector");
|
|
34398
|
+
let n;
|
|
34399
|
+
if (isRuntimeTensor(bArg)) {
|
|
34400
|
+
n = bArg.data.length;
|
|
34401
|
+
} else {
|
|
34402
|
+
n = 1;
|
|
34403
|
+
}
|
|
34404
|
+
const restartArg = args.length >= 3 ? ensureRuntimeValue(args[2]) : null;
|
|
34405
|
+
const tolArg = args.length >= 4 ? ensureRuntimeValue(args[3]) : null;
|
|
34406
|
+
const maxitArg = args.length >= 5 ? ensureRuntimeValue(args[4]) : null;
|
|
34407
|
+
const M1arg = args.length >= 6 ? ensureRuntimeValue(args[5]) : null;
|
|
34408
|
+
const M2arg = args.length >= 7 ? ensureRuntimeValue(args[6]) : null;
|
|
34409
|
+
const x0Arg = args.length >= 8 ? ensureRuntimeValue(args[7]) : null;
|
|
34410
|
+
let restart = n;
|
|
34411
|
+
if (restartArg !== null && !_isEmpty(restartArg)) {
|
|
34412
|
+
restart = _toNum(restartArg, "gmres: restart");
|
|
34413
|
+
}
|
|
34414
|
+
if (restart <= 0 || restart > n) restart = n;
|
|
34415
|
+
const noRestart = restart === n;
|
|
34416
|
+
const tol = tolArg !== null && !_isEmpty(tolArg) ? _toNum(tolArg, "gmres: tol") : 1e-6;
|
|
34417
|
+
let maxit;
|
|
34418
|
+
if (maxitArg !== null && !_isEmpty(maxitArg)) {
|
|
34419
|
+
maxit = _toNum(maxitArg, "gmres: maxit");
|
|
34420
|
+
} else {
|
|
34421
|
+
maxit = noRestart ? 1 : Math.max(1, Math.min(Math.ceil(n / restart), 10));
|
|
34422
|
+
}
|
|
34423
|
+
if (noRestart && maxitArg === null) restart = Math.min(n, 10);
|
|
34424
|
+
const isComplex2 = _isComplexArg(Aarg) || _isComplexArg(bArg) || M1arg !== null && _isComplexArg(M1arg) || M2arg !== null && _isComplexArg(M2arg) || x0Arg !== null && _isComplexArg(x0Arg);
|
|
34425
|
+
let flag;
|
|
34426
|
+
let relres;
|
|
34427
|
+
let iter;
|
|
34428
|
+
let resvec;
|
|
34429
|
+
let xTensor;
|
|
34430
|
+
if (isComplex2) {
|
|
34431
|
+
const bCV = _toComplexVec(bArg, n);
|
|
34432
|
+
const x0CV = x0Arg !== null && !_isEmpty(x0Arg) ? _toComplexVec(x0Arg, n) : null;
|
|
34433
|
+
const allMatrices = _isMatrixArg(Aarg) && _isMatrixArg(M1arg) && _isMatrixArg(M2arg);
|
|
34434
|
+
if (allMatrices) {
|
|
34435
|
+
const { re: ARe, im: AIm } = _toComplexMatrix(Aarg, n * n);
|
|
34436
|
+
const M1cv = _extractComplexMatrix(M1arg, n * n);
|
|
34437
|
+
const M2cv = _extractComplexMatrix(M2arg, n * n);
|
|
34438
|
+
const bridge = getEffectiveBridge("gmresComplex", "gmresComplex");
|
|
34439
|
+
if (bridge?.gmresComplex) {
|
|
34440
|
+
const r = bridge.gmresComplex(
|
|
34441
|
+
ARe,
|
|
34442
|
+
AIm,
|
|
34443
|
+
n,
|
|
34444
|
+
bCV.re,
|
|
34445
|
+
bCV.im,
|
|
34446
|
+
restart,
|
|
34447
|
+
tol,
|
|
34448
|
+
maxit,
|
|
34449
|
+
M1cv?.re ?? null,
|
|
34450
|
+
M1cv?.im ?? null,
|
|
34451
|
+
M2cv?.re ?? null,
|
|
34452
|
+
M2cv?.im ?? null,
|
|
34453
|
+
x0CV?.re ?? null,
|
|
34454
|
+
x0CV?.im ?? null
|
|
34455
|
+
);
|
|
34456
|
+
flag = r.flag;
|
|
34457
|
+
relres = r.relres;
|
|
34458
|
+
iter = [r.iter[0], r.iter[1]];
|
|
34459
|
+
resvec = r.resvec;
|
|
34460
|
+
xTensor = RTV.tensor(
|
|
34461
|
+
new FloatXArray(r.xRe),
|
|
34462
|
+
[n, 1],
|
|
34463
|
+
new FloatXArray(r.xIm)
|
|
34464
|
+
);
|
|
34465
|
+
} else {
|
|
34466
|
+
const matvec = _makeComplexMatvec(rt, Aarg, n);
|
|
34467
|
+
const precSolve = _makeComplexPrecSolve(rt, M1arg, M2arg, n);
|
|
34468
|
+
const r = gmresCoreComplex(
|
|
34469
|
+
matvec,
|
|
34470
|
+
precSolve,
|
|
34471
|
+
bCV,
|
|
34472
|
+
n,
|
|
34473
|
+
restart,
|
|
34474
|
+
tol,
|
|
34475
|
+
maxit,
|
|
34476
|
+
x0CV
|
|
34477
|
+
);
|
|
34478
|
+
flag = r.flag;
|
|
34479
|
+
relres = r.relres;
|
|
34480
|
+
iter = r.iter;
|
|
34481
|
+
resvec = r.resvec;
|
|
34482
|
+
xTensor = RTV.tensor(
|
|
34483
|
+
new FloatXArray(r.x.re),
|
|
34484
|
+
[n, 1],
|
|
34485
|
+
new FloatXArray(r.x.im)
|
|
34486
|
+
);
|
|
34487
|
+
}
|
|
34488
|
+
} else {
|
|
34489
|
+
const matvec = _makeComplexMatvec(rt, Aarg, n);
|
|
34490
|
+
const precSolve = _makeComplexPrecSolve(rt, M1arg, M2arg, n);
|
|
34491
|
+
const r = gmresCoreComplex(
|
|
34492
|
+
matvec,
|
|
34493
|
+
precSolve,
|
|
34494
|
+
bCV,
|
|
34495
|
+
n,
|
|
34496
|
+
restart,
|
|
34497
|
+
tol,
|
|
34498
|
+
maxit,
|
|
34499
|
+
x0CV
|
|
34500
|
+
);
|
|
34501
|
+
flag = r.flag;
|
|
34502
|
+
relres = r.relres;
|
|
34503
|
+
iter = r.iter;
|
|
34504
|
+
resvec = r.resvec;
|
|
34505
|
+
xTensor = RTV.tensor(
|
|
34506
|
+
new FloatXArray(r.x.re),
|
|
34507
|
+
[n, 1],
|
|
34508
|
+
new FloatXArray(r.x.im)
|
|
34509
|
+
);
|
|
34510
|
+
}
|
|
34511
|
+
} else {
|
|
34512
|
+
let bData;
|
|
34513
|
+
if (isRuntimeNumber(bArg)) {
|
|
34514
|
+
bData = new Float64Array([bArg]);
|
|
34515
|
+
} else {
|
|
34516
|
+
bData = toF64(bArg.data);
|
|
34517
|
+
}
|
|
34518
|
+
let x0 = null;
|
|
34519
|
+
if (x0Arg !== null && !_isEmpty(x0Arg)) {
|
|
34520
|
+
if (isRuntimeTensor(x0Arg)) x0 = toF64(x0Arg.data);
|
|
34521
|
+
else if (isRuntimeNumber(x0Arg)) x0 = new Float64Array([x0Arg]);
|
|
34522
|
+
}
|
|
34523
|
+
let xResult;
|
|
34524
|
+
const Ais_matrix = _isMatrixArg(Aarg);
|
|
34525
|
+
const M1is_matrix = _isMatrixArg(M1arg);
|
|
34526
|
+
const M2is_matrix = _isMatrixArg(M2arg);
|
|
34527
|
+
if (Ais_matrix && M1is_matrix && M2is_matrix) {
|
|
34528
|
+
const Adata = _extractRealMatrix(Aarg);
|
|
34529
|
+
const M1data = _extractMatrix(M1arg);
|
|
34530
|
+
const M2data = _extractMatrix(M2arg);
|
|
34531
|
+
const bridge = getEffectiveBridge("gmres", "gmres");
|
|
34532
|
+
if (bridge?.gmres) {
|
|
34533
|
+
const result = bridge.gmres(
|
|
34534
|
+
Adata,
|
|
34535
|
+
n,
|
|
34536
|
+
bData,
|
|
34537
|
+
restart,
|
|
34538
|
+
tol,
|
|
34539
|
+
maxit,
|
|
34540
|
+
M1data,
|
|
34541
|
+
M2data,
|
|
34542
|
+
x0
|
|
34543
|
+
);
|
|
34544
|
+
xResult = result.x;
|
|
34545
|
+
flag = result.flag;
|
|
34546
|
+
relres = result.relres;
|
|
34547
|
+
iter = [result.iter[0], result.iter[1]];
|
|
34548
|
+
resvec = result.resvec;
|
|
34549
|
+
} else {
|
|
34550
|
+
const r = _gmresWithCallbacks(
|
|
34551
|
+
Adata,
|
|
34552
|
+
n,
|
|
34553
|
+
bData,
|
|
34554
|
+
restart,
|
|
34555
|
+
tol,
|
|
34556
|
+
maxit,
|
|
34557
|
+
M1data,
|
|
34558
|
+
M2data,
|
|
34559
|
+
x0
|
|
34560
|
+
);
|
|
34561
|
+
xResult = r.x;
|
|
34562
|
+
flag = r.flag;
|
|
34563
|
+
relres = r.relres;
|
|
34564
|
+
iter = r.iter;
|
|
34565
|
+
resvec = r.resvec;
|
|
34566
|
+
}
|
|
34567
|
+
} else {
|
|
34568
|
+
const matvec = _makeMatvec(rt, Aarg, n);
|
|
34569
|
+
const precSolve = _makePrecSolve(rt, M1arg, M2arg, n);
|
|
34570
|
+
const r = gmresCore(matvec, precSolve, bData, n, restart, tol, maxit, x0);
|
|
34571
|
+
xResult = r.x;
|
|
34572
|
+
flag = r.flag;
|
|
34573
|
+
relres = r.relres;
|
|
34574
|
+
iter = r.iter;
|
|
34575
|
+
resvec = r.resvec;
|
|
34576
|
+
}
|
|
34577
|
+
xTensor = RTV.tensor(new FloatXArray(xResult), [n, 1]);
|
|
34578
|
+
}
|
|
34579
|
+
if (nargout <= 1) {
|
|
34580
|
+
if (flag === 0) {
|
|
34581
|
+
rt.output(
|
|
34582
|
+
`gmres converged at iteration ${iter[1]} to a solution with relative residual ${relres.toExponential(1)}.
|
|
34583
|
+
`
|
|
34584
|
+
);
|
|
34585
|
+
} else {
|
|
34586
|
+
rt.output(
|
|
34587
|
+
`gmres stopped at iteration ${iter[1]} without converging to the desired tolerance ${tol}
|
|
34588
|
+
because the maximum number of iterations was reached.
|
|
34589
|
+
The iterate returned (number ${iter[1]}) has relative residual ${relres.toExponential(1)}.
|
|
34590
|
+
`
|
|
34591
|
+
);
|
|
34592
|
+
}
|
|
34593
|
+
}
|
|
34594
|
+
if (nargout <= 1) return xTensor;
|
|
34595
|
+
if (nargout === 2) return [xTensor, flag];
|
|
34596
|
+
if (nargout === 3) return [xTensor, flag, relres];
|
|
34597
|
+
if (nargout === 4) {
|
|
34598
|
+
const iterTensor2 = RTV.tensor(new FloatXArray([iter[0], iter[1]]), [1, 2]);
|
|
34599
|
+
return [xTensor, flag, relres, iterTensor2];
|
|
34600
|
+
}
|
|
34601
|
+
const iterTensor = RTV.tensor(new FloatXArray([iter[0], iter[1]]), [1, 2]);
|
|
34602
|
+
const resvecTensor = RTV.tensor(new FloatXArray(resvec), [resvec.length, 1]);
|
|
34603
|
+
return [xTensor, flag, relres, iterTensor, resvecTensor];
|
|
34604
|
+
}
|
|
34605
|
+
function _isEmpty(v) {
|
|
34606
|
+
if (isRuntimeTensor(v) && v.data.length === 0) return true;
|
|
34607
|
+
return false;
|
|
34608
|
+
}
|
|
34609
|
+
function _toNum(v, ctx) {
|
|
34610
|
+
if (isRuntimeNumber(v)) return v;
|
|
34611
|
+
if (isRuntimeTensor(v) && v.data.length === 1) return v.data[0];
|
|
34612
|
+
throw new RuntimeError(`${ctx} must be a scalar`);
|
|
34613
|
+
}
|
|
34614
|
+
function _extractMatrix(arg) {
|
|
34615
|
+
if (arg === null || _isEmpty(arg)) return null;
|
|
34616
|
+
if (isRuntimeNumber(arg)) return new Float64Array([arg]);
|
|
34617
|
+
if (isRuntimeSparseMatrix(arg)) {
|
|
34618
|
+
const dense = sparseToDense(arg);
|
|
34619
|
+
return toF64(dense.data);
|
|
34620
|
+
}
|
|
34621
|
+
if (isRuntimeTensor(arg)) return toF64(arg.data);
|
|
34622
|
+
return null;
|
|
34623
|
+
}
|
|
34624
|
+
function _makeMatvec(rt, Aarg, n) {
|
|
34625
|
+
if (isRuntimeFunction(Aarg)) {
|
|
34626
|
+
return (x) => {
|
|
34627
|
+
const xTensor = RTV.tensor(new FloatXArray(x), [n, 1]);
|
|
34628
|
+
const resultRaw = rt.index(Aarg, [xTensor], 1);
|
|
34629
|
+
const rv = ensureRuntimeValue(resultRaw);
|
|
34630
|
+
if (isRuntimeNumber(rv)) return new Float64Array([rv]);
|
|
34631
|
+
if (isRuntimeTensor(rv)) return toF64(rv.data);
|
|
34632
|
+
throw new RuntimeError("gmres: A(x) must return a numeric vector");
|
|
34633
|
+
};
|
|
34634
|
+
}
|
|
34635
|
+
let Adata;
|
|
34636
|
+
if (isRuntimeNumber(Aarg)) {
|
|
34637
|
+
Adata = new Float64Array([Aarg]);
|
|
34638
|
+
} else if (isRuntimeSparseMatrix(Aarg)) {
|
|
34639
|
+
Adata = toF64(sparseToDense(Aarg).data);
|
|
34640
|
+
} else if (isRuntimeTensor(Aarg)) {
|
|
34641
|
+
Adata = toF64(Aarg.data);
|
|
34642
|
+
} else {
|
|
34643
|
+
throw new RuntimeError("gmres: A must be a matrix or function handle");
|
|
34644
|
+
}
|
|
34645
|
+
return (x) => {
|
|
34646
|
+
const y = new Float64Array(n);
|
|
34647
|
+
for (let i = 0; i < n; i++) {
|
|
34648
|
+
let s = 0;
|
|
34649
|
+
for (let j = 0; j < n; j++) s += Adata[i + j * n] * x[j];
|
|
34650
|
+
y[i] = s;
|
|
34651
|
+
}
|
|
34652
|
+
return y;
|
|
34653
|
+
};
|
|
34654
|
+
}
|
|
34655
|
+
function _makePrecSolve(rt, M1arg, M2arg, n) {
|
|
34656
|
+
const hasM1 = M1arg !== null && !_isEmpty(M1arg);
|
|
34657
|
+
const hasM2 = M2arg !== null && !_isEmpty(M2arg);
|
|
34658
|
+
if (!hasM1 && !hasM2) return null;
|
|
34659
|
+
const solve1 = hasM1 ? _makeSinglePrecSolve(rt, M1arg, n) : null;
|
|
34660
|
+
const solve2 = hasM2 ? _makeSinglePrecSolve(rt, M2arg, n) : null;
|
|
34661
|
+
return (r) => {
|
|
34662
|
+
let z = r;
|
|
34663
|
+
if (solve1) z = solve1(z);
|
|
34664
|
+
if (solve2) z = solve2(z);
|
|
34665
|
+
return z;
|
|
34666
|
+
};
|
|
34667
|
+
}
|
|
34668
|
+
function _makeSinglePrecSolve(rt, Marg, n) {
|
|
34669
|
+
if (isRuntimeFunction(Marg)) {
|
|
34670
|
+
return (r) => {
|
|
34671
|
+
const rTensor = RTV.tensor(new FloatXArray(r), [n, 1]);
|
|
34672
|
+
const resultRaw = rt.index(Marg, [rTensor], 1);
|
|
34673
|
+
const rv = ensureRuntimeValue(resultRaw);
|
|
34674
|
+
if (isRuntimeNumber(rv)) return new Float64Array([rv]);
|
|
34675
|
+
if (isRuntimeTensor(rv)) return toF64(rv.data);
|
|
34676
|
+
throw new RuntimeError("gmres: M(x) must return a numeric vector");
|
|
34677
|
+
};
|
|
34678
|
+
}
|
|
34679
|
+
let Mdata;
|
|
34680
|
+
if (isRuntimeNumber(Marg)) {
|
|
34681
|
+
Mdata = new Float64Array([Marg]);
|
|
34682
|
+
} else if (isRuntimeSparseMatrix(Marg)) {
|
|
34683
|
+
Mdata = toF64(sparseToDense(Marg).data);
|
|
34684
|
+
} else if (isRuntimeTensor(Marg)) {
|
|
34685
|
+
Mdata = toF64(Marg.data);
|
|
34686
|
+
} else {
|
|
34687
|
+
throw new RuntimeError(
|
|
34688
|
+
"gmres: preconditioner must be a matrix or function handle"
|
|
34689
|
+
);
|
|
34690
|
+
}
|
|
34691
|
+
const LU = new Float64Array(Mdata);
|
|
34692
|
+
const ipiv = new Int32Array(n);
|
|
34693
|
+
const info = dgetrf(n, n, LU, n, ipiv);
|
|
34694
|
+
if (info > 0)
|
|
34695
|
+
throw new RuntimeError("gmres: preconditioner matrix is singular");
|
|
34696
|
+
return (r) => {
|
|
34697
|
+
const z = new Float64Array(r);
|
|
34698
|
+
luSolveInPlace(n, LU, ipiv, z);
|
|
34699
|
+
return z;
|
|
34700
|
+
};
|
|
34701
|
+
}
|
|
34702
|
+
function _gmresWithCallbacks(A, n, b, restart, tol, maxit, M1, M2, x0) {
|
|
34703
|
+
const matvec = (x) => {
|
|
34704
|
+
const y = new Float64Array(n);
|
|
34705
|
+
for (let i = 0; i < n; i++) {
|
|
34706
|
+
let s = 0;
|
|
34707
|
+
for (let j = 0; j < n; j++) s += A[i + j * n] * x[j];
|
|
34708
|
+
y[i] = s;
|
|
34709
|
+
}
|
|
34710
|
+
return y;
|
|
34711
|
+
};
|
|
34712
|
+
let precSolve = null;
|
|
34713
|
+
if (M1 || M2) {
|
|
34714
|
+
const m1lu = M1 ? new Float64Array(M1) : null;
|
|
34715
|
+
const m1ipiv = M1 ? new Int32Array(n) : null;
|
|
34716
|
+
if (m1lu && m1ipiv) dgetrf(n, n, m1lu, n, m1ipiv);
|
|
34717
|
+
const m2lu = M2 ? new Float64Array(M2) : null;
|
|
34718
|
+
const m2ipiv = M2 ? new Int32Array(n) : null;
|
|
34719
|
+
if (m2lu && m2ipiv) dgetrf(n, n, m2lu, n, m2ipiv);
|
|
34720
|
+
precSolve = (r) => {
|
|
34721
|
+
const z = new Float64Array(r);
|
|
34722
|
+
if (m1lu && m1ipiv) luSolveInPlace(n, m1lu, m1ipiv, z);
|
|
34723
|
+
if (m2lu && m2ipiv) luSolveInPlace(n, m2lu, m2ipiv, z);
|
|
34724
|
+
return z;
|
|
34725
|
+
};
|
|
34726
|
+
}
|
|
34727
|
+
return gmresCore(matvec, precSolve, b, n, restart, tol, maxit, x0);
|
|
34728
|
+
}
|
|
34729
|
+
function _isComplexArg(v) {
|
|
34730
|
+
if (v === null) return false;
|
|
34731
|
+
if (isRuntimeComplexNumber(v)) return true;
|
|
34732
|
+
if (isRuntimeTensor(v) && v.imag) return true;
|
|
34733
|
+
if (isRuntimeSparseMatrix(v) && v.pi) return true;
|
|
34734
|
+
return false;
|
|
34735
|
+
}
|
|
34736
|
+
function _isMatrixArg(v) {
|
|
34737
|
+
if (v === null) return true;
|
|
34738
|
+
if (_isEmpty(v)) return true;
|
|
34739
|
+
return isRuntimeTensor(v) || isRuntimeNumber(v) || isRuntimeComplexNumber(v) || isRuntimeSparseMatrix(v);
|
|
34740
|
+
}
|
|
34741
|
+
function _extractRealMatrix(arg) {
|
|
34742
|
+
if (arg === null) return null;
|
|
34743
|
+
if (isRuntimeNumber(arg)) return new Float64Array([arg]);
|
|
34744
|
+
if (isRuntimeSparseMatrix(arg)) return toF64(sparseToDense(arg).data);
|
|
34745
|
+
if (isRuntimeTensor(arg)) return toF64(arg.data);
|
|
34746
|
+
return null;
|
|
34747
|
+
}
|
|
34748
|
+
function _toComplexVec(v, n) {
|
|
34749
|
+
if (isRuntimeComplexNumber(v)) {
|
|
34750
|
+
return { re: new Float64Array([v.re]), im: new Float64Array([v.im]) };
|
|
34751
|
+
}
|
|
34752
|
+
if (isRuntimeTensor(v)) {
|
|
34753
|
+
return {
|
|
34754
|
+
re: new Float64Array(toF64(v.data)),
|
|
34755
|
+
im: v.imag ? new Float64Array(toF64(v.imag)) : new Float64Array(n)
|
|
34756
|
+
};
|
|
34757
|
+
}
|
|
34758
|
+
if (isRuntimeNumber(v)) {
|
|
34759
|
+
const re2 = new Float64Array(1);
|
|
34760
|
+
re2[0] = v;
|
|
34761
|
+
return { re: re2, im: new Float64Array(1) };
|
|
34762
|
+
}
|
|
34763
|
+
throw new RuntimeError("gmres: cannot convert argument to complex vector");
|
|
34764
|
+
}
|
|
34765
|
+
function _toComplexMatrix(v, len) {
|
|
34766
|
+
if (isRuntimeTensor(v)) {
|
|
34767
|
+
return {
|
|
34768
|
+
re: new Float64Array(toF64(v.data)),
|
|
34769
|
+
im: v.imag ? new Float64Array(toF64(v.imag)) : new Float64Array(len)
|
|
34770
|
+
};
|
|
34771
|
+
}
|
|
34772
|
+
if (isRuntimeSparseMatrix(v)) {
|
|
34773
|
+
const dense = sparseToDense(v);
|
|
34774
|
+
return {
|
|
34775
|
+
re: new Float64Array(toF64(dense.data)),
|
|
34776
|
+
im: dense.imag ? new Float64Array(toF64(dense.imag)) : new Float64Array(len)
|
|
34777
|
+
};
|
|
34778
|
+
}
|
|
34779
|
+
if (isRuntimeNumber(v)) {
|
|
34780
|
+
const re2 = new Float64Array(1);
|
|
34781
|
+
re2[0] = v;
|
|
34782
|
+
return { re: re2, im: new Float64Array(1) };
|
|
34783
|
+
}
|
|
34784
|
+
throw new RuntimeError("gmres: cannot convert to complex matrix");
|
|
34785
|
+
}
|
|
34786
|
+
function _extractComplexMatrix(arg, len) {
|
|
34787
|
+
if (arg === null || _isEmpty(arg)) return null;
|
|
34788
|
+
return _toComplexMatrix(arg, len);
|
|
34789
|
+
}
|
|
34790
|
+
function _makeComplexMatvec(rt, Aarg, n) {
|
|
34791
|
+
if (isRuntimeFunction(Aarg)) {
|
|
34792
|
+
return (x) => {
|
|
34793
|
+
const xTensor = RTV.tensor(
|
|
34794
|
+
new FloatXArray(x.re),
|
|
34795
|
+
[n, 1],
|
|
34796
|
+
new FloatXArray(x.im)
|
|
34797
|
+
);
|
|
34798
|
+
const resultRaw = rt.index(Aarg, [xTensor], 1);
|
|
34799
|
+
const rv = ensureRuntimeValue(resultRaw);
|
|
34800
|
+
if (isRuntimeTensor(rv)) {
|
|
34801
|
+
return {
|
|
34802
|
+
re: new Float64Array(toF64(rv.data)),
|
|
34803
|
+
im: rv.imag ? new Float64Array(toF64(rv.imag)) : new Float64Array(n)
|
|
34804
|
+
};
|
|
34805
|
+
}
|
|
34806
|
+
if (isRuntimeComplexNumber(rv)) {
|
|
34807
|
+
return { re: new Float64Array([rv.re]), im: new Float64Array([rv.im]) };
|
|
34808
|
+
}
|
|
34809
|
+
if (isRuntimeNumber(rv)) {
|
|
34810
|
+
const re2 = new Float64Array(1);
|
|
34811
|
+
re2[0] = rv;
|
|
34812
|
+
return { re: re2, im: new Float64Array(1) };
|
|
34813
|
+
}
|
|
34814
|
+
throw new RuntimeError("gmres: A(x) must return a numeric vector");
|
|
34815
|
+
};
|
|
34816
|
+
}
|
|
34817
|
+
const { re: ARe, im: AIm } = _toComplexMatrix(Aarg, n * n);
|
|
34818
|
+
return (x) => {
|
|
34819
|
+
const yRe = new Float64Array(n);
|
|
34820
|
+
const yIm = new Float64Array(n);
|
|
34821
|
+
for (let i = 0; i < n; i++) {
|
|
34822
|
+
let sR = 0, sI = 0;
|
|
34823
|
+
for (let j = 0; j < n; j++) {
|
|
34824
|
+
const aR = ARe[i + j * n], aI = AIm[i + j * n];
|
|
34825
|
+
sR += aR * x.re[j] - aI * x.im[j];
|
|
34826
|
+
sI += aR * x.im[j] + aI * x.re[j];
|
|
34827
|
+
}
|
|
34828
|
+
yRe[i] = sR;
|
|
34829
|
+
yIm[i] = sI;
|
|
34830
|
+
}
|
|
34831
|
+
return { re: yRe, im: yIm };
|
|
34832
|
+
};
|
|
34833
|
+
}
|
|
34834
|
+
function _makeComplexPrecSolve(rt, M1arg, M2arg, n) {
|
|
34835
|
+
const hasM1 = M1arg !== null && !_isEmpty(M1arg);
|
|
34836
|
+
const hasM2 = M2arg !== null && !_isEmpty(M2arg);
|
|
34837
|
+
if (!hasM1 && !hasM2) return null;
|
|
34838
|
+
const solve1 = hasM1 ? _makeSingleComplexPrecSolve(rt, M1arg, n) : null;
|
|
34839
|
+
const solve2 = hasM2 ? _makeSingleComplexPrecSolve(rt, M2arg, n) : null;
|
|
34840
|
+
return (r) => {
|
|
34841
|
+
let z = r;
|
|
34842
|
+
if (solve1) z = solve1(z);
|
|
34843
|
+
if (solve2) z = solve2(z);
|
|
34844
|
+
return z;
|
|
34845
|
+
};
|
|
34846
|
+
}
|
|
34847
|
+
function _makeSingleComplexPrecSolve(rt, Marg, n) {
|
|
34848
|
+
if (isRuntimeFunction(Marg)) {
|
|
34849
|
+
return (r) => {
|
|
34850
|
+
const rTensor = RTV.tensor(
|
|
34851
|
+
new FloatXArray(r.re),
|
|
34852
|
+
[n, 1],
|
|
34853
|
+
new FloatXArray(r.im)
|
|
34854
|
+
);
|
|
34855
|
+
const resultRaw = rt.index(Marg, [rTensor], 1);
|
|
34856
|
+
const rv = ensureRuntimeValue(resultRaw);
|
|
34857
|
+
if (isRuntimeTensor(rv)) {
|
|
34858
|
+
return {
|
|
34859
|
+
re: new Float64Array(toF64(rv.data)),
|
|
34860
|
+
im: rv.imag ? new Float64Array(toF64(rv.imag)) : new Float64Array(n)
|
|
34861
|
+
};
|
|
34862
|
+
}
|
|
34863
|
+
throw new RuntimeError("gmres: M(x) must return a numeric vector");
|
|
34864
|
+
};
|
|
34865
|
+
}
|
|
34866
|
+
const { re: MRe, im: MIm } = _toComplexMatrix(Marg, n * n);
|
|
34867
|
+
const ipiv = new Int32Array(n);
|
|
34868
|
+
_complexLuFactor(n, MRe, MIm, ipiv);
|
|
34869
|
+
return (r) => {
|
|
34870
|
+
const zRe = new Float64Array(r.re);
|
|
34871
|
+
const zIm = new Float64Array(r.im);
|
|
34872
|
+
complexLuSolveInPlace(n, MRe, MIm, ipiv, zRe, zIm);
|
|
34873
|
+
return { re: zRe, im: zIm };
|
|
34874
|
+
};
|
|
34875
|
+
}
|
|
34876
|
+
function _complexLuFactor(n, re2, im2, ipiv) {
|
|
34877
|
+
for (let k = 0; k < n; k++) {
|
|
34878
|
+
let maxVal = -1, maxIdx = k;
|
|
34879
|
+
for (let i = k; i < n; i++) {
|
|
34880
|
+
const v = Math.sqrt(
|
|
34881
|
+
re2[i + k * n] * re2[i + k * n] + im2[i + k * n] * im2[i + k * n]
|
|
34882
|
+
);
|
|
34883
|
+
if (v > maxVal) {
|
|
34884
|
+
maxVal = v;
|
|
34885
|
+
maxIdx = i;
|
|
34886
|
+
}
|
|
34887
|
+
}
|
|
34888
|
+
ipiv[k] = maxIdx + 1;
|
|
34889
|
+
if (maxIdx !== k) {
|
|
34890
|
+
for (let j = 0; j < n; j++) {
|
|
34891
|
+
let tmp = re2[k + j * n];
|
|
34892
|
+
re2[k + j * n] = re2[maxIdx + j * n];
|
|
34893
|
+
re2[maxIdx + j * n] = tmp;
|
|
34894
|
+
tmp = im2[k + j * n];
|
|
34895
|
+
im2[k + j * n] = im2[maxIdx + j * n];
|
|
34896
|
+
im2[maxIdx + j * n] = tmp;
|
|
34897
|
+
}
|
|
34898
|
+
}
|
|
34899
|
+
const dR = re2[k + k * n], dI = im2[k + k * n];
|
|
34900
|
+
const dAbs2 = dR * dR + dI * dI;
|
|
34901
|
+
if (dAbs2 === 0) continue;
|
|
34902
|
+
for (let i = k + 1; i < n; i++) {
|
|
34903
|
+
const aR = re2[i + k * n], aI = im2[i + k * n];
|
|
34904
|
+
const lR = (aR * dR + aI * dI) / dAbs2;
|
|
34905
|
+
const lI = (aI * dR - aR * dI) / dAbs2;
|
|
34906
|
+
re2[i + k * n] = lR;
|
|
34907
|
+
im2[i + k * n] = lI;
|
|
34908
|
+
for (let j = k + 1; j < n; j++) {
|
|
34909
|
+
re2[i + j * n] -= lR * re2[k + j * n] - lI * im2[k + j * n];
|
|
34910
|
+
im2[i + j * n] -= lR * im2[k + j * n] + lI * re2[k + j * n];
|
|
34911
|
+
}
|
|
34912
|
+
}
|
|
34913
|
+
}
|
|
34914
|
+
}
|
|
33619
34915
|
|
|
33620
34916
|
// src/numbl-core/runtime/runtimeMemberAccess.ts
|
|
33621
34917
|
function getMember(rt, base, name) {
|
|
@@ -33858,6 +35154,11 @@ var Runtime = class _Runtime {
|
|
|
33858
35154
|
// Custom builtins (execution-specific overrides).
|
|
33859
35155
|
// These take priority over IBuiltins.
|
|
33860
35156
|
customBuiltins = {};
|
|
35157
|
+
// Per-runtime JIT helpers ($h) — populated by executeCode after the runtime
|
|
35158
|
+
// is constructed. Cloned from the global jitHelpers and extended with
|
|
35159
|
+
// ib_<name> entries for any .numbl.js user functions of this execution.
|
|
35160
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35161
|
+
jitHelpers = null;
|
|
33861
35162
|
// JIT compilation callback: compiles and evaluates a specialized function at
|
|
33862
35163
|
// runtime. Set by executeCode() to close over the LoweringContext and Codegen.
|
|
33863
35164
|
// The callback handles the full resolution chain (local → class method →
|
|
@@ -33878,6 +35179,8 @@ var Runtime = class _Runtime {
|
|
|
33878
35179
|
profileStack = [];
|
|
33879
35180
|
profileAccum = /* @__PURE__ */ new Map();
|
|
33880
35181
|
profileCounts = /* @__PURE__ */ new Map();
|
|
35182
|
+
// Profiling: interpreted loops with >1000 iterations (keyed by "file:line")
|
|
35183
|
+
hotLoops = /* @__PURE__ */ new Map();
|
|
33881
35184
|
// ── Builtin initialization ──────────────────────────────────────────
|
|
33882
35185
|
initBuiltins() {
|
|
33883
35186
|
registerSpecialBuiltins(this);
|
|
@@ -33896,6 +35199,10 @@ var Runtime = class _Runtime {
|
|
|
33896
35199
|
this.builtins["imagesc"] = (_nargout, args) => {
|
|
33897
35200
|
this.imagesc_call(args.map((a) => ensureRuntimeValue(a)));
|
|
33898
35201
|
};
|
|
35202
|
+
this.builtins["pcolor"] = (_nargout, args) => {
|
|
35203
|
+
this.pcolor_call(args.map((a) => ensureRuntimeValue(a)));
|
|
35204
|
+
if (_nargout >= 1) return RTV.dummyHandle();
|
|
35205
|
+
};
|
|
33899
35206
|
this.builtins["contour"] = (_nargout, args) => {
|
|
33900
35207
|
this.contour_call(
|
|
33901
35208
|
args.map((a) => ensureRuntimeValue(a)),
|
|
@@ -33980,8 +35287,21 @@ var Runtime = class _Runtime {
|
|
|
33980
35287
|
this.builtins["colormap"] = (_nargout, args) => {
|
|
33981
35288
|
if (args.length > 0) {
|
|
33982
35289
|
const rv = ensureRuntimeValue(args[0]);
|
|
33983
|
-
|
|
33984
|
-
|
|
35290
|
+
if (isRuntimeTensor(rv) && rv.shape.length === 2 && rv.shape[1] === 3) {
|
|
35291
|
+
const rows = rv.shape[0];
|
|
35292
|
+
const data = [];
|
|
35293
|
+
for (let i = 0; i < rows; i++) {
|
|
35294
|
+
data.push([rv.data[i], rv.data[rows + i], rv.data[2 * rows + i]]);
|
|
35295
|
+
}
|
|
35296
|
+
plotInstr(this.plotInstructions, {
|
|
35297
|
+
type: "set_colormap",
|
|
35298
|
+
name: "__custom__",
|
|
35299
|
+
data
|
|
35300
|
+
});
|
|
35301
|
+
} else {
|
|
35302
|
+
const name = toString(rv).replace(/^"|"$/g, "");
|
|
35303
|
+
plotInstr(this.plotInstructions, { type: "set_colormap", name });
|
|
35304
|
+
}
|
|
33985
35305
|
}
|
|
33986
35306
|
};
|
|
33987
35307
|
this.builtins["view"] = (_nargout, args) => {
|
|
@@ -33995,10 +35315,6 @@ var Runtime = class _Runtime {
|
|
|
33995
35315
|
});
|
|
33996
35316
|
}
|
|
33997
35317
|
};
|
|
33998
|
-
this.builtins["colorbar"] = (_nargout, args) => {
|
|
33999
|
-
const val = args.length > 0 ? toString(ensureRuntimeValue(args[0])) : "on";
|
|
34000
|
-
plotInstr(this.plotInstructions, { type: "set_colorbar", value: val });
|
|
34001
|
-
};
|
|
34002
35318
|
this.builtins["axis"] = (_nargout, args) => {
|
|
34003
35319
|
if (args.length > 0) {
|
|
34004
35320
|
const val = toString(ensureRuntimeValue(args[0])).replace(
|
|
@@ -34008,6 +35324,17 @@ var Runtime = class _Runtime {
|
|
|
34008
35324
|
plotInstr(this.plotInstructions, { type: "set_axis", value: val });
|
|
34009
35325
|
}
|
|
34010
35326
|
};
|
|
35327
|
+
this.builtins["caxis"] = (_nargout, args) => {
|
|
35328
|
+
if (args.length > 0) {
|
|
35329
|
+
const rv = ensureRuntimeValue(args[0]);
|
|
35330
|
+
if (isRuntimeTensor(rv) && rv.data.length >= 2) {
|
|
35331
|
+
plotInstr(this.plotInstructions, {
|
|
35332
|
+
type: "set_caxis",
|
|
35333
|
+
limits: [rv.data[0], rv.data[1]]
|
|
35334
|
+
});
|
|
35335
|
+
}
|
|
35336
|
+
}
|
|
35337
|
+
};
|
|
34011
35338
|
}
|
|
34012
35339
|
profileEnter(key) {
|
|
34013
35340
|
if (!this.profilingEnabled) return;
|
|
@@ -34114,8 +35441,9 @@ var Runtime = class _Runtime {
|
|
|
34114
35441
|
if (e instanceof RuntimeError) {
|
|
34115
35442
|
return RTV.struct(
|
|
34116
35443
|
/* @__PURE__ */ new Map([
|
|
34117
|
-
["message", RTV.char(e.message)],
|
|
34118
35444
|
["identifier", RTV.char(e.identifier)],
|
|
35445
|
+
["message", RTV.char(e.message)],
|
|
35446
|
+
["cause", RTV.cell([], [0, 0])],
|
|
34119
35447
|
["stack", buildStackField(e)]
|
|
34120
35448
|
])
|
|
34121
35449
|
);
|
|
@@ -34123,16 +35451,18 @@ var Runtime = class _Runtime {
|
|
|
34123
35451
|
if (e instanceof Error) {
|
|
34124
35452
|
return RTV.struct(
|
|
34125
35453
|
/* @__PURE__ */ new Map([
|
|
34126
|
-
["message", RTV.char(e.message)],
|
|
34127
35454
|
["identifier", RTV.char("")],
|
|
35455
|
+
["message", RTV.char(e.message)],
|
|
35456
|
+
["cause", RTV.cell([], [0, 0])],
|
|
34128
35457
|
["stack", emptyStackField()]
|
|
34129
35458
|
])
|
|
34130
35459
|
);
|
|
34131
35460
|
}
|
|
34132
35461
|
return RTV.struct(
|
|
34133
35462
|
/* @__PURE__ */ new Map([
|
|
34134
|
-
["message", RTV.char(String(e))],
|
|
34135
35463
|
["identifier", RTV.char("")],
|
|
35464
|
+
["message", RTV.char(String(e))],
|
|
35465
|
+
["cause", RTV.cell([], [0, 0])],
|
|
34136
35466
|
["stack", emptyStackField()]
|
|
34137
35467
|
])
|
|
34138
35468
|
);
|
|
@@ -34871,6 +36201,9 @@ var Runtime = class _Runtime {
|
|
|
34871
36201
|
imagesc_call(args) {
|
|
34872
36202
|
imagescCall(this.plotInstructions, args);
|
|
34873
36203
|
}
|
|
36204
|
+
pcolor_call(args) {
|
|
36205
|
+
pcolorCall(this.plotInstructions, args);
|
|
36206
|
+
}
|
|
34874
36207
|
contour_call(args, filled) {
|
|
34875
36208
|
contourCall(this.plotInstructions, args, filled);
|
|
34876
36209
|
}
|
|
@@ -36256,7 +37589,7 @@ defineBuiltin({
|
|
|
36256
37589
|
},
|
|
36257
37590
|
apply: (args) => {
|
|
36258
37591
|
const first = textValue(args[0]) ?? String(args[0]);
|
|
36259
|
-
if (args.length >= 2 &&
|
|
37592
|
+
if (args.length >= 2 && /^[A-Za-z]\w*(:[A-Za-z]\w*)+$/.test(first)) {
|
|
36260
37593
|
const msg2 = args.length === 2 ? textValue(args[1]) ?? String(args[1]) : sprintfFormat(
|
|
36261
37594
|
textValue(args[1]) ?? String(args[1]),
|
|
36262
37595
|
args.slice(2)
|
|
@@ -36294,6 +37627,134 @@ defineBuiltin({
|
|
|
36294
37627
|
}
|
|
36295
37628
|
]
|
|
36296
37629
|
});
|
|
37630
|
+
function makeMException(identifier, message) {
|
|
37631
|
+
return RTV.struct(
|
|
37632
|
+
/* @__PURE__ */ new Map([
|
|
37633
|
+
["identifier", RTV.char(identifier)],
|
|
37634
|
+
["message", RTV.char(message)],
|
|
37635
|
+
["cause", RTV.cell([], [0, 0])],
|
|
37636
|
+
["stack", emptyStackField()]
|
|
37637
|
+
])
|
|
37638
|
+
);
|
|
37639
|
+
}
|
|
37640
|
+
defineBuiltin({
|
|
37641
|
+
name: "MException",
|
|
37642
|
+
help: {
|
|
37643
|
+
signatures: [
|
|
37644
|
+
"ME = MException(errID, msg)",
|
|
37645
|
+
"ME = MException(errID, msg, A1, ..., An)"
|
|
37646
|
+
],
|
|
37647
|
+
description: "Construct an exception object with an error identifier and message. Extra arguments format the message with sprintf-style conversion specifiers. In numbl the result is a struct with fields identifier, message, cause, and stack."
|
|
37648
|
+
},
|
|
37649
|
+
cases: [
|
|
37650
|
+
{
|
|
37651
|
+
match: (argTypes) => {
|
|
37652
|
+
if (argTypes.length < 2) return null;
|
|
37653
|
+
const k0 = argTypes[0].kind;
|
|
37654
|
+
const k1 = argTypes[1].kind;
|
|
37655
|
+
if (k0 !== "string" && k0 !== "char") return null;
|
|
37656
|
+
if (k1 !== "string" && k1 !== "char") return null;
|
|
37657
|
+
return [{ kind: "struct", fields: {} }];
|
|
37658
|
+
},
|
|
37659
|
+
apply: (args) => {
|
|
37660
|
+
const errID = textValue(args[0]) ?? String(args[0]);
|
|
37661
|
+
const fmt = textValue(args[1]) ?? String(args[1]);
|
|
37662
|
+
const msg = args.length === 2 ? fmt : sprintfFormat(fmt, args.slice(2));
|
|
37663
|
+
return makeMException(errID, msg);
|
|
37664
|
+
}
|
|
37665
|
+
}
|
|
37666
|
+
]
|
|
37667
|
+
});
|
|
37668
|
+
function throwException(me) {
|
|
37669
|
+
if (isRuntimeStruct(me)) {
|
|
37670
|
+
const msgVal = me.fields.get("message");
|
|
37671
|
+
const idVal = me.fields.get("identifier");
|
|
37672
|
+
const msg = msgVal ? textValue(msgVal) ?? String(msgVal) : "";
|
|
37673
|
+
const err = new RuntimeError(msg);
|
|
37674
|
+
if (idVal) err.identifier = textValue(idVal) ?? "";
|
|
37675
|
+
throw err;
|
|
37676
|
+
}
|
|
37677
|
+
throw new RuntimeError(String(me));
|
|
37678
|
+
}
|
|
37679
|
+
defineBuiltin({
|
|
37680
|
+
name: "throw",
|
|
37681
|
+
help: {
|
|
37682
|
+
signatures: ["throw(ME)"],
|
|
37683
|
+
description: "Throw an exception. ME is an MException-shaped struct with identifier and message fields."
|
|
37684
|
+
},
|
|
37685
|
+
cases: [
|
|
37686
|
+
{
|
|
37687
|
+
match: (argTypes) => {
|
|
37688
|
+
if (argTypes.length !== 1) return null;
|
|
37689
|
+
return [];
|
|
37690
|
+
},
|
|
37691
|
+
apply: (args) => throwException(args[0])
|
|
37692
|
+
}
|
|
37693
|
+
]
|
|
37694
|
+
});
|
|
37695
|
+
defineBuiltin({
|
|
37696
|
+
name: "throwAsCaller",
|
|
37697
|
+
help: {
|
|
37698
|
+
signatures: ["throwAsCaller(ME)"],
|
|
37699
|
+
description: "Throw an exception as if from the calling function. In numbl this is equivalent to throw(ME) \u2014 the throw site is not hidden from the stack."
|
|
37700
|
+
},
|
|
37701
|
+
cases: [
|
|
37702
|
+
{
|
|
37703
|
+
match: (argTypes) => {
|
|
37704
|
+
if (argTypes.length !== 1) return null;
|
|
37705
|
+
return [];
|
|
37706
|
+
},
|
|
37707
|
+
apply: (args) => throwException(args[0])
|
|
37708
|
+
}
|
|
37709
|
+
]
|
|
37710
|
+
});
|
|
37711
|
+
defineBuiltin({
|
|
37712
|
+
name: "getReport",
|
|
37713
|
+
help: {
|
|
37714
|
+
signatures: ["S = getReport(ME)", "S = getReport(ME, TYPE)"],
|
|
37715
|
+
description: "Return a formatted error report for an MException-shaped struct as a char string. TYPE is 'basic' or 'extended' (default 'extended'). The 'extended' form appends stack frames if present."
|
|
37716
|
+
},
|
|
37717
|
+
cases: [
|
|
37718
|
+
{
|
|
37719
|
+
match: (argTypes) => {
|
|
37720
|
+
if (argTypes.length < 1 || argTypes.length > 4) return null;
|
|
37721
|
+
return [{ kind: "char" }];
|
|
37722
|
+
},
|
|
37723
|
+
apply: (args) => {
|
|
37724
|
+
const me = args[0];
|
|
37725
|
+
if (!isRuntimeStruct(me)) {
|
|
37726
|
+
return RTV.char(String(me));
|
|
37727
|
+
}
|
|
37728
|
+
const msgVal = me.fields.get("message");
|
|
37729
|
+
const message = msgVal ? textValue(msgVal) ?? String(msgVal) : "";
|
|
37730
|
+
let type = "extended";
|
|
37731
|
+
if (args.length >= 2) {
|
|
37732
|
+
const t = textValue(args[1]);
|
|
37733
|
+
if (t === "basic" || t === "extended") type = t;
|
|
37734
|
+
}
|
|
37735
|
+
if (type === "basic") return RTV.char(message);
|
|
37736
|
+
const stackVal = me.fields.get("stack");
|
|
37737
|
+
const lines = [message];
|
|
37738
|
+
const appendFrame = (frame) => {
|
|
37739
|
+
if (!isRuntimeStruct(frame)) return;
|
|
37740
|
+
const nameVal = frame.fields.get("name");
|
|
37741
|
+
const lineVal = frame.fields.get("line");
|
|
37742
|
+
const name = nameVal ? textValue(nameVal) ?? "" : "";
|
|
37743
|
+
const lineNum = typeof lineVal === "number" ? lineVal : 0;
|
|
37744
|
+
if (name) lines.push(`Error in ${name} (line ${lineNum})`);
|
|
37745
|
+
};
|
|
37746
|
+
if (stackVal) {
|
|
37747
|
+
if (isRuntimeStructArray(stackVal)) {
|
|
37748
|
+
for (const el of stackVal.elements) appendFrame(el);
|
|
37749
|
+
} else if (isRuntimeStruct(stackVal)) {
|
|
37750
|
+
appendFrame(stackVal);
|
|
37751
|
+
}
|
|
37752
|
+
}
|
|
37753
|
+
return RTV.char(lines.join("\n"));
|
|
37754
|
+
}
|
|
37755
|
+
}
|
|
37756
|
+
]
|
|
37757
|
+
});
|
|
36297
37758
|
|
|
36298
37759
|
// src/numbl-core/interpreter/builtins/introspection.ts
|
|
36299
37760
|
function anyToLogicalCase(applyFn) {
|
|
@@ -38178,6 +39639,150 @@ registerIBuiltin({
|
|
|
38178
39639
|
};
|
|
38179
39640
|
}
|
|
38180
39641
|
});
|
|
39642
|
+
var RE_ALPHA = /\p{L}/u;
|
|
39643
|
+
var RE_ALPHANUM = /[\p{L}\p{N}]/u;
|
|
39644
|
+
var RE_CNTRL = /\p{Cc}/u;
|
|
39645
|
+
var RE_GRAPHIC = /[\p{L}\p{N}\p{P}\p{S}\p{M}]/u;
|
|
39646
|
+
var RE_LOWER = /\p{Ll}/u;
|
|
39647
|
+
var RE_PUNCT = /\p{P}/u;
|
|
39648
|
+
var RE_UPPER = /\p{Lu}/u;
|
|
39649
|
+
var RE_WSPACE = /\s/u;
|
|
39650
|
+
function isstrpropPredicate(category) {
|
|
39651
|
+
switch (category) {
|
|
39652
|
+
case "alpha":
|
|
39653
|
+
return (cp) => RE_ALPHA.test(String.fromCodePoint(cp));
|
|
39654
|
+
case "alphanum":
|
|
39655
|
+
return (cp) => RE_ALPHANUM.test(String.fromCodePoint(cp));
|
|
39656
|
+
case "cntrl":
|
|
39657
|
+
return (cp) => RE_CNTRL.test(String.fromCodePoint(cp));
|
|
39658
|
+
case "digit":
|
|
39659
|
+
return (cp) => cp >= 48 && cp <= 57;
|
|
39660
|
+
case "graphic":
|
|
39661
|
+
return (cp) => RE_GRAPHIC.test(String.fromCodePoint(cp));
|
|
39662
|
+
case "lower":
|
|
39663
|
+
return (cp) => RE_LOWER.test(String.fromCodePoint(cp));
|
|
39664
|
+
case "print":
|
|
39665
|
+
return (cp) => cp === 32 || RE_GRAPHIC.test(String.fromCodePoint(cp));
|
|
39666
|
+
case "punct":
|
|
39667
|
+
return (cp) => RE_PUNCT.test(String.fromCodePoint(cp));
|
|
39668
|
+
case "wspace":
|
|
39669
|
+
return (cp) => RE_WSPACE.test(String.fromCodePoint(cp));
|
|
39670
|
+
case "upper":
|
|
39671
|
+
return (cp) => RE_UPPER.test(String.fromCodePoint(cp));
|
|
39672
|
+
case "xdigit":
|
|
39673
|
+
return (cp) => cp >= 48 && cp <= 57 || cp >= 65 && cp <= 70 || cp >= 97 && cp <= 102;
|
|
39674
|
+
default:
|
|
39675
|
+
return null;
|
|
39676
|
+
}
|
|
39677
|
+
}
|
|
39678
|
+
function stringCodePoints(s) {
|
|
39679
|
+
const out = [];
|
|
39680
|
+
for (const ch of s) out.push(ch.codePointAt(0));
|
|
39681
|
+
return out;
|
|
39682
|
+
}
|
|
39683
|
+
function logicalRowFromString(s, pred, shape) {
|
|
39684
|
+
const cps = stringCodePoints(s);
|
|
39685
|
+
const data = new FloatXArray(cps.length);
|
|
39686
|
+
for (let i = 0; i < cps.length; i++) data[i] = pred(cps[i]) ? 1 : 0;
|
|
39687
|
+
return {
|
|
39688
|
+
kind: "tensor",
|
|
39689
|
+
data,
|
|
39690
|
+
shape: shape ?? [1, cps.length],
|
|
39691
|
+
_isLogical: true,
|
|
39692
|
+
_rc: 1
|
|
39693
|
+
};
|
|
39694
|
+
}
|
|
39695
|
+
function logicalFromNumericTensor(data, shape, pred) {
|
|
39696
|
+
const out = new FloatXArray(data.length);
|
|
39697
|
+
for (let i = 0; i < data.length; i++) {
|
|
39698
|
+
out[i] = pred(Math.round(data[i])) ? 1 : 0;
|
|
39699
|
+
}
|
|
39700
|
+
return {
|
|
39701
|
+
kind: "tensor",
|
|
39702
|
+
data: out,
|
|
39703
|
+
shape: [...shape],
|
|
39704
|
+
_isLogical: true,
|
|
39705
|
+
_rc: 1
|
|
39706
|
+
};
|
|
39707
|
+
}
|
|
39708
|
+
function isstrpropApply(args) {
|
|
39709
|
+
const v = args[0];
|
|
39710
|
+
const category = toString(args[1]);
|
|
39711
|
+
const pred = isstrpropPredicate(category);
|
|
39712
|
+
if (!pred) {
|
|
39713
|
+
throw new RuntimeError(`isstrprop: unknown category '${category}'`);
|
|
39714
|
+
}
|
|
39715
|
+
let forceCell = false;
|
|
39716
|
+
if (args.length >= 3) {
|
|
39717
|
+
const flagName = toString(args[2]).toLowerCase();
|
|
39718
|
+
if (flagName !== "forcecelloutput") {
|
|
39719
|
+
throw new RuntimeError(`isstrprop: unknown name '${toString(args[2])}'`);
|
|
39720
|
+
}
|
|
39721
|
+
if (args.length < 4) {
|
|
39722
|
+
throw new RuntimeError("isstrprop: 'ForceCellOutput' requires a value");
|
|
39723
|
+
}
|
|
39724
|
+
forceCell = toNumber(args[3]) !== 0;
|
|
39725
|
+
}
|
|
39726
|
+
if (isRuntimeCell(v)) {
|
|
39727
|
+
const out = new Array(v.data.length);
|
|
39728
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
39729
|
+
const elem = v.data[i];
|
|
39730
|
+
const s = isText(elem) ? toString(elem) : "";
|
|
39731
|
+
out[i] = logicalRowFromString(s, pred);
|
|
39732
|
+
}
|
|
39733
|
+
return RTV.cell(out, [...v.shape]);
|
|
39734
|
+
}
|
|
39735
|
+
let result;
|
|
39736
|
+
if (isRuntimeString(v)) {
|
|
39737
|
+
result = logicalRowFromString(toString(v), pred);
|
|
39738
|
+
} else if (isRuntimeChar(v)) {
|
|
39739
|
+
const c = v;
|
|
39740
|
+
result = logicalRowFromString(
|
|
39741
|
+
c.value,
|
|
39742
|
+
pred,
|
|
39743
|
+
c.shape ? [...c.shape] : void 0
|
|
39744
|
+
);
|
|
39745
|
+
} else if (isRuntimeTensor(v)) {
|
|
39746
|
+
result = logicalFromNumericTensor(v.data, v.shape, pred);
|
|
39747
|
+
} else if (isRuntimeNumber(v) || isRuntimeLogical(v)) {
|
|
39748
|
+
const cp = Math.round(toNumber(v));
|
|
39749
|
+
const data = new FloatXArray(1);
|
|
39750
|
+
data[0] = pred(cp) ? 1 : 0;
|
|
39751
|
+
result = { kind: "tensor", data, shape: [1, 1], _isLogical: true, _rc: 1 };
|
|
39752
|
+
} else {
|
|
39753
|
+
throw new RuntimeError("isstrprop: unsupported input type");
|
|
39754
|
+
}
|
|
39755
|
+
if (forceCell) return RTV.cell([result], [1, 1]);
|
|
39756
|
+
return result;
|
|
39757
|
+
}
|
|
39758
|
+
registerIBuiltin({
|
|
39759
|
+
name: "isstrprop",
|
|
39760
|
+
help: {
|
|
39761
|
+
signatures: [
|
|
39762
|
+
"TF = isstrprop(str, category)",
|
|
39763
|
+
"TF = isstrprop(str, category, 'ForceCellOutput', tf)"
|
|
39764
|
+
],
|
|
39765
|
+
description: "Test which characters in str belong to a category (alpha, alphanum, cntrl, digit, graphic, lower, print, punct, upper, wspace, xdigit). Returns a logical array, or a cell of logical vectors when str is a cell array or ForceCellOutput is true. Numeric input is treated as Unicode code points."
|
|
39766
|
+
},
|
|
39767
|
+
resolve: (argTypes) => {
|
|
39768
|
+
if (argTypes.length < 2 || argTypes.length > 4) return null;
|
|
39769
|
+
if (!isTextType(argTypes[1])) return null;
|
|
39770
|
+
if (argTypes.length >= 3 && !isTextType(argTypes[2])) return null;
|
|
39771
|
+
if (argTypes.length === 4) {
|
|
39772
|
+
const k = argTypes[3].kind;
|
|
39773
|
+
if (k !== "number" && k !== "boolean") return null;
|
|
39774
|
+
}
|
|
39775
|
+
const t0 = argTypes[0];
|
|
39776
|
+
if (t0.kind !== "char" && t0.kind !== "string" && t0.kind !== "number" && t0.kind !== "boolean" && t0.kind !== "tensor" && t0.kind !== "cell") {
|
|
39777
|
+
return null;
|
|
39778
|
+
}
|
|
39779
|
+
const isCell = t0.kind === "cell";
|
|
39780
|
+
return {
|
|
39781
|
+
outputTypes: isCell ? [{ kind: "cell" }] : [{ kind: "tensor", isComplex: false, isLogical: true }],
|
|
39782
|
+
apply: (args) => isstrpropApply(args)
|
|
39783
|
+
};
|
|
39784
|
+
}
|
|
39785
|
+
});
|
|
38181
39786
|
registerIBuiltin({
|
|
38182
39787
|
name: "contains",
|
|
38183
39788
|
resolve: (argTypes) => {
|
|
@@ -39150,32 +40755,31 @@ defineBuiltin({
|
|
|
39150
40755
|
}
|
|
39151
40756
|
]
|
|
39152
40757
|
});
|
|
39153
|
-
|
|
39154
|
-
|
|
39155
|
-
|
|
39156
|
-
|
|
39157
|
-
|
|
39158
|
-
|
|
39159
|
-
|
|
39160
|
-
|
|
39161
|
-
|
|
39162
|
-
|
|
39163
|
-
|
|
39164
|
-
|
|
39165
|
-
|
|
39166
|
-
|
|
39167
|
-
|
|
39168
|
-
|
|
39169
|
-
|
|
39170
|
-
|
|
39171
|
-
);
|
|
39172
|
-
|
|
39173
|
-
return ismemberStrings(v, b, nargout);
|
|
39174
|
-
return ismemberNumeric(v, b, nargout);
|
|
39175
|
-
}
|
|
40758
|
+
var ismemberCases = [
|
|
40759
|
+
{
|
|
40760
|
+
match: (argTypes, nargout) => {
|
|
40761
|
+
if (argTypes.length < 2) return null;
|
|
40762
|
+
const out = [{ kind: "unknown" }];
|
|
40763
|
+
if (nargout > 1) out.push({ kind: "unknown" });
|
|
40764
|
+
return out;
|
|
40765
|
+
},
|
|
40766
|
+
apply: (args, nargout) => {
|
|
40767
|
+
if (args.length < 2)
|
|
40768
|
+
throw new RuntimeError("ismember requires 2 arguments");
|
|
40769
|
+
const v = args[0];
|
|
40770
|
+
const b = args[1];
|
|
40771
|
+
const isStringLike = (x) => isRuntimeString(x) || isRuntimeChar(x);
|
|
40772
|
+
const isCellOfStrings = (x) => isRuntimeCell(x) && x.data.every(
|
|
40773
|
+
(e) => isRuntimeString(e) || isRuntimeChar(e)
|
|
40774
|
+
);
|
|
40775
|
+
if (isStringLike(v) || isCellOfStrings(v) || isStringLike(b) || isCellOfStrings(b))
|
|
40776
|
+
return ismemberStrings(v, b, nargout);
|
|
40777
|
+
return ismemberNumeric(v, b, nargout);
|
|
39176
40778
|
}
|
|
39177
|
-
|
|
39178
|
-
|
|
40779
|
+
}
|
|
40780
|
+
];
|
|
40781
|
+
defineBuiltin({ name: "ismember", cases: ismemberCases });
|
|
40782
|
+
defineBuiltin({ name: "ismembc", cases: ismemberCases });
|
|
39179
40783
|
function ismemberStrings(v, b, nargout) {
|
|
39180
40784
|
const isStringLike = (x) => isRuntimeString(x) || isRuntimeChar(x);
|
|
39181
40785
|
const isCellOfStrings = (x) => isRuntimeCell(x) && x.data.every((e) => isRuntimeString(e) || isRuntimeChar(e));
|
|
@@ -43717,11 +45321,11 @@ defineBuiltin({
|
|
|
43717
45321
|
}
|
|
43718
45322
|
} else {
|
|
43719
45323
|
const p2 = n / 2;
|
|
43720
|
-
const
|
|
45324
|
+
const sub2 = new Array(p2 * p2).fill(0);
|
|
43721
45325
|
const sset = (r, c, v) => {
|
|
43722
|
-
|
|
45326
|
+
sub2[c * p2 + r] = v;
|
|
43723
45327
|
};
|
|
43724
|
-
const sget = (r, c) =>
|
|
45328
|
+
const sget = (r, c) => sub2[c * p2 + r];
|
|
43725
45329
|
let si = 0;
|
|
43726
45330
|
let sj = Math.floor(p2 / 2);
|
|
43727
45331
|
for (let k2 = 1; k2 <= p2 * p2; k2++) {
|
|
@@ -47024,6 +48628,88 @@ for (const [name, fn, scaleFn] of besselDefs) {
|
|
|
47024
48628
|
})
|
|
47025
48629
|
});
|
|
47026
48630
|
}
|
|
48631
|
+
function besselhScalar(nu, k, z, scale) {
|
|
48632
|
+
const J = besselj(nu, z);
|
|
48633
|
+
const Y = bessely(nu, z);
|
|
48634
|
+
let re2 = J;
|
|
48635
|
+
let im2 = k === 1 ? Y : -Y;
|
|
48636
|
+
if (scale) {
|
|
48637
|
+
const c = Math.cos(z);
|
|
48638
|
+
const s = Math.sin(z);
|
|
48639
|
+
if (k === 1) {
|
|
48640
|
+
const newRe = re2 * c + im2 * s;
|
|
48641
|
+
const newIm = im2 * c - re2 * s;
|
|
48642
|
+
re2 = newRe;
|
|
48643
|
+
im2 = newIm;
|
|
48644
|
+
} else {
|
|
48645
|
+
const newRe = re2 * c - im2 * s;
|
|
48646
|
+
const newIm = re2 * s + im2 * c;
|
|
48647
|
+
re2 = newRe;
|
|
48648
|
+
im2 = newIm;
|
|
48649
|
+
}
|
|
48650
|
+
}
|
|
48651
|
+
return { re: re2, im: im2 };
|
|
48652
|
+
}
|
|
48653
|
+
function binaryApplyComplex(a, b, fn, name) {
|
|
48654
|
+
const aIsT = isRuntimeTensor(a);
|
|
48655
|
+
const bIsT = isRuntimeTensor(b);
|
|
48656
|
+
const buildTensor = (len, shape, iter) => {
|
|
48657
|
+
const re2 = new FloatXArray(len);
|
|
48658
|
+
const im2 = new FloatXArray(len);
|
|
48659
|
+
let hasImag = false;
|
|
48660
|
+
for (let i = 0; i < len; i++) {
|
|
48661
|
+
const r2 = iter(i);
|
|
48662
|
+
re2[i] = r2.re;
|
|
48663
|
+
im2[i] = r2.im;
|
|
48664
|
+
if (r2.im !== 0) hasImag = true;
|
|
48665
|
+
}
|
|
48666
|
+
return RTV.tensor(re2, shape, hasImag ? im2 : void 0);
|
|
48667
|
+
};
|
|
48668
|
+
if (aIsT && bIsT) {
|
|
48669
|
+
if (a.data.length !== b.data.length)
|
|
48670
|
+
throw new RuntimeError(`${name}: array dimensions must agree`);
|
|
48671
|
+
return buildTensor(a.data.length, a.shape, (i) => fn(a.data[i], b.data[i]));
|
|
48672
|
+
}
|
|
48673
|
+
if (aIsT) {
|
|
48674
|
+
const bv = toNumber(b);
|
|
48675
|
+
return buildTensor(a.data.length, a.shape, (i) => fn(a.data[i], bv));
|
|
48676
|
+
}
|
|
48677
|
+
if (bIsT) {
|
|
48678
|
+
const av = toNumber(a);
|
|
48679
|
+
return buildTensor(b.data.length, b.shape, (i) => fn(av, b.data[i]));
|
|
48680
|
+
}
|
|
48681
|
+
const r = fn(toNumber(a), toNumber(b));
|
|
48682
|
+
return r.im === 0 ? RTV.num(r.re) : RTV.complex(r.re, r.im);
|
|
48683
|
+
}
|
|
48684
|
+
registerIBuiltin({
|
|
48685
|
+
name: "besselh",
|
|
48686
|
+
resolve: () => ({
|
|
48687
|
+
outputTypes: [{ kind: "unknown" }],
|
|
48688
|
+
apply: (args) => {
|
|
48689
|
+
if (args.length < 2 || args.length > 4)
|
|
48690
|
+
throw new RuntimeError("besselh requires 2 to 4 arguments");
|
|
48691
|
+
const nuArg = args[0];
|
|
48692
|
+
let k = 1;
|
|
48693
|
+
let zArg;
|
|
48694
|
+
let scale = false;
|
|
48695
|
+
if (args.length === 2) {
|
|
48696
|
+
zArg = args[1];
|
|
48697
|
+
} else {
|
|
48698
|
+
k = Math.round(toNumber(args[1]));
|
|
48699
|
+
if (k !== 1 && k !== 2)
|
|
48700
|
+
throw new RuntimeError("besselh: K must be 1 or 2");
|
|
48701
|
+
zArg = args[2];
|
|
48702
|
+
if (args.length === 4) scale = toNumber(args[3]) === 1;
|
|
48703
|
+
}
|
|
48704
|
+
return binaryApplyComplex(
|
|
48705
|
+
nuArg,
|
|
48706
|
+
zArg,
|
|
48707
|
+
(nu, z) => besselhScalar(nu, k, z, scale),
|
|
48708
|
+
"besselh"
|
|
48709
|
+
);
|
|
48710
|
+
}
|
|
48711
|
+
})
|
|
48712
|
+
});
|
|
47027
48713
|
var airyFns = [airyAi, airyAiPrime, airyBi, airyBiPrime];
|
|
47028
48714
|
var airyComplexKeys = ["ai", "aip", "bi", "bip"];
|
|
47029
48715
|
function scaleAiry(n, x, val) {
|
|
@@ -48389,6 +50075,14 @@ var H = {
|
|
|
48389
50075
|
signatures: ["Y = besselk(NU, Z)", "Y = besselk(NU, Z, SCALE)"],
|
|
48390
50076
|
description: "Modified Bessel function of the second kind. SCALE=1 applies exponential scaling."
|
|
48391
50077
|
},
|
|
50078
|
+
besselh: {
|
|
50079
|
+
signatures: [
|
|
50080
|
+
"H = besselh(NU, Z)",
|
|
50081
|
+
"H = besselh(NU, K, Z)",
|
|
50082
|
+
"H = besselh(NU, K, Z, SCALE)"
|
|
50083
|
+
],
|
|
50084
|
+
description: "Hankel function (Bessel function of the third kind). K=1 (default) gives H^(1) = J + i*Y; K=2 gives H^(2) = J - i*Y. SCALE=1 multiplies by exp(-i*Z) for K=1 or exp(+i*Z) for K=2."
|
|
50085
|
+
},
|
|
48392
50086
|
airy: {
|
|
48393
50087
|
signatures: ["Y = airy(X)", "Y = airy(K, X)", "Y = airy(K, X, SCALE)"],
|
|
48394
50088
|
description: "Airy functions. K selects the function: 0=Ai (default), 1=Ai', 2=Bi, 3=Bi'. SCALE=1 applies exponential scaling."
|
|
@@ -48439,6 +50133,15 @@ var H = {
|
|
|
48439
50133
|
signatures: ["TF = isequal(A, B, ...)"],
|
|
48440
50134
|
description: "True if all inputs are equal (NaN ~= NaN)."
|
|
48441
50135
|
},
|
|
50136
|
+
// ── Dynamic evaluation ────────────────────────────────────────────────
|
|
50137
|
+
evalin: {
|
|
50138
|
+
signatures: ["V = evalin(WS, EXPR)", "V = evalin(WS, EXPR, DEFAULT)"],
|
|
50139
|
+
description: "Evaluate EXPR in workspace WS ('caller' or 'base'/'workspace').\n\nnumbl-specific note: variables read by evalin must be declared in the\nfunction that owns them with a `% external-access:` comment, e.g.\n function out = f()\n % external-access: x y\n x = 1; y = 2;\n ...\n end\nVariables not listed in `% external-access` are stored in a separate\ndynamic map and are only reachable through evalin/assignin. The\ndirective is a comment, so MATLAB ignores it."
|
|
50140
|
+
},
|
|
50141
|
+
assignin: {
|
|
50142
|
+
signatures: ["assignin(WS, NAME, VALUE)"],
|
|
50143
|
+
description: "Assign VALUE to variable NAME in workspace WS ('caller' or 'base'/'workspace').\n\nnumbl-specific note: variables written by assignin must be declared in\nthe function that owns them with a `% external-access:` comment, e.g.\n function out = f()\n % external-access: x y\n x = 1; y = 2;\n ...\n end\nVariables not listed in `% external-access` are stored in a separate\ndynamic map and are only reachable through evalin/assignin. The\ndirective is a comment, so MATLAB ignores it."
|
|
50144
|
+
},
|
|
48442
50145
|
// ── Misc ──────────────────────────────────────────────────────────────
|
|
48443
50146
|
disp: {
|
|
48444
50147
|
signatures: ["disp(X)"],
|
|
@@ -49253,6 +50956,46 @@ function formatDiagnostics(infos, getSource) {
|
|
|
49253
50956
|
return infos.map((i) => formatDiagnostic(i, getSource)).join("\n\n");
|
|
49254
50957
|
}
|
|
49255
50958
|
function formatDiagnostic(info, getSource) {
|
|
50959
|
+
if (info.callStack != null && info.callStack.length > 0) {
|
|
50960
|
+
const stack = info.callStack;
|
|
50961
|
+
const N = stack.length;
|
|
50962
|
+
const parts = [];
|
|
50963
|
+
const innerName = stack[N - 1].name;
|
|
50964
|
+
const innerFile = info.file;
|
|
50965
|
+
const innerLine = info.line ?? 0;
|
|
50966
|
+
if (innerFile && innerLine > 0) {
|
|
50967
|
+
parts.push(`Error using ${innerName} (${innerFile}:${innerLine})`);
|
|
50968
|
+
} else if (innerLine > 0) {
|
|
50969
|
+
parts.push(`Error using ${innerName} (line ${innerLine})`);
|
|
50970
|
+
} else {
|
|
50971
|
+
parts.push(`Error using ${innerName}`);
|
|
50972
|
+
}
|
|
50973
|
+
parts.push(info.message);
|
|
50974
|
+
for (let i = N - 2; i >= 0; i--) {
|
|
50975
|
+
const name = stack[i].name;
|
|
50976
|
+
const callerFrame = stack[i + 1];
|
|
50977
|
+
const file = callerFrame.callerFile;
|
|
50978
|
+
const line = callerFrame.callerLine;
|
|
50979
|
+
parts.push("");
|
|
50980
|
+
if (file && line > 0) {
|
|
50981
|
+
parts.push(`Error in ${name} (${file}:${line})`);
|
|
50982
|
+
const srcLine = getSource ? getSourceLine(getSource, file, line) : callerFrame.callerSourceLine ?? null;
|
|
50983
|
+
if (srcLine) parts.push(` ${srcLine}`);
|
|
50984
|
+
} else if (line > 0) {
|
|
50985
|
+
parts.push(`Error in ${name} (line ${line})`);
|
|
50986
|
+
} else {
|
|
50987
|
+
parts.push(`Error in ${name}`);
|
|
50988
|
+
}
|
|
50989
|
+
}
|
|
50990
|
+
const outermost = stack[0];
|
|
50991
|
+
if (outermost.callerFile && outermost.callerLine > 0) {
|
|
50992
|
+
parts.push("");
|
|
50993
|
+
parts.push(`Error in ${outermost.callerFile}:${outermost.callerLine}`);
|
|
50994
|
+
const srcLine = getSource ? getSourceLine(getSource, outermost.callerFile, outermost.callerLine) : outermost.callerSourceLine ?? null;
|
|
50995
|
+
if (srcLine) parts.push(` ${srcLine}`);
|
|
50996
|
+
}
|
|
50997
|
+
return parts.join("\n");
|
|
50998
|
+
}
|
|
49256
50999
|
const labels = {
|
|
49257
51000
|
syntax: "SyntaxError",
|
|
49258
51001
|
semantic: "SemanticError",
|
|
@@ -49270,61 +51013,6 @@ function formatDiagnostic(info, getSource) {
|
|
|
49270
51013
|
result += `
|
|
49271
51014
|
${info.snippet}`;
|
|
49272
51015
|
}
|
|
49273
|
-
if (info.callStack != null && info.callStack.length > 0) {
|
|
49274
|
-
result += `
|
|
49275
|
-
Call stack (most recent call first):`;
|
|
49276
|
-
const stack = info.callStack;
|
|
49277
|
-
const N = stack.length;
|
|
49278
|
-
for (let i = N - 1; i >= 0; i--) {
|
|
49279
|
-
const name = stack[i].name;
|
|
49280
|
-
let loc;
|
|
49281
|
-
let file = null;
|
|
49282
|
-
let line = 0;
|
|
49283
|
-
if (i === N - 1) {
|
|
49284
|
-
file = info.file;
|
|
49285
|
-
line = info.line ?? 0;
|
|
49286
|
-
if (file && line > 0) {
|
|
49287
|
-
loc = `${file}:${line}`;
|
|
49288
|
-
} else if (line > 0) {
|
|
49289
|
-
loc = `line ${line}`;
|
|
49290
|
-
} else {
|
|
49291
|
-
loc = "unknown";
|
|
49292
|
-
}
|
|
49293
|
-
} else {
|
|
49294
|
-
const callerFrame = stack[i + 1];
|
|
49295
|
-
file = callerFrame.callerFile;
|
|
49296
|
-
line = callerFrame.callerLine;
|
|
49297
|
-
if (file && line > 0) {
|
|
49298
|
-
loc = `${file}:${line}`;
|
|
49299
|
-
} else if (line > 0) {
|
|
49300
|
-
loc = `line ${line}`;
|
|
49301
|
-
} else {
|
|
49302
|
-
loc = "unknown";
|
|
49303
|
-
}
|
|
49304
|
-
}
|
|
49305
|
-
result += `
|
|
49306
|
-
at ${name} (${loc})`;
|
|
49307
|
-
if (file && line > 0) {
|
|
49308
|
-
let srcLine = null;
|
|
49309
|
-
if (getSource) {
|
|
49310
|
-
srcLine = getSourceLine(getSource, file, line);
|
|
49311
|
-
} else if (i === N - 1) {
|
|
49312
|
-
} else {
|
|
49313
|
-
srcLine = stack[i + 1].callerSourceLine ?? null;
|
|
49314
|
-
}
|
|
49315
|
-
if (srcLine) result += `
|
|
49316
|
-
${srcLine}`;
|
|
49317
|
-
}
|
|
49318
|
-
}
|
|
49319
|
-
const outermost = stack[0];
|
|
49320
|
-
if (outermost.callerFile && outermost.callerLine > 0) {
|
|
49321
|
-
result += `
|
|
49322
|
-
at ${outermost.callerFile}:${outermost.callerLine}`;
|
|
49323
|
-
const srcLine = getSource ? getSourceLine(getSource, outermost.callerFile, outermost.callerLine) : outermost.callerSourceLine ?? null;
|
|
49324
|
-
if (srcLine) result += `
|
|
49325
|
-
${srcLine}`;
|
|
49326
|
-
}
|
|
49327
|
-
}
|
|
49328
51016
|
return result;
|
|
49329
51017
|
}
|
|
49330
51018
|
function getSourceLine(getSource, file, line) {
|
|
@@ -49336,7 +51024,7 @@ function getSourceLine(getSource, file, line) {
|
|
|
49336
51024
|
}
|
|
49337
51025
|
|
|
49338
51026
|
// src/numbl-core/version.ts
|
|
49339
|
-
var NUMBL_VERSION = "0.1.
|
|
51027
|
+
var NUMBL_VERSION = "0.1.6";
|
|
49340
51028
|
|
|
49341
51029
|
// src/cli-repl.ts
|
|
49342
51030
|
import { createInterface } from "readline";
|
|
@@ -49354,7 +51042,7 @@ import { homedir as homedir2 } from "os";
|
|
|
49354
51042
|
// src/numbl-core/jsUserFunctions.ts
|
|
49355
51043
|
function funcNameFromFile(fileName) {
|
|
49356
51044
|
const base = fileName.split("/").pop();
|
|
49357
|
-
return base.replace(/\.js$/, "");
|
|
51045
|
+
return base.replace(/\.numbl\.js$/, "");
|
|
49358
51046
|
}
|
|
49359
51047
|
function buildWasmMap(wasmFiles) {
|
|
49360
51048
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -49378,6 +51066,9 @@ function parseDirectives(source) {
|
|
|
49378
51066
|
}
|
|
49379
51067
|
return directives;
|
|
49380
51068
|
}
|
|
51069
|
+
function isNumblJsFile(fileName) {
|
|
51070
|
+
return fileName.endsWith(".numbl.js");
|
|
51071
|
+
}
|
|
49381
51072
|
function nativeLibFilename(baseName) {
|
|
49382
51073
|
const platform = typeof process !== "undefined" ? process.platform : "linux";
|
|
49383
51074
|
switch (platform) {
|
|
@@ -49451,7 +51142,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
49451
51142
|
for (const file of jsFiles) {
|
|
49452
51143
|
const base = file.name.split("/").pop();
|
|
49453
51144
|
if (base.startsWith("_")) {
|
|
49454
|
-
const libName = base.replace(/\.js$/, "");
|
|
51145
|
+
const libName = base.replace(/\.numbl\.js$/, "");
|
|
49455
51146
|
libraryFiles.set(libName, file);
|
|
49456
51147
|
} else {
|
|
49457
51148
|
functionFiles.push(file);
|
|
@@ -49461,13 +51152,13 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
49461
51152
|
function importJS(name) {
|
|
49462
51153
|
const cached = libCache.get(name);
|
|
49463
51154
|
if (cached === LOADING) {
|
|
49464
|
-
throw new RuntimeError(`Circular dependency detected: ${name}.js`);
|
|
51155
|
+
throw new RuntimeError(`Circular dependency detected: ${name}.numbl.js`);
|
|
49465
51156
|
}
|
|
49466
51157
|
if (libCache.has(name)) return cached;
|
|
49467
51158
|
const libFile = libraryFiles.get(name);
|
|
49468
51159
|
if (!libFile) {
|
|
49469
51160
|
throw new RuntimeError(
|
|
49470
|
-
`importJS: library '${name}.js' not found in workspace`
|
|
51161
|
+
`importJS: library '${name}.numbl.js' not found in workspace`
|
|
49471
51162
|
);
|
|
49472
51163
|
}
|
|
49473
51164
|
libCache.set(name, LOADING);
|
|
@@ -49480,7 +51171,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
49480
51171
|
);
|
|
49481
51172
|
const dummyRegister = () => {
|
|
49482
51173
|
throw new RuntimeError(
|
|
49483
|
-
`Library file '${name}.js' must not call register(). Use return {...} to export values.`
|
|
51174
|
+
`Library file '${name}.numbl.js' must not call register(). Use return {...} to export values.`
|
|
49484
51175
|
);
|
|
49485
51176
|
};
|
|
49486
51177
|
const factory = new Function(
|
|
@@ -49515,7 +51206,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
49515
51206
|
}
|
|
49516
51207
|
if (builtin) {
|
|
49517
51208
|
throw new Error(
|
|
49518
|
-
"register() called more than once \u2014 only one registration per .js file"
|
|
51209
|
+
"register() called more than once \u2014 only one registration per .numbl.js file"
|
|
49519
51210
|
);
|
|
49520
51211
|
}
|
|
49521
51212
|
builtin = {
|
|
@@ -49582,7 +51273,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
49582
51273
|
};
|
|
49583
51274
|
};
|
|
49584
51275
|
}
|
|
49585
|
-
result.push(builtin);
|
|
51276
|
+
result.push({ name: funcName, fileName: file.name, builtin });
|
|
49586
51277
|
} catch (e) {
|
|
49587
51278
|
const msg = e instanceof Error ? e.message : String(e);
|
|
49588
51279
|
throw new Error(
|
|
@@ -49795,7 +51486,7 @@ function resolveFunction(name, argTypes, callSite, index2) {
|
|
|
49795
51486
|
};
|
|
49796
51487
|
}
|
|
49797
51488
|
if (index2.jsUserFunctions.has(name)) {
|
|
49798
|
-
return { kind: "
|
|
51489
|
+
return { kind: "jsUserFunction", name, argTypes };
|
|
49799
51490
|
}
|
|
49800
51491
|
if (index2.workspaceClasses.has(name)) {
|
|
49801
51492
|
return {
|
|
@@ -50648,7 +52339,8 @@ function lowerMultiAssign(ctx, stmt) {
|
|
|
50648
52339
|
if (args.some((a) => a === null)) return null;
|
|
50649
52340
|
const loweredArgs = args;
|
|
50650
52341
|
const argJitTypes = loweredArgs.map((a) => a.jitType);
|
|
50651
|
-
const
|
|
52342
|
+
const jsEntry = ctx.interp?.ctx.registry.jsUserFunctionsByName.get(rhs.name);
|
|
52343
|
+
const ib = jsEntry?.builtin ?? getIBuiltin(rhs.name);
|
|
50652
52344
|
if (!ib) return null;
|
|
50653
52345
|
const resolution = ib.resolve(argJitTypes, nargout);
|
|
50654
52346
|
if (!resolution || resolution.outputTypes.length < nargout) return null;
|
|
@@ -51072,7 +52764,8 @@ function resolveUserFunction(interp, name, argJitTypes) {
|
|
|
51072
52764
|
return null;
|
|
51073
52765
|
}
|
|
51074
52766
|
function lowerIBuiltinCall(ctx, expr) {
|
|
51075
|
-
const
|
|
52767
|
+
const jsEntry = ctx.interp?.ctx.registry.jsUserFunctionsByName.get(expr.name);
|
|
52768
|
+
const ib = jsEntry?.builtin ?? getIBuiltin(expr.name);
|
|
51076
52769
|
if (!ib) return null;
|
|
51077
52770
|
const args = expr.args.map((a) => lowerExpr(ctx, a));
|
|
51078
52771
|
if (args.some((a) => a === null)) return null;
|
|
@@ -51315,10 +53008,10 @@ function idxN(base, indices) {
|
|
|
51315
53008
|
let stride = 1;
|
|
51316
53009
|
for (let k = 0; k < indices.length; k++) {
|
|
51317
53010
|
const dimSize = k < s.length ? s[k] : 1;
|
|
51318
|
-
const
|
|
51319
|
-
if (
|
|
53011
|
+
const sub2 = Math.round(indices[k]) - 1;
|
|
53012
|
+
if (sub2 < 0 || sub2 >= dimSize)
|
|
51320
53013
|
throw new Error("Index exceeds array bounds");
|
|
51321
|
-
lin +=
|
|
53014
|
+
lin += sub2 * stride;
|
|
51322
53015
|
stride *= dimSize;
|
|
51323
53016
|
}
|
|
51324
53017
|
if (base.imag !== void 0) {
|
|
@@ -51429,6 +53122,48 @@ setDynamicRegisterHook((b) => {
|
|
|
51429
53122
|
return typeof result === "boolean" ? result ? 1 : 0 : result;
|
|
51430
53123
|
};
|
|
51431
53124
|
});
|
|
53125
|
+
function buildPerRuntimeJitHelpers(jsUserFunctions) {
|
|
53126
|
+
const h = Object.assign({}, jitHelpers);
|
|
53127
|
+
for (const [name, ib] of jsUserFunctions) {
|
|
53128
|
+
h[`ib_${name}`] = (...args) => {
|
|
53129
|
+
const pe = h._profileEnter;
|
|
53130
|
+
const pl = h._profileLeave;
|
|
53131
|
+
pe("jsUserFunction:jit:" + name);
|
|
53132
|
+
const rtArgs = args;
|
|
53133
|
+
const argTypes = rtArgs.map(inferJitType);
|
|
53134
|
+
const res = ib.resolve(argTypes, 1);
|
|
53135
|
+
if (!res) {
|
|
53136
|
+
pl();
|
|
53137
|
+
throw new Error(`JIT ib_${name}: resolve failed`);
|
|
53138
|
+
}
|
|
53139
|
+
const result = res.apply(rtArgs, 1);
|
|
53140
|
+
pl();
|
|
53141
|
+
return typeof result === "boolean" ? result ? 1 : 0 : result;
|
|
53142
|
+
};
|
|
53143
|
+
}
|
|
53144
|
+
const origIbcall = h.ibcall;
|
|
53145
|
+
h.ibcall = (name, nargout, ...args) => {
|
|
53146
|
+
const ib = jsUserFunctions.get(name);
|
|
53147
|
+
if (!ib) return origIbcall(name, nargout, ...args);
|
|
53148
|
+
const pe = h._profileEnter;
|
|
53149
|
+
const pl = h._profileLeave;
|
|
53150
|
+
pe("jsUserFunction:jit:" + name);
|
|
53151
|
+
const rtArgs = args;
|
|
53152
|
+
const argTypes = rtArgs.map(inferJitType);
|
|
53153
|
+
const res = ib.resolve(argTypes, nargout);
|
|
53154
|
+
if (!res) {
|
|
53155
|
+
pl();
|
|
53156
|
+
throw new Error(`JIT ibcall: resolve failed for ${name}`);
|
|
53157
|
+
}
|
|
53158
|
+
const result = res.apply(rtArgs, nargout);
|
|
53159
|
+
pl();
|
|
53160
|
+
if (Array.isArray(result)) {
|
|
53161
|
+
return result.map((v) => typeof v === "boolean" ? v ? 1 : 0 : v);
|
|
53162
|
+
}
|
|
53163
|
+
return [typeof result === "boolean" ? result ? 1 : 0 : result];
|
|
53164
|
+
};
|
|
53165
|
+
return h;
|
|
53166
|
+
}
|
|
51432
53167
|
|
|
51433
53168
|
// src/numbl-core/interpreter/jit/jitLoopAnalysis.ts
|
|
51434
53169
|
function analyzeForLoop(stmt) {
|
|
@@ -51843,18 +53578,26 @@ function execStmt(stmt) {
|
|
|
51843
53578
|
}
|
|
51844
53579
|
case "While": {
|
|
51845
53580
|
if (this.optimization >= 1 && tryJitWhile(this, stmt)) return null;
|
|
53581
|
+
const _whileStart = this.rt.profilingEnabled ? performance.now() : 0;
|
|
53582
|
+
let _whileIters = 0;
|
|
51846
53583
|
while (true) {
|
|
51847
53584
|
const cond = this.evalExpr(stmt.cond);
|
|
51848
53585
|
if (!this.rt.toBool(cond)) break;
|
|
53586
|
+
_whileIters++;
|
|
51849
53587
|
const signal = this.execStmts(stmt.body);
|
|
51850
53588
|
if (signal instanceof BreakSignal) break;
|
|
51851
53589
|
if (signal instanceof ContinueSignal) continue;
|
|
51852
|
-
if (signal instanceof ReturnSignal)
|
|
53590
|
+
if (signal instanceof ReturnSignal) {
|
|
53591
|
+
recordHotLoop(this, stmt, "while", _whileIters, _whileStart);
|
|
53592
|
+
return signal;
|
|
53593
|
+
}
|
|
51853
53594
|
}
|
|
53595
|
+
recordHotLoop(this, stmt, "while", _whileIters, _whileStart);
|
|
51854
53596
|
return null;
|
|
51855
53597
|
}
|
|
51856
53598
|
case "For": {
|
|
51857
53599
|
if (this.optimization >= 1 && tryJitFor(this, stmt)) return null;
|
|
53600
|
+
const _forStart = this.rt.profilingEnabled ? performance.now() : 0;
|
|
51858
53601
|
const iterVal = this.evalExpr(stmt.expr);
|
|
51859
53602
|
const rv = ensureRuntimeValue(iterVal);
|
|
51860
53603
|
const iterItems = forIter(rv);
|
|
@@ -51863,8 +53606,12 @@ function execStmt(stmt) {
|
|
|
51863
53606
|
const signal = this.execStmts(stmt.body);
|
|
51864
53607
|
if (signal instanceof BreakSignal) break;
|
|
51865
53608
|
if (signal instanceof ContinueSignal) continue;
|
|
51866
|
-
if (signal instanceof ReturnSignal)
|
|
53609
|
+
if (signal instanceof ReturnSignal) {
|
|
53610
|
+
recordHotLoop(this, stmt, "for", _i + 1, _forStart);
|
|
53611
|
+
return signal;
|
|
53612
|
+
}
|
|
51867
53613
|
}
|
|
53614
|
+
recordHotLoop(this, stmt, "for", iterItems.length, _forStart);
|
|
51868
53615
|
return null;
|
|
51869
53616
|
}
|
|
51870
53617
|
case "Switch": {
|
|
@@ -52626,6 +54373,33 @@ function isOutputExpr(expr) {
|
|
|
52626
54373
|
if (expr.type === "Ident") return outputFunctions.includes(expr.name);
|
|
52627
54374
|
return false;
|
|
52628
54375
|
}
|
|
54376
|
+
function recordHotLoop(interp, stmt, kind, iterations, startTime) {
|
|
54377
|
+
if (!interp.rt.profilingEnabled || iterations <= 1e3 || !stmt.span) return;
|
|
54378
|
+
const durationMs = performance.now() - startTime;
|
|
54379
|
+
let table = interp.lineTableCache.get(stmt.span.file);
|
|
54380
|
+
if (!table) {
|
|
54381
|
+
const src = interp.fileSources.get(stmt.span.file) ?? "";
|
|
54382
|
+
table = buildLineTable(src);
|
|
54383
|
+
interp.lineTableCache.set(stmt.span.file, table);
|
|
54384
|
+
}
|
|
54385
|
+
const line = offsetToLineFast(table, stmt.span.start);
|
|
54386
|
+
const key = `${stmt.span.file}:${line}`;
|
|
54387
|
+
const prev = interp.rt.hotLoops.get(key);
|
|
54388
|
+
if (prev) {
|
|
54389
|
+
prev.callCount++;
|
|
54390
|
+
prev.totalTimeMs += durationMs;
|
|
54391
|
+
if (iterations > prev.iterations) prev.iterations = iterations;
|
|
54392
|
+
} else {
|
|
54393
|
+
interp.rt.hotLoops.set(key, {
|
|
54394
|
+
file: stmt.span.file,
|
|
54395
|
+
line,
|
|
54396
|
+
kind,
|
|
54397
|
+
iterations,
|
|
54398
|
+
callCount: 1,
|
|
54399
|
+
totalTimeMs: durationMs
|
|
54400
|
+
});
|
|
54401
|
+
}
|
|
54402
|
+
}
|
|
52629
54403
|
|
|
52630
54404
|
// src/numbl-core/interpreter/interpreterFunctions.ts
|
|
52631
54405
|
var interpreterFunctions_exports = {};
|
|
@@ -52644,6 +54418,7 @@ __export(interpreterFunctions_exports, {
|
|
|
52644
54418
|
instantiateClass: () => instantiateClass,
|
|
52645
54419
|
interpretClassMethod: () => interpretClassMethod,
|
|
52646
54420
|
interpretConstructor: () => interpretConstructor,
|
|
54421
|
+
interpretJsUserFunction: () => interpretJsUserFunction,
|
|
52647
54422
|
interpretLocalFunction: () => interpretLocalFunction,
|
|
52648
54423
|
interpretPrivateFunction: () => interpretPrivateFunction,
|
|
52649
54424
|
interpretTarget: () => interpretTarget,
|
|
@@ -52707,7 +54482,8 @@ function tryJitCall(interp, fn, args, nargout) {
|
|
|
52707
54482
|
const rt = interp.rt;
|
|
52708
54483
|
try {
|
|
52709
54484
|
const factory = new Function("$h", "$rt", ...paramNames, jsBody);
|
|
52710
|
-
|
|
54485
|
+
const helpers = rt.jitHelpers ?? jitHelpers;
|
|
54486
|
+
compiledFn = (...callArgs) => factory(helpers, rt, ...callArgs);
|
|
52711
54487
|
} catch {
|
|
52712
54488
|
fnWithCache._jitCache.set(cacheKey, null);
|
|
52713
54489
|
return JIT_SKIP;
|
|
@@ -52809,27 +54585,76 @@ register("exist", (ctx, args) => {
|
|
|
52809
54585
|
if (args.length < 1) return FALL_THROUGH;
|
|
52810
54586
|
const nameArg = toString(ensureRuntimeValue(args[0]));
|
|
52811
54587
|
const typeArg = args.length >= 2 ? toString(ensureRuntimeValue(args[1])) : "";
|
|
54588
|
+
const fio = ctx.rt.fileIO;
|
|
54589
|
+
const isBuiltin2 = () => !!(ctx.rt.builtins[nameArg] || getIBuiltin(nameArg));
|
|
54590
|
+
const fileTypeFromExt = (path) => /\.numbl\.js$/i.test(path) ? 3 : 2;
|
|
54591
|
+
const nameHasKnownExt = /\.(numbl\.js|m|mlx|mlapp)$/i.test(nameArg);
|
|
54592
|
+
const isAbsolutePath = (p2) => p2.startsWith("/") || p2.startsWith("\\") || /^[a-zA-Z]:[/\\]/.test(p2);
|
|
54593
|
+
const joinPath = (dir, name) => {
|
|
54594
|
+
if (!dir) return name;
|
|
54595
|
+
if (dir.endsWith("/") || dir.endsWith("\\")) return dir + name;
|
|
54596
|
+
return dir + "/" + name;
|
|
54597
|
+
};
|
|
54598
|
+
const walkSearchPath = (acceptDir) => {
|
|
54599
|
+
if (!fio?.existsPath) return 0;
|
|
54600
|
+
const dirs = isAbsolutePath(nameArg) ? [""] : ctx.rt.searchPaths.length > 0 ? ctx.rt.searchPaths : [""];
|
|
54601
|
+
for (const dir of dirs) {
|
|
54602
|
+
if (acceptDir) {
|
|
54603
|
+
const t = fio.existsPath(joinPath(dir, nameArg));
|
|
54604
|
+
if (t === "dir") return 7;
|
|
54605
|
+
}
|
|
54606
|
+
if (!nameHasKnownExt) {
|
|
54607
|
+
for (const ext of [".m", ".mlx", ".mlapp"]) {
|
|
54608
|
+
const t = fio.existsPath(joinPath(dir, nameArg + ext));
|
|
54609
|
+
if (t === "file") {
|
|
54610
|
+
const ws = ctx.lookupWorkspaceFile(nameArg);
|
|
54611
|
+
return ws?.kind === "class" ? 8 : 2;
|
|
54612
|
+
}
|
|
54613
|
+
}
|
|
54614
|
+
const numblJs = fio.existsPath(joinPath(dir, nameArg + ".numbl.js"));
|
|
54615
|
+
if (numblJs === "file") return 3;
|
|
54616
|
+
}
|
|
54617
|
+
const lit = fio.existsPath(joinPath(dir, nameArg));
|
|
54618
|
+
if (lit === "file") return fileTypeFromExt(nameArg);
|
|
54619
|
+
}
|
|
54620
|
+
return 0;
|
|
54621
|
+
};
|
|
54622
|
+
const workspaceTypeId = () => {
|
|
54623
|
+
const ws = ctx.lookupWorkspaceFile(nameArg);
|
|
54624
|
+
if (!ws) return 0;
|
|
54625
|
+
switch (ws.kind) {
|
|
54626
|
+
case "function":
|
|
54627
|
+
return 2;
|
|
54628
|
+
case "jsfunction":
|
|
54629
|
+
return 3;
|
|
54630
|
+
case "class":
|
|
54631
|
+
return 8;
|
|
54632
|
+
}
|
|
54633
|
+
};
|
|
52812
54634
|
if (typeArg === "var") {
|
|
52813
54635
|
return ctx.env.has(nameArg) ? 1 : 0;
|
|
52814
54636
|
}
|
|
52815
54637
|
if (typeArg === "builtin") {
|
|
52816
|
-
return
|
|
54638
|
+
return isBuiltin2() ? 5 : 0;
|
|
54639
|
+
}
|
|
54640
|
+
if (typeArg === "class") {
|
|
54641
|
+
const ws = ctx.lookupWorkspaceFile(nameArg);
|
|
54642
|
+
return ws?.kind === "class" ? 8 : 0;
|
|
52817
54643
|
}
|
|
52818
54644
|
if (typeArg === "dir") {
|
|
52819
|
-
|
|
52820
|
-
|
|
52821
|
-
|
|
52822
|
-
|
|
52823
|
-
|
|
52824
|
-
|
|
52825
|
-
|
|
52826
|
-
|
|
52827
|
-
if (typeArg === "file") return result === "file" ? 2 : 0;
|
|
54645
|
+
return walkSearchPath(true) === 7 ? 7 : 0;
|
|
54646
|
+
}
|
|
54647
|
+
if (typeArg === "file") {
|
|
54648
|
+
const t = walkSearchPath(true);
|
|
54649
|
+
if (t) return t;
|
|
54650
|
+
return workspaceTypeId();
|
|
54651
|
+
}
|
|
54652
|
+
if (typeArg === "") {
|
|
52828
54653
|
if (ctx.env.has(nameArg)) return 1;
|
|
52829
|
-
if (
|
|
52830
|
-
|
|
52831
|
-
if (
|
|
52832
|
-
return
|
|
54654
|
+
if (isBuiltin2()) return 5;
|
|
54655
|
+
const t = walkSearchPath(true);
|
|
54656
|
+
if (t) return t;
|
|
54657
|
+
return workspaceTypeId();
|
|
52833
54658
|
}
|
|
52834
54659
|
return FALL_THROUGH;
|
|
52835
54660
|
});
|
|
@@ -52837,8 +54662,8 @@ register("which", (ctx, args) => {
|
|
|
52837
54662
|
if (args.length < 1) return FALL_THROUGH;
|
|
52838
54663
|
const nameArg = toString(ensureRuntimeValue(args[0]));
|
|
52839
54664
|
if (ctx.env.has(nameArg)) return RTV.char("variable");
|
|
52840
|
-
const
|
|
52841
|
-
if (
|
|
54665
|
+
const ws = ctx.lookupWorkspaceFile(nameArg);
|
|
54666
|
+
if (ws) return RTV.char(ws.path);
|
|
52842
54667
|
if (ctx.rt.builtins[nameArg] || getIBuiltin(nameArg)) {
|
|
52843
54668
|
return RTV.char("built-in");
|
|
52844
54669
|
}
|
|
@@ -52985,9 +54810,11 @@ function callFunction(name, args, nargout) {
|
|
|
52985
54810
|
rt: this.rt,
|
|
52986
54811
|
lookupWorkspaceFile: (n) => {
|
|
52987
54812
|
const entry = this.ctx.registry.filesByFuncName.get(n);
|
|
52988
|
-
if (entry) return entry.fileName;
|
|
54813
|
+
if (entry) return { path: entry.fileName, kind: "function" };
|
|
52989
54814
|
const classInfo = this.ctx.getClassInfo(n);
|
|
52990
|
-
if (classInfo) return classInfo.fileName;
|
|
54815
|
+
if (classInfo) return { path: classInfo.fileName, kind: "class" };
|
|
54816
|
+
const jsEntry = this.ctx.registry.jsUserFunctionsByName.get(n);
|
|
54817
|
+
if (jsEntry) return { path: jsEntry.fileName, kind: "jsfunction" };
|
|
52991
54818
|
return void 0;
|
|
52992
54819
|
}
|
|
52993
54820
|
};
|
|
@@ -53053,6 +54880,8 @@ function interpretTarget(target, args, nargout) {
|
|
|
53053
54880
|
return this.interpretLocalFunction(target, args, nargout);
|
|
53054
54881
|
case "workspaceFunction":
|
|
53055
54882
|
return this.interpretWorkspaceFunction(target, args, nargout);
|
|
54883
|
+
case "jsUserFunction":
|
|
54884
|
+
return this.interpretJsUserFunction(target, args, nargout);
|
|
53056
54885
|
case "classMethod":
|
|
53057
54886
|
return this.interpretClassMethod(target, args, nargout);
|
|
53058
54887
|
case "workspaceClassConstructor":
|
|
@@ -53061,6 +54890,36 @@ function interpretTarget(target, args, nargout) {
|
|
|
53061
54890
|
return this.interpretPrivateFunction(target, args, nargout);
|
|
53062
54891
|
}
|
|
53063
54892
|
}
|
|
54893
|
+
function interpretJsUserFunction(target, args, nargout) {
|
|
54894
|
+
const entry = this.ctx.registry.jsUserFunctionsByName.get(target.name);
|
|
54895
|
+
if (!entry) {
|
|
54896
|
+
throw new RuntimeError(`JS user function '${target.name}' not found`);
|
|
54897
|
+
}
|
|
54898
|
+
const ib = entry.builtin;
|
|
54899
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
54900
|
+
const argTypes = margs.map(inferJitType);
|
|
54901
|
+
const resolution = ib.resolve(argTypes, nargout);
|
|
54902
|
+
if (!resolution) {
|
|
54903
|
+
const typeNames = argTypes.map((t) => t.kind);
|
|
54904
|
+
throw new RuntimeError(
|
|
54905
|
+
`JS user function '${target.name}' does not support these argument types: (${typeNames.join(", ")})`
|
|
54906
|
+
);
|
|
54907
|
+
}
|
|
54908
|
+
const isVoid = resolution.outputTypes.length === 0;
|
|
54909
|
+
if (isVoid && nargout > 0) {
|
|
54910
|
+
throw new RuntimeError("Too many output arguments.");
|
|
54911
|
+
}
|
|
54912
|
+
return this.withFileContext(entry.fileName, void 0, void 0, () => {
|
|
54913
|
+
if (this.rt.profilingEnabled) {
|
|
54914
|
+
this.rt.profileEnter("jsUserFunction:interp:" + target.name);
|
|
54915
|
+
const result2 = resolution.apply(margs, nargout);
|
|
54916
|
+
this.rt.profileLeave();
|
|
54917
|
+
return isVoid ? void 0 : result2;
|
|
54918
|
+
}
|
|
54919
|
+
const result = resolution.apply(margs, nargout);
|
|
54920
|
+
return isVoid ? void 0 : result;
|
|
54921
|
+
});
|
|
54922
|
+
}
|
|
53064
54923
|
function interpretLocalFunction(target, args, nargout) {
|
|
53065
54924
|
const { source } = target;
|
|
53066
54925
|
if (source.from === "main") {
|
|
@@ -53925,6 +55784,7 @@ function extractClassInfo(classDef, qualifiedName, fileName, source) {
|
|
|
53925
55784
|
function createWorkspaceRegistry() {
|
|
53926
55785
|
return {
|
|
53927
55786
|
filesByFuncName: /* @__PURE__ */ new Map(),
|
|
55787
|
+
jsUserFunctionsByName: /* @__PURE__ */ new Map(),
|
|
53928
55788
|
fileContexts: /* @__PURE__ */ new Map(),
|
|
53929
55789
|
classesByName: /* @__PURE__ */ new Map(),
|
|
53930
55790
|
localClassesByName: /* @__PURE__ */ new Map(),
|
|
@@ -54118,6 +55978,7 @@ var LoweringContext = class _LoweringContext {
|
|
|
54118
55978
|
/** Clear workspace-level registrations so they can be rebuilt after addpath/rmpath. */
|
|
54119
55979
|
clearWorkspaceRegistrations() {
|
|
54120
55980
|
this.registry.filesByFuncName.clear();
|
|
55981
|
+
this.registry.jsUserFunctionsByName.clear();
|
|
54121
55982
|
this.registry.classesByName.clear();
|
|
54122
55983
|
this.registry.privateFilesByDir.clear();
|
|
54123
55984
|
this.registry.fileContexts.clear();
|
|
@@ -54125,6 +55986,14 @@ var LoweringContext = class _LoweringContext {
|
|
|
54125
55986
|
this.registry.externalAccessByFile.clear();
|
|
54126
55987
|
this.registry.functionIndex = null;
|
|
54127
55988
|
}
|
|
55989
|
+
/**
|
|
55990
|
+
* Register a JS user function (.numbl.js) in the workspace registry.
|
|
55991
|
+
* Uses first-wins semantics so search-path priority is honored.
|
|
55992
|
+
*/
|
|
55993
|
+
registerJsUserFunction(funcName, fileName, builtin) {
|
|
55994
|
+
if (this.registry.jsUserFunctionsByName.has(funcName)) return;
|
|
55995
|
+
this.registry.jsUserFunctionsByName.set(funcName, { fileName, builtin });
|
|
55996
|
+
}
|
|
54128
55997
|
// ── Private function management ──────────────────────────────────
|
|
54129
55998
|
/**
|
|
54130
55999
|
* Get the effective directory for this context's file, used for
|
|
@@ -54388,19 +56257,15 @@ var LoweringContext = class _LoweringContext {
|
|
|
54388
56257
|
* Should be called once after registerWorkspaceFiles() and registerLocalFunctionAST().
|
|
54389
56258
|
* Parses all workspace files eagerly to discover subfunctions.
|
|
54390
56259
|
*/
|
|
54391
|
-
buildFunctionIndex(
|
|
56260
|
+
buildFunctionIndex() {
|
|
54392
56261
|
const builtins = /* @__PURE__ */ new Set([
|
|
54393
56262
|
...getAllBuiltinNames(),
|
|
54394
56263
|
...getAllIBuiltinNames(),
|
|
54395
56264
|
...SPECIAL_BUILTIN_NAMES
|
|
54396
56265
|
]);
|
|
54397
|
-
const jsUserFunctions =
|
|
54398
|
-
|
|
54399
|
-
|
|
54400
|
-
builtins.delete(name);
|
|
54401
|
-
jsUserFunctions.add(name);
|
|
54402
|
-
}
|
|
54403
|
-
}
|
|
56266
|
+
const jsUserFunctions = new Set(
|
|
56267
|
+
this.registry.jsUserFunctionsByName.keys()
|
|
56268
|
+
);
|
|
54404
56269
|
const mainLocalFunctions = new Set(this.localFunctionASTs.keys());
|
|
54405
56270
|
const workspaceFunctions = new Set(this.registry.filesByFuncName.keys());
|
|
54406
56271
|
const workspaceClasses = /* @__PURE__ */ new Set([
|
|
@@ -54934,7 +56799,7 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
54934
56799
|
for (const f of workspaceFiles) {
|
|
54935
56800
|
if (f.name.endsWith(".m")) {
|
|
54936
56801
|
mWorkspaceFiles.push(f);
|
|
54937
|
-
} else if (f.name
|
|
56802
|
+
} else if (isNumblJsFile(f.name)) {
|
|
54938
56803
|
jsWorkspaceFiles.push(f);
|
|
54939
56804
|
} else if (f.name.endsWith(".wasm")) {
|
|
54940
56805
|
wasmWorkspaceFiles.push(f);
|
|
@@ -54958,6 +56823,8 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
54958
56823
|
for (const f of cwdFiles) {
|
|
54959
56824
|
if (f.name.endsWith(".m")) {
|
|
54960
56825
|
mWorkspaceFiles.push(f);
|
|
56826
|
+
} else if (isNumblJsFile(f.name)) {
|
|
56827
|
+
jsWorkspaceFiles.push(f);
|
|
54961
56828
|
}
|
|
54962
56829
|
}
|
|
54963
56830
|
}
|
|
@@ -54971,7 +56838,6 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
54971
56838
|
wasmWorkspaceFiles,
|
|
54972
56839
|
nativeBridge2
|
|
54973
56840
|
);
|
|
54974
|
-
const jsUserFunctionNames = jsUserFunctions.map((ib) => ib.name);
|
|
54975
56841
|
const stdlibShimNames = /* @__PURE__ */ new Set();
|
|
54976
56842
|
for (const f of stdlibFiles) {
|
|
54977
56843
|
mWorkspaceFiles.push(f);
|
|
@@ -55018,19 +56884,21 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
55018
56884
|
if (mWorkspaceFiles.length > 0) {
|
|
55019
56885
|
ctx.registerWorkspaceFiles(mWorkspaceFiles);
|
|
55020
56886
|
}
|
|
55021
|
-
const
|
|
56887
|
+
for (const entry of jsUserFunctions) {
|
|
56888
|
+
ctx.registerJsUserFunction(entry.name, entry.fileName, entry.builtin);
|
|
56889
|
+
}
|
|
56890
|
+
const functionIndex = ctx.buildFunctionIndex();
|
|
55022
56891
|
const savedSpecialBuiltins = /* @__PURE__ */ new Map();
|
|
55023
56892
|
for (const name of SPECIAL_BUILTIN_NAMES) {
|
|
55024
56893
|
const existing = getIBuiltin(name);
|
|
55025
56894
|
if (existing) savedSpecialBuiltins.set(name, existing);
|
|
55026
56895
|
}
|
|
55027
56896
|
const rt = new Runtime(options, options.initialVariableValues);
|
|
55028
|
-
const
|
|
55029
|
-
for (const
|
|
55030
|
-
|
|
55031
|
-
if (orig) savedIBuiltins.set(ib.name, orig);
|
|
55032
|
-
registerDynamicIBuiltin(ib);
|
|
56897
|
+
const jsBuiltinMap = /* @__PURE__ */ new Map();
|
|
56898
|
+
for (const [n, e] of ctx.registry.jsUserFunctionsByName.entries()) {
|
|
56899
|
+
jsBuiltinMap.set(n, e.builtin);
|
|
55033
56900
|
}
|
|
56901
|
+
rt.jitHelpers = buildPerRuntimeJitHelpers(jsBuiltinMap);
|
|
55034
56902
|
if (options.customBuiltins) {
|
|
55035
56903
|
Object.assign(rt.builtins, options.customBuiltins);
|
|
55036
56904
|
Object.assign(rt.customBuiltins, options.customBuiltins);
|
|
@@ -55065,6 +56933,14 @@ ${jsCode}`
|
|
|
55065
56933
|
interpreter.installRuntimeCallbacks();
|
|
55066
56934
|
rt.searchPaths = ctx.registry.searchPaths;
|
|
55067
56935
|
let pathsModified = false;
|
|
56936
|
+
const loadedJsUserFunctions = [...jsUserFunctions];
|
|
56937
|
+
const rebuildJitHelpers = () => {
|
|
56938
|
+
const map = /* @__PURE__ */ new Map();
|
|
56939
|
+
for (const [n, e] of ctx.registry.jsUserFunctionsByName.entries()) {
|
|
56940
|
+
map.set(n, e.builtin);
|
|
56941
|
+
}
|
|
56942
|
+
rt.jitHelpers = buildPerRuntimeJitHelpers(map);
|
|
56943
|
+
};
|
|
55068
56944
|
const rebuildWorkspace = () => {
|
|
55069
56945
|
const paths = ctx.registry.searchPaths;
|
|
55070
56946
|
const priorityOf = (name) => {
|
|
@@ -55083,11 +56959,18 @@ ${jsCode}`
|
|
|
55083
56959
|
return bestIdx;
|
|
55084
56960
|
};
|
|
55085
56961
|
mWorkspaceFiles.sort((a, b) => priorityOf(a.name) - priorityOf(b.name));
|
|
56962
|
+
loadedJsUserFunctions.sort(
|
|
56963
|
+
(a, b) => priorityOf(a.fileName) - priorityOf(b.fileName)
|
|
56964
|
+
);
|
|
55086
56965
|
ctx.clearWorkspaceRegistrations();
|
|
55087
56966
|
ctx.registerWorkspaceFiles(mWorkspaceFiles);
|
|
55088
|
-
const
|
|
56967
|
+
for (const entry of loadedJsUserFunctions) {
|
|
56968
|
+
ctx.registerJsUserFunction(entry.name, entry.fileName, entry.builtin);
|
|
56969
|
+
}
|
|
56970
|
+
const newIndex = ctx.buildFunctionIndex();
|
|
55089
56971
|
interpreter.functionIndex = newIndex;
|
|
55090
56972
|
interpreter.clearAllCaches();
|
|
56973
|
+
rebuildJitHelpers();
|
|
55091
56974
|
pathsModified = true;
|
|
55092
56975
|
};
|
|
55093
56976
|
rt.onPathChange = (action, dir, position) => {
|
|
@@ -55126,24 +57009,32 @@ ${jsCode}`
|
|
|
55126
57009
|
}
|
|
55127
57010
|
interpreter.fileSources.set(f.name, f.source);
|
|
55128
57011
|
mWorkspaceFiles.push(f);
|
|
55129
|
-
} else if (f.name
|
|
57012
|
+
} else if (isNumblJsFile(f.name)) {
|
|
55130
57013
|
newJsFiles.push(f);
|
|
57014
|
+
if (!jsWorkspaceFiles.some((e) => e.name === f.name)) {
|
|
57015
|
+
jsWorkspaceFiles.push(f);
|
|
57016
|
+
}
|
|
55131
57017
|
} else if (f.name.endsWith(".wasm")) {
|
|
55132
57018
|
newWasmFiles.push(f);
|
|
57019
|
+
if (!wasmWorkspaceFiles.some((e) => e.name === f.name)) {
|
|
57020
|
+
wasmWorkspaceFiles.push(f);
|
|
57021
|
+
}
|
|
55133
57022
|
}
|
|
55134
57023
|
}
|
|
55135
57024
|
if (newJsFiles.length > 0) {
|
|
55136
|
-
const
|
|
57025
|
+
const loaded = loadJsUserFunctions(
|
|
55137
57026
|
newJsFiles,
|
|
55138
57027
|
newWasmFiles,
|
|
55139
57028
|
nativeBridge2
|
|
55140
57029
|
);
|
|
55141
|
-
for (const
|
|
55142
|
-
const
|
|
55143
|
-
|
|
55144
|
-
|
|
55145
|
-
if (
|
|
55146
|
-
|
|
57030
|
+
for (const entry of loaded) {
|
|
57031
|
+
const existingIdx = loadedJsUserFunctions.findIndex(
|
|
57032
|
+
(e) => e.fileName === entry.fileName
|
|
57033
|
+
);
|
|
57034
|
+
if (existingIdx >= 0) {
|
|
57035
|
+
loadedJsUserFunctions[existingIdx] = entry;
|
|
57036
|
+
} else {
|
|
57037
|
+
loadedJsUserFunctions.push(entry);
|
|
55147
57038
|
}
|
|
55148
57039
|
}
|
|
55149
57040
|
}
|
|
@@ -55161,6 +57052,21 @@ ${jsCode}`
|
|
|
55161
57052
|
mWorkspaceFiles.splice(i, 1);
|
|
55162
57053
|
}
|
|
55163
57054
|
}
|
|
57055
|
+
for (let i = loadedJsUserFunctions.length - 1; i >= 0; i--) {
|
|
57056
|
+
if (loadedJsUserFunctions[i].fileName.startsWith(prefix)) {
|
|
57057
|
+
loadedJsUserFunctions.splice(i, 1);
|
|
57058
|
+
}
|
|
57059
|
+
}
|
|
57060
|
+
for (let i = jsWorkspaceFiles.length - 1; i >= 0; i--) {
|
|
57061
|
+
if (jsWorkspaceFiles[i].name.startsWith(prefix)) {
|
|
57062
|
+
jsWorkspaceFiles.splice(i, 1);
|
|
57063
|
+
}
|
|
57064
|
+
}
|
|
57065
|
+
for (let i = wasmWorkspaceFiles.length - 1; i >= 0; i--) {
|
|
57066
|
+
if (wasmWorkspaceFiles[i].name.startsWith(prefix)) {
|
|
57067
|
+
wasmWorkspaceFiles.splice(i, 1);
|
|
57068
|
+
}
|
|
57069
|
+
}
|
|
55164
57070
|
}
|
|
55165
57071
|
rebuildWorkspace();
|
|
55166
57072
|
};
|
|
@@ -55188,6 +57094,24 @@ ${jsCode}`
|
|
|
55188
57094
|
mWorkspaceFiles.splice(i, 1);
|
|
55189
57095
|
}
|
|
55190
57096
|
}
|
|
57097
|
+
for (let i = loadedJsUserFunctions.length - 1; i >= 0; i--) {
|
|
57098
|
+
const fname = loadedJsUserFunctions[i].fileName;
|
|
57099
|
+
if ((fname === implicitCwdPath || fname.startsWith(oldPrefix)) && !fileBelongsToDeeperPath(fname)) {
|
|
57100
|
+
loadedJsUserFunctions.splice(i, 1);
|
|
57101
|
+
}
|
|
57102
|
+
}
|
|
57103
|
+
for (let i = jsWorkspaceFiles.length - 1; i >= 0; i--) {
|
|
57104
|
+
const fname = jsWorkspaceFiles[i].name;
|
|
57105
|
+
if ((fname === implicitCwdPath || fname.startsWith(oldPrefix)) && !fileBelongsToDeeperPath(fname)) {
|
|
57106
|
+
jsWorkspaceFiles.splice(i, 1);
|
|
57107
|
+
}
|
|
57108
|
+
}
|
|
57109
|
+
for (let i = wasmWorkspaceFiles.length - 1; i >= 0; i--) {
|
|
57110
|
+
const fname = wasmWorkspaceFiles[i].name;
|
|
57111
|
+
if ((fname === implicitCwdPath || fname.startsWith(oldPrefix)) && !fileBelongsToDeeperPath(fname)) {
|
|
57112
|
+
wasmWorkspaceFiles.splice(i, 1);
|
|
57113
|
+
}
|
|
57114
|
+
}
|
|
55191
57115
|
const oldIdx = ctx.registry.searchPaths.indexOf(implicitCwdPath);
|
|
55192
57116
|
if (oldIdx >= 0) ctx.registry.searchPaths.splice(oldIdx, 1);
|
|
55193
57117
|
implicitCwdPath = null;
|
|
@@ -55204,6 +57128,8 @@ ${jsCode}`
|
|
|
55204
57128
|
newFiles = fileIO.scanDirectory(absNewCwd);
|
|
55205
57129
|
} catch {
|
|
55206
57130
|
}
|
|
57131
|
+
const newJsFiles = [];
|
|
57132
|
+
const newWasmFiles = [];
|
|
55207
57133
|
for (const f of newFiles) {
|
|
55208
57134
|
if (f.name.endsWith(".m") && !ctx.fileASTCache.has(f.name)) {
|
|
55209
57135
|
try {
|
|
@@ -55220,6 +57146,33 @@ ${jsCode}`
|
|
|
55220
57146
|
}
|
|
55221
57147
|
interpreter.fileSources.set(f.name, f.source);
|
|
55222
57148
|
mWorkspaceFiles.push(f);
|
|
57149
|
+
} else if (isNumblJsFile(f.name)) {
|
|
57150
|
+
newJsFiles.push(f);
|
|
57151
|
+
if (!jsWorkspaceFiles.some((e) => e.name === f.name)) {
|
|
57152
|
+
jsWorkspaceFiles.push(f);
|
|
57153
|
+
}
|
|
57154
|
+
} else if (f.name.endsWith(".wasm")) {
|
|
57155
|
+
newWasmFiles.push(f);
|
|
57156
|
+
if (!wasmWorkspaceFiles.some((e) => e.name === f.name)) {
|
|
57157
|
+
wasmWorkspaceFiles.push(f);
|
|
57158
|
+
}
|
|
57159
|
+
}
|
|
57160
|
+
}
|
|
57161
|
+
if (newJsFiles.length > 0) {
|
|
57162
|
+
const loaded = loadJsUserFunctions(
|
|
57163
|
+
newJsFiles,
|
|
57164
|
+
newWasmFiles,
|
|
57165
|
+
nativeBridge2
|
|
57166
|
+
);
|
|
57167
|
+
for (const entry of loaded) {
|
|
57168
|
+
const existingIdx = loadedJsUserFunctions.findIndex(
|
|
57169
|
+
(e) => e.fileName === entry.fileName
|
|
57170
|
+
);
|
|
57171
|
+
if (existingIdx >= 0) {
|
|
57172
|
+
loadedJsUserFunctions[existingIdx] = entry;
|
|
57173
|
+
} else {
|
|
57174
|
+
loadedJsUserFunctions.push(entry);
|
|
57175
|
+
}
|
|
55223
57176
|
}
|
|
55224
57177
|
}
|
|
55225
57178
|
}
|
|
@@ -55229,9 +57182,11 @@ ${jsCode}`
|
|
|
55229
57182
|
const nestedSearchPaths = ctx.registry.searchPaths.filter(
|
|
55230
57183
|
(p2) => p2 !== SHIM_SEARCH_PATH && p2 !== implicitCwdPath
|
|
55231
57184
|
);
|
|
55232
|
-
const nestedWorkspaceFiles =
|
|
55233
|
-
(f) => !stdlibShimNames.has(f.name)
|
|
55234
|
-
|
|
57185
|
+
const nestedWorkspaceFiles = [
|
|
57186
|
+
...mWorkspaceFiles.filter((f) => !stdlibShimNames.has(f.name)),
|
|
57187
|
+
...jsWorkspaceFiles,
|
|
57188
|
+
...wasmWorkspaceFiles
|
|
57189
|
+
];
|
|
55235
57190
|
const evalResult = executeCode(
|
|
55236
57191
|
code,
|
|
55237
57192
|
{
|
|
@@ -55277,16 +57232,19 @@ ${jitSections.join("\n\n")}` : "// No JS generated",
|
|
|
55277
57232
|
executionTimeMs,
|
|
55278
57233
|
jitCompileTimeMs: rt.getJitCompileTimeMs(),
|
|
55279
57234
|
builtins: rt.getBuiltinProfile(),
|
|
55280
|
-
dispatches: rt.getDispatchProfile()
|
|
57235
|
+
dispatches: rt.getDispatchProfile(),
|
|
57236
|
+
hotLoops: [...rt.hotLoops.values()]
|
|
55281
57237
|
};
|
|
55282
57238
|
}
|
|
55283
57239
|
if (pathsModified) {
|
|
55284
57240
|
result.searchPaths = ctx.registry.searchPaths.filter(
|
|
55285
57241
|
(p2) => p2 !== SHIM_SEARCH_PATH && p2 !== implicitCwdPath
|
|
55286
57242
|
);
|
|
55287
|
-
result.workspaceFiles =
|
|
55288
|
-
(f) => !stdlibShimNames.has(f.name)
|
|
55289
|
-
|
|
57243
|
+
result.workspaceFiles = [
|
|
57244
|
+
...mWorkspaceFiles.filter((f) => !stdlibShimNames.has(f.name)),
|
|
57245
|
+
...jsWorkspaceFiles,
|
|
57246
|
+
...wasmWorkspaceFiles
|
|
57247
|
+
];
|
|
55290
57248
|
}
|
|
55291
57249
|
result.implicitCwdPath = implicitCwdPath;
|
|
55292
57250
|
return result;
|
|
@@ -55316,14 +57274,6 @@ ${jitSections.join("\n\n")}` : "// No JS generated";
|
|
|
55316
57274
|
jitHelpers._profileEnter = Function.prototype;
|
|
55317
57275
|
jitHelpers._profileLeave = Function.prototype;
|
|
55318
57276
|
}
|
|
55319
|
-
for (const ib of jsUserFunctions) {
|
|
55320
|
-
const orig = savedIBuiltins.get(ib.name);
|
|
55321
|
-
if (orig) {
|
|
55322
|
-
registerDynamicIBuiltin(orig);
|
|
55323
|
-
} else {
|
|
55324
|
-
unregisterIBuiltin(ib.name);
|
|
55325
|
-
}
|
|
55326
|
-
}
|
|
55327
57277
|
for (const [, ib] of savedSpecialBuiltins) {
|
|
55328
57278
|
registerDynamicIBuiltin(ib);
|
|
55329
57279
|
}
|
|
@@ -55375,7 +57325,7 @@ function scanMFiles(dirPath, excludeFile) {
|
|
|
55375
57325
|
if (entry.startsWith("@") || entry.startsWith("+") || entry === "private") {
|
|
55376
57326
|
files.push(...scanMFiles(fullPath, excludeFile));
|
|
55377
57327
|
}
|
|
55378
|
-
} else if (stat.isFile() && (entry.endsWith(".m") || entry.endsWith(".js"))) {
|
|
57328
|
+
} else if (stat.isFile() && (entry.endsWith(".m") || entry.endsWith(".numbl.js"))) {
|
|
55379
57329
|
const source = readFileSync2(fullPath, "utf-8");
|
|
55380
57330
|
files.push({
|
|
55381
57331
|
name: fullPath,
|
|
@@ -55957,8 +57907,8 @@ var NodeFileIOAdapter = class {
|
|
|
55957
57907
|
} catch {
|
|
55958
57908
|
}
|
|
55959
57909
|
}
|
|
55960
|
-
for (const
|
|
55961
|
-
walkDir(join3(dir,
|
|
57910
|
+
for (const sub2 of subdirs) {
|
|
57911
|
+
walkDir(join3(dir, sub2));
|
|
55962
57912
|
}
|
|
55963
57913
|
};
|
|
55964
57914
|
walkDir(absBase);
|
|
@@ -56944,7 +58894,8 @@ async function executeWithOptions(code, mainFileName, workspaceFiles, opts, sear
|
|
|
56944
58894
|
executionTimeMs: pd.executionTimeMs,
|
|
56945
58895
|
jitCompileTimeMs: pd.jitCompileTimeMs,
|
|
56946
58896
|
builtins,
|
|
56947
|
-
dispatches
|
|
58897
|
+
dispatches,
|
|
58898
|
+
hotLoops: pd.hotLoops ?? []
|
|
56948
58899
|
};
|
|
56949
58900
|
writeFileSync3(opts.profileOutput, JSON.stringify(profile, null, 2) + "\n");
|
|
56950
58901
|
console.error(`Profile written to ${opts.profileOutput}`);
|
|
@@ -57302,6 +59253,20 @@ function cmdShowProfile(args) {
|
|
|
57302
59253
|
} else {
|
|
57303
59254
|
console.log("\nNo builtin functions were called.");
|
|
57304
59255
|
}
|
|
59256
|
+
const hotLoops = data.hotLoops ?? [];
|
|
59257
|
+
if (hotLoops.length > 0) {
|
|
59258
|
+
hotLoops.sort((a, b) => b.totalTimeMs - a.totalTimeMs);
|
|
59259
|
+
const locW = Math.max(20, ...hotLoops.map((l) => `${l.file}:${l.line}`.length)) + 2;
|
|
59260
|
+
const header = "Location".padEnd(locW) + pad("Kind", 8) + pad("Calls", 8) + pad("Max Iters", 12) + pad("Total (ms)", 13);
|
|
59261
|
+
console.log("\nInterpreted loops (>1000 iterations):");
|
|
59262
|
+
console.log(header);
|
|
59263
|
+
console.log("\u2500".repeat(header.length));
|
|
59264
|
+
for (const l of hotLoops) {
|
|
59265
|
+
const loc = `${l.file}:${l.line}`;
|
|
59266
|
+
const line = loc.padEnd(locW) + pad(l.kind, 8) + pad(String(l.callCount ?? 1), 8) + pad(String(l.iterations), 12) + pad(fmt(l.totalTimeMs ?? 0, 2), 13);
|
|
59267
|
+
console.log(line);
|
|
59268
|
+
}
|
|
59269
|
+
}
|
|
57305
59270
|
}
|
|
57306
59271
|
async function main() {
|
|
57307
59272
|
const args = process.argv.slice(2);
|