numbl 0.4.1 → 0.4.3
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/dist-cli/cli.js +1225 -49
- package/dist-lib/graphics/axisLimits.d.ts +23 -0
- package/dist-lib/graphics/figuresReducer.d.ts +73 -0
- package/dist-lib/graphics/types.d.ts +17 -0
- package/dist-lib/lib.js +1224 -48
- package/dist-lib/numbl-core/helpers/effectively-real.d.ts +25 -0
- package/dist-lib/numbl-core/helpers/eigs-select.d.ts +25 -0
- package/dist-lib/numbl-core/jit/builtins/runtime/snippets.gen.d.ts +1 -0
- package/dist-lib/numbl-core/jit/builtins/runtime/tensor_ops/tensor_imag_all_zero.d.ts +1 -0
- package/dist-lib/numbl-core/runtime/axisCommand.d.ts +34 -0
- package/dist-lib/numbl-core/runtime/runtime.d.ts +5 -0
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/dist-plot-viewer/assets/index-ClpZQuMR.js +4426 -0
- package/dist-plot-viewer/index.html +1 -1
- package/dist-site-viewer/assets/index-CgKjTQT7.js +4748 -0
- package/dist-site-viewer/assets/{numbl-worker-CkoM4MUa.js → numbl-worker-DarsHbBe.js} +297 -140
- package/dist-site-viewer/index.html +1 -1
- package/package.json +1 -1
- package/dist-plot-viewer/assets/index-DfxsWeyf.js +0 -4426
- package/dist-site-viewer/assets/index-C5c2lKAx.js +0 -4748
package/dist-lib/lib.js
CHANGED
|
@@ -19452,9 +19452,9 @@ function airyAllComplex(zr, zi) {
|
|
|
19452
19452
|
sfpi += m3k * tfi;
|
|
19453
19453
|
sgpr += (m3k + 1) * tgr;
|
|
19454
19454
|
sgpi += (m3k + 1) * tgi;
|
|
19455
|
-
const
|
|
19455
|
+
const mag2 = Math.abs(tfr) + Math.abs(tfi) + Math.abs(tgr) + Math.abs(tgi);
|
|
19456
19456
|
const ref = Math.abs(sfr) + Math.abs(sfi) + Math.abs(sgr) + Math.abs(sgi) + 1e-300;
|
|
19457
|
-
if (
|
|
19457
|
+
if (mag2 < 1e-16 * ref) break;
|
|
19458
19458
|
}
|
|
19459
19459
|
const gr = zr * sgr - zi * sgi;
|
|
19460
19460
|
const gi = zr * sgi + zi * sgr;
|
|
@@ -22329,8 +22329,8 @@ function sinpi(x) {
|
|
|
22329
22329
|
return Math.sin(Math.PI * x);
|
|
22330
22330
|
}
|
|
22331
22331
|
function negRealPow(negBase, exponent) {
|
|
22332
|
-
const
|
|
22333
|
-
return { re:
|
|
22332
|
+
const mag2 = Math.pow(-negBase, exponent);
|
|
22333
|
+
return { re: mag2 * cospi(exponent), im: mag2 * sinpi(exponent) };
|
|
22334
22334
|
}
|
|
22335
22335
|
function mPow(a, b) {
|
|
22336
22336
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -29285,9 +29285,9 @@ function complexSqrt(re, im) {
|
|
|
29285
29285
|
if (re >= 0) return { re: Math.sqrt(re), im: 0 };
|
|
29286
29286
|
return { re: 0, im: Math.sqrt(-re) };
|
|
29287
29287
|
}
|
|
29288
|
-
const
|
|
29289
|
-
if (
|
|
29290
|
-
const r = Math.sqrt(
|
|
29288
|
+
const mag2 = Math.hypot(re, im);
|
|
29289
|
+
if (mag2 === 0) return { re: 0, im: 0 };
|
|
29290
|
+
const r = Math.sqrt(mag2);
|
|
29291
29291
|
const angle2 = Math.atan2(im, re) / 2;
|
|
29292
29292
|
return { re: r * Math.cos(angle2), im: r * Math.sin(angle2) };
|
|
29293
29293
|
}
|
|
@@ -29335,9 +29335,9 @@ defineBuiltin({
|
|
|
29335
29335
|
)
|
|
29336
29336
|
});
|
|
29337
29337
|
registerUnary("sign", Math.sign, (re, im) => {
|
|
29338
|
-
const
|
|
29339
|
-
if (
|
|
29340
|
-
return { re: re /
|
|
29338
|
+
const mag2 = Math.hypot(re, im);
|
|
29339
|
+
if (mag2 === 0) return { re: 0, im: 0 };
|
|
29340
|
+
return { re: re / mag2, im: im / mag2 };
|
|
29341
29341
|
});
|
|
29342
29342
|
function registerRounding(name, fn) {
|
|
29343
29343
|
defineBuiltin({
|
|
@@ -30210,6 +30210,27 @@ function toNumArray(v, name) {
|
|
|
30210
30210
|
throw new RuntimeError(`${name}: arguments must be numeric arrays`);
|
|
30211
30211
|
}
|
|
30212
30212
|
|
|
30213
|
+
// src/numbl-core/helpers/effectively-real.ts
|
|
30214
|
+
function imagAllZero(imag2) {
|
|
30215
|
+
if (!imag2) return true;
|
|
30216
|
+
for (let i = 0; i < imag2.length; i++) {
|
|
30217
|
+
if (imag2[i] !== 0) return false;
|
|
30218
|
+
}
|
|
30219
|
+
return true;
|
|
30220
|
+
}
|
|
30221
|
+
function stripZeroImagTensor(t) {
|
|
30222
|
+
if (t.imag && imagAllZero(t.imag)) {
|
|
30223
|
+
const out = RTV.tensor(t.data, t.shape);
|
|
30224
|
+
if (t._isLogical) out._isLogical = true;
|
|
30225
|
+
return out;
|
|
30226
|
+
}
|
|
30227
|
+
return t;
|
|
30228
|
+
}
|
|
30229
|
+
function stripZeroImagValue(v) {
|
|
30230
|
+
if (isRuntimeTensor(v)) return stripZeroImagTensor(v);
|
|
30231
|
+
return v;
|
|
30232
|
+
}
|
|
30233
|
+
|
|
30213
30234
|
// src/numbl-core/helpers/reduction/min-max.ts
|
|
30214
30235
|
function minMaxScan(data, imag2, indices, initial, isBetter, complexIsBetter) {
|
|
30215
30236
|
let mRe = initial, mIm = 0, mIdx = 0;
|
|
@@ -30394,6 +30415,7 @@ function minMaxImpl(name, args, nargout, initial, isBetter, twoArgFn) {
|
|
|
30394
30415
|
return isBetter(Math.atan2(imA, reA), Math.atan2(imB, reB));
|
|
30395
30416
|
};
|
|
30396
30417
|
args = args.map((a) => isRuntimeSparseMatrix(a) ? sparseToDense(a) : a);
|
|
30418
|
+
args = args.map(stripZeroImagValue);
|
|
30397
30419
|
if (args.length === 1) {
|
|
30398
30420
|
const v = args[0];
|
|
30399
30421
|
if (isRuntimeNumber(v) || isRuntimeLogical(v) || isRuntimeComplexNumber(v)) {
|
|
@@ -30881,8 +30903,8 @@ defineBuiltin({
|
|
|
30881
30903
|
if (typeof v === "number") return true;
|
|
30882
30904
|
if (typeof v === "boolean") return true;
|
|
30883
30905
|
if (isRuntimeComplexNumber(v)) return v.im === 0;
|
|
30884
|
-
if (isRuntimeTensor(v)) return
|
|
30885
|
-
if (isRuntimeSparseMatrix(v)) return !v.pi;
|
|
30906
|
+
if (isRuntimeTensor(v)) return imagAllZero(v.imag);
|
|
30907
|
+
if (isRuntimeSparseMatrix(v)) return !v.pi || imagAllZero(v.pi);
|
|
30886
30908
|
return true;
|
|
30887
30909
|
}
|
|
30888
30910
|
}
|
|
@@ -34009,7 +34031,7 @@ defineBuiltin({
|
|
|
34009
34031
|
return v;
|
|
34010
34032
|
}
|
|
34011
34033
|
if (isRuntimeTensor(v)) {
|
|
34012
|
-
return sortTensor(v, dim, descend, nargout);
|
|
34034
|
+
return sortTensor(stripZeroImagTensor(v), dim, descend, nargout);
|
|
34013
34035
|
}
|
|
34014
34036
|
if (isRuntimeCell(v)) {
|
|
34015
34037
|
return sortCell(v, descend, nargout);
|
|
@@ -34048,10 +34070,10 @@ function sortTensor(v, dim, descend, nargout) {
|
|
|
34048
34070
|
const dimSize = shape[dimIdx];
|
|
34049
34071
|
let cmpFlatIdx;
|
|
34050
34072
|
if (im && !im.every((x) => x === 0)) {
|
|
34051
|
-
const
|
|
34073
|
+
const mag2 = (i) => Math.sqrt(re[i] * re[i] + im[i] * im[i]);
|
|
34052
34074
|
const phase = (i) => Math.atan2(im[i], re[i]);
|
|
34053
34075
|
cmpFlatIdx = (a, b) => {
|
|
34054
|
-
const diff2 =
|
|
34076
|
+
const diff2 = mag2(a) - mag2(b);
|
|
34055
34077
|
if (diff2 !== 0) return descend ? -diff2 : diff2;
|
|
34056
34078
|
const pDiff = phase(a) - phase(b);
|
|
34057
34079
|
return descend ? -pDiff : pDiff;
|
|
@@ -35479,9 +35501,9 @@ function invComplexJS(dataRe, dataIm, n) {
|
|
|
35479
35501
|
let maxRow = col;
|
|
35480
35502
|
let maxMag = augRe[col * 2 * n + col] ** 2 + augIm[col * 2 * n + col] ** 2;
|
|
35481
35503
|
for (let row = col + 1; row < n; row++) {
|
|
35482
|
-
const
|
|
35483
|
-
if (
|
|
35484
|
-
maxMag =
|
|
35504
|
+
const mag2 = augRe[row * 2 * n + col] ** 2 + augIm[row * 2 * n + col] ** 2;
|
|
35505
|
+
if (mag2 > maxMag) {
|
|
35506
|
+
maxMag = mag2;
|
|
35485
35507
|
maxRow = row;
|
|
35486
35508
|
}
|
|
35487
35509
|
}
|
|
@@ -35526,6 +35548,88 @@ function invComplexJS(dataRe, dataIm, n) {
|
|
|
35526
35548
|
}
|
|
35527
35549
|
return { re: resultRe, im: resultIm };
|
|
35528
35550
|
}
|
|
35551
|
+
defineBuiltin({
|
|
35552
|
+
name: "expm",
|
|
35553
|
+
cases: [
|
|
35554
|
+
{
|
|
35555
|
+
match: (argTypes, nargout) => {
|
|
35556
|
+
if (argTypes.length !== 1 || nargout > 1) return null;
|
|
35557
|
+
if (!isNumericJitType(argTypes[0])) return null;
|
|
35558
|
+
const a = argTypes[0];
|
|
35559
|
+
if (a.kind === "number" || a.kind === "boolean") return [NUM];
|
|
35560
|
+
if (a.kind === "complex_or_number") return [COMPLEX_OR_NUM];
|
|
35561
|
+
if (a.kind === "tensor")
|
|
35562
|
+
return [{ kind: "tensor", isComplex: a.isComplex }];
|
|
35563
|
+
return null;
|
|
35564
|
+
},
|
|
35565
|
+
apply: (args) => expmApply(args)
|
|
35566
|
+
}
|
|
35567
|
+
]
|
|
35568
|
+
});
|
|
35569
|
+
function expmApply(args) {
|
|
35570
|
+
if (args.length !== 1) throw new RuntimeError("expm requires 1 argument");
|
|
35571
|
+
const A = args[0];
|
|
35572
|
+
if (isRuntimeNumber(A)) return RTV.num(Math.exp(A));
|
|
35573
|
+
if (isRuntimeComplexNumber(A)) {
|
|
35574
|
+
const ex = Math.exp(A.re);
|
|
35575
|
+
return RTV.complex(ex * Math.cos(A.im), ex * Math.sin(A.im));
|
|
35576
|
+
}
|
|
35577
|
+
if (!isRuntimeTensor(A))
|
|
35578
|
+
throw new RuntimeError("expm: argument must be a numeric matrix");
|
|
35579
|
+
const [m, n] = tensorSize2D(A);
|
|
35580
|
+
if (m !== n) throw new RuntimeError("expm: input must be a square matrix");
|
|
35581
|
+
if (n === 0) return A;
|
|
35582
|
+
if (n === 1) {
|
|
35583
|
+
const ex = Math.exp(A.data[0]);
|
|
35584
|
+
if (A.imag)
|
|
35585
|
+
return RTV.tensor(
|
|
35586
|
+
Float64Array.of(ex * Math.cos(A.imag[0])),
|
|
35587
|
+
[1, 1],
|
|
35588
|
+
Float64Array.of(ex * Math.sin(A.imag[0]))
|
|
35589
|
+
);
|
|
35590
|
+
return RTV.tensor(Float64Array.of(ex), [1, 1]);
|
|
35591
|
+
}
|
|
35592
|
+
let s = 0;
|
|
35593
|
+
for (let scaled = matrixOneNorm(A, n); scaled > 0.5; scaled /= 2) s++;
|
|
35594
|
+
const As = mMul(A, RTV.num(Math.pow(2, -s)));
|
|
35595
|
+
const q = 6;
|
|
35596
|
+
const I = identityTensor(n);
|
|
35597
|
+
let c = 0.5;
|
|
35598
|
+
let E = mAdd(I, mMul(As, RTV.num(c)));
|
|
35599
|
+
let D = mSub(I, mMul(As, RTV.num(c)));
|
|
35600
|
+
let X = As;
|
|
35601
|
+
let plus2 = true;
|
|
35602
|
+
for (let k = 2; k <= q; k++) {
|
|
35603
|
+
c = c * (q - k + 1) / (k * (2 * q - k + 1));
|
|
35604
|
+
X = mMul(As, X);
|
|
35605
|
+
const cX = mMul(X, RTV.num(c));
|
|
35606
|
+
E = mAdd(E, cX);
|
|
35607
|
+
D = plus2 ? mAdd(D, cX) : mSub(D, cX);
|
|
35608
|
+
plus2 = !plus2;
|
|
35609
|
+
}
|
|
35610
|
+
let R = mLeftDiv(D, E);
|
|
35611
|
+
for (let i = 0; i < s; i++) R = mMul(R, R);
|
|
35612
|
+
return R;
|
|
35613
|
+
}
|
|
35614
|
+
function matrixOneNorm(A, n) {
|
|
35615
|
+
const re = A.data;
|
|
35616
|
+
const im = A.imag;
|
|
35617
|
+
let maxSum = 0;
|
|
35618
|
+
for (let j = 0; j < n; j++) {
|
|
35619
|
+
let colSum = 0;
|
|
35620
|
+
for (let i = 0; i < n; i++) {
|
|
35621
|
+
const idx = i + j * n;
|
|
35622
|
+
colSum += im ? Math.hypot(re[idx], im[idx]) : Math.abs(re[idx]);
|
|
35623
|
+
}
|
|
35624
|
+
if (colSum > maxSum) maxSum = colSum;
|
|
35625
|
+
}
|
|
35626
|
+
return maxSum;
|
|
35627
|
+
}
|
|
35628
|
+
function identityTensor(n) {
|
|
35629
|
+
const data = allocFloat64Array(n * n);
|
|
35630
|
+
for (let i = 0; i < n; i++) data[i + i * n] = 1;
|
|
35631
|
+
return RTV.tensor(data, [n, n]);
|
|
35632
|
+
}
|
|
35529
35633
|
registerIBuiltin({
|
|
35530
35634
|
name: "svd",
|
|
35531
35635
|
resolve: (argTypes, nargout) => {
|
|
@@ -37052,8 +37156,8 @@ function isFiberConjugateSymmetric(re, im) {
|
|
|
37052
37156
|
if (N <= 1) return Math.abs(im[0]) < 1e-14;
|
|
37053
37157
|
let maxMag = 0;
|
|
37054
37158
|
for (let i = 0; i < N; i++) {
|
|
37055
|
-
const
|
|
37056
|
-
if (
|
|
37159
|
+
const mag2 = Math.abs(re[i]) + Math.abs(im[i]);
|
|
37160
|
+
if (mag2 > maxMag) maxMag = mag2;
|
|
37057
37161
|
}
|
|
37058
37162
|
const tol = Math.max(1e-14, maxMag * 1e-12);
|
|
37059
37163
|
if (Math.abs(im[0]) > tol) return false;
|
|
@@ -45623,6 +45727,10 @@ var H = {
|
|
|
45623
45727
|
signatures: ["B = inv(A)"],
|
|
45624
45728
|
description: "Matrix inverse."
|
|
45625
45729
|
},
|
|
45730
|
+
expm: {
|
|
45731
|
+
signatures: ["Y = expm(X)"],
|
|
45732
|
+
description: "Matrix exponential of square matrix X (scaling-and-squaring Pad\xE9). Use exp for the element-wise exponential."
|
|
45733
|
+
},
|
|
45626
45734
|
trace: {
|
|
45627
45735
|
signatures: ["T = trace(A)"],
|
|
45628
45736
|
description: "Sum of diagonal elements."
|
|
@@ -45631,6 +45739,17 @@ var H = {
|
|
|
45631
45739
|
signatures: ["E = eig(A)", "[V, D] = eig(A)", "[V, D, W] = eig(A)"],
|
|
45632
45740
|
description: "Eigenvalues and eigenvectors of square matrix. With three outputs, W contains left eigenvectors."
|
|
45633
45741
|
},
|
|
45742
|
+
eigs: {
|
|
45743
|
+
signatures: [
|
|
45744
|
+
"d = eigs(A)",
|
|
45745
|
+
"d = eigs(A, k)",
|
|
45746
|
+
"d = eigs(A, k, sigma)",
|
|
45747
|
+
"d = eigs(A, B, ...)",
|
|
45748
|
+
"d = eigs(Afun, n, ...)",
|
|
45749
|
+
"[V, D, flag] = eigs(...)"
|
|
45750
|
+
],
|
|
45751
|
+
description: "Subset of k eigenvalues/eigenvectors (default 6). sigma selects which: 'largestabs' (default), 'smallestabs', 'largestreal', 'smallestreal', 'bothendsreal', 'largestimag', 'smallestimag', 'bothendsimag', or a scalar (eigenvalues closest to it). Supports the generalized problem A*V = B*V*D and a function handle Afun. Computed densely via eig, so convergence options are accepted but ignored and flag is always 0."
|
|
45752
|
+
},
|
|
45634
45753
|
svd: {
|
|
45635
45754
|
signatures: [
|
|
45636
45755
|
"S = svd(A)",
|
|
@@ -46432,6 +46551,17 @@ var H = {
|
|
|
46432
46551
|
signatures: ["colorbar", "colorbar(MODE)"],
|
|
46433
46552
|
description: "Display colorbar on current axes."
|
|
46434
46553
|
},
|
|
46554
|
+
axis: {
|
|
46555
|
+
signatures: [
|
|
46556
|
+
"axis([xmin xmax ymin ymax])",
|
|
46557
|
+
"axis STYLE",
|
|
46558
|
+
"axis MODE",
|
|
46559
|
+
"axis ij | xy",
|
|
46560
|
+
"axis on | off",
|
|
46561
|
+
"LIM = axis"
|
|
46562
|
+
],
|
|
46563
|
+
description: "Set or query axis limits, scaling, direction, and visibility. LIMITS is a 4-, 6-, or 8-element vector (inf bounds stay automatic). STYLE is tight | padded | fill | equal | image | square | vis3d | normal | tickaligned. MODE is manual | auto | 'auto x' | 'auto y' | 'auto z' (and xy combinations). 'ij' reverses the y-axis; 'off' hides the axes lines and background. LIM = axis returns the current limits."
|
|
46564
|
+
},
|
|
46435
46565
|
xlim: {
|
|
46436
46566
|
signatures: ["xlim(LIMITS)"],
|
|
46437
46567
|
description: "Set x-axis limits."
|
|
@@ -49605,6 +49735,134 @@ function stream2Call(args) {
|
|
|
49605
49735
|
return RTV.cell(cellData, [1, cellData.length]);
|
|
49606
49736
|
}
|
|
49607
49737
|
|
|
49738
|
+
// src/numbl-core/runtime/axisCommand.ts
|
|
49739
|
+
var STYLE_WORDS = /* @__PURE__ */ new Set([
|
|
49740
|
+
"tight",
|
|
49741
|
+
"padded",
|
|
49742
|
+
"fill",
|
|
49743
|
+
"equal",
|
|
49744
|
+
"image",
|
|
49745
|
+
"square",
|
|
49746
|
+
"vis3d",
|
|
49747
|
+
"normal",
|
|
49748
|
+
"tickaligned"
|
|
49749
|
+
]);
|
|
49750
|
+
var STYLE_RESETS_LIMITS = /* @__PURE__ */ new Set([
|
|
49751
|
+
"tight",
|
|
49752
|
+
"padded",
|
|
49753
|
+
"equal",
|
|
49754
|
+
"image",
|
|
49755
|
+
"tickaligned"
|
|
49756
|
+
]);
|
|
49757
|
+
var AUTO_AXIS_TOKENS = {
|
|
49758
|
+
auto: ["x", "y", "z"],
|
|
49759
|
+
"auto x": ["x"],
|
|
49760
|
+
"auto y": ["y"],
|
|
49761
|
+
"auto z": ["z"],
|
|
49762
|
+
"auto xy": ["x", "y"],
|
|
49763
|
+
"auto yx": ["x", "y"],
|
|
49764
|
+
"auto xz": ["x", "z"],
|
|
49765
|
+
"auto zx": ["x", "z"],
|
|
49766
|
+
"auto yz": ["y", "z"],
|
|
49767
|
+
"auto zy": ["y", "z"]
|
|
49768
|
+
};
|
|
49769
|
+
function isHandle(v) {
|
|
49770
|
+
return isRuntimeDummyHandle(v) || isRuntimeGraphicsHandle(v);
|
|
49771
|
+
}
|
|
49772
|
+
function numericValues(v) {
|
|
49773
|
+
if (isRuntimeTensor(v)) return Array.from(v.data);
|
|
49774
|
+
if (isRuntimeNumber(v)) return [v];
|
|
49775
|
+
if (isRuntimeLogical(v)) return [v ? 1 : 0];
|
|
49776
|
+
return null;
|
|
49777
|
+
}
|
|
49778
|
+
function bound(v) {
|
|
49779
|
+
return Number.isFinite(v) ? v : null;
|
|
49780
|
+
}
|
|
49781
|
+
function clearLimits(axes) {
|
|
49782
|
+
const instr = {
|
|
49783
|
+
type: "set_axis_limits"
|
|
49784
|
+
};
|
|
49785
|
+
if (axes.includes("x")) instr.xlim = "auto";
|
|
49786
|
+
if (axes.includes("y")) instr.ylim = "auto";
|
|
49787
|
+
if (axes.includes("z")) instr.zlim = "auto";
|
|
49788
|
+
return instr;
|
|
49789
|
+
}
|
|
49790
|
+
function applyAxisCommand(args, instructions, freezeLimits) {
|
|
49791
|
+
let i = 0;
|
|
49792
|
+
while (i < args.length && isHandle(args[i])) i++;
|
|
49793
|
+
let applied = false;
|
|
49794
|
+
const styles = [];
|
|
49795
|
+
for (; i < args.length; i++) {
|
|
49796
|
+
const arg = args[i];
|
|
49797
|
+
const nums = numericValues(arg);
|
|
49798
|
+
if (nums !== null) {
|
|
49799
|
+
applied = true;
|
|
49800
|
+
if (nums.length === 1) {
|
|
49801
|
+
instructions.push({ type: "set_axis_visible", value: nums[0] !== 0 });
|
|
49802
|
+
continue;
|
|
49803
|
+
}
|
|
49804
|
+
if (nums.length === 4 || nums.length === 6 || nums.length === 8) {
|
|
49805
|
+
const instr = {
|
|
49806
|
+
type: "set_axis_limits",
|
|
49807
|
+
xlim: [bound(nums[0]), bound(nums[1])],
|
|
49808
|
+
ylim: [bound(nums[2]), bound(nums[3])]
|
|
49809
|
+
};
|
|
49810
|
+
if (nums.length >= 6) instr.zlim = [bound(nums[4]), bound(nums[5])];
|
|
49811
|
+
instructions.push(instr);
|
|
49812
|
+
if (nums.length === 8 && Number.isFinite(nums[6]) && Number.isFinite(nums[7])) {
|
|
49813
|
+
instructions.push({ type: "set_caxis", limits: [nums[6], nums[7]] });
|
|
49814
|
+
}
|
|
49815
|
+
continue;
|
|
49816
|
+
}
|
|
49817
|
+
throw new RuntimeError(
|
|
49818
|
+
"axis: limit vector must have 4, 6, or 8 elements"
|
|
49819
|
+
);
|
|
49820
|
+
}
|
|
49821
|
+
const kw = toString(arg).trim().replace(/^["']|["']$/g, "").toLowerCase();
|
|
49822
|
+
applied = true;
|
|
49823
|
+
if (STYLE_WORDS.has(kw)) {
|
|
49824
|
+
styles.push(kw);
|
|
49825
|
+
if (STYLE_RESETS_LIMITS.has(kw)) {
|
|
49826
|
+
instructions.push(clearLimits(["x", "y", "z"]));
|
|
49827
|
+
}
|
|
49828
|
+
continue;
|
|
49829
|
+
}
|
|
49830
|
+
if (kw === "manual") {
|
|
49831
|
+
const lim = freezeLimits?.();
|
|
49832
|
+
if (lim && lim.length >= 4) {
|
|
49833
|
+
const instr = {
|
|
49834
|
+
type: "set_axis_limits",
|
|
49835
|
+
xlim: [lim[0], lim[1]],
|
|
49836
|
+
ylim: [lim[2], lim[3]]
|
|
49837
|
+
};
|
|
49838
|
+
if (lim.length >= 6) instr.zlim = [lim[4], lim[5]];
|
|
49839
|
+
instructions.push(instr);
|
|
49840
|
+
}
|
|
49841
|
+
continue;
|
|
49842
|
+
}
|
|
49843
|
+
if (kw in AUTO_AXIS_TOKENS) {
|
|
49844
|
+
instructions.push(clearLimits(AUTO_AXIS_TOKENS[kw]));
|
|
49845
|
+
continue;
|
|
49846
|
+
}
|
|
49847
|
+
if (kw === "xy" || kw === "ij") {
|
|
49848
|
+
instructions.push({
|
|
49849
|
+
type: "set_axis_ydir",
|
|
49850
|
+
dir: kw === "ij" ? "reverse" : "normal"
|
|
49851
|
+
});
|
|
49852
|
+
continue;
|
|
49853
|
+
}
|
|
49854
|
+
if (kw === "on" || kw === "off") {
|
|
49855
|
+
instructions.push({ type: "set_axis_visible", value: kw === "on" });
|
|
49856
|
+
continue;
|
|
49857
|
+
}
|
|
49858
|
+
throw new RuntimeError(`axis: unknown option '${kw}'`);
|
|
49859
|
+
}
|
|
49860
|
+
if (styles.length > 0) {
|
|
49861
|
+
instructions.push({ type: "set_axis", value: styles.join(" ") });
|
|
49862
|
+
}
|
|
49863
|
+
return applied;
|
|
49864
|
+
}
|
|
49865
|
+
|
|
49608
49866
|
// src/numbl-core/runtime/plotBuiltinDispatch.ts
|
|
49609
49867
|
function dispatchPlotBuiltin(name, args, instructions, state) {
|
|
49610
49868
|
switch (name) {
|
|
@@ -49793,10 +50051,7 @@ function dispatchPlotBuiltin(name, args, instructions, state) {
|
|
|
49793
50051
|
dispatchColormap(args, instructions);
|
|
49794
50052
|
return true;
|
|
49795
50053
|
case "axis": {
|
|
49796
|
-
|
|
49797
|
-
const val = toString(args[0]).replace(/^"|"$/g, "");
|
|
49798
|
-
plotInstr(instructions, { type: "set_axis", value: val });
|
|
49799
|
-
}
|
|
50054
|
+
applyAxisCommand(args, instructions);
|
|
49800
50055
|
return true;
|
|
49801
50056
|
}
|
|
49802
50057
|
case "caxis":
|
|
@@ -50491,6 +50746,85 @@ function quadgkAdaptive(integrand, a, b, opts = {}) {
|
|
|
50491
50746
|
};
|
|
50492
50747
|
}
|
|
50493
50748
|
|
|
50749
|
+
// src/numbl-core/helpers/eigs-select.ts
|
|
50750
|
+
var SIGMA_ALIASES = {
|
|
50751
|
+
lm: "largestabs",
|
|
50752
|
+
largestabs: "largestabs",
|
|
50753
|
+
sm: "smallestabs",
|
|
50754
|
+
smallestabs: "smallestabs",
|
|
50755
|
+
lr: "largestreal",
|
|
50756
|
+
la: "largestreal",
|
|
50757
|
+
largestreal: "largestreal",
|
|
50758
|
+
sr: "smallestreal",
|
|
50759
|
+
sa: "smallestreal",
|
|
50760
|
+
smallestreal: "smallestreal",
|
|
50761
|
+
be: "bothendsreal",
|
|
50762
|
+
bothendsreal: "bothendsreal",
|
|
50763
|
+
li: "largestimag",
|
|
50764
|
+
largestimag: "largestimag",
|
|
50765
|
+
si: "smallestimag",
|
|
50766
|
+
smallestimag: "smallestimag",
|
|
50767
|
+
bothendsimag: "bothendsimag"
|
|
50768
|
+
};
|
|
50769
|
+
function normalizeSigmaString(s) {
|
|
50770
|
+
return SIGMA_ALIASES[s.trim().toLowerCase()] ?? null;
|
|
50771
|
+
}
|
|
50772
|
+
var mag = (re, im) => Math.hypot(re, im);
|
|
50773
|
+
function sortedBy(n, key, descending) {
|
|
50774
|
+
const idx = Array.from({ length: n }, (_, i) => i);
|
|
50775
|
+
idx.sort((a, b) => {
|
|
50776
|
+
const ka = key(a);
|
|
50777
|
+
const kb = key(b);
|
|
50778
|
+
if (ka !== kb) return descending ? kb - ka : ka - kb;
|
|
50779
|
+
return a - b;
|
|
50780
|
+
});
|
|
50781
|
+
return idx;
|
|
50782
|
+
}
|
|
50783
|
+
function bothEnds(n, key, k) {
|
|
50784
|
+
const nHigh = Math.ceil(k / 2);
|
|
50785
|
+
const nLow = Math.floor(k / 2);
|
|
50786
|
+
const desc = sortedBy(n, key, true);
|
|
50787
|
+
const high = desc.slice(0, nHigh);
|
|
50788
|
+
const highSet = new Set(high);
|
|
50789
|
+
const low = [];
|
|
50790
|
+
for (let i = desc.length - 1; i >= 0 && low.length < nLow; i--) {
|
|
50791
|
+
if (!highSet.has(desc[i])) low.push(desc[i]);
|
|
50792
|
+
}
|
|
50793
|
+
return { high, low };
|
|
50794
|
+
}
|
|
50795
|
+
function selectEigsIndices(re, im, k, sigma) {
|
|
50796
|
+
const n = re.length;
|
|
50797
|
+
const kk = Math.max(0, Math.min(k, n));
|
|
50798
|
+
switch (sigma.kind) {
|
|
50799
|
+
case "largestabs":
|
|
50800
|
+
return sortedBy(n, (i) => mag(re[i], im[i]), true).slice(0, kk);
|
|
50801
|
+
case "smallestabs":
|
|
50802
|
+
return sortedBy(n, (i) => mag(re[i], im[i]), false).slice(0, kk);
|
|
50803
|
+
case "largestreal":
|
|
50804
|
+
return sortedBy(n, (i) => re[i], true).slice(0, kk);
|
|
50805
|
+
case "smallestreal":
|
|
50806
|
+
return sortedBy(n, (i) => re[i], false).slice(0, kk);
|
|
50807
|
+
case "largestimag":
|
|
50808
|
+
return sortedBy(n, (i) => im[i], true).slice(0, kk);
|
|
50809
|
+
case "smallestimag":
|
|
50810
|
+
return sortedBy(n, (i) => im[i], false).slice(0, kk);
|
|
50811
|
+
case "scalar": {
|
|
50812
|
+
const { re: sr, im: si } = sigma;
|
|
50813
|
+
return sortedBy(n, (i) => mag(re[i] - sr, im[i] - si), false).slice(0, kk);
|
|
50814
|
+
}
|
|
50815
|
+
case "bothendsreal": {
|
|
50816
|
+
const { high, low } = bothEnds(n, (i) => re[i], kk);
|
|
50817
|
+
return [...high, ...low].sort((a, b) => re[a] - re[b] || a - b);
|
|
50818
|
+
}
|
|
50819
|
+
case "bothendsimag": {
|
|
50820
|
+
const { high, low } = bothEnds(n, (i) => im[i], kk);
|
|
50821
|
+
return [...high, ...low].sort(
|
|
50822
|
+
(a, b) => Math.abs(im[b]) - Math.abs(im[a]) || a - b
|
|
50823
|
+
);
|
|
50824
|
+
}
|
|
50825
|
+
}
|
|
50826
|
+
}
|
|
50827
|
+
|
|
50494
50828
|
// src/numbl-core/runtime/specialBuiltinNames.ts
|
|
50495
50829
|
var SPECIAL_BUILTIN_NAMES = [
|
|
50496
50830
|
"help",
|
|
@@ -50609,6 +50943,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
50609
50943
|
"toc",
|
|
50610
50944
|
"quadgk",
|
|
50611
50945
|
"gmres",
|
|
50946
|
+
"eigs",
|
|
50612
50947
|
"onCleanup"
|
|
50613
50948
|
];
|
|
50614
50949
|
|
|
@@ -51986,6 +52321,9 @@ function registerSpecialBuiltins(rt) {
|
|
|
51986
52321
|
registerSpecial("gmres", (nargout, args) => {
|
|
51987
52322
|
return _gmresImpl(rt, nargout, args);
|
|
51988
52323
|
});
|
|
52324
|
+
registerSpecial("eigs", (nargout, args) => {
|
|
52325
|
+
return _eigsImpl(rt, nargout, args);
|
|
52326
|
+
});
|
|
51989
52327
|
registerSpecial("onCleanup", (_nargout, args) => {
|
|
51990
52328
|
if (args.length !== 1 || !isRuntimeFunction(args[0]))
|
|
51991
52329
|
throw new RuntimeError("onCleanup requires a function handle argument");
|
|
@@ -51993,6 +52331,271 @@ function registerSpecialBuiltins(rt) {
|
|
|
51993
52331
|
return RTV.classInstance("onCleanup", [], false);
|
|
51994
52332
|
});
|
|
51995
52333
|
}
|
|
52334
|
+
function eigsReIm(v) {
|
|
52335
|
+
if (isRuntimeNumber(v)) return { re: [v], im: [0] };
|
|
52336
|
+
if (isRuntimeComplexNumber(v)) return { re: [v.re], im: [v.im] };
|
|
52337
|
+
if (isRuntimeTensor(v)) {
|
|
52338
|
+
const re = Array.from(v.data);
|
|
52339
|
+
const im = v.imag ? Array.from(v.imag) : re.map(() => 0);
|
|
52340
|
+
return { re, im };
|
|
52341
|
+
}
|
|
52342
|
+
throw new RuntimeError("eigs: expected a numeric value");
|
|
52343
|
+
}
|
|
52344
|
+
function eigsAsTensor(v) {
|
|
52345
|
+
const rv = ensureRuntimeValue(v);
|
|
52346
|
+
if (isRuntimeTensor(rv)) return rv;
|
|
52347
|
+
if (isRuntimeNumber(rv))
|
|
52348
|
+
return RTV.tensor(allocFloat64Array([rv]), [1, 1]);
|
|
52349
|
+
if (isRuntimeComplexNumber(rv))
|
|
52350
|
+
return RTV.tensor(
|
|
52351
|
+
allocFloat64Array([rv.re]),
|
|
52352
|
+
[1, 1],
|
|
52353
|
+
allocFloat64Array([rv.im])
|
|
52354
|
+
);
|
|
52355
|
+
throw new RuntimeError("eigs: expected a numeric matrix");
|
|
52356
|
+
}
|
|
52357
|
+
function eigsMatrixSize(A) {
|
|
52358
|
+
if (isRuntimeNumber(A) || isRuntimeComplexNumber(A)) return 1;
|
|
52359
|
+
if (isRuntimeTensor(A)) {
|
|
52360
|
+
const rows = A.shape[0] ?? 1;
|
|
52361
|
+
const cols = A.shape[1] ?? 1;
|
|
52362
|
+
if (rows !== cols)
|
|
52363
|
+
throw new RuntimeError("eigs: input matrix must be square");
|
|
52364
|
+
return rows;
|
|
52365
|
+
}
|
|
52366
|
+
throw new RuntimeError("eigs: input must be a numeric matrix");
|
|
52367
|
+
}
|
|
52368
|
+
function eigsIsScalar(v) {
|
|
52369
|
+
return isRuntimeNumber(v) || isRuntimeComplexNumber(v) || isRuntimeTensor(v) && v.data.length === 1;
|
|
52370
|
+
}
|
|
52371
|
+
function eigsIsMatrixArg(v) {
|
|
52372
|
+
if (!isRuntimeTensor(v)) return false;
|
|
52373
|
+
if (v.data.length === 0) return true;
|
|
52374
|
+
const rows = v.shape[0] ?? 1;
|
|
52375
|
+
const cols = v.shape[1] ?? 1;
|
|
52376
|
+
return rows > 1 || cols > 1;
|
|
52377
|
+
}
|
|
52378
|
+
function eigsToBool(v) {
|
|
52379
|
+
if (isRuntimeLogical(v)) return v;
|
|
52380
|
+
if (isRuntimeNumber(v)) return v !== 0;
|
|
52381
|
+
if (isRuntimeTensor(v) && v.data.length >= 1) return v.data[0] !== 0;
|
|
52382
|
+
return false;
|
|
52383
|
+
}
|
|
52384
|
+
function eigsParseSigma(v) {
|
|
52385
|
+
if (isRuntimeString(v) || isRuntimeChar(v)) {
|
|
52386
|
+
const s = typeof v === "string" ? v : v.value;
|
|
52387
|
+
const kind = normalizeSigmaString(s);
|
|
52388
|
+
if (!kind) throw new RuntimeError(`eigs: unknown sigma option '${s}'`);
|
|
52389
|
+
return { kind };
|
|
52390
|
+
}
|
|
52391
|
+
let re;
|
|
52392
|
+
let im = 0;
|
|
52393
|
+
if (isRuntimeComplexNumber(v)) {
|
|
52394
|
+
re = v.re;
|
|
52395
|
+
im = v.im;
|
|
52396
|
+
} else if (isRuntimeNumber(v)) {
|
|
52397
|
+
re = v;
|
|
52398
|
+
} else if (isRuntimeTensor(v) && v.data.length >= 1) {
|
|
52399
|
+
re = v.data[0];
|
|
52400
|
+
im = v.imag ? v.imag[0] : 0;
|
|
52401
|
+
} else {
|
|
52402
|
+
throw new RuntimeError("eigs: invalid sigma argument");
|
|
52403
|
+
}
|
|
52404
|
+
if (re === 0 && im === 0) return { kind: "smallestabs" };
|
|
52405
|
+
return { kind: "scalar", re, im };
|
|
52406
|
+
}
|
|
52407
|
+
function eigsReconstructOperator(rt, afun, n) {
|
|
52408
|
+
const re = allocFloat64Array(n * n);
|
|
52409
|
+
const im = allocFloat64Array(n * n);
|
|
52410
|
+
let anyImag = false;
|
|
52411
|
+
for (let j = 0; j < n; j++) {
|
|
52412
|
+
const e = allocFloat64Array(n);
|
|
52413
|
+
e[j] = 1;
|
|
52414
|
+
const col = ensureRuntimeValue(
|
|
52415
|
+
rt.index(afun, [RTV.tensor(e, [n, 1])], 1)
|
|
52416
|
+
);
|
|
52417
|
+
const { re: cre, im: cim } = eigsReIm(col);
|
|
52418
|
+
for (let i = 0; i < n; i++) {
|
|
52419
|
+
re[j * n + i] = cre[i] ?? 0;
|
|
52420
|
+
im[j * n + i] = cim[i] ?? 0;
|
|
52421
|
+
if (im[j * n + i] !== 0) anyImag = true;
|
|
52422
|
+
}
|
|
52423
|
+
}
|
|
52424
|
+
return anyImag ? RTV.tensor(re, [n, n], im) : RTV.tensor(re, [n, n]);
|
|
52425
|
+
}
|
|
52426
|
+
function eigsRecoverAfunMatrix(rt, M, sigma, B, n) {
|
|
52427
|
+
if (sigma.kind === "smallestabs") {
|
|
52428
|
+
return eigsAsTensor(rt.dispatch("inv", 1, [M]));
|
|
52429
|
+
}
|
|
52430
|
+
if (sigma.kind === "scalar") {
|
|
52431
|
+
const base = eigsAsTensor(rt.dispatch("inv", 1, [M]));
|
|
52432
|
+
const shiftRe = allocFloat64Array(n * n);
|
|
52433
|
+
const shiftIm = allocFloat64Array(n * n);
|
|
52434
|
+
if (B && isRuntimeTensor(B)) {
|
|
52435
|
+
for (let i = 0; i < n * n; i++) {
|
|
52436
|
+
shiftRe[i] = (B.data[i] ?? 0) * sigma.re - (B.imag?.[i] ?? 0) * sigma.im;
|
|
52437
|
+
shiftIm[i] = (B.data[i] ?? 0) * sigma.im + (B.imag?.[i] ?? 0) * sigma.re;
|
|
52438
|
+
}
|
|
52439
|
+
} else {
|
|
52440
|
+
for (let d = 0; d < n; d++) {
|
|
52441
|
+
shiftRe[d * n + d] = sigma.re;
|
|
52442
|
+
shiftIm[d * n + d] = sigma.im;
|
|
52443
|
+
}
|
|
52444
|
+
}
|
|
52445
|
+
const shift = maybeComplexTensor(shiftRe, [n, n], shiftIm);
|
|
52446
|
+
return eigsAsTensor(rt.dispatch("plus", 1, [base, shift]));
|
|
52447
|
+
}
|
|
52448
|
+
return M;
|
|
52449
|
+
}
|
|
52450
|
+
function eigsReconstructCholesky(R, perm, n) {
|
|
52451
|
+
if (!isRuntimeTensor(R))
|
|
52452
|
+
throw new RuntimeError("eigs: Cholesky factor must be a matrix");
|
|
52453
|
+
const r = R.data;
|
|
52454
|
+
const rtr = allocFloat64Array(n * n);
|
|
52455
|
+
for (let i = 0; i < n; i++) {
|
|
52456
|
+
for (let j = 0; j < n; j++) {
|
|
52457
|
+
let s = 0;
|
|
52458
|
+
for (let kk = 0; kk < n; kk++) s += r[i * n + kk] * r[j * n + kk];
|
|
52459
|
+
rtr[j * n + i] = s;
|
|
52460
|
+
}
|
|
52461
|
+
}
|
|
52462
|
+
if (!perm) return RTV.tensor(rtr, [n, n]);
|
|
52463
|
+
const b = allocFloat64Array(n * n);
|
|
52464
|
+
for (let i = 0; i < n; i++) {
|
|
52465
|
+
for (let j = 0; j < n; j++) {
|
|
52466
|
+
const pi2 = (perm[i] ?? i + 1) - 1;
|
|
52467
|
+
const pj = (perm[j] ?? j + 1) - 1;
|
|
52468
|
+
b[pj * n + pi2] = rtr[j * n + i];
|
|
52469
|
+
}
|
|
52470
|
+
}
|
|
52471
|
+
return RTV.tensor(b, [n, n]);
|
|
52472
|
+
}
|
|
52473
|
+
function _eigsImpl(rt, nargout, args) {
|
|
52474
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
52475
|
+
if (margs.length < 1)
|
|
52476
|
+
throw new RuntimeError("eigs requires at least 1 argument");
|
|
52477
|
+
let afun = null;
|
|
52478
|
+
let A = null;
|
|
52479
|
+
let n;
|
|
52480
|
+
let pos;
|
|
52481
|
+
if (isRuntimeFunction(margs[0])) {
|
|
52482
|
+
afun = margs[0];
|
|
52483
|
+
if (margs.length < 2 || !eigsIsScalar(margs[1]))
|
|
52484
|
+
throw new RuntimeError(
|
|
52485
|
+
"eigs: a function handle must be followed by the matrix size n"
|
|
52486
|
+
);
|
|
52487
|
+
n = Math.floor(toNumber(margs[1]));
|
|
52488
|
+
pos = 2;
|
|
52489
|
+
} else {
|
|
52490
|
+
A = margs[0];
|
|
52491
|
+
n = eigsMatrixSize(A);
|
|
52492
|
+
pos = 1;
|
|
52493
|
+
}
|
|
52494
|
+
let B = null;
|
|
52495
|
+
if (pos < margs.length && eigsIsMatrixArg(margs[pos])) {
|
|
52496
|
+
const b = margs[pos];
|
|
52497
|
+
if (!(isRuntimeTensor(b) && b.data.length === 0)) B = b;
|
|
52498
|
+
pos++;
|
|
52499
|
+
}
|
|
52500
|
+
let kReq = null;
|
|
52501
|
+
if (pos < margs.length && eigsIsScalar(margs[pos])) {
|
|
52502
|
+
kReq = Math.max(1, Math.floor(toNumber(margs[pos])));
|
|
52503
|
+
pos++;
|
|
52504
|
+
}
|
|
52505
|
+
let sigma = { kind: "largestabs" };
|
|
52506
|
+
if (pos < margs.length) {
|
|
52507
|
+
const a = margs[pos];
|
|
52508
|
+
if (isRuntimeString(a) || isRuntimeChar(a)) {
|
|
52509
|
+
const s = typeof a === "string" ? a : a.value;
|
|
52510
|
+
if (normalizeSigmaString(s)) {
|
|
52511
|
+
sigma = eigsParseSigma(a);
|
|
52512
|
+
pos++;
|
|
52513
|
+
}
|
|
52514
|
+
} else if (eigsIsScalar(a)) {
|
|
52515
|
+
sigma = eigsParseSigma(a);
|
|
52516
|
+
pos++;
|
|
52517
|
+
}
|
|
52518
|
+
}
|
|
52519
|
+
let isCholesky = false;
|
|
52520
|
+
let cholPerm = null;
|
|
52521
|
+
const applyOption = (key, val) => {
|
|
52522
|
+
const lk = key.toLowerCase();
|
|
52523
|
+
if (lk === "ischolesky" || lk === "cholb") isCholesky = eigsToBool(val);
|
|
52524
|
+
else if (lk === "choleskypermutation" || lk === "permb") {
|
|
52525
|
+
if (isRuntimeTensor(val)) cholPerm = Array.from(val.data);
|
|
52526
|
+
}
|
|
52527
|
+
};
|
|
52528
|
+
while (pos < margs.length) {
|
|
52529
|
+
const a = margs[pos];
|
|
52530
|
+
if (isRuntimeStruct(a)) {
|
|
52531
|
+
for (const [key, val] of a.fields) applyOption(key, val);
|
|
52532
|
+
pos++;
|
|
52533
|
+
} else if (pos + 1 < margs.length) {
|
|
52534
|
+
applyOption(
|
|
52535
|
+
isRuntimeChar(margs[pos]) ? margs[pos].value : String(toString(margs[pos])),
|
|
52536
|
+
margs[pos + 1]
|
|
52537
|
+
);
|
|
52538
|
+
pos += 2;
|
|
52539
|
+
} else {
|
|
52540
|
+
break;
|
|
52541
|
+
}
|
|
52542
|
+
}
|
|
52543
|
+
const k = kReq == null ? Math.min(6, n) : Math.min(kReq, n);
|
|
52544
|
+
let actualA;
|
|
52545
|
+
if (afun) {
|
|
52546
|
+
const M = eigsReconstructOperator(rt, afun, n);
|
|
52547
|
+
actualA = eigsRecoverAfunMatrix(rt, M, sigma, B, n);
|
|
52548
|
+
} else {
|
|
52549
|
+
actualA = A;
|
|
52550
|
+
}
|
|
52551
|
+
let effective = actualA;
|
|
52552
|
+
if (B) {
|
|
52553
|
+
const Bmat = isCholesky ? eigsReconstructCholesky(B, cholPerm, n) : B;
|
|
52554
|
+
effective = eigsAsTensor(rt.dispatch("mldivide", 1, [Bmat, actualA]));
|
|
52555
|
+
}
|
|
52556
|
+
if (nargout <= 1) {
|
|
52557
|
+
const d = ensureRuntimeValue(rt.dispatch("eig", 1, [effective]));
|
|
52558
|
+
const { re: re2, im: im2 } = eigsReIm(d);
|
|
52559
|
+
const order2 = selectEigsIndices(re2, im2, k, sigma);
|
|
52560
|
+
const outRe = allocFloat64Array(order2.length);
|
|
52561
|
+
const outIm = allocFloat64Array(order2.length);
|
|
52562
|
+
for (let c = 0; c < order2.length; c++) {
|
|
52563
|
+
outRe[c] = re2[order2[c]];
|
|
52564
|
+
outIm[c] = im2[order2[c]];
|
|
52565
|
+
}
|
|
52566
|
+
return maybeComplexTensor(outRe, [order2.length, 1], outIm);
|
|
52567
|
+
}
|
|
52568
|
+
const res = rt.dispatch("eig", 2, [effective]);
|
|
52569
|
+
const Vall = eigsAsTensor(res[0]);
|
|
52570
|
+
const Dall = eigsAsTensor(res[1]);
|
|
52571
|
+
const p2 = Dall.shape[0] ?? 1;
|
|
52572
|
+
const vrows = Vall.shape[0] ?? p2;
|
|
52573
|
+
const re = [];
|
|
52574
|
+
const im = [];
|
|
52575
|
+
for (let j = 0; j < p2; j++) {
|
|
52576
|
+
re.push(Dall.data[j * p2 + j]);
|
|
52577
|
+
im.push(Dall.imag ? Dall.imag[j * p2 + j] : 0);
|
|
52578
|
+
}
|
|
52579
|
+
const order = selectEigsIndices(re, im, k, sigma);
|
|
52580
|
+
const kk = order.length;
|
|
52581
|
+
const Vre = allocFloat64Array(vrows * kk);
|
|
52582
|
+
const Vim = allocFloat64Array(vrows * kk);
|
|
52583
|
+
const Dre = allocFloat64Array(kk * kk);
|
|
52584
|
+
const Dim = allocFloat64Array(kk * kk);
|
|
52585
|
+
for (let c = 0; c < kk; c++) {
|
|
52586
|
+
const s = order[c];
|
|
52587
|
+
for (let r = 0; r < vrows; r++) {
|
|
52588
|
+
Vre[c * vrows + r] = Vall.data[s * vrows + r];
|
|
52589
|
+
if (Vall.imag) Vim[c * vrows + r] = Vall.imag[s * vrows + r];
|
|
52590
|
+
}
|
|
52591
|
+
Dre[c * kk + c] = re[s];
|
|
52592
|
+
Dim[c * kk + c] = im[s];
|
|
52593
|
+
}
|
|
52594
|
+
const V = maybeComplexTensor(Vre, [vrows, kk], Vim);
|
|
52595
|
+
const D = maybeComplexTensor(Dre, [kk, kk], Dim);
|
|
52596
|
+
if (nargout === 2) return [V, D];
|
|
52597
|
+
return [V, D, RTV.num(0)];
|
|
52598
|
+
}
|
|
51996
52599
|
function _ode45Impl(rt, nargout, args, tableau = dormandPrince45) {
|
|
51997
52600
|
const solverName = tableau.name;
|
|
51998
52601
|
if (args.length < 3)
|
|
@@ -54350,6 +54953,484 @@ function memberChainAssign(rt, base, names, rhs) {
|
|
|
54350
54953
|
return subsasgnFallback(rt, base, names, rhs);
|
|
54351
54954
|
}
|
|
54352
54955
|
|
|
54956
|
+
// src/graphics/figuresReducer.ts
|
|
54957
|
+
var defaultAxes = {
|
|
54958
|
+
holdOn: false,
|
|
54959
|
+
traces: [],
|
|
54960
|
+
plot3Traces: [],
|
|
54961
|
+
surfTraces: [],
|
|
54962
|
+
pcolorTraces: [],
|
|
54963
|
+
contourTraces: [],
|
|
54964
|
+
barTraces: [],
|
|
54965
|
+
barhTraces: [],
|
|
54966
|
+
bar3Traces: [],
|
|
54967
|
+
bar3hTraces: [],
|
|
54968
|
+
errorBarTraces: [],
|
|
54969
|
+
boxTraces: [],
|
|
54970
|
+
quiverTraces: [],
|
|
54971
|
+
quiver3Traces: [],
|
|
54972
|
+
areaTraces: [],
|
|
54973
|
+
areaBaseValue: 0
|
|
54974
|
+
};
|
|
54975
|
+
function getAxes(fig) {
|
|
54976
|
+
return fig.axes[fig.currentAxesIndex] || { ...defaultAxes };
|
|
54977
|
+
}
|
|
54978
|
+
function setAxes(fig, axes) {
|
|
54979
|
+
return {
|
|
54980
|
+
...fig,
|
|
54981
|
+
axes: { ...fig.axes, [fig.currentAxesIndex]: axes }
|
|
54982
|
+
};
|
|
54983
|
+
}
|
|
54984
|
+
var initialFiguresState = {
|
|
54985
|
+
currentHandle: 1,
|
|
54986
|
+
figs: {}
|
|
54987
|
+
};
|
|
54988
|
+
var defaultFigure = {
|
|
54989
|
+
currentAxesIndex: 1,
|
|
54990
|
+
axes: {}
|
|
54991
|
+
};
|
|
54992
|
+
function ensureFig(state) {
|
|
54993
|
+
return state.figs[state.currentHandle] || { ...defaultFigure };
|
|
54994
|
+
}
|
|
54995
|
+
function updateAxes(state, update) {
|
|
54996
|
+
const fig = ensureFig(state);
|
|
54997
|
+
const axes = getAxes(fig);
|
|
54998
|
+
return {
|
|
54999
|
+
...state,
|
|
55000
|
+
figs: {
|
|
55001
|
+
...state.figs,
|
|
55002
|
+
[state.currentHandle]: setAxes(fig, { ...axes, ...update })
|
|
55003
|
+
}
|
|
55004
|
+
};
|
|
55005
|
+
}
|
|
55006
|
+
function addTraces(state, update) {
|
|
55007
|
+
const fig = ensureFig(state);
|
|
55008
|
+
const axes = getAxes(fig);
|
|
55009
|
+
const hold = axes.holdOn;
|
|
55010
|
+
return {
|
|
55011
|
+
...state,
|
|
55012
|
+
figs: {
|
|
55013
|
+
...state.figs,
|
|
55014
|
+
[state.currentHandle]: setAxes(fig, {
|
|
55015
|
+
...axes,
|
|
55016
|
+
traces: update.traces ?? (hold ? axes.traces : []),
|
|
55017
|
+
plot3Traces: update.plot3Traces ?? (hold ? axes.plot3Traces : []),
|
|
55018
|
+
surfTraces: update.surfTraces ?? (hold ? axes.surfTraces : []),
|
|
55019
|
+
pcolorTraces: update.pcolorTraces ?? (hold ? axes.pcolorTraces : []),
|
|
55020
|
+
contourTraces: update.contourTraces ?? (hold ? axes.contourTraces : []),
|
|
55021
|
+
barTraces: update.barTraces ?? (hold ? axes.barTraces : []),
|
|
55022
|
+
barhTraces: update.barhTraces ?? (hold ? axes.barhTraces : []),
|
|
55023
|
+
bar3Traces: update.bar3Traces ?? (hold ? axes.bar3Traces : []),
|
|
55024
|
+
bar3hTraces: update.bar3hTraces ?? (hold ? axes.bar3hTraces : []),
|
|
55025
|
+
errorBarTraces: update.errorBarTraces ?? (hold ? axes.errorBarTraces : []),
|
|
55026
|
+
boxTraces: update.boxTraces ?? (hold ? axes.boxTraces : []),
|
|
55027
|
+
pieTrace: update.pieTrace ?? (hold ? axes.pieTrace : void 0),
|
|
55028
|
+
heatmapTrace: update.heatmapTrace ?? (hold ? axes.heatmapTrace : void 0),
|
|
55029
|
+
quiverTraces: update.quiverTraces ?? (hold ? axes.quiverTraces : []),
|
|
55030
|
+
quiver3Traces: update.quiver3Traces ?? (hold ? axes.quiver3Traces : []),
|
|
55031
|
+
areaTraces: update.areaTraces ?? (hold ? axes.areaTraces : []),
|
|
55032
|
+
areaBaseValue: update.areaBaseValue ?? axes.areaBaseValue,
|
|
55033
|
+
...update.imagescTrace !== void 0 ? { imagescTrace: update.imagescTrace } : {}
|
|
55034
|
+
})
|
|
55035
|
+
}
|
|
55036
|
+
};
|
|
55037
|
+
}
|
|
55038
|
+
var figuresReducer = (state, action) => {
|
|
55039
|
+
switch (action.type) {
|
|
55040
|
+
case "set_figure_handle":
|
|
55041
|
+
return { ...state, currentHandle: action.handle };
|
|
55042
|
+
case "set_hold":
|
|
55043
|
+
return updateAxes(state, { holdOn: action.value });
|
|
55044
|
+
case "plot": {
|
|
55045
|
+
const axes = getAxes(ensureFig(state));
|
|
55046
|
+
return addTraces(state, {
|
|
55047
|
+
traces: axes.holdOn ? [...axes.traces, ...action.traces] : [...action.traces]
|
|
55048
|
+
});
|
|
55049
|
+
}
|
|
55050
|
+
case "plot3": {
|
|
55051
|
+
const axes = getAxes(ensureFig(state));
|
|
55052
|
+
return addTraces(state, {
|
|
55053
|
+
plot3Traces: axes.holdOn ? [...axes.plot3Traces, ...action.traces] : [...action.traces]
|
|
55054
|
+
});
|
|
55055
|
+
}
|
|
55056
|
+
case "surf": {
|
|
55057
|
+
const axes = getAxes(ensureFig(state));
|
|
55058
|
+
return addTraces(state, {
|
|
55059
|
+
surfTraces: axes.holdOn ? [...axes.surfTraces, action.trace] : [action.trace]
|
|
55060
|
+
});
|
|
55061
|
+
}
|
|
55062
|
+
case "surface": {
|
|
55063
|
+
const axes = getAxes(ensureFig(state));
|
|
55064
|
+
return updateAxes(state, {
|
|
55065
|
+
surfTraces: [...axes.surfTraces, action.trace]
|
|
55066
|
+
});
|
|
55067
|
+
}
|
|
55068
|
+
case "imagesc":
|
|
55069
|
+
return addTraces(state, { imagescTrace: action.trace });
|
|
55070
|
+
case "pcolor": {
|
|
55071
|
+
const axes = getAxes(ensureFig(state));
|
|
55072
|
+
return addTraces(state, {
|
|
55073
|
+
pcolorTraces: axes.holdOn ? [...axes.pcolorTraces, action.trace] : [action.trace]
|
|
55074
|
+
});
|
|
55075
|
+
}
|
|
55076
|
+
case "contour": {
|
|
55077
|
+
const axes = getAxes(ensureFig(state));
|
|
55078
|
+
return addTraces(state, {
|
|
55079
|
+
contourTraces: axes.holdOn ? [...axes.contourTraces, action.trace] : [action.trace]
|
|
55080
|
+
});
|
|
55081
|
+
}
|
|
55082
|
+
case "mesh": {
|
|
55083
|
+
const axes = getAxes(ensureFig(state));
|
|
55084
|
+
return addTraces(state, {
|
|
55085
|
+
surfTraces: axes.holdOn ? [...axes.surfTraces, action.trace] : [action.trace]
|
|
55086
|
+
});
|
|
55087
|
+
}
|
|
55088
|
+
case "bar": {
|
|
55089
|
+
const axes = getAxes(ensureFig(state));
|
|
55090
|
+
return addTraces(state, {
|
|
55091
|
+
barTraces: axes.holdOn ? [...axes.barTraces, ...action.traces] : [...action.traces]
|
|
55092
|
+
});
|
|
55093
|
+
}
|
|
55094
|
+
case "barh": {
|
|
55095
|
+
const axes = getAxes(ensureFig(state));
|
|
55096
|
+
return addTraces(state, {
|
|
55097
|
+
barhTraces: axes.holdOn ? [...axes.barhTraces, ...action.traces] : [...action.traces]
|
|
55098
|
+
});
|
|
55099
|
+
}
|
|
55100
|
+
case "bar3": {
|
|
55101
|
+
const axes = getAxes(ensureFig(state));
|
|
55102
|
+
return addTraces(state, {
|
|
55103
|
+
bar3Traces: axes.holdOn ? [...axes.bar3Traces, action.trace] : [action.trace]
|
|
55104
|
+
});
|
|
55105
|
+
}
|
|
55106
|
+
case "bar3h": {
|
|
55107
|
+
const axes = getAxes(ensureFig(state));
|
|
55108
|
+
return addTraces(state, {
|
|
55109
|
+
bar3hTraces: axes.holdOn ? [...axes.bar3hTraces, action.trace] : [action.trace]
|
|
55110
|
+
});
|
|
55111
|
+
}
|
|
55112
|
+
case "errorbar": {
|
|
55113
|
+
const axes = getAxes(ensureFig(state));
|
|
55114
|
+
return addTraces(state, {
|
|
55115
|
+
errorBarTraces: axes.holdOn ? [...axes.errorBarTraces, ...action.traces] : [...action.traces]
|
|
55116
|
+
});
|
|
55117
|
+
}
|
|
55118
|
+
case "boxchart": {
|
|
55119
|
+
const axes = getAxes(ensureFig(state));
|
|
55120
|
+
return addTraces(state, {
|
|
55121
|
+
boxTraces: axes.holdOn ? [...axes.boxTraces, ...action.traces] : [...action.traces]
|
|
55122
|
+
});
|
|
55123
|
+
}
|
|
55124
|
+
case "piechart":
|
|
55125
|
+
return addTraces(state, { pieTrace: action.trace });
|
|
55126
|
+
case "heatmap":
|
|
55127
|
+
return addTraces(state, { heatmapTrace: action.trace });
|
|
55128
|
+
case "quiver": {
|
|
55129
|
+
const axes = getAxes(ensureFig(state));
|
|
55130
|
+
return addTraces(state, {
|
|
55131
|
+
quiverTraces: axes.holdOn ? [...axes.quiverTraces, ...action.traces] : [...action.traces]
|
|
55132
|
+
});
|
|
55133
|
+
}
|
|
55134
|
+
case "quiver3": {
|
|
55135
|
+
const axes = getAxes(ensureFig(state));
|
|
55136
|
+
return addTraces(state, {
|
|
55137
|
+
quiver3Traces: axes.holdOn ? [...axes.quiver3Traces, action.trace] : [action.trace]
|
|
55138
|
+
});
|
|
55139
|
+
}
|
|
55140
|
+
case "area": {
|
|
55141
|
+
const axes = getAxes(ensureFig(state));
|
|
55142
|
+
return addTraces(state, {
|
|
55143
|
+
areaTraces: axes.holdOn ? [...axes.areaTraces, ...action.traces] : [...action.traces],
|
|
55144
|
+
areaBaseValue: action.baseValue
|
|
55145
|
+
});
|
|
55146
|
+
}
|
|
55147
|
+
case "close": {
|
|
55148
|
+
const remainingFigs = Object.fromEntries(
|
|
55149
|
+
Object.entries(state.figs).filter(
|
|
55150
|
+
([k]) => Number(k) !== state.currentHandle
|
|
55151
|
+
)
|
|
55152
|
+
);
|
|
55153
|
+
const handles = Object.keys(remainingFigs).map(Number).sort((a, b) => a - b);
|
|
55154
|
+
return {
|
|
55155
|
+
...state,
|
|
55156
|
+
currentHandle: handles.length > 0 ? handles[handles.length - 1] : 1,
|
|
55157
|
+
figs: remainingFigs
|
|
55158
|
+
};
|
|
55159
|
+
}
|
|
55160
|
+
case "close_all":
|
|
55161
|
+
case "clear":
|
|
55162
|
+
return initialFiguresState;
|
|
55163
|
+
case "set_title":
|
|
55164
|
+
return updateAxes(state, { title: action.text });
|
|
55165
|
+
case "set_xlabel":
|
|
55166
|
+
return updateAxes(state, { xlabel: action.text });
|
|
55167
|
+
case "set_ylabel":
|
|
55168
|
+
return updateAxes(state, { ylabel: action.text });
|
|
55169
|
+
case "set_zlabel":
|
|
55170
|
+
return updateAxes(state, { zlabel: action.text });
|
|
55171
|
+
case "set_shading":
|
|
55172
|
+
return updateAxes(state, { shading: action.shading });
|
|
55173
|
+
case "set_legend":
|
|
55174
|
+
return updateAxes(state, { legend: action.labels });
|
|
55175
|
+
case "set_sgtitle": {
|
|
55176
|
+
const fig = ensureFig(state);
|
|
55177
|
+
return {
|
|
55178
|
+
...state,
|
|
55179
|
+
figs: {
|
|
55180
|
+
...state.figs,
|
|
55181
|
+
[state.currentHandle]: { ...fig, sgtitle: action.text }
|
|
55182
|
+
}
|
|
55183
|
+
};
|
|
55184
|
+
}
|
|
55185
|
+
case "set_grid":
|
|
55186
|
+
return updateAxes(state, { gridOn: action.value });
|
|
55187
|
+
case "set_colorbar":
|
|
55188
|
+
return updateAxes(state, {
|
|
55189
|
+
colorbar: action.value !== "off",
|
|
55190
|
+
colorbarLocation: action.location ?? "eastoutside"
|
|
55191
|
+
});
|
|
55192
|
+
case "set_colormap":
|
|
55193
|
+
return updateAxes(state, {
|
|
55194
|
+
colormap: action.name,
|
|
55195
|
+
colormapData: action.data
|
|
55196
|
+
});
|
|
55197
|
+
case "set_view":
|
|
55198
|
+
return updateAxes(state, { view: { az: action.az, el: action.el } });
|
|
55199
|
+
case "set_axis":
|
|
55200
|
+
return updateAxes(state, { axisMode: action.value });
|
|
55201
|
+
case "set_axis_limits": {
|
|
55202
|
+
const axes = getAxes(ensureFig(state));
|
|
55203
|
+
const resolve = (prev, spec) => {
|
|
55204
|
+
if (spec === void 0) return prev;
|
|
55205
|
+
if (spec === "auto") return void 0;
|
|
55206
|
+
return spec;
|
|
55207
|
+
};
|
|
55208
|
+
return updateAxes(state, {
|
|
55209
|
+
xlim: resolve(axes.xlim, action.xlim),
|
|
55210
|
+
ylim: resolve(axes.ylim, action.ylim),
|
|
55211
|
+
zlim: resolve(axes.zlim, action.zlim)
|
|
55212
|
+
});
|
|
55213
|
+
}
|
|
55214
|
+
case "set_axis_ydir":
|
|
55215
|
+
return updateAxes(state, { yDir: action.dir });
|
|
55216
|
+
case "set_axis_visible":
|
|
55217
|
+
return updateAxes(state, { axisVisible: action.value });
|
|
55218
|
+
case "set_axis_scale":
|
|
55219
|
+
return updateAxes(state, { axisScale: action.value });
|
|
55220
|
+
case "set_caxis":
|
|
55221
|
+
return updateAxes(state, { caxis: action.limits });
|
|
55222
|
+
case "clf": {
|
|
55223
|
+
const fig = state.figs[state.currentHandle];
|
|
55224
|
+
if (!fig) return state;
|
|
55225
|
+
return {
|
|
55226
|
+
...state,
|
|
55227
|
+
figs: {
|
|
55228
|
+
...state.figs,
|
|
55229
|
+
[state.currentHandle]: { ...defaultFigure }
|
|
55230
|
+
}
|
|
55231
|
+
};
|
|
55232
|
+
}
|
|
55233
|
+
case "cla": {
|
|
55234
|
+
const fig = ensureFig(state);
|
|
55235
|
+
const prev = getAxes(fig);
|
|
55236
|
+
const cleared = action.reset ? { ...defaultAxes } : {
|
|
55237
|
+
...defaultAxes,
|
|
55238
|
+
title: prev.title,
|
|
55239
|
+
xlabel: prev.xlabel,
|
|
55240
|
+
ylabel: prev.ylabel,
|
|
55241
|
+
zlabel: prev.zlabel,
|
|
55242
|
+
gridOn: prev.gridOn,
|
|
55243
|
+
colorbar: prev.colorbar,
|
|
55244
|
+
colorbarLocation: prev.colorbarLocation,
|
|
55245
|
+
colormap: prev.colormap,
|
|
55246
|
+
colormapData: prev.colormapData,
|
|
55247
|
+
view: prev.view,
|
|
55248
|
+
axisMode: prev.axisMode,
|
|
55249
|
+
axisScale: prev.axisScale,
|
|
55250
|
+
caxis: prev.caxis,
|
|
55251
|
+
xlim: prev.xlim,
|
|
55252
|
+
ylim: prev.ylim,
|
|
55253
|
+
zlim: prev.zlim,
|
|
55254
|
+
yDir: prev.yDir,
|
|
55255
|
+
axisVisible: prev.axisVisible,
|
|
55256
|
+
shading: prev.shading
|
|
55257
|
+
};
|
|
55258
|
+
return {
|
|
55259
|
+
...state,
|
|
55260
|
+
figs: {
|
|
55261
|
+
...state.figs,
|
|
55262
|
+
[state.currentHandle]: setAxes(fig, cleared)
|
|
55263
|
+
}
|
|
55264
|
+
};
|
|
55265
|
+
}
|
|
55266
|
+
case "set_subplot": {
|
|
55267
|
+
const fig = ensureFig(state);
|
|
55268
|
+
const newFig = {
|
|
55269
|
+
...fig,
|
|
55270
|
+
subplotGrid: { rows: action.rows, cols: action.cols },
|
|
55271
|
+
currentAxesIndex: action.index
|
|
55272
|
+
};
|
|
55273
|
+
if (!newFig.axes[action.index]) {
|
|
55274
|
+
newFig.axes = { ...newFig.axes, [action.index]: { ...defaultAxes } };
|
|
55275
|
+
}
|
|
55276
|
+
return {
|
|
55277
|
+
...state,
|
|
55278
|
+
figs: { ...state.figs, [state.currentHandle]: newFig }
|
|
55279
|
+
};
|
|
55280
|
+
}
|
|
55281
|
+
default:
|
|
55282
|
+
return state;
|
|
55283
|
+
}
|
|
55284
|
+
};
|
|
55285
|
+
|
|
55286
|
+
// src/graphics/axisLimits.ts
|
|
55287
|
+
var EMPTY = { min: Infinity, max: -Infinity };
|
|
55288
|
+
function include(e, v) {
|
|
55289
|
+
if (Number.isFinite(v)) {
|
|
55290
|
+
if (v < e.min) e.min = v;
|
|
55291
|
+
if (v > e.max) e.max = v;
|
|
55292
|
+
}
|
|
55293
|
+
}
|
|
55294
|
+
function includeAll(e, vs) {
|
|
55295
|
+
if (!vs) return;
|
|
55296
|
+
for (let i = 0; i < vs.length; i++) include(e, vs[i]);
|
|
55297
|
+
}
|
|
55298
|
+
function axesIs3D(axes) {
|
|
55299
|
+
return (axes.surfTraces?.length ?? 0) > 0 || (axes.plot3Traces?.length ?? 0) > 0 || (axes.bar3Traces?.length ?? 0) > 0 || (axes.bar3hTraces?.length ?? 0) > 0 || (axes.quiver3Traces?.length ?? 0) > 0;
|
|
55300
|
+
}
|
|
55301
|
+
function dataExtents(axes) {
|
|
55302
|
+
const x = { ...EMPTY };
|
|
55303
|
+
const y = { ...EMPTY };
|
|
55304
|
+
const z = { ...EMPTY };
|
|
55305
|
+
for (const t of axes.traces ?? []) {
|
|
55306
|
+
includeAll(x, t.x);
|
|
55307
|
+
includeAll(y, t.y);
|
|
55308
|
+
}
|
|
55309
|
+
for (const t of axes.plot3Traces ?? []) {
|
|
55310
|
+
includeAll(x, t.x);
|
|
55311
|
+
includeAll(y, t.y);
|
|
55312
|
+
includeAll(z, t.z);
|
|
55313
|
+
}
|
|
55314
|
+
for (const t of [...axes.surfTraces ?? []]) {
|
|
55315
|
+
includeAll(x, t.x);
|
|
55316
|
+
includeAll(y, t.y);
|
|
55317
|
+
includeAll(z, t.z);
|
|
55318
|
+
}
|
|
55319
|
+
if (axes.imagescTrace) {
|
|
55320
|
+
include(x, axes.imagescTrace.x[0]);
|
|
55321
|
+
include(x, axes.imagescTrace.x[1]);
|
|
55322
|
+
include(y, axes.imagescTrace.y[0]);
|
|
55323
|
+
include(y, axes.imagescTrace.y[1]);
|
|
55324
|
+
}
|
|
55325
|
+
for (const t of axes.pcolorTraces ?? []) {
|
|
55326
|
+
includeAll(x, t.x);
|
|
55327
|
+
includeAll(y, t.y);
|
|
55328
|
+
}
|
|
55329
|
+
for (const t of axes.contourTraces ?? []) {
|
|
55330
|
+
includeAll(x, t.x);
|
|
55331
|
+
includeAll(y, t.y);
|
|
55332
|
+
}
|
|
55333
|
+
for (const bt of axes.barTraces ?? []) {
|
|
55334
|
+
const hw = bt.width / 2;
|
|
55335
|
+
for (let i = 0; i < bt.x.length; i++) {
|
|
55336
|
+
include(x, bt.x[i] - hw);
|
|
55337
|
+
include(x, bt.x[i] + hw);
|
|
55338
|
+
include(y, bt.y[i]);
|
|
55339
|
+
}
|
|
55340
|
+
include(y, 0);
|
|
55341
|
+
}
|
|
55342
|
+
for (const bt of axes.barhTraces ?? []) {
|
|
55343
|
+
const hh = bt.width / 2;
|
|
55344
|
+
for (let i = 0; i < bt.x.length; i++) {
|
|
55345
|
+
include(y, bt.x[i] - hh);
|
|
55346
|
+
include(y, bt.x[i] + hh);
|
|
55347
|
+
include(x, bt.y[i]);
|
|
55348
|
+
}
|
|
55349
|
+
include(x, 0);
|
|
55350
|
+
}
|
|
55351
|
+
for (const bt of [...axes.bar3Traces ?? [], ...axes.bar3hTraces ?? []]) {
|
|
55352
|
+
includeAll(x, bt.x);
|
|
55353
|
+
includeAll(y, bt.y);
|
|
55354
|
+
includeAll(z, bt.z);
|
|
55355
|
+
include(z, 0);
|
|
55356
|
+
}
|
|
55357
|
+
for (const et of axes.errorBarTraces ?? []) {
|
|
55358
|
+
for (let i = 0; i < et.x.length; i++) {
|
|
55359
|
+
include(x, et.xNeg ? et.x[i] - et.xNeg[i] : et.x[i]);
|
|
55360
|
+
include(x, et.xPos ? et.x[i] + et.xPos[i] : et.x[i]);
|
|
55361
|
+
include(y, et.y[i] - et.yNeg[i]);
|
|
55362
|
+
include(y, et.y[i] + et.yPos[i]);
|
|
55363
|
+
}
|
|
55364
|
+
}
|
|
55365
|
+
for (const bt of axes.boxTraces ?? []) {
|
|
55366
|
+
const hw = bt.width / 2;
|
|
55367
|
+
include(x, bt.x - hw);
|
|
55368
|
+
include(x, bt.x + hw);
|
|
55369
|
+
include(y, bt.whiskerLow);
|
|
55370
|
+
include(y, bt.whiskerHigh);
|
|
55371
|
+
for (const o of bt.outliers) include(y, o);
|
|
55372
|
+
}
|
|
55373
|
+
if (axes.areaTraces && axes.areaTraces.length > 0) {
|
|
55374
|
+
const base = axes.areaBaseValue ?? 0;
|
|
55375
|
+
include(y, base);
|
|
55376
|
+
const n = axes.areaTraces[0].x.length;
|
|
55377
|
+
for (let i = 0; i < n; i++) {
|
|
55378
|
+
let cum = base;
|
|
55379
|
+
for (const t of axes.areaTraces) {
|
|
55380
|
+
if (i < t.x.length) {
|
|
55381
|
+
include(x, t.x[i]);
|
|
55382
|
+
cum += t.y[i] - base;
|
|
55383
|
+
include(y, cum);
|
|
55384
|
+
}
|
|
55385
|
+
}
|
|
55386
|
+
}
|
|
55387
|
+
}
|
|
55388
|
+
for (const qt of axes.quiverTraces ?? []) {
|
|
55389
|
+
for (let i = 0; i < qt.x.length; i++) {
|
|
55390
|
+
include(x, qt.x[i]);
|
|
55391
|
+
include(x, qt.x[i] + qt.u[i]);
|
|
55392
|
+
include(y, qt.y[i]);
|
|
55393
|
+
include(y, qt.y[i] + qt.v[i]);
|
|
55394
|
+
}
|
|
55395
|
+
}
|
|
55396
|
+
for (const qt of axes.quiver3Traces ?? []) {
|
|
55397
|
+
for (let i = 0; i < qt.x.length; i++) {
|
|
55398
|
+
include(x, qt.x[i]);
|
|
55399
|
+
include(x, qt.x[i] + qt.u[i]);
|
|
55400
|
+
include(y, qt.y[i]);
|
|
55401
|
+
include(y, qt.y[i] + qt.v[i]);
|
|
55402
|
+
include(z, qt.z[i]);
|
|
55403
|
+
include(z, qt.z[i] + qt.w[i]);
|
|
55404
|
+
}
|
|
55405
|
+
}
|
|
55406
|
+
return { x, y, z };
|
|
55407
|
+
}
|
|
55408
|
+
function padExtent(e, tight) {
|
|
55409
|
+
if (!Number.isFinite(e.min) || !Number.isFinite(e.max)) return [0, 1];
|
|
55410
|
+
let { min: min2, max: max2 } = e;
|
|
55411
|
+
if (max2 === min2) {
|
|
55412
|
+
min2 -= 1;
|
|
55413
|
+
max2 += 1;
|
|
55414
|
+
return [min2, max2];
|
|
55415
|
+
}
|
|
55416
|
+
if (tight) return [min2, max2];
|
|
55417
|
+
const pad = (max2 - min2) * 0.05;
|
|
55418
|
+
return [min2 - pad, max2 + pad];
|
|
55419
|
+
}
|
|
55420
|
+
function applyExplicit(auto, explicit) {
|
|
55421
|
+
if (!explicit) return auto;
|
|
55422
|
+
return [explicit[0] ?? auto[0], explicit[1] ?? auto[1]];
|
|
55423
|
+
}
|
|
55424
|
+
function computeAxisLimits(axes) {
|
|
55425
|
+
const tight = axes.axisMode?.includes("tight") || axes.axisMode?.includes("image") ? true : false;
|
|
55426
|
+
const ext = dataExtents(axes);
|
|
55427
|
+
const xl = applyExplicit(padExtent(ext.x, tight), axes.xlim);
|
|
55428
|
+
const yl = applyExplicit(padExtent(ext.y, tight), axes.ylim);
|
|
55429
|
+
if (!axesIs3D(axes)) return [xl[0], xl[1], yl[0], yl[1]];
|
|
55430
|
+
const zl = applyExplicit(padExtent(ext.z, tight), axes.zlim);
|
|
55431
|
+
return [xl[0], xl[1], yl[0], yl[1], zl[0], zl[1]];
|
|
55432
|
+
}
|
|
55433
|
+
|
|
54353
55434
|
// src/numbl-core/runtime/runtime.ts
|
|
54354
55435
|
var Runtime = class _Runtime {
|
|
54355
55436
|
constructor(options, initialVariableValues) {
|
|
@@ -54571,6 +55652,18 @@ var Runtime = class _Runtime {
|
|
|
54571
55652
|
}
|
|
54572
55653
|
return RTV.dummyHandle();
|
|
54573
55654
|
};
|
|
55655
|
+
this.builtins["axis"] = (nargout, args) => {
|
|
55656
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
55657
|
+
const applied = applyAxisCommand(
|
|
55658
|
+
margs,
|
|
55659
|
+
this.plotInstructions,
|
|
55660
|
+
() => this.currentAxisLimits()
|
|
55661
|
+
);
|
|
55662
|
+
if (!applied && nargout >= 1) {
|
|
55663
|
+
return RTV.row(this.currentAxisLimits());
|
|
55664
|
+
}
|
|
55665
|
+
return void 0;
|
|
55666
|
+
};
|
|
54574
55667
|
this.builtins["fplot"] = (_nargout, args) => {
|
|
54575
55668
|
fplotCall(this, this.plotInstructions, args.map(ensureRuntimeValue));
|
|
54576
55669
|
};
|
|
@@ -55474,6 +56567,21 @@ var Runtime = class _Runtime {
|
|
|
55474
56567
|
ishold() {
|
|
55475
56568
|
return RTV.logical(this.holdState);
|
|
55476
56569
|
}
|
|
56570
|
+
/** Current axis limits of the active axes, as MATLAB's `axis` query
|
|
56571
|
+
* returns them: `[xmin xmax ymin ymax]` (2-D) or with `zmin zmax`
|
|
56572
|
+
* appended (3-D). Reduces the accumulated plot instructions into a figure
|
|
56573
|
+
* state and reads the current axes' explicit/data-derived limits. */
|
|
56574
|
+
currentAxisLimits() {
|
|
56575
|
+
let state = initialFiguresState;
|
|
56576
|
+
for (const instr of this.plotInstructions) {
|
|
56577
|
+
state = figuresReducer(state, instr);
|
|
56578
|
+
}
|
|
56579
|
+
const fig = state.figs[state.currentHandle];
|
|
56580
|
+
if (!fig) return [0, 1, 0, 1];
|
|
56581
|
+
const axes = fig.axes[fig.currentAxesIndex];
|
|
56582
|
+
if (!axes) return [0, 1, 0, 1];
|
|
56583
|
+
return computeAxisLimits(axes);
|
|
56584
|
+
}
|
|
55477
56585
|
// ── Drawnow / Pause ─────────────────────────────────────────────────
|
|
55478
56586
|
drawnow() {
|
|
55479
56587
|
return drawnow(this.plotInstructions, this.options);
|
|
@@ -59235,11 +60343,11 @@ function instantiateClass(className, args, nargout) {
|
|
|
59235
60343
|
} catch {
|
|
59236
60344
|
}
|
|
59237
60345
|
}
|
|
59238
|
-
const
|
|
60346
|
+
const isHandle3 = this.isHandleClass(classInfo);
|
|
59239
60347
|
const instance = RTV.classInstance(
|
|
59240
60348
|
className,
|
|
59241
60349
|
propertyNames,
|
|
59242
|
-
|
|
60350
|
+
isHandle3,
|
|
59243
60351
|
defaults
|
|
59244
60352
|
);
|
|
59245
60353
|
if (classInfo.constructorName) {
|
|
@@ -61291,7 +62399,7 @@ function isNumeric2(t) {
|
|
|
61291
62399
|
function isVoid(t) {
|
|
61292
62400
|
return t.kind === "Void";
|
|
61293
62401
|
}
|
|
61294
|
-
function
|
|
62402
|
+
function isHandle2(t) {
|
|
61295
62403
|
return t.kind === "Handle";
|
|
61296
62404
|
}
|
|
61297
62405
|
function isStruct(t) {
|
|
@@ -63821,6 +64929,15 @@ function mtoc2_tensor_flip_complex(a, dimIdx) {
|
|
|
63821
64929
|
return r;
|
|
63822
64930
|
}
|
|
63823
64931
|
|
|
64932
|
+
// src/numbl-core/jit/builtins/runtime/tensor_ops/tensor_imag_all_zero.js
|
|
64933
|
+
function mtoc2_tensor_imag_all_zero(a) {
|
|
64934
|
+
if (a.imag === void 0) return true;
|
|
64935
|
+
for (let i = 0; i < a.imag.length; i++) {
|
|
64936
|
+
if (a.imag[i] !== 0) return false;
|
|
64937
|
+
}
|
|
64938
|
+
return true;
|
|
64939
|
+
}
|
|
64940
|
+
|
|
63824
64941
|
// src/numbl-core/jit/builtins/runtime/tensor_ops/tensor_linspace.js
|
|
63825
64942
|
function mtoc2_tensor_linspace(a, b, n) {
|
|
63826
64943
|
if (n < 0) n = 0;
|
|
@@ -64122,6 +65239,13 @@ function cSqueezeTrailing(dims) {
|
|
|
64122
65239
|
function cReduceLaneIm(t, i) {
|
|
64123
65240
|
return t.imag !== void 0 ? t.imag[i] : 0;
|
|
64124
65241
|
}
|
|
65242
|
+
function cReduceAllImagZero(t) {
|
|
65243
|
+
if (t.imag === void 0) return true;
|
|
65244
|
+
for (let i = 0; i < t.imag.length; i++) {
|
|
65245
|
+
if (t.imag[i] !== 0) return false;
|
|
65246
|
+
}
|
|
65247
|
+
return true;
|
|
65248
|
+
}
|
|
64125
65249
|
function complexAccumAll(t, init, accum, finalize) {
|
|
64126
65250
|
let acc = { ...init };
|
|
64127
65251
|
for (let i = 0; i < t.data.length; i++) {
|
|
@@ -64179,6 +65303,7 @@ var mtoc2_prod_complex_dim = (t, d) => complexAccumDim(t, d, cProdInit, cProdAcc
|
|
|
64179
65303
|
var mtoc2_mean_complex_all = (t) => complexAccumAll(t, cSumInit, cSumAccum, cMeanFinalize);
|
|
64180
65304
|
var mtoc2_mean_complex_dim = (t, d) => complexAccumDim(t, d, cSumInit, cSumAccum, cMeanFinalize);
|
|
64181
65305
|
function complexMinmaxAll(t, cmp) {
|
|
65306
|
+
const realMode = cReduceAllImagZero(t);
|
|
64182
65307
|
let found = false;
|
|
64183
65308
|
let mRe = NaN;
|
|
64184
65309
|
let mIm = 0;
|
|
@@ -64186,7 +65311,8 @@ function complexMinmaxAll(t, cmp) {
|
|
|
64186
65311
|
const xr = t.data[i];
|
|
64187
65312
|
const xi = cReduceLaneIm(t, i);
|
|
64188
65313
|
if (xr !== xr || xi !== xi) continue;
|
|
64189
|
-
|
|
65314
|
+
const better = realMode ? cmp === "<" ? xr < mRe : xr > mRe : complexBetter(xr, xi, mRe, mIm, cmp);
|
|
65315
|
+
if (!found || better) {
|
|
64190
65316
|
mRe = xr;
|
|
64191
65317
|
mIm = xi;
|
|
64192
65318
|
found = true;
|
|
@@ -64209,6 +65335,7 @@ function complexMinmaxDim(t, dim, cmp) {
|
|
|
64209
65335
|
return out2;
|
|
64210
65336
|
}
|
|
64211
65337
|
const dimIdx = dim - 1;
|
|
65338
|
+
const realMode = cReduceAllImagZero(t);
|
|
64212
65339
|
const axis = t.shape[dimIdx];
|
|
64213
65340
|
let before = 1;
|
|
64214
65341
|
for (let i = 0; i < dimIdx; i++) before *= t.shape[i];
|
|
@@ -64229,7 +65356,8 @@ function complexMinmaxDim(t, dim, cmp) {
|
|
|
64229
65356
|
const xr = t.data[off];
|
|
64230
65357
|
const xi = cReduceLaneIm(t, off);
|
|
64231
65358
|
if (xr !== xr || xi !== xi) continue;
|
|
64232
|
-
|
|
65359
|
+
const better = realMode ? cmp === "<" ? xr < mRe : xr > mRe : complexBetter(xr, xi, mRe, mIm, cmp);
|
|
65360
|
+
if (!found || better) {
|
|
64233
65361
|
mRe = xr;
|
|
64234
65362
|
mIm = xi;
|
|
64235
65363
|
found = true;
|
|
@@ -64709,18 +65837,46 @@ function complex_sort_indices(a, descending) {
|
|
|
64709
65837
|
const n = a.data.length;
|
|
64710
65838
|
const im = a.imag;
|
|
64711
65839
|
const idx = new Array(n);
|
|
64712
|
-
|
|
65840
|
+
for (let i = 0; i < n; i++) idx[i] = i;
|
|
65841
|
+
let realMode = true;
|
|
65842
|
+
if (im !== void 0) {
|
|
65843
|
+
for (let i = 0; i < n; i++) {
|
|
65844
|
+
if (im[i] !== 0) {
|
|
65845
|
+
realMode = false;
|
|
65846
|
+
break;
|
|
65847
|
+
}
|
|
65848
|
+
}
|
|
65849
|
+
}
|
|
65850
|
+
if (realMode) {
|
|
65851
|
+
const re = a.data;
|
|
65852
|
+
idx.sort((p2, q) => {
|
|
65853
|
+
const rp = re[p2];
|
|
65854
|
+
const rq = re[q];
|
|
65855
|
+
const pNaN = rp !== rp;
|
|
65856
|
+
const qNaN = rq !== rq;
|
|
65857
|
+
if (pNaN && qNaN) return 0;
|
|
65858
|
+
if (descending) {
|
|
65859
|
+
if (pNaN) return -1;
|
|
65860
|
+
if (qNaN) return 1;
|
|
65861
|
+
return rp < rq ? 1 : rp > rq ? -1 : 0;
|
|
65862
|
+
}
|
|
65863
|
+
if (pNaN) return 1;
|
|
65864
|
+
if (qNaN) return -1;
|
|
65865
|
+
return rp < rq ? -1 : rp > rq ? 1 : 0;
|
|
65866
|
+
});
|
|
65867
|
+
return idx;
|
|
65868
|
+
}
|
|
65869
|
+
const mag2 = new Float64Array(n);
|
|
64713
65870
|
const ph = new Float64Array(n);
|
|
64714
65871
|
for (let i = 0; i < n; i++) {
|
|
64715
65872
|
const re = a.data[i];
|
|
64716
65873
|
const xi = im !== void 0 ? im[i] : 0;
|
|
64717
|
-
|
|
65874
|
+
mag2[i] = Math.hypot(re, xi);
|
|
64718
65875
|
ph[i] = Math.atan2(xi, re);
|
|
64719
|
-
idx[i] = i;
|
|
64720
65876
|
}
|
|
64721
65877
|
idx.sort((p2, q) => {
|
|
64722
|
-
if (
|
|
64723
|
-
if (
|
|
65878
|
+
if (mag2[p2] < mag2[q]) return descending ? 1 : -1;
|
|
65879
|
+
if (mag2[p2] > mag2[q]) return descending ? -1 : 1;
|
|
64724
65880
|
if (ph[p2] < ph[q]) return descending ? 1 : -1;
|
|
64725
65881
|
if (ph[p2] > ph[q]) return descending ? -1 : 1;
|
|
64726
65882
|
return p2 - q;
|
|
@@ -65986,6 +67142,7 @@ static void mtoc2__format_walk(mtoc2__writer_fn writer, void *ctx,
|
|
|
65986
67142
|
"tensor_fill_nd.h": "/* mtoc2 runtime helper: build an N-D tensor filled with `v`. Real\n * variant allocates a real tensor; complex variant takes `(re, im)`\n * and fills both lanes.\n *\n * Parameterized companion to `mtoc2_tensor_zeros_nd` / `_ones_nd`;\n * activated by the `nan` / `NaN` / `Inf` / `inf` shape-constructor\n * builtins (which would otherwise need their own per-constant fill\n * helpers) and by `repmat(scalar, ...)`. The returned tensor is\n * freshly owned.\n */\n\nstatic mtoc2_tensor_t mtoc2_tensor_fill_nd(double v, int ndim,\n const long *dims) {\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(ndim, dims);\n size_t n = 1;\n for (int i = 0; i < ndim; i++) n *= (size_t)out.dims[i];\n for (size_t i = 0; i < n; i++) out.real[i] = v;\n return out;\n}\n\nstatic mtoc2_tensor_t mtoc2_tensor_fill_nd_complex(double re, double im,\n int ndim,\n const long *dims) {\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(ndim, dims);\n size_t n = 1;\n for (int i = 0; i < ndim; i++) n *= (size_t)out.dims[i];\n for (size_t i = 0; i < n; i++) {\n out.real[i] = re;\n out.imag[i] = im;\n }\n return out;\n}\n",
|
|
65987
67143
|
"tensor_fill_square.h": "/* mtoc2 runtime helper: build an n\xD7n real tensor filled with `v`.\n *\n * Single-eval companion to `mtoc2_tensor_fill_nd` for the MATLAB\n * `nan(n)` / `Inf(n)` shorthand when `n` is a runtime expression.\n * See `mtoc2_tensor_zeros_square` for the rationale.\n */\n\nstatic mtoc2_tensor_t mtoc2_tensor_fill_square(double v, long n) {\n long dims[2] = {n, n};\n return mtoc2_tensor_fill_nd(v, 2, dims);\n}\n",
|
|
65988
67144
|
"tensor_flip.h": "/* mtoc2 runtime helper: `flip(t, dimIdx)` \u2014 return a freshly-owned\n * tensor with `t.real` mirrored along axis `dimIdx` (0-based).\n *\n * Numbl's reference is `flipAlongDim` in\n * `interpreter/builtins/array-manipulation.ts` line ~41. Same\n * column-major slab math: stride = product of dims below the axis,\n * outer = product of dims above. For each outer slab, we walk the\n * axis backwards on the source and forward on the destination,\n * copying `strideDim`-element contiguous blocks.\n *\n * `flipud(t)` lowers to `mtoc2_tensor_flip(t, 0)`; `fliplr(t)` to\n * `mtoc2_tensor_flip(t, 1)`; `flip(t, k)` to\n * `mtoc2_tensor_flip(t, k - 1)`. The `dimIdx` is 0-based at the C\n * boundary so the runtime stays uniform across the three source-\n * level builtins. mtoc2 codegen converts MATLAB's 1-based `k` to\n * 0-based at the call site.\n *\n * Out-of-range `dimIdx` (\u2265 ndim) is a no-op flip \u2014 numbl returns\n * the input unchanged in that case (the \"axis is size 1\" rule). We\n * still allocate a fresh copy so the owned-value invariant holds.\n *\n * `mtoc2_tensor_flip_complex` is the sibling that walks both lanes;\n * it tolerates `a.imag == NULL` (a real tensor that flowed in via a\n * complex-typed route) by zero-filling the output imag lane.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_flip(mtoc2_tensor_t a, long dimIdx) {\n long total = 1;\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i];\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)total * sizeof(double));\n r.imag = NULL;\n r.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i];\n\n long axisSize = (dimIdx >= 0 && dimIdx < (long)a.ndim) ? a.dims[dimIdx] : 1;\n // total==0 (empty along some axis) must short-circuit BEFORE the slab math:\n // if a dim below the axis is 0, slabSize becomes 0 and total/slabSize is a\n // 0/0 integer division (SIGILL). An empty result needs no copy anyway.\n if (axisSize <= 1 || total == 0) {\n // Nothing to flip \u2014 just deep-copy the buffer.\n if (total > 0) memcpy(r.real, a.real, (size_t)total * sizeof(double));\n return r;\n }\n\n long strideDim = 1;\n for (long d = 0; d < dimIdx; d++) strideDim *= a.dims[d];\n long slabSize = strideDim * axisSize;\n long numOuter = total / slabSize;\n\n for (long outer = 0; outer < numOuter; outer++) {\n long base = outer * slabSize;\n for (long k = 0; k < axisSize; k++) {\n long srcOff = base + k * strideDim;\n long dstOff = base + (axisSize - 1 - k) * strideDim;\n memcpy(\n r.real + dstOff,\n a.real + srcOff,\n (size_t)strideDim * sizeof(double)\n );\n }\n }\n return r;\n}\n\nstatic mtoc2_tensor_t mtoc2_tensor_flip_complex(mtoc2_tensor_t a, long dimIdx) {\n long total = 1;\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i];\n mtoc2_tensor_t r = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims);\n int srcHasImag = (a.imag != NULL);\n\n long axisSize = (dimIdx >= 0 && dimIdx < (long)a.ndim) ? a.dims[dimIdx] : 1;\n // See mtoc2_tensor_flip: total==0 must short-circuit before slab math to\n // avoid a 0/0 division when a dim below the axis is 0.\n if (axisSize <= 1 || total == 0) {\n if (total > 0) {\n memcpy(r.real, a.real, (size_t)total * sizeof(double));\n if (srcHasImag) {\n memcpy(r.imag, a.imag, (size_t)total * sizeof(double));\n } else {\n memset(r.imag, 0, (size_t)total * sizeof(double));\n }\n }\n return r;\n }\n\n if (!srcHasImag && total > 0) {\n memset(r.imag, 0, (size_t)total * sizeof(double));\n }\n\n long strideDim = 1;\n for (long d = 0; d < dimIdx; d++) strideDim *= a.dims[d];\n long slabSize = strideDim * axisSize;\n long numOuter = total / slabSize;\n\n for (long outer = 0; outer < numOuter; outer++) {\n long base = outer * slabSize;\n for (long k = 0; k < axisSize; k++) {\n long srcOff = base + k * strideDim;\n long dstOff = base + (axisSize - 1 - k) * strideDim;\n memcpy(r.real + dstOff, a.real + srcOff,\n (size_t)strideDim * sizeof(double));\n if (srcHasImag) {\n memcpy(r.imag + dstOff, a.imag + srcOff,\n (size_t)strideDim * sizeof(double));\n }\n }\n }\n return r;\n}\n",
|
|
67145
|
+
"tensor_imag_all_zero.h": "/* mtoc2 runtime helper: true (1.0) when a tensor carries no imaginary\n * content \u2014 NULL imag lane, or every imag element exactly zero. `isreal`\n * uses this for complex-typed tensors the JIT could not prove real at\n * compile time, reporting realness by value (matching the interpreter\n * and the complex-scalar `cimag(z) == 0` rule). Returns a logical double. */\n\nstatic double mtoc2_tensor_imag_all_zero(mtoc2_tensor_t a) {\n if (a.imag == NULL) return 1.0;\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n for (long i = 0; i < n; i++) {\n if (a.imag[i] != 0.0) return 0.0;\n }\n return 1.0;\n}\n",
|
|
65989
67146
|
"tensor_linspace.h": "/* mtoc2 runtime helper: build a 1\xD7n row tensor of n linearly-spaced\n * values from `a` to `b` inclusive. Matches numbl's `linspace` byte-\n * for-byte:\n *\n * - n <= 0 \u2192 1\xD70 empty tensor.\n * - n == 1 \u2192 just `[b]` (matches MATLAB; not the midpoint).\n * - n > 1 \u2192 first/last slots pinned at `a`/`b` exactly so a NaN\n * or Inf endpoint doesn't contaminate the other end;\n * inner values are `a + (b - a) * i / (n - 1)`.\n *\n * Opposite-sign infinite endpoints place 0 at the exact center for\n * odd n (e.g. `linspace(-Inf, Inf, 5)` \u2192 `[-Inf, ?, 0, ?, Inf]`).\n */\n\n#include <math.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_linspace(double a, double b, long n) {\n if (n < 0) n = 0;\n mtoc2_tensor_t out = mtoc2_tensor_alloc(1, n);\n if (n == 0) return out;\n if (n == 1) {\n out.real[0] = b;\n return out;\n }\n out.real[0] = a;\n out.real[n - 1] = b;\n for (long i = 1; i < n - 1; i++) {\n out.real[i] = a + (b - a) * (double)i / (double)(n - 1);\n }\n if ((n & 1) == 1 && !isfinite(a) && !isfinite(b)) {\n double sa = (a > 0) - (a < 0);\n double sb = (b > 0) - (b < 0);\n if (sa != sb) {\n out.real[(n - 1) / 2] = 0.0;\n }\n }\n return out;\n}\n",
|
|
65990
67147
|
"tensor_logical_mask.h": '/* mtoc2 runtime helper: logical-mask indexing support.\n *\n * `mtoc2_logical_mask_indices` scans `mask` column-major and fills\n * `out_indices` with the 0-based positions where the mask is truthy.\n * Each truthy position must be less than `axis_len`; otherwise this\n * aborts with a numbl-style "Index exceeds array bounds" message via\n * `mtoc2_oob_abort`. Returns the truthy count, which is also the\n * number of entries written into `out_indices`. `out_indices` must\n * have room for at least `mask.numel()` longs.\n *\n * `axis` is the axis number for the diagnostic (0-based) when this\n * helper is called for a per-axis slot (`M(:, mask)` \u2192 axis = 1), or\n * `-1` for the linear single-slot form (`a(mask)`).\n *\n * Used by both reads (`IndexSlice` with a `LogicalMask` slot) and\n * linear-form writes (`IndexSliceStore` with a single `LogicalMask`\n * slot). The caller allocates the index buffer with `mtoc2_alloc`,\n * passes it in, and frees it after the iteration that consumes it.\n */\n\nstatic long mtoc2_logical_mask_indices(\n mtoc2_tensor_t mask, long axis_len, int axis, const char *loc,\n long *out_indices\n) {\n long mask_n = 1;\n for (int d = 0; d < mask.ndim; d++) mask_n *= mask.dims[d];\n long count = 0;\n for (long i = 0; i < mask_n; i++) {\n if (mask.real[i] != 0.0) {\n if (i >= axis_len) {\n mtoc2_oob_abort(loc, axis, i + 1, 1, axis_len);\n }\n out_indices[count++] = i;\n }\n }\n return count;\n}\n',
|
|
65991
67148
|
"tensor_logical_real.h": '/* mtoc2 runtime helpers: elementwise logical ops on tensors.\n *\n * Same allocate-and-fill pattern as tensor_unary_real_math.h, but the\n * per-element kernel is a logical predicate that returns 0.0 or 1.0.\n *\n * `mtoc2_tensor_not` mirrors numbl\'s `not(v)` (runtimeOperators.ts):\n * a real-tensor input produces a freshly-owned logical-typed tensor\n * of the same shape with `out[i] = (in[i] == 0.0) ? 1.0 : 0.0`. The\n * complex sibling fires "true" iff both lanes are exactly zero. The\n * result is a real (logical-typed) tensor in both cases \u2014 the type\n * system records `elem: "logical"` so disp / downstream consumers\n * know how to interpret the doubles.\n */\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_not(mtoc2_tensor_t a) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)n * sizeof(double));\n r.imag = NULL;\n r.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i];\n for (long i = 0; i < n; i++) r.real[i] = (a.real[i] == 0.0) ? 1.0 : 0.0;\n return r;\n}\n\nstatic mtoc2_tensor_t mtoc2_tensor_not_complex(mtoc2_tensor_t a) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)n * sizeof(double));\n r.imag = NULL;\n r.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i];\n int srcHasImag = (a.imag != NULL);\n for (long i = 0; i < n; i++) {\n double re = a.real[i];\n double im = srcHasImag ? a.imag[i] : 0.0;\n r.real[i] = (re == 0.0 && im == 0.0) ? 1.0 : 0.0;\n }\n return r;\n}\n',
|
|
@@ -65997,13 +67154,13 @@ static void mtoc2__format_walk(mtoc2__writer_fn writer, void *ctx,
|
|
|
65997
67154
|
"tensor_ones_nd.h": "/* mtoc2 runtime helper: build a real N-D tensor filled with ones.\n *\n * Allocates via `mtoc2_tensor_alloc_nd`, then fills the `real` buffer\n * with `1.0` via a plain element loop (`memset` only works for byte\n * patterns; `1.0` is not such a pattern). The returned tensor is\n * freshly owned; `imag` is NULL.\n */\n\nstatic mtoc2_tensor_t mtoc2_tensor_ones_nd(int ndim, const long *dims) {\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(ndim, dims);\n size_t n = 1;\n for (int i = 0; i < ndim; i++) n *= (size_t)out.dims[i];\n for (size_t i = 0; i < n; i++) out.real[i] = 1.0;\n return out;\n}\n",
|
|
65998
67155
|
"tensor_ones_square.h": "/* mtoc2 runtime helper: build an n\xD7n real tensor filled with ones.\n *\n * Single-eval companion to `mtoc2_tensor_ones_nd` for the MATLAB\n * `ones(n)` shorthand when `n` is a runtime expression. See the\n * `mtoc2_tensor_zeros_square` header for the rationale.\n */\n\nstatic mtoc2_tensor_t mtoc2_tensor_ones_square(long n) {\n long dims[2] = {n, n};\n return mtoc2_tensor_ones_nd(2, dims);\n}\n",
|
|
65999
67156
|
"tensor_predicate.h": "/* mtoc2 runtime helpers: elementwise tensor \u2192 logical-tensor\n * predicates (`isnan`, `isinf`, `isfinite`, `logical`). Same\n * allocate-and-fill shape as `tensor_unary_real_math.h`; each element\n * maps to 1.0 / 0.0. The result is logical at the source level (the\n * buffer is the usual Float64 lane, `imag == NULL`).\n *\n * The `_complex` siblings operate per-element on `(re, im)`; for\n * `isnan` / `isinf` the predicate fires if either component\n * triggers, for `isfinite` both must be finite. They tolerate\n * `a.imag == NULL` (a real tensor that flowed through a\n * complex-typed route) by treating the imag input as zero.\n */\n#include <math.h>\n#include <stdlib.h>\n\n#define MTOC2_DEFINE_UNARY_PRED(name, EXPR) \\\n static mtoc2_tensor_t name(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n mtoc2_tensor_t r; \\\n r.real = mtoc2_alloc((size_t)n * sizeof(double)); \\\n r.imag = NULL; \\\n r.ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i]; \\\n MTOC2_OMP_PARFOR_N \\\n for (long i = 0; i < n; i++) { \\\n double x = a.real[i]; \\\n r.real[i] = (EXPR) ? 1.0 : 0.0; \\\n } \\\n return r; \\\n }\n\nMTOC2_DEFINE_UNARY_PRED(mtoc2_tensor_isnan, isnan(x))\nMTOC2_DEFINE_UNARY_PRED(mtoc2_tensor_logical, x != 0.0)\nMTOC2_DEFINE_UNARY_PRED(mtoc2_tensor_isinf, isinf(x))\nMTOC2_DEFINE_UNARY_PRED(mtoc2_tensor_isfinite, isfinite(x))\n\n#undef MTOC2_DEFINE_UNARY_PRED\n\n#define MTOC2_DEFINE_UNARY_PRED_COMPLEX(name, EXPR) \\\n static mtoc2_tensor_t name(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n mtoc2_tensor_t r; \\\n r.real = mtoc2_alloc((size_t)n * sizeof(double)); \\\n r.imag = NULL; \\\n r.ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i]; \\\n MTOC2_OMP_PARFOR_N \\\n for (long i = 0; i < n; i++) { \\\n double re = a.real[i]; \\\n double im = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n r.real[i] = (EXPR) ? 1.0 : 0.0; \\\n } \\\n return r; \\\n }\n\nMTOC2_DEFINE_UNARY_PRED_COMPLEX(mtoc2_tensor_isnan_complex,\n isnan(re) || isnan(im))\nMTOC2_DEFINE_UNARY_PRED_COMPLEX(mtoc2_tensor_isinf_complex,\n isinf(re) || isinf(im))\nMTOC2_DEFINE_UNARY_PRED_COMPLEX(mtoc2_tensor_isfinite_complex,\n isfinite(re) && isfinite(im))\n\n#undef MTOC2_DEFINE_UNARY_PRED_COMPLEX\n",
|
|
66000
|
-
"tensor_reduce_complex.h": '/* mtoc2 runtime helpers: complex-tensor reductions.\n *\n * Sibling of `tensor_reduce_real.h`. Same `_all` / `_dim` shape per\n * op; each kernel walks both lanes and builds intermediate\n * `double _Complex` values through `mtoc2_cmake` / `mtoc2_c*` so the\n * c2js backend can translate the bodies straight (no bare\n * `<complex.h>` operators).\n *\n * Result types per op:\n * sum / prod / mean \u2192 complex (lane-pair accumulator)\n * min / max \u2192 complex (magnitude compare, atan2\n * tiebreak \u2014 matches numbl\'s\n * `complexIsBetter`)\n * any / all \u2192 real (toBool: `re != 0 || im != 0`,\n * then aggregate via OR/AND)\n *\n * Input tolerance: `imag == NULL` (a real tensor flowing in through\n * a complex-typed route) is treated as zero on every cell.\n *\n * `_all` returns a `double _Complex` for the numeric reducers and a\n * `double` for the logical reducers. `_dim` returns a freshly-owned\n * complex tensor (numeric reducers) or a real tensor (logical\n * reducers) of the reduced shape \u2014 same trailing-singleton squeeze\n * rule as the real helper.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* Shared with the real helper; defined inline here so this file is\n * standalone-includable (the runtime activator may pull the complex\n * snippet in independently of the real one). */\nstatic void mtoc2__squeeze_trailing_c(int *ndim, long *dims) {\n while (*ndim > 2 && dims[*ndim - 1] == 1) {\n (*ndim)--;\n }\n}\n\n/* Numeric (sum/prod/mean) reduction template \u2014 complex accumulator. */\n#define MTOC2_DEFINE_CACCUM_REDUCTION(name, INIT, ACCUM, FINALIZE) \\\n static double _Complex mtoc2_##name##_complex_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n double _Complex acc = (INIT); \\\n for (long i = 0; i < n; i++) { \\\n double aim = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n double _Complex x = mtoc2_cmake(a.real[i], aim); \\\n acc = ACCUM(acc, x); \\\n } \\\n return FINALIZE(acc, n); \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_complex_dim( \\\n mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_complex_dim: dim must be >= 1 (got %d)\\n", dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims); \\\n memcpy(out.real, a.real, (size_t)total * sizeof(double)); \\\n if (a.imag != NULL) { \\\n memcpy(out.imag, a.imag, (size_t)total * sizeof(double)); \\\n } else { \\\n memset(out.imag, 0, (size_t)total * sizeof(double)); \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing_c(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double _Complex acc = (INIT); \\\n for (long k = 0; k < axis; k++) { \\\n long off = slabBase + inner + k * before; \\\n double aim = (a.imag != NULL) ? a.imag[off] : 0.0; \\\n double _Complex x = mtoc2_cmake(a.real[off], aim); \\\n acc = ACCUM(acc, x); \\\n } \\\n double _Complex fin = FINALIZE(acc, axis); \\\n long dst = outer * before + inner; \\\n out.real[dst] = mtoc2_creal(fin); \\\n out.imag[dst] = mtoc2_cimag(fin); \\\n } \\\n } \\\n return out; \\\n }\n\n/* min/max template \u2014 complex compare via magnitude + atan2 tiebreak.\n * NaN-skip on either lane. Accumulator seed is NaN+NaN; first non-\n * NaN element captures, later non-NaN elements compare. */\n#define MTOC2_DEFINE_CMINMAX_REDUCTION(name, CMP) \\\n static int mtoc2__##name##_complex_better( \\\n double aRe, double aIm, double bRe, double bIm) { \\\n double absA = hypot(aRe, aIm); \\\n double absB = hypot(bRe, bIm); \\\n if (absA != absB) return absA CMP absB; \\\n return atan2(aIm, aRe) CMP atan2(bIm, bRe); \\\n } \\\n static double _Complex mtoc2_##name##_complex_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n int found = 0; \\\n double mRe = NAN, mIm = 0.0; \\\n for (long i = 0; i < n; i++) { \\\n double xr = a.real[i]; \\\n double xi = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n if (xr != xr || xi != xi) continue; \\\n if (!found || mtoc2__##name##_complex_better(xr, xi, mRe, mIm)) { \\\n mRe = xr; \\\n mIm = xi; \\\n found = 1; \\\n } \\\n } \\\n return mtoc2_cmake(mRe, mIm); \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_complex_dim( \\\n mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_complex_dim: dim must be >= 1 (got %d)\\n", dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims); \\\n memcpy(out.real, a.real, (size_t)total * sizeof(double)); \\\n if (a.imag != NULL) { \\\n memcpy(out.imag, a.imag, (size_t)total * sizeof(double)); \\\n } else { \\\n memset(out.imag, 0, (size_t)total * sizeof(double)); \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing_c(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n int found = 0; \\\n double mRe = NAN, mIm = 0.0; \\\n for (long k = 0; k < axis; k++) { \\\n long off = slabBase + inner + k * before; \\\n double xr = a.real[off]; \\\n double xi = (a.imag != NULL) ? a.imag[off] : 0.0; \\\n if (xr != xr || xi != xi) continue; \\\n if (!found || mtoc2__##name##_complex_better(xr, xi, mRe, mIm)) { \\\n mRe = xr; \\\n mIm = xi; \\\n found = 1; \\\n } \\\n } \\\n long dst = outer * before + inner; \\\n out.real[dst] = mRe; \\\n out.imag[dst] = mIm; \\\n } \\\n } \\\n return out; \\\n }\n\n/* any/all template \u2014 real result; toBool per element (either lane\n * nonzero). Mirrors `MTOC2_DEFINE_LOGICAL_REDUCTION` shape. */\n#define MTOC2_DEFINE_CLOGICAL_REDUCTION(name, EMPTY_RESULT, SHORT_BODY) \\\n static double mtoc2_##name##_complex_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n if (n == 0) return (double)(EMPTY_RESULT); \\\n double acc = (double)(EMPTY_RESULT); \\\n for (long i = 0; i < n; i++) { \\\n double xr = a.real[i]; \\\n double xi = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n int x = (xr != 0.0 || xi != 0.0); \\\n SHORT_BODY; \\\n } \\\n return acc; \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_complex_dim( \\\n mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_complex_dim: dim must be >= 1 (got %d)\\n", dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n for (long i = 0; i < total; i++) { \\\n double xr = a.real[i]; \\\n double xi = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n out.real[i] = (xr != 0.0 || xi != 0.0) ? 1.0 : 0.0; \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing_c(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double acc = (double)(EMPTY_RESULT); \\\n for (long k = 0; k < axis; k++) { \\\n long off = slabBase + inner + k * before; \\\n double xr = a.real[off]; \\\n double xi = (a.imag != NULL) ? a.imag[off] : 0.0; \\\n int x = (xr != 0.0 || xi != 0.0); \\\n SHORT_BODY; \\\n } \\\n out.real[outer * before + inner] = acc; \\\n } \\\n } \\\n return out; \\\n }\n\n/* Accumulator-statement macros. */\n#define MTOC2_CACC_SUM(acc, x) mtoc2_cadd((acc), (x))\n#define MTOC2_CACC_PROD(acc, x) mtoc2_cmul((acc), (x))\n#define MTOC2_CFIN_ID(acc, n) (acc)\n#define MTOC2_CFIN_MEAN(acc, n) mtoc2_cdiv((acc), mtoc2_cmake((double)(n), 0.0))\n\nMTOC2_DEFINE_CACCUM_REDUCTION(sum, mtoc2_cmake(0.0, 0.0), MTOC2_CACC_SUM, MTOC2_CFIN_ID)\nMTOC2_DEFINE_CACCUM_REDUCTION(prod, mtoc2_cmake(1.0, 0.0), MTOC2_CACC_PROD, MTOC2_CFIN_ID)\nMTOC2_DEFINE_CACCUM_REDUCTION(mean, mtoc2_cmake(0.0, 0.0), MTOC2_CACC_SUM, MTOC2_CFIN_MEAN)\n\nMTOC2_DEFINE_CMINMAX_REDUCTION(min, <)\nMTOC2_DEFINE_CMINMAX_REDUCTION(max, >)\n\nMTOC2_DEFINE_CLOGICAL_REDUCTION(any, 0,\n if (x) { acc = 1.0; break; })\nMTOC2_DEFINE_CLOGICAL_REDUCTION(all, 1,\n if (!x) { acc = 0.0; break; })\n',
|
|
67157
|
+
"tensor_reduce_complex.h": '/* mtoc2 runtime helpers: complex-tensor reductions.\n *\n * Sibling of `tensor_reduce_real.h`. Same `_all` / `_dim` shape per\n * op; each kernel walks both lanes and builds intermediate\n * `double _Complex` values through `mtoc2_cmake` / `mtoc2_c*` so the\n * c2js backend can translate the bodies straight (no bare\n * `<complex.h>` operators).\n *\n * Result types per op:\n * sum / prod / mean \u2192 complex (lane-pair accumulator)\n * min / max \u2192 complex (magnitude compare, atan2\n * tiebreak \u2014 matches numbl\'s\n * `complexIsBetter`)\n * any / all \u2192 real (toBool: `re != 0 || im != 0`,\n * then aggregate via OR/AND)\n *\n * Input tolerance: `imag == NULL` (a real tensor flowing in through\n * a complex-typed route) is treated as zero on every cell.\n *\n * `_all` returns a `double _Complex` for the numeric reducers and a\n * `double` for the logical reducers. `_dim` returns a freshly-owned\n * complex tensor (numeric reducers) or a real tensor (logical\n * reducers) of the reduced shape \u2014 same trailing-singleton squeeze\n * rule as the real helper.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* Shared with the real helper; defined inline here so this file is\n * standalone-includable (the runtime activator may pull the complex\n * snippet in independently of the real one). */\nstatic void mtoc2__squeeze_trailing_c(int *ndim, long *dims) {\n while (*ndim > 2 && dims[*ndim - 1] == 1) {\n (*ndim)--;\n }\n}\n\n/* Numeric (sum/prod/mean) reduction template \u2014 complex accumulator. */\n#define MTOC2_DEFINE_CACCUM_REDUCTION(name, INIT, ACCUM, FINALIZE) \\\n static double _Complex mtoc2_##name##_complex_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n double _Complex acc = (INIT); \\\n for (long i = 0; i < n; i++) { \\\n double aim = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n double _Complex x = mtoc2_cmake(a.real[i], aim); \\\n acc = ACCUM(acc, x); \\\n } \\\n return FINALIZE(acc, n); \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_complex_dim( \\\n mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_complex_dim: dim must be >= 1 (got %d)\\n", dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims); \\\n memcpy(out.real, a.real, (size_t)total * sizeof(double)); \\\n if (a.imag != NULL) { \\\n memcpy(out.imag, a.imag, (size_t)total * sizeof(double)); \\\n } else { \\\n memset(out.imag, 0, (size_t)total * sizeof(double)); \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing_c(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double _Complex acc = (INIT); \\\n for (long k = 0; k < axis; k++) { \\\n long off = slabBase + inner + k * before; \\\n double aim = (a.imag != NULL) ? a.imag[off] : 0.0; \\\n double _Complex x = mtoc2_cmake(a.real[off], aim); \\\n acc = ACCUM(acc, x); \\\n } \\\n double _Complex fin = FINALIZE(acc, axis); \\\n long dst = outer * before + inner; \\\n out.real[dst] = mtoc2_creal(fin); \\\n out.imag[dst] = mtoc2_cimag(fin); \\\n } \\\n } \\\n return out; \\\n }\n\n/* True when the tensor carries no imaginary content (NULL lane or every\n * element zero). Such a tensor is real in value \u2014 min/max must order by\n * value, not magnitude, to match the interpreter and MATLAB on real data. */\nstatic int mtoc2__creduce_all_imag_zero(mtoc2_tensor_t a) {\n if (a.imag == NULL) return 1;\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n for (long i = 0; i < n; i++) {\n if (a.imag[i] != 0.0) return 0;\n }\n return 1;\n}\n\n/* min/max template \u2014 complex compare via magnitude + atan2 tiebreak.\n * When the whole tensor is real (all-zero imag) we order by value\n * instead. NaN-skip on either lane. Accumulator seed is NaN+NaN; first\n * non-NaN element captures, later non-NaN elements compare. */\n#define MTOC2_DEFINE_CMINMAX_REDUCTION(name, CMP) \\\n static int mtoc2__##name##_complex_better( \\\n double aRe, double aIm, double bRe, double bIm) { \\\n double absA = hypot(aRe, aIm); \\\n double absB = hypot(bRe, bIm); \\\n if (absA != absB) return absA CMP absB; \\\n return atan2(aIm, aRe) CMP atan2(bIm, bRe); \\\n } \\\n static double _Complex mtoc2_##name##_complex_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n int realMode = mtoc2__creduce_all_imag_zero(a); \\\n int found = 0; \\\n double mRe = NAN, mIm = 0.0; \\\n for (long i = 0; i < n; i++) { \\\n double xr = a.real[i]; \\\n double xi = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n if (xr != xr || xi != xi) continue; \\\n int better = realMode ? (xr CMP mRe) \\\n : mtoc2__##name##_complex_better(xr, xi, mRe, mIm); \\\n if (!found || better) { \\\n mRe = xr; \\\n mIm = xi; \\\n found = 1; \\\n } \\\n } \\\n return mtoc2_cmake(mRe, mIm); \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_complex_dim( \\\n mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_complex_dim: dim must be >= 1 (got %d)\\n", dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims); \\\n memcpy(out.real, a.real, (size_t)total * sizeof(double)); \\\n if (a.imag != NULL) { \\\n memcpy(out.imag, a.imag, (size_t)total * sizeof(double)); \\\n } else { \\\n memset(out.imag, 0, (size_t)total * sizeof(double)); \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing_c(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(out_ndim, out_dims); \\\n long slab = before * axis; \\\n int realMode = mtoc2__creduce_all_imag_zero(a); \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n int found = 0; \\\n double mRe = NAN, mIm = 0.0; \\\n for (long k = 0; k < axis; k++) { \\\n long off = slabBase + inner + k * before; \\\n double xr = a.real[off]; \\\n double xi = (a.imag != NULL) ? a.imag[off] : 0.0; \\\n if (xr != xr || xi != xi) continue; \\\n int better = realMode ? (xr CMP mRe) \\\n : mtoc2__##name##_complex_better(xr, xi, mRe, mIm); \\\n if (!found || better) { \\\n mRe = xr; \\\n mIm = xi; \\\n found = 1; \\\n } \\\n } \\\n long dst = outer * before + inner; \\\n out.real[dst] = mRe; \\\n out.imag[dst] = mIm; \\\n } \\\n } \\\n return out; \\\n }\n\n/* any/all template \u2014 real result; toBool per element (either lane\n * nonzero). Mirrors `MTOC2_DEFINE_LOGICAL_REDUCTION` shape. */\n#define MTOC2_DEFINE_CLOGICAL_REDUCTION(name, EMPTY_RESULT, SHORT_BODY) \\\n static double mtoc2_##name##_complex_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n if (n == 0) return (double)(EMPTY_RESULT); \\\n double acc = (double)(EMPTY_RESULT); \\\n for (long i = 0; i < n; i++) { \\\n double xr = a.real[i]; \\\n double xi = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n int x = (xr != 0.0 || xi != 0.0); \\\n SHORT_BODY; \\\n } \\\n return acc; \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_complex_dim( \\\n mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_complex_dim: dim must be >= 1 (got %d)\\n", dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n for (long i = 0; i < total; i++) { \\\n double xr = a.real[i]; \\\n double xi = (a.imag != NULL) ? a.imag[i] : 0.0; \\\n out.real[i] = (xr != 0.0 || xi != 0.0) ? 1.0 : 0.0; \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing_c(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double acc = (double)(EMPTY_RESULT); \\\n for (long k = 0; k < axis; k++) { \\\n long off = slabBase + inner + k * before; \\\n double xr = a.real[off]; \\\n double xi = (a.imag != NULL) ? a.imag[off] : 0.0; \\\n int x = (xr != 0.0 || xi != 0.0); \\\n SHORT_BODY; \\\n } \\\n out.real[outer * before + inner] = acc; \\\n } \\\n } \\\n return out; \\\n }\n\n/* Accumulator-statement macros. */\n#define MTOC2_CACC_SUM(acc, x) mtoc2_cadd((acc), (x))\n#define MTOC2_CACC_PROD(acc, x) mtoc2_cmul((acc), (x))\n#define MTOC2_CFIN_ID(acc, n) (acc)\n#define MTOC2_CFIN_MEAN(acc, n) mtoc2_cdiv((acc), mtoc2_cmake((double)(n), 0.0))\n\nMTOC2_DEFINE_CACCUM_REDUCTION(sum, mtoc2_cmake(0.0, 0.0), MTOC2_CACC_SUM, MTOC2_CFIN_ID)\nMTOC2_DEFINE_CACCUM_REDUCTION(prod, mtoc2_cmake(1.0, 0.0), MTOC2_CACC_PROD, MTOC2_CFIN_ID)\nMTOC2_DEFINE_CACCUM_REDUCTION(mean, mtoc2_cmake(0.0, 0.0), MTOC2_CACC_SUM, MTOC2_CFIN_MEAN)\n\nMTOC2_DEFINE_CMINMAX_REDUCTION(min, <)\nMTOC2_DEFINE_CMINMAX_REDUCTION(max, >)\n\nMTOC2_DEFINE_CLOGICAL_REDUCTION(any, 0,\n if (x) { acc = 1.0; break; })\nMTOC2_DEFINE_CLOGICAL_REDUCTION(all, 1,\n if (!x) { acc = 0.0; break; })\n',
|
|
66001
67158
|
"tensor_reduce_real.h": '/* mtoc2 runtime helpers: real-tensor reductions.\n *\n * One macro per op generates two helpers:\n *\n * mtoc2_<name>_all(a) \u2014 reduce every element to a scalar.\n * mtoc2_<name>_dim(a, dim) \u2014 reduce along the 1-based axis `dim`,\n * returning a freshly-owned tensor.\n *\n * The `_dim` template mirrors numbl\'s `forEachSlice`: compute\n * `before = prod(dims[0..dim-2])`, `axis = dims[dim-1]`,\n * `after = prod(dims[dim..ndim-1])`. Walk the column-major buffer in\n * `(after \xD7 before)` fiber order with stride `before` between\n * elements along the reduced axis. Output dims are the input dims\n * with `dims[dim-1] = 1`, then trailing singletons stripped subject\n * to a 2-axis floor (matches the type system\'s\n * `tensorDoubleFromDims` rule).\n *\n * If `dim > a.ndim` the runtime emits a per-op no-op: every reducer\n * (sum/prod/mean/min/max) copies `a` as-is; the logical reducers\n * (any/all) emit an elementwise cast to {0, 1}. The transfer step\n * already proved the output shape, so this branch only fires when\n * the type-side dim/shape analysis can\'t fold to AxisAll.\n *\n * Real-only \u2014 complex is out of scope. Same-shape and column-major\n * conventions match the rest of mtoc2\'s tensor runtime.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* Strip trailing singleton axes down to a 2-axis floor. Updates\n * `*ndim` in place; `dims` is the row buffer. */\nstatic void mtoc2__squeeze_trailing(int *ndim, long *dims) {\n while (*ndim > 2 && dims[*ndim - 1] == 1) {\n (*ndim)--;\n }\n}\n\n/* Helper: reduce-all loop for accumulator-based reducers\n * (sum, prod, mean). `INIT` seeds the accumulator; `ACCUM(acc, x)`\n * is a C statement updating `acc`; `FINALIZE(acc, n)` is the final\n * transformation given the count. */\n#define MTOC2_DEFINE_ACCUM_REDUCTION(name, INIT, ACCUM, FINALIZE) \\\n static double mtoc2_##name##_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n double acc = (INIT); \\\n for (long i = 0; i < n; i++) { \\\n double x = a.real[i]; \\\n ACCUM(acc, x); \\\n } \\\n return FINALIZE(acc, n); \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_dim(mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_dim: dim must be >= 1 (got %d)\\n", \\\n dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n /* No-op axis: output is same shape/data as input (fresh copy). */ \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n mtoc2_tensor_t out; \\\n out.ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out.dims[i] = a.dims[i]; \\\n out.real = mtoc2_alloc((size_t)total * sizeof(double)); \\\n out.imag = NULL; \\\n memcpy(out.real, a.real, (size_t)total * sizeof(double)); \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_total = before * after; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double acc = (INIT); \\\n for (long k = 0; k < axis; k++) { \\\n double x = a.real[slabBase + inner + k * before]; \\\n ACCUM(acc, x); \\\n } \\\n out.real[outer * before + inner] = FINALIZE(acc, axis); \\\n } \\\n } \\\n (void)out_total; \\\n return out; \\\n }\n\n/* Helper: reduce-all loop for min/max. Seed is NaN; first non-NaN\n * element captures, later non-NaN elements compare via CMP.\n * Mirrors numbl\'s NaN-skip convention. */\n#define MTOC2_DEFINE_MINMAX_REDUCTION(name, CMP) \\\n static double mtoc2_##name##_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n double acc = NAN; \\\n for (long i = 0; i < n; i++) { \\\n double x = a.real[i]; \\\n if (x != x) continue; /* skip NaN */ \\\n if (acc != acc || (x CMP acc)) acc = x; \\\n } \\\n return acc; \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_dim(mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_dim: dim must be >= 1 (got %d)\\n", \\\n dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n mtoc2_tensor_t out; \\\n out.ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out.dims[i] = a.dims[i]; \\\n out.real = mtoc2_alloc((size_t)total * sizeof(double)); \\\n out.imag = NULL; \\\n memcpy(out.real, a.real, (size_t)total * sizeof(double)); \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double acc = NAN; \\\n for (long k = 0; k < axis; k++) { \\\n double x = a.real[slabBase + inner + k * before]; \\\n if (x != x) continue; \\\n if (acc != acc || (x CMP acc)) acc = x; \\\n } \\\n out.real[outer * before + inner] = acc; \\\n } \\\n } \\\n return out; \\\n }\n\n/* Helper: any/all reduction. Short-circuits per fiber.\n * `EMPTY_RESULT` is the value when the reduced fiber is empty:\n * - any: 0 (no element is nonzero in an empty set)\n * - all: 1 (vacuously true)\n * `SHORT(acc, x)` updates `acc` if `x` triggers the short-circuit;\n * `done` short-circuits the inner loop once `acc` settles. */\n#define MTOC2_DEFINE_LOGICAL_REDUCTION(name, EMPTY_RESULT, SHORT_BODY) \\\n static double mtoc2_##name##_all(mtoc2_tensor_t a) { \\\n long n = 1; \\\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i]; \\\n if (n == 0) return (double)(EMPTY_RESULT); \\\n double acc = (double)(EMPTY_RESULT); \\\n for (long i = 0; i < n; i++) { \\\n double x = a.real[i]; \\\n SHORT_BODY; \\\n } \\\n return acc; \\\n } \\\n \\\n static mtoc2_tensor_t mtoc2_##name##_dim(mtoc2_tensor_t a, int dim) { \\\n if (dim < 1) { \\\n fprintf(stderr, "mtoc2: " #name "_dim: dim must be >= 1 (got %d)\\n", \\\n dim); \\\n abort(); \\\n } \\\n if (dim > a.ndim) { \\\n /* Numbl\'s `logicalAlongDim` with `dim > ndims` does an elementwise \\\n * cast to logical: each element becomes 1.0 if nonzero else 0.0. */ \\\n long total = 1; \\\n for (int i = 0; i < a.ndim; i++) total *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n for (long i = 0; i < total; i++) { \\\n out.real[i] = (a.real[i] != 0.0) ? 1.0 : 0.0; \\\n } \\\n return out; \\\n } \\\n int dimIdx = dim - 1; \\\n long axis = a.dims[dimIdx]; \\\n long before = 1; \\\n for (int i = 0; i < dimIdx; i++) before *= a.dims[i]; \\\n long after = 1; \\\n for (int i = dimIdx + 1; i < a.ndim; i++) after *= a.dims[i]; \\\n long out_dims[MTOC2_MAX_NDIM]; \\\n int out_ndim = a.ndim; \\\n for (int i = 0; i < a.ndim; i++) out_dims[i] = a.dims[i]; \\\n out_dims[dimIdx] = 1; \\\n mtoc2__squeeze_trailing(&out_ndim, out_dims); \\\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, out_dims); \\\n long slab = before * axis; \\\n for (long outer = 0; outer < after; outer++) { \\\n long slabBase = outer * slab; \\\n for (long inner = 0; inner < before; inner++) { \\\n double acc = (double)(EMPTY_RESULT); \\\n for (long k = 0; k < axis; k++) { \\\n double x = a.real[slabBase + inner + k * before]; \\\n SHORT_BODY; \\\n } \\\n out.real[outer * before + inner] = acc; \\\n } \\\n } \\\n return out; \\\n }\n\n/* Identity finalizer (sum, prod): pass the accumulator through. */\n#define MTOC2_FIN_ID(acc, n) (acc)\n/* Mean finalizer: divide by element count. Empty fiber \u2192 0/0 = NaN. */\n#define MTOC2_FIN_MEAN(acc, n) ((double)(acc) / (double)(n))\n\n/* Accumulator-statement macros. Wrapped in `do {} while(0)` to keep\n * them safe inside any single-statement context the templates use. */\n#define MTOC2_ACC_SUM(acc, x) do { (acc) += (x); } while (0)\n#define MTOC2_ACC_PROD(acc, x) do { (acc) *= (x); } while (0)\n\nMTOC2_DEFINE_ACCUM_REDUCTION(sum, 0.0, MTOC2_ACC_SUM, MTOC2_FIN_ID)\nMTOC2_DEFINE_ACCUM_REDUCTION(prod, 1.0, MTOC2_ACC_PROD, MTOC2_FIN_ID)\nMTOC2_DEFINE_ACCUM_REDUCTION(mean, 0.0, MTOC2_ACC_SUM, MTOC2_FIN_MEAN)\n\nMTOC2_DEFINE_MINMAX_REDUCTION(min, <)\nMTOC2_DEFINE_MINMAX_REDUCTION(max, >)\n\n/* `any` ignores NaN (MATLAB: any(NaN) is 0); `x == x` excludes it so a\n * NaN doesn\'t wrongly short-circuit to true. `all` tests `x == 0.0`,\n * which NaN already fails, so it needs no guard. */\nMTOC2_DEFINE_LOGICAL_REDUCTION(any, 0,\n if (x != 0.0 && x == x) { acc = 1.0; break; })\nMTOC2_DEFINE_LOGICAL_REDUCTION(all, 1,\n if (x == 0.0) { acc = 0.0; break; })\n',
|
|
66002
67159
|
"tensor_repmat.h": '/* mtoc2 runtime helper: `repmat(A, reps)` \u2014 tile a tensor by\n * replicating it along each axis.\n *\n * Numbl\'s reference is the `repmat` builtin in\n * `interpreter/builtins/array-manipulation.ts` (the tensor branch).\n *\n * Contract:\n * - `in` is the source tensor (real, owned-value invariant unchanged).\n * - `nreps` is the number of replication factors supplied (1..MTOC2_MAX_NDIM).\n * - `reps_in[i]` is the per-axis replication factor; negative values\n * clamp to 0 (yielding an empty axis), matching numbl/MATLAB.\n *\n * Output shape is `padShape[i] * padReps[i]` where the input\'s shape\n * and the reps vector are both right-padded with 1s to a common rank\n * `max(in.ndim, nreps)`. Result is freshly owned; `imag` is NULL.\n *\n * Algorithm: copy the input data into the start of the output buffer\n * (column-major flat layout is preserved when trailing dims are 1),\n * then iteratively expand along each axis. For axis `d` with rep > 1,\n * we walk the existing blocks of size `blockSize = prod(curShape[0..d])`\n * in reverse order and replicate each block `rep` times consecutively.\n * Reverse order avoids overwriting source data; `memmove` covers the\n * b=0 in-place case where the block stays at its original offset.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_repmat(mtoc2_tensor_t in, int nreps,\n const long *reps_in) {\n if (nreps < 1 || nreps > MTOC2_MAX_NDIM) {\n fprintf(stderr,\n "mtoc2: repmat nreps %d out of range [1, %d]\\n", nreps, MTOC2_MAX_NDIM);\n abort();\n }\n long reps[MTOC2_MAX_NDIM];\n for (int i = 0; i < nreps; i++) reps[i] = reps_in[i] < 0 ? 0 : reps_in[i];\n\n int in_ndim = in.ndim;\n int out_ndim = nreps > in_ndim ? nreps : in_ndim;\n if (out_ndim > MTOC2_MAX_NDIM) {\n fprintf(stderr,\n "mtoc2: repmat output ndim %d exceeds %d\\n", out_ndim, MTOC2_MAX_NDIM);\n abort();\n }\n\n long padShape[MTOC2_MAX_NDIM];\n long padReps[MTOC2_MAX_NDIM];\n long outDims[MTOC2_MAX_NDIM];\n for (int i = 0; i < out_ndim; i++) {\n padShape[i] = i < in_ndim ? in.dims[i] : 1;\n padReps[i] = i < nreps ? reps[i] : 1;\n outDims[i] = padShape[i] * padReps[i];\n }\n\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(out_ndim, outDims);\n\n size_t outTotal = 1;\n for (int i = 0; i < out_ndim; i++) outTotal *= (size_t)outDims[i];\n if (outTotal == 0) return out;\n\n size_t inTotal = 1;\n for (int i = 0; i < in_ndim; i++) inTotal *= (size_t)in.dims[i];\n if (inTotal == 0) return out;\n\n /* Initial copy: input\'s data laid out in column-major with shape\n * `in.dims` matches the same flat layout under `padShape` (trailing\n * 1s don\'t change flat indexing). */\n memcpy(out.real, in.real, inTotal * sizeof(double));\n\n long curShape[MTOC2_MAX_NDIM];\n for (int i = 0; i < out_ndim; i++) curShape[i] = padShape[i];\n size_t curTotal = inTotal;\n\n for (int d = 0; d < out_ndim; d++) {\n long rep = padReps[d];\n if (rep == 1) continue;\n\n size_t blockSize = 1;\n for (int i = 0; i <= d; i++) blockSize *= (size_t)curShape[i];\n\n if (rep == 0 || blockSize == 0) {\n curShape[d] *= rep;\n curTotal = 0;\n /* Once curTotal is 0, no further work needed \u2014 outTotal is also\n * 0 (because outDims[d] = padShape[d] * 0 = 0). The alloc above\n * already produced a zero-element tensor; bail out. */\n return out;\n }\n\n size_t numBlocks = curTotal / blockSize;\n /* Walk blocks in reverse so writes don\'t clobber as-yet-unread\n * source blocks. Each block of `blockSize` doubles to `blockSize\n * * rep` consecutive slots at offset `b * blockSize * rep`. */\n for (size_t b = numBlocks; b > 0;) {\n b--;\n size_t srcOff = b * blockSize;\n size_t dstBase = b * blockSize * (size_t)rep;\n if (dstBase != srcOff) {\n memmove(out.real + dstBase, out.real + srcOff,\n blockSize * sizeof(double));\n }\n for (long r = 1; r < rep; r++) {\n memcpy(out.real + dstBase + (size_t)r * blockSize,\n out.real + dstBase,\n blockSize * sizeof(double));\n }\n }\n\n curShape[d] *= rep;\n curTotal *= (size_t)rep;\n }\n\n return out;\n}\n\n/* Complex-input sibling: tiles both lanes. Tolerates `in.imag == NULL`\n * (a real tensor that flowed in via a complex-typed route) by zero-\n * filling the output imag lane. */\nstatic mtoc2_tensor_t mtoc2_tensor_repmat_complex(mtoc2_tensor_t in,\n int nreps,\n const long *reps_in) {\n if (nreps < 1 || nreps > MTOC2_MAX_NDIM) {\n fprintf(stderr,\n "mtoc2: repmat_complex nreps %d out of range [1, %d]\\n",\n nreps, MTOC2_MAX_NDIM);\n abort();\n }\n long reps[MTOC2_MAX_NDIM];\n for (int i = 0; i < nreps; i++) reps[i] = reps_in[i] < 0 ? 0 : reps_in[i];\n\n int in_ndim = in.ndim;\n int out_ndim = nreps > in_ndim ? nreps : in_ndim;\n if (out_ndim > MTOC2_MAX_NDIM) {\n fprintf(stderr,\n "mtoc2: repmat_complex output ndim %d exceeds %d\\n",\n out_ndim, MTOC2_MAX_NDIM);\n abort();\n }\n\n long padShape[MTOC2_MAX_NDIM];\n long padReps[MTOC2_MAX_NDIM];\n long outDims[MTOC2_MAX_NDIM];\n for (int i = 0; i < out_ndim; i++) {\n padShape[i] = i < in_ndim ? in.dims[i] : 1;\n padReps[i] = i < nreps ? reps[i] : 1;\n outDims[i] = padShape[i] * padReps[i];\n }\n\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(out_ndim, outDims);\n\n size_t outTotal = 1;\n for (int i = 0; i < out_ndim; i++) outTotal *= (size_t)outDims[i];\n if (outTotal == 0) return out;\n\n size_t inTotal = 1;\n for (int i = 0; i < in_ndim; i++) inTotal *= (size_t)in.dims[i];\n if (inTotal == 0) {\n memset(out.imag, 0, outTotal * sizeof(double));\n return out;\n }\n\n int srcHasImag = (in.imag != NULL);\n\n memcpy(out.real, in.real, inTotal * sizeof(double));\n if (srcHasImag) {\n memcpy(out.imag, in.imag, inTotal * sizeof(double));\n } else {\n memset(out.imag, 0, inTotal * sizeof(double));\n }\n\n long curShape[MTOC2_MAX_NDIM];\n for (int i = 0; i < out_ndim; i++) curShape[i] = padShape[i];\n size_t curTotal = inTotal;\n\n for (int d = 0; d < out_ndim; d++) {\n long rep = padReps[d];\n if (rep == 1) continue;\n\n size_t blockSize = 1;\n for (int i = 0; i <= d; i++) blockSize *= (size_t)curShape[i];\n\n if (rep == 0 || blockSize == 0) {\n curShape[d] *= rep;\n curTotal = 0;\n return out;\n }\n\n size_t numBlocks = curTotal / blockSize;\n for (size_t b = numBlocks; b > 0;) {\n b--;\n size_t srcOff = b * blockSize;\n size_t dstBase = b * blockSize * (size_t)rep;\n if (dstBase != srcOff) {\n memmove(out.real + dstBase, out.real + srcOff,\n blockSize * sizeof(double));\n memmove(out.imag + dstBase, out.imag + srcOff,\n blockSize * sizeof(double));\n }\n for (long r = 1; r < rep; r++) {\n memcpy(out.real + dstBase + (size_t)r * blockSize,\n out.real + dstBase,\n blockSize * sizeof(double));\n memcpy(out.imag + dstBase + (size_t)r * blockSize,\n out.imag + dstBase,\n blockSize * sizeof(double));\n }\n }\n\n curShape[d] *= rep;\n curTotal *= (size_t)rep;\n }\n\n return out;\n}\n',
|
|
66003
67160
|
"tensor_reshape_nd.h": '/* mtoc2 runtime helper: reshape a real tensor to an N-D shape.\n *\n * Receives the input tensor by value (`mtoc2_tensor_t`) plus a\n * caller-supplied dim list (`ndim`, `dims`). Allocates a fresh\n * output tensor via `mtoc2_tensor_alloc_nd` and copies the input\'s\n * column-major buffer wholesale \u2014 reshape is a layout reinterpret,\n * so the linear element order is unchanged.\n *\n * `dims[i] == -1` is the MATLAB `[]` auto-infer slot: the helper\n * scans for a single -1 and fills it from `in_total / prod(others)`.\n * Two or more sentinels, or an `in_total` not divisible by the\n * explicit dims, abort with a clear message.\n *\n * Element-count check: the lowerer enforces `prod(input.dims) ==\n * prod(dims)` at translate time when the input shape is statically\n * known. This helper is the fallback when the input shape only\n * appears at runtime (e.g. a tensor function param whose\n * specialization arg type came in without a concrete shape). On\n * mismatch it prints to stderr and aborts, matching numbl\'s\n * runtime-error surface.\n *\n * Real-only \u2014 mtoc2\'s tensor side is real-only today; the type\n * lattice rejects complex inputs at lowering. The output\'s `imag`\n * is NULL, set by `mtoc2_tensor_alloc_nd`.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_reshape_nd(\n mtoc2_tensor_t in, int ndim, const long *dims) {\n size_t in_total = 1;\n for (int i = 0; i < in.ndim; i++) in_total *= (size_t)in.dims[i];\n /* Scan for at most one `-1` infer slot and the product of the\n * remaining explicit dims. */\n int infer_idx = -1;\n size_t explicit_prod = 1;\n for (int i = 0; i < ndim; i++) {\n if (dims[i] == -1) {\n if (infer_idx != -1) {\n fprintf(stderr,\n "mtoc2: reshape: at most one \'[]\' auto-infer slot allowed\\n");\n abort();\n }\n infer_idx = i;\n } else if (dims[i] < 0) {\n fprintf(stderr,\n "mtoc2: reshape: dim %d must be a non-negative integer "\n "(got %ld)\\n", i + 1, dims[i]);\n abort();\n } else {\n explicit_prod *= (size_t)dims[i];\n }\n }\n long resolved_dims[MTOC2_MAX_NDIM];\n for (int i = 0; i < ndim; i++) resolved_dims[i] = dims[i];\n size_t out_total;\n if (infer_idx != -1) {\n if (explicit_prod == 0 && in_total != 0) {\n fprintf(stderr,\n "mtoc2: reshape: input has %zu elements but the explicit dims "\n "around \'[]\' multiply to 0\\n", in_total);\n abort();\n }\n if (explicit_prod > 0 && in_total % explicit_prod != 0) {\n fprintf(stderr,\n "mtoc2: reshape: input has %zu elements, not divisible by %zu "\n "(the explicit dims around \'[]\')\\n", in_total, explicit_prod);\n abort();\n }\n resolved_dims[infer_idx] =\n (explicit_prod == 0) ? 0 : (long)(in_total / explicit_prod);\n out_total = in_total;\n } else {\n out_total = explicit_prod;\n if (in_total != out_total) {\n fprintf(stderr,\n "mtoc2: reshape: number of elements must not change "\n "(in=%zu, out=%zu)\\n", in_total, out_total);\n abort();\n }\n }\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd(ndim, resolved_dims);\n if (out_total > 0)\n memcpy(out.real, in.real, out_total * sizeof(double));\n return out;\n}\n',
|
|
66004
67161
|
"tensor_reshape_nd_complex.h": '/* mtoc2 runtime helper: reshape a complex tensor to an N-D shape.\n *\n * Sibling of `mtoc2_reshape_nd`. Same `-1` auto-infer slot, same\n * element-count check, same runtime-error surface \u2014 the only\n * difference is the output is allocated via\n * `mtoc2_tensor_alloc_nd_complex` (both lanes) and both lanes get\n * memcpy\'d from the input. Reshape is a layout reinterpret, so the\n * linear element order is unchanged on either lane.\n *\n * Tolerates `in.imag == NULL` (a real tensor flowing through a\n * complex-typed reshape route) by zeroing the output imag lane.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_reshape_nd_complex(\n mtoc2_tensor_t in, int ndim, const long *dims) {\n size_t in_total = 1;\n for (int i = 0; i < in.ndim; i++) in_total *= (size_t)in.dims[i];\n int infer_idx = -1;\n size_t explicit_prod = 1;\n for (int i = 0; i < ndim; i++) {\n if (dims[i] == -1) {\n if (infer_idx != -1) {\n fprintf(stderr,\n "mtoc2: reshape: at most one \'[]\' auto-infer slot allowed\\n");\n abort();\n }\n infer_idx = i;\n } else if (dims[i] < 0) {\n fprintf(stderr,\n "mtoc2: reshape: dim %d must be a non-negative integer "\n "(got %ld)\\n", i + 1, dims[i]);\n abort();\n } else {\n explicit_prod *= (size_t)dims[i];\n }\n }\n long resolved_dims[MTOC2_MAX_NDIM];\n for (int i = 0; i < ndim; i++) resolved_dims[i] = dims[i];\n size_t out_total;\n if (infer_idx != -1) {\n if (explicit_prod == 0 && in_total != 0) {\n fprintf(stderr,\n "mtoc2: reshape: input has %zu elements but the explicit dims "\n "around \'[]\' multiply to 0\\n", in_total);\n abort();\n }\n if (explicit_prod > 0 && in_total % explicit_prod != 0) {\n fprintf(stderr,\n "mtoc2: reshape: input has %zu elements, not divisible by %zu "\n "(the explicit dims around \'[]\')\\n", in_total, explicit_prod);\n abort();\n }\n resolved_dims[infer_idx] =\n (explicit_prod == 0) ? 0 : (long)(in_total / explicit_prod);\n out_total = in_total;\n } else {\n out_total = explicit_prod;\n if (in_total != out_total) {\n fprintf(stderr,\n "mtoc2: reshape: number of elements must not change "\n "(in=%zu, out=%zu)\\n", in_total, out_total);\n abort();\n }\n }\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(ndim, resolved_dims);\n if (out_total > 0) {\n memcpy(out.real, in.real, out_total * sizeof(double));\n if (in.imag != NULL) {\n memcpy(out.imag, in.imag, out_total * sizeof(double));\n } else {\n memset(out.imag, 0, out_total * sizeof(double));\n }\n }\n return out;\n}\n',
|
|
66005
67162
|
"tensor_size.h": "/* mtoc2 runtime helper: `size(t)` \u2014 returns a freshly-owned 1\xD7ndim\n * row tensor whose elements are the input's dim sizes as doubles.\n * MATLAB / numbl semantics: scalars and vectors return at least a\n * 2-element row (the type system already pads to ndim \u2265 2; this\n * helper just copies dims[] into a row vector).\n *\n * For `size(t, k)` mtoc2 emits a scalar `(double)t.dims[k-1]` inline\n * \u2014 no runtime helper needed for that form.\n */\n\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_size_row(mtoc2_tensor_t a) {\n long n = a.ndim;\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)n * sizeof(double));\n r.imag = NULL;\n r.ndim = 2;\n r.dims[0] = 1;\n r.dims[1] = n;\n for (long i = 0; i < n; i++) r.real[i] = (double)a.dims[i];\n return r;\n}\n",
|
|
66006
|
-
"tensor_sort_real.h": '/* mtoc2 runtime helper: stable sort on a tensor.\n *\n * mtoc2_sort_real(a, descending)\n * `b = sort(a)` / `sort(a, \'ascend\'|\'descend\')` \u2014 returns a\n * freshly-owned tensor of the same shape as `a`, with the flat\n * (column-major) entries sorted in the requested direction.\n *\n * mtoc2_sort_real_2(a, descending, &out_v, &out_i)\n * `[v, i] = sort(...)` \u2014 fills `*out_v` with the sorted values\n * and `*out_i` with 1-based original positions.\n *\n * mtoc2_sort_complex / mtoc2_sort_complex_2\n * Complex-input siblings. Numbl / MATLAB sort complex by\n * magnitude (hypot), tiebreak by phase (atan2). Tolerates\n * `a.imag == NULL` (real-input flowed through a complex route)\n * by treating imag as zero.\n *\n * Sort is stable in both directions: ties resolve by ascending\n * original index, matching numbl\'s behaviour (verified against\n * `sort([5 2 8 1 2], \'descend\')` \u2192 indices `3 1 2 5 4`).\n *\n * The lowering layer restricts the input to a 1\xD7N row vector or N\xD71\n * column vector for v1; the helper itself walks the column-major\n * flat buffer and would handle any rank, but the type system rejects\n * the higher-rank cases until the per-axis form is plumbed through.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\ntypedef struct {\n double v;\n long ix;\n} mtoc2_sort_pair_t;\n\n/* NaN ranks as the maximum (MATLAB): last when ascending, first when\n * descending. Without this, NaN compares false both ways and falls to\n * the index tie-break, leaving the comparator non-transitive \u2014 which is\n * undefined behavior for qsort and corrupts the array. */\nstatic int mtoc2_sort_cmp_asc(const void *pa, const void *pb) {\n const mtoc2_sort_pair_t *a = (const mtoc2_sort_pair_t *)pa;\n const mtoc2_sort_pair_t *b = (const mtoc2_sort_pair_t *)pb;\n int an = a->v != a->v, bn = b->v != b->v;\n if (an || bn) {\n if (!(an && bn)) return an ? 1 : -1; /* NaN sorts last */\n } else {\n if (a->v < b->v) return -1;\n if (a->v > b->v) return 1;\n }\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic int mtoc2_sort_cmp_desc(const void *pa, const void *pb) {\n const mtoc2_sort_pair_t *a = (const mtoc2_sort_pair_t *)pa;\n const mtoc2_sort_pair_t *b = (const mtoc2_sort_pair_t *)pb;\n int an = a->v != a->v, bn = b->v != b->v;\n if (an || bn) {\n if (!(an && bn)) return an ? -1 : 1; /* NaN sorts first */\n } else {\n if (a->v > b->v) return -1;\n if (a->v < b->v) return 1;\n }\n /* Tie-break still by ascending original index \u2014 both numbl and\n * MATLAB keep ties in original order in either direction. */\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic mtoc2_tensor_t mtoc2_sort_real(mtoc2_tensor_t a, int descending) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)n * sizeof(double));\n r.imag = NULL;\n r.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i];\n if (n == 0) return r;\n mtoc2_sort_pair_t *buf =\n (mtoc2_sort_pair_t *)malloc((size_t)n * sizeof(mtoc2_sort_pair_t));\n if (!buf) {\n fprintf(stderr, "mtoc2: out of memory (sort buffer)\\n");\n abort();\n }\n for (long i = 0; i < n; i++) {\n buf[i].v = a.real[i];\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_pair_t),\n descending ? mtoc2_sort_cmp_desc : mtoc2_sort_cmp_asc);\n for (long i = 0; i < n; i++) r.real[i] = buf[i].v;\n free(buf);\n return r;\n}\n\nstatic void mtoc2_sort_real_2(mtoc2_tensor_t a, int descending,\n mtoc2_tensor_t *out_v, mtoc2_tensor_t *out_i) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t v;\n mtoc2_tensor_t ix;\n v.real = mtoc2_alloc((size_t)n * sizeof(double));\n v.imag = NULL;\n v.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) v.dims[i] = a.dims[i];\n ix.real = mtoc2_alloc((size_t)n * sizeof(double));\n ix.imag = NULL;\n ix.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) ix.dims[i] = a.dims[i];\n if (n > 0) {\n mtoc2_sort_pair_t *buf =\n (mtoc2_sort_pair_t *)malloc((size_t)n * sizeof(mtoc2_sort_pair_t));\n if (!buf) {\n fprintf(stderr, "mtoc2: out of memory (sort buffer)\\n");\n abort();\n }\n for (long i = 0; i < n; i++) {\n buf[i].v = a.real[i];\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_pair_t),\n descending ? mtoc2_sort_cmp_desc : mtoc2_sort_cmp_asc);\n for (long i = 0; i < n; i++) {\n v.real[i] = buf[i].v;\n ix.real[i] = (double)(buf[i].ix + 1);\n }\n free(buf);\n }\n mtoc2_tensor_assign(out_v, v);\n mtoc2_tensor_assign(out_i, ix);\n}\n\ntypedef struct {\n double mag;\n double phase;\n long ix;\n} mtoc2_sort_complex_pair_t;\n\nstatic int mtoc2_sort_cmp_complex_asc(const void *pa, const void *pb) {\n const mtoc2_sort_complex_pair_t *a = (const mtoc2_sort_complex_pair_t *)pa;\n const mtoc2_sort_complex_pair_t *b = (const mtoc2_sort_complex_pair_t *)pb;\n if (a->mag < b->mag) return -1;\n if (a->mag > b->mag) return 1;\n if (a->phase < b->phase) return -1;\n if (a->phase > b->phase) return 1;\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic int mtoc2_sort_cmp_complex_desc(const void *pa, const void *pb) {\n const mtoc2_sort_complex_pair_t *a = (const mtoc2_sort_complex_pair_t *)pa;\n const mtoc2_sort_complex_pair_t *b = (const mtoc2_sort_complex_pair_t *)pb;\n if (a->mag > b->mag) return -1;\n if (a->mag < b->mag) return 1;\n if (a->phase > b->phase) return -1;\n if (a->phase < b->phase) return 1;\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic mtoc2_tensor_t mtoc2_sort_complex(mtoc2_tensor_t a, int descending) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t r = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims);\n if (n == 0) return r;\n int srcHasImag = (a.imag != NULL);\n if (!srcHasImag) memset(r.imag, 0, (size_t)n * sizeof(double));\n mtoc2_sort_complex_pair_t *buf =\n (mtoc2_sort_complex_pair_t *)malloc(\n (size_t)n * sizeof(mtoc2_sort_complex_pair_t));\n if (!buf) {\n fprintf(stderr, "mtoc2: out of memory (sort complex buffer)\\n");\n abort();\n }\n for (long i = 0; i < n; i++) {\n double re = a.real[i];\n double im = srcHasImag ? a.imag[i] : 0.0;\n buf[i].mag = hypot(re, im);\n buf[i].phase = atan2(im, re);\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_complex_pair_t),\n descending ? mtoc2_sort_cmp_complex_desc\n : mtoc2_sort_cmp_complex_asc);\n for (long i = 0; i < n; i++) {\n r.real[i] = a.real[buf[i].ix];\n r.imag[i] = srcHasImag ? a.imag[buf[i].ix] : 0.0;\n }\n free(buf);\n return r;\n}\n\nstatic void mtoc2_sort_complex_2(mtoc2_tensor_t a, int descending,\n mtoc2_tensor_t *out_v, mtoc2_tensor_t *out_i) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t v = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims);\n mtoc2_tensor_t ix;\n ix.real = mtoc2_alloc((size_t)n * sizeof(double));\n ix.imag = NULL;\n ix.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) ix.dims[i] = a.dims[i];\n if (n > 0) {\n int srcHasImag = (a.imag != NULL);\n if (!srcHasImag) memset(v.imag, 0, (size_t)n * sizeof(double));\n mtoc2_sort_complex_pair_t *buf =\n (mtoc2_sort_complex_pair_t *)malloc(\n (size_t)n * sizeof(mtoc2_sort_complex_pair_t));\n if (!buf) {\n fprintf(stderr, "mtoc2: out of memory (sort complex buffer)\\n");\n abort();\n }\n for (long i = 0; i < n; i++) {\n double re = a.real[i];\n double im = srcHasImag ? a.imag[i] : 0.0;\n buf[i].mag = hypot(re, im);\n buf[i].phase = atan2(im, re);\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_complex_pair_t),\n descending ? mtoc2_sort_cmp_complex_desc\n : mtoc2_sort_cmp_complex_asc);\n for (long i = 0; i < n; i++) {\n v.real[i] = a.real[buf[i].ix];\n v.imag[i] = srcHasImag ? a.imag[buf[i].ix] : 0.0;\n ix.real[i] = (double)(buf[i].ix + 1);\n }\n free(buf);\n }\n mtoc2_tensor_assign(out_v, v);\n mtoc2_tensor_assign(out_i, ix);\n}\n',
|
|
67163
|
+
"tensor_sort_real.h": "/* mtoc2 runtime helper: stable sort on a tensor.\n *\n * mtoc2_sort_real(a, descending)\n * `b = sort(a)` / `sort(a, 'ascend'|'descend')` \u2014 returns a\n * freshly-owned tensor of the same shape as `a`, with the flat\n * (column-major) entries sorted in the requested direction.\n *\n * mtoc2_sort_real_2(a, descending, &out_v, &out_i)\n * `[v, i] = sort(...)` \u2014 fills `*out_v` with the sorted values\n * and `*out_i` with 1-based original positions.\n *\n * mtoc2_sort_complex / mtoc2_sort_complex_2\n * Complex-input siblings. Numbl / MATLAB sort complex by\n * magnitude (hypot), tiebreak by phase (atan2). Tolerates\n * `a.imag == NULL` (real-input flowed through a complex route)\n * by treating imag as zero.\n *\n * Sort is stable in both directions: ties resolve by ascending\n * original index, matching numbl's behaviour (verified against\n * `sort([5 2 8 1 2], 'descend')` \u2192 indices `3 1 2 5 4`).\n *\n * The lowering layer restricts the input to a 1\xD7N row vector or N\xD71\n * column vector for v1; the helper itself walks the column-major\n * flat buffer and would handle any rank, but the type system rejects\n * the higher-rank cases until the per-axis form is plumbed through.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\ntypedef struct {\n double v;\n long ix;\n} mtoc2_sort_pair_t;\n\n/* NaN ranks as the maximum (MATLAB): last when ascending, first when\n * descending. Without this, NaN compares false both ways and falls to\n * the index tie-break, leaving the comparator non-transitive \u2014 which is\n * undefined behavior for qsort and corrupts the array. */\nstatic int mtoc2_sort_cmp_asc(const void *pa, const void *pb) {\n const mtoc2_sort_pair_t *a = (const mtoc2_sort_pair_t *)pa;\n const mtoc2_sort_pair_t *b = (const mtoc2_sort_pair_t *)pb;\n int an = a->v != a->v, bn = b->v != b->v;\n if (an || bn) {\n if (!(an && bn)) return an ? 1 : -1; /* NaN sorts last */\n } else {\n if (a->v < b->v) return -1;\n if (a->v > b->v) return 1;\n }\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic int mtoc2_sort_cmp_desc(const void *pa, const void *pb) {\n const mtoc2_sort_pair_t *a = (const mtoc2_sort_pair_t *)pa;\n const mtoc2_sort_pair_t *b = (const mtoc2_sort_pair_t *)pb;\n int an = a->v != a->v, bn = b->v != b->v;\n if (an || bn) {\n if (!(an && bn)) return an ? -1 : 1; /* NaN sorts first */\n } else {\n if (a->v > b->v) return -1;\n if (a->v < b->v) return 1;\n }\n /* Tie-break still by ascending original index \u2014 both numbl and\n * MATLAB keep ties in original order in either direction. */\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic mtoc2_tensor_t mtoc2_sort_real(mtoc2_tensor_t a, int descending) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)n * sizeof(double));\n r.imag = NULL;\n r.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) r.dims[i] = a.dims[i];\n if (n == 0) return r;\n mtoc2_sort_pair_t *buf =\n (mtoc2_sort_pair_t *)malloc((size_t)n * sizeof(mtoc2_sort_pair_t));\n if (!buf) {\n fprintf(stderr, \"mtoc2: out of memory (sort buffer)\\n\");\n abort();\n }\n for (long i = 0; i < n; i++) {\n buf[i].v = a.real[i];\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_pair_t),\n descending ? mtoc2_sort_cmp_desc : mtoc2_sort_cmp_asc);\n for (long i = 0; i < n; i++) r.real[i] = buf[i].v;\n free(buf);\n return r;\n}\n\nstatic void mtoc2_sort_real_2(mtoc2_tensor_t a, int descending,\n mtoc2_tensor_t *out_v, mtoc2_tensor_t *out_i) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t v;\n mtoc2_tensor_t ix;\n v.real = mtoc2_alloc((size_t)n * sizeof(double));\n v.imag = NULL;\n v.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) v.dims[i] = a.dims[i];\n ix.real = mtoc2_alloc((size_t)n * sizeof(double));\n ix.imag = NULL;\n ix.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) ix.dims[i] = a.dims[i];\n if (n > 0) {\n mtoc2_sort_pair_t *buf =\n (mtoc2_sort_pair_t *)malloc((size_t)n * sizeof(mtoc2_sort_pair_t));\n if (!buf) {\n fprintf(stderr, \"mtoc2: out of memory (sort buffer)\\n\");\n abort();\n }\n for (long i = 0; i < n; i++) {\n buf[i].v = a.real[i];\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_pair_t),\n descending ? mtoc2_sort_cmp_desc : mtoc2_sort_cmp_asc);\n for (long i = 0; i < n; i++) {\n v.real[i] = buf[i].v;\n ix.real[i] = (double)(buf[i].ix + 1);\n }\n free(buf);\n }\n mtoc2_tensor_assign(out_v, v);\n mtoc2_tensor_assign(out_i, ix);\n}\n\ntypedef struct {\n double mag;\n double phase;\n long ix;\n} mtoc2_sort_complex_pair_t;\n\nstatic int mtoc2_sort_cmp_complex_asc(const void *pa, const void *pb) {\n const mtoc2_sort_complex_pair_t *a = (const mtoc2_sort_complex_pair_t *)pa;\n const mtoc2_sort_complex_pair_t *b = (const mtoc2_sort_complex_pair_t *)pb;\n if (a->mag < b->mag) return -1;\n if (a->mag > b->mag) return 1;\n if (a->phase < b->phase) return -1;\n if (a->phase > b->phase) return 1;\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic int mtoc2_sort_cmp_complex_desc(const void *pa, const void *pb) {\n const mtoc2_sort_complex_pair_t *a = (const mtoc2_sort_complex_pair_t *)pa;\n const mtoc2_sort_complex_pair_t *b = (const mtoc2_sort_complex_pair_t *)pb;\n if (a->mag > b->mag) return -1;\n if (a->mag < b->mag) return 1;\n if (a->phase > b->phase) return -1;\n if (a->phase < b->phase) return 1;\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\n/* Real-value comparators used when the input's imaginary lane is all\n * zero: order by signed value (the `mag` field holds the signed real\n * part in that mode), NaNs last (asc) / first (desc), tiebreak by index.\n * Matches the interpreter and MATLAB on real data. */\nstatic int mtoc2_sort_cmp_real_asc(const void *pa, const void *pb) {\n const mtoc2_sort_complex_pair_t *a = (const mtoc2_sort_complex_pair_t *)pa;\n const mtoc2_sort_complex_pair_t *b = (const mtoc2_sort_complex_pair_t *)pb;\n int aNaN = a->mag != a->mag;\n int bNaN = b->mag != b->mag;\n if (!(aNaN && bNaN)) {\n if (aNaN) return 1;\n if (bNaN) return -1;\n if (a->mag < b->mag) return -1;\n if (a->mag > b->mag) return 1;\n }\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\nstatic int mtoc2_sort_cmp_real_desc(const void *pa, const void *pb) {\n const mtoc2_sort_complex_pair_t *a = (const mtoc2_sort_complex_pair_t *)pa;\n const mtoc2_sort_complex_pair_t *b = (const mtoc2_sort_complex_pair_t *)pb;\n int aNaN = a->mag != a->mag;\n int bNaN = b->mag != b->mag;\n if (!(aNaN && bNaN)) {\n if (aNaN) return -1;\n if (bNaN) return 1;\n if (a->mag > b->mag) return -1;\n if (a->mag < b->mag) return 1;\n }\n if (a->ix < b->ix) return -1;\n if (a->ix > b->ix) return 1;\n return 0;\n}\n\n/* True when the tensor carries no imaginary content (NULL lane or all\n * elements zero) \u2014 then sort orders by signed real value. */\nstatic int mtoc2_sort_all_imag_zero(mtoc2_tensor_t a) {\n if (a.imag == NULL) return 1;\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n for (long i = 0; i < n; i++) {\n if (a.imag[i] != 0.0) return 0;\n }\n return 1;\n}\n\nstatic mtoc2_tensor_t mtoc2_sort_complex(mtoc2_tensor_t a, int descending) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t r = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims);\n if (n == 0) return r;\n int srcHasImag = (a.imag != NULL);\n if (!srcHasImag) memset(r.imag, 0, (size_t)n * sizeof(double));\n int realMode = mtoc2_sort_all_imag_zero(a);\n mtoc2_sort_complex_pair_t *buf =\n (mtoc2_sort_complex_pair_t *)malloc(\n (size_t)n * sizeof(mtoc2_sort_complex_pair_t));\n if (!buf) {\n fprintf(stderr, \"mtoc2: out of memory (sort complex buffer)\\n\");\n abort();\n }\n for (long i = 0; i < n; i++) {\n double re = a.real[i];\n double im = srcHasImag ? a.imag[i] : 0.0;\n buf[i].mag = realMode ? re : hypot(re, im);\n buf[i].phase = realMode ? 0.0 : atan2(im, re);\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_complex_pair_t),\n realMode ? (descending ? mtoc2_sort_cmp_real_desc\n : mtoc2_sort_cmp_real_asc)\n : (descending ? mtoc2_sort_cmp_complex_desc\n : mtoc2_sort_cmp_complex_asc));\n for (long i = 0; i < n; i++) {\n r.real[i] = a.real[buf[i].ix];\n r.imag[i] = srcHasImag ? a.imag[buf[i].ix] : 0.0;\n }\n free(buf);\n return r;\n}\n\nstatic void mtoc2_sort_complex_2(mtoc2_tensor_t a, int descending,\n mtoc2_tensor_t *out_v, mtoc2_tensor_t *out_i) {\n long n = 1;\n for (int i = 0; i < a.ndim; i++) n *= a.dims[i];\n mtoc2_tensor_t v = mtoc2_tensor_alloc_nd_complex(a.ndim, a.dims);\n mtoc2_tensor_t ix;\n ix.real = mtoc2_alloc((size_t)n * sizeof(double));\n ix.imag = NULL;\n ix.ndim = a.ndim;\n for (int i = 0; i < a.ndim; i++) ix.dims[i] = a.dims[i];\n if (n > 0) {\n int srcHasImag = (a.imag != NULL);\n if (!srcHasImag) memset(v.imag, 0, (size_t)n * sizeof(double));\n int realMode = mtoc2_sort_all_imag_zero(a);\n mtoc2_sort_complex_pair_t *buf =\n (mtoc2_sort_complex_pair_t *)malloc(\n (size_t)n * sizeof(mtoc2_sort_complex_pair_t));\n if (!buf) {\n fprintf(stderr, \"mtoc2: out of memory (sort complex buffer)\\n\");\n abort();\n }\n for (long i = 0; i < n; i++) {\n double re = a.real[i];\n double im = srcHasImag ? a.imag[i] : 0.0;\n buf[i].mag = realMode ? re : hypot(re, im);\n buf[i].phase = realMode ? 0.0 : atan2(im, re);\n buf[i].ix = i;\n }\n qsort(buf, (size_t)n, sizeof(mtoc2_sort_complex_pair_t),\n realMode ? (descending ? mtoc2_sort_cmp_real_desc\n : mtoc2_sort_cmp_real_asc)\n : (descending ? mtoc2_sort_cmp_complex_desc\n : mtoc2_sort_cmp_complex_asc));\n for (long i = 0; i < n; i++) {\n v.real[i] = a.real[buf[i].ix];\n v.imag[i] = srcHasImag ? a.imag[buf[i].ix] : 0.0;\n ix.real[i] = (double)(buf[i].ix + 1);\n }\n free(buf);\n }\n mtoc2_tensor_assign(out_v, v);\n mtoc2_tensor_assign(out_i, ix);\n}\n",
|
|
66007
67164
|
"tensor_transpose.h": "/* mtoc2 runtime helper: real-tensor non-conjugate transpose for 2-D\n * inputs. Returns a freshly-owned tensor with `dims` swapped. The\n * 2-D restriction is enforced at lowering; by the time this helper\n * runs, `a.ndim` is always 2.\n *\n * Column-major in, column-major out. Source `a` has shape (m \xD7 n);\n * destination has shape (n \xD7 m). Source element at (sr, sc) lives at\n * `a.real[sr + sc*m]`; destination element at (sc, sr) \u2014 the transpose\n * mapping \u2014 lives at `out.real[sc + sr*n]`. The inner loop walks the\n * source's column-major buffer linearly to keep the read stride\n * unit-stride.\n *\n * For complex support (not yet a thing in mtoc2), the conjugate\n * variant would negate `a.imag` while copying; the non-conjugate\n * variant just copies. Mirrors numbl's `transposeCore` in\n * `helpers/arithmetic.ts`.\n */\n\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_transpose(mtoc2_tensor_t a) {\n long m = a.dims[0];\n long n = a.dims[1];\n mtoc2_tensor_t r;\n r.real = mtoc2_alloc((size_t)m * (size_t)n * sizeof(double));\n r.imag = NULL;\n r.ndim = 2;\n r.dims[0] = n;\n r.dims[1] = m;\n for (long sc = 0; sc < n; sc++) {\n for (long sr = 0; sr < m; sr++) {\n r.real[sc + sr * n] = a.real[sr + sc * m];\n }\n }\n return r;\n}\n",
|
|
66008
67165
|
"tensor_transpose_complex.h": "/* mtoc2 runtime helper: complex-tensor non-conjugate transpose for\n * 2-D inputs. Sibling of `mtoc2_tensor_transpose` \u2014 same shape\n * permutation, but copies BOTH lanes (no conjugation, the `.'`\n * operator). The `'` (conjugate transpose) operator lowers to\n * `transpose(conj(z))` at the lowering layer, so this helper only\n * sees the non-conjugating case.\n *\n * Tolerates `a.imag == NULL` (real-tensor flowing through a\n * complex-typed transpose route) by zeroing the result's imag lane.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_transpose_complex(mtoc2_tensor_t a) {\n long m = a.dims[0];\n long n = a.dims[1];\n long dims[2];\n dims[0] = n;\n dims[1] = m;\n mtoc2_tensor_t r = mtoc2_tensor_alloc_nd_complex(2, dims);\n if (a.imag == NULL) {\n /* Defensive: zero the imag lane so the transposed result is a\n * well-formed complex tensor with re-only content. */\n memset(r.imag, 0, (size_t)m * (size_t)n * sizeof(double));\n }\n for (long sc = 0; sc < n; sc++) {\n for (long sr = 0; sr < m; sr++) {\n r.real[sc + sr * n] = a.real[sr + sc * m];\n if (a.imag != NULL) {\n r.imag[sc + sr * n] = a.imag[sr + sc * m];\n }\n }\n }\n return r;\n}\n",
|
|
66009
67166
|
"tensor_triangular.h": "/* mtoc2 runtime helper: `triu` / `tril` \u2014 extract upper / lower\n * triangular part of a 2-D matrix around the k-th diagonal. Mirrors\n * numbl's `triPart` in `interpreter/builtins/array-extras.ts`.\n *\n * - `mtoc2_tensor_triu(A, k)` returns a fresh `rows \xD7 cols` tensor\n * equal to `A` where `j - i >= k` (column - row), zero elsewhere.\n * `k = 0` is the main diagonal; `k > 0` selects a super-diagonal;\n * `k < 0` selects a sub-diagonal.\n * - `mtoc2_tensor_tril(A, k)` is the mirror: keep entries where\n * `i - j >= -k` (equivalently `j - i <= k`), zero elsewhere.\n * - `*_complex` siblings walk both lanes; tolerate `a.imag == NULL`\n * (real-input flowed through a complex route).\n *\n * Storage column-major to match `mtoc2_tensor_t`. Result is freshly\n * owned.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\nstatic mtoc2_tensor_t mtoc2_tensor_triu(mtoc2_tensor_t a, long k) {\n long rows = a.dims[0];\n long cols = a.dims[1];\n mtoc2_tensor_t out = mtoc2_tensor_alloc(rows, cols);\n if (rows > 0 && cols > 0)\n memset(out.real, 0, (size_t)rows * (size_t)cols * sizeof(double));\n for (long j = 0; j < cols; j++) {\n for (long i = 0; i < rows; i++) {\n if (j - i >= k) {\n long idx = i + j * rows;\n out.real[idx] = a.real[idx];\n }\n }\n }\n return out;\n}\n\nstatic mtoc2_tensor_t mtoc2_tensor_tril(mtoc2_tensor_t a, long k) {\n long rows = a.dims[0];\n long cols = a.dims[1];\n mtoc2_tensor_t out = mtoc2_tensor_alloc(rows, cols);\n if (rows > 0 && cols > 0)\n memset(out.real, 0, (size_t)rows * (size_t)cols * sizeof(double));\n for (long j = 0; j < cols; j++) {\n for (long i = 0; i < rows; i++) {\n if (i - j >= -k) {\n long idx = i + j * rows;\n out.real[idx] = a.real[idx];\n }\n }\n }\n return out;\n}\n\nstatic mtoc2_tensor_t mtoc2_tensor_triu_complex(mtoc2_tensor_t a, long k) {\n long rows = a.dims[0];\n long cols = a.dims[1];\n long dims2[2] = {rows, cols};\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(2, dims2);\n if (rows > 0 && cols > 0) {\n memset(out.real, 0, (size_t)rows * (size_t)cols * sizeof(double));\n memset(out.imag, 0, (size_t)rows * (size_t)cols * sizeof(double));\n }\n int srcHasImag = (a.imag != NULL);\n for (long j = 0; j < cols; j++) {\n for (long i = 0; i < rows; i++) {\n if (j - i >= k) {\n long idx = i + j * rows;\n out.real[idx] = a.real[idx];\n if (srcHasImag) out.imag[idx] = a.imag[idx];\n }\n }\n }\n return out;\n}\n\nstatic mtoc2_tensor_t mtoc2_tensor_tril_complex(mtoc2_tensor_t a, long k) {\n long rows = a.dims[0];\n long cols = a.dims[1];\n long dims2[2] = {rows, cols};\n mtoc2_tensor_t out = mtoc2_tensor_alloc_nd_complex(2, dims2);\n if (rows > 0 && cols > 0) {\n memset(out.real, 0, (size_t)rows * (size_t)cols * sizeof(double));\n memset(out.imag, 0, (size_t)rows * (size_t)cols * sizeof(double));\n }\n int srcHasImag = (a.imag != NULL);\n for (long j = 0; j < cols; j++) {\n for (long i = 0; i < rows; i++) {\n if (i - j >= -k) {\n long idx = i + j * rows;\n out.real[idx] = a.real[idx];\n if (srcHasImag) out.imag[idx] = a.imag[idx];\n }\n }\n }\n return out;\n}\n",
|
|
@@ -66075,6 +67232,7 @@ var JS_SNIPPETS = {
|
|
|
66075
67232
|
"tensor_fill_nd.js": "// JS sibling of `tensor_fill_nd.h`. Like zeros/ones but takes the\n// fill value as a leading argument \u2014 used by the `nan` / `Inf` shape-\n// constructor branches and by `repmat(scalar, ...)`. Complex variant\n// takes `(re, im)` and fills both lanes.\n\n\n\nfunction mtoc2_tensor_fill_nd(value, ndim, dims) {\n const t = mtoc2_tensor_alloc_nd(ndim, dims);\n t.data.fill(value);\n return t;\n}\n\nfunction mtoc2_tensor_fill_nd_complex(re, im, ndim, dims) {\n const t = mtoc2_tensor_alloc_nd_complex(ndim, dims);\n t.data.fill(re);\n t.imag.fill(im);\n return t;\n}\n",
|
|
66076
67233
|
"tensor_fill_square.js": "// JS sibling of `tensor_fill_square.h`. Single-eval helper for\n// `nan(n)` / `Inf(n)` style square-fill constructors.\n\n\nfunction mtoc2_tensor_fill_square(value, n) {\n return mtoc2_tensor_fill_nd(value, 2, [n, n]);\n}\n",
|
|
66077
67234
|
"tensor_flip.js": "// JS sibling of `tensor_flip.h`. Two helpers:\n// - `mtoc2_tensor_flip(t, dimIdx)` \u2014 real-input variant.\n// - `mtoc2_tensor_flip_complex(t, dimIdx)` \u2014 walks both lanes;\n// if `imag` is undefined the output imag stays zero.\n// Out-of-range axis acts as a deep-copy no-op in both.\n\n\n\nfunction mtoc2_tensor_flip(a, dimIdx) {\n const r = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n const axisSize = dimIdx >= 0 && dimIdx < a.shape.length ? a.shape[dimIdx] : 1;\n if (axisSize <= 1) {\n r.data.set(a.data);\n return r;\n }\n let strideDim = 1;\n for (let d = 0; d < dimIdx; d++) strideDim *= a.shape[d];\n const slabSize = strideDim * axisSize;\n const total = r.data.length;\n const numOuter = total / slabSize;\n for (let outer = 0; outer < numOuter; outer++) {\n const base = outer * slabSize;\n for (let k = 0; k < axisSize; k++) {\n const srcOff = base + k * strideDim;\n const dstOff = base + (axisSize - 1 - k) * strideDim;\n for (let i = 0; i < strideDim; i++) {\n r.data[dstOff + i] = a.data[srcOff + i];\n }\n }\n }\n return r;\n}\n\nfunction mtoc2_tensor_flip_complex(a, dimIdx) {\n const r = mtoc2_tensor_alloc_nd_complex(a.shape.length, a.shape);\n const im = a.imag;\n const axisSize = dimIdx >= 0 && dimIdx < a.shape.length ? a.shape[dimIdx] : 1;\n if (axisSize <= 1) {\n r.data.set(a.data);\n if (im !== undefined) r.imag.set(im);\n return r;\n }\n let strideDim = 1;\n for (let d = 0; d < dimIdx; d++) strideDim *= a.shape[d];\n const slabSize = strideDim * axisSize;\n const total = r.data.length;\n const numOuter = total / slabSize;\n for (let outer = 0; outer < numOuter; outer++) {\n const base = outer * slabSize;\n for (let k = 0; k < axisSize; k++) {\n const srcOff = base + k * strideDim;\n const dstOff = base + (axisSize - 1 - k) * strideDim;\n for (let i = 0; i < strideDim; i++) {\n r.data[dstOff + i] = a.data[srcOff + i];\n if (im !== undefined) r.imag[dstOff + i] = im[srcOff + i];\n }\n }\n }\n return r;\n}\n",
|
|
67235
|
+
"tensor_imag_all_zero.js": "// JS sibling of `tensor_imag_all_zero.h`. True when a tensor carries no\n// imaginary content (no imag lane, or every imag element exactly zero).\n// `isreal` uses this for complex-typed tensors the JIT could not prove\n// real at compile time, so it reports realness by value \u2014 matching the\n// interpreter and the complex-scalar `v.im === 0` rule.\nfunction mtoc2_tensor_imag_all_zero(a) {\n if (a.imag === undefined) return true;\n for (let i = 0; i < a.imag.length; i++) {\n if (a.imag[i] !== 0) return false;\n }\n return true;\n}\n",
|
|
66078
67236
|
"tensor_linspace.js": "// JS sibling of `tensor_linspace.h`. Build a 1\xD7n row tensor of n\n// linearly-spaced values from `a` to `b`.\n\n\nfunction mtoc2_tensor_linspace(a, b, n) {\n if (n < 0) n = 0;\n const out = mtoc2_tensor_alloc(1, n);\n if (n === 0) return out;\n if (n === 1) {\n out.data[0] = b;\n return out;\n }\n out.data[0] = a;\n out.data[n - 1] = b;\n for (let i = 1; i < n - 1; i++) {\n out.data[i] = a + ((b - a) * i) / (n - 1);\n }\n if ((n & 1) === 1 && !Number.isFinite(a) && !Number.isFinite(b)) {\n const sa = Math.sign(a);\n const sb = Math.sign(b);\n if (sa !== sb) out.data[(n - 1) / 2] = 0;\n }\n return out;\n}\n",
|
|
66079
67237
|
"tensor_logical_real.js": '// JS sibling of `tensor_logical_real.h`. Elementwise logical NOT on\n// real and complex tensors. Real input: `out[i] = (in[i] == 0) ? 1 : 0`.\n// Complex input: fires "true" iff both lanes are exactly zero.\n// Result is logical-tagged in both cases.\n\n\nfunction mtoc2_tensor_not(a) {\n const r = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n for (let i = 0; i < r.data.length; i++) {\n r.data[i] = a.data[i] === 0 ? 1 : 0;\n }\n // Tag as logical so `a(mask)` / `M(:, mask)` etc. take the mask\n // path in the interpreter (and js-aot, when wired). The tensor\n // alloc helpers return plain numeric tensors; we mutate the field\n // here rather than threading a parameter through every allocator.\n r.isLogical = true;\n return r;\n}\n\nfunction mtoc2_tensor_not_complex(a) {\n const r = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n const im = a.imag;\n for (let i = 0; i < r.data.length; i++) {\n const re = a.data[i];\n const v = im !== undefined ? im[i] : 0;\n r.data[i] = re === 0 && v === 0 ? 1 : 0;\n }\n r.isLogical = true;\n return r;\n}\n',
|
|
66080
67238
|
"tensor_logspace.js": "// JS sibling of `tensor_logspace.h`. Build a 1\xD7n row tensor of n\n// logarithmically-spaced values from 10^a to 10^b. Byte-for-byte with\n// numbl's interpreter `logspace`, including the MATLAB special case\n// where an upper limit of exactly `pi` makes the last point `pi`.\n\n\nfunction mtoc2_tensor_logspace(a, b, n) {\n if (n <= 0) return mtoc2_tensor_alloc(1, 0);\n const isPi = b === Math.PI;\n const endVal = isPi ? Math.PI : Math.pow(10, b);\n const out = mtoc2_tensor_alloc(1, n);\n if (n === 1) {\n out.data[0] = endVal;\n return out;\n }\n if (isPi) {\n const logStart = Math.log10(Math.pow(10, a));\n const logEnd = Math.log10(Math.PI);\n for (let i = 0; i < n; i++) {\n const t = logStart + ((logEnd - logStart) * i) / (n - 1);\n out.data[i] = Math.pow(10, t);\n }\n } else {\n for (let i = 0; i < n; i++) {\n const t = a + ((b - a) * i) / (n - 1);\n out.data[i] = Math.pow(10, t);\n }\n }\n return out;\n}\n",
|
|
@@ -66085,13 +67243,13 @@ var JS_SNIPPETS = {
|
|
|
66085
67243
|
"tensor_ones_nd.js": "// JS sibling of `tensor_ones_nd.h`. Fill the freshly-allocated\n// tensor with `1.0`.\n\n\nfunction mtoc2_tensor_ones_nd(ndim, dims) {\n const t = mtoc2_tensor_alloc_nd(ndim, dims);\n t.data.fill(1);\n return t;\n}\n",
|
|
66086
67244
|
"tensor_ones_square.js": "// JS sibling of `tensor_ones_square.h`. See `tensor_zeros_square.js`\n// for the rationale.\n\n\nfunction mtoc2_tensor_ones_square(n) {\n return mtoc2_tensor_ones_nd(2, [n, n]);\n}\n",
|
|
66087
67245
|
"tensor_predicate.js": '// JS sibling of `tensor_predicate.h`. Real-tensor \u2192 logical-tensor\n// predicate kernels for the js-aot backend, plus their `_complex`\n// siblings (each reads `imag[i]` when defined, treats it as 0\n// otherwise). Result carries `isLogical: true` so downstream index-\n// slot resolution treats it as a mask.\n\nfunction pred_kernel(a, fn) {\n const out = new Float64Array(a.data.length);\n for (let i = 0; i < a.data.length; i++) out[i] = fn(a.data[i]) ? 1 : 0;\n return {\n mtoc2Tag: "tensor",\n shape: a.shape.slice(),\n data: out,\n isLogical: true,\n };\n}\n\nfunction pred_kernel_complex(a, fn) {\n const out = new Float64Array(a.data.length);\n const im = a.imag;\n for (let i = 0; i < a.data.length; i++) {\n out[i] = fn(a.data[i], im !== undefined ? im[i] : 0) ? 1 : 0;\n }\n return {\n mtoc2Tag: "tensor",\n shape: a.shape.slice(),\n data: out,\n isLogical: true,\n };\n}\n\nfunction mtoc2_tensor_isnan(a) {\n return pred_kernel(a, Number.isNaN);\n}\n\nfunction mtoc2_tensor_logical(a) {\n return pred_kernel(a, x => x !== 0);\n}\n\nfunction mtoc2_tensor_isinf(a) {\n return pred_kernel(a, x => x === Infinity || x === -Infinity);\n}\n\nfunction mtoc2_tensor_isfinite(a) {\n return pred_kernel(a, Number.isFinite);\n}\n\nfunction mtoc2_tensor_isnan_complex(a) {\n return pred_kernel_complex(\n a,\n (re, im) => Number.isNaN(re) || Number.isNaN(im)\n );\n}\n\nfunction mtoc2_tensor_isinf_complex(a) {\n const isInf = x => x === Infinity || x === -Infinity;\n return pred_kernel_complex(a, (re, im) => isInf(re) || isInf(im));\n}\n\nfunction mtoc2_tensor_isfinite_complex(a) {\n return pred_kernel_complex(\n a,\n (re, im) => Number.isFinite(re) && Number.isFinite(im)\n );\n}\n',
|
|
66088
|
-
"tensor_reduce_complex.js": '// JS sibling of `tensor_reduce_complex.h`. Complex-tensor reductions.\n// Mirrors the real reducer shape (sum/prod/mean \u2192 complex; min/max\n// \u2192 complex via magnitude+atan2 tiebreak; any/all \u2192 real).\n\n\n\nfunction cSqueezeTrailing(dims) {\n while (dims.length > 2 && dims[dims.length - 1] === 1) dims.pop();\n return dims;\n}\n\nfunction cReduceLaneIm(t, i) {\n return t.imag !== undefined ? t.imag[i] : 0;\n}\n\n// Numeric (sum/prod/mean) \u2014 complex accumulator { re, im }.\nfunction complexAccumAll(t, init, accum, finalize) {\n let acc = { ...init };\n for (let i = 0; i < t.data.length; i++) {\n acc = accum(acc, { re: t.data[i], im: cReduceLaneIm(t, i) });\n }\n return finalize(acc, t.data.length);\n}\n\nfunction complexAccumDim(t, dim, init, accum, finalize) {\n if (dim < 1) throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n if (dim > t.shape.length) {\n // No-op axis: return a fresh complex copy.\n const out = mtoc2_tensor_alloc_nd_complex(t.shape.length, t.shape.slice());\n out.data.set(t.data);\n if (t.imag !== undefined) out.imag.set(t.imag);\n return out;\n }\n const dimIdx = dim - 1;\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = t.shape.slice();\n outDims[dimIdx] = 1;\n cSqueezeTrailing(outDims);\n const out = mtoc2_tensor_alloc_nd_complex(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let acc = { ...init };\n for (let k = 0; k < axis; k++) {\n const off = base + k * before;\n acc = accum(acc, { re: t.data[off], im: cReduceLaneIm(t, off) });\n }\n const fin = finalize(acc, axis);\n const dst = aft * before + bef;\n out.data[dst] = fin.re;\n out.imag[dst] = fin.im;\n }\n }\n return out;\n}\n\nconst cSumInit = { re: 0, im: 0 };\nconst cProdInit = { re: 1, im: 0 };\nconst cSumAccum = (a, x) => ({ re: a.re + x.re, im: a.im + x.im });\nconst cProdAccum = (a, x) => ({\n re: a.re * x.re - a.im * x.im,\n im: a.re * x.im + a.im * x.re,\n});\nconst cIdFinalize = a => a;\nconst cMeanFinalize = (a, n) =>\n n === 0 ? { re: NaN, im: NaN } : { re: a.re / n, im: a.im / n };\n\nconst mtoc2_sum_complex_all = t =>\n complexAccumAll(t, cSumInit, cSumAccum, cIdFinalize);\nconst mtoc2_sum_complex_dim = (t, d) =>\n complexAccumDim(t, d, cSumInit, cSumAccum, cIdFinalize);\nconst mtoc2_prod_complex_all = t =>\n complexAccumAll(t, cProdInit, cProdAccum, cIdFinalize);\nconst mtoc2_prod_complex_dim = (t, d) =>\n complexAccumDim(t, d, cProdInit, cProdAccum, cIdFinalize);\nconst mtoc2_mean_complex_all = t =>\n complexAccumAll(t, cSumInit, cSumAccum, cMeanFinalize);\nconst mtoc2_mean_complex_dim = (t, d) =>\n complexAccumDim(t, d, cSumInit, cSumAccum, cMeanFinalize);\n\n// Min / max \u2014 magnitude compare with atan2 tiebreak (numbl\'s\n// complexIsBetter). Skip NaN-lane elements; result is complex.\nfunction complexMinmaxAll(t, cmp) {\n let found = false;\n let mRe = NaN;\n let mIm = 0;\n for (let i = 0; i < t.data.length; i++) {\n const xr = t.data[i];\n const xi = cReduceLaneIm(t, i);\n if (xr !== xr || xi !== xi) continue;\n
|
|
67246
|
+
"tensor_reduce_complex.js": '// JS sibling of `tensor_reduce_complex.h`. Complex-tensor reductions.\n// Mirrors the real reducer shape (sum/prod/mean \u2192 complex; min/max\n// \u2192 complex via magnitude+atan2 tiebreak; any/all \u2192 real).\n\n\n\nfunction cSqueezeTrailing(dims) {\n while (dims.length > 2 && dims[dims.length - 1] === 1) dims.pop();\n return dims;\n}\n\nfunction cReduceLaneIm(t, i) {\n return t.imag !== undefined ? t.imag[i] : 0;\n}\n\n// True when the tensor carries no imaginary content (no lane, or every\n// element zero). Such a tensor is real in value \u2014 min/max must order by\n// value, not magnitude, to match the interpreter and MATLAB on real data.\nfunction cReduceAllImagZero(t) {\n if (t.imag === undefined) return true;\n for (let i = 0; i < t.imag.length; i++) {\n if (t.imag[i] !== 0) return false;\n }\n return true;\n}\n\n// Numeric (sum/prod/mean) \u2014 complex accumulator { re, im }.\nfunction complexAccumAll(t, init, accum, finalize) {\n let acc = { ...init };\n for (let i = 0; i < t.data.length; i++) {\n acc = accum(acc, { re: t.data[i], im: cReduceLaneIm(t, i) });\n }\n return finalize(acc, t.data.length);\n}\n\nfunction complexAccumDim(t, dim, init, accum, finalize) {\n if (dim < 1) throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n if (dim > t.shape.length) {\n // No-op axis: return a fresh complex copy.\n const out = mtoc2_tensor_alloc_nd_complex(t.shape.length, t.shape.slice());\n out.data.set(t.data);\n if (t.imag !== undefined) out.imag.set(t.imag);\n return out;\n }\n const dimIdx = dim - 1;\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = t.shape.slice();\n outDims[dimIdx] = 1;\n cSqueezeTrailing(outDims);\n const out = mtoc2_tensor_alloc_nd_complex(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let acc = { ...init };\n for (let k = 0; k < axis; k++) {\n const off = base + k * before;\n acc = accum(acc, { re: t.data[off], im: cReduceLaneIm(t, off) });\n }\n const fin = finalize(acc, axis);\n const dst = aft * before + bef;\n out.data[dst] = fin.re;\n out.imag[dst] = fin.im;\n }\n }\n return out;\n}\n\nconst cSumInit = { re: 0, im: 0 };\nconst cProdInit = { re: 1, im: 0 };\nconst cSumAccum = (a, x) => ({ re: a.re + x.re, im: a.im + x.im });\nconst cProdAccum = (a, x) => ({\n re: a.re * x.re - a.im * x.im,\n im: a.re * x.im + a.im * x.re,\n});\nconst cIdFinalize = a => a;\nconst cMeanFinalize = (a, n) =>\n n === 0 ? { re: NaN, im: NaN } : { re: a.re / n, im: a.im / n };\n\nconst mtoc2_sum_complex_all = t =>\n complexAccumAll(t, cSumInit, cSumAccum, cIdFinalize);\nconst mtoc2_sum_complex_dim = (t, d) =>\n complexAccumDim(t, d, cSumInit, cSumAccum, cIdFinalize);\nconst mtoc2_prod_complex_all = t =>\n complexAccumAll(t, cProdInit, cProdAccum, cIdFinalize);\nconst mtoc2_prod_complex_dim = (t, d) =>\n complexAccumDim(t, d, cProdInit, cProdAccum, cIdFinalize);\nconst mtoc2_mean_complex_all = t =>\n complexAccumAll(t, cSumInit, cSumAccum, cMeanFinalize);\nconst mtoc2_mean_complex_dim = (t, d) =>\n complexAccumDim(t, d, cSumInit, cSumAccum, cMeanFinalize);\n\n// Min / max \u2014 magnitude compare with atan2 tiebreak (numbl\'s\n// complexIsBetter). Skip NaN-lane elements; result is complex.\nfunction complexMinmaxAll(t, cmp) {\n const realMode = cReduceAllImagZero(t);\n let found = false;\n let mRe = NaN;\n let mIm = 0;\n for (let i = 0; i < t.data.length; i++) {\n const xr = t.data[i];\n const xi = cReduceLaneIm(t, i);\n if (xr !== xr || xi !== xi) continue;\n const better = realMode\n ? cmp === "<"\n ? xr < mRe\n : xr > mRe\n : complexBetter(xr, xi, mRe, mIm, cmp);\n if (!found || better) {\n mRe = xr;\n mIm = xi;\n found = true;\n }\n }\n return { re: mRe, im: mIm };\n}\n\nfunction complexBetter(aRe, aIm, bRe, bIm, cmp) {\n const absA = Math.hypot(aRe, aIm);\n const absB = Math.hypot(bRe, bIm);\n if (absA !== absB) return cmp === "<" ? absA < absB : absA > absB;\n return cmp === "<"\n ? Math.atan2(aIm, aRe) < Math.atan2(bIm, bRe)\n : Math.atan2(aIm, aRe) > Math.atan2(bIm, bRe);\n}\n\nfunction complexMinmaxDim(t, dim, cmp) {\n if (dim < 1) throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n if (dim > t.shape.length) {\n const out = mtoc2_tensor_alloc_nd_complex(t.shape.length, t.shape.slice());\n out.data.set(t.data);\n if (t.imag !== undefined) out.imag.set(t.imag);\n return out;\n }\n const dimIdx = dim - 1;\n const realMode = cReduceAllImagZero(t);\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = t.shape.slice();\n outDims[dimIdx] = 1;\n cSqueezeTrailing(outDims);\n const out = mtoc2_tensor_alloc_nd_complex(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let found = false;\n let mRe = NaN;\n let mIm = 0;\n for (let k = 0; k < axis; k++) {\n const off = base + k * before;\n const xr = t.data[off];\n const xi = cReduceLaneIm(t, off);\n if (xr !== xr || xi !== xi) continue;\n const better = realMode\n ? cmp === "<"\n ? xr < mRe\n : xr > mRe\n : complexBetter(xr, xi, mRe, mIm, cmp);\n if (!found || better) {\n mRe = xr;\n mIm = xi;\n found = true;\n }\n }\n const dst = aft * before + bef;\n out.data[dst] = mRe;\n out.imag[dst] = mIm;\n }\n }\n return out;\n}\n\nconst mtoc2_min_complex_all = t => complexMinmaxAll(t, "<");\nconst mtoc2_min_complex_dim = (t, d) => complexMinmaxDim(t, d, "<");\nconst mtoc2_max_complex_all = t => complexMinmaxAll(t, ">");\nconst mtoc2_max_complex_dim = (t, d) => complexMinmaxDim(t, d, ">");\n\n// any / all \u2014 real result; toBool per element (either lane nonzero).\nfunction complexLogicalAll(t, emptyResult, shortPredicate) {\n if (t.data.length === 0) return emptyResult;\n for (let i = 0; i < t.data.length; i++) {\n const xr = t.data[i];\n const xi = cReduceLaneIm(t, i);\n const x = xr !== 0 || xi !== 0;\n if (shortPredicate(x)) return emptyResult === 1 ? 0 : 1;\n }\n return emptyResult;\n}\n\nfunction complexLogicalDim(t, dim, emptyResult, shortPredicate) {\n if (dim < 1) throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n if (dim > t.shape.length) {\n const out = mtoc2_tensor_alloc_nd(t.shape.length, t.shape.slice());\n for (let i = 0; i < t.data.length; i++) {\n const xr = t.data[i];\n const xi = cReduceLaneIm(t, i);\n out.data[i] = xr !== 0 || xi !== 0 ? 1 : 0;\n }\n return out;\n }\n const dimIdx = dim - 1;\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = t.shape.slice();\n outDims[dimIdx] = 1;\n cSqueezeTrailing(outDims);\n const out = mtoc2_tensor_alloc_nd(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let res = emptyResult;\n for (let k = 0; k < axis; k++) {\n const off = base + k * before;\n const x = t.data[off] !== 0 || cReduceLaneIm(t, off) !== 0;\n if (shortPredicate(x)) {\n res = emptyResult === 1 ? 0 : 1;\n break;\n }\n }\n out.data[aft * before + bef] = res;\n }\n }\n return out;\n}\n\nconst cAnyShort = x => x;\nconst cAllShort = x => !x;\nconst mtoc2_any_complex_all = t => complexLogicalAll(t, 0, cAnyShort);\nconst mtoc2_any_complex_dim = (t, d) =>\n complexLogicalDim(t, d, 0, cAnyShort);\nconst mtoc2_all_complex_all = t => complexLogicalAll(t, 1, cAllShort);\nconst mtoc2_all_complex_dim = (t, d) =>\n complexLogicalDim(t, d, 1, cAllShort);\n',
|
|
66089
67247
|
"tensor_reduce_real.js": '// JS sibling of `tensor_reduce_real.h`. Real-tensor reductions \u2014\n// `_all` returns a scalar; `_dim` returns a freshly-allocated tensor\n// reduced along the 1-based `dim` axis. Mirrors numbl\'s\n// `forEachSlice` semantics with column-major (before \xD7 axis \xD7 after)\n// traversal.\n//\n// Output shape rule for `_dim`: input dims with `dims[dim-1] = 1`,\n// then trailing singletons stripped subject to a 2-axis floor.\n\n\nfunction squeeze_trailing(dims) {\n while (dims.length > 2 && dims[dims.length - 1] === 1) dims.pop();\n return dims;\n}\n\n// Accumulator-based reducer (`sum`, `prod`, `mean`). `init` seeds\n// the running value; `accum(a, x)` is the per-element step;\n// `finalize(a, n)` is the post-loop transform.\nfunction accum_all(t, init, accum, finalize) {\n let acc = init;\n for (let i = 0; i < t.data.length; i++) acc = accum(acc, t.data[i]);\n return finalize(acc, t.data.length);\n}\n\nfunction accum_dim(t, dim, init, accum, finalize) {\n if (dim < 1) {\n throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n }\n if (dim > t.shape.length) {\n // Reducing along a trailing singleton axis is the identity: every\n // fiber has length 1, so sum/prod/mean each yield that single\n // element unchanged. Return a same-shape COPY of the data (the C\n // kernel memcpy\'s here too); allocating without copying left a\n // zero-filled tensor \u2014 the original opt1 bug.\n const out = mtoc2_tensor_alloc_nd(t.shape.length, t.shape.slice());\n out.data.set(t.data);\n return out;\n }\n const dimIdx = dim - 1;\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = squeeze_trailing(t.shape.slice());\n outDims[dimIdx] = 1;\n // Re-squeeze after the in-place axis update (the original `out_dims\n // = a.shape.slice(); out_dims[dimIdx] = 1` then squeeze pattern).\n squeeze_trailing(outDims);\n const out = mtoc2_tensor_alloc_nd(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let acc = init;\n for (let k = 0; k < axis; k++) {\n acc = accum(acc, t.data[base + k * before]);\n }\n out.data[aft * before + bef] = finalize(acc, axis);\n }\n }\n return out;\n}\n\n// Min/max reducer. Ignores NaN like numbl/MATLAB: NaN entries are\n// skipped, and the result is NaN only when every element is NaN.\n// Mirrors the interpreter\'s `minMaxScan` (helpers/reduction/min-max.ts)\n// and the C kernel \u2014 seeding with data[0] would let a *leading* NaN\n// poison the result (`x < NaN` / `x > NaN` are always false).\nfunction minmax_all(t, op /* "min" | "max" */) {\n if (t.data.length === 0) return op === "min" ? Infinity : -Infinity;\n let best = NaN;\n let found = false;\n for (let i = 0; i < t.data.length; i++) {\n const x = t.data[i];\n if (x !== x) continue; // skip NaN\n if (!found || (op === "min" ? x < best : x > best)) {\n best = x;\n found = true;\n }\n }\n return found ? best : NaN;\n}\n\nfunction minmax_dim(t, dim, op) {\n if (dim < 1) throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n if (dim > t.shape.length) {\n const out = mtoc2_tensor_alloc_nd(t.shape.length, t.shape.slice());\n out.data.set(t.data);\n return out;\n }\n const dimIdx = dim - 1;\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = t.shape.slice();\n outDims[dimIdx] = 1;\n squeeze_trailing(outDims);\n const out = mtoc2_tensor_alloc_nd(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let best = NaN;\n let found = false;\n for (let k = 0; k < axis; k++) {\n const x = t.data[base + k * before];\n if (x !== x) continue; // skip NaN\n if (!found || (op === "min" ? x < best : x > best)) {\n best = x;\n found = true;\n }\n }\n out.data[aft * before + bef] = found ? best : NaN;\n }\n }\n return out;\n}\n\n// Logical reducer (`any`, `all`). `emptyResult` is the value for a\n// 0-element reduction; `short` is the early-exit predicate.\nfunction logical_all(t, emptyResult, shortPredicate) {\n if (t.data.length === 0) return emptyResult;\n for (let i = 0; i < t.data.length; i++) {\n if (shortPredicate(t.data[i])) return emptyResult === 1 ? 0 : 1;\n }\n return emptyResult;\n}\n\nfunction logical_dim(t, dim, emptyResult, shortPredicate) {\n if (dim < 1) throw new Error(`reducer _dim: dim must be >= 1 (got ${dim})`);\n if (dim > t.shape.length) {\n // No-op axis: emit a logical cast of the input (each element \u2192\n // 1 if nonzero, 0 otherwise).\n const out = mtoc2_tensor_alloc_nd(t.shape.length, t.shape.slice());\n for (let i = 0; i < t.data.length; i++) {\n out.data[i] = t.data[i] !== 0 ? 1 : 0;\n }\n return out;\n }\n const dimIdx = dim - 1;\n const axis = t.shape[dimIdx];\n let before = 1;\n for (let i = 0; i < dimIdx; i++) before *= t.shape[i];\n let after = 1;\n for (let i = dimIdx + 1; i < t.shape.length; i++) after *= t.shape[i];\n const outDims = t.shape.slice();\n outDims[dimIdx] = 1;\n squeeze_trailing(outDims);\n const out = mtoc2_tensor_alloc_nd(outDims.length, outDims);\n for (let aft = 0; aft < after; aft++) {\n for (let bef = 0; bef < before; bef++) {\n const base = aft * before * axis + bef;\n let res = emptyResult;\n for (let k = 0; k < axis; k++) {\n if (shortPredicate(t.data[base + k * before])) {\n res = emptyResult === 1 ? 0 : 1;\n break;\n }\n }\n out.data[aft * before + bef] = res;\n }\n }\n return out;\n}\n\n// \u2500\u2500 Sum \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst sumInit = 0;\nconst sumAccum = (a, x) => a + x;\nconst idFinalize = a => a;\nconst mtoc2_sum_all = t => accum_all(t, sumInit, sumAccum, idFinalize);\nconst mtoc2_sum_dim = (t, d) =>\n accum_dim(t, d, sumInit, sumAccum, idFinalize);\n\n// \u2500\u2500 Prod \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst prodInit = 1;\nconst prodAccum = (a, x) => a * x;\nconst mtoc2_prod_all = t =>\n accum_all(t, prodInit, prodAccum, idFinalize);\nconst mtoc2_prod_dim = (t, d) =>\n accum_dim(t, d, prodInit, prodAccum, idFinalize);\n\n// \u2500\u2500 Mean \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst meanFinalize = (a, n) => (n === 0 ? NaN : a / n);\nconst mtoc2_mean_all = t =>\n accum_all(t, sumInit, sumAccum, meanFinalize);\nconst mtoc2_mean_dim = (t, d) =>\n accum_dim(t, d, sumInit, sumAccum, meanFinalize);\n\n// \u2500\u2500 Min / max \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst mtoc2_min_all = t => minmax_all(t, "min");\nconst mtoc2_min_dim = (t, d) => minmax_dim(t, d, "min");\nconst mtoc2_max_all = t => minmax_all(t, "max");\nconst mtoc2_max_dim = (t, d) => minmax_dim(t, d, "max");\n\n// \u2500\u2500 Any / all \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// any: short-circuits on a non-NaN nonzero; emptyResult = 0. NaN is\n// ignored (MATLAB: any(NaN) is 0, any([0 NaN]) is 0), so `x === x`\n// excludes it \u2014 without that, NaN wrongly short-circuited to true.\n// (`all` needs no such guard: allShort tests `x === 0`, which NaN\n// already fails, so a NaN simply doesn\'t force all to false.)\nconst anyShort = x => x !== 0 && x === x;\nconst mtoc2_any_all = t => logical_all(t, 0, anyShort);\nconst mtoc2_any_dim = (t, d) => logical_dim(t, d, 0, anyShort);\n// all: short-circuits on zero; emptyResult = 1.\nconst allShort = x => x === 0;\nconst mtoc2_all_all = t => logical_all(t, 1, allShort);\nconst mtoc2_all_dim = (t, d) => logical_dim(t, d, 1, allShort);\n',
|
|
66090
67248
|
"tensor_repmat.js": "// JS sibling of `tensor_repmat.h`. Two helpers:\n// - `mtoc2_tensor_repmat(in, nreps, reps)` \u2014 tile a real tensor.\n// - `mtoc2_tensor_repmat_complex(in, nreps, reps)` \u2014 tile both\n// lanes of a complex tensor (zero imag when input is real).\n// Negative reps clamp to 0; input shape and reps are right-padded\n// with 1s to a common rank.\n\n\n\nfunction mtoc2_tensor_repmat(input, nreps, repsIn) {\n const reps = [];\n for (let i = 0; i < nreps; i++) {\n const r = repsIn[i] < 0 ? 0 : repsIn[i];\n reps.push(r);\n }\n const inShape = input.shape;\n const inNdim = inShape.length;\n const outNdim = Math.max(nreps, inNdim);\n const padShape = [];\n const padReps = [];\n const outDims = [];\n for (let i = 0; i < outNdim; i++) {\n padShape.push(i < inNdim ? inShape[i] : 1);\n padReps.push(i < nreps ? reps[i] : 1);\n outDims.push(padShape[i] * padReps[i]);\n }\n const out = mtoc2_tensor_alloc_nd(outNdim, outDims);\n let outTotal = 1;\n for (const d of outDims) outTotal *= d;\n if (outTotal === 0) return out;\n let inTotal = 1;\n for (const d of inShape) inTotal *= d;\n if (inTotal === 0) return out;\n\n // Initial copy: trailing-1 padding doesn't change column-major layout.\n out.data.set(input.data.subarray(0, inTotal), 0);\n\n const curShape = padShape.slice();\n let curTotal = inTotal;\n\n for (let d = 0; d < outNdim; d++) {\n const rep = padReps[d];\n if (rep === 1) continue;\n let blockSize = 1;\n for (let i = 0; i <= d; i++) blockSize *= curShape[i];\n if (rep === 0 || blockSize === 0) {\n // outTotal will be 0; the alloc above already produced an empty\n // tensor. Done.\n return out;\n }\n const numBlocks = curTotal / blockSize;\n // Walk blocks in reverse to avoid overwriting source data.\n for (let b = numBlocks - 1; b >= 0; b--) {\n const srcOff = b * blockSize;\n const dstBase = b * blockSize * rep;\n if (dstBase !== srcOff) {\n // copyWithin handles overlapping moves correctly.\n out.data.copyWithin(dstBase, srcOff, srcOff + blockSize);\n }\n for (let r = 1; r < rep; r++) {\n out.data.copyWithin(\n dstBase + r * blockSize,\n dstBase,\n dstBase + blockSize\n );\n }\n }\n curShape[d] *= rep;\n curTotal *= rep;\n }\n return out;\n}\n\nfunction mtoc2_tensor_repmat_complex(input, nreps, repsIn) {\n const reps = [];\n for (let i = 0; i < nreps; i++) {\n const r = repsIn[i] < 0 ? 0 : repsIn[i];\n reps.push(r);\n }\n const inShape = input.shape;\n const inNdim = inShape.length;\n const outNdim = Math.max(nreps, inNdim);\n const padShape = [];\n const padReps = [];\n const outDims = [];\n for (let i = 0; i < outNdim; i++) {\n padShape.push(i < inNdim ? inShape[i] : 1);\n padReps.push(i < nreps ? reps[i] : 1);\n outDims.push(padShape[i] * padReps[i]);\n }\n const out = mtoc2_tensor_alloc_nd_complex(outNdim, outDims);\n let outTotal = 1;\n for (const d of outDims) outTotal *= d;\n if (outTotal === 0) return out;\n let inTotal = 1;\n for (const d of inShape) inTotal *= d;\n if (inTotal === 0) return out;\n\n const im = input.imag;\n out.data.set(input.data.subarray(0, inTotal), 0);\n if (im !== undefined) out.imag.set(im.subarray(0, inTotal), 0);\n\n const curShape = padShape.slice();\n let curTotal = inTotal;\n\n for (let d = 0; d < outNdim; d++) {\n const rep = padReps[d];\n if (rep === 1) continue;\n let blockSize = 1;\n for (let i = 0; i <= d; i++) blockSize *= curShape[i];\n if (rep === 0 || blockSize === 0) return out;\n const numBlocks = curTotal / blockSize;\n for (let b = numBlocks - 1; b >= 0; b--) {\n const srcOff = b * blockSize;\n const dstBase = b * blockSize * rep;\n if (dstBase !== srcOff) {\n out.data.copyWithin(dstBase, srcOff, srcOff + blockSize);\n out.imag.copyWithin(dstBase, srcOff, srcOff + blockSize);\n }\n for (let r = 1; r < rep; r++) {\n out.data.copyWithin(\n dstBase + r * blockSize,\n dstBase,\n dstBase + blockSize\n );\n out.imag.copyWithin(\n dstBase + r * blockSize,\n dstBase,\n dstBase + blockSize\n );\n }\n }\n curShape[d] *= rep;\n curTotal *= rep;\n }\n return out;\n}\n",
|
|
66091
67249
|
"tensor_reshape_nd.js": "// JS sibling of `tensor_reshape_nd.h`. Reshape a real tensor to an\n// N-D shape, supporting one `-1` auto-infer slot. Same error\n// behaviour as the C side: throws (instead of `abort()`) on bad\n// inputs.\n\n\nfunction mtoc2_reshape_nd(input, ndim, dims) {\n let inTotal = 1;\n for (const d of input.shape) inTotal *= d;\n let inferIdx = -1;\n let explicitProd = 1;\n for (let i = 0; i < ndim; i++) {\n if (dims[i] === -1) {\n if (inferIdx !== -1) {\n throw new Error(\"reshape: at most one '[]' auto-infer slot allowed\");\n }\n inferIdx = i;\n } else if (dims[i] < 0) {\n throw new Error(\n `reshape: dim ${i + 1} must be a non-negative integer (got ${dims[i]})`\n );\n } else {\n explicitProd *= dims[i];\n }\n }\n const resolved = new Array(ndim);\n for (let i = 0; i < ndim; i++) resolved[i] = dims[i];\n let outTotal;\n if (inferIdx !== -1) {\n if (explicitProd === 0 && inTotal !== 0) {\n throw new Error(\n `reshape: input has ${inTotal} elements but explicit dims around '[]' multiply to 0`\n );\n }\n if (explicitProd > 0 && inTotal % explicitProd !== 0) {\n throw new Error(\n `reshape: input has ${inTotal} elements, not divisible by ${explicitProd}`\n );\n }\n resolved[inferIdx] = explicitProd === 0 ? 0 : inTotal / explicitProd;\n outTotal = inTotal;\n } else {\n outTotal = explicitProd;\n if (inTotal !== outTotal) {\n throw new Error(\n `reshape: number of elements must not change (in=${inTotal}, out=${outTotal})`\n );\n }\n }\n const out = mtoc2_tensor_alloc_nd(ndim, resolved);\n if (outTotal > 0) out.data.set(input.data.subarray(0, outTotal));\n return out;\n}\n",
|
|
66092
67250
|
"tensor_reshape_nd_complex.js": "// JS sibling of `tensor_reshape_nd_complex.h`. Reshape a complex\n// tensor to an N-D shape. Same auto-infer / element-count rules as\n// the real reshape; both lanes are reinterpreted (no rearrangement).\n\n\nfunction mtoc2_reshape_nd_complex(input, ndim, dims) {\n let inTotal = 1;\n for (const d of input.shape) inTotal *= d;\n let inferIdx = -1;\n let explicitProd = 1;\n for (let i = 0; i < ndim; i++) {\n if (dims[i] === -1) {\n if (inferIdx !== -1) {\n throw new Error(\"reshape: at most one '[]' auto-infer slot allowed\");\n }\n inferIdx = i;\n } else if (dims[i] < 0) {\n throw new Error(\n `reshape: dim ${i + 1} must be a non-negative integer (got ${dims[i]})`\n );\n } else {\n explicitProd *= dims[i];\n }\n }\n const resolved = new Array(ndim);\n for (let i = 0; i < ndim; i++) resolved[i] = dims[i];\n let outTotal;\n if (inferIdx !== -1) {\n if (explicitProd === 0 && inTotal !== 0) {\n throw new Error(\n `reshape: input has ${inTotal} elements but explicit dims around '[]' multiply to 0`\n );\n }\n if (explicitProd > 0 && inTotal % explicitProd !== 0) {\n throw new Error(\n `reshape: input has ${inTotal} elements, not divisible by ${explicitProd}`\n );\n }\n resolved[inferIdx] = explicitProd === 0 ? 0 : inTotal / explicitProd;\n outTotal = inTotal;\n } else {\n outTotal = explicitProd;\n if (inTotal !== outTotal) {\n throw new Error(\n `reshape: number of elements must not change (in=${inTotal}, out=${outTotal})`\n );\n }\n }\n const out = mtoc2_tensor_alloc_nd_complex(ndim, resolved);\n if (outTotal > 0) {\n out.data.set(input.data.subarray(0, outTotal));\n if (input.imag !== undefined) {\n out.imag.set(input.imag.subarray(0, outTotal));\n }\n }\n return out;\n}\n",
|
|
66093
67251
|
"tensor_size.js": "// JS sibling of `tensor_size.h`. Build a 1\xD7ndim row tensor whose\n// elements are the input's dim sizes.\n\n\nfunction mtoc2_tensor_size_row(a) {\n const n = a.shape.length;\n const r = mtoc2_tensor_alloc(1, n);\n for (let i = 0; i < n; i++) r.data[i] = a.shape[i];\n return r;\n}\n",
|
|
66094
|
-
"tensor_sort_real.js": "// JS sibling of `tensor_sort_real.h`. Stable sort on real and\n// complex tensors. The descending flag flips the comparator while\n// keeping the tie-break on ascending original index. Complex sort\n// orders by magnitude then phase (matches numbl).\n\n\n\nfunction pair_sort_indices(a, descending) {\n const n = a.data.length;\n const idx = new Array(n);\n for (let i = 0; i < n; i++) idx[i] = i;\n idx.sort((p, q) => {\n const av = a.data[p];\n const bv = a.data[q];\n // NaN ranks as the maximum (MATLAB): last when ascending, first\n // when descending. Without this, NaN compares false both ways and\n // falls through to the index tie-break, making the comparator\n // non-transitive and corrupting the whole array.\n const an = av !== av;\n const bn = bv !== bv;\n if (an || bn) {\n if (an && bn) return p - q;\n if (an) return descending ? -1 : 1;\n return descending ? 1 : -1;\n }\n if (av < bv) return descending ? 1 : -1;\n if (av > bv) return descending ? -1 : 1;\n return p - q;\n });\n return idx;\n}\n\nfunction complex_sort_indices(a, descending) {\n const n = a.data.length;\n const im = a.imag;\n const idx = new Array(n);\n const mag = new Float64Array(n);\n const ph = new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const re = a.data[i];\n const xi = im !== undefined ? im[i] : 0;\n mag[i] = Math.hypot(re, xi);\n ph[i] = Math.atan2(xi, re);\n
|
|
67252
|
+
"tensor_sort_real.js": "// JS sibling of `tensor_sort_real.h`. Stable sort on real and\n// complex tensors. The descending flag flips the comparator while\n// keeping the tie-break on ascending original index. Complex sort\n// orders by magnitude then phase (matches numbl).\n\n\n\nfunction pair_sort_indices(a, descending) {\n const n = a.data.length;\n const idx = new Array(n);\n for (let i = 0; i < n; i++) idx[i] = i;\n idx.sort((p, q) => {\n const av = a.data[p];\n const bv = a.data[q];\n // NaN ranks as the maximum (MATLAB): last when ascending, first\n // when descending. Without this, NaN compares false both ways and\n // falls through to the index tie-break, making the comparator\n // non-transitive and corrupting the whole array.\n const an = av !== av;\n const bn = bv !== bv;\n if (an || bn) {\n if (an && bn) return p - q;\n if (an) return descending ? -1 : 1;\n return descending ? 1 : -1;\n }\n if (av < bv) return descending ? 1 : -1;\n if (av > bv) return descending ? -1 : 1;\n return p - q;\n });\n return idx;\n}\n\nfunction complex_sort_indices(a, descending) {\n const n = a.data.length;\n const im = a.imag;\n const idx = new Array(n);\n for (let i = 0; i < n; i++) idx[i] = i;\n\n // All-zero imaginary lane \u2192 order by signed real value (matches the\n // interpreter and MATLAB on real data), not by magnitude. NaNs sort\n // last when ascending, first when descending.\n let realMode = true;\n if (im !== undefined) {\n for (let i = 0; i < n; i++) {\n if (im[i] !== 0) {\n realMode = false;\n break;\n }\n }\n }\n if (realMode) {\n const re = a.data;\n idx.sort((p, q) => {\n const rp = re[p];\n const rq = re[q];\n const pNaN = rp !== rp;\n const qNaN = rq !== rq;\n if (pNaN && qNaN) return 0;\n if (descending) {\n if (pNaN) return -1;\n if (qNaN) return 1;\n return rp < rq ? 1 : rp > rq ? -1 : 0;\n }\n if (pNaN) return 1;\n if (qNaN) return -1;\n return rp < rq ? -1 : rp > rq ? 1 : 0;\n });\n return idx;\n }\n\n const mag = new Float64Array(n);\n const ph = new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const re = a.data[i];\n const xi = im !== undefined ? im[i] : 0;\n mag[i] = Math.hypot(re, xi);\n ph[i] = Math.atan2(xi, re);\n }\n idx.sort((p, q) => {\n if (mag[p] < mag[q]) return descending ? 1 : -1;\n if (mag[p] > mag[q]) return descending ? -1 : 1;\n if (ph[p] < ph[q]) return descending ? 1 : -1;\n if (ph[p] > ph[q]) return descending ? -1 : 1;\n return p - q;\n });\n return idx;\n}\n\nfunction mtoc2_sort_real(a, descending) {\n const v = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n if (a.data.length === 0) return v;\n const sorted = pair_sort_indices(a, descending);\n for (let i = 0; i < sorted.length; i++) v.data[i] = a.data[sorted[i]];\n return v;\n}\n\nfunction mtoc2_sort_real_2(a, descending) {\n const v = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n const ix = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n if (a.data.length === 0) return { v, ix };\n const sorted = pair_sort_indices(a, descending);\n for (let i = 0; i < sorted.length; i++) {\n v.data[i] = a.data[sorted[i]];\n ix.data[i] = sorted[i] + 1;\n }\n return { v, ix };\n}\n\nfunction mtoc2_sort_complex(a, descending) {\n const v = mtoc2_tensor_alloc_nd_complex(a.shape.length, a.shape);\n if (a.data.length === 0) return v;\n const sorted = complex_sort_indices(a, descending);\n const im = a.imag;\n for (let i = 0; i < sorted.length; i++) {\n v.data[i] = a.data[sorted[i]];\n if (im !== undefined) v.imag[i] = im[sorted[i]];\n }\n return v;\n}\n\nfunction mtoc2_sort_complex_2(a, descending) {\n const v = mtoc2_tensor_alloc_nd_complex(a.shape.length, a.shape);\n const ix = mtoc2_tensor_alloc_nd(a.shape.length, a.shape);\n if (a.data.length === 0) return { v, ix };\n const sorted = complex_sort_indices(a, descending);\n const im = a.imag;\n for (let i = 0; i < sorted.length; i++) {\n v.data[i] = a.data[sorted[i]];\n if (im !== undefined) v.imag[i] = im[sorted[i]];\n ix.data[i] = sorted[i] + 1;\n }\n return { v, ix };\n}\n",
|
|
66095
67253
|
"tensor_transpose.js": "// JS sibling of `tensor_transpose.h`. Real 2-D non-conjugate\n// transpose. Mirrors `transposeCore` semantics: column-major in,\n// column-major out.\n\n\nfunction mtoc2_tensor_transpose(a) {\n const m = a.shape[0];\n const n = a.shape[1];\n const r = mtoc2_tensor_alloc(n, m);\n for (let sc = 0; sc < n; sc++) {\n for (let sr = 0; sr < m; sr++) {\n r.data[sc + sr * n] = a.data[sr + sc * m];\n }\n }\n return r;\n}\n",
|
|
66096
67254
|
"tensor_transpose_complex.js": "// JS sibling of `tensor_transpose_complex.h`. Real 2-D non-conjugate\n// transpose for a complex tensor \u2014 both lanes get the same index\n// permutation. `'` (conjugate transpose) lowers to\n// `transpose(conj(z))` upstream, so this helper isn't responsible\n// for negating the imag lane.\n\n\nfunction mtoc2_tensor_transpose_complex(a) {\n const m = a.shape[0];\n const n = a.shape[1];\n const r = mtoc2_tensor_alloc_complex(n, m);\n const aim = a.imag;\n for (let sc = 0; sc < n; sc++) {\n for (let sr = 0; sr < m; sr++) {\n r.data[sc + sr * n] = a.data[sr + sc * m];\n r.imag[sc + sr * n] = aim !== undefined ? aim[sr + sc * m] : 0;\n }\n }\n return r;\n}\n",
|
|
66097
67255
|
"tensor_triangular.js": "// JS sibling of `tensor_triangular.h`. Four helpers: `triu` / `tril`\n// keep entries where `j - i >= k` / `i - j >= -k`; their `_complex`\n// siblings walk both lanes. Mirrors `triPart` in numbl's\n// `interpreter/builtins/array-extras.ts`.\n\n\n\nfunction mtoc2_tensor_triu(a, k) {\n const rows = a.shape[0];\n const cols = a.shape[1];\n const out = mtoc2_tensor_alloc(rows, cols);\n for (let j = 0; j < cols; j++) {\n for (let i = 0; i < rows; i++) {\n if (j - i >= k) {\n const idx = i + j * rows;\n out.data[idx] = a.data[idx];\n }\n }\n }\n return out;\n}\n\nfunction mtoc2_tensor_tril(a, k) {\n const rows = a.shape[0];\n const cols = a.shape[1];\n const out = mtoc2_tensor_alloc(rows, cols);\n for (let j = 0; j < cols; j++) {\n for (let i = 0; i < rows; i++) {\n if (i - j >= -k) {\n const idx = i + j * rows;\n out.data[idx] = a.data[idx];\n }\n }\n }\n return out;\n}\n\nfunction mtoc2_tensor_triu_complex(a, k) {\n const rows = a.shape[0];\n const cols = a.shape[1];\n const out = mtoc2_tensor_alloc_nd_complex(2, [rows, cols]);\n const im = a.imag;\n for (let j = 0; j < cols; j++) {\n for (let i = 0; i < rows; i++) {\n if (j - i >= k) {\n const idx = i + j * rows;\n out.data[idx] = a.data[idx];\n if (im !== undefined) out.imag[idx] = im[idx];\n }\n }\n }\n return out;\n}\n\nfunction mtoc2_tensor_tril_complex(a, k) {\n const rows = a.shape[0];\n const cols = a.shape[1];\n const out = mtoc2_tensor_alloc_nd_complex(2, [rows, cols]);\n const im = a.imag;\n for (let j = 0; j < cols; j++) {\n for (let i = 0; i < rows; i++) {\n if (i - j >= -k) {\n const idx = i + j * rows;\n out.data[idx] = a.data[idx];\n if (im !== undefined) out.imag[idx] = im[idx];\n }\n }\n }\n return out;\n}\n",
|
|
@@ -66154,6 +67312,7 @@ var JS_IMPORTS = {
|
|
|
66154
67312
|
"tensor_fill_nd.js": ["tensor_alloc_nd.js", "tensor_alloc_nd_complex.js"],
|
|
66155
67313
|
"tensor_fill_square.js": ["tensor_fill_nd.js"],
|
|
66156
67314
|
"tensor_flip.js": ["tensor_alloc_nd.js", "tensor_alloc_nd_complex.js"],
|
|
67315
|
+
"tensor_imag_all_zero.js": [],
|
|
66157
67316
|
"tensor_linspace.js": ["tensor_alloc.js"],
|
|
66158
67317
|
"tensor_logical_real.js": ["tensor_alloc_nd.js"],
|
|
66159
67318
|
"tensor_logspace.js": ["tensor_alloc.js"],
|
|
@@ -67538,7 +68697,7 @@ var ge = defineCompare("ge", ">=", (a, b) => a >= b);
|
|
|
67538
68697
|
// src/numbl-core/jit/codegen/cHelpers.ts
|
|
67539
68698
|
function cTypeFor(t) {
|
|
67540
68699
|
if (isMultiElement(t)) return "mtoc2_tensor_t";
|
|
67541
|
-
if (
|
|
68700
|
+
if (isHandle2(t)) return handleTypedefName(t);
|
|
67542
68701
|
if (t.kind === "Struct") return structTypedefName(t);
|
|
67543
68702
|
if (t.kind === "Class") return classTypedefName(t);
|
|
67544
68703
|
if (t.kind === "Cell") return cellTypedefName(t);
|
|
@@ -73174,7 +74333,7 @@ function staticAnswer(t) {
|
|
|
73174
74333
|
}
|
|
73175
74334
|
if (isString(t)) return true;
|
|
73176
74335
|
if (isChar(t)) return false;
|
|
73177
|
-
if (isStruct(t) || isClass(t) ||
|
|
74336
|
+
if (isStruct(t) || isClass(t) || isHandle2(t)) return false;
|
|
73178
74337
|
return void 0;
|
|
73179
74338
|
}
|
|
73180
74339
|
function requireKnown(t) {
|
|
@@ -73293,7 +74452,7 @@ var isstruct = {
|
|
|
73293
74452
|
function staticClassNameOf(t) {
|
|
73294
74453
|
if (isClass(t)) return t.className;
|
|
73295
74454
|
if (isStruct(t)) return "struct";
|
|
73296
|
-
if (
|
|
74455
|
+
if (isHandle2(t)) return "function_handle";
|
|
73297
74456
|
if (isChar(t)) return "char";
|
|
73298
74457
|
if (isString(t)) return "string";
|
|
73299
74458
|
if (isCell(t)) return "cell";
|
|
@@ -73776,7 +74935,7 @@ function checkArity2(argTypes, nargout) {
|
|
|
73776
74935
|
function staticVerdict(t) {
|
|
73777
74936
|
if (!isNumeric2(t)) return true;
|
|
73778
74937
|
if (!t.isComplex) return true;
|
|
73779
|
-
if (!isScalar(t)) return
|
|
74938
|
+
if (!isScalar(t)) return "runtime";
|
|
73780
74939
|
const ex = t.exact;
|
|
73781
74940
|
if (ex !== void 0 && typeof ex === "object" && "im" in ex) {
|
|
73782
74941
|
const im = ex.im;
|
|
@@ -73793,23 +74952,33 @@ var isreal = {
|
|
|
73793
74952
|
return [scalarLogical(v)];
|
|
73794
74953
|
},
|
|
73795
74954
|
emitC({ argTypes, argsC, useRuntime }) {
|
|
73796
|
-
const
|
|
74955
|
+
const t = argTypes[0];
|
|
74956
|
+
const v = staticVerdict(t);
|
|
73797
74957
|
if (v === true) return "1.0";
|
|
73798
74958
|
if (v === false) return "0.0";
|
|
74959
|
+
if (isNumeric2(t) && t.isComplex && !isScalar(t)) {
|
|
74960
|
+
useRuntime("mtoc2_tensor_imag_all_zero");
|
|
74961
|
+
return `mtoc2_tensor_imag_all_zero(${argsC[0]})`;
|
|
74962
|
+
}
|
|
73799
74963
|
useRuntime("mtoc2_cscalar");
|
|
73800
74964
|
return `(cimag(${argsC[0]}) == 0.0)`;
|
|
73801
74965
|
},
|
|
73802
|
-
emitJs({ argTypes, argsJs }) {
|
|
73803
|
-
const
|
|
74966
|
+
emitJs({ argTypes, argsJs, useRuntime }) {
|
|
74967
|
+
const t = argTypes[0];
|
|
74968
|
+
const v = staticVerdict(t);
|
|
73804
74969
|
if (v === true) return "true";
|
|
73805
74970
|
if (v === false) return "false";
|
|
74971
|
+
if (isNumeric2(t) && t.isComplex && !isScalar(t)) {
|
|
74972
|
+
useRuntime("mtoc2_tensor_imag_all_zero");
|
|
74973
|
+
return `mtoc2_tensor_imag_all_zero(${argsJs[0]})`;
|
|
74974
|
+
}
|
|
73806
74975
|
return `(${argsJs[0]}.im === 0)`;
|
|
73807
74976
|
},
|
|
73808
74977
|
call({ args }) {
|
|
73809
74978
|
const v = args[0];
|
|
73810
74979
|
if (typeof v === "number" || typeof v === "boolean") return [true];
|
|
73811
74980
|
if (isComplexValue(v)) return [v.im === 0];
|
|
73812
|
-
if (isTensor(v)) return [
|
|
74981
|
+
if (isTensor(v)) return [mtoc2_tensor_imag_all_zero(v)];
|
|
73813
74982
|
return [true];
|
|
73814
74983
|
}
|
|
73815
74984
|
};
|
|
@@ -78363,7 +79532,7 @@ function lowerFuncCall(e) {
|
|
|
78363
79532
|
if (envEntry === void 0 && e.name === "feval") {
|
|
78364
79533
|
return lowerFevalCall.call(this, e);
|
|
78365
79534
|
}
|
|
78366
|
-
if (envEntry !== void 0 &&
|
|
79535
|
+
if (envEntry !== void 0 && isHandle2(envEntry.ty)) {
|
|
78367
79536
|
return dispatchHandleCall.call(this, e.name, envEntry, e.args, e.span);
|
|
78368
79537
|
}
|
|
78369
79538
|
if (envEntry === void 0 && this.workspace.isClass(e.name)) {
|
|
@@ -78810,7 +79979,7 @@ function lowerMultiAssign(s) {
|
|
|
78810
79979
|
s = { ...s, lvalues: expandedLvalues };
|
|
78811
79980
|
if (s.expr.type === "FuncCall") {
|
|
78812
79981
|
const envEntry = this.env.get(callName);
|
|
78813
|
-
if (envEntry !== void 0 &&
|
|
79982
|
+
if (envEntry !== void 0 && isHandle2(envEntry.ty)) {
|
|
78814
79983
|
return dispatchHandleMultiAssign.call(
|
|
78815
79984
|
this,
|
|
78816
79985
|
callName,
|
|
@@ -81969,6 +83138,13 @@ var REGISTRY2 = /* @__PURE__ */ new Map([
|
|
|
81969
83138
|
"mtoc2_cdiv"
|
|
81970
83139
|
])
|
|
81971
83140
|
],
|
|
83141
|
+
// `isreal` on a complex-typed tensor: scan the imag lane (true iff all
|
|
83142
|
+
// zero). Lets the JIT report realness by value, matching the
|
|
83143
|
+
// interpreter on tensors the type system could not prove real.
|
|
83144
|
+
[
|
|
83145
|
+
"mtoc2_tensor_imag_all_zero",
|
|
83146
|
+
loadSnippet("tensor_imag_all_zero.h", ["mtoc2_tensor_t"])
|
|
83147
|
+
],
|
|
81972
83148
|
// ── Elementwise binary/unary on real tensors ──────────────────────
|
|
81973
83149
|
// One snippet covers all 11 funcs (4×_tt, 4×_ts, 2×_st, 1×uminus).
|
|
81974
83150
|
// Builtins activate by op-specific synthetic name; all map to the
|