numbl 0.4.2 → 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-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 mag = Math.abs(tfr) + Math.abs(tfi) + Math.abs(tgr) + Math.abs(tgi);
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 (mag < 1e-16 * ref) break;
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 mag = Math.pow(-negBase, exponent);
22333
- return { re: mag * cospi(exponent), im: mag * sinpi(exponent) };
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 mag = Math.hypot(re, im);
29289
- if (mag === 0) return { re: 0, im: 0 };
29290
- const r = Math.sqrt(mag);
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 mag = Math.hypot(re, im);
29339
- if (mag === 0) return { re: 0, im: 0 };
29340
- return { re: re / mag, im: im / mag };
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({
@@ -34070,10 +34070,10 @@ function sortTensor(v, dim, descend, nargout) {
34070
34070
  const dimSize = shape[dimIdx];
34071
34071
  let cmpFlatIdx;
34072
34072
  if (im && !im.every((x) => x === 0)) {
34073
- const mag = (i) => Math.sqrt(re[i] * re[i] + im[i] * im[i]);
34073
+ const mag2 = (i) => Math.sqrt(re[i] * re[i] + im[i] * im[i]);
34074
34074
  const phase = (i) => Math.atan2(im[i], re[i]);
34075
34075
  cmpFlatIdx = (a, b) => {
34076
- const diff2 = mag(a) - mag(b);
34076
+ const diff2 = mag2(a) - mag2(b);
34077
34077
  if (diff2 !== 0) return descend ? -diff2 : diff2;
34078
34078
  const pDiff = phase(a) - phase(b);
34079
34079
  return descend ? -pDiff : pDiff;
@@ -35501,9 +35501,9 @@ function invComplexJS(dataRe, dataIm, n) {
35501
35501
  let maxRow = col;
35502
35502
  let maxMag = augRe[col * 2 * n + col] ** 2 + augIm[col * 2 * n + col] ** 2;
35503
35503
  for (let row = col + 1; row < n; row++) {
35504
- const mag = augRe[row * 2 * n + col] ** 2 + augIm[row * 2 * n + col] ** 2;
35505
- if (mag > maxMag) {
35506
- maxMag = mag;
35504
+ const mag2 = augRe[row * 2 * n + col] ** 2 + augIm[row * 2 * n + col] ** 2;
35505
+ if (mag2 > maxMag) {
35506
+ maxMag = mag2;
35507
35507
  maxRow = row;
35508
35508
  }
35509
35509
  }
@@ -35548,6 +35548,88 @@ function invComplexJS(dataRe, dataIm, n) {
35548
35548
  }
35549
35549
  return { re: resultRe, im: resultIm };
35550
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
+ }
35551
35633
  registerIBuiltin({
35552
35634
  name: "svd",
35553
35635
  resolve: (argTypes, nargout) => {
@@ -37074,8 +37156,8 @@ function isFiberConjugateSymmetric(re, im) {
37074
37156
  if (N <= 1) return Math.abs(im[0]) < 1e-14;
37075
37157
  let maxMag = 0;
37076
37158
  for (let i = 0; i < N; i++) {
37077
- const mag = Math.abs(re[i]) + Math.abs(im[i]);
37078
- if (mag > maxMag) maxMag = mag;
37159
+ const mag2 = Math.abs(re[i]) + Math.abs(im[i]);
37160
+ if (mag2 > maxMag) maxMag = mag2;
37079
37161
  }
37080
37162
  const tol = Math.max(1e-14, maxMag * 1e-12);
37081
37163
  if (Math.abs(im[0]) > tol) return false;
@@ -45645,6 +45727,10 @@ var H = {
45645
45727
  signatures: ["B = inv(A)"],
45646
45728
  description: "Matrix inverse."
45647
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
+ },
45648
45734
  trace: {
45649
45735
  signatures: ["T = trace(A)"],
45650
45736
  description: "Sum of diagonal elements."
@@ -45653,6 +45739,17 @@ var H = {
45653
45739
  signatures: ["E = eig(A)", "[V, D] = eig(A)", "[V, D, W] = eig(A)"],
45654
45740
  description: "Eigenvalues and eigenvectors of square matrix. With three outputs, W contains left eigenvectors."
45655
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
+ },
45656
45753
  svd: {
45657
45754
  signatures: [
45658
45755
  "S = svd(A)",
@@ -46454,6 +46551,17 @@ var H = {
46454
46551
  signatures: ["colorbar", "colorbar(MODE)"],
46455
46552
  description: "Display colorbar on current axes."
46456
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
+ },
46457
46565
  xlim: {
46458
46566
  signatures: ["xlim(LIMITS)"],
46459
46567
  description: "Set x-axis limits."
@@ -49627,6 +49735,134 @@ function stream2Call(args) {
49627
49735
  return RTV.cell(cellData, [1, cellData.length]);
49628
49736
  }
49629
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
+
49630
49866
  // src/numbl-core/runtime/plotBuiltinDispatch.ts
49631
49867
  function dispatchPlotBuiltin(name, args, instructions, state) {
49632
49868
  switch (name) {
@@ -49815,10 +50051,7 @@ function dispatchPlotBuiltin(name, args, instructions, state) {
49815
50051
  dispatchColormap(args, instructions);
49816
50052
  return true;
49817
50053
  case "axis": {
49818
- if (args.length > 0) {
49819
- const val = toString(args[0]).replace(/^"|"$/g, "");
49820
- plotInstr(instructions, { type: "set_axis", value: val });
49821
- }
50054
+ applyAxisCommand(args, instructions);
49822
50055
  return true;
49823
50056
  }
49824
50057
  case "caxis":
@@ -50513,6 +50746,85 @@ function quadgkAdaptive(integrand, a, b, opts = {}) {
50513
50746
  };
50514
50747
  }
50515
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
+
50516
50828
  // src/numbl-core/runtime/specialBuiltinNames.ts
50517
50829
  var SPECIAL_BUILTIN_NAMES = [
50518
50830
  "help",
@@ -50631,6 +50943,7 @@ var SPECIAL_BUILTIN_NAMES = [
50631
50943
  "toc",
50632
50944
  "quadgk",
50633
50945
  "gmres",
50946
+ "eigs",
50634
50947
  "onCleanup"
50635
50948
  ];
50636
50949
 
@@ -52008,6 +52321,9 @@ function registerSpecialBuiltins(rt) {
52008
52321
  registerSpecial("gmres", (nargout, args) => {
52009
52322
  return _gmresImpl(rt, nargout, args);
52010
52323
  });
52324
+ registerSpecial("eigs", (nargout, args) => {
52325
+ return _eigsImpl(rt, nargout, args);
52326
+ });
52011
52327
  registerSpecial("onCleanup", (_nargout, args) => {
52012
52328
  if (args.length !== 1 || !isRuntimeFunction(args[0]))
52013
52329
  throw new RuntimeError("onCleanup requires a function handle argument");
@@ -52015,6 +52331,271 @@ function registerSpecialBuiltins(rt) {
52015
52331
  return RTV.classInstance("onCleanup", [], false);
52016
52332
  });
52017
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
+ }
52018
52599
  function _ode45Impl(rt, nargout, args, tableau = dormandPrince45) {
52019
52600
  const solverName = tableau.name;
52020
52601
  if (args.length < 3)
@@ -54372,6 +54953,484 @@ function memberChainAssign(rt, base, names, rhs) {
54372
54953
  return subsasgnFallback(rt, base, names, rhs);
54373
54954
  }
54374
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
+
54375
55434
  // src/numbl-core/runtime/runtime.ts
54376
55435
  var Runtime = class _Runtime {
54377
55436
  constructor(options, initialVariableValues) {
@@ -54593,6 +55652,18 @@ var Runtime = class _Runtime {
54593
55652
  }
54594
55653
  return RTV.dummyHandle();
54595
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
+ };
54596
55667
  this.builtins["fplot"] = (_nargout, args) => {
54597
55668
  fplotCall(this, this.plotInstructions, args.map(ensureRuntimeValue));
54598
55669
  };
@@ -55496,6 +56567,21 @@ var Runtime = class _Runtime {
55496
56567
  ishold() {
55497
56568
  return RTV.logical(this.holdState);
55498
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
+ }
55499
56585
  // ── Drawnow / Pause ─────────────────────────────────────────────────
55500
56586
  drawnow() {
55501
56587
  return drawnow(this.plotInstructions, this.options);
@@ -59257,11 +60343,11 @@ function instantiateClass(className, args, nargout) {
59257
60343
  } catch {
59258
60344
  }
59259
60345
  }
59260
- const isHandle2 = this.isHandleClass(classInfo);
60346
+ const isHandle3 = this.isHandleClass(classInfo);
59261
60347
  const instance = RTV.classInstance(
59262
60348
  className,
59263
60349
  propertyNames,
59264
- isHandle2,
60350
+ isHandle3,
59265
60351
  defaults
59266
60352
  );
59267
60353
  if (classInfo.constructorName) {
@@ -61313,7 +62399,7 @@ function isNumeric2(t) {
61313
62399
  function isVoid(t) {
61314
62400
  return t.kind === "Void";
61315
62401
  }
61316
- function isHandle(t) {
62402
+ function isHandle2(t) {
61317
62403
  return t.kind === "Handle";
61318
62404
  }
61319
62405
  function isStruct(t) {
@@ -64780,17 +65866,17 @@ function complex_sort_indices(a, descending) {
64780
65866
  });
64781
65867
  return idx;
64782
65868
  }
64783
- const mag = new Float64Array(n);
65869
+ const mag2 = new Float64Array(n);
64784
65870
  const ph = new Float64Array(n);
64785
65871
  for (let i = 0; i < n; i++) {
64786
65872
  const re = a.data[i];
64787
65873
  const xi = im !== void 0 ? im[i] : 0;
64788
- mag[i] = Math.hypot(re, xi);
65874
+ mag2[i] = Math.hypot(re, xi);
64789
65875
  ph[i] = Math.atan2(xi, re);
64790
65876
  }
64791
65877
  idx.sort((p2, q) => {
64792
- if (mag[p2] < mag[q]) return descending ? 1 : -1;
64793
- if (mag[p2] > mag[q]) return descending ? -1 : 1;
65878
+ if (mag2[p2] < mag2[q]) return descending ? 1 : -1;
65879
+ if (mag2[p2] > mag2[q]) return descending ? -1 : 1;
64794
65880
  if (ph[p2] < ph[q]) return descending ? 1 : -1;
64795
65881
  if (ph[p2] > ph[q]) return descending ? -1 : 1;
64796
65882
  return p2 - q;
@@ -67611,7 +68697,7 @@ var ge = defineCompare("ge", ">=", (a, b) => a >= b);
67611
68697
  // src/numbl-core/jit/codegen/cHelpers.ts
67612
68698
  function cTypeFor(t) {
67613
68699
  if (isMultiElement(t)) return "mtoc2_tensor_t";
67614
- if (isHandle(t)) return handleTypedefName(t);
68700
+ if (isHandle2(t)) return handleTypedefName(t);
67615
68701
  if (t.kind === "Struct") return structTypedefName(t);
67616
68702
  if (t.kind === "Class") return classTypedefName(t);
67617
68703
  if (t.kind === "Cell") return cellTypedefName(t);
@@ -73247,7 +74333,7 @@ function staticAnswer(t) {
73247
74333
  }
73248
74334
  if (isString(t)) return true;
73249
74335
  if (isChar(t)) return false;
73250
- if (isStruct(t) || isClass(t) || isHandle(t)) return false;
74336
+ if (isStruct(t) || isClass(t) || isHandle2(t)) return false;
73251
74337
  return void 0;
73252
74338
  }
73253
74339
  function requireKnown(t) {
@@ -73366,7 +74452,7 @@ var isstruct = {
73366
74452
  function staticClassNameOf(t) {
73367
74453
  if (isClass(t)) return t.className;
73368
74454
  if (isStruct(t)) return "struct";
73369
- if (isHandle(t)) return "function_handle";
74455
+ if (isHandle2(t)) return "function_handle";
73370
74456
  if (isChar(t)) return "char";
73371
74457
  if (isString(t)) return "string";
73372
74458
  if (isCell(t)) return "cell";
@@ -78446,7 +79532,7 @@ function lowerFuncCall(e) {
78446
79532
  if (envEntry === void 0 && e.name === "feval") {
78447
79533
  return lowerFevalCall.call(this, e);
78448
79534
  }
78449
- if (envEntry !== void 0 && isHandle(envEntry.ty)) {
79535
+ if (envEntry !== void 0 && isHandle2(envEntry.ty)) {
78450
79536
  return dispatchHandleCall.call(this, e.name, envEntry, e.args, e.span);
78451
79537
  }
78452
79538
  if (envEntry === void 0 && this.workspace.isClass(e.name)) {
@@ -78893,7 +79979,7 @@ function lowerMultiAssign(s) {
78893
79979
  s = { ...s, lvalues: expandedLvalues };
78894
79980
  if (s.expr.type === "FuncCall") {
78895
79981
  const envEntry = this.env.get(callName);
78896
- if (envEntry !== void 0 && isHandle(envEntry.ty)) {
79982
+ if (envEntry !== void 0 && isHandle2(envEntry.ty)) {
78897
79983
  return dispatchHandleMultiAssign.call(
78898
79984
  this,
78899
79985
  callName,