numbl 0.0.15 → 0.0.17

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 CHANGED
@@ -158,17 +158,17 @@ async function fetchPackageIndex(backend, indexUrl = DEFAULT_INDEX_URL) {
158
158
  return backend.fetchJson(indexUrl);
159
159
  }
160
160
  function findPackageEntry(index2, packageName, arch) {
161
- const exact = index2.packages.find(
162
- (p) => p.name === packageName && p.architecture === arch
163
- );
164
- if (exact) return exact;
165
- return index2.packages.find(
166
- (p) => p.name === packageName && p.architecture === "any"
167
- );
161
+ for (const candidate of ["numbl_" + arch, "numbl_wasm", "any"]) {
162
+ const entry = index2.packages.find(
163
+ (p) => p.name === packageName && p.architecture === candidate
164
+ );
165
+ if (entry) return entry;
166
+ }
167
+ return void 0;
168
168
  }
169
169
  function listAvailablePackages(index2, arch) {
170
170
  return index2.packages.filter(
171
- (p) => p.architecture === arch || p.architecture === "any"
171
+ (p) => p.architecture === "numbl_" + arch || p.architecture === "numbl_wasm" || p.architecture === "any"
172
172
  );
173
173
  }
174
174
 
@@ -181,7 +181,9 @@ function resolveDependencies(index2, packageName, arch) {
181
181
  visited.add(name);
182
182
  const entry = findPackageEntry(index2, name, arch);
183
183
  if (!entry) {
184
- throw new Error(`Package "${name}" not found for architecture "${arch}"`);
184
+ throw new Error(
185
+ `Package "${name}" not found for architecture "${arch}" (tried ${arch}, wasm, all)`
186
+ );
185
187
  }
186
188
  for (const dep of entry.dependencies) {
187
189
  visit(dep);
@@ -210,13 +212,13 @@ function computeRequiredPackages(directlyInstalled, index2, arch) {
210
212
 
211
213
  // src/mip/mip-manager.ts
212
214
  function packagesDir(mipDir) {
213
- return `${mipDir}/packages`;
215
+ return `${mipDir}/numbl_packages`;
214
216
  }
215
217
  function packageDir(mipDir, name) {
216
- return `${mipDir}/packages/${name}`;
218
+ return `${mipDir}/numbl_packages/${name}`;
217
219
  }
218
220
  function directlyInstalledPath(mipDir) {
219
- return `${mipDir}/packages/directly_installed.txt`;
221
+ return `${mipDir}/numbl_packages/directly_installed.txt`;
220
222
  }
221
223
  var MipManager = class {
222
224
  constructor(backend) {
@@ -17430,14 +17432,24 @@ function parseEconArg(argType) {
17430
17432
  if (isString(argType) === true || isChar(argType) === true) return "unknown";
17431
17433
  return null;
17432
17434
  }
17435
+ function toF64(data) {
17436
+ return data instanceof Float64Array ? data : new Float64Array(data);
17437
+ }
17438
+ function parseStringArgLower(arg) {
17439
+ if (typeof arg === "string") {
17440
+ return arg.replace(/^['"]|['"]$/g, "").toLowerCase();
17441
+ }
17442
+ if (arg && typeof arg === "object" && "value" in arg) {
17443
+ return String(arg.value).replace(/^['"]|['"]$/g, "").toLowerCase();
17444
+ }
17445
+ return String(arg).toLowerCase();
17446
+ }
17433
17447
 
17434
17448
  // src/numbl-core/builtins/linear-algebra/linsolve.ts
17435
17449
  function linsolveLapack(A, m, n, B, nrhs) {
17436
17450
  const bridge = getEffectiveBridge("linsolve", "linsolve");
17437
17451
  if (!bridge?.linsolve) return null;
17438
- const f64A = A instanceof Float64Array ? A : new Float64Array(A);
17439
- const f64B = B instanceof Float64Array ? B : new Float64Array(B);
17440
- return bridge.linsolve(f64A, m, n, f64B, nrhs);
17452
+ return bridge.linsolve(toF64(A), m, n, toF64(B), nrhs);
17441
17453
  }
17442
17454
  function linsolveComplexLapack(ARe, AIm, m, n, BRe, BIm, nrhs) {
17443
17455
  const bridge = getEffectiveBridge("linsolveComplex", "linsolveComplex");
@@ -17445,11 +17457,15 @@ function linsolveComplexLapack(ARe, AIm, m, n, BRe, BIm, nrhs) {
17445
17457
  throw new RuntimeError(
17446
17458
  "linsolveComplex: no bridge available (should not happen)"
17447
17459
  );
17448
- const f64ARe = ARe instanceof Float64Array ? ARe : new Float64Array(ARe);
17449
- const f64AIm = AIm instanceof Float64Array ? AIm : new Float64Array(AIm);
17450
- const f64BRe = BRe instanceof Float64Array ? BRe : new Float64Array(BRe);
17451
- const f64BIm = BIm instanceof Float64Array ? BIm : new Float64Array(BIm);
17452
- return bridge.linsolveComplex(f64ARe, f64AIm, m, n, f64BRe, f64BIm, nrhs);
17460
+ return bridge.linsolveComplex(
17461
+ toF64(ARe),
17462
+ toF64(AIm),
17463
+ m,
17464
+ n,
17465
+ toF64(BRe),
17466
+ toF64(BIm),
17467
+ nrhs
17468
+ );
17453
17469
  }
17454
17470
  function registerLinsolve() {
17455
17471
  register("linsolve", [
@@ -17600,6 +17616,22 @@ function complexComparisonOp(a, b, op) {
17600
17616
  `Matrix dimensions must agree for comparison: [${at.shape.join(",")}] vs [${bt.shape.join(",")}]`
17601
17617
  );
17602
17618
  }
17619
+ function signedInf(x) {
17620
+ return x > 0 ? Infinity : x < 0 ? -Infinity : 0;
17621
+ }
17622
+ function complexDivide(aRe, aIm, bRe, bIm) {
17623
+ const denom = bRe * bRe + bIm * bIm;
17624
+ if (denom === 0) {
17625
+ if (aRe === 0 && aIm === 0) {
17626
+ return { re: NaN, im: 0 };
17627
+ }
17628
+ return { re: signedInf(aRe), im: signedInf(aIm) };
17629
+ }
17630
+ return {
17631
+ re: (aRe * bRe + aIm * bIm) / denom,
17632
+ im: (aIm * bRe - aRe * bIm) / denom
17633
+ };
17634
+ }
17603
17635
  function complexBinaryOp(a, b, op) {
17604
17636
  const ac = toComplexParts(a);
17605
17637
  const bc = toComplexParts(b);
@@ -17702,25 +17734,13 @@ function mDiv(a, b) {
17702
17734
  return mConjugateTranspose(result);
17703
17735
  }
17704
17736
  if (isComplexOrMixed(a, b)) {
17705
- return complexBinaryOp(a, b, (aRe, aIm, bRe, bIm) => {
17706
- const denom = bRe * bRe + bIm * bIm;
17707
- return {
17708
- re: (aRe * bRe + aIm * bIm) / denom,
17709
- im: (aIm * bRe - aRe * bIm) / denom
17710
- };
17711
- });
17737
+ return complexBinaryOp(a, b, complexDivide);
17712
17738
  }
17713
17739
  return binaryOp(a, b, (x, y) => x / y);
17714
17740
  }
17715
17741
  function mElemDiv(a, b) {
17716
17742
  if (isComplexOrMixed(a, b)) {
17717
- return complexBinaryOp(a, b, (aRe, aIm, bRe, bIm) => {
17718
- const denom = bRe * bRe + bIm * bIm;
17719
- return {
17720
- re: (aRe * bRe + aIm * bIm) / denom,
17721
- im: (aIm * bRe - aRe * bIm) / denom
17722
- };
17723
- });
17743
+ return complexBinaryOp(a, b, complexDivide);
17724
17744
  }
17725
17745
  return binaryOp(a, b, (x, y) => x / y);
17726
17746
  }
@@ -20603,7 +20623,8 @@ var COMMAND_VERBS = [
20603
20623
  "square",
20604
20624
  "vis3d"
20605
20625
  ],
20606
- optional: false
20626
+ optional: false,
20627
+ multiKeyword: true
20607
20628
  }
20608
20629
  },
20609
20630
  { name: "clear", argKind: { type: "Any" } },
@@ -20965,19 +20986,41 @@ var ExpressionParser = class extends ParserBase {
20965
20986
  }
20966
20987
  }
20967
20988
  parsePow() {
20968
- const node = this.parsePostfix();
20969
- const tok = this.peekToken();
20970
- let op;
20971
- if (tok === 36 /* Caret */) {
20972
- op = "Pow" /* Pow */;
20973
- } else if (tok === 58 /* DotCaret */) {
20974
- op = "ElemPow" /* ElemPow */;
20975
- } else {
20976
- return node;
20989
+ let node = this.parsePostfix();
20990
+ while (true) {
20991
+ const tok = this.peekToken();
20992
+ let op;
20993
+ if (tok === 36 /* Caret */) {
20994
+ op = "Pow" /* Pow */;
20995
+ } else if (tok === 58 /* DotCaret */) {
20996
+ op = "ElemPow" /* ElemPow */;
20997
+ } else {
20998
+ return node;
20999
+ }
21000
+ this.pos++;
21001
+ const rhs = this.parsePowRHS();
21002
+ node = this.makeBinary(node, op, rhs);
20977
21003
  }
20978
- this.pos++;
20979
- const rhs = this.parseUnary();
20980
- return this.makeBinary(node, op, rhs);
21004
+ }
21005
+ /** Parse the right-hand side of a ^ or .^ operator: unary prefixes then postfix. */
21006
+ parsePowRHS() {
21007
+ if (this.peekToken() === 31 /* Plus */) {
21008
+ const start = this.tokens[this.pos].position;
21009
+ this.pos++;
21010
+ const expr = this.parsePowRHS();
21011
+ return this.makeUnary("Plus" /* Plus */, expr, start);
21012
+ } else if (this.peekToken() === 32 /* Minus */) {
21013
+ const start = this.tokens[this.pos].position;
21014
+ this.pos++;
21015
+ const expr = this.parsePowRHS();
21016
+ return this.makeUnary("Minus" /* Minus */, expr, start);
21017
+ } else if (this.peekToken() === 39 /* Tilde */) {
21018
+ const start = this.tokens[this.pos].position;
21019
+ this.pos++;
21020
+ const expr = this.parsePowRHS();
21021
+ return this.makeUnary("Not" /* Not */, expr, start);
21022
+ }
21023
+ return this.parsePostfix();
20981
21024
  }
20982
21025
  parsePostfixWithBase(expr) {
20983
21026
  while (true) {
@@ -21560,25 +21603,32 @@ var CommandParser = class extends ExpressionParser {
21560
21603
  }
21561
21604
  return args;
21562
21605
  }
21563
- if (args.length > 1) {
21606
+ if (args.length > 1 && !command.argKind.multiKeyword) {
21564
21607
  throw this.error(
21565
21608
  `'${command.name}' command syntax accepts only one argument`
21566
21609
  );
21567
21610
  }
21568
- const keyword = extractKeyword(args[0]);
21569
- if (!keyword) {
21570
- throw this.error(
21571
- `'${command.name}' command syntax expects a keyword argument`
21572
- );
21611
+ const keywords = [];
21612
+ for (const arg of args) {
21613
+ const keyword = extractKeyword(arg);
21614
+ if (!keyword) {
21615
+ throw this.error(
21616
+ `'${command.name}' command syntax expects a keyword argument`
21617
+ );
21618
+ }
21619
+ if (allowed !== void 0 && !allowed.some((a) => a.toLowerCase() === keyword.toLowerCase())) {
21620
+ throw this.error(
21621
+ `'${command.name}' command syntax does not support '${keyword}'`
21622
+ );
21623
+ }
21624
+ keywords.push(keyword);
21573
21625
  }
21574
- if (allowed === void 0 || allowed.some((a) => a.toLowerCase() === keyword.toLowerCase())) {
21575
- const span = args[0].span;
21576
- return [{ type: "String", value: `"${keyword}"`, span }];
21577
- } else {
21578
- throw this.error(
21579
- `'${command.name}' command syntax does not support '${keyword}'`
21580
- );
21626
+ if (keywords.length === 1) {
21627
+ const span2 = args[0].span;
21628
+ return [{ type: "String", value: `"${keywords[0]}"`, span: span2 }];
21581
21629
  }
21630
+ const span = args[0].span;
21631
+ return [{ type: "String", value: `"${keywords.join(" ")}"`, span }];
21582
21632
  }
21583
21633
  return args;
21584
21634
  }
@@ -24487,82 +24537,43 @@ function registerMathFunctions() {
24487
24537
  }),
24488
24538
  1
24489
24539
  );
24490
- register(
24491
- "isnan",
24492
- builtinSingle((args) => {
24493
- if (args.length !== 1)
24494
- throw new RuntimeError("isnan requires 1 argument");
24495
- const v = args[0];
24496
- if (isRuntimeNumber(v)) return RTV.logical(Number.isNaN(v));
24497
- if (isRuntimeLogical(v)) return RTV.logical(false);
24498
- if (isRuntimeComplexNumber(v))
24499
- return RTV.logical(Number.isNaN(v.re) || Number.isNaN(v.im));
24500
- if (isRuntimeTensor(v)) {
24501
- const result = new FloatXArray(v.data.length);
24502
- for (let i = 0; i < v.data.length; i++) {
24503
- const reNaN = Number.isNaN(v.data[i]);
24504
- const imNaN = v.imag ? Number.isNaN(v.imag[i]) : false;
24505
- result[i] = reNaN || imNaN ? 1 : 0;
24506
- }
24507
- const t = RTV.tensor(result, v.shape);
24508
- t._isLogical = true;
24509
- return t;
24510
- }
24511
- throw new RuntimeError("Expected numeric argument");
24512
- }),
24513
- 1
24514
- );
24515
- register(
24516
- "isinf",
24517
- builtinSingle((args) => {
24518
- if (args.length !== 1)
24519
- throw new RuntimeError("isinf requires 1 argument");
24520
- const v = args[0];
24521
- const isInf = (x) => !Number.isFinite(x) && !Number.isNaN(x);
24522
- if (isRuntimeNumber(v)) return RTV.logical(isInf(v));
24523
- if (isRuntimeLogical(v)) return RTV.logical(false);
24524
- if (isRuntimeComplexNumber(v))
24525
- return RTV.logical(isInf(v.re) || isInf(v.im));
24526
- if (isRuntimeTensor(v)) {
24527
- const result = new FloatXArray(v.data.length);
24528
- for (let i = 0; i < v.data.length; i++) {
24529
- const reInf = isInf(v.data[i]);
24530
- const imInf = v.imag ? isInf(v.imag[i]) : false;
24531
- result[i] = reInf || imInf ? 1 : 0;
24540
+ function numericPredicate(name, scalarTest, logicalDefault, combineReIm) {
24541
+ register(
24542
+ name,
24543
+ builtinSingle((args) => {
24544
+ if (args.length !== 1)
24545
+ throw new RuntimeError(`${name} requires 1 argument`);
24546
+ const v = args[0];
24547
+ if (isRuntimeNumber(v)) return RTV.logical(scalarTest(v));
24548
+ if (isRuntimeLogical(v)) return RTV.logical(logicalDefault);
24549
+ if (isRuntimeComplexNumber(v)) {
24550
+ const re = scalarTest(v.re), im = scalarTest(v.im);
24551
+ return RTV.logical(combineReIm === "or" ? re || im : re && im);
24532
24552
  }
24533
- const t = RTV.tensor(result, v.shape);
24534
- t._isLogical = true;
24535
- return t;
24536
- }
24537
- throw new RuntimeError("Expected numeric argument");
24538
- }),
24539
- 1
24540
- );
24541
- register(
24542
- "isfinite",
24543
- builtinSingle((args) => {
24544
- if (args.length !== 1)
24545
- throw new RuntimeError("isfinite requires 1 argument");
24546
- const v = args[0];
24547
- if (isRuntimeNumber(v)) return RTV.logical(Number.isFinite(v));
24548
- if (isRuntimeLogical(v)) return RTV.logical(true);
24549
- if (isRuntimeComplexNumber(v))
24550
- return RTV.logical(Number.isFinite(v.re) && Number.isFinite(v.im));
24551
- if (isRuntimeTensor(v)) {
24552
- const result = new FloatXArray(v.data.length);
24553
- for (let i = 0; i < v.data.length; i++) {
24554
- const reFin = Number.isFinite(v.data[i]);
24555
- const imFin = v.imag ? Number.isFinite(v.imag[i]) : true;
24556
- result[i] = reFin && imFin ? 1 : 0;
24553
+ if (isRuntimeTensor(v)) {
24554
+ const result = new FloatXArray(v.data.length);
24555
+ for (let i = 0; i < v.data.length; i++) {
24556
+ const re = scalarTest(v.data[i]);
24557
+ const im = v.imag ? scalarTest(v.imag[i]) : logicalDefault;
24558
+ result[i] = (combineReIm === "or" ? re || im : re && im) ? 1 : 0;
24559
+ }
24560
+ const t = RTV.tensor(result, v.shape);
24561
+ t._isLogical = true;
24562
+ return t;
24557
24563
  }
24558
- const t = RTV.tensor(result, v.shape);
24559
- t._isLogical = true;
24560
- return t;
24561
- }
24562
- throw new RuntimeError("Expected numeric argument");
24563
- }),
24564
- 1
24564
+ throw new RuntimeError("Expected numeric argument");
24565
+ }),
24566
+ 1
24567
+ );
24568
+ }
24569
+ numericPredicate("isnan", Number.isNaN, false, "or");
24570
+ numericPredicate(
24571
+ "isinf",
24572
+ (x) => !Number.isFinite(x) && !Number.isNaN(x),
24573
+ false,
24574
+ "or"
24565
24575
  );
24576
+ numericPredicate("isfinite", Number.isFinite, true, "and");
24566
24577
  register(
24567
24578
  "real",
24568
24579
  builtinSingle((args) => {
@@ -24879,54 +24890,26 @@ function registerMathFunctions() {
24879
24890
  }),
24880
24891
  1
24881
24892
  );
24882
- register(
24883
- "besselj",
24884
- builtinSingle((args) => {
24885
- if (args.length < 2 || args.length > 3)
24886
- throw new RuntimeError("besselj requires 2 or 3 arguments");
24887
- const scale = args.length === 3 ? toNumber(args[2]) : 0;
24888
- return applyBesselBinary(args[0], args[1], (nu, z) => {
24889
- const val = besselj(nu, z);
24890
- return scale === 1 ? val * Math.exp(-Math.abs(z)) : val;
24891
- });
24892
- })
24893
- );
24894
- register(
24895
- "bessely",
24896
- builtinSingle((args) => {
24897
- if (args.length < 2 || args.length > 3)
24898
- throw new RuntimeError("bessely requires 2 or 3 arguments");
24899
- const scale = args.length === 3 ? toNumber(args[2]) : 0;
24900
- return applyBesselBinary(args[0], args[1], (nu, z) => {
24901
- const val = bessely(nu, z);
24902
- return scale === 1 ? val * Math.exp(-Math.abs(z)) : val;
24903
- });
24904
- })
24905
- );
24906
- register(
24907
- "besseli",
24908
- builtinSingle((args) => {
24909
- if (args.length < 2 || args.length > 3)
24910
- throw new RuntimeError("besseli requires 2 or 3 arguments");
24911
- const scale = args.length === 3 ? toNumber(args[2]) : 0;
24912
- return applyBesselBinary(args[0], args[1], (nu, z) => {
24913
- const val = besseli(nu, z);
24914
- return scale === 1 ? val * Math.exp(-Math.abs(z)) : val;
24915
- });
24916
- })
24917
- );
24918
- register(
24919
- "besselk",
24920
- builtinSingle((args) => {
24921
- if (args.length < 2 || args.length > 3)
24922
- throw new RuntimeError("besselk requires 2 or 3 arguments");
24923
- const scale = args.length === 3 ? toNumber(args[2]) : 0;
24924
- return applyBesselBinary(args[0], args[1], (nu, z) => {
24925
- const val = besselk(nu, z);
24926
- return scale === 1 ? val * Math.exp(z) : val;
24927
- });
24928
- })
24929
- );
24893
+ const besselDefs = [
24894
+ ["besselj", besselj, (z) => Math.exp(-Math.abs(z))],
24895
+ ["bessely", bessely, (z) => Math.exp(-Math.abs(z))],
24896
+ ["besseli", besseli, (z) => Math.exp(-Math.abs(z))],
24897
+ ["besselk", besselk, (z) => Math.exp(z)]
24898
+ ];
24899
+ for (const [name, fn, scaleFn] of besselDefs) {
24900
+ register(
24901
+ name,
24902
+ builtinSingle((args) => {
24903
+ if (args.length < 2 || args.length > 3)
24904
+ throw new RuntimeError(`${name} requires 2 or 3 arguments`);
24905
+ const scale = args.length === 3 ? toNumber(args[2]) : 0;
24906
+ return applyBesselBinary(args[0], args[1], (nu, z) => {
24907
+ const val = fn(nu, z);
24908
+ return scale === 1 ? val * scaleFn(z) : val;
24909
+ });
24910
+ })
24911
+ );
24912
+ }
24930
24913
  const airyFns = [airyAi, airyAiPrime, airyBi, airyBiPrime];
24931
24914
  const airyComplexKeys = ["ai", "aip", "bi", "bip"];
24932
24915
  function applyAiryElementwise(xArg, n, scaled) {
@@ -25342,33 +25325,36 @@ function registerPrngFunctions() {
25342
25325
  return RTV.num(0);
25343
25326
  })
25344
25327
  );
25345
- register("rand", [
25346
- // Legacy: rand('seed', s) — prefer rng(s) instead
25347
- {
25348
- check: (argTypes) => argTypes.length === 2 && (argTypes[0].kind === "Char" || argTypes[0].kind === "String") && (argTypes[1].kind === "Number" || argTypes[1].kind === "Unknown") ? { outputTypes: [{ kind: "Number" }] } : null,
25349
- apply: (args) => {
25350
- const s = args[0];
25351
- if (!isRuntimeString(s) && !isRuntimeChar(s) || rstr(s) !== "seed")
25352
- throw new RuntimeError(
25353
- "rand: only 'seed' string option is supported"
25354
- );
25355
- seedRng(Math.round(toNumber(args[1])));
25356
- return RTV.num(0);
25357
- }
25358
- },
25359
- {
25360
- check: realArrayConstructorCheck,
25361
- apply: (args) => {
25362
- if (args.length === 0) return RTV.num(rngRandom());
25363
- const shape = parseShapeArgs(args);
25364
- if (shape.length === 1) shape.push(shape[0]);
25365
- const n = numel(shape);
25366
- const data = new FloatXArray(n);
25367
- for (let i = 0; i < n; i++) data[i] = rngRandom();
25368
- return RTV.tensor(data, shape);
25328
+ function registerRandFn(name, gen) {
25329
+ register(name, [
25330
+ {
25331
+ check: (argTypes) => argTypes.length === 2 && (argTypes[0].kind === "Char" || argTypes[0].kind === "String") && (argTypes[1].kind === "Number" || argTypes[1].kind === "Unknown") ? { outputTypes: [{ kind: "Number" }] } : null,
25332
+ apply: (args) => {
25333
+ const s = args[0];
25334
+ if (!isRuntimeString(s) && !isRuntimeChar(s) || rstr(s) !== "seed")
25335
+ throw new RuntimeError(
25336
+ `${name}: only 'seed' string option is supported`
25337
+ );
25338
+ seedRng(Math.round(toNumber(args[1])));
25339
+ return RTV.num(0);
25340
+ }
25341
+ },
25342
+ {
25343
+ check: realArrayConstructorCheck,
25344
+ apply: (args) => {
25345
+ if (args.length === 0) return RTV.num(gen());
25346
+ const shape = parseShapeArgs(args);
25347
+ if (shape.length === 1) shape.push(shape[0]);
25348
+ const n = numel(shape);
25349
+ const data = new FloatXArray(n);
25350
+ for (let i = 0; i < n; i++) data[i] = gen();
25351
+ return RTV.tensor(data, shape);
25352
+ }
25369
25353
  }
25370
- }
25371
- ]);
25354
+ ]);
25355
+ }
25356
+ registerRandFn("rand", rngRandom);
25357
+ registerRandFn("randn", boxMullerRandom);
25372
25358
  register(
25373
25359
  "randi",
25374
25360
  builtinSingle((args) => {
@@ -25421,33 +25407,6 @@ function registerPrngFunctions() {
25421
25407
  return RTV.tensor(perm.slice(0, k), [1, k]);
25422
25408
  })
25423
25409
  );
25424
- register("randn", [
25425
- // Legacy: randn('seed', s) — prefer rng(s) instead
25426
- {
25427
- check: (argTypes) => argTypes.length === 2 && (argTypes[0].kind === "Char" || argTypes[0].kind === "String") && (argTypes[1].kind === "Number" || argTypes[1].kind === "Unknown") ? { outputTypes: [{ kind: "Number" }] } : null,
25428
- apply: (args) => {
25429
- const s = args[0];
25430
- if (!isRuntimeString(s) && !isRuntimeChar(s) || rstr(s) !== "seed")
25431
- throw new RuntimeError(
25432
- "randn: only 'seed' string option is supported"
25433
- );
25434
- seedRng(Math.round(toNumber(args[1])));
25435
- return RTV.num(0);
25436
- }
25437
- },
25438
- {
25439
- check: realArrayConstructorCheck,
25440
- apply: (args) => {
25441
- if (args.length === 0) return RTV.num(boxMullerRandom());
25442
- const shape = parseShapeArgs(args);
25443
- if (shape.length === 1) shape.push(shape[0]);
25444
- const n = numel(shape);
25445
- const data = new FloatXArray(n);
25446
- for (let i = 0; i < n; i++) data[i] = boxMullerRandom();
25447
- return RTV.tensor(data, shape);
25448
- }
25449
- }
25450
- ]);
25451
25410
  }
25452
25411
 
25453
25412
  // src/numbl-core/builtins/array.ts
@@ -25520,7 +25479,7 @@ function registerArrayFunctions() {
25520
25479
  "linspace",
25521
25480
  builtinSingle((args) => {
25522
25481
  if (args.length < 2 || args.length > 3)
25523
- throw new Error("linspace requires 2 or 3 arguments");
25482
+ throw new RuntimeError("linspace requires 2 or 3 arguments");
25524
25483
  const start = toNumber(args[0]);
25525
25484
  const end = toNumber(args[1]);
25526
25485
  const n = args.length === 3 ? Math.round(toNumber(args[2])) : 100;
@@ -25540,7 +25499,7 @@ function registerArrayFunctions() {
25540
25499
  return makeRangeTensor(toNumber(args[0]), 1, toNumber(args[1]));
25541
25500
  if (args.length === 3)
25542
25501
  return makeRangeTensor(toNumber(args[0]), toNumber(args[1]), toNumber(args[2]));
25543
- throw new Error("colon requires 2 or 3 arguments");
25502
+ throw new RuntimeError("colon requires 2 or 3 arguments");
25544
25503
  })
25545
25504
  );
25546
25505
  register(
@@ -27173,6 +27132,69 @@ function registerIntrospectionFunctions() {
27173
27132
  }
27174
27133
 
27175
27134
  // src/numbl-core/builtins/reduction.ts
27135
+ function nextSubscripts(subs, shape, skipDim) {
27136
+ for (let d = 0; d < subs.length; d++) {
27137
+ if (skipDim !== void 0 && d === skipDim) continue;
27138
+ subs[d]++;
27139
+ if (subs[d] < shape[d]) return true;
27140
+ subs[d] = 0;
27141
+ }
27142
+ return false;
27143
+ }
27144
+ function squeezeTrailing(shape) {
27145
+ while (shape.length > 2 && shape[shape.length - 1] === 1) {
27146
+ shape.pop();
27147
+ }
27148
+ }
27149
+ function scanLogical(data, imag, mode) {
27150
+ const defaultResult = mode === "all";
27151
+ for (let i = 0; i < data.length; i++) {
27152
+ const isNonZero = data[i] !== 0 || imag !== void 0 && imag[i] !== 0;
27153
+ if (isNonZero !== defaultResult) return !defaultResult;
27154
+ }
27155
+ return defaultResult;
27156
+ }
27157
+ function logicalAlongDim(v, dim, mode) {
27158
+ const shape = v.shape;
27159
+ const dimIdx = dim - 1;
27160
+ if (dimIdx >= shape.length) {
27161
+ const result2 = new FloatXArray(v.data.length);
27162
+ for (let i = 0; i < v.data.length; i++)
27163
+ result2[i] = v.data[i] !== 0 || v.imag && v.imag[i] !== 0 ? 1 : 0;
27164
+ const t2 = RTV.tensor(result2, [...shape]);
27165
+ t2._isLogical = true;
27166
+ return t2;
27167
+ }
27168
+ const reduceDimSize = shape[dimIdx];
27169
+ const resultShape = [...shape];
27170
+ resultShape[dimIdx] = 1;
27171
+ const totalElems = resultShape.reduce((a, b) => a * b, 1);
27172
+ const result = new FloatXArray(totalElems);
27173
+ const outSubs = new Array(shape.length).fill(0);
27174
+ for (let i = 0; i < totalElems; i++) {
27175
+ let val = mode === "all";
27176
+ for (let k = 0; k < reduceDimSize; k++) {
27177
+ const srcSubs = [...outSubs];
27178
+ srcSubs[dimIdx] = k;
27179
+ const srcIdx = sub2ind(shape, srcSubs);
27180
+ const isNonZero = v.data[srcIdx] !== 0 || v.imag !== void 0 && v.imag[srcIdx] !== 0;
27181
+ if (mode === "any" && isNonZero) {
27182
+ val = true;
27183
+ break;
27184
+ }
27185
+ if (mode === "all" && !isNonZero) {
27186
+ val = false;
27187
+ break;
27188
+ }
27189
+ }
27190
+ result[i] = val ? 1 : 0;
27191
+ nextSubscripts(outSubs, resultShape, dimIdx);
27192
+ }
27193
+ squeezeTrailing(resultShape);
27194
+ const t = RTV.tensor(result, resultShape);
27195
+ t._isLogical = true;
27196
+ return t;
27197
+ }
27176
27198
  function dimReduce(v, dim, reduceFn, initialValue, finalizeFn) {
27177
27199
  if (!isRuntimeTensor(v))
27178
27200
  throw new RuntimeError("dimReduce: argument must be a tensor");
@@ -27205,16 +27227,9 @@ function dimReduce(v, dim, reduceFn, initialValue, finalizeFn) {
27205
27227
  result[i] = finalizeFn ? finalizeFn(acc, reduceDimSize) : acc;
27206
27228
  if (resultImag)
27207
27229
  resultImag[i] = finalizeFn ? finalizeFn(accIm, reduceDimSize) : accIm;
27208
- for (let d = 0; d < outSubs.length; d++) {
27209
- if (d === dimIdx) continue;
27210
- outSubs[d]++;
27211
- if (outSubs[d] < resultShape[d]) break;
27212
- outSubs[d] = 0;
27213
- }
27214
- }
27215
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1) {
27216
- resultShape.pop();
27230
+ nextSubscripts(outSubs, resultShape, dimIdx);
27217
27231
  }
27232
+ squeezeTrailing(resultShape);
27218
27233
  const imOut = resultImag && resultImag.some((x) => x !== 0) ? resultImag : void 0;
27219
27234
  return RTV.tensor(result, resultShape, imOut);
27220
27235
  }
@@ -27258,15 +27273,9 @@ function complexProd(v, dim) {
27258
27273
  }
27259
27274
  resultRe[i] = accRe;
27260
27275
  resultIm[i] = accIm;
27261
- for (let d = 0; d < outSubs.length; d++) {
27262
- if (d === dimIdx) continue;
27263
- outSubs[d]++;
27264
- if (outSubs[d] < resultShape[d]) break;
27265
- outSubs[d] = 0;
27266
- }
27276
+ nextSubscripts(outSubs, resultShape, dimIdx);
27267
27277
  }
27268
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1)
27269
- resultShape.pop();
27278
+ squeezeTrailing(resultShape);
27270
27279
  const imOut = resultIm.some((x) => x !== 0) ? resultIm : void 0;
27271
27280
  return RTV.tensor(resultRe, resultShape, imOut);
27272
27281
  }
@@ -27330,92 +27339,6 @@ function preserveTypeCheck(argTypes, nargout) {
27330
27339
  if (nargout === 2) return { outputTypes: [outType, outType] };
27331
27340
  return null;
27332
27341
  }
27333
- function anyAlongDim(v, dim) {
27334
- const shape = v.shape;
27335
- const dimIdx = dim - 1;
27336
- if (dimIdx >= shape.length) {
27337
- const result2 = new FloatXArray(v.data.length);
27338
- for (let i = 0; i < v.data.length; i++)
27339
- result2[i] = v.data[i] !== 0 || v.imag && v.imag[i] !== 0 ? 1 : 0;
27340
- const t2 = RTV.tensor(result2, [...shape]);
27341
- t2._isLogical = true;
27342
- return t2;
27343
- }
27344
- const reduceDimSize = shape[dimIdx];
27345
- const resultShape = [...shape];
27346
- resultShape[dimIdx] = 1;
27347
- const totalElems = resultShape.reduce((a, b) => a * b, 1);
27348
- const result = new FloatXArray(totalElems);
27349
- const outSubs = new Array(shape.length).fill(0);
27350
- for (let i = 0; i < totalElems; i++) {
27351
- let found = false;
27352
- for (let k = 0; k < reduceDimSize; k++) {
27353
- const srcSubs = [...outSubs];
27354
- srcSubs[dimIdx] = k;
27355
- const srcIdx = sub2ind(shape, srcSubs);
27356
- if (v.data[srcIdx] !== 0 || v.imag && v.imag[srcIdx] !== 0) {
27357
- found = true;
27358
- break;
27359
- }
27360
- }
27361
- result[i] = found ? 1 : 0;
27362
- for (let d = 0; d < outSubs.length; d++) {
27363
- if (d === dimIdx) continue;
27364
- outSubs[d]++;
27365
- if (outSubs[d] < resultShape[d]) break;
27366
- outSubs[d] = 0;
27367
- }
27368
- }
27369
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1) {
27370
- resultShape.pop();
27371
- }
27372
- const t = RTV.tensor(result, resultShape);
27373
- t._isLogical = true;
27374
- return t;
27375
- }
27376
- function allAlongDim(v, dim) {
27377
- const shape = v.shape;
27378
- const dimIdx = dim - 1;
27379
- if (dimIdx >= shape.length) {
27380
- const result2 = new FloatXArray(v.data.length);
27381
- for (let i = 0; i < v.data.length; i++)
27382
- result2[i] = v.data[i] !== 0 || v.imag && v.imag[i] !== 0 ? 1 : 0;
27383
- const t2 = RTV.tensor(result2, [...shape]);
27384
- t2._isLogical = true;
27385
- return t2;
27386
- }
27387
- const reduceDimSize = shape[dimIdx];
27388
- const resultShape = [...shape];
27389
- resultShape[dimIdx] = 1;
27390
- const totalElems = resultShape.reduce((a, b) => a * b, 1);
27391
- const result = new FloatXArray(totalElems);
27392
- const outSubs = new Array(shape.length).fill(0);
27393
- for (let i = 0; i < totalElems; i++) {
27394
- let allNonZero = true;
27395
- for (let k = 0; k < reduceDimSize; k++) {
27396
- const srcSubs = [...outSubs];
27397
- srcSubs[dimIdx] = k;
27398
- const srcIdx = sub2ind(shape, srcSubs);
27399
- if (v.data[srcIdx] === 0 && (!v.imag || v.imag[srcIdx] === 0)) {
27400
- allNonZero = false;
27401
- break;
27402
- }
27403
- }
27404
- result[i] = allNonZero ? 1 : 0;
27405
- for (let d = 0; d < outSubs.length; d++) {
27406
- if (d === dimIdx) continue;
27407
- outSubs[d]++;
27408
- if (outSubs[d] < resultShape[d]) break;
27409
- outSubs[d] = 0;
27410
- }
27411
- }
27412
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1) {
27413
- resultShape.pop();
27414
- }
27415
- const t = RTV.tensor(result, resultShape);
27416
- t._isLogical = true;
27417
- return t;
27418
- }
27419
27342
  function registerReductionFunctions() {
27420
27343
  const defaultDimOrScalar = (v, reduceFn, initial, finalizeFn) => {
27421
27344
  const shape = v.shape;
@@ -27480,15 +27403,9 @@ function registerReductionFunctions() {
27480
27403
  slice[k] = v.data[sub2ind(shape, srcSubs)];
27481
27404
  }
27482
27405
  result[i] = sliceFn(slice);
27483
- for (let d = 0; d < outSubs.length; d++) {
27484
- if (d === dimIdx) continue;
27485
- outSubs[d]++;
27486
- if (outSubs[d] < resultShape[d]) break;
27487
- outSubs[d] = 0;
27488
- }
27406
+ nextSubscripts(outSubs, resultShape, dimIdx);
27489
27407
  }
27490
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1)
27491
- resultShape.pop();
27408
+ squeezeTrailing(resultShape);
27492
27409
  return RTV.tensor(result, resultShape);
27493
27410
  };
27494
27411
  const makeSliceReduction = (name, sliceFn) => ({
@@ -27752,16 +27669,9 @@ function registerReductionFunctions() {
27752
27669
  resultRe[i] = mRe;
27753
27670
  resultIm[i] = mIm;
27754
27671
  if (indices2) indices2[i] = mIdx + 1;
27755
- for (let d = 0; d < outSubsC.length; d++) {
27756
- if (d === dimIdx) continue;
27757
- outSubsC[d]++;
27758
- if (outSubsC[d] < resultShape[d]) break;
27759
- outSubsC[d] = 0;
27760
- }
27761
- }
27762
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1) {
27763
- resultShape.pop();
27672
+ nextSubscripts(outSubsC, resultShape, dimIdx);
27764
27673
  }
27674
+ squeezeTrailing(resultShape);
27765
27675
  const hasImag = resultIm.some((x) => x !== 0);
27766
27676
  const outTensorC = RTV.tensor(
27767
27677
  resultRe,
@@ -27793,16 +27703,9 @@ function registerReductionFunctions() {
27793
27703
  if (!foundNonNaN) m = NaN;
27794
27704
  result[i] = m;
27795
27705
  if (indices) indices[i] = mIdx + 1;
27796
- for (let d = 0; d < outSubs.length; d++) {
27797
- if (d === dimIdx) continue;
27798
- outSubs[d]++;
27799
- if (outSubs[d] < resultShape[d]) break;
27800
- outSubs[d] = 0;
27801
- }
27802
- }
27803
- while (resultShape.length > 2 && resultShape[resultShape.length - 1] === 1) {
27804
- resultShape.pop();
27706
+ nextSubscripts(outSubs, resultShape, dimIdx);
27805
27707
  }
27708
+ squeezeTrailing(resultShape);
27806
27709
  const outTensor3 = RTV.tensor(result, resultShape);
27807
27710
  if (v._isLogical) outTensor3._isLogical = true;
27808
27711
  if (nargout > 1) return [outTensor3, RTV.tensor(indices, resultShape)];
@@ -27878,168 +27781,82 @@ function registerReductionFunctions() {
27878
27781
  apply: stdVarApply("var", (v) => v)
27879
27782
  }
27880
27783
  ]);
27881
- register("any", [
27882
- {
27883
- check: (argTypes, nargout) => {
27884
- if (nargout !== 1) return null;
27885
- if (argTypes.length === 1) {
27784
+ const makeAnyAll = (name, mode) => {
27785
+ const anyAllCheck = (argTypes, nargout) => {
27786
+ if (nargout !== 1) return null;
27787
+ if (argTypes.length === 1) {
27788
+ return { outputTypes: [{ kind: "Boolean" }] };
27789
+ }
27790
+ if (argTypes.length === 2) {
27791
+ const arg2 = argTypes[1];
27792
+ if (arg2.kind === "Char" || arg2.kind === "String") {
27886
27793
  return { outputTypes: [{ kind: "Boolean" }] };
27887
27794
  }
27888
- if (argTypes.length === 2) {
27889
- const arg2 = argTypes[1];
27890
- if (arg2.kind === "Char" || arg2.kind === "String") {
27891
- return { outputTypes: [{ kind: "Boolean" }] };
27892
- }
27893
- return {
27894
- outputTypes: [
27895
- { kind: "Tensor", ndim: 2, shape: "unknown" }
27896
- ]
27897
- };
27898
- }
27899
- return null;
27900
- },
27901
- apply: (args) => {
27902
- if (args.length < 1)
27903
- throw new RuntimeError("any requires at least 1 argument");
27904
- const v = args[0];
27905
- if (args.length === 1) {
27906
- if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
27907
- if (isRuntimeLogical(v)) return RTV.logical(v);
27908
- if (isRuntimeComplexNumber(v))
27909
- return RTV.logical(v.re !== 0 || v.im !== 0);
27910
- if (isRuntimeTensor(v)) {
27911
- if (v.data.length === 0) return RTV.logical(false);
27912
- const shape = v.shape;
27913
- if (shape[0] === 1) {
27914
- for (let i = 0; i < v.data.length; i++) {
27915
- if (v.data[i] !== 0) return RTV.logical(true);
27916
- if (v.imag && v.imag[i] !== 0) return RTV.logical(true);
27917
- }
27918
- return RTV.logical(false);
27919
- }
27920
- return anyAlongDim(v, 1);
27921
- }
27922
- throw new RuntimeError("any: argument must be numeric or logical");
27923
- }
27924
- const arg2 = args[1];
27925
- if ((isRuntimeString(arg2) || isRuntimeChar(arg2)) && rstr(arg2).toLowerCase() === "all") {
27926
- if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
27927
- if (isRuntimeLogical(v)) return RTV.logical(v);
27928
- if (isRuntimeComplexNumber(v))
27929
- return RTV.logical(v.re !== 0 || v.im !== 0);
27930
- if (isRuntimeTensor(v)) {
27931
- for (let i = 0; i < v.data.length; i++) {
27932
- if (v.data[i] !== 0) return RTV.logical(true);
27933
- if (v.imag && v.imag[i] !== 0) return RTV.logical(true);
27934
- }
27935
- return RTV.logical(false);
27936
- }
27937
- throw new RuntimeError("any: argument must be numeric or logical");
27938
- }
27939
- if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
27940
- if (isRuntimeLogical(v)) return RTV.logical(v);
27941
- if (isRuntimeComplexNumber(v))
27942
- return RTV.logical(v.re !== 0 || v.im !== 0);
27943
- if (isRuntimeTensor(v)) {
27944
- if (isRuntimeNumber(arg2)) {
27945
- return anyAlongDim(v, Math.round(arg2));
27946
- }
27947
- if (isRuntimeTensor(arg2)) {
27948
- const dims = Array.from(arg2.data).map((d) => Math.round(d));
27949
- let result = v;
27950
- for (const dim of dims) {
27951
- if (isRuntimeTensor(result)) {
27952
- result = anyAlongDim(result, dim);
27953
- }
27954
- }
27955
- return result;
27956
- }
27957
- }
27958
- throw new RuntimeError("any: invalid arguments");
27795
+ return {
27796
+ outputTypes: [{ kind: "Tensor" }]
27797
+ };
27959
27798
  }
27960
- }
27961
- ]);
27962
- register("all", [
27963
- {
27964
- check: (argTypes, nargout) => {
27965
- if (nargout !== 1) return null;
27966
- if (argTypes.length === 1) {
27967
- return { outputTypes: [{ kind: "Boolean" }] };
27968
- }
27969
- if (argTypes.length === 2) {
27970
- const arg2 = argTypes[1];
27971
- if (arg2.kind === "Char" || arg2.kind === "String") {
27972
- return { outputTypes: [{ kind: "Boolean" }] };
27973
- }
27974
- return {
27975
- outputTypes: [
27976
- { kind: "Tensor", ndim: 2, shape: "unknown" }
27977
- ]
27978
- };
27979
- }
27980
- return null;
27981
- },
27799
+ return null;
27800
+ };
27801
+ const scalarLogical = (v) => {
27802
+ if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
27803
+ if (isRuntimeLogical(v)) return RTV.logical(v);
27804
+ if (isRuntimeComplexNumber(v))
27805
+ return RTV.logical(v.re !== 0 || v.im !== 0);
27806
+ return null;
27807
+ };
27808
+ return {
27809
+ check: anyAllCheck,
27982
27810
  apply: (args) => {
27983
27811
  if (args.length < 1)
27984
- throw new RuntimeError("all requires at least 1 argument");
27812
+ throw new RuntimeError(`${name} requires at least 1 argument`);
27985
27813
  const v = args[0];
27986
27814
  if (args.length === 1) {
27987
- if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
27988
- if (isRuntimeLogical(v)) return RTV.logical(v);
27989
- if (isRuntimeComplexNumber(v))
27990
- return RTV.logical(v.re !== 0 || v.im !== 0);
27815
+ const scalar2 = scalarLogical(v);
27816
+ if (scalar2 !== null) return scalar2;
27991
27817
  if (isRuntimeTensor(v)) {
27992
- if (v.data.length === 0) return RTV.logical(true);
27993
- const shape = v.shape;
27994
- if (shape[0] === 1) {
27995
- for (let i = 0; i < v.data.length; i++) {
27996
- if (v.data[i] === 0 && (!v.imag || v.imag[i] === 0))
27997
- return RTV.logical(false);
27998
- }
27999
- return RTV.logical(v.data.length > 0);
28000
- }
28001
- return allAlongDim(v, 1);
27818
+ if (v.data.length === 0) return RTV.logical(mode === "all");
27819
+ if (v.shape[0] === 1)
27820
+ return RTV.logical(scanLogical(v.data, v.imag, mode));
27821
+ return logicalAlongDim(v, 1, mode);
28002
27822
  }
28003
- throw new RuntimeError("all: argument must be numeric or logical");
27823
+ throw new RuntimeError(
27824
+ `${name}: argument must be numeric or logical`
27825
+ );
28004
27826
  }
28005
27827
  const arg2 = args[1];
28006
27828
  if ((isRuntimeString(arg2) || isRuntimeChar(arg2)) && rstr(arg2).toLowerCase() === "all") {
28007
- if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
28008
- if (isRuntimeLogical(v)) return RTV.logical(v);
28009
- if (isRuntimeComplexNumber(v))
28010
- return RTV.logical(v.re !== 0 || v.im !== 0);
28011
- if (isRuntimeTensor(v)) {
28012
- for (let i = 0; i < v.data.length; i++) {
28013
- if (v.data[i] === 0 && (!v.imag || v.imag[i] === 0))
28014
- return RTV.logical(false);
28015
- }
28016
- return RTV.logical(v.data.length > 0);
28017
- }
28018
- throw new RuntimeError("all: argument must be numeric or logical");
27829
+ const scalar2 = scalarLogical(v);
27830
+ if (scalar2 !== null) return scalar2;
27831
+ if (isRuntimeTensor(v))
27832
+ return RTV.logical(scanLogical(v.data, v.imag, mode));
27833
+ throw new RuntimeError(
27834
+ `${name}: argument must be numeric or logical`
27835
+ );
28019
27836
  }
28020
- if (isRuntimeNumber(v)) return RTV.logical(v !== 0);
28021
- if (isRuntimeLogical(v)) return RTV.logical(v);
28022
- if (isRuntimeComplexNumber(v))
28023
- return RTV.logical(v.re !== 0 || v.im !== 0);
27837
+ const scalar = scalarLogical(v);
27838
+ if (scalar !== null) return scalar;
28024
27839
  if (isRuntimeTensor(v)) {
28025
27840
  if (isRuntimeNumber(arg2)) {
28026
- return allAlongDim(v, Math.round(arg2));
27841
+ return logicalAlongDim(v, Math.round(arg2), mode);
28027
27842
  }
28028
27843
  if (isRuntimeTensor(arg2)) {
28029
27844
  const dims = Array.from(arg2.data).map((d) => Math.round(d));
28030
27845
  let result = v;
28031
27846
  for (const dim of dims) {
28032
27847
  if (isRuntimeTensor(result)) {
28033
- result = allAlongDim(result, dim);
27848
+ result = logicalAlongDim(result, dim, mode);
28034
27849
  }
28035
27850
  }
28036
27851
  return result;
28037
27852
  }
28038
27853
  }
28039
- throw new RuntimeError("all: invalid arguments");
27854
+ throw new RuntimeError(`${name}: invalid arguments`);
28040
27855
  }
28041
- }
28042
- ]);
27856
+ };
27857
+ };
27858
+ register("any", [makeAnyAll("any", "any")]);
27859
+ register("all", [makeAnyAll("all", "all")]);
28043
27860
  register(
28044
27861
  "xor",
28045
27862
  builtinSingle(
@@ -28290,11 +28107,7 @@ function registerReductionFunctions() {
28290
28107
  resultIm[fiberFlatIdx[r]] = im[fiberFlatIdx[order[r]]];
28291
28108
  if (resultIdx) resultIdx[fiberFlatIdx[r]] = order[r] + 1;
28292
28109
  }
28293
- for (let d = 0; d < fiberSubs.length; d++) {
28294
- fiberSubs[d]++;
28295
- if (fiberSubs[d] < fiberShape[d]) break;
28296
- fiberSubs[d] = 0;
28297
- }
28110
+ nextSubscripts(fiberSubs, fiberShape);
28298
28111
  }
28299
28112
  }
28300
28113
  const imOut = resultIm && resultIm.some((x) => x !== 0) ? resultIm : void 0;
@@ -28673,11 +28486,7 @@ function registerReductionFunctions() {
28673
28486
  if (resultImag) resultImag[idx] = accIm;
28674
28487
  }
28675
28488
  }
28676
- for (let d = 0; d < fiberSubs.length; d++) {
28677
- fiberSubs[d]++;
28678
- if (fiberSubs[d] < fiberShape[d]) break;
28679
- fiberSubs[d] = 0;
28680
- }
28489
+ nextSubscripts(fiberSubs, fiberShape);
28681
28490
  }
28682
28491
  }
28683
28492
  const imOut = resultImag && resultImag.some((x) => x !== 0) ? resultImag : void 0;
@@ -30640,15 +30449,12 @@ function registerDot() {
30640
30449
  function qrLapack(data, m, n, econ, wantQ) {
30641
30450
  const bridge = getEffectiveBridge("qr", "qr");
30642
30451
  if (!bridge?.qr) return null;
30643
- const f64 = data instanceof Float64Array ? data : new Float64Array(data);
30644
- return bridge.qr(f64, m, n, econ, wantQ);
30452
+ return bridge.qr(toF64(data), m, n, econ, wantQ);
30645
30453
  }
30646
30454
  function qrLapackComplex(dataRe, dataIm, m, n, econ, wantQ) {
30647
30455
  const bridge = getEffectiveBridge("qr", "qrComplex");
30648
30456
  if (!bridge?.qrComplex) return null;
30649
- const re = dataRe instanceof Float64Array ? dataRe : new Float64Array(dataRe);
30650
- const im = dataIm instanceof Float64Array ? dataIm : new Float64Array(dataIm);
30651
- return bridge.qrComplex(re, im, m, n, econ, wantQ);
30457
+ return bridge.qrComplex(toF64(dataRe), toF64(dataIm), m, n, econ, wantQ);
30652
30458
  }
30653
30459
  function registerQr() {
30654
30460
  register("qr", [
@@ -30866,15 +30672,12 @@ function registerQr() {
30866
30672
  // src/numbl-core/builtins/linear-algebra/inv.ts
30867
30673
  function invLapack(data, n) {
30868
30674
  const bridge = getEffectiveBridge("inv");
30869
- const f64 = data instanceof Float64Array ? data : new Float64Array(data);
30870
- return bridge.inv(f64, n);
30675
+ return bridge.inv(toF64(data), n);
30871
30676
  }
30872
30677
  function invLapackComplex(dataRe, dataIm, n) {
30873
30678
  const bridge = getLapackBridge();
30874
30679
  if (!bridge || !bridge.invComplex) return null;
30875
- const f64Re = dataRe instanceof Float64Array ? dataRe : new Float64Array(dataRe);
30876
- const f64Im = dataIm instanceof Float64Array ? dataIm : new Float64Array(dataIm);
30877
- return bridge.invComplex(f64Re, f64Im, n);
30680
+ return bridge.invComplex(toF64(dataRe), toF64(dataIm), n);
30878
30681
  }
30879
30682
  function invComplexJS(dataRe, dataIm, n) {
30880
30683
  const augRe = new Float64Array(n * 2 * n);
@@ -31104,14 +30907,11 @@ function registerDet() {
31104
30907
  const [m, n] = tensorSize2D(A);
31105
30908
  if (m !== n) throw new RuntimeError("det: matrix must be square");
31106
30909
  if (A.imag) {
31107
- const dataRe = A.data instanceof Float64Array ? A.data : new Float64Array(A.data);
31108
- const dataIm = A.imag instanceof Float64Array ? A.imag : new Float64Array(A.imag);
31109
- const [detRe, detIm] = detComplexJS(dataRe, dataIm, n);
30910
+ const [detRe, detIm] = detComplexJS(toF64(A.data), toF64(A.imag), n);
31110
30911
  if (Math.abs(detIm) < 1e-15) return RTV.num(detRe);
31111
30912
  return RTV.complex(detRe, detIm);
31112
30913
  }
31113
- const data = A.data instanceof Float64Array ? A.data : new Float64Array(A.data);
31114
- return RTV.num(detJS(data, n));
30914
+ return RTV.num(detJS(toF64(A.data), n));
31115
30915
  }
31116
30916
  }
31117
30917
  ]);
@@ -31199,15 +30999,12 @@ function registerDet() {
31199
30999
  function svdLapack(data, m, n, econ, computeUV) {
31200
31000
  const bridge = getEffectiveBridge("svd", "svd");
31201
31001
  if (!bridge || !bridge.svd) return null;
31202
- const f64 = data instanceof Float64Array ? data : new Float64Array(data);
31203
- return bridge.svd(f64, m, n, econ, computeUV);
31002
+ return bridge.svd(toF64(data), m, n, econ, computeUV);
31204
31003
  }
31205
31004
  function svdLapackComplex(dataRe, dataIm, m, n, econ, computeUV) {
31206
31005
  const bridge = getLapackBridge();
31207
31006
  if (!bridge || !bridge.svdComplex) return null;
31208
- const f64Re = dataRe instanceof Float64Array ? dataRe : new Float64Array(dataRe);
31209
- const f64Im = dataIm instanceof Float64Array ? dataIm : new Float64Array(dataIm);
31210
- return bridge.svdComplex(f64Re, f64Im, m, n, econ, computeUV);
31007
+ return bridge.svdComplex(toF64(dataRe), toF64(dataIm), m, n, econ, computeUV);
31211
31008
  }
31212
31009
  function registerSvd() {
31213
31010
  register("svd", [
@@ -31822,14 +31619,8 @@ function parseEigOptionsRuntime(args) {
31822
31619
  let outputForm = "matrix";
31823
31620
  for (let i = 1; i < args.length; i++) {
31824
31621
  const arg = args[i];
31825
- if (isRuntimeString(arg)) {
31826
- const val = arg.replace(/^['"]|['"]$/g, "").toLowerCase();
31827
- if (val === "nobalance") balance = false;
31828
- else if (val === "balance") balance = true;
31829
- else if (val === "vector") outputForm = "vector";
31830
- else if (val === "matrix") outputForm = "matrix";
31831
- } else if (isRuntimeChar(arg)) {
31832
- const val = arg.value.replace(/^['"]|['"]$/g, "").toLowerCase();
31622
+ if (isRuntimeString(arg) || isRuntimeChar(arg)) {
31623
+ const val = parseStringArgLower(arg);
31833
31624
  if (val === "nobalance") balance = false;
31834
31625
  else if (val === "balance") balance = true;
31835
31626
  else if (val === "vector") outputForm = "vector";
@@ -31929,11 +31720,9 @@ function registerEig() {
31929
31720
  const computeVL = nargout >= 3;
31930
31721
  const computeVR = nargout >= 2;
31931
31722
  if (A.imag) {
31932
- const f64Re = A.data instanceof Float64Array ? A.data : new Float64Array(A.data);
31933
- const f64Im = A.imag instanceof Float64Array ? A.imag : new Float64Array(A.imag);
31934
31723
  const result2 = eigLapackComplex(
31935
- f64Re,
31936
- f64Im,
31724
+ toF64(A.data),
31725
+ toF64(A.imag),
31937
31726
  n,
31938
31727
  computeVL,
31939
31728
  computeVR
@@ -32020,8 +31809,13 @@ function registerEig() {
32020
31809
  }
32021
31810
  return [Vout2, Dout2, Wout2];
32022
31811
  }
32023
- const f64 = A.data instanceof Float64Array ? A.data : new Float64Array(A.data);
32024
- const result = eigLapack(f64, n, computeVL, computeVR, balance);
31812
+ const result = eigLapack(
31813
+ toF64(A.data),
31814
+ n,
31815
+ computeVL,
31816
+ computeVR,
31817
+ balance
31818
+ );
32025
31819
  if (!result) {
32026
31820
  throw new RuntimeError("eig: LAPACK bridge not available");
32027
31821
  }
@@ -32414,15 +32208,12 @@ function registerPagetranspose() {
32414
32208
  function luLapack(data, m, n) {
32415
32209
  const bridge = getEffectiveBridge("lu", "lu");
32416
32210
  if (!bridge?.lu) return null;
32417
- const f64 = data instanceof Float64Array ? data : new Float64Array(data);
32418
- return bridge.lu(f64, m, n);
32211
+ return bridge.lu(toF64(data), m, n);
32419
32212
  }
32420
32213
  function luLapackComplex(dataRe, dataIm, m, n) {
32421
32214
  const bridge = getEffectiveBridge("lu", "luComplex");
32422
32215
  if (!bridge?.luComplex) return null;
32423
- const re = dataRe instanceof Float64Array ? dataRe : new Float64Array(dataRe);
32424
- const im = dataIm instanceof Float64Array ? dataIm : new Float64Array(dataIm);
32425
- return bridge.luComplex(re, im, m, n);
32216
+ return bridge.luComplex(toF64(dataRe), toF64(dataIm), m, n);
32426
32217
  }
32427
32218
  function ipivToPermVector(ipiv, m) {
32428
32219
  const perm = new Int32Array(m);
@@ -32439,15 +32230,9 @@ function ipivToPermVector(ipiv, m) {
32439
32230
  }
32440
32231
  function parseOutputForm(arg) {
32441
32232
  if (arg === void 0) return "matrix";
32442
- let s;
32443
- if (isRuntimeString(arg)) {
32444
- s = arg.replace(/^['"]|['"]$/g, "").toLowerCase();
32445
- } else if (typeof arg === "object" && arg !== null && arg.kind === "char") {
32446
- s = arg.value.toLowerCase();
32447
- }
32233
+ const s = parseStringArgLower(arg);
32448
32234
  if (s === "vector") return "vector";
32449
32235
  if (s === "matrix") return "matrix";
32450
- if (s !== void 0) return null;
32451
32236
  return null;
32452
32237
  }
32453
32238
  function registerLu() {
@@ -32655,24 +32440,16 @@ function registerBlkdiag() {
32655
32440
  function cholLapack(data, n, upper) {
32656
32441
  const bridge = getEffectiveBridge("chol", "chol");
32657
32442
  if (!bridge?.chol) return null;
32658
- const f64 = data instanceof Float64Array ? data : new Float64Array(data);
32659
- return bridge.chol(f64, n, upper);
32443
+ return bridge.chol(toF64(data), n, upper);
32660
32444
  }
32661
32445
  function cholLapackComplex(dataRe, dataIm, n, upper) {
32662
32446
  const bridge = getEffectiveBridge("chol", "cholComplex");
32663
32447
  if (!bridge?.cholComplex) return null;
32664
- const re = dataRe instanceof Float64Array ? dataRe : new Float64Array(dataRe);
32665
- const im = dataIm instanceof Float64Array ? dataIm : new Float64Array(dataIm);
32666
- return bridge.cholComplex(re, im, n, upper);
32448
+ return bridge.cholComplex(toF64(dataRe), toF64(dataIm), n, upper);
32667
32449
  }
32668
32450
  function parseTriangleArg(arg) {
32669
32451
  if (arg === void 0) return "upper";
32670
- let s;
32671
- if (isRuntimeString(arg)) {
32672
- s = arg.replace(/^['"]|['"]$/g, "").toLowerCase();
32673
- } else if (typeof arg === "object" && arg !== null && arg.kind === "char") {
32674
- s = arg.value.toLowerCase();
32675
- }
32452
+ const s = parseStringArgLower(arg);
32676
32453
  if (s === "upper") return "upper";
32677
32454
  if (s === "lower") return "lower";
32678
32455
  return null;
@@ -32820,8 +32597,7 @@ function registerPinv() {
32820
32597
  if (!bridge || !bridge.svd) {
32821
32598
  return pinvFallback(A.data, m, n);
32822
32599
  }
32823
- const f64 = A.data instanceof Float64Array ? A.data : new Float64Array(A.data);
32824
- const svdResult = bridge.svd(f64, m, n, true, true);
32600
+ const svdResult = bridge.svd(toF64(A.data), m, n, true, true);
32825
32601
  if (!svdResult || !svdResult.U || !svdResult.V)
32826
32602
  throw new RuntimeError("pinv: SVD computation failed");
32827
32603
  const { U, S, V } = svdResult;
@@ -33002,9 +32778,6 @@ function qzComplexLapack(dataARe, dataAIm, dataBRe, dataBIm, n, computeEigvecs)
33002
32778
  computeEigvecs
33003
32779
  );
33004
32780
  }
33005
- function toF64(data) {
33006
- return data instanceof Float64Array ? data : new Float64Array(data);
33007
- }
33008
32781
  function zeroF64(n) {
33009
32782
  return new Float64Array(n);
33010
32783
  }
@@ -33779,42 +33552,32 @@ function registerMiscFunctions() {
33779
33552
  { outputType: { kind: "Number" } }
33780
33553
  )
33781
33554
  );
33782
- register(
33783
- "true",
33784
- builtinSingle((args) => {
33785
- if (args.length === 0) return RTV.logical(true);
33786
- const shape = parseShapeArgs(args);
33787
- const rows = shape[0];
33788
- const cols = shape[1] ?? rows;
33789
- const t = RTV.tensor(new FloatXArray(rows * cols).fill(1), [rows, cols]);
33790
- t._isLogical = true;
33791
- return t;
33792
- })
33793
- );
33794
- register(
33795
- "false",
33796
- builtinSingle((args) => {
33797
- if (args.length === 0) return RTV.logical(false);
33798
- const shape = parseShapeArgs(args);
33799
- const rows = shape[0];
33800
- const cols = shape[1] ?? rows;
33801
- const t = RTV.tensor(new FloatXArray(rows * cols), [rows, cols]);
33802
- t._isLogical = true;
33803
- return t;
33804
- })
33805
- );
33806
- register(
33807
- "clear",
33808
- builtinSingle(() => {
33809
- return RTV.num(0);
33810
- })
33811
- );
33812
- register(
33813
- "clf",
33814
- builtinSingle(() => {
33815
- return RTV.num(0);
33816
- })
33817
- );
33555
+ for (const [name, scalarVal, fillVal] of [
33556
+ ["true", true, 1],
33557
+ ["false", false, 0]
33558
+ ]) {
33559
+ register(
33560
+ name,
33561
+ builtinSingle((args) => {
33562
+ if (args.length === 0) return RTV.logical(scalarVal);
33563
+ const shape = parseShapeArgs(args);
33564
+ const rows = shape[0];
33565
+ const cols = shape[1] ?? rows;
33566
+ const t = RTV.tensor(
33567
+ fillVal ? new FloatXArray(rows * cols).fill(1) : new FloatXArray(rows * cols),
33568
+ [rows, cols]
33569
+ );
33570
+ t._isLogical = true;
33571
+ return t;
33572
+ })
33573
+ );
33574
+ }
33575
+ for (const name of ["clear", "clc", "clf"]) {
33576
+ register(
33577
+ name,
33578
+ builtinSingle(() => RTV.num(0))
33579
+ );
33580
+ }
33818
33581
  register(
33819
33582
  "exist",
33820
33583
  builtinSingle((args) => {
@@ -33864,12 +33627,14 @@ function registerMiscFunctions() {
33864
33627
  return result.returnValue;
33865
33628
  })
33866
33629
  );
33867
- register(
33868
- "feval",
33869
- builtinSingle(() => {
33870
- throw new RuntimeError("feval: should be handled by runtime");
33871
- })
33872
- );
33630
+ for (const name of ["feval", "arrayfun", "cellfun", "structfun", "bsxfun"]) {
33631
+ register(
33632
+ name,
33633
+ builtinSingle(() => {
33634
+ throw new RuntimeError(`${name}: should be handled by runtime`);
33635
+ })
33636
+ );
33637
+ }
33873
33638
  register(
33874
33639
  "deal",
33875
33640
  builtinSingle((args, nargout) => {
@@ -33898,30 +33663,6 @@ function registerMiscFunctions() {
33898
33663
  return RTV.string(v.name);
33899
33664
  })
33900
33665
  );
33901
- register(
33902
- "arrayfun",
33903
- builtinSingle(() => {
33904
- throw new RuntimeError("arrayfun: should be handled by runtime");
33905
- })
33906
- );
33907
- register(
33908
- "cellfun",
33909
- builtinSingle(() => {
33910
- throw new RuntimeError("cellfun: should be handled by runtime");
33911
- })
33912
- );
33913
- register(
33914
- "structfun",
33915
- builtinSingle(() => {
33916
- throw new RuntimeError("structfun: should be handled by runtime");
33917
- })
33918
- );
33919
- register(
33920
- "bsxfun",
33921
- builtinSingle(() => {
33922
- throw new RuntimeError("bsxfun: should be handled by runtime");
33923
- })
33924
- );
33925
33666
  const opMap = [
33926
33667
  ["plus", mAdd],
33927
33668
  ["minus", mSub],
@@ -33968,18 +33709,12 @@ function registerMiscFunctions() {
33968
33709
  return args[0];
33969
33710
  })
33970
33711
  );
33971
- register(
33972
- "narginchk",
33973
- builtinSingle(() => {
33974
- return RTV.num(0);
33975
- })
33976
- );
33977
- register(
33978
- "nargoutchk",
33979
- builtinSingle(() => {
33980
- return RTV.num(0);
33981
- })
33982
- );
33712
+ for (const name of ["narginchk", "nargoutchk"]) {
33713
+ register(
33714
+ name,
33715
+ builtinSingle(() => RTV.num(0))
33716
+ );
33717
+ }
33983
33718
  register(
33984
33719
  "__inferred_type_str",
33985
33720
  builtinSingle(
@@ -33991,279 +33726,158 @@ function registerMiscFunctions() {
33991
33726
  { outputType: { kind: "String" } }
33992
33727
  )
33993
33728
  );
33994
- register(
33995
- "cart2sph",
33996
- builtinSingle((args, nargout) => {
33997
- if (args.length !== 3)
33998
- throw new RuntimeError("cart2sph requires 3 arguments");
33999
- const x = args[0];
34000
- const y = args[1];
34001
- const z = args[2];
34002
- const xIsT = isRuntimeTensor(x);
34003
- const yIsT = isRuntimeTensor(y);
34004
- const zIsT = isRuntimeTensor(z);
34005
- if (xIsT || yIsT || zIsT) {
34006
- const xd = xIsT ? x.data : null;
34007
- const yd = yIsT ? y.data : null;
34008
- const zd = zIsT ? z.data : null;
34009
- const shape = xIsT ? x.shape : yIsT ? y.shape : z.shape;
34010
- const len = xIsT ? xd.length : yIsT ? yd.length : zd.length;
34011
- const azData = new FloatXArray(len);
34012
- const elData = new FloatXArray(len);
34013
- const rData = new FloatXArray(len);
34014
- for (let i = 0; i < len; i++) {
34015
- const xi = xd ? xd[i] : toNumber(x);
34016
- const yi = yd ? yd[i] : toNumber(y);
34017
- const zi = zd ? zd[i] : toNumber(z);
34018
- const hypotxy2 = Math.sqrt(xi * xi + yi * yi);
34019
- azData[i] = Math.atan2(yi, xi);
34020
- elData[i] = Math.atan2(zi, hypotxy2);
34021
- rData[i] = Math.sqrt(xi * xi + yi * yi + zi * zi);
34022
- }
34023
- if (nargout <= 1) return RTV.tensor(azData, shape);
34024
- return [
34025
- RTV.tensor(azData, shape),
34026
- RTV.tensor(elData, shape),
34027
- RTV.tensor(rData, shape)
34028
- ];
34029
- }
34030
- const xv = toNumber(x);
34031
- const yv = toNumber(y);
34032
- const zv = toNumber(z);
34033
- const hypotxy = Math.sqrt(xv * xv + yv * yv);
34034
- const az = Math.atan2(yv, xv);
34035
- const el = Math.atan2(zv, hypotxy);
34036
- const r = Math.sqrt(xv * xv + yv * yv + zv * zv);
34037
- if (nargout <= 1) return RTV.num(az);
34038
- return [RTV.num(az), RTV.num(el), RTV.num(r)];
34039
- }),
34040
- 3
34041
- );
34042
- register(
34043
- "sph2cart",
34044
- builtinSingle((args, nargout) => {
34045
- if (args.length !== 3)
34046
- throw new RuntimeError("sph2cart requires 3 arguments");
34047
- const az = args[0];
34048
- const el = args[1];
34049
- const r = args[2];
34050
- const azIsT = isRuntimeTensor(az);
34051
- const elIsT = isRuntimeTensor(el);
34052
- const rIsT = isRuntimeTensor(r);
34053
- if (azIsT || elIsT || rIsT) {
34054
- const azd = azIsT ? az.data : null;
34055
- const eld = elIsT ? el.data : null;
34056
- const rd = rIsT ? r.data : null;
34057
- const shape = azIsT ? az.shape : elIsT ? el.shape : r.shape;
34058
- const len = azIsT ? azd.length : elIsT ? eld.length : rd.length;
34059
- const xData = new FloatXArray(len);
34060
- const yData = new FloatXArray(len);
34061
- const zData = new FloatXArray(len);
34062
- for (let i = 0; i < len; i++) {
34063
- const a = azd ? azd[i] : toNumber(az);
34064
- const e = eld ? eld[i] : toNumber(el);
34065
- const rv2 = rd ? rd[i] : toNumber(r);
34066
- const rcosel2 = rv2 * Math.cos(e);
34067
- xData[i] = rcosel2 * Math.cos(a);
34068
- yData[i] = rcosel2 * Math.sin(a);
34069
- zData[i] = rv2 * Math.sin(e);
34070
- }
34071
- if (nargout <= 1) return RTV.tensor(xData, shape);
34072
- return [
34073
- RTV.tensor(xData, shape),
34074
- RTV.tensor(yData, shape),
34075
- RTV.tensor(zData, shape)
34076
- ];
34077
- }
34078
- const av = toNumber(az);
34079
- const ev = toNumber(el);
34080
- const rv = toNumber(r);
34081
- const rcosel = rv * Math.cos(ev);
34082
- const xv = rcosel * Math.cos(av);
34083
- const yv = rcosel * Math.sin(av);
34084
- const zv = rv * Math.sin(ev);
34085
- if (nargout <= 1) return RTV.num(xv);
34086
- return [RTV.num(xv), RTV.num(yv), RTV.num(zv)];
34087
- }),
34088
- 3
34089
- );
34090
- register(
34091
- "cart2pol",
34092
- builtinSingle((args, nargout) => {
34093
- if (args.length < 2 || args.length > 3)
34094
- throw new RuntimeError("cart2pol requires 2 or 3 arguments");
34095
- const x = args[0];
34096
- const y = args[1];
34097
- const hasZ = args.length === 3;
34098
- const z = hasZ ? args[2] : void 0;
34099
- const xIsT = isRuntimeTensor(x);
34100
- const yIsT = isRuntimeTensor(y);
34101
- const zIsT = z !== void 0 && isRuntimeTensor(z);
34102
- if (xIsT || yIsT || zIsT) {
34103
- const xd = xIsT ? x.data : null;
34104
- const yd = yIsT ? y.data : null;
34105
- const zd = zIsT ? z.data : null;
34106
- const shape = xIsT ? x.shape : yIsT ? y.shape : z.shape;
34107
- const len = xIsT ? xd.length : yIsT ? yd.length : zd.length;
34108
- const thData = new FloatXArray(len);
34109
- const rhoData = new FloatXArray(len);
34110
- for (let i = 0; i < len; i++) {
34111
- const xi = xd ? xd[i] : toNumber(x);
34112
- const yi = yd ? yd[i] : toNumber(y);
34113
- thData[i] = Math.atan2(yi, xi);
34114
- rhoData[i] = Math.sqrt(xi * xi + yi * yi);
34115
- }
34116
- if (!hasZ) {
34117
- if (nargout <= 1) return RTV.tensor(thData, shape);
34118
- return [RTV.tensor(thData, shape), RTV.tensor(rhoData, shape)];
34119
- }
34120
- const zOutData = new FloatXArray(len);
34121
- for (let i = 0; i < len; i++) {
34122
- zOutData[i] = zd ? zd[i] : toNumber(z);
34123
- }
34124
- if (nargout <= 1) return RTV.tensor(thData, shape);
34125
- if (nargout === 2)
34126
- return [RTV.tensor(thData, shape), RTV.tensor(rhoData, shape)];
34127
- return [
34128
- RTV.tensor(thData, shape),
34129
- RTV.tensor(rhoData, shape),
34130
- RTV.tensor(zOutData, shape)
34131
- ];
34132
- }
34133
- const xv = toNumber(x);
34134
- const yv = toNumber(y);
34135
- const th = Math.atan2(yv, xv);
34136
- const rho = Math.sqrt(xv * xv + yv * yv);
34137
- if (!hasZ) {
34138
- if (nargout <= 1) return RTV.num(th);
34139
- return [RTV.num(th), RTV.num(rho)];
34140
- }
34141
- const zv = toNumber(z);
34142
- if (nargout <= 1) return RTV.num(th);
34143
- if (nargout === 2) return [RTV.num(th), RTV.num(rho)];
34144
- return [RTV.num(th), RTV.num(rho), RTV.num(zv)];
34145
- })
34146
- );
34147
- register(
34148
- "pol2cart",
34149
- builtinSingle((args, nargout) => {
34150
- if (args.length < 2 || args.length > 3)
34151
- throw new RuntimeError("pol2cart requires 2 or 3 arguments");
34152
- const theta = args[0];
34153
- const rho = args[1];
34154
- const hasZ = args.length === 3;
34155
- const z = hasZ ? args[2] : void 0;
34156
- const thIsT = isRuntimeTensor(theta);
34157
- const rhoIsT = isRuntimeTensor(rho);
34158
- const zIsT = z !== void 0 && isRuntimeTensor(z);
34159
- if (thIsT || rhoIsT || zIsT) {
34160
- const thd = thIsT ? theta.data : null;
34161
- const rhod = rhoIsT ? rho.data : null;
34162
- const zd = zIsT ? z.data : null;
34163
- const shape = thIsT ? theta.shape : rhoIsT ? rho.shape : z.shape;
34164
- const len = thIsT ? thd.length : rhoIsT ? rhod.length : zd.length;
34165
- const xData = new FloatXArray(len);
34166
- const yData = new FloatXArray(len);
34167
- for (let i = 0; i < len; i++) {
34168
- const t = thd ? thd[i] : toNumber(theta);
34169
- const rv2 = rhod ? rhod[i] : toNumber(rho);
34170
- xData[i] = rv2 * Math.cos(t);
34171
- yData[i] = rv2 * Math.sin(t);
34172
- }
34173
- if (!hasZ) {
34174
- if (nargout <= 1) return RTV.tensor(xData, shape);
34175
- return [RTV.tensor(xData, shape), RTV.tensor(yData, shape)];
34176
- }
34177
- const zOutData = new FloatXArray(len);
34178
- for (let i = 0; i < len; i++) {
34179
- zOutData[i] = zd ? zd[i] : toNumber(z);
34180
- }
34181
- if (nargout <= 1) return RTV.tensor(xData, shape);
34182
- if (nargout === 2)
34183
- return [RTV.tensor(xData, shape), RTV.tensor(yData, shape)];
34184
- return [
34185
- RTV.tensor(xData, shape),
34186
- RTV.tensor(yData, shape),
34187
- RTV.tensor(zOutData, shape)
34188
- ];
34189
- }
34190
- const tv = toNumber(theta);
34191
- const rv = toNumber(rho);
34192
- const xv = rv * Math.cos(tv);
34193
- const yv = rv * Math.sin(tv);
34194
- if (!hasZ) {
34195
- if (nargout <= 1) return RTV.num(xv);
34196
- return [RTV.num(xv), RTV.num(yv)];
34197
- }
34198
- const zv = toNumber(z);
34199
- if (nargout <= 1) return RTV.num(xv);
34200
- if (nargout === 2) return [RTV.num(xv), RTV.num(yv)];
34201
- return [RTV.num(xv), RTV.num(yv), RTV.num(zv)];
34202
- })
34203
- );
33729
+ function coordTransform(name, nArgs, nOut, fn) {
33730
+ register(
33731
+ name,
33732
+ builtinSingle((args, nargout) => {
33733
+ const minArgs = nArgs === "2or3" ? 2 : nArgs;
33734
+ const maxArgs = nArgs === "2or3" ? 3 : nArgs;
33735
+ if (args.length < minArgs || args.length > maxArgs)
33736
+ throw new RuntimeError(
33737
+ `${name} requires ${nArgs === "2or3" ? "2 or 3" : nArgs} arguments`
33738
+ );
33739
+ const n = args.length;
33740
+ const tensors = args.map((a) => isRuntimeTensor(a) ? a : null);
33741
+ const anyTensor = tensors.some((t) => t !== null);
33742
+ if (anyTensor) {
33743
+ const refT = tensors.find((t) => t !== null);
33744
+ const shape = refT.shape;
33745
+ const len = refT.data.length;
33746
+ const datas = tensors.map((t) => t ? t.data : null);
33747
+ const scalars = args.map((a, i) => datas[i] ? 0 : toNumber(a));
33748
+ const outArrays = Array.from(
33749
+ { length: nOut },
33750
+ () => new FloatXArray(len)
33751
+ );
33752
+ for (let i = 0; i < len; i++) {
33753
+ const vals2 = datas.map((d, j) => d ? d[i] : scalars[j]);
33754
+ const result2 = fn(...vals2);
33755
+ for (let k = 0; k < nOut; k++) outArrays[k][i] = result2[k];
33756
+ }
33757
+ const effOut2 = nArgs === "2or3" && n === 3 ? 3 : nOut;
33758
+ const outTensors = outArrays.map((d) => RTV.tensor(d, shape));
33759
+ if (nArgs === "2or3" && n === 3 && nOut === 2) {
33760
+ const zd = datas[2];
33761
+ const zOut = new FloatXArray(len);
33762
+ for (let i = 0; i < len; i++) zOut[i] = zd ? zd[i] : scalars[2];
33763
+ outTensors.push(RTV.tensor(zOut, shape));
33764
+ }
33765
+ if (nargout <= 1) return outTensors[0];
33766
+ return outTensors.slice(0, Math.min(nargout, effOut2));
33767
+ }
33768
+ const vals = args.map((a) => toNumber(a));
33769
+ const result = fn(...vals);
33770
+ const effOut = nArgs === "2or3" && n === 3 ? 3 : nOut;
33771
+ const outVals = result.map((v) => RTV.num(v));
33772
+ if (nArgs === "2or3" && n === 3 && nOut === 2) {
33773
+ outVals.push(RTV.num(vals[2]));
33774
+ }
33775
+ if (nargout <= 1) return outVals[0];
33776
+ return outVals.slice(0, Math.min(nargout, effOut));
33777
+ }),
33778
+ nOut
33779
+ );
33780
+ }
33781
+ coordTransform("cart2sph", 3, 3, (x, y, z) => {
33782
+ const hypotxy = Math.sqrt(x * x + y * y);
33783
+ return [
33784
+ Math.atan2(y, x),
33785
+ Math.atan2(z, hypotxy),
33786
+ Math.sqrt(x * x + y * y + z * z)
33787
+ ];
33788
+ });
33789
+ coordTransform("sph2cart", 3, 3, (az, el, r) => {
33790
+ const rcosel = r * Math.cos(el);
33791
+ return [rcosel * Math.cos(az), rcosel * Math.sin(az), r * Math.sin(el)];
33792
+ });
33793
+ coordTransform("cart2pol", "2or3", 2, (x, y) => [
33794
+ Math.atan2(y, x),
33795
+ Math.sqrt(x * x + y * y)
33796
+ ]);
33797
+ coordTransform("pol2cart", "2or3", 2, (theta, rho) => [
33798
+ rho * Math.cos(theta),
33799
+ rho * Math.sin(theta)
33800
+ ]);
34204
33801
  }
34205
33802
 
34206
33803
  // src/numbl-core/builtins/graphics.ts
34207
33804
  function registerGraphicsFunctions() {
34208
- register(
33805
+ const placeholderNames = [
34209
33806
  "figure",
34210
- builtinSingle(() => RTV.num(0))
34211
- );
34212
- register(
34213
33807
  "plot",
34214
- builtinSingle(() => RTV.num(0))
34215
- );
34216
- register(
34217
33808
  "plot3",
34218
- builtinSingle(() => RTV.num(0))
34219
- );
34220
- register(
34221
33809
  "surf",
34222
- builtinSingle(() => RTV.num(0))
34223
- );
34224
- register(
34225
33810
  "hold",
34226
- builtinSingle(() => RTV.num(0))
34227
- );
34228
- register(
34229
- "ishold",
34230
- builtinSingle(() => RTV.logical(false), { outputType: IType.Logical })
34231
- );
34232
- register(
34233
33811
  "grid",
34234
- builtinSingle(() => RTV.num(0))
34235
- );
34236
- register(
34237
33812
  "clf",
34238
- builtinSingle(() => RTV.num(0))
34239
- );
34240
- register(
34241
33813
  "close",
34242
- builtinSingle(() => RTV.num(0))
34243
- );
34244
- register(
34245
33814
  "title",
34246
- builtinSingle(() => RTV.num(0))
34247
- );
34248
- register(
34249
33815
  "xlabel",
34250
- builtinSingle(() => RTV.num(0))
34251
- );
34252
- register(
34253
33816
  "ylabel",
34254
- builtinSingle(() => RTV.num(0))
34255
- );
34256
- register(
34257
33817
  "shading",
34258
- builtinSingle(() => RTV.num(0))
34259
- );
34260
- register(
33818
+ "subplot",
33819
+ "legend",
33820
+ "sgtitle",
33821
+ "zlabel",
33822
+ "colorbar",
33823
+ "colormap",
33824
+ "axis",
33825
+ "view",
33826
+ "imagesc",
33827
+ "contour",
33828
+ "contourf",
33829
+ "mesh",
33830
+ "waterfall",
33831
+ "scatter",
34261
33832
  "drawnow",
34262
- builtinSingle(() => RTV.num(0))
33833
+ "pause"
33834
+ ];
33835
+ const placeholder = builtinSingle(() => RTV.num(0));
33836
+ for (const name of placeholderNames) {
33837
+ register(name, placeholder);
33838
+ }
33839
+ register(
33840
+ "ishold",
33841
+ builtinSingle(() => RTV.logical(false), { outputType: IType.Logical })
34263
33842
  );
33843
+ const colormapNames = [
33844
+ "parula",
33845
+ "jet",
33846
+ "hsv",
33847
+ "hot",
33848
+ "cool",
33849
+ "spring",
33850
+ "summer",
33851
+ "autumn",
33852
+ "winter",
33853
+ "gray",
33854
+ "bone",
33855
+ "copper",
33856
+ "pink"
33857
+ ];
33858
+ for (const cm of colormapNames) {
33859
+ register(
33860
+ cm,
33861
+ builtinSingle(() => RTV.char(cm))
33862
+ );
33863
+ }
34264
33864
  register(
34265
- "pause",
34266
- builtinSingle(() => RTV.num(0))
33865
+ "peaks",
33866
+ builtinSingle((args) => {
33867
+ const n = args.length > 0 ? isRuntimeNumber(args[0]) ? args[0] : toNumber(args[0]) : 49;
33868
+ const data = new FloatXArray(n * n);
33869
+ for (let j = 0; j < n; j++) {
33870
+ const y = -3 + 6 * j / (n - 1);
33871
+ for (let i = 0; i < n; i++) {
33872
+ const x = -3 + 6 * i / (n - 1);
33873
+ const x2 = x * x;
33874
+ const y2 = y * y;
33875
+ const z = 3 * Math.pow(1 - x, 2) * Math.exp(-x2 - Math.pow(y + 1, 2)) - 10 * (x / 5 - x * x2 - Math.pow(y, 5)) * Math.exp(-x2 - y2) - 1 / 3 * Math.exp(-Math.pow(x + 1, 2) - y2);
33876
+ data[j * n + i] = z;
33877
+ }
33878
+ }
33879
+ return RTV.tensor(data, [n, n]);
33880
+ })
34267
33881
  );
34268
33882
  }
34269
33883
 
@@ -34402,6 +34016,9 @@ function registerValidatorFunctions() {
34402
34016
  }
34403
34017
 
34404
34018
  // src/numbl-core/builtins/dummy.ts
34019
+ function registerDummyGroup(names, fn) {
34020
+ for (const name of names) register(name, fn);
34021
+ }
34405
34022
  var dummyHandleFunctions = [
34406
34023
  "groot",
34407
34024
  "gcf",
@@ -34413,14 +34030,6 @@ var dummyHandleFunctions = [
34413
34030
  "axis",
34414
34031
  "odeset"
34415
34032
  ];
34416
- function registerDummyHandleFunctions() {
34417
- const fn = builtinSingle(() => RTV.dummyHandle(), {
34418
- outputType: IType.DummyHandle
34419
- });
34420
- for (const name of dummyHandleFunctions) {
34421
- register(name, fn);
34422
- }
34423
- }
34424
34033
  var returnDummyStringFunctions = [
34425
34034
  "pwd",
34426
34035
  "datestr",
@@ -34428,41 +34037,9 @@ var returnDummyStringFunctions = [
34428
34037
  "lastwarn",
34429
34038
  "mfilename"
34430
34039
  ];
34431
- function registerDummyStringFunctions() {
34432
- const fn = builtinSingle(() => RTV.string(""), {
34433
- outputType: IType.String
34434
- });
34435
- for (const name of returnDummyStringFunctions) {
34436
- register(name, fn);
34437
- }
34438
- }
34439
- var returnEmptyArrayFunctions = ["who", "xlim", "ylim", "jet", "hot"];
34440
- function registerDummyArrayFunctions() {
34441
- const fn = builtinSingle(() => RTV.tensor([], [0, 0]), {
34442
- outputType: IType.tensor()
34443
- });
34444
- for (const name of returnEmptyArrayFunctions) {
34445
- register(name, fn);
34446
- }
34447
- }
34040
+ var returnEmptyArrayFunctions = ["who", "xlim", "ylim"];
34448
34041
  var returnDummyBooleanFunctions = ["ispc", "ismac", "isunix"];
34449
- function registerDummyBooleanFunctions() {
34450
- const fn = builtinSingle(() => RTV.logical(false), {
34451
- outputType: IType.Logical
34452
- });
34453
- for (const name of returnDummyBooleanFunctions) {
34454
- register(name, fn);
34455
- }
34456
- }
34457
34042
  var returnDummyCellArrayFunctions = ["listfonts"];
34458
- function registerDummyCellArrayFunctions() {
34459
- const fn = builtinSingle(() => RTV.cell([], [0, 0]), {
34460
- outputType: IType.cell(IType.Unknown, "unknown")
34461
- });
34462
- for (const name of returnDummyCellArrayFunctions) {
34463
- register(name, fn);
34464
- }
34465
- }
34466
34043
  function registerPathFunctions() {
34467
34044
  const dummyStr = builtinSingle(() => RTV.string(""), {
34468
34045
  outputType: IType.String
@@ -34510,11 +34087,28 @@ function registerHandleGetSet() {
34510
34087
  );
34511
34088
  }
34512
34089
  var registerDummyFunctions = () => {
34513
- registerDummyHandleFunctions();
34514
- registerDummyStringFunctions();
34515
- registerDummyArrayFunctions();
34516
- registerDummyBooleanFunctions();
34517
- registerDummyCellArrayFunctions();
34090
+ registerDummyGroup(
34091
+ dummyHandleFunctions,
34092
+ builtinSingle(() => RTV.dummyHandle(), { outputType: IType.DummyHandle })
34093
+ );
34094
+ registerDummyGroup(
34095
+ returnDummyStringFunctions,
34096
+ builtinSingle(() => RTV.string(""), { outputType: IType.String })
34097
+ );
34098
+ registerDummyGroup(
34099
+ returnEmptyArrayFunctions,
34100
+ builtinSingle(() => RTV.tensor([], [0, 0]), { outputType: IType.tensor() })
34101
+ );
34102
+ registerDummyGroup(
34103
+ returnDummyBooleanFunctions,
34104
+ builtinSingle(() => RTV.logical(false), { outputType: IType.Logical })
34105
+ );
34106
+ registerDummyGroup(
34107
+ returnDummyCellArrayFunctions,
34108
+ builtinSingle(() => RTV.cell([], [0, 0]), {
34109
+ outputType: IType.cell(IType.Unknown, "unknown")
34110
+ })
34111
+ );
34518
34112
  registerHandleGetSet();
34519
34113
  registerPathFunctions();
34520
34114
  registerFileIOFunctions();
@@ -34652,6 +34246,11 @@ function registerNumericalFunctions() {
34652
34246
  throw new RuntimeError("polyfit: x and y must have the same length");
34653
34247
  if (n < 0) throw new RuntimeError("polyfit: degree must be non-negative");
34654
34248
  const ncols = n + 1;
34249
+ if (ncols > m) {
34250
+ console.warn(
34251
+ "Warning: Polynomial is not unique; degree >= number of data points."
34252
+ );
34253
+ }
34655
34254
  const V = new FloatXArray(m * ncols);
34656
34255
  for (let j = 0; j < ncols; j++) {
34657
34256
  const power = n - j;
@@ -34659,65 +34258,31 @@ function registerNumericalFunctions() {
34659
34258
  V[j * m + i] = Math.pow(xArr[i], power);
34660
34259
  }
34661
34260
  }
34662
- const VTV = new FloatXArray(ncols * ncols);
34663
- for (let i = 0; i < ncols; i++) {
34664
- for (let j = 0; j < ncols; j++) {
34665
- let sum = 0;
34666
- for (let k = 0; k < m; k++) {
34667
- sum += V[i * m + k] * V[j * m + k];
34668
- }
34669
- VTV[j * ncols + i] = sum;
34670
- }
34671
- }
34672
- const VTy = new FloatXArray(ncols);
34261
+ const B = new FloatXArray(m);
34262
+ for (let i = 0; i < m; i++) B[i] = yArr[i];
34263
+ const X = linsolveLapack(V, m, ncols, B, 1);
34264
+ if (!X) throw new RuntimeError("polyfit: LAPACK bridge unavailable");
34265
+ let badlyConditioned = false;
34673
34266
  for (let i = 0; i < ncols; i++) {
34674
- let sum = 0;
34675
- for (let k = 0; k < m; k++) {
34676
- sum += V[i * m + k] * yArr[k];
34267
+ if (!isFinite(X[i])) {
34268
+ badlyConditioned = true;
34269
+ break;
34677
34270
  }
34678
- VTy[i] = sum;
34679
34271
  }
34680
- const aug = new FloatXArray(ncols * (ncols + 1));
34681
- for (let i = 0; i < ncols; i++) {
34682
- for (let j = 0; j < ncols; j++) {
34683
- aug[j * ncols + i] = VTV[j * ncols + i];
34684
- }
34685
- aug[ncols * ncols + i] = VTy[i];
34272
+ if (!badlyConditioned) {
34273
+ let maxX = 0;
34274
+ for (let i = 0; i < ncols; i++) maxX = Math.max(maxX, Math.abs(X[i]));
34275
+ let maxY = 0;
34276
+ for (let i = 0; i < m; i++) maxY = Math.max(maxY, Math.abs(yArr[i]));
34277
+ if (maxY > 0 && maxX / maxY > 1e10) badlyConditioned = true;
34686
34278
  }
34687
- for (let col = 0; col < ncols; col++) {
34688
- let maxVal = Math.abs(aug[col * ncols + col]);
34689
- let maxRow = col;
34690
- for (let row = col + 1; row < ncols; row++) {
34691
- const val = Math.abs(aug[col * ncols + row]);
34692
- if (val > maxVal) {
34693
- maxVal = val;
34694
- maxRow = row;
34695
- }
34696
- }
34697
- if (maxRow !== col) {
34698
- for (let j = 0; j <= ncols; j++) {
34699
- const tmp = aug[j * ncols + col];
34700
- aug[j * ncols + col] = aug[j * ncols + maxRow];
34701
- aug[j * ncols + maxRow] = tmp;
34702
- }
34703
- }
34704
- const pivot = aug[col * ncols + col];
34705
- if (Math.abs(pivot) < 1e-14) continue;
34706
- for (let j = 0; j <= ncols; j++) {
34707
- aug[j * ncols + col] /= pivot;
34708
- }
34709
- for (let row = 0; row < ncols; row++) {
34710
- if (row === col) continue;
34711
- const factor = aug[col * ncols + row];
34712
- for (let j = 0; j <= ncols; j++) {
34713
- aug[j * ncols + row] -= factor * aug[j * ncols + col];
34714
- }
34715
- }
34279
+ if (badlyConditioned) {
34280
+ console.warn(
34281
+ "Warning: Polynomial is badly conditioned. Add points with distinct X values, reduce the degree of the polynomial, or try centering and scaling as described in HELP POLYFIT."
34282
+ );
34716
34283
  }
34717
34284
  const result = new FloatXArray(ncols);
34718
- for (let i = 0; i < ncols; i++) {
34719
- result[i] = aug[ncols * ncols + i];
34720
- }
34285
+ for (let i = 0; i < ncols; i++) result[i] = X[i];
34721
34286
  return RTV.tensor(result, [1, ncols]);
34722
34287
  })
34723
34288
  );
@@ -36191,6 +35756,65 @@ function switchMatch(control, caseVal) {
36191
35756
  }
36192
35757
 
36193
35758
  // src/numbl-core/runtime/runtimeDispatch.ts
35759
+ function dispatchPlotCall(rt, name, args) {
35760
+ switch (name) {
35761
+ case "plot":
35762
+ return rt.plot_call(args.map((a) => ensureRuntimeValue(a)));
35763
+ case "plot3":
35764
+ return rt.plot3_call(args.map((a) => ensureRuntimeValue(a)));
35765
+ case "surf":
35766
+ return rt.surf_call(args.map((a) => ensureRuntimeValue(a)));
35767
+ case "scatter":
35768
+ return rt.scatter_call(args.map((a) => ensureRuntimeValue(a)));
35769
+ case "imagesc":
35770
+ return rt.imagesc_call(args.map((a) => ensureRuntimeValue(a)));
35771
+ case "contour":
35772
+ return rt.contour_call(
35773
+ args.map((a) => ensureRuntimeValue(a)),
35774
+ false
35775
+ );
35776
+ case "contourf":
35777
+ return rt.contour_call(
35778
+ args.map((a) => ensureRuntimeValue(a)),
35779
+ true
35780
+ );
35781
+ case "mesh":
35782
+ case "waterfall":
35783
+ return rt.mesh_call(args.map((a) => ensureRuntimeValue(a)));
35784
+ default:
35785
+ return void 0;
35786
+ }
35787
+ }
35788
+ function packResults(results, shape) {
35789
+ const allScalar = results.every(
35790
+ (r) => isRuntimeNumber(r) || isRuntimeLogical(r) || isRuntimeTensor(r) && r.data.length === 1
35791
+ );
35792
+ if (allScalar) {
35793
+ const data = new FloatXArray(results.length);
35794
+ const allLogical = results.every((r) => isRuntimeLogical(r));
35795
+ for (let i = 0; i < results.length; i++) {
35796
+ data[i] = toNumber(results[i]);
35797
+ }
35798
+ const result = RTV.tensor(data, [...shape]);
35799
+ if (allLogical) result._isLogical = true;
35800
+ return result;
35801
+ }
35802
+ return RTV.cell(results, [...shape]);
35803
+ }
35804
+ function coerceToTensor(v, fnName, which) {
35805
+ if (isRuntimeNumber(v)) {
35806
+ return RTV.tensor(new FloatXArray([v]), [1, 1]);
35807
+ }
35808
+ if (isRuntimeComplexNumber(v)) {
35809
+ return RTV.tensor(new FloatXArray([v.re]), [1, 1], new FloatXArray([v.im]));
35810
+ }
35811
+ if (isRuntimeTensor(v)) {
35812
+ return v;
35813
+ }
35814
+ throw new RuntimeError(
35815
+ `${fnName}: unsupported type for ${which} input argument: ${kstr(v)}`
35816
+ );
35817
+ }
36194
35818
  function getFuncHandle(name) {
36195
35819
  const handle = RTV.func(name, isBuiltin(name) ? "builtin" : "user");
36196
35820
  const nargin = getBuiltinNargin(name);
@@ -36289,15 +35913,8 @@ function dispatch(rt, name, nargout, args, targetClassName) {
36289
35913
  const callerLine = rt.$line;
36290
35914
  try {
36291
35915
  if (!targetClassName) {
36292
- if (name === "plot") {
36293
- return rt.plot_call(args.map((a) => ensureRuntimeValue(a)));
36294
- }
36295
- if (name === "plot3") {
36296
- return rt.plot3_call(args.map((a) => ensureRuntimeValue(a)));
36297
- }
36298
- if (name === "surf") {
36299
- return rt.surf_call(args.map((a) => ensureRuntimeValue(a)));
36300
- }
35916
+ const plotResult = dispatchPlotCall(rt, name, args);
35917
+ if (plotResult !== void 0) return plotResult;
36301
35918
  }
36302
35919
  if (rt.compileSpecialized) {
36303
35920
  const argTypes = args.map(
@@ -36336,29 +35953,15 @@ function dispatch(rt, name, nargout, args, targetClassName) {
36336
35953
  }
36337
35954
  }
36338
35955
  function callBuiltin(rt, name, nargout, args) {
36339
- if (name === "plot") {
36340
- return rt.plot_call(args.map((a) => ensureRuntimeValue(a)));
36341
- }
36342
- if (name === "plot3") {
36343
- return rt.plot3_call(args.map((a) => ensureRuntimeValue(a)));
36344
- }
36345
- if (name === "surf") {
36346
- return rt.surf_call(args.map((a) => ensureRuntimeValue(a)));
36347
- }
35956
+ const plotResult = dispatchPlotCall(rt, name, args);
35957
+ if (plotResult !== void 0) return plotResult;
36348
35958
  const builtin = rt.builtins[name];
36349
35959
  if (builtin) return builtin(nargout, args);
36350
35960
  throw new RuntimeError(`'${name}' is not a builtin function`);
36351
35961
  }
36352
35962
  function callBuiltinSync(rt, name, nargout, args) {
36353
- if (name === "plot") {
36354
- return rt.plot_call(args.map((a) => ensureRuntimeValue(a)));
36355
- }
36356
- if (name === "plot3") {
36357
- return rt.plot3_call(args.map((a) => ensureRuntimeValue(a)));
36358
- }
36359
- if (name === "surf") {
36360
- return rt.surf_call(args.map((a) => ensureRuntimeValue(a)));
36361
- }
35963
+ const plotResult = dispatchPlotCall(rt, name, args);
35964
+ if (plotResult !== void 0) return plotResult;
36362
35965
  const builtin = rt.builtins[name];
36363
35966
  if (builtin) return builtin(nargout, args);
36364
35967
  throw new RuntimeError(`'${name}' is not a builtin function`);
@@ -36543,28 +36146,12 @@ function arrayfunCellfunImpl(rt, name, nargout, args) {
36543
36146
  }
36544
36147
  }
36545
36148
  if (!uniformOutput) {
36546
- const outputs2 = allResults.map(
36149
+ const outputs = allResults.map(
36547
36150
  (results2) => RTV.cell(results2, [...shape])
36548
36151
  );
36549
- return outputs2;
36152
+ return outputs;
36550
36153
  }
36551
- const outputs = allResults.map((results2) => {
36552
- const allScalar2 = results2.every(
36553
- (r2) => isRuntimeNumber(r2) || isRuntimeLogical(r2) || isRuntimeTensor(r2) && r2.data.length === 1
36554
- );
36555
- if (allScalar2) {
36556
- const data = new FloatXArray(results2.length);
36557
- const allLogical = results2.every((r2) => isRuntimeLogical(r2));
36558
- for (let j = 0; j < results2.length; j++) {
36559
- data[j] = toNumber(results2[j]);
36560
- }
36561
- const result = RTV.tensor(data, [...shape]);
36562
- if (allLogical) result._isLogical = true;
36563
- return result;
36564
- }
36565
- return RTV.cell(results2, [...shape]);
36566
- });
36567
- return outputs;
36154
+ return allResults.map((results2) => packResults(results2, shape));
36568
36155
  }
36569
36156
  const results = [];
36570
36157
  for (let i = 0; i < len; i++) {
@@ -36574,20 +36161,7 @@ function arrayfunCellfunImpl(rt, name, nargout, args) {
36574
36161
  if (!uniformOutput) {
36575
36162
  return RTV.cell(results, [...shape]);
36576
36163
  }
36577
- const allScalar = results.every(
36578
- (r2) => isRuntimeNumber(r2) || isRuntimeLogical(r2) || isRuntimeTensor(r2) && r2.data.length === 1
36579
- );
36580
- if (allScalar) {
36581
- const data = new FloatXArray(results.length);
36582
- const allLogical = results.every((r2) => isRuntimeLogical(r2));
36583
- for (let i = 0; i < results.length; i++) {
36584
- data[i] = toNumber(results[i]);
36585
- }
36586
- const result = RTV.tensor(data, [...shape]);
36587
- if (allLogical) result._isLogical = true;
36588
- return result;
36589
- }
36590
- return RTV.cell(results, [...shape]);
36164
+ return packResults(results, shape);
36591
36165
  }
36592
36166
  const r = callFn(collectArgs(0));
36593
36167
  if (typeof r === "number") return r;
@@ -36697,38 +36271,8 @@ function bsxfunImpl(rt, _nargout, args) {
36697
36271
  }
36698
36272
  const rawA = ensureRuntimeValue(args[1]);
36699
36273
  const rawB = ensureRuntimeValue(args[2]);
36700
- let a;
36701
- let b;
36702
- if (isRuntimeNumber(rawA)) {
36703
- a = RTV.tensor(new FloatXArray([rawA]), [1, 1]);
36704
- } else if (isRuntimeComplexNumber(rawA)) {
36705
- a = RTV.tensor(
36706
- new FloatXArray([rawA.re]),
36707
- [1, 1],
36708
- new FloatXArray([rawA.im])
36709
- );
36710
- } else if (isRuntimeTensor(rawA)) {
36711
- a = rawA;
36712
- } else {
36713
- throw new RuntimeError(
36714
- `bsxfun: unsupported type for first input argument: ${kstr(rawA)}`
36715
- );
36716
- }
36717
- if (isRuntimeNumber(rawB)) {
36718
- b = RTV.tensor(new FloatXArray([rawB]), [1, 1]);
36719
- } else if (isRuntimeComplexNumber(rawB)) {
36720
- b = RTV.tensor(
36721
- new FloatXArray([rawB.re]),
36722
- [1, 1],
36723
- new FloatXArray([rawB.im])
36724
- );
36725
- } else if (isRuntimeTensor(rawB)) {
36726
- b = rawB;
36727
- } else {
36728
- throw new RuntimeError(
36729
- `bsxfun: unsupported type for second input argument: ${kstr(rawB)}`
36730
- );
36731
- }
36274
+ const a = coerceToTensor(rawA, "bsxfun", "first");
36275
+ const b = coerceToTensor(rawB, "bsxfun", "second");
36732
36276
  const outShape = getBroadcastShape(a.shape, b.shape);
36733
36277
  if (!outShape)
36734
36278
  throw new RuntimeError(
@@ -36819,6 +36363,20 @@ function extractSubsIndices(subs) {
36819
36363
  }
36820
36364
  return [subs];
36821
36365
  }
36366
+ function applySubsEntry(rt, entry, target, nargout, fnName) {
36367
+ if (entry.type === ".") {
36368
+ return rt.getMember(target, extractSubsType(entry.subs));
36369
+ }
36370
+ if (entry.type === "()") {
36371
+ return rt.index(target, extractSubsIndices(entry.subs), nargout);
36372
+ }
36373
+ if (entry.type === "{}") {
36374
+ return rt.indexCell(target, extractSubsIndices(entry.subs));
36375
+ }
36376
+ throw new RuntimeError(
36377
+ `${fnName}: unsupported subscript type '${entry.type}'`
36378
+ );
36379
+ }
36822
36380
  function subsrefBuiltin(rt, nargout, args) {
36823
36381
  if (args.length !== 2)
36824
36382
  throw new RuntimeError("subsref requires exactly 2 arguments");
@@ -36846,20 +36404,7 @@ function subsrefBuiltin(rt, nargout, args) {
36846
36404
  }
36847
36405
  let result = obj;
36848
36406
  for (const entry of elements) {
36849
- if (entry.type === ".") {
36850
- const fieldName = extractSubsType(entry.subs);
36851
- result = rt.getMember(result, fieldName);
36852
- } else if (entry.type === "()") {
36853
- const indices = extractSubsIndices(entry.subs);
36854
- result = rt.index(result, indices, nargout);
36855
- } else if (entry.type === "{}") {
36856
- const indices = extractSubsIndices(entry.subs);
36857
- result = rt.indexCell(result, indices);
36858
- } else {
36859
- throw new RuntimeError(
36860
- `subsref: unsupported subscript type '${entry.type}'`
36861
- );
36862
- }
36407
+ result = applySubsEntry(rt, entry, result, nargout, "subsref");
36863
36408
  }
36864
36409
  return result;
36865
36410
  }
@@ -36894,21 +36439,7 @@ function subsasgnBuiltin(rt, _nargout, args) {
36894
36439
  const intermediates = [obj];
36895
36440
  let current = obj;
36896
36441
  for (let i = 0; i < elements.length - 1; i++) {
36897
- const entry = elements[i];
36898
- if (entry.type === ".") {
36899
- const fieldName = extractSubsType(entry.subs);
36900
- current = rt.getMember(current, fieldName);
36901
- } else if (entry.type === "()") {
36902
- const indices = extractSubsIndices(entry.subs);
36903
- current = rt.index(current, indices, 1);
36904
- } else if (entry.type === "{}") {
36905
- const indices = extractSubsIndices(entry.subs);
36906
- current = rt.indexCell(current, indices);
36907
- } else {
36908
- throw new RuntimeError(
36909
- `subsasgn: unsupported subscript type '${entry.type}'`
36910
- );
36911
- }
36442
+ current = applySubsEntry(rt, elements[i], current, 1, "subsasgn");
36912
36443
  intermediates.push(current);
36913
36444
  }
36914
36445
  const last = elements[elements.length - 1];
@@ -38238,6 +37769,88 @@ function getStringValueIfString(v) {
38238
37769
  if (isRuntimeChar(v)) return v.value;
38239
37770
  return void 0;
38240
37771
  }
37772
+ function parseScatterArgs(args) {
37773
+ if (args.length < 2) throw new Error("scatter requires at least 2 arguments");
37774
+ const xData = toNumberArray(args[0]);
37775
+ const yData = toNumberArray(args[1]);
37776
+ const trace = {
37777
+ x: xData,
37778
+ y: yData,
37779
+ marker: "o",
37780
+ lineStyle: "none"
37781
+ };
37782
+ let pos = 2;
37783
+ let filled = false;
37784
+ if (pos < args.length && isNumericArg(args[pos])) {
37785
+ const sz = args[pos];
37786
+ if (isRuntimeNumber(sz)) {
37787
+ trace.markerSize = Math.sqrt(sz) * 0.5;
37788
+ } else if (isRuntimeTensor(sz)) {
37789
+ const sArr = toNumberArray(sz);
37790
+ if (sArr.length === 1 || new Set(sArr).size === 1) {
37791
+ trace.markerSize = Math.sqrt(sArr[0]) * 0.5;
37792
+ }
37793
+ }
37794
+ pos++;
37795
+ }
37796
+ if (pos < args.length && !isNameValueKey(args[pos])) {
37797
+ if (isStringArg(args[pos])) {
37798
+ const s = getStringValue(args[pos]);
37799
+ if (s === "filled") {
37800
+ filled = true;
37801
+ pos++;
37802
+ } else {
37803
+ const c = resolveColor(s);
37804
+ if (c) {
37805
+ trace.color = c;
37806
+ pos++;
37807
+ } else {
37808
+ const spec = parseLineSpec(s);
37809
+ if (spec?.marker) {
37810
+ trace.marker = spec.marker;
37811
+ if (spec.color) trace.color = COLOR_SHORT[spec.color];
37812
+ pos++;
37813
+ }
37814
+ }
37815
+ }
37816
+ } else if (isNumericArg(args[pos])) {
37817
+ const c = resolveColor(args[pos]);
37818
+ if (c) {
37819
+ trace.color = c;
37820
+ pos++;
37821
+ }
37822
+ }
37823
+ }
37824
+ while (pos < args.length && isStringArg(args[pos]) && !isNameValueKey(args[pos])) {
37825
+ const s = getStringValue(args[pos]);
37826
+ if (s === "filled") {
37827
+ filled = true;
37828
+ pos++;
37829
+ } else {
37830
+ const spec = parseLineSpec(s);
37831
+ if (spec?.marker) {
37832
+ trace.marker = spec.marker;
37833
+ if (spec.color) trace.color = COLOR_SHORT[spec.color];
37834
+ pos++;
37835
+ } else {
37836
+ break;
37837
+ }
37838
+ }
37839
+ }
37840
+ if (filled) {
37841
+ trace.markerFaceColor = trace.color || [0, 0, 1];
37842
+ }
37843
+ while (pos < args.length) {
37844
+ const key = isNameValueKey(args[pos]);
37845
+ if (!key) break;
37846
+ pos++;
37847
+ if (pos >= args.length) break;
37848
+ const value = args[pos];
37849
+ pos++;
37850
+ applyNameValue([trace], key, value);
37851
+ }
37852
+ return [trace];
37853
+ }
38241
37854
  function applyNameValue(traces, key, value) {
38242
37855
  switch (key) {
38243
37856
  case "color": {
@@ -38282,6 +37895,95 @@ function applyNameValue(traces, key, value) {
38282
37895
  }
38283
37896
  }
38284
37897
  }
37898
+ function parseImagescArgs(args) {
37899
+ if (args.length === 1) {
37900
+ const info = getMatrixInfo(args[0]);
37901
+ return {
37902
+ x: [1, info.cols],
37903
+ y: [1, info.rows],
37904
+ z: info.data,
37905
+ rows: info.rows,
37906
+ cols: info.cols
37907
+ };
37908
+ }
37909
+ if (args.length >= 3) {
37910
+ const xArr = toNumberArray(args[0]);
37911
+ const yArr = toNumberArray(args[1]);
37912
+ const info = getMatrixInfo(args[2]);
37913
+ return {
37914
+ x: [xArr[0], xArr[xArr.length - 1]],
37915
+ y: [yArr[0], yArr[yArr.length - 1]],
37916
+ z: info.data,
37917
+ rows: info.rows,
37918
+ cols: info.cols
37919
+ };
37920
+ }
37921
+ throw new Error("imagesc requires 1 or 3+ arguments");
37922
+ }
37923
+ function parseContourArgs(args, filled) {
37924
+ let pos = 0;
37925
+ let numericCount = 0;
37926
+ for (let i = pos; i < args.length; i++) {
37927
+ if (isNumericArg(args[i])) numericCount++;
37928
+ else break;
37929
+ }
37930
+ let xData;
37931
+ let yData;
37932
+ let zData;
37933
+ let rows;
37934
+ let cols;
37935
+ let nLevels = 10;
37936
+ if (numericCount === 1) {
37937
+ const info = getMatrixInfo(args[pos++]);
37938
+ rows = info.rows;
37939
+ cols = info.cols;
37940
+ zData = info.data;
37941
+ const gen = generateMeshgrid(rows, cols);
37942
+ xData = gen.x;
37943
+ yData = gen.y;
37944
+ } else if (numericCount === 2) {
37945
+ const info = getMatrixInfo(args[pos++]);
37946
+ rows = info.rows;
37947
+ cols = info.cols;
37948
+ zData = info.data;
37949
+ nLevels = typeof args[pos] === "number" ? args[pos] : toNumber(args[pos]);
37950
+ pos++;
37951
+ const gen = generateMeshgrid(rows, cols);
37952
+ xData = gen.x;
37953
+ yData = gen.y;
37954
+ } else if (numericCount === 3) {
37955
+ const x = args[pos++];
37956
+ const y = args[pos++];
37957
+ const zInfo = getMatrixInfo(args[pos++]);
37958
+ rows = zInfo.rows;
37959
+ cols = zInfo.cols;
37960
+ zData = zInfo.data;
37961
+ const expanded = expandXY(x, y, rows, cols);
37962
+ xData = expanded.x;
37963
+ yData = expanded.y;
37964
+ } else if (numericCount >= 4) {
37965
+ const x = args[pos++];
37966
+ const y = args[pos++];
37967
+ const zInfo = getMatrixInfo(args[pos++]);
37968
+ rows = zInfo.rows;
37969
+ cols = zInfo.cols;
37970
+ zData = zInfo.data;
37971
+ nLevels = typeof args[pos] === "number" ? args[pos] : toNumber(args[pos]);
37972
+ pos++;
37973
+ const expanded = expandXY(x, y, rows, cols);
37974
+ xData = expanded.x;
37975
+ yData = expanded.y;
37976
+ } else {
37977
+ throw new Error("contour requires at least 1 argument");
37978
+ }
37979
+ return { x: xData, y: yData, z: zData, rows, cols, nLevels, filled };
37980
+ }
37981
+ function parseMeshArgs(args) {
37982
+ const trace = parseSurfArgs(args);
37983
+ if (!trace.edgeColor) trace.edgeColor = "flat";
37984
+ if (!trace.faceColor) trace.faceColor = "none";
37985
+ return trace;
37986
+ }
38285
37987
 
38286
37988
  // src/numbl-core/runtime/syncChannel.ts
38287
37989
  var syncSleepWarned = false;
@@ -38307,10 +38009,17 @@ function syncSleep(ms) {
38307
38009
  // src/numbl-core/runtime/runtimePlot.ts
38308
38010
  function plotInstr(plotInstructions, instr) {
38309
38011
  if (instr.type === "set_figure_handle") {
38310
- plotInstructions.push({
38311
- type: "set_figure_handle",
38312
- handle: typeof instr.handle === "number" ? instr.handle : toNumber(ensureRuntimeValue(instr.handle))
38313
- });
38012
+ let handle;
38013
+ if (typeof instr.handle === "number") {
38014
+ handle = instr.handle;
38015
+ } else {
38016
+ try {
38017
+ handle = toNumber(ensureRuntimeValue(instr.handle));
38018
+ } catch {
38019
+ handle = 1;
38020
+ }
38021
+ }
38022
+ plotInstructions.push({ type: "set_figure_handle", handle });
38314
38023
  } else if (instr.type === "plot") {
38315
38024
  plotInstructions.push({
38316
38025
  type: "plot",
@@ -38349,7 +38058,63 @@ function plotInstr(plotInstructions, instr) {
38349
38058
  plotInstructions.push({ type: "close_all" });
38350
38059
  } else if (instr.type === "clf") {
38351
38060
  plotInstructions.push({ type: "clf" });
38061
+ } else if (instr.type === "set_subplot") {
38062
+ const rows = typeof instr.rows === "number" ? instr.rows : toNumber(ensureRuntimeValue(instr.rows));
38063
+ const cols = typeof instr.cols === "number" ? instr.cols : toNumber(ensureRuntimeValue(instr.cols));
38064
+ const index2 = typeof instr.index === "number" ? instr.index : toNumber(ensureRuntimeValue(instr.index));
38065
+ plotInstructions.push({ type: "set_subplot", rows, cols, index: index2 });
38066
+ } else if (instr.type === "set_sgtitle") {
38067
+ const text = typeof instr.text === "string" ? instr.text : toString(ensureRuntimeValue(instr.text));
38068
+ plotInstructions.push({ type: "set_sgtitle", text });
38069
+ } else if (instr.type === "set_grid") {
38070
+ const val = instr.value;
38071
+ let on;
38072
+ if (typeof val === "string") on = val === "on";
38073
+ else if (typeof val === "boolean") on = val;
38074
+ else {
38075
+ const mv = ensureRuntimeValue(val);
38076
+ on = toString(mv) === "on";
38077
+ }
38078
+ plotInstructions.push({ type: "set_grid", value: on });
38079
+ } else if (instr.type === "set_zlabel") {
38080
+ const text = typeof instr.text === "string" ? instr.text : toString(ensureRuntimeValue(instr.text));
38081
+ plotInstructions.push({ type: "set_zlabel", text });
38082
+ } else if (instr.type === "set_colorbar") {
38083
+ const val = typeof instr.value === "string" ? instr.value : toString(ensureRuntimeValue(instr.value));
38084
+ plotInstructions.push({ type: "set_colorbar", value: val });
38085
+ } else if (instr.type === "set_colormap") {
38086
+ const name = typeof instr.name === "string" ? instr.name : toString(ensureRuntimeValue(instr.name));
38087
+ plotInstructions.push({
38088
+ type: "set_colormap",
38089
+ name: name.replace(/^"|"$/g, "")
38090
+ });
38091
+ } else if (instr.type === "set_axis") {
38092
+ const val = typeof instr.value === "string" ? instr.value : toString(ensureRuntimeValue(instr.value));
38093
+ plotInstructions.push({
38094
+ type: "set_axis",
38095
+ value: val.replace(/^"|"$/g, "")
38096
+ });
38097
+ }
38098
+ }
38099
+ function viewCall(plotInstructions, args) {
38100
+ let az;
38101
+ let el;
38102
+ if (args.length === 1) {
38103
+ const n = typeof args[0] === "number" ? args[0] : toNumber(args[0]);
38104
+ if (n === 2) {
38105
+ az = 0;
38106
+ el = 90;
38107
+ } else {
38108
+ az = -37.5;
38109
+ el = 30;
38110
+ }
38111
+ } else if (args.length >= 2) {
38112
+ az = typeof args[0] === "number" ? args[0] : toNumber(args[0]);
38113
+ el = typeof args[1] === "number" ? args[1] : toNumber(args[1]);
38114
+ } else {
38115
+ return;
38352
38116
  }
38117
+ plotInstructions.push({ type: "set_view", az, el });
38353
38118
  }
38354
38119
  function plotCall(plotInstructions, args) {
38355
38120
  const traces = parsePlotArgs(args);
@@ -38367,6 +38132,38 @@ function surfCall(plotInstructions, args) {
38367
38132
  const trace = parseSurfArgs(args);
38368
38133
  plotInstructions.push({ type: "surf", trace });
38369
38134
  }
38135
+ function imagescCall(plotInstructions, args) {
38136
+ const trace = parseImagescArgs(args);
38137
+ plotInstructions.push({ type: "imagesc", trace });
38138
+ }
38139
+ function contourCall(plotInstructions, args, filled) {
38140
+ const trace = parseContourArgs(args, filled);
38141
+ plotInstructions.push({ type: "contour", trace });
38142
+ }
38143
+ function meshCall(plotInstructions, args) {
38144
+ const trace = parseMeshArgs(args);
38145
+ plotInstructions.push({ type: "mesh", trace });
38146
+ }
38147
+ function scatterCall(plotInstructions, args) {
38148
+ const traces = parseScatterArgs(args);
38149
+ if (traces.length > 0) {
38150
+ plotInstructions.push({ type: "plot", traces });
38151
+ }
38152
+ }
38153
+ function legendCall(plotInstructions, args) {
38154
+ const labels = [];
38155
+ for (let i = 0; i < args.length; i++) {
38156
+ const s = toString(args[i]);
38157
+ if (s === "Location" || s === "Orientation" || s === "FontSize" || s === "Box" || s === "Color" || s === "EdgeColor" || s === "TextColor") {
38158
+ i++;
38159
+ continue;
38160
+ }
38161
+ labels.push(s);
38162
+ }
38163
+ if (labels.length > 0) {
38164
+ plotInstructions.push({ type: "set_legend", labels });
38165
+ }
38166
+ }
38370
38167
  function drawnow(plotInstructions, options) {
38371
38168
  if (options.onDrawnow && plotInstructions.length > 0) {
38372
38169
  options.onDrawnow([...plotInstructions]);
@@ -38475,6 +38272,61 @@ var Runtime = class _Runtime {
38475
38272
  this.builtins["surf"] = (_nargout, args) => {
38476
38273
  this.surf_call(args.map((a) => ensureRuntimeValue(a)));
38477
38274
  };
38275
+ this.builtins["scatter"] = (_nargout, args) => {
38276
+ this.scatter_call(args.map((a) => ensureRuntimeValue(a)));
38277
+ };
38278
+ this.builtins["imagesc"] = (_nargout, args) => {
38279
+ this.imagesc_call(args.map((a) => ensureRuntimeValue(a)));
38280
+ };
38281
+ this.builtins["contour"] = (_nargout, args) => {
38282
+ this.contour_call(
38283
+ args.map((a) => ensureRuntimeValue(a)),
38284
+ false
38285
+ );
38286
+ };
38287
+ this.builtins["contourf"] = (_nargout, args) => {
38288
+ this.contour_call(
38289
+ args.map((a) => ensureRuntimeValue(a)),
38290
+ true
38291
+ );
38292
+ };
38293
+ this.builtins["mesh"] = (_nargout, args) => {
38294
+ this.mesh_call(args.map((a) => ensureRuntimeValue(a)));
38295
+ };
38296
+ this.builtins["waterfall"] = (_nargout, args) => {
38297
+ this.mesh_call(args.map((a) => ensureRuntimeValue(a)));
38298
+ };
38299
+ this.builtins["colormap"] = (_nargout, args) => {
38300
+ if (args.length > 0) {
38301
+ const rv = ensureRuntimeValue(args[0]);
38302
+ const name = toString(rv).replace(/^"|"$/g, "");
38303
+ plotInstr(this.plotInstructions, { type: "set_colormap", name });
38304
+ }
38305
+ };
38306
+ this.builtins["view"] = (_nargout, args) => {
38307
+ this.view_call(args.map((a) => ensureRuntimeValue(a)));
38308
+ };
38309
+ this.builtins["zlabel"] = (_nargout, args) => {
38310
+ if (args.length > 0) {
38311
+ plotInstr(this.plotInstructions, {
38312
+ type: "set_zlabel",
38313
+ text: args[0]
38314
+ });
38315
+ }
38316
+ };
38317
+ this.builtins["colorbar"] = (_nargout, args) => {
38318
+ const val = args.length > 0 ? toString(ensureRuntimeValue(args[0])) : "on";
38319
+ plotInstr(this.plotInstructions, { type: "set_colorbar", value: val });
38320
+ };
38321
+ this.builtins["axis"] = (_nargout, args) => {
38322
+ if (args.length > 0) {
38323
+ const val = toString(ensureRuntimeValue(args[0])).replace(
38324
+ /^"|"$/g,
38325
+ ""
38326
+ );
38327
+ plotInstr(this.plotInstructions, { type: "set_axis", value: val });
38328
+ }
38329
+ };
38478
38330
  }
38479
38331
  profileEnter(key) {
38480
38332
  if (!this.profilingEnabled) return;
@@ -39065,6 +38917,24 @@ var Runtime = class _Runtime {
39065
38917
  surf_call(args) {
39066
38918
  surfCall(this.plotInstructions, args);
39067
38919
  }
38920
+ scatter_call(args) {
38921
+ scatterCall(this.plotInstructions, args);
38922
+ }
38923
+ imagesc_call(args) {
38924
+ imagescCall(this.plotInstructions, args);
38925
+ }
38926
+ contour_call(args, filled) {
38927
+ contourCall(this.plotInstructions, args, filled);
38928
+ }
38929
+ mesh_call(args) {
38930
+ meshCall(this.plotInstructions, args);
38931
+ }
38932
+ view_call(args) {
38933
+ viewCall(this.plotInstructions, args);
38934
+ }
38935
+ legend_call(args) {
38936
+ legendCall(this.plotInstructions, args);
38937
+ }
39068
38938
  // ── Drawnow / Pause ─────────────────────────────────────────────────
39069
38939
  drawnow() {
39070
38940
  return drawnow(this.plotInstructions, this.options);
@@ -40637,13 +40507,6 @@ var LoweringContext = class _LoweringContext {
40637
40507
  }
40638
40508
  for (const [className, group] of classFolderGroups) {
40639
40509
  if (!group.classDefFile) {
40640
- for (const mf of group.methodFiles) {
40641
- const baseName = mf.name.split("/").pop().replace(/\.m$/, "");
40642
- this.registry.filesByFuncName.set(baseName, {
40643
- fileName: mf.name,
40644
- source: mf.source
40645
- });
40646
- }
40647
40510
  continue;
40648
40511
  }
40649
40512
  this.registerWorkspaceClass(className, group.classDefFile);
@@ -40778,7 +40641,9 @@ var LoweringContext = class _LoweringContext {
40778
40641
  file.name,
40779
40642
  file.source
40780
40643
  );
40781
- this.registry.classesByName.set(qualifiedName, info);
40644
+ if (!this.registry.classesByName.has(qualifiedName)) {
40645
+ this.registry.classesByName.set(qualifiedName, info);
40646
+ }
40782
40647
  }
40783
40648
  /**
40784
40649
  * Register a classdef statement found in the local (main) file.
@@ -41875,25 +41740,36 @@ function genFuncCall(cg, kind) {
41875
41740
  }
41876
41741
  }
41877
41742
  }
41878
- if (kind.name === "figure")
41879
- return `$rt.plot_instr({type: "set_figure_handle", handle: ${args[0] ?? "1"}})`;
41880
- if (kind.name === "hold")
41881
- return `$rt.plot_instr({type: "set_hold", value: ${args[0]}})`;
41882
- if (kind.name === "ishold") return `$rt.ishold()`;
41883
- if (kind.name === "clf") return `$rt.plot_instr({type: "clf"})`;
41884
- if (kind.name === "title")
41885
- return `$rt.plot_instr({type: "set_title", text: ${args[0] ?? '""'}})`;
41886
- if (kind.name === "xlabel")
41887
- return `$rt.plot_instr({type: "set_xlabel", text: ${args[0] ?? '""'}})`;
41888
- if (kind.name === "ylabel")
41889
- return `$rt.plot_instr({type: "set_ylabel", text: ${args[0] ?? '""'}})`;
41890
- if (kind.name === "shading")
41891
- return `$rt.plot_instr({type: "set_shading", shading: ${args[0] ?? '"faceted"'}})`;
41892
- if (kind.name === "close") {
41893
- if (args.length > 0) {
41894
- return `$rt.plot_instr({type: "close_all"})`;
41743
+ {
41744
+ const plotInstrTable = {
41745
+ figure: ["set_figure_handle", "handle", "1"],
41746
+ hold: ["set_hold", "value", "true"],
41747
+ clf: ["clf", "", ""],
41748
+ title: ["set_title", "text", '""'],
41749
+ xlabel: ["set_xlabel", "text", '""'],
41750
+ ylabel: ["set_ylabel", "text", '""'],
41751
+ zlabel: ["set_zlabel", "text", '""'],
41752
+ shading: ["set_shading", "shading", '"faceted"'],
41753
+ sgtitle: ["set_sgtitle", "text", '""'],
41754
+ grid: ["set_grid", "value", "true"],
41755
+ colorbar: ["set_colorbar", "value", '"on"'],
41756
+ colormap: ["set_colormap", "name", '"parula"'],
41757
+ axis: ["set_axis", "value", '"auto"']
41758
+ };
41759
+ const entry = Object.hasOwn(plotInstrTable, kind.name) ? plotInstrTable[kind.name] : void 0;
41760
+ if (entry) {
41761
+ const [instrType, paramName, defaultVal] = entry;
41762
+ if (!paramName) return `$rt.plot_instr({type: "${instrType}"})`;
41763
+ return `$rt.plot_instr({type: "${instrType}", ${paramName}: ${args[0] ?? defaultVal}})`;
41764
+ }
41765
+ if (kind.name === "ishold") return `$rt.ishold()`;
41766
+ if (kind.name === "close") {
41767
+ return args.length > 0 ? `$rt.plot_instr({type: "close_all"})` : `$rt.plot_instr({type: "close"})`;
41895
41768
  }
41896
- return `$rt.plot_instr({type: "close"})`;
41769
+ if (kind.name === "subplot")
41770
+ return `$rt.plot_instr({type: "set_subplot", rows: ${args[0] ?? "1"}, cols: ${args[1] ?? "1"}, index: ${args[2] ?? "1"}})`;
41771
+ if (kind.name === "legend") return `$rt.legend_call([${args.join(", ")}])`;
41772
+ if (kind.name === "view") return `$rt.view_call([${args.join(", ")}])`;
41897
41773
  }
41898
41774
  if (cg.nestedFunctionNames.has(kind.name)) {
41899
41775
  return buildSpecializedCall(
@@ -43626,9 +43502,28 @@ function buildWasmMap(wasmFiles) {
43626
43502
  }
43627
43503
  return map;
43628
43504
  }
43629
- function parseWasmDirective(source) {
43630
- const match = source.match(/^\s*\/\/\s*wasm:\s*(\S+)/);
43631
- return match ? match[1] : null;
43505
+ function parseDirectives(source) {
43506
+ const directives = {};
43507
+ const lines = source.split("\n");
43508
+ for (const line of lines) {
43509
+ const match = line.match(/^\s*\/\/\s*(\w+):\s*(\S+)/);
43510
+ if (!match) break;
43511
+ const key = match[1];
43512
+ const value = match[2];
43513
+ if (key === "wasm") directives.wasm = value;
43514
+ else if (key === "native") directives.native = value;
43515
+ }
43516
+ return directives;
43517
+ }
43518
+ function nativeLibFilename(baseName) {
43519
+ switch (process.platform) {
43520
+ case "win32":
43521
+ return `${baseName}.dll`;
43522
+ case "darwin":
43523
+ return `${baseName}.dylib`;
43524
+ default:
43525
+ return `${baseName}.so`;
43526
+ }
43632
43527
  }
43633
43528
  function instantiateWasm(wasmData) {
43634
43529
  const wasmModule = new WebAssembly.Module(wasmData);
@@ -43659,7 +43554,7 @@ function instantiateWasm(wasmData) {
43659
43554
  }
43660
43555
  return new WebAssembly.Instance(wasmModule, importObject);
43661
43556
  }
43662
- function loadJsUserFunctions(jsFiles, wasmFiles) {
43557
+ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
43663
43558
  const result = /* @__PURE__ */ new Map();
43664
43559
  const wasmMap = wasmFiles ? buildWasmMap(wasmFiles) : /* @__PURE__ */ new Map();
43665
43560
  const wasmInstanceCache = /* @__PURE__ */ new Map();
@@ -43667,7 +43562,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles) {
43667
43562
  const cached = wasmInstanceCache.get(name);
43668
43563
  if (cached) return cached;
43669
43564
  const data = wasmMap.get(name);
43670
- if (!data) return null;
43565
+ if (!data) return void 0;
43671
43566
  const instance = instantiateWasm(data);
43672
43567
  wasmInstanceCache.set(name, instance);
43673
43568
  return instance;
@@ -43685,8 +43580,18 @@ function loadJsUserFunctions(jsFiles, wasmFiles) {
43685
43580
  apply: branch.apply
43686
43581
  });
43687
43582
  };
43688
- const wasmName = parseWasmDirective(file.source) ?? funcName;
43689
- const wasmInstance = getWasmInstance(wasmName);
43583
+ const directives = parseDirectives(file.source);
43584
+ const wasmInstance = directives.wasm ? getWasmInstance(directives.wasm) : void 0;
43585
+ let nativeLib;
43586
+ if (directives.native && nativeBridge2) {
43587
+ const libFile = nativeLibFilename(directives.native);
43588
+ const dir = file.name.substring(0, file.name.lastIndexOf("/") + 1);
43589
+ const libPath = dir + libFile;
43590
+ try {
43591
+ nativeLib = nativeBridge2.load(libPath);
43592
+ } catch {
43593
+ }
43594
+ }
43690
43595
  const factory = new Function(
43691
43596
  "RTV",
43692
43597
  "RuntimeError",
@@ -43694,14 +43599,44 @@ function loadJsUserFunctions(jsFiles, wasmFiles) {
43694
43599
  "IType",
43695
43600
  "register",
43696
43601
  "wasm",
43602
+ "native",
43697
43603
  file.source
43698
43604
  );
43699
- factory(RTV, RuntimeError, FloatXArray, IType, registerFn, wasmInstance);
43605
+ factory(
43606
+ RTV,
43607
+ RuntimeError,
43608
+ FloatXArray,
43609
+ IType,
43610
+ registerFn,
43611
+ wasmInstance,
43612
+ nativeLib
43613
+ );
43700
43614
  if (branches.length === 0) {
43701
43615
  throw new Error(
43702
43616
  `JS user function '${funcName}' (${file.name}) must call register() at least once`
43703
43617
  );
43704
43618
  }
43619
+ if (directives.native || directives.wasm) {
43620
+ const parts = [];
43621
+ if (directives.native) {
43622
+ parts.push(nativeLib ? "native: loaded" : "native: not found");
43623
+ }
43624
+ if (directives.wasm) {
43625
+ parts.push(wasmInstance ? "wasm: loaded" : "wasm: not found");
43626
+ }
43627
+ const statusMsg = `${funcName}: ${parts.join(", ")}`;
43628
+ let logged = false;
43629
+ for (const branch of branches) {
43630
+ const origApply = branch.apply;
43631
+ branch.apply = (...applyArgs) => {
43632
+ if (!logged) {
43633
+ logged = true;
43634
+ console.log(statusMsg);
43635
+ }
43636
+ return origApply(...applyArgs);
43637
+ };
43638
+ }
43639
+ }
43705
43640
  result.set(funcName, branches);
43706
43641
  } catch (e) {
43707
43642
  const msg = e instanceof Error ? e.message : String(e);
@@ -43817,7 +43752,8 @@ function generateMainScriptCode(source, mainFileName = "script.m", workspaceFile
43817
43752
  _t0 = performance.now();
43818
43753
  const jsUserFunctions = loadJsUserFunctions(
43819
43754
  jsWorkspaceFiles,
43820
- wasmWorkspaceFiles
43755
+ wasmWorkspaceFiles,
43756
+ opts?.nativeBridge
43821
43757
  );
43822
43758
  const _loadJsUserFunctionsMs = performance.now() - _t0;
43823
43759
  _t0 = performance.now();
@@ -43959,7 +43895,7 @@ function generateMainScriptCode(source, mainFileName = "script.m", workspaceFile
43959
43895
  }
43960
43896
 
43961
43897
  // src/numbl-core/executeCode.ts
43962
- function executeCode(source, options = {}, workspaceFiles, mainFileName = "script.m", searchPaths) {
43898
+ function executeCode(source, options = {}, workspaceFiles, mainFileName = "script.m", searchPaths, nativeBridge2) {
43963
43899
  const initialVariableNames = options.initialVariableValues ? Object.keys(options.initialVariableValues) : void 0;
43964
43900
  const codegenStart = performance.now();
43965
43901
  const {
@@ -43983,7 +43919,7 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
43983
43919
  workspaceFiles,
43984
43920
  initialVariableNames,
43985
43921
  searchPaths,
43986
- { noLineTracking: options.noLineTracking }
43922
+ { noLineTracking: options.noLineTracking, nativeBridge: nativeBridge2 }
43987
43923
  );
43988
43924
  const codegenTimeMs = performance.now() - codegenStart;
43989
43925
  if (options.log) {
@@ -44126,7 +44062,7 @@ function processMipLoad(packageName, _visited) {
44126
44062
  if (visited.has(packageName)) return [];
44127
44063
  visited.add(packageName);
44128
44064
  const mipDir = process.env.MIP_DIR || join3(homedir2(), ".mip");
44129
- const pkgDir = join3(mipDir, "packages", packageName);
44065
+ const pkgDir = join3(mipDir, "numbl_packages", packageName);
44130
44066
  const loadScript = join3(pkgDir, "load_package.m");
44131
44067
  if (!existsSync3(loadScript)) {
44132
44068
  throw new Error(
@@ -44140,7 +44076,7 @@ function processMipLoad(packageName, _visited) {
44140
44076
  const mipJson = JSON.parse(readFileSync3(mipJsonPath, "utf-8"));
44141
44077
  const deps = mipJson.dependencies ?? [];
44142
44078
  for (const dep of deps) {
44143
- const depPkgDir = join3(mipDir, "packages", dep);
44079
+ const depPkgDir = join3(mipDir, "numbl_packages", dep);
44144
44080
  if (!existsSync3(depPkgDir)) {
44145
44081
  console.warn(
44146
44082
  `Warning: dependency "${dep}" of "${packageName}" is not installed; skipping`
@@ -44380,7 +44316,7 @@ function saveHistoryEntry(entry, hist) {
44380
44316
  } catch {
44381
44317
  }
44382
44318
  }
44383
- async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths) {
44319
+ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nativeBridge2) {
44384
44320
  let variableValues = {};
44385
44321
  let holdState = false;
44386
44322
  const workspaceFiles = [...initialWorkspaceFiles];
@@ -44439,7 +44375,8 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths) {
44439
44375
  },
44440
44376
  workspaceFiles,
44441
44377
  "repl",
44442
- searchPaths
44378
+ searchPaths,
44379
+ nativeBridge2
44443
44380
  );
44444
44381
  variableValues = result.variableValues;
44445
44382
  holdState = result.holdState;
@@ -44547,7 +44484,8 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths) {
44547
44484
  },
44548
44485
  workspaceFiles,
44549
44486
  "repl",
44550
- searchPaths
44487
+ searchPaths,
44488
+ nativeBridge2
44551
44489
  );
44552
44490
  variableValues = result.variableValues;
44553
44491
  holdState = result.holdState;
@@ -44989,15 +44927,27 @@ try {
44989
44927
  nativeAddonLoaded = true;
44990
44928
  } catch {
44991
44929
  }
44930
+ var nativeBridge;
44931
+ try {
44932
+ const req = createRequire(import.meta.url);
44933
+ const koffi = req("koffi");
44934
+ nativeBridge = { load: (path) => koffi.load(path) };
44935
+ } catch {
44936
+ }
44992
44937
  function scanMFiles(dirPath, excludeFile) {
44993
44938
  const files = [];
44939
+ let entries;
44994
44940
  try {
44995
- const entries = readdirSync2(dirPath);
44996
- for (const entry of entries) {
44997
- const fullPath = join6(dirPath, entry);
44998
- if (excludeFile && fullPath === excludeFile) {
44999
- continue;
45000
- }
44941
+ entries = readdirSync2(dirPath);
44942
+ } catch {
44943
+ return files;
44944
+ }
44945
+ for (const entry of entries) {
44946
+ const fullPath = join6(dirPath, entry);
44947
+ if (excludeFile && fullPath === excludeFile) {
44948
+ continue;
44949
+ }
44950
+ try {
45001
44951
  const stat = statSync2(fullPath);
45002
44952
  if (stat.isDirectory()) {
45003
44953
  if (entry.startsWith("@") || entry.startsWith("+") || entry === "private") {
@@ -45017,8 +44967,11 @@ function scanMFiles(dirPath, excludeFile) {
45017
44967
  data: new Uint8Array(data)
45018
44968
  });
45019
44969
  }
44970
+ } catch (err) {
44971
+ console.warn(
44972
+ `Warning: could not read ${fullPath}: ${err instanceof Error ? err.message : String(err)}`
44973
+ );
45020
44974
  }
45021
- } catch {
45022
44975
  }
45023
44976
  return files;
45024
44977
  }
@@ -45078,7 +45031,8 @@ async function runTests(dir) {
45078
45031
  { displayResults: true },
45079
45032
  workspaceFiles,
45080
45033
  mainFileName,
45081
- searchPaths
45034
+ searchPaths,
45035
+ nativeBridge
45082
45036
  );
45083
45037
  const outputText = result.output.join("");
45084
45038
  const lines = outputText.split("\n").filter((l) => l.length > 0);
@@ -45377,7 +45331,8 @@ async function executeWithOptions(code, mainFileName, workspaceFiles, opts, sear
45377
45331
  },
45378
45332
  workspaceFiles,
45379
45333
  mainFileName,
45380
- searchPaths
45334
+ searchPaths,
45335
+ nativeBridge
45381
45336
  );
45382
45337
  if (result.plotInstructions.length > 0) {
45383
45338
  streamLine({
@@ -45425,7 +45380,8 @@ async function executeWithOptions(code, mainFileName, workspaceFiles, opts, sear
45425
45380
  },
45426
45381
  workspaceFiles,
45427
45382
  mainFileName,
45428
- searchPaths
45383
+ searchPaths,
45384
+ nativeBridge
45429
45385
  );
45430
45386
  writeProfileIfNeeded(result);
45431
45387
  if (opts.dumpJs) {
@@ -45453,7 +45409,8 @@ async function executeWithOptions(code, mainFileName, workspaceFiles, opts, sear
45453
45409
  },
45454
45410
  workspaceFiles,
45455
45411
  mainFileName,
45456
- searchPaths
45412
+ searchPaths,
45413
+ nativeBridge
45457
45414
  );
45458
45415
  writeProfileIfNeeded(result);
45459
45416
  if (opts.dumpJs) {
@@ -45538,7 +45495,7 @@ async function cmdRepl(args) {
45538
45495
  !opts.plot,
45539
45496
  replPlotOpts
45540
45497
  );
45541
- await runRepl(replFiles, replDrawnow, replSearchPaths);
45498
+ await runRepl(replFiles, replDrawnow, replSearchPaths, nativeBridge);
45542
45499
  }
45543
45500
  function createPlotHandler(disabled, plotOpts) {
45544
45501
  if (disabled) {