numbl 0.4.0 → 0.4.1

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
@@ -786,10 +786,12 @@ var RuntimeClassInstanceArray = class extends Refcounted {
786
786
  kind = "class_instance_array";
787
787
  className;
788
788
  elements;
789
- constructor(className, elements) {
789
+ shape;
790
+ constructor(className, elements, shape) {
790
791
  super();
791
792
  this.className = className;
792
793
  this.elements = elements;
794
+ this.shape = shape ?? [1, elements.length];
793
795
  for (const el of elements) incref(el);
794
796
  }
795
797
  _destroy(rt) {
@@ -3547,10 +3549,11 @@ function sparseElemMul(a, b) {
3547
3549
  }
3548
3550
  function sparseElemMulDense(S, D) {
3549
3551
  const [dRows, dCols] = tensorSize2D(D);
3550
- if (S.m !== dRows || S.n !== dCols)
3552
+ if (!(dRows === S.m || dRows === 1) || !(dCols === S.n || dCols === 1))
3551
3553
  throw new RuntimeError(
3552
3554
  `Matrix dimensions must agree: [${S.m},${S.n}] vs [${dRows},${dCols}]`
3553
3555
  );
3556
+ const denseIdx = (row, col) => (dCols === 1 ? 0 : col) * dRows + (dRows === 1 ? 0 : row);
3554
3557
  const hasImag = isComplexSparse(S) || D.imag !== void 0;
3555
3558
  const irList = [];
3556
3559
  const prList = [];
@@ -3560,7 +3563,7 @@ function sparseElemMulDense(S, D) {
3560
3563
  jc[col] = irList.length;
3561
3564
  for (let k = S.jc[col]; k < S.jc[col + 1]; k++) {
3562
3565
  const row = S.ir[k];
3563
- const idx = col * S.m + row;
3566
+ const idx = denseIdx(row, col);
3564
3567
  const aRe = S.pr[k], aIm = S.pi ? S.pi[k] : 0;
3565
3568
  const bRe = D.data[idx], bIm = D.imag ? D.imag[idx] : 0;
3566
3569
  const re = aRe * bRe - aIm * bIm;
@@ -20924,7 +20927,7 @@ function displayValue(v) {
20924
20927
  case "dictionary":
20925
20928
  return formatDictionary(v);
20926
20929
  case "class_instance_array":
20927
- return ` 1x${v.elements.length} ${v.className} array`;
20930
+ return ` ${v.shape[0]}x${v.shape[1]} ${v.className} array`;
20928
20931
  }
20929
20932
  }
20930
20933
  var formatStructArray = (v) => {
@@ -23337,6 +23340,60 @@ function cellCatAlongDim(values, dimIdx) {
23337
23340
  }
23338
23341
 
23339
23342
  // src/numbl-core/runtime/struct-access.ts
23343
+ function handlePropToRuntime(v) {
23344
+ if (typeof v === "number") return RTV.num(v);
23345
+ if (typeof v === "boolean") return RTV.logical(v);
23346
+ if (typeof v === "string") return RTV.char(v);
23347
+ if (Array.isArray(v)) {
23348
+ const data = allocFloat64Array(v);
23349
+ return RTV.tensor(data, [1, v.length]);
23350
+ }
23351
+ return v;
23352
+ }
23353
+ var HANDLE_DEFAULTS = {
23354
+ quiver3: {
23355
+ LineWidth: 0.5,
23356
+ LineStyle: "-",
23357
+ ShowArrowHead: true,
23358
+ AutoScale: true,
23359
+ AutoScaleFactor: 0.9,
23360
+ Marker: "none",
23361
+ Color: [0, 0.447, 0.741]
23362
+ }
23363
+ };
23364
+ function resolveHandleKey(trace, field) {
23365
+ if (field in trace) return field;
23366
+ const camel = field.charAt(0).toLowerCase() + field.slice(1);
23367
+ if (camel in trace) return camel;
23368
+ if (field.endsWith("Data")) {
23369
+ const base = field.slice(0, -4);
23370
+ const short = base.charAt(0).toLowerCase() + base.slice(1);
23371
+ if (short in trace) return short;
23372
+ }
23373
+ return null;
23374
+ }
23375
+ function runtimeToHandleValue(value, current) {
23376
+ if (typeof current === "boolean") {
23377
+ if (typeof value === "boolean") return value;
23378
+ if (typeof value === "number") return value !== 0;
23379
+ if (isRuntimeString(value) || isRuntimeChar(value)) {
23380
+ const s = (isRuntimeChar(value) ? value.value : value).toLowerCase();
23381
+ return !(s === "off" || s === "false" || s === "0");
23382
+ }
23383
+ return true;
23384
+ }
23385
+ if (typeof current === "string") {
23386
+ return isRuntimeChar(value) ? value.value : isRuntimeString(value) ? value : String(value);
23387
+ }
23388
+ if (typeof current === "number" || current === void 0) {
23389
+ if (typeof value === "number") return value;
23390
+ if (isRuntimeNumber(value)) return value;
23391
+ }
23392
+ if (Array.isArray(current) && isRuntimeTensor(value)) {
23393
+ return Array.from(value.data);
23394
+ }
23395
+ return value;
23396
+ }
23340
23397
  function getRTValueField(base, field) {
23341
23398
  if (isRuntimeStruct(base) || isRuntimeClassInstance(base)) {
23342
23399
  const val = base.fields.get(field);
@@ -23360,6 +23417,15 @@ function getRTValueField(base, field) {
23360
23417
  });
23361
23418
  return horzcat(...values);
23362
23419
  }
23420
+ if (isRuntimeGraphicsHandle(base)) {
23421
+ const key = resolveHandleKey(base._trace, field);
23422
+ if (key !== null) return handlePropToRuntime(base._trace[key]);
23423
+ const dflt = HANDLE_DEFAULTS[base._traceType]?.[field];
23424
+ if (dflt !== void 0) return handlePropToRuntime(dflt);
23425
+ throw new RuntimeError(
23426
+ `No property '${field}' on ${base._traceType} handle`
23427
+ );
23428
+ }
23363
23429
  throw new RuntimeError(`Cannot access field ${field} on ${kstr(base)}`);
23364
23430
  }
23365
23431
  function setRTValueField(base, field, value, rt) {
@@ -23404,6 +23470,12 @@ function setRTValueField(base, field, value, rt) {
23404
23470
  `Cannot assign field '${field}' on a non-scalar struct array without indexing`
23405
23471
  );
23406
23472
  }
23473
+ if (isRuntimeGraphicsHandle(base)) {
23474
+ const key = resolveHandleKey(base._trace, field) ?? field.charAt(0).toLowerCase() + field.slice(1);
23475
+ const current = base._trace[key] ?? HANDLE_DEFAULTS[base._traceType]?.[field];
23476
+ base._trace[key] = runtimeToHandleValue(value, current);
23477
+ return base;
23478
+ }
23407
23479
  if (isRuntimeNumber(base) && base === 0) {
23408
23480
  return RTV.struct(/* @__PURE__ */ new Map([[field, value]]));
23409
23481
  }
@@ -24669,12 +24741,24 @@ function transposeCore(v, conjugate) {
24669
24741
  if (v._isLogical) t._isLogical = true;
24670
24742
  return t;
24671
24743
  }
24744
+ function transposeClassInstanceArray(v) {
24745
+ const [r, c] = v.shape;
24746
+ const out = new Array(v.elements.length);
24747
+ for (let i = 0; i < r; i++) {
24748
+ for (let j = 0; j < c; j++) {
24749
+ out[i * c + j] = v.elements[j * r + i];
24750
+ }
24751
+ }
24752
+ return new RuntimeClassInstanceArray(v.className, out, [c, r]);
24753
+ }
24672
24754
  function mTranspose(v) {
24673
24755
  if (isRuntimeSparseMatrix(v)) return sparseTranspose(v);
24674
24756
  if (isRuntimeComplexNumber(v)) return v;
24675
24757
  if (isRuntimeNumber(v) || isRuntimeLogical(v)) return v;
24676
24758
  if (isRuntimeCell(v)) return transposeCellArray(v);
24677
24759
  if (isRuntimeChar(v)) return v;
24760
+ if (isRuntimeClassInstance(v)) return v;
24761
+ if (isRuntimeClassInstanceArray(v)) return transposeClassInstanceArray(v);
24678
24762
  if (!isRuntimeTensor(v))
24679
24763
  throw new RuntimeError("Cannot transpose non-numeric value");
24680
24764
  return transposeCore(v, false);
@@ -24685,6 +24769,8 @@ function mConjugateTranspose(v) {
24685
24769
  if (isRuntimeNumber(v) || isRuntimeLogical(v)) return v;
24686
24770
  if (isRuntimeCell(v)) return transposeCellArray(v);
24687
24771
  if (isRuntimeChar(v)) return v;
24772
+ if (isRuntimeClassInstance(v)) return v;
24773
+ if (isRuntimeClassInstanceArray(v)) return transposeClassInstanceArray(v);
24688
24774
  if (!isRuntimeTensor(v))
24689
24775
  throw new RuntimeError("Cannot transpose non-numeric value");
24690
24776
  return transposeCore(v, true);
@@ -31042,6 +31128,12 @@ function parseContourArgs(args, filled) {
31042
31128
  let rows;
31043
31129
  let cols;
31044
31130
  let nLevels = 10;
31131
+ let levels;
31132
+ const applyLevelArg = (arg) => {
31133
+ const vals = toNumberArray(arg);
31134
+ if (vals.length <= 1) nLevels = vals.length === 1 ? vals[0] : nLevels;
31135
+ else levels = vals;
31136
+ };
31045
31137
  if (numericCount === 1) {
31046
31138
  const info = getMatrixInfo(args[pos++]);
31047
31139
  rows = info.rows;
@@ -31055,8 +31147,7 @@ function parseContourArgs(args, filled) {
31055
31147
  rows = info.rows;
31056
31148
  cols = info.cols;
31057
31149
  zData = info.data;
31058
- nLevels = typeof args[pos] === "number" ? args[pos] : toNumber(args[pos]);
31059
- pos++;
31150
+ applyLevelArg(args[pos++]);
31060
31151
  const gen = generateMeshgrid(rows, cols);
31061
31152
  xData = gen.x;
31062
31153
  yData = gen.y;
@@ -31077,15 +31168,144 @@ function parseContourArgs(args, filled) {
31077
31168
  rows = zInfo.rows;
31078
31169
  cols = zInfo.cols;
31079
31170
  zData = zInfo.data;
31080
- nLevels = typeof args[pos] === "number" ? args[pos] : toNumber(args[pos]);
31081
- pos++;
31171
+ applyLevelArg(args[pos++]);
31082
31172
  const expanded = expandXY(x, y, rows, cols);
31083
31173
  xData = expanded.x;
31084
31174
  yData = expanded.y;
31085
31175
  } else {
31086
31176
  throw new Error("contour requires at least 1 argument");
31087
31177
  }
31088
- return { x: xData, y: yData, z: zData, rows, cols, nLevels, filled };
31178
+ let lineWidth;
31179
+ let lineStyle;
31180
+ let lineColor;
31181
+ for (; pos + 1 < args.length; pos += 2) {
31182
+ if (!isStringArg(args[pos])) break;
31183
+ const name = getStringValue(args[pos]).toLowerCase();
31184
+ const val = args[pos + 1];
31185
+ switch (name) {
31186
+ case "linewidth":
31187
+ lineWidth = toNumber(val);
31188
+ break;
31189
+ case "linestyle":
31190
+ lineStyle = getStringValue(val);
31191
+ break;
31192
+ case "linecolor":
31193
+ case "color":
31194
+ lineColor = isStringArg(val) ? getStringValue(val) : toNumberArray(val);
31195
+ break;
31196
+ case "levellist":
31197
+ case "levels": {
31198
+ const vals = toNumberArray(val);
31199
+ if (vals.length >= 1) levels = vals;
31200
+ break;
31201
+ }
31202
+ }
31203
+ }
31204
+ if (levels) nLevels = levels.length;
31205
+ return {
31206
+ x: xData,
31207
+ y: yData,
31208
+ z: zData,
31209
+ rows,
31210
+ cols,
31211
+ nLevels,
31212
+ ...levels ? { levels } : {},
31213
+ ...lineWidth !== void 0 ? { lineWidth } : {},
31214
+ ...lineStyle !== void 0 ? { lineStyle } : {},
31215
+ ...lineColor !== void 0 ? { lineColor } : {},
31216
+ filled
31217
+ };
31218
+ }
31219
+ function marchingSquaresCell(z00, z10, z01, z11, x00, y00, x10, y10, x01, y01, x11, y11, level) {
31220
+ const code = (z00 >= level ? 1 : 0) | (z10 >= level ? 2 : 0) | (z01 >= level ? 4 : 0) | (z11 >= level ? 8 : 0);
31221
+ if (code === 0 || code === 15) return [];
31222
+ const lerp = (a, b, za, zb) => a + (level - za) / (zb - za || 1) * (b - a);
31223
+ const bx = lerp(x00, x10, z00, z10), by = lerp(y00, y10, z00, z10);
31224
+ const rx = lerp(x10, x11, z10, z11), ry = lerp(y10, y11, z10, z11);
31225
+ const tx = lerp(x01, x11, z01, z11), ty = lerp(y01, y11, z01, z11);
31226
+ const lx = lerp(x00, x01, z00, z01), ly = lerp(y00, y01, z00, z01);
31227
+ const segs = [];
31228
+ switch (code) {
31229
+ case 1:
31230
+ case 14:
31231
+ segs.push([bx, by, lx, ly]);
31232
+ break;
31233
+ case 2:
31234
+ case 13:
31235
+ segs.push([bx, by, rx, ry]);
31236
+ break;
31237
+ case 3:
31238
+ case 12:
31239
+ segs.push([lx, ly, rx, ry]);
31240
+ break;
31241
+ case 4:
31242
+ case 11:
31243
+ segs.push([lx, ly, tx, ty]);
31244
+ break;
31245
+ case 5:
31246
+ case 10:
31247
+ segs.push([bx, by, tx, ty]);
31248
+ break;
31249
+ case 6:
31250
+ case 9:
31251
+ segs.push([bx, by, lx, ly]);
31252
+ segs.push([tx, ty, rx, ry]);
31253
+ break;
31254
+ case 7:
31255
+ case 8:
31256
+ segs.push([tx, ty, rx, ry]);
31257
+ break;
31258
+ }
31259
+ return segs;
31260
+ }
31261
+ function computeContourMatrix(trace) {
31262
+ const { x, y, z, rows, cols } = trace;
31263
+ const at = (a, i, j) => a[j * rows + i];
31264
+ let zMin = Infinity;
31265
+ let zMax = -Infinity;
31266
+ for (const v of z) {
31267
+ if (Number.isFinite(v)) {
31268
+ if (v < zMin) zMin = v;
31269
+ if (v > zMax) zMax = v;
31270
+ }
31271
+ }
31272
+ let levelList;
31273
+ if (trace.levels && trace.levels.length > 0) {
31274
+ levelList = trace.levels.filter((v) => Number.isFinite(v));
31275
+ } else {
31276
+ const n = Math.max(1, Math.round(trace.nLevels));
31277
+ levelList = [];
31278
+ if (Number.isFinite(zMin) && Number.isFinite(zMax) && zMax > zMin) {
31279
+ const step = (zMax - zMin) / (n + 1);
31280
+ for (let k = 1; k <= n; k++) levelList.push(zMin + k * step);
31281
+ }
31282
+ }
31283
+ const data = [];
31284
+ for (const level of levelList) {
31285
+ for (let j = 0; j < cols - 1; j++) {
31286
+ for (let i = 0; i < rows - 1; i++) {
31287
+ const segs = marchingSquaresCell(
31288
+ at(z, i, j),
31289
+ at(z, i + 1, j),
31290
+ at(z, i, j + 1),
31291
+ at(z, i + 1, j + 1),
31292
+ at(x, i, j),
31293
+ at(y, i, j),
31294
+ at(x, i + 1, j),
31295
+ at(y, i + 1, j),
31296
+ at(x, i, j + 1),
31297
+ at(y, i, j + 1),
31298
+ at(x, i + 1, j + 1),
31299
+ at(y, i + 1, j + 1),
31300
+ level
31301
+ );
31302
+ for (const [x1, y1, x2, y2] of segs) {
31303
+ data.push(level, 2, x1, y1, x2, y2);
31304
+ }
31305
+ }
31306
+ }
31307
+ }
31308
+ return { data, n: data.length / 2, levelList };
31089
31309
  }
31090
31310
  function parseMeshArgs(args) {
31091
31311
  const trace = parseSurfArgs(args);
@@ -32033,6 +32253,213 @@ function computeQuiverAutoScale(x, y, u, v, rows, cols, factor) {
32033
32253
  if (maxMag === 0) return 1;
32034
32254
  return factor * spacing / maxMag;
32035
32255
  }
32256
+ function parseQuiver3Args(args) {
32257
+ if (args.length < 4) throw new Error("quiver3 requires at least 4 arguments");
32258
+ let numericCount = 0;
32259
+ for (let i = 0; i < args.length; i++) {
32260
+ if (isNumericArg(args[i])) numericCount++;
32261
+ else break;
32262
+ }
32263
+ let pos = 0;
32264
+ let xData;
32265
+ let yData;
32266
+ let zData;
32267
+ let uData;
32268
+ let vData;
32269
+ let wData;
32270
+ let rows;
32271
+ let cols;
32272
+ const arity = numericCount >= 6 ? 6 : 4;
32273
+ if (arity === 4) {
32274
+ const zInfo = getMatrixInfo(args[pos++]);
32275
+ rows = zInfo.rows;
32276
+ cols = zInfo.cols;
32277
+ zData = zInfo.data;
32278
+ uData = getMatrixInfo(args[pos++]).data;
32279
+ vData = getMatrixInfo(args[pos++]).data;
32280
+ wData = getMatrixInfo(args[pos++]).data;
32281
+ const n = zData.length;
32282
+ if (rows === 1 || cols === 1) {
32283
+ xData = new Array(n);
32284
+ yData = new Array(n);
32285
+ for (let i = 0; i < n; i++) {
32286
+ xData[i] = i + 1;
32287
+ yData[i] = 1;
32288
+ }
32289
+ } else {
32290
+ const gen = generateMeshgrid(rows, n / rows);
32291
+ xData = gen.x;
32292
+ yData = gen.y;
32293
+ }
32294
+ } else {
32295
+ const X = args[pos++];
32296
+ const Y = args[pos++];
32297
+ const zInfo = getMatrixInfo(args[pos++]);
32298
+ rows = zInfo.rows;
32299
+ cols = zInfo.cols;
32300
+ zData = zInfo.data;
32301
+ uData = getMatrixInfo(args[pos++]).data;
32302
+ vData = getMatrixInfo(args[pos++]).data;
32303
+ wData = getMatrixInfo(args[pos++]).data;
32304
+ const n = uData.length;
32305
+ const xFlat = toNumberArray(X);
32306
+ const yFlat = toNumberArray(Y);
32307
+ if (xFlat.length === n && yFlat.length === n) {
32308
+ xData = xFlat;
32309
+ yData = yFlat;
32310
+ } else {
32311
+ const expanded = expandXY(X, Y, rows, cols);
32312
+ xData = expanded.x;
32313
+ yData = expanded.y;
32314
+ }
32315
+ }
32316
+ let autoScale = true;
32317
+ let autoScaleFactor = 0.9;
32318
+ let reportedASF = 0.9;
32319
+ if (pos < args.length && isNumericArg(args[pos]) && !isStringArg(args[pos])) {
32320
+ const s = toNumber(args[pos]);
32321
+ if (s === 0) {
32322
+ autoScale = false;
32323
+ } else {
32324
+ autoScaleFactor = s * 0.9;
32325
+ reportedASF = s;
32326
+ }
32327
+ pos++;
32328
+ }
32329
+ const trace = {
32330
+ x: xData,
32331
+ y: yData,
32332
+ z: zData,
32333
+ u: uData,
32334
+ v: vData,
32335
+ w: wData,
32336
+ showArrowHead: true
32337
+ };
32338
+ while (pos < args.length && isStringArg(args[pos]) && !isQuiverNameValueKey(args[pos])) {
32339
+ const s = getStringIfString(args[pos]);
32340
+ if (s === void 0) break;
32341
+ if (s === "off") {
32342
+ autoScale = false;
32343
+ pos++;
32344
+ continue;
32345
+ }
32346
+ if (s === "filled") {
32347
+ trace.markerFilled = true;
32348
+ pos++;
32349
+ continue;
32350
+ }
32351
+ const spec = parseLineSpec(s);
32352
+ if (spec) {
32353
+ if (spec.color) trace.color = COLOR_SHORT[spec.color];
32354
+ if (spec.lineStyle) trace.lineStyle = spec.lineStyle;
32355
+ if (spec.marker) {
32356
+ trace.marker = spec.marker;
32357
+ trace.showArrowHead = false;
32358
+ }
32359
+ pos++;
32360
+ continue;
32361
+ }
32362
+ const c = resolveColor(s);
32363
+ if (c) {
32364
+ trace.color = c;
32365
+ pos++;
32366
+ continue;
32367
+ }
32368
+ break;
32369
+ }
32370
+ while (pos < args.length) {
32371
+ const key = isQuiverNameValueKey(args[pos]);
32372
+ if (!key) break;
32373
+ pos++;
32374
+ if (pos >= args.length) break;
32375
+ const value = args[pos++];
32376
+ switch (key) {
32377
+ case "color": {
32378
+ const c = resolveColor(value);
32379
+ if (c) trace.color = c;
32380
+ break;
32381
+ }
32382
+ case "linestyle":
32383
+ trace.lineStyle = getStringValue(value);
32384
+ break;
32385
+ case "linewidth":
32386
+ trace.lineWidth = typeof value === "number" ? value : toNumber(value);
32387
+ break;
32388
+ case "marker": {
32389
+ const s = getStringValue(value);
32390
+ trace.marker = s === "none" ? void 0 : s;
32391
+ break;
32392
+ }
32393
+ case "showarrowhead": {
32394
+ const s = getStringValue(value).toLowerCase();
32395
+ trace.showArrowHead = !(s === "off" || s === "false" || s === "0");
32396
+ break;
32397
+ }
32398
+ case "autoscale": {
32399
+ const s = getStringValue(value).toLowerCase();
32400
+ autoScale = !(s === "off" || s === "false" || s === "0");
32401
+ break;
32402
+ }
32403
+ case "autoscalefactor": {
32404
+ const n = typeof value === "number" ? value : toNumber(value);
32405
+ autoScaleFactor = n * 0.9;
32406
+ reportedASF = n;
32407
+ break;
32408
+ }
32409
+ }
32410
+ }
32411
+ trace.autoScale = autoScale;
32412
+ trace.autoScaleFactor = reportedASF;
32413
+ if (autoScale) {
32414
+ const factor = computeQuiver3AutoScale(
32415
+ xData,
32416
+ yData,
32417
+ zData,
32418
+ uData,
32419
+ vData,
32420
+ wData,
32421
+ autoScaleFactor
32422
+ );
32423
+ if (factor !== 1) {
32424
+ trace.u = uData.map((x) => x * factor);
32425
+ trace.v = vData.map((x) => x * factor);
32426
+ trace.w = wData.map((x) => x * factor);
32427
+ }
32428
+ }
32429
+ return trace;
32430
+ }
32431
+ function computeQuiver3AutoScale(x, y, z, u, v, w, factor) {
32432
+ const n = u.length;
32433
+ if (n === 0) return 1;
32434
+ const range2 = (a) => {
32435
+ let lo = Infinity;
32436
+ let hi = -Infinity;
32437
+ for (const t of a) {
32438
+ if (isFinite(t)) {
32439
+ if (t < lo) lo = t;
32440
+ if (t > hi) hi = t;
32441
+ }
32442
+ }
32443
+ return hi > lo ? hi - lo : 0;
32444
+ };
32445
+ const xr = range2(x);
32446
+ const yr = range2(y);
32447
+ const zr = range2(z);
32448
+ const dims = [xr, yr, zr].filter((d) => d > 0);
32449
+ let spacing;
32450
+ if (dims.length === 3) spacing = Math.cbrt(xr * yr * zr / n);
32451
+ else if (dims.length === 2) spacing = Math.sqrt(dims[0] * dims[1] / n);
32452
+ else if (dims.length === 1) spacing = dims[0] / Math.max(1, n - 1);
32453
+ else spacing = 1;
32454
+ spacing = spacing || 1;
32455
+ let maxMag = 0;
32456
+ for (let i = 0; i < n; i++) {
32457
+ const m = Math.sqrt(u[i] * u[i] + v[i] * v[i] + w[i] * w[i]);
32458
+ if (isFinite(m) && m > maxMag) maxMag = m;
32459
+ }
32460
+ if (maxMag === 0) return 1;
32461
+ return factor * spacing / maxMag;
32462
+ }
32036
32463
 
32037
32464
  // src/numbl-core/runtime/syncChannel.ts
32038
32465
  var syncSleepWarned = false;
@@ -32124,6 +32551,9 @@ function plotInstr(plotInstructions, instr) {
32124
32551
  case "clf":
32125
32552
  plotInstructions.push({ type: instr.type });
32126
32553
  break;
32554
+ case "cla":
32555
+ plotInstructions.push({ type: "cla", reset: instr.reset });
32556
+ break;
32127
32557
  case "set_subplot":
32128
32558
  plotInstructions.push({
32129
32559
  type: "set_subplot",
@@ -32208,6 +32638,10 @@ function surfCall(plotInstructions, args) {
32208
32638
  const trace = parseSurfArgs(args);
32209
32639
  plotInstructions.push({ type: "surf", trace });
32210
32640
  }
32641
+ function surfaceCall(plotInstructions, args) {
32642
+ const trace = parseSurfArgs(args);
32643
+ plotInstructions.push({ type: "surface", trace });
32644
+ }
32211
32645
  function imagescCall(plotInstructions, args) {
32212
32646
  const trace = parseImagescArgs(args);
32213
32647
  plotInstructions.push({ type: "imagesc", trace });
@@ -32460,6 +32894,10 @@ function quiverCall(plotInstructions, args) {
32460
32894
  plotInstructions.push({ type: "quiver", traces });
32461
32895
  }
32462
32896
  }
32897
+ function quiver3Call(plotInstructions, args) {
32898
+ const trace = parseQuiver3Args(args);
32899
+ plotInstructions.push({ type: "quiver3", trace });
32900
+ }
32463
32901
  function legendCall(plotInstructions, args) {
32464
32902
  const labels = [];
32465
32903
  for (let i = 0; i < args.length; i++) {
@@ -32708,6 +33146,9 @@ function dispatchPlotBuiltin(name, args, instructions, state) {
32708
33146
  case "surf":
32709
33147
  surfCall(instructions, args);
32710
33148
  return true;
33149
+ case "surface":
33150
+ surfaceCall(instructions, args);
33151
+ return true;
32711
33152
  case "scatter":
32712
33153
  scatterCall(instructions, args);
32713
33154
  return true;
@@ -32787,6 +33228,9 @@ function dispatchPlotBuiltin(name, args, instructions, state) {
32787
33228
  case "quiver":
32788
33229
  quiverCall(instructions, args);
32789
33230
  return true;
33231
+ case "quiver3":
33232
+ quiver3Call(instructions, args);
33233
+ return true;
32790
33234
  case "view":
32791
33235
  viewCall(instructions, args);
32792
33236
  return true;
@@ -32852,6 +33296,18 @@ function dispatchPlotBuiltin(name, args, instructions, state) {
32852
33296
  case "clf":
32853
33297
  plotInstr(instructions, { type: "clf" });
32854
33298
  return true;
33299
+ case "cla": {
33300
+ let reset = false;
33301
+ for (const a of args) {
33302
+ try {
33303
+ if (toString(a).toLowerCase().replace(/^["']|["']$/g, "") === "reset")
33304
+ reset = true;
33305
+ } catch {
33306
+ }
33307
+ }
33308
+ plotInstr(instructions, { type: "cla", reset });
33309
+ return true;
33310
+ }
32855
33311
  case "shading": {
32856
33312
  if (args.length > 0) {
32857
33313
  plotInstr(instructions, { type: "set_shading", shading: args[0] });
@@ -33029,6 +33485,7 @@ var PLOT_DISPATCH_NAMES = [
33029
33485
  "plot",
33030
33486
  "plot3",
33031
33487
  "surf",
33488
+ "surface",
33032
33489
  "scatter",
33033
33490
  "imagesc",
33034
33491
  "pcolor",
@@ -33056,6 +33513,7 @@ var PLOT_DISPATCH_NAMES = [
33056
33513
  "donutchart",
33057
33514
  "heatmap",
33058
33515
  "quiver",
33516
+ "quiver3",
33059
33517
  "view",
33060
33518
  "legend",
33061
33519
  "figure",
@@ -33071,6 +33529,7 @@ var PLOT_DISPATCH_NAMES = [
33071
33529
  "grid",
33072
33530
  "close",
33073
33531
  "clf",
33532
+ "cla",
33074
33533
  "shading",
33075
33534
  "colorbar",
33076
33535
  "colormap",
@@ -33128,7 +33587,8 @@ var PLOT_DISPATCH_NAMES_JIT = /* @__PURE__ */ new Set([
33128
33587
  "piechart",
33129
33588
  "donutchart",
33130
33589
  "heatmap",
33131
- "quiver"
33590
+ "quiver",
33591
+ "quiver3"
33132
33592
  ]);
33133
33593
  function dispatchPlotCall(rt, name, args) {
33134
33594
  if (PLOT_DISPATCH_NAMES_JIT.has(name)) {
@@ -34497,45 +34957,70 @@ function classInstanceParenIndex(rt, mv, base, indices, nargout, skipSubsref) {
34497
34957
  }
34498
34958
  throw new RuntimeError(`Index exceeds class instance dimensions`);
34499
34959
  }
34960
+ function resolveObjSubscript(raw, dimSize) {
34961
+ if (raw === COLON_SENTINEL) {
34962
+ return Array.from({ length: dimSize }, (_, i) => i);
34963
+ }
34964
+ if (typeof raw === "number") return [Math.round(raw) - 1];
34965
+ const rv = ensureRuntimeValue(raw);
34966
+ if (isRuntimeNumber(rv)) return [Math.round(toNumber(rv)) - 1];
34967
+ if (isRuntimeLogical(rv)) return rv ? [0] : [];
34968
+ if (isRuntimeTensor(rv)) {
34969
+ if (rv._isLogical) {
34970
+ const out = [];
34971
+ for (let k = 0; k < rv.data.length; k++) if (rv.data[k]) out.push(k);
34972
+ return out;
34973
+ }
34974
+ return Array.from(rv.data, (x) => Math.round(x) - 1);
34975
+ }
34976
+ throw new RuntimeError("Invalid index type for class instance array");
34977
+ }
34978
+ function makeObjResult(className, elements, shape) {
34979
+ if (elements.length === 1) return elements[0];
34980
+ return {
34981
+ kind: "class_instance_array",
34982
+ className,
34983
+ elements,
34984
+ shape
34985
+ };
34986
+ }
34500
34987
  function classInstanceArrayParenIndex(mv, indices) {
34988
+ const [rows, cols] = mv.shape;
34989
+ const total = mv.elements.length;
34990
+ if (indices.length === 2) {
34991
+ const ri = resolveObjSubscript(indices[0], rows);
34992
+ const ci = resolveObjSubscript(indices[1], cols);
34993
+ const selected2 = [];
34994
+ for (const j of ci) {
34995
+ if (j < 0 || j >= cols)
34996
+ throw new RuntimeError("Index exceeds array bounds");
34997
+ for (const i of ri) {
34998
+ if (i < 0 || i >= rows)
34999
+ throw new RuntimeError("Index exceeds array bounds");
35000
+ selected2.push(mv.elements[j * rows + i]);
35001
+ }
35002
+ }
35003
+ return makeObjResult(mv.className, selected2, [ri.length, ci.length]);
35004
+ }
34501
35005
  if (indices.length !== 1) {
34502
35006
  throw new RuntimeError(
34503
- "Class instance arrays only support single-subscript indexing"
35007
+ "Class instance arrays support one- or two-subscript indexing"
34504
35008
  );
34505
35009
  }
34506
35010
  const idx = indices[0];
34507
35011
  if (idx === COLON_SENTINEL) {
34508
- return mv;
35012
+ return makeObjResult(mv.className, mv.elements.slice(), [total, 1]);
34509
35013
  }
34510
- if (typeof idx === "number") {
34511
- const i = Math.round(idx) - 1;
34512
- if (i < 0 || i >= mv.elements.length)
35014
+ const linear = resolveObjSubscript(idx, total);
35015
+ const selected = [];
35016
+ for (const i of linear) {
35017
+ if (i < 0 || i >= total)
34513
35018
  throw new RuntimeError("Index exceeds array bounds");
34514
- return mv.elements[i];
34515
- }
34516
- const rv = ensureRuntimeValue(idx);
34517
- if (isRuntimeLogical(rv)) {
34518
- const i = rv ? 0 : -1;
34519
- if (i < 0 || i >= mv.elements.length)
34520
- throw new RuntimeError("Index exceeds array bounds");
34521
- return mv.elements[i];
34522
- }
34523
- if (isRuntimeTensor(rv)) {
34524
- const selected = [];
34525
- for (let k = 0; k < rv.data.length; k++) {
34526
- const i = Math.round(rv.data[k]) - 1;
34527
- if (i < 0 || i >= mv.elements.length)
34528
- throw new RuntimeError("Index exceeds array bounds");
34529
- selected.push(mv.elements[i]);
34530
- }
34531
- if (selected.length === 1) return selected[0];
34532
- return {
34533
- kind: "class_instance_array",
34534
- className: mv.className,
34535
- elements: selected
34536
- };
35019
+ selected.push(mv.elements[i]);
34537
35020
  }
34538
- throw new RuntimeError("Invalid index type for class instance array");
35021
+ const isColumn = cols === 1 && rows !== 1;
35022
+ const shape = isColumn ? [selected.length, 1] : [1, selected.length];
35023
+ return makeObjResult(mv.className, selected, shape);
34539
35024
  }
34540
35025
  function resolveIndicesForClassInstance(rt, mv, base, indices) {
34541
35026
  const numIndices = indices.length;
@@ -35479,6 +35964,13 @@ for (const name of ["groot", "gcf", "gca", "shg", "newplot"]) {
35479
35964
  })
35480
35965
  });
35481
35966
  }
35967
+ registerIBuiltin({
35968
+ name: "camlight",
35969
+ resolve: () => ({
35970
+ outputTypes: [{ kind: "unknown" }],
35971
+ apply: (_args, nargout) => nargout >= 1 ? RTV.dummyHandle() : void 0
35972
+ })
35973
+ });
35482
35974
  registerIBuiltin({
35483
35975
  name: "get",
35484
35976
  resolve: () => ({
@@ -35633,7 +36125,6 @@ registerIBuiltin({
35633
36125
  })
35634
36126
  });
35635
36127
  for (const cm of [
35636
- "parula",
35637
36128
  "jet",
35638
36129
  "hsv",
35639
36130
  "hot",
@@ -35655,6 +36146,44 @@ for (const cm of [
35655
36146
  })
35656
36147
  });
35657
36148
  }
36149
+ var PARULA_ANCHORS = [
36150
+ [0.2422, 0.1504, 0.6603],
36151
+ [0.278, 0.3556, 0.9777],
36152
+ [0.1085, 0.5267, 0.8943],
36153
+ [0.0469, 0.6353, 0.7861],
36154
+ [0.2161, 0.7269, 0.6499],
36155
+ [0.5044, 0.7993, 0.4519],
36156
+ [0.8328, 0.8056, 0.2008],
36157
+ [0.9871, 0.8092, 0.1432],
36158
+ [0.9763, 0.9831, 0.0538]
36159
+ ];
36160
+ function parulaColormap(m) {
36161
+ const data = allocFloat64Array(m * 3);
36162
+ const last = PARULA_ANCHORS.length - 1;
36163
+ for (let i = 0; i < m; i++) {
36164
+ const t = m <= 1 ? 0 : i / (m - 1) * last;
36165
+ const k = Math.min(last - 1, Math.floor(t));
36166
+ const f = t - k;
36167
+ const a = PARULA_ANCHORS[k];
36168
+ const b = PARULA_ANCHORS[Math.min(last, k + 1)];
36169
+ for (let c = 0; c < 3; c++) {
36170
+ data[c * m + i] = a[c] + f * (b[c] - a[c]);
36171
+ }
36172
+ }
36173
+ return RTV.tensor(data, [m, 3]);
36174
+ }
36175
+ registerIBuiltin({
36176
+ name: "parula",
36177
+ resolve: () => ({
36178
+ outputTypes: [{ kind: "unknown" }],
36179
+ apply: (args) => {
36180
+ if (args.length >= 1 && (isRuntimeNumber(args[0]) || isRuntimeTensor(args[0]))) {
36181
+ return parulaColormap(Math.max(0, Math.round(toNumber(args[0]))));
36182
+ }
36183
+ return RTV.char("parula");
36184
+ }
36185
+ })
36186
+ });
35658
36187
  var appdataStore = /* @__PURE__ */ new Map();
35659
36188
  function resetAppdataStore() {
35660
36189
  const rt = getCurrentRuntime();
@@ -36512,6 +37041,7 @@ var SPECIAL_BUILTIN_NAMES = [
36512
37041
  "plot",
36513
37042
  "plot3",
36514
37043
  "surf",
37044
+ "surface",
36515
37045
  "scatter",
36516
37046
  "imagesc",
36517
37047
  "pcolor",
@@ -36541,6 +37071,7 @@ var SPECIAL_BUILTIN_NAMES = [
36541
37071
  "donutchart",
36542
37072
  "heatmap",
36543
37073
  "quiver",
37074
+ "quiver3",
36544
37075
  "streamline",
36545
37076
  "stream2",
36546
37077
  "ishold",
@@ -36558,6 +37089,7 @@ var SPECIAL_BUILTIN_NAMES = [
36558
37089
  "sgtitle",
36559
37090
  "shading",
36560
37091
  "clf",
37092
+ "cla",
36561
37093
  "colormap",
36562
37094
  "view",
36563
37095
  "zlabel",
@@ -37450,13 +37982,21 @@ function registerSpecialBuiltins(rt) {
37450
37982
  }
37451
37983
  });
37452
37984
  registerSpecialVoid("delete", (args) => {
37453
- const io = requireFileIO();
37454
- if (!io.deleteFile)
37455
- throw new RuntimeError("delete is not available in this environment");
37456
37985
  const margs = args.map((a) => ensureRuntimeValue(a));
37457
37986
  if (margs.length < 1)
37458
37987
  throw new RuntimeError("delete requires at least 1 argument");
37459
37988
  for (const arg of margs) {
37989
+ if (isRuntimeGraphicsHandle(arg)) {
37990
+ const instr = arg._trace.__instruction;
37991
+ if (instr) {
37992
+ const idx = rt.plotInstructions.indexOf(instr);
37993
+ if (idx >= 0) rt.plotInstructions.splice(idx, 1);
37994
+ }
37995
+ continue;
37996
+ }
37997
+ const io = requireFileIO();
37998
+ if (!io.deleteFile)
37999
+ throw new RuntimeError("delete is not available in this environment");
37460
38000
  io.deleteFile(toString(arg));
37461
38001
  }
37462
38002
  });
@@ -37925,7 +38465,7 @@ function registerSpecialBuiltins(rt) {
37925
38465
  return nargout >= 1 ? RTV.num(1) : void 0;
37926
38466
  });
37927
38467
  }
37928
- const PLOT_VOID = ["hold", "grid", "shading"];
38468
+ const PLOT_VOID = ["hold", "grid", "shading", "cla"];
37929
38469
  for (const name of PLOT_VOID) {
37930
38470
  registerSpecialVoid(name, (args) => {
37931
38471
  dispatchPlotBuiltin(
@@ -39088,6 +39628,43 @@ var Runtime = class _Runtime {
39088
39628
  return RTV.dummyHandle();
39089
39629
  }
39090
39630
  };
39631
+ const contourOverride = (filled) => (_nargout, args) => {
39632
+ const margs = args.map((a) => ensureRuntimeValue(a));
39633
+ contourCall(this.plotInstructions, margs, filled);
39634
+ if (_nargout < 1) return void 0;
39635
+ const last = this.plotInstructions[this.plotInstructions.length - 1];
39636
+ if (!last || last.type !== "contour") return RTV.dummyHandle();
39637
+ const trace = last.trace;
39638
+ const cm = computeContourMatrix(trace);
39639
+ const C = RTV.tensor(allocFloat64Array(cm.data), [2, cm.n]);
39640
+ if (_nargout < 2) return C;
39641
+ const H2 = RTV.graphicsHandle(
39642
+ {
39643
+ LineWidth: trace.lineWidth ?? 0.5,
39644
+ LineStyle: trace.lineStyle ?? "-",
39645
+ LineColor: trace.lineColor ?? "flat",
39646
+ LevelList: cm.levelList,
39647
+ __instruction: last
39648
+ },
39649
+ "contour"
39650
+ );
39651
+ return [C, H2];
39652
+ };
39653
+ this.builtins["contour"] = contourOverride(false);
39654
+ this.builtins["contourf"] = contourOverride(true);
39655
+ this.builtins["quiver3"] = (_nargout, args) => {
39656
+ const margs = args.map((a) => ensureRuntimeValue(a));
39657
+ quiver3Call(this.plotInstructions, margs);
39658
+ if (_nargout < 1) return void 0;
39659
+ const last = this.plotInstructions[this.plotInstructions.length - 1];
39660
+ if (last && last.type === "quiver3") {
39661
+ return RTV.graphicsHandle(
39662
+ last.trace,
39663
+ "quiver3"
39664
+ );
39665
+ }
39666
+ return RTV.dummyHandle();
39667
+ };
39091
39668
  this.builtins["fplot"] = (_nargout, args) => {
39092
39669
  fplotCall(this, this.plotInstructions, args.map(ensureRuntimeValue));
39093
39670
  };
@@ -39635,14 +40212,15 @@ var Runtime = class _Runtime {
39635
40212
  transpose(v) {
39636
40213
  if (typeof v !== "number") {
39637
40214
  const mv = ensureRuntimeValue(v);
39638
- if (isRuntimeClassInstance(mv)) return this.dispatch("transpose", 1, [v]);
40215
+ if (isRuntimeClassInstance(mv) || isRuntimeClassInstanceArray(mv))
40216
+ return this.dispatch("transpose", 1, [v]);
39639
40217
  }
39640
40218
  return transpose(v);
39641
40219
  }
39642
40220
  ctranspose(v) {
39643
40221
  if (typeof v !== "number") {
39644
40222
  const mv = ensureRuntimeValue(v);
39645
- if (isRuntimeClassInstance(mv))
40223
+ if (isRuntimeClassInstance(mv) || isRuntimeClassInstanceArray(mv))
39646
40224
  return this.dispatch("ctranspose", 1, [v]);
39647
40225
  }
39648
40226
  return ctranspose(v);
@@ -39726,7 +40304,9 @@ var Runtime = class _Runtime {
39726
40304
  const mvals = flat.map(
39727
40305
  (e) => typeof e === "number" ? null : ensureRuntimeValue(e)
39728
40306
  );
39729
- if (mvals.some((v) => v && isRuntimeClassInstance(v))) {
40307
+ if (mvals.some(
40308
+ (v) => v && (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v))
40309
+ )) {
39730
40310
  if (this._classHasMethod(mvals, "horzcat")) {
39731
40311
  return this.dispatch("horzcat", 1, flat);
39732
40312
  }
@@ -39739,7 +40319,9 @@ var Runtime = class _Runtime {
39739
40319
  const mvals = rows.map(
39740
40320
  (r) => typeof r === "number" ? null : ensureRuntimeValue(r)
39741
40321
  );
39742
- if (mvals.some((v) => v && isRuntimeClassInstance(v))) {
40322
+ if (mvals.some(
40323
+ (v) => v && (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v))
40324
+ )) {
39743
40325
  if (this._classHasMethod(mvals, "vertcat")) {
39744
40326
  return this.dispatch("vertcat", 1, rows);
39745
40327
  }
@@ -39751,7 +40333,7 @@ var Runtime = class _Runtime {
39751
40333
  _classHasMethod(mvals, methodName) {
39752
40334
  if (!this.resolveClassMethod) return false;
39753
40335
  for (const v of mvals) {
39754
- if (v && isRuntimeClassInstance(v)) {
40336
+ if (v && (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v))) {
39755
40337
  if (this.resolveClassMethod(v.className, methodName) !== null) {
39756
40338
  return true;
39757
40339
  }
@@ -40062,31 +40644,66 @@ function buildStackField(e) {
40062
40644
  }
40063
40645
  return RTV.structArray(fieldNames, elements);
40064
40646
  }
40065
- function collectClassInstances(items) {
40066
- const out = [];
40067
- for (const item of items) {
40068
- const rv = ensureRuntimeValue(item);
40069
- if (isRuntimeClassInstance(rv)) {
40070
- out.push(rv);
40071
- } else if (isRuntimeClassInstanceArray(rv)) {
40072
- out.push(...rv.elements);
40073
- } else {
40647
+ function asObjArrayParts(item) {
40648
+ const rv = ensureRuntimeValue(item);
40649
+ if (isRuntimeClassInstance(rv))
40650
+ return { rows: 1, cols: 1, elements: [rv], className: rv.className };
40651
+ if (isRuntimeClassInstanceArray(rv))
40652
+ return {
40653
+ rows: rv.shape[0],
40654
+ cols: rv.shape[1],
40655
+ elements: rv.elements,
40656
+ className: rv.className
40657
+ };
40658
+ if (isRuntimeTensor(rv) && rv.data.length === 0) return null;
40659
+ throw new RuntimeError(`Cannot concatenate ${kstr(rv)} with class instances`);
40660
+ }
40661
+ function objColumn(p2, j) {
40662
+ return p2.elements.slice(j * p2.rows, j * p2.rows + p2.rows);
40663
+ }
40664
+ function defaultClassInstanceHorzcat(items) {
40665
+ const parts = items.map(asObjArrayParts).filter((p2) => p2 !== null && p2.elements.length > 0);
40666
+ if (parts.length === 0)
40667
+ throw new RuntimeError("Cannot concatenate empty class instances");
40668
+ const rows = parts[0].rows;
40669
+ let cols = 0;
40670
+ const elements = [];
40671
+ for (const p2 of parts) {
40672
+ if (p2.rows !== rows)
40074
40673
  throw new RuntimeError(
40075
- `Cannot concatenate ${kstr(rv)} with class instances`
40674
+ "Dimensions of arrays being concatenated are not consistent"
40076
40675
  );
40077
- }
40676
+ elements.push(...p2.elements);
40677
+ cols += p2.cols;
40078
40678
  }
40079
- return out;
40080
- }
40081
- function defaultClassInstanceHorzcat(items) {
40082
- const elements = collectClassInstances(items);
40083
40679
  if (elements.length === 1) return elements[0];
40084
- return new RuntimeClassInstanceArray(elements[0].className, elements);
40680
+ return new RuntimeClassInstanceArray(parts[0].className, elements, [
40681
+ rows,
40682
+ cols
40683
+ ]);
40085
40684
  }
40086
40685
  function defaultClassInstanceVertcat(rows) {
40087
- const elements = collectClassInstances(rows);
40686
+ const parts = rows.map(asObjArrayParts).filter((p2) => p2 !== null && p2.elements.length > 0);
40687
+ if (parts.length === 0)
40688
+ throw new RuntimeError("Cannot concatenate empty class instances");
40689
+ const cols = parts[0].cols;
40690
+ let totalRows = 0;
40691
+ for (const p2 of parts) {
40692
+ if (p2.cols !== cols)
40693
+ throw new RuntimeError(
40694
+ "Dimensions of arrays being concatenated are not consistent"
40695
+ );
40696
+ totalRows += p2.rows;
40697
+ }
40698
+ const elements = [];
40699
+ for (let j = 0; j < cols; j++) {
40700
+ for (const p2 of parts) elements.push(...objColumn(p2, j));
40701
+ }
40088
40702
  if (elements.length === 1) return elements[0];
40089
- return new RuntimeClassInstanceArray(elements[0].className, elements);
40703
+ return new RuntimeClassInstanceArray(parts[0].className, elements, [
40704
+ totalRows,
40705
+ cols
40706
+ ]);
40090
40707
  }
40091
40708
 
40092
40709
  // src/numbl-core/helpers/reduction-helpers.ts
@@ -41598,7 +42215,7 @@ function getShape(v) {
41598
42215
  if (isRuntimeSparseMatrix(v)) return [v.m, v.n];
41599
42216
  if (isRuntimeCell(v)) return v.shape;
41600
42217
  if (isRuntimeStructArray(v)) return [1, v.elements.length];
41601
- if (isRuntimeClassInstanceArray(v)) return [1, v.elements.length];
42218
+ if (isRuntimeClassInstanceArray(v)) return [...v.shape];
41602
42219
  return [1, 1];
41603
42220
  }
41604
42221
  defineBuiltin({
@@ -41776,7 +42393,8 @@ defineBuiltin({
41776
42393
  }
41777
42394
  if (isRuntimeString(v)) return 1;
41778
42395
  if (isRuntimeStructArray(v)) return v.elements.length;
41779
- if (isRuntimeClassInstanceArray(v)) return v.elements.length;
42396
+ if (isRuntimeClassInstanceArray(v))
42397
+ return v.elements.length === 0 ? 0 : Math.max(...v.shape);
41780
42398
  return 1;
41781
42399
  }
41782
42400
  }
@@ -41889,8 +42507,15 @@ defineBuiltin({
41889
42507
  if (isRuntimeClassInstanceArray(v)) return mkChar(v.className);
41890
42508
  if (isRuntimeFunction(v)) return mkChar("function_handle");
41891
42509
  if (isRuntimeDummyHandle(v)) return mkChar("dummy_handle");
41892
- if (isRuntimeGraphicsHandle(v))
41893
- return mkChar("matlab.graphics.primitive.Surface");
42510
+ if (isRuntimeGraphicsHandle(v)) {
42511
+ const handleClass = {
42512
+ contour: "matlab.graphics.chart.primitive.Contour",
42513
+ quiver3: "matlab.graphics.chart.primitive.Quiver"
42514
+ };
42515
+ return mkChar(
42516
+ handleClass[v._traceType] ?? "matlab.graphics.primitive.Surface"
42517
+ );
42518
+ }
41894
42519
  return mkChar("unknown");
41895
42520
  }
41896
42521
  }
@@ -46931,6 +47556,7 @@ defineBuiltin({
46931
47556
  const blocks = args.map((a) => {
46932
47557
  if (isRuntimeNumber(a))
46933
47558
  return RTV.tensor(allocFloat64Array([a]), [1, 1]);
47559
+ if (isRuntimeSparseMatrix(a)) return sparseToDense(a);
46934
47560
  if (!isRuntimeTensor(a))
46935
47561
  throw new RuntimeError("blkdiag: arguments must be numeric");
46936
47562
  return a;
@@ -48299,6 +48925,21 @@ defineBuiltin({
48299
48925
  const shape = reps.length >= 2 ? reps : [reps[0], reps[0]];
48300
48926
  return RTV.tensor(data, shape, imag2);
48301
48927
  }
48928
+ if (isRuntimeCell(v)) {
48929
+ const srcShape2 = v.shape.length >= 2 ? v.shape : [1, v.shape[0] ?? v.data.length];
48930
+ const [sm, sn] = [srcShape2[0], srcShape2[1]];
48931
+ const r0 = reps[0] ?? 1;
48932
+ const r1 = reps.length >= 2 ? reps[1] : reps[0] ?? 1;
48933
+ const om = sm * r0;
48934
+ const on = sn * r1;
48935
+ const out2 = new Array(om * on);
48936
+ for (let J = 0; J < on; J++) {
48937
+ for (let I = 0; I < om; I++) {
48938
+ out2[I + J * om] = v.data[I % sm + J % sn * sm];
48939
+ }
48940
+ }
48941
+ return RTV.cell(out2, [om, on]);
48942
+ }
48302
48943
  if (!isRuntimeTensor(v))
48303
48944
  throw new RuntimeError("repmat: first argument must be numeric");
48304
48945
  if (reps.every((r) => r === 1)) {
@@ -55076,6 +55717,10 @@ var H = {
55076
55717
  signatures: ["nexttile", "nexttile(IDX)"],
55077
55718
  description: "Advance to the next tile in the current tiled layout, or move to tile IDX. Auto-creates a flow layout if none exists."
55078
55719
  },
55720
+ surface: {
55721
+ signatures: ["surface(X,Y,Z)", "surface(Z)", "surface(X,Y,Z,C)"],
55722
+ description: "Primitive surface plot. Like surf, but adds to the current axes without clearing existing objects (does not respect hold)."
55723
+ },
55079
55724
  title: {
55080
55725
  signatures: ["title(TXT)"],
55081
55726
  description: "Set title of current axes."
@@ -55112,6 +55757,10 @@ var H = {
55112
55757
  signatures: ["clf"],
55113
55758
  description: "Clear current figure."
55114
55759
  },
55760
+ cla: {
55761
+ signatures: ["cla", "cla(ax)", "cla reset", "cla(ax,'reset')"],
55762
+ description: "Clear current axes. With 'reset', also reset axes properties to defaults."
55763
+ },
55115
55764
  sgtitle: {
55116
55765
  signatures: ["sgtitle(TXT)"],
55117
55766
  description: "Set super-title for subplot grid."
@@ -55164,6 +55813,10 @@ var H = {
55164
55813
  signatures: ["shg"],
55165
55814
  description: "Show current figure."
55166
55815
  },
55816
+ camlight: {
55817
+ signatures: ["camlight", "camlight(position)", "cl = camlight(___)"],
55818
+ description: "Create a light in camera coordinates. Stub in numbl (no lighting model): accepts all arguments and returns a placeholder handle."
55819
+ },
55167
55820
  newplot: {
55168
55821
  signatures: ["newplot"],
55169
55822
  description: "Prepare axes for new plot."
@@ -55689,7 +56342,7 @@ function getSourceLine(getSource, file, line) {
55689
56342
  }
55690
56343
 
55691
56344
  // src/numbl-core/version.ts
55692
- var NUMBL_VERSION = "0.4.0";
56345
+ var NUMBL_VERSION = "0.4.1";
55693
56346
 
55694
56347
  // src/cli-repl.ts
55695
56348
  import { createInterface } from "readline";
@@ -59392,16 +60045,27 @@ function callUserFunction(fn, args, nargout, narginOverride) {
59392
60045
  const fnEnv = new Environment();
59393
60046
  fnEnv.rt = this.rt;
59394
60047
  fnEnv.persistentFuncId = `${this.currentFile}:${fn.name}`;
59395
- const processedArgs = this.processArgumentsBlocks(fn, sharedArgs);
59396
60048
  const hasVarargin = fn.params.length > 0 && fn.params[fn.params.length - 1] === "varargin";
59397
60049
  const regularParams = hasVarargin ? fn.params.slice(0, -1) : fn.params;
59398
- for (let i = 0; i < regularParams.length; i++) {
59399
- if (i < processedArgs.length) {
59400
- fnEnv.set(regularParams[i], ensureRuntimeValue(processedArgs[i]));
60050
+ let numPositional = regularParams.length;
60051
+ const inputBlocks = (fn.argumentsBlocks ?? []).filter(
60052
+ (b) => b.kind !== "Output"
60053
+ );
60054
+ for (const block of inputBlocks) {
60055
+ for (const e of block.entries) {
60056
+ const dot2 = e.name.indexOf(".");
60057
+ if (dot2 < 0) continue;
60058
+ const idx = fn.params.indexOf(e.name.slice(0, dot2));
60059
+ if (idx >= 0 && idx < numPositional) numPositional = idx;
60060
+ }
60061
+ }
60062
+ for (let i = 0; i < numPositional && i < regularParams.length; i++) {
60063
+ if (i < sharedArgs.length && sharedArgs[i] !== void 0) {
60064
+ fnEnv.set(regularParams[i], ensureRuntimeValue(sharedArgs[i]));
59401
60065
  }
59402
60066
  }
59403
60067
  if (hasVarargin) {
59404
- const extraArgs = processedArgs.slice(regularParams.length).map((a) => ensureRuntimeValue(a));
60068
+ const extraArgs = sharedArgs.slice(regularParams.length).map((a) => ensureRuntimeValue(a));
59405
60069
  fnEnv.set("varargin", RTV.cell(extraArgs, [1, extraArgs.length]));
59406
60070
  }
59407
60071
  fnEnv.set("$nargin", narginOverride ?? args.length);
@@ -59421,6 +60085,7 @@ function callUserFunction(fn, args, nargout, narginOverride) {
59421
60085
  this.rt.pushCallFrame(fn.name);
59422
60086
  this.rt.pushCleanupScope();
59423
60087
  try {
60088
+ this.processArgumentsBlocks(fn, sharedArgs);
59424
60089
  this.execStmts(fn.body);
59425
60090
  if (fnEnv.persistentFuncId) {
59426
60091
  for (const name of fnEnv.persistentNames) {
@@ -59664,12 +60329,13 @@ function findExternalMethod(classInfo, methodName) {
59664
60329
  return null;
59665
60330
  }
59666
60331
  const ast = this.ctx.getCachedAST(mf.fileName);
60332
+ let primary = null;
59667
60333
  for (const stmt of ast.body) {
59668
- if (stmt.type === "Function" && stmt.name === methodName) {
59669
- return funcDefFromStmt(stmt);
59670
- }
60334
+ if (stmt.type !== "Function") continue;
60335
+ if (stmt.name === methodName) return funcDefFromStmt(stmt);
60336
+ if (!primary) primary = funcDefFromStmt(stmt);
59671
60337
  }
59672
- return null;
60338
+ return primary;
59673
60339
  }
59674
60340
  function collectClassProperties(classInfo) {
59675
60341
  const propertyNames = [...classInfo.propertyNames];
@@ -59743,7 +60409,7 @@ function evalInLocalScope(codeArg, fileName) {
59743
60409
  }
59744
60410
  function processArgumentsBlocks(fn, args) {
59745
60411
  const argBlocks = fn.argumentsBlocks;
59746
- if (!argBlocks || argBlocks.length === 0) return args;
60412
+ if (!argBlocks || argBlocks.length === 0) return;
59747
60413
  for (const block of argBlocks) {
59748
60414
  if (block.kind === "Output") continue;
59749
60415
  const entries = block.entries;
@@ -59764,48 +60430,27 @@ function processArgumentsBlocks(fn, args) {
59764
60430
  }
59765
60431
  return true;
59766
60432
  });
59767
- if (nvGroups.size > 0) {
59768
- const processedArgs2 = [...args];
59769
- const nvParamIndex = regularEntries.length;
59770
- for (const [paramName, fields] of nvGroups) {
59771
- const nvArgs = args.slice(nvParamIndex);
59772
- const defaults = {};
59773
- for (const { field, defaultExpr } of fields) {
59774
- if (defaultExpr) {
59775
- try {
59776
- defaults[field] = this.evalExpr(defaultExpr);
59777
- } catch {
59778
- }
59779
- }
59780
- }
59781
- const struct = this.rt.buildNameValueStruct(nvArgs, defaults);
59782
- const paramIdx = fn.params.indexOf(paramName);
59783
- const targetIdx = paramIdx >= 0 ? paramIdx : nvParamIndex;
59784
- processedArgs2.length = Math.max(processedArgs2.length, targetIdx + 1);
59785
- processedArgs2[targetIdx] = struct;
59786
- }
59787
- for (let i = 0; i < regularEntries.length; i++) {
59788
- if (processedArgs2[i] === void 0 && regularEntries[i].defaultValue) {
59789
- try {
59790
- processedArgs2[i] = this.evalExpr(regularEntries[i].defaultValue);
59791
- } catch {
59792
- }
59793
- }
60433
+ for (const entry of regularEntries) {
60434
+ const pIdx = fn.params.indexOf(entry.name);
60435
+ if (pIdx < 0) continue;
60436
+ const provided = pIdx < args.length && args[pIdx] !== void 0;
60437
+ if (!provided && entry.defaultValue) {
60438
+ this.env.set(
60439
+ entry.name,
60440
+ ensureRuntimeValue(this.evalExpr(entry.defaultValue))
60441
+ );
59794
60442
  }
59795
- return processedArgs2;
59796
60443
  }
59797
- const processedArgs = [...args];
59798
- for (let i = 0; i < entries.length; i++) {
59799
- if (processedArgs[i] === void 0 && entries[i].defaultValue) {
59800
- try {
59801
- processedArgs[i] = this.evalExpr(entries[i].defaultValue);
59802
- } catch {
59803
- }
60444
+ for (const [paramName, fields] of nvGroups) {
60445
+ const pIdx = fn.params.indexOf(paramName);
60446
+ const nvArgs = args.slice(pIdx >= 0 ? pIdx : args.length);
60447
+ const defaults = {};
60448
+ for (const { field, defaultExpr } of fields) {
60449
+ if (defaultExpr) defaults[field] = this.evalExpr(defaultExpr);
59804
60450
  }
60451
+ this.env.set(paramName, this.rt.buildNameValueStruct(nvArgs, defaults));
59805
60452
  }
59806
- return processedArgs;
59807
60453
  }
59808
- return args;
59809
60454
  }
59810
60455
 
59811
60456
  // src/numbl-core/interpreter/interpreter.ts
@@ -87108,15 +87753,18 @@ var Workspace = class _Workspace {
87108
87753
  );
87109
87754
  }
87110
87755
  let primary = null;
87756
+ let firstFn = null;
87111
87757
  for (const stmt of ast.body) {
87112
87758
  if (stmt.type !== "Function") continue;
87759
+ if (!firstFn) firstFn = stmt;
87113
87760
  if (stmt.name === methodName) {
87114
87761
  primary = stmt;
87115
87762
  }
87116
87763
  }
87764
+ primary ??= firstFn;
87117
87765
  if (!primary) {
87118
87766
  throw new UnsupportedConstruct(
87119
- `external method file '${mf.fileName}' has no function named '${methodName}'`,
87767
+ `external method file '${mf.fileName}' has no function`,
87120
87768
  info.ast.span
87121
87769
  );
87122
87770
  }