numbl 0.4.6 → 0.4.8
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 +2600 -228
- package/dist-graphics/graphics/FigureView.d.ts +6 -0
- package/dist-graphics/graphics/SurfView.d.ts +18 -0
- package/dist-graphics/graphics/axisLimits.d.ts +23 -0
- package/dist-graphics/graphics/drawPlot.d.ts +2 -0
- package/dist-graphics/graphics/exportFigureHdf5.d.ts +21 -0
- package/dist-graphics/graphics/figureHashTransport.d.ts +24 -0
- package/dist-graphics/graphics/figureHdf5Schema.d.ts +19 -0
- package/dist-graphics/graphics/figureUpload.d.ts +45 -0
- package/dist-graphics/graphics/figuresReducer.d.ts +86 -0
- package/dist-graphics/graphics/importFigureHdf5.d.ts +9 -0
- package/dist-graphics/graphics/openInFigureViewer.d.ts +26 -0
- package/dist-graphics/graphics/plotHelpers.d.ts +6 -0
- package/dist-graphics/graphics/plotLegend.d.ts +2 -0
- package/dist-graphics/graphics/plotMarkers.d.ts +2 -0
- package/dist-graphics/graphics/restoreNaNs.d.ts +2 -0
- package/dist-graphics/graphics/surfColormap.d.ts +2 -0
- package/dist-graphics/graphics/types.d.ts +423 -0
- package/dist-graphics/graphics/uihtmlSrcDoc.d.ts +23 -0
- package/dist-graphics/graphics-lib.d.ts +21 -0
- package/dist-graphics/index.js +35334 -0
- package/dist-lib/lib.d.ts +4 -0
- package/dist-lib/lib.js +3286 -222
- package/dist-lib/numbl-core/executors/jit/hostHelpers.d.ts +4 -0
- package/dist-lib/numbl-core/fileIOAdapter.d.ts +13 -0
- package/dist-lib/numbl-core/interpreter/builtins/gallery.d.ts +7 -0
- package/dist-lib/numbl-core/interpreter/builtins/geometry.d.ts +3 -3
- package/dist-lib/numbl-core/interpreter/builtins/graph.d.ts +29 -0
- package/dist-lib/numbl-core/interpreter/builtins/index.d.ts +2 -0
- package/dist-lib/numbl-core/interpreter/interpreter.d.ts +5 -0
- package/dist-lib/numbl-core/interpreter/interpreterExec.d.ts +14 -1
- package/dist-lib/numbl-core/interpreter/interpreterFunctions.d.ts +6 -0
- package/dist-lib/numbl-core/interpreter/interpreterSpecialBuiltins.d.ts +4 -0
- package/dist-lib/numbl-core/interpreter/types.d.ts +13 -0
- package/dist-lib/numbl-core/jit/builtins/defs/math/rand.d.ts +2 -0
- package/dist-lib/numbl-core/jitDeclineDiagnostics.d.ts +32 -0
- package/dist-lib/numbl-core/jsUserFunctions.d.ts +13 -0
- package/dist-lib/numbl-core/lowering/classInfo.d.ts +19 -2
- package/dist-lib/numbl-core/native/geometry-bridge.d.ts +10 -0
- package/dist-lib/numbl-core/parser/ArgumentsParser.d.ts +6 -1
- package/dist-lib/numbl-core/runtime/constructors.d.ts +2 -1
- package/dist-lib/numbl-core/runtime/runtime.d.ts +2 -1
- package/dist-lib/numbl-core/runtime/runtimeMemberAccess.d.ts +1 -1
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/dist-lib/vfs/BrowserFileIOAdapter.d.ts +54 -0
- package/dist-lib/vfs/BrowserSystemAdapter.d.ts +27 -0
- package/dist-lib/vfs/VirtualFileSystem.d.ts +66 -0
- package/dist-plot-viewer/assets/hdf5_hl-C9YUKPMe.js +24296 -0
- package/dist-plot-viewer/assets/index-YeXWXIxH.js +4504 -0
- package/dist-plot-viewer/index.html +1 -1
- package/dist-site-viewer/assets/hdf5_hl-C9YUKPMe.js +24296 -0
- package/dist-site-viewer/assets/index-C-wfkZK0.js +4829 -0
- package/dist-site-viewer/assets/numbl-worker-Bnbz2rMQ.js +5228 -0
- package/dist-site-viewer/index.html +1 -1
- package/native/lapack_svd.cpp +50 -0
- package/package.json +21 -2
- package/dist-plot-viewer/assets/index-D4grNz8m.js +0 -4504
- package/dist-site-viewer/assets/index-B2mCFC55.js +0 -4826
- package/dist-site-viewer/assets/numbl-worker-DWZE29ck.js +0 -5116
package/dist-lib/lib.js
CHANGED
|
@@ -1141,6 +1141,9 @@ var RTV = {
|
|
|
1141
1141
|
}
|
|
1142
1142
|
return new RuntimeClassInstance(className, fields, isHandleClass2);
|
|
1143
1143
|
},
|
|
1144
|
+
classInstanceArray(className, elements, shape) {
|
|
1145
|
+
return new RuntimeClassInstanceArray(className, elements, shape);
|
|
1146
|
+
},
|
|
1144
1147
|
complex(re, im) {
|
|
1145
1148
|
return new RuntimeComplexNumber(re, im);
|
|
1146
1149
|
},
|
|
@@ -18426,6 +18429,24 @@ function lu(data, m, n) {
|
|
|
18426
18429
|
}
|
|
18427
18430
|
function svd(data, m, n, econ, computeUV) {
|
|
18428
18431
|
const k = Math.min(m, n);
|
|
18432
|
+
let finite = true;
|
|
18433
|
+
for (let i = 0; i < data.length; i++) {
|
|
18434
|
+
if (!Number.isFinite(data[i])) {
|
|
18435
|
+
finite = false;
|
|
18436
|
+
break;
|
|
18437
|
+
}
|
|
18438
|
+
}
|
|
18439
|
+
if (!finite) {
|
|
18440
|
+
const sNan = allocFloat64Array(k).fill(NaN);
|
|
18441
|
+
if (!computeUV) return { S: sNan };
|
|
18442
|
+
const uCols2 = econ ? k : m;
|
|
18443
|
+
const vCols2 = econ ? k : n;
|
|
18444
|
+
return {
|
|
18445
|
+
U: allocFloat64Array(m * uCols2).fill(NaN),
|
|
18446
|
+
S: sNan,
|
|
18447
|
+
V: allocFloat64Array(n * vCols2).fill(NaN)
|
|
18448
|
+
};
|
|
18449
|
+
}
|
|
18429
18450
|
const a = allocFloat64Array(data);
|
|
18430
18451
|
const s = allocFloat64Array(k);
|
|
18431
18452
|
const JOBU_A2 = 0;
|
|
@@ -22299,6 +22320,24 @@ function sprintfFormat(fmt, args) {
|
|
|
22299
22320
|
case "t":
|
|
22300
22321
|
result += " ";
|
|
22301
22322
|
break;
|
|
22323
|
+
case "r":
|
|
22324
|
+
result += "\r";
|
|
22325
|
+
break;
|
|
22326
|
+
case "a":
|
|
22327
|
+
result += "\x07";
|
|
22328
|
+
break;
|
|
22329
|
+
case "b":
|
|
22330
|
+
result += "\b";
|
|
22331
|
+
break;
|
|
22332
|
+
case "f":
|
|
22333
|
+
result += "\f";
|
|
22334
|
+
break;
|
|
22335
|
+
case "v":
|
|
22336
|
+
result += "\v";
|
|
22337
|
+
break;
|
|
22338
|
+
case "0":
|
|
22339
|
+
result += "\0";
|
|
22340
|
+
break;
|
|
22302
22341
|
case "\\":
|
|
22303
22342
|
result += "\\";
|
|
22304
22343
|
break;
|
|
@@ -24235,8 +24274,8 @@ function indexIntoScalar(base, indices) {
|
|
|
24235
24274
|
const idx = indices[0];
|
|
24236
24275
|
if (isRuntimeTensor(idx)) {
|
|
24237
24276
|
const is0x0 = idx.shape.length === 2 && idx.shape[0] === 0 && idx.shape[1] === 0;
|
|
24238
|
-
const
|
|
24239
|
-
return RTV.tensor(allocFloat64Array(0),
|
|
24277
|
+
const outShape2 = is0x0 ? [0, 0] : [...idx.shape];
|
|
24278
|
+
return RTV.tensor(allocFloat64Array(0), outShape2);
|
|
24240
24279
|
}
|
|
24241
24280
|
}
|
|
24242
24281
|
if (indices.length === 1) {
|
|
@@ -24266,22 +24305,46 @@ function indexIntoScalar(base, indices) {
|
|
|
24266
24305
|
if (k !== 1) throw new RuntimeError("Index exceeds array bounds");
|
|
24267
24306
|
}
|
|
24268
24307
|
const n = idx.data.length;
|
|
24269
|
-
const
|
|
24270
|
-
const
|
|
24271
|
-
|
|
24308
|
+
const scalarRe2 = isRuntimeNumber(base) ? base : base.re;
|
|
24309
|
+
const data2 = allocFloat64Array(n);
|
|
24310
|
+
data2.fill(scalarRe2);
|
|
24272
24311
|
if (isRuntimeComplexNumber(base) && base.im !== 0) {
|
|
24273
24312
|
const im = allocFloat64Array(n);
|
|
24274
24313
|
im.fill(base.im);
|
|
24275
|
-
return RTV.tensor(
|
|
24314
|
+
return RTV.tensor(data2, [...idx.shape], im);
|
|
24276
24315
|
}
|
|
24277
|
-
return RTV.tensor(
|
|
24316
|
+
return RTV.tensor(data2, [...idx.shape]);
|
|
24278
24317
|
}
|
|
24318
|
+
const dimLengths = [];
|
|
24319
|
+
let anyTensor = false;
|
|
24279
24320
|
for (const idx of indices) {
|
|
24280
|
-
if (isColonIndex(idx))
|
|
24281
|
-
|
|
24282
|
-
if (
|
|
24321
|
+
if (isColonIndex(idx)) {
|
|
24322
|
+
dimLengths.push(1);
|
|
24323
|
+
} else if (isRuntimeTensor(idx)) {
|
|
24324
|
+
anyTensor = true;
|
|
24325
|
+
for (let i = 0; i < idx.data.length; i++) {
|
|
24326
|
+
if (Math.round(idx.data[i]) !== 1)
|
|
24327
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
24328
|
+
}
|
|
24329
|
+
dimLengths.push(idx.data.length);
|
|
24330
|
+
} else {
|
|
24331
|
+
if (Math.round(toNumber(idx)) !== 1)
|
|
24332
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
24333
|
+
dimLengths.push(1);
|
|
24334
|
+
}
|
|
24283
24335
|
}
|
|
24284
|
-
return base;
|
|
24336
|
+
if (!anyTensor) return base;
|
|
24337
|
+
const total = dimLengths.reduce((a, b) => a * b, 1);
|
|
24338
|
+
const scalarRe = isRuntimeNumber(base) ? base : base.re;
|
|
24339
|
+
const data = allocFloat64Array(total);
|
|
24340
|
+
data.fill(scalarRe);
|
|
24341
|
+
const outShape = dimLengths.length >= 2 ? dimLengths : [dimLengths[0], 1];
|
|
24342
|
+
if (isRuntimeComplexNumber(base) && base.im !== 0) {
|
|
24343
|
+
const im = allocFloat64Array(total);
|
|
24344
|
+
im.fill(base.im);
|
|
24345
|
+
return RTV.tensor(data, outShape, im);
|
|
24346
|
+
}
|
|
24347
|
+
return RTV.tensor(data, outShape);
|
|
24285
24348
|
}
|
|
24286
24349
|
function indexIntoTensor(base, indices) {
|
|
24287
24350
|
if (indices.length === 1) {
|
|
@@ -24316,11 +24379,13 @@ function indexIntoTensor(base, indices) {
|
|
|
24316
24379
|
function indexIntoTensor1D(base, idx) {
|
|
24317
24380
|
if (isColonIndex(idx)) {
|
|
24318
24381
|
const imag2 = base.imag ? allocFloat64Array(base.imag) : void 0;
|
|
24319
|
-
|
|
24382
|
+
const result = RTV.tensor(
|
|
24320
24383
|
allocFloat64Array(base.data),
|
|
24321
24384
|
[base.data.length, 1],
|
|
24322
24385
|
imag2
|
|
24323
24386
|
);
|
|
24387
|
+
if (base._isLogical === true) result._isLogical = true;
|
|
24388
|
+
return result;
|
|
24324
24389
|
}
|
|
24325
24390
|
if (isRuntimeLogical(idx)) {
|
|
24326
24391
|
if (!idx) return RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
@@ -24518,6 +24583,17 @@ function indexIntoChar(base, indices) {
|
|
|
24518
24583
|
if (indices.length === 1) {
|
|
24519
24584
|
const idx = indices[0];
|
|
24520
24585
|
if (isColonIndex(idx)) return base;
|
|
24586
|
+
if (isRuntimeTensor(idx) && idx._isLogical) {
|
|
24587
|
+
let result = "";
|
|
24588
|
+
for (let k = 0; k < idx.data.length; k++) {
|
|
24589
|
+
if (idx.data[k] !== 0) {
|
|
24590
|
+
if (k >= base.value.length)
|
|
24591
|
+
throw new RuntimeError("Index exceeds char array length");
|
|
24592
|
+
result += base.value[k];
|
|
24593
|
+
}
|
|
24594
|
+
}
|
|
24595
|
+
return RTV.char(result);
|
|
24596
|
+
}
|
|
24521
24597
|
if (isRuntimeTensor(idx)) {
|
|
24522
24598
|
let result = "";
|
|
24523
24599
|
for (let k = 0; k < idx.data.length; k++) {
|
|
@@ -24536,22 +24612,19 @@ function indexIntoChar(base, indices) {
|
|
|
24536
24612
|
if (indices.length === 2) {
|
|
24537
24613
|
const rowIdx = indices[0];
|
|
24538
24614
|
const colIdx = indices[1];
|
|
24539
|
-
|
|
24540
|
-
|
|
24541
|
-
|
|
24542
|
-
|
|
24543
|
-
|
|
24544
|
-
|
|
24545
|
-
|
|
24546
|
-
|
|
24547
|
-
|
|
24548
|
-
|
|
24549
|
-
|
|
24550
|
-
|
|
24551
|
-
|
|
24552
|
-
} else {
|
|
24553
|
-
cols = [Math.round(toNumber(colIdx)) - 1];
|
|
24554
|
-
}
|
|
24615
|
+
const toPositions = (idx) => {
|
|
24616
|
+
if (isRuntimeTensor(idx) && idx._isLogical) {
|
|
24617
|
+
const out = [];
|
|
24618
|
+
for (let i = 0; i < idx.data.length; i++)
|
|
24619
|
+
if (idx.data[i] !== 0) out.push(i);
|
|
24620
|
+
return out;
|
|
24621
|
+
}
|
|
24622
|
+
if (isRuntimeTensor(idx))
|
|
24623
|
+
return Array.from(idx.data, (v) => Math.round(v) - 1);
|
|
24624
|
+
return [Math.round(toNumber(idx)) - 1];
|
|
24625
|
+
};
|
|
24626
|
+
const rows = isColonIndex(rowIdx) ? Array.from({ length: nRows }, (_, i) => i) : toPositions(rowIdx);
|
|
24627
|
+
const cols = isColonIndex(colIdx) ? Array.from({ length: nCols }, (_, i) => i) : toPositions(colIdx);
|
|
24555
24628
|
let result = "";
|
|
24556
24629
|
for (const r of rows) {
|
|
24557
24630
|
for (const c of cols) {
|
|
@@ -24577,11 +24650,11 @@ function indexIntoLogical(base, indices) {
|
|
|
24577
24650
|
const vi = Math.round(idx.data[i2]);
|
|
24578
24651
|
if (vi !== 1) throw new RuntimeError("Index exceeds array bounds");
|
|
24579
24652
|
}
|
|
24580
|
-
const
|
|
24581
|
-
|
|
24582
|
-
const
|
|
24583
|
-
|
|
24584
|
-
return
|
|
24653
|
+
const data2 = allocFloat64Array(idx.data.length);
|
|
24654
|
+
data2.fill(base ? 1 : 0);
|
|
24655
|
+
const result2 = RTV.tensor(data2, [...idx.shape]);
|
|
24656
|
+
result2._isLogical = true;
|
|
24657
|
+
return result2;
|
|
24585
24658
|
}
|
|
24586
24659
|
if (isRuntimeLogical(idx)) {
|
|
24587
24660
|
if (!idx) return RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
@@ -24591,16 +24664,35 @@ function indexIntoLogical(base, indices) {
|
|
|
24591
24664
|
if (i !== 1) throw new RuntimeError("Index exceeds array bounds");
|
|
24592
24665
|
return base;
|
|
24593
24666
|
}
|
|
24667
|
+
const dimLengths = [];
|
|
24668
|
+
let anyTensor = false;
|
|
24594
24669
|
for (const idx of indices) {
|
|
24595
|
-
if (isColonIndex(idx))
|
|
24596
|
-
|
|
24670
|
+
if (isColonIndex(idx)) {
|
|
24671
|
+
dimLengths.push(1);
|
|
24672
|
+
} else if (isRuntimeLogical(idx)) {
|
|
24597
24673
|
if (!idx) return RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
24598
|
-
|
|
24674
|
+
dimLengths.push(1);
|
|
24675
|
+
} else if (isRuntimeTensor(idx)) {
|
|
24676
|
+
anyTensor = true;
|
|
24677
|
+
for (let i = 0; i < idx.data.length; i++) {
|
|
24678
|
+
if (Math.round(idx.data[i]) !== 1)
|
|
24679
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
24680
|
+
}
|
|
24681
|
+
dimLengths.push(idx.data.length);
|
|
24682
|
+
} else {
|
|
24683
|
+
if (Math.round(toNumber(idx)) !== 1)
|
|
24684
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
24685
|
+
dimLengths.push(1);
|
|
24599
24686
|
}
|
|
24600
|
-
const i = Math.round(toNumber(idx));
|
|
24601
|
-
if (i !== 1) throw new RuntimeError("Index exceeds array bounds");
|
|
24602
24687
|
}
|
|
24603
|
-
return base;
|
|
24688
|
+
if (!anyTensor) return base;
|
|
24689
|
+
const total = dimLengths.reduce((a, b) => a * b, 1);
|
|
24690
|
+
const data = allocFloat64Array(total);
|
|
24691
|
+
data.fill(base ? 1 : 0);
|
|
24692
|
+
const outShape = dimLengths.length >= 2 ? dimLengths : [dimLengths[0], 1];
|
|
24693
|
+
const result = RTV.tensor(data, outShape);
|
|
24694
|
+
result._isLogical = true;
|
|
24695
|
+
return result;
|
|
24604
24696
|
}
|
|
24605
24697
|
function indexIntoTensorWithTensor(base, idx) {
|
|
24606
24698
|
const baseLogical = base._isLogical === true;
|
|
@@ -24680,11 +24772,15 @@ function indexIntoRTValue(base, indices) {
|
|
|
24680
24772
|
return indexIntoLogical(base, indices);
|
|
24681
24773
|
}
|
|
24682
24774
|
if (isRuntimeStruct(base) || isRuntimeClassInstance(base)) {
|
|
24683
|
-
|
|
24684
|
-
|
|
24685
|
-
if (
|
|
24686
|
-
|
|
24687
|
-
|
|
24775
|
+
const allOnes = indices.length >= 1 && indices.every((idx) => {
|
|
24776
|
+
if (isRuntimeNumber(idx)) return Math.round(idx) === 1;
|
|
24777
|
+
if (isRuntimeLogical(idx)) return idx === true;
|
|
24778
|
+
if (isRuntimeTensor(idx))
|
|
24779
|
+
return idx.data.length === 1 && Math.round(idx.data[0]) === 1;
|
|
24780
|
+
return false;
|
|
24781
|
+
});
|
|
24782
|
+
if (allOnes) return base;
|
|
24783
|
+
throw new RuntimeError("Index exceeds struct dimensions");
|
|
24688
24784
|
}
|
|
24689
24785
|
if (isRuntimeSparseMatrix(base)) {
|
|
24690
24786
|
return indexIntoSparse(base, indices);
|
|
@@ -24734,7 +24830,13 @@ function storeIntoTensor(base, indices, rhs, _rt) {
|
|
|
24734
24830
|
}
|
|
24735
24831
|
if (isShared(base)) {
|
|
24736
24832
|
const cowImag = base.imag ? allocFloat64Array(base.imag) : void 0;
|
|
24737
|
-
|
|
24833
|
+
const copy = RTV.tensor(
|
|
24834
|
+
allocFloat64Array(base.data),
|
|
24835
|
+
[...base.shape],
|
|
24836
|
+
cowImag
|
|
24837
|
+
);
|
|
24838
|
+
copy._isLogical = base._isLogical;
|
|
24839
|
+
base = copy;
|
|
24738
24840
|
}
|
|
24739
24841
|
if (indices.length === 1) {
|
|
24740
24842
|
return storeIntoTensor1D(base, indices[0], rhs);
|
|
@@ -24762,7 +24864,9 @@ function deleteTensorElements(base, idx) {
|
|
|
24762
24864
|
toDelete.add(Math.round(idx.data[i]) - 1);
|
|
24763
24865
|
}
|
|
24764
24866
|
} else if (isColonIndex(idx)) {
|
|
24765
|
-
|
|
24867
|
+
const empty = RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
24868
|
+
empty._isLogical = base._isLogical;
|
|
24869
|
+
return empty;
|
|
24766
24870
|
}
|
|
24767
24871
|
if (toDelete.size === 0) return base;
|
|
24768
24872
|
const newData = [];
|
|
@@ -24777,7 +24881,9 @@ function deleteTensorElements(base, idx) {
|
|
|
24777
24881
|
const baseIsColVec = base.shape.length >= 2 && base.shape[1] === 1 && base.shape[0] !== 1;
|
|
24778
24882
|
const outShape = baseIsColVec ? [newData.length, 1] : [1, newData.length];
|
|
24779
24883
|
const imOut = hasImag && newIm.some((x) => x !== 0) ? allocFloat64Array(newIm) : void 0;
|
|
24780
|
-
|
|
24884
|
+
const result = RTV.tensor(allocFloat64Array(newData), outShape, imOut);
|
|
24885
|
+
result._isLogical = base._isLogical;
|
|
24886
|
+
return result;
|
|
24781
24887
|
}
|
|
24782
24888
|
function collectDelIndices(idx, dimLen) {
|
|
24783
24889
|
const s = /* @__PURE__ */ new Set();
|
|
@@ -24817,7 +24923,9 @@ function deleteTensorRowsOrCols(base, indices) {
|
|
|
24817
24923
|
if (newIm && base.imag) newIm[dstIdx] = base.imag[srcIdx];
|
|
24818
24924
|
}
|
|
24819
24925
|
}
|
|
24820
|
-
|
|
24926
|
+
const result = RTV.tensor(newData, [newNrows, ncols], newIm);
|
|
24927
|
+
result._isLogical = base._isLogical;
|
|
24928
|
+
return result;
|
|
24821
24929
|
}
|
|
24822
24930
|
if (isColonIndex(indices[0])) {
|
|
24823
24931
|
const delCols = collectDelIndices(indices[1], ncols);
|
|
@@ -24836,7 +24944,9 @@ function deleteTensorRowsOrCols(base, indices) {
|
|
|
24836
24944
|
if (newIm && base.imag) newIm[dstIdx] = base.imag[srcIdx];
|
|
24837
24945
|
}
|
|
24838
24946
|
}
|
|
24839
|
-
|
|
24947
|
+
const result = RTV.tensor(newData, [nrows, newNcols], newIm);
|
|
24948
|
+
result._isLogical = base._isLogical;
|
|
24949
|
+
return result;
|
|
24840
24950
|
}
|
|
24841
24951
|
throw new RuntimeError("Cannot delete from both row and column dimensions");
|
|
24842
24952
|
}
|
|
@@ -24906,6 +25016,9 @@ function storeIntoTensor1D(base, idx, rhs) {
|
|
|
24906
25016
|
}
|
|
24907
25017
|
function storeIntoTensorByVector(base, idx, rhs) {
|
|
24908
25018
|
if (idx._isLogical) {
|
|
25019
|
+
if (isRuntimeTensor(rhs) && rhs.data.length === 1) {
|
|
25020
|
+
rhs = rhs.imag && rhs.imag[0] !== 0 ? RTV.complex(rhs.data[0], rhs.imag[0]) : RTV.num(rhs.data[0]);
|
|
25021
|
+
}
|
|
24909
25022
|
const { re: rhsRe, im: rhsIm } = isRuntimeTensor(rhs) ? { re: null, im: null } : toReIm(rhs);
|
|
24910
25023
|
let maxTruthy = -1;
|
|
24911
25024
|
for (let i = 0; i < idx.data.length; i++) {
|
|
@@ -25155,7 +25268,8 @@ function storeIntoTensorND(base, indices, rhs) {
|
|
|
25155
25268
|
const dimIndices = indices.map((idx, dim) => {
|
|
25156
25269
|
const dimSize = dim < shape.length ? shape[dim] : 1;
|
|
25157
25270
|
if (isColonIndex(idx)) {
|
|
25158
|
-
|
|
25271
|
+
const dimSizeUnknown = dimSize === 0 || dim >= shape.length;
|
|
25272
|
+
if (dimSizeUnknown && rhsShape) {
|
|
25159
25273
|
const rDim = rhsDimCursor < rhsShape.length ? rhsShape[rhsDimCursor] : 1;
|
|
25160
25274
|
rhsDimCursor++;
|
|
25161
25275
|
return Array.from({ length: rDim }, (_, i) => i);
|
|
@@ -25472,6 +25586,9 @@ function horzcat(...values) {
|
|
|
25472
25586
|
if (values.some((v) => isRuntimeSparseMatrix(v))) {
|
|
25473
25587
|
return sparseCatAlongDim(values, 1);
|
|
25474
25588
|
}
|
|
25589
|
+
if (values.some((v) => isRuntimeCell(v))) {
|
|
25590
|
+
return cellCatAlongDim(values, 1);
|
|
25591
|
+
}
|
|
25475
25592
|
if (values.some((v) => isRuntimeChar(v))) {
|
|
25476
25593
|
let result = "";
|
|
25477
25594
|
for (const v of values) {
|
|
@@ -25492,9 +25609,6 @@ function horzcat(...values) {
|
|
|
25492
25609
|
}
|
|
25493
25610
|
return RTV.string(result);
|
|
25494
25611
|
}
|
|
25495
|
-
if (values.some((v) => isRuntimeCell(v))) {
|
|
25496
|
-
return cellCatAlongDim(values, 1);
|
|
25497
|
-
}
|
|
25498
25612
|
if (values.some((v) => isRuntimeStruct(v) || isRuntimeStructArray(v))) {
|
|
25499
25613
|
return structCat(values);
|
|
25500
25614
|
}
|
|
@@ -25506,12 +25620,12 @@ function vertcat(...values) {
|
|
|
25506
25620
|
if (values.some((v) => isRuntimeSparseMatrix(v))) {
|
|
25507
25621
|
return sparseCatAlongDim(values, 0);
|
|
25508
25622
|
}
|
|
25509
|
-
if (values.some((v) => isRuntimeChar(v))) {
|
|
25510
|
-
return vertcatChars(values);
|
|
25511
|
-
}
|
|
25512
25623
|
if (values.some((v) => isRuntimeCell(v))) {
|
|
25513
25624
|
return cellCatAlongDim(values, 0);
|
|
25514
25625
|
}
|
|
25626
|
+
if (values.some((v) => isRuntimeChar(v))) {
|
|
25627
|
+
return vertcatChars(values);
|
|
25628
|
+
}
|
|
25515
25629
|
if (values.some((v) => isRuntimeStruct(v) || isRuntimeStructArray(v))) {
|
|
25516
25630
|
return structCat(values);
|
|
25517
25631
|
}
|
|
@@ -25857,11 +25971,22 @@ function catAlongDim(values, dimIdx) {
|
|
|
25857
25971
|
if (allLogical) result._isLogical = true;
|
|
25858
25972
|
return result;
|
|
25859
25973
|
}
|
|
25974
|
+
function isEmptyNonCellOperand(v) {
|
|
25975
|
+
if (isRuntimeChar(v)) return v.value.length === 0;
|
|
25976
|
+
if (isRuntimeTensor(v)) return v.data.length === 0;
|
|
25977
|
+
return false;
|
|
25978
|
+
}
|
|
25860
25979
|
function cellCatAlongDim(values, dimIdx) {
|
|
25861
|
-
let cells =
|
|
25862
|
-
|
|
25863
|
-
|
|
25864
|
-
|
|
25980
|
+
let cells = [];
|
|
25981
|
+
for (const v of values) {
|
|
25982
|
+
if (isRuntimeCell(v)) {
|
|
25983
|
+
cells.push(v);
|
|
25984
|
+
} else if (isEmptyNonCellOperand(v)) {
|
|
25985
|
+
continue;
|
|
25986
|
+
} else {
|
|
25987
|
+
cells.push(RTV.cell([v], [1, 1]));
|
|
25988
|
+
}
|
|
25989
|
+
}
|
|
25865
25990
|
cells = cells.filter((c) => c.data.length > 0);
|
|
25866
25991
|
if (cells.length === 0) return RTV.cell([], [0, 0]);
|
|
25867
25992
|
if (cells.length === 1) return cells[0];
|
|
@@ -29760,7 +29885,7 @@ var ExpressionParser = class extends ParserBase {
|
|
|
29760
29885
|
}
|
|
29761
29886
|
} else if (expr.type === "Ident" && this.peekToken() === 41 /* At */ && this.peekTokenAt(1) === 4 /* Ident */) {
|
|
29762
29887
|
this.pos++;
|
|
29763
|
-
const className = this.
|
|
29888
|
+
const className = this.parseQualifiedName();
|
|
29764
29889
|
if (!this.consume(50 /* LParen */)) {
|
|
29765
29890
|
throw this.error("expected '(' after superclass name in super call");
|
|
29766
29891
|
}
|
|
@@ -30361,7 +30486,10 @@ var ControlFlowParser = class extends CommandParser {
|
|
|
30361
30486
|
let catchBody = [];
|
|
30362
30487
|
if (this.consume(27 /* Catch */)) {
|
|
30363
30488
|
if (this.peekToken() === 4 /* Ident */) {
|
|
30364
|
-
|
|
30489
|
+
const after = this.peekTokenAt(1);
|
|
30490
|
+
if (after === void 0 || after === 68 /* Newline */ || after === 49 /* Semicolon */ || after === 47 /* Comma */ || after === 15 /* End */) {
|
|
30491
|
+
catchVar = this.expectIdent();
|
|
30492
|
+
}
|
|
30365
30493
|
}
|
|
30366
30494
|
catchBody = this.parseBlock((t) => t === 15 /* End */);
|
|
30367
30495
|
}
|
|
@@ -30486,8 +30614,12 @@ var ArgumentsParser = class extends ControlFlowParser {
|
|
|
30486
30614
|
dimensions = this.parseArgDimensions();
|
|
30487
30615
|
}
|
|
30488
30616
|
let className = null;
|
|
30489
|
-
if (this.peekToken() === 4 /* Ident */
|
|
30617
|
+
if (this.peekToken() === 4 /* Ident */) {
|
|
30490
30618
|
className = this.next().lexeme;
|
|
30619
|
+
while (this.peekToken() === 45 /* Dot */) {
|
|
30620
|
+
this.consume(45 /* Dot */);
|
|
30621
|
+
className += "." + this.expectIdent();
|
|
30622
|
+
}
|
|
30491
30623
|
}
|
|
30492
30624
|
let validators = [];
|
|
30493
30625
|
if (this.peekToken() === 54 /* LBrace */) {
|
|
@@ -30523,18 +30655,28 @@ var ArgumentsParser = class extends ControlFlowParser {
|
|
|
30523
30655
|
return dims;
|
|
30524
30656
|
}
|
|
30525
30657
|
/**
|
|
30526
|
-
* Parse validator list: {mustBeNumeric, mustBePositive}
|
|
30658
|
+
* Parse validator list: {mustBeNumeric, mustBePositive}. Validators may be
|
|
30659
|
+
* full function calls with arguments, e.g.
|
|
30660
|
+
* `{mustBeMember(x,["a","b"]), mustBeInRange(x,0,7)}`. The validator bodies
|
|
30661
|
+
* are not enforced at runtime, so we capture the top-level validator name
|
|
30662
|
+
* tokens and skip past any nested `(...)`, `[...]`, `{...}` so parsing
|
|
30663
|
+
* resumes correctly at the default value (`= expr`) or end of line.
|
|
30527
30664
|
*/
|
|
30528
30665
|
parseArgValidators() {
|
|
30529
30666
|
this.consume(54 /* LBrace */);
|
|
30530
30667
|
const validators = [];
|
|
30531
|
-
|
|
30532
|
-
|
|
30533
|
-
|
|
30534
|
-
|
|
30535
|
-
|
|
30536
|
-
|
|
30668
|
+
let depth = 0;
|
|
30669
|
+
while (this.peekToken() !== void 0) {
|
|
30670
|
+
const tok = this.peekToken();
|
|
30671
|
+
if (depth === 0 && tok === 55 /* RBrace */) break;
|
|
30672
|
+
if (tok === 50 /* LParen */ || tok === 52 /* LBracket */ || tok === 54 /* LBrace */) {
|
|
30673
|
+
depth++;
|
|
30674
|
+
} else if (tok === 51 /* RParen */ || tok === 53 /* RBracket */ || tok === 55 /* RBrace */) {
|
|
30675
|
+
depth--;
|
|
30676
|
+
} else if (depth === 0 && tok === 4 /* Ident */) {
|
|
30677
|
+
validators.push(this.peek().lexeme);
|
|
30537
30678
|
}
|
|
30679
|
+
this.next();
|
|
30538
30680
|
}
|
|
30539
30681
|
this.consume(55 /* RBrace */);
|
|
30540
30682
|
return validators;
|
|
@@ -30565,7 +30707,8 @@ var FunctionParser = class extends ArgumentsParser {
|
|
|
30565
30707
|
if (this.consume(52 /* LBracket */)) {
|
|
30566
30708
|
if (this.peekToken() !== 53 /* RBracket */) {
|
|
30567
30709
|
outputs.push(this.expectIdentOrTilde());
|
|
30568
|
-
while (this.
|
|
30710
|
+
while (this.peekToken() === 47 /* Comma */ || this.peekToken() === 4 /* Ident */ || this.peekToken() === 40 /* Tilde */) {
|
|
30711
|
+
this.consume(47 /* Comma */);
|
|
30569
30712
|
outputs.push(this.expectIdentOrTilde());
|
|
30570
30713
|
}
|
|
30571
30714
|
}
|
|
@@ -30673,6 +30816,14 @@ var FunctionParser = class extends ArgumentsParser {
|
|
|
30673
30816
|
};
|
|
30674
30817
|
|
|
30675
30818
|
// src/numbl-core/parser/ClassParser.ts
|
|
30819
|
+
var HANDLE_BASE_CLASSES = /* @__PURE__ */ new Set([
|
|
30820
|
+
"handle",
|
|
30821
|
+
"dynamicprops",
|
|
30822
|
+
"matlab.mixin.Copyable",
|
|
30823
|
+
"matlab.mixin.SetGet",
|
|
30824
|
+
"matlab.mixin.SetGetExactNames",
|
|
30825
|
+
"hgsetget"
|
|
30826
|
+
]);
|
|
30676
30827
|
var ClassParser = class extends FunctionParser {
|
|
30677
30828
|
// ── Imports & ClassDef ───────────────────────────────────────────────
|
|
30678
30829
|
parseImport() {
|
|
@@ -30707,7 +30858,11 @@ var ClassParser = class extends FunctionParser {
|
|
|
30707
30858
|
const name = this.parseQualifiedName();
|
|
30708
30859
|
let superClass = null;
|
|
30709
30860
|
if (this.consume(43 /* Less */)) {
|
|
30710
|
-
|
|
30861
|
+
const supers = [this.parseQualifiedName()];
|
|
30862
|
+
while (this.consume(38 /* And */)) {
|
|
30863
|
+
supers.push(this.parseQualifiedName());
|
|
30864
|
+
}
|
|
30865
|
+
superClass = supers.some((s) => HANDLE_BASE_CLASSES.has(s)) ? "handle" : supers[0];
|
|
30711
30866
|
}
|
|
30712
30867
|
const members = [];
|
|
30713
30868
|
while (true) {
|
|
@@ -31582,7 +31737,7 @@ function insertFunctionEndTokens(tokens) {
|
|
|
31582
31737
|
}
|
|
31583
31738
|
if (BLOCK_OPENERS.has(tok.token)) {
|
|
31584
31739
|
depth++;
|
|
31585
|
-
} else if (tok.token === 15 /* End */ && groupDepth === 0) {
|
|
31740
|
+
} else if (tok.token === 15 /* End */ && groupDepth === 0 && tokens[i - 1]?.token !== 45 /* Dot */) {
|
|
31586
31741
|
depth--;
|
|
31587
31742
|
if (depth === 0 && inFunction) {
|
|
31588
31743
|
inFunction = false;
|
|
@@ -34294,6 +34449,8 @@ defineBuiltin({
|
|
|
34294
34449
|
if (isRuntimeComplexNumber(v)) return v.im === 0;
|
|
34295
34450
|
if (isRuntimeTensor(v)) return imagAllZero(v.imag);
|
|
34296
34451
|
if (isRuntimeSparseMatrix(v)) return !v.pi || imagAllZero(v.pi);
|
|
34452
|
+
if (isRuntimeCell(v) || isRuntimeStruct(v) || isRuntimeStructArray(v) || isRuntimeString(v) || isRuntimeFunction(v))
|
|
34453
|
+
return false;
|
|
34297
34454
|
return true;
|
|
34298
34455
|
}
|
|
34299
34456
|
}
|
|
@@ -34765,10 +34922,79 @@ defineBuiltin({
|
|
|
34765
34922
|
name: "ischar",
|
|
34766
34923
|
cases: [anyToLogicalCase((args) => isRuntimeChar(args[0]))]
|
|
34767
34924
|
});
|
|
34925
|
+
defineBuiltin({
|
|
34926
|
+
name: "isstr",
|
|
34927
|
+
cases: [anyToLogicalCase((args) => isRuntimeChar(args[0]))]
|
|
34928
|
+
});
|
|
34768
34929
|
defineBuiltin({
|
|
34769
34930
|
name: "isstring",
|
|
34770
34931
|
cases: [anyToLogicalCase((args) => isRuntimeString(args[0]))]
|
|
34771
34932
|
});
|
|
34933
|
+
var MATLAB_KEYWORDS = /* @__PURE__ */ new Set([
|
|
34934
|
+
"break",
|
|
34935
|
+
"case",
|
|
34936
|
+
"catch",
|
|
34937
|
+
"classdef",
|
|
34938
|
+
"continue",
|
|
34939
|
+
"else",
|
|
34940
|
+
"elseif",
|
|
34941
|
+
"end",
|
|
34942
|
+
"for",
|
|
34943
|
+
"function",
|
|
34944
|
+
"global",
|
|
34945
|
+
"if",
|
|
34946
|
+
"otherwise",
|
|
34947
|
+
"parfor",
|
|
34948
|
+
"persistent",
|
|
34949
|
+
"return",
|
|
34950
|
+
"spmd",
|
|
34951
|
+
"switch",
|
|
34952
|
+
"try",
|
|
34953
|
+
"while"
|
|
34954
|
+
]);
|
|
34955
|
+
function singleRowText(v) {
|
|
34956
|
+
if (isRuntimeChar(v)) {
|
|
34957
|
+
if (v.shape && v.shape.length >= 1 && v.shape[0] > 1) return null;
|
|
34958
|
+
return v.value;
|
|
34959
|
+
}
|
|
34960
|
+
if (isRuntimeString(v)) return v;
|
|
34961
|
+
return null;
|
|
34962
|
+
}
|
|
34963
|
+
defineBuiltin({
|
|
34964
|
+
name: "isvarname",
|
|
34965
|
+
cases: [
|
|
34966
|
+
anyToLogicalCase((args) => {
|
|
34967
|
+
const s = singleRowText(args[0]);
|
|
34968
|
+
if (s === null || s.length === 0 || s.length > 63) return false;
|
|
34969
|
+
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(s)) return false;
|
|
34970
|
+
return !MATLAB_KEYWORDS.has(s);
|
|
34971
|
+
})
|
|
34972
|
+
]
|
|
34973
|
+
});
|
|
34974
|
+
defineBuiltin({
|
|
34975
|
+
name: "iskeyword",
|
|
34976
|
+
cases: [
|
|
34977
|
+
{
|
|
34978
|
+
// iskeyword() with no args returns the list of keywords (column cell).
|
|
34979
|
+
match: (argTypes) => {
|
|
34980
|
+
if (argTypes.length === 0) return [{ kind: "cell" }];
|
|
34981
|
+
if (argTypes.length === 1) return [{ kind: "boolean" }];
|
|
34982
|
+
return null;
|
|
34983
|
+
},
|
|
34984
|
+
apply: (args) => {
|
|
34985
|
+
if (args.length === 0) {
|
|
34986
|
+
const names = [...MATLAB_KEYWORDS].sort();
|
|
34987
|
+
return RTV.cell(
|
|
34988
|
+
names.map((n) => RTV.char(n)),
|
|
34989
|
+
[names.length, 1]
|
|
34990
|
+
);
|
|
34991
|
+
}
|
|
34992
|
+
const s = singleRowText(args[0]);
|
|
34993
|
+
return RTV.logical(s !== null && MATLAB_KEYWORDS.has(s));
|
|
34994
|
+
}
|
|
34995
|
+
}
|
|
34996
|
+
]
|
|
34997
|
+
});
|
|
34772
34998
|
defineBuiltin({
|
|
34773
34999
|
name: "iscell",
|
|
34774
35000
|
cases: [anyToLogicalCase((args) => isRuntimeCell(args[0]))]
|
|
@@ -34785,6 +35011,82 @@ defineBuiltin({
|
|
|
34785
35011
|
name: "issparse",
|
|
34786
35012
|
cases: [anyToLogicalCase((args) => isRuntimeSparseMatrix(args[0]))]
|
|
34787
35013
|
});
|
|
35014
|
+
defineBuiltin({
|
|
35015
|
+
name: "isobject",
|
|
35016
|
+
cases: [
|
|
35017
|
+
anyToLogicalCase(
|
|
35018
|
+
(args) => isRuntimeClassInstance(args[0]) || isRuntimeClassInstanceArray(args[0])
|
|
35019
|
+
)
|
|
35020
|
+
]
|
|
35021
|
+
});
|
|
35022
|
+
defineBuiltin({
|
|
35023
|
+
name: "isprop",
|
|
35024
|
+
help: {
|
|
35025
|
+
signatures: ["tf = isprop(obj, PropertyName)"],
|
|
35026
|
+
description: "Return logical 1 where PropertyName is a property of object obj, else 0. The result has the same size as obj. Only class objects have properties: structs (even with that field), numeric, char and other built-in types always return false. Methods are not properties."
|
|
35027
|
+
},
|
|
35028
|
+
cases: [
|
|
35029
|
+
{
|
|
35030
|
+
match: (argTypes) => {
|
|
35031
|
+
if (argTypes.length !== 2) return null;
|
|
35032
|
+
return [{ kind: "boolean" }];
|
|
35033
|
+
},
|
|
35034
|
+
apply: (args) => {
|
|
35035
|
+
const v = args[0];
|
|
35036
|
+
const nameArg = args[1];
|
|
35037
|
+
let propName = null;
|
|
35038
|
+
if (isRuntimeChar(nameArg)) propName = nameArg.value;
|
|
35039
|
+
else if (isRuntimeString(nameArg)) propName = nameArg;
|
|
35040
|
+
let answer = false;
|
|
35041
|
+
if (propName !== null) {
|
|
35042
|
+
if (isRuntimeClassInstance(v)) answer = v.fields.has(propName);
|
|
35043
|
+
else if (isRuntimeClassInstanceArray(v))
|
|
35044
|
+
answer = v.elements.length > 0 && v.elements[0].fields.has(propName);
|
|
35045
|
+
}
|
|
35046
|
+
const shape = getShape(v);
|
|
35047
|
+
const n = shape.reduce((a, b) => a * b, 1);
|
|
35048
|
+
if (n === 1) return RTV.logical(answer);
|
|
35049
|
+
const data = allocFloat64Array(n);
|
|
35050
|
+
if (answer) data.fill(1);
|
|
35051
|
+
return new RuntimeTensor(data, shape, void 0, true);
|
|
35052
|
+
}
|
|
35053
|
+
}
|
|
35054
|
+
]
|
|
35055
|
+
});
|
|
35056
|
+
defineBuiltin({
|
|
35057
|
+
name: "addprop",
|
|
35058
|
+
help: {
|
|
35059
|
+
signatures: ["p = addprop(obj, PropertyName)"],
|
|
35060
|
+
description: "Add a dynamic property named PropertyName to the dynamicprops (handle) object obj. The property can then be read and assigned via obj.PropertyName. Returns a meta.DynamicProperty describing the new property."
|
|
35061
|
+
},
|
|
35062
|
+
cases: [
|
|
35063
|
+
{
|
|
35064
|
+
match: (argTypes) => {
|
|
35065
|
+
if (argTypes.length !== 2) return null;
|
|
35066
|
+
return [{ kind: "unknown" }];
|
|
35067
|
+
},
|
|
35068
|
+
apply: (args) => {
|
|
35069
|
+
const obj = args[0];
|
|
35070
|
+
if (!isRuntimeClassInstance(obj))
|
|
35071
|
+
throw new RuntimeError(
|
|
35072
|
+
"addprop: first argument must be a dynamicprops object"
|
|
35073
|
+
);
|
|
35074
|
+
const name = toString(args[1]);
|
|
35075
|
+
if (!obj.fields.has(name)) {
|
|
35076
|
+
const empty = RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
35077
|
+
incref(empty);
|
|
35078
|
+
obj.fields.set(name, empty);
|
|
35079
|
+
}
|
|
35080
|
+
return RTV.classInstance(
|
|
35081
|
+
"meta.DynamicProperty",
|
|
35082
|
+
["Name"],
|
|
35083
|
+
true,
|
|
35084
|
+
/* @__PURE__ */ new Map([["Name", RTV.char(name)]])
|
|
35085
|
+
);
|
|
35086
|
+
}
|
|
35087
|
+
}
|
|
35088
|
+
]
|
|
35089
|
+
});
|
|
34788
35090
|
defineBuiltin({
|
|
34789
35091
|
name: "isscalar",
|
|
34790
35092
|
cases: [
|
|
@@ -34982,6 +35284,30 @@ function mkChar(value) {
|
|
|
34982
35284
|
defineBuiltin({
|
|
34983
35285
|
name: "class",
|
|
34984
35286
|
cases: [
|
|
35287
|
+
// Old-style (pre-classdef) constructor form: class(structData, 'ClassName')
|
|
35288
|
+
// builds a value-type instance whose fields are the struct's fields. The
|
|
35289
|
+
// optional class(s,'Name',parent,...) inheritance form is not supported
|
|
35290
|
+
// (returns null → "unsupported argument types").
|
|
35291
|
+
{
|
|
35292
|
+
match: (argTypes) => {
|
|
35293
|
+
if (argTypes.length !== 2) return null;
|
|
35294
|
+
if (argTypes[0].kind !== "struct") return null;
|
|
35295
|
+
const k = argTypes[1].kind;
|
|
35296
|
+
if (k !== "char" && k !== "string") return null;
|
|
35297
|
+
return [{ kind: "unknown" }];
|
|
35298
|
+
},
|
|
35299
|
+
apply: (args) => {
|
|
35300
|
+
const s = args[0];
|
|
35301
|
+
if (!isRuntimeStruct(s))
|
|
35302
|
+
throw new RuntimeError(
|
|
35303
|
+
"class: first argument must be a scalar struct"
|
|
35304
|
+
);
|
|
35305
|
+
const nameVal = args[1];
|
|
35306
|
+
const className = isRuntimeChar(nameVal) ? nameVal.value : isRuntimeString(nameVal) ? nameVal : String(nameVal);
|
|
35307
|
+
const fieldNames = [...s.fields.keys()];
|
|
35308
|
+
return RTV.classInstance(className, fieldNames, false, s.fields);
|
|
35309
|
+
}
|
|
35310
|
+
},
|
|
34985
35311
|
{
|
|
34986
35312
|
match: (argTypes) => {
|
|
34987
35313
|
if (argTypes.length !== 1) return null;
|
|
@@ -35019,6 +35345,26 @@ defineBuiltin({
|
|
|
35019
35345
|
}
|
|
35020
35346
|
]
|
|
35021
35347
|
});
|
|
35348
|
+
for (const name of ["superiorto", "inferiorto"]) {
|
|
35349
|
+
defineBuiltin({
|
|
35350
|
+
name,
|
|
35351
|
+
help: {
|
|
35352
|
+
signatures: [`${name}('Class1', 'Class2', ...)`],
|
|
35353
|
+
description: name === "superiorto" ? "Establish superior class relationship (old-style class precedence). Accepted as a no-op." : "Establish inferior class relationship (old-style class precedence). Accepted as a no-op."
|
|
35354
|
+
},
|
|
35355
|
+
cases: [
|
|
35356
|
+
{
|
|
35357
|
+
match: (argTypes) => {
|
|
35358
|
+
for (const t of argTypes) {
|
|
35359
|
+
if (t.kind !== "char" && t.kind !== "string") return null;
|
|
35360
|
+
}
|
|
35361
|
+
return [];
|
|
35362
|
+
},
|
|
35363
|
+
apply: () => void 0
|
|
35364
|
+
}
|
|
35365
|
+
]
|
|
35366
|
+
});
|
|
35367
|
+
}
|
|
35022
35368
|
function fieldnamesApply(args) {
|
|
35023
35369
|
if (args.length !== 1)
|
|
35024
35370
|
throw new RuntimeError("fieldnames requires 1 argument");
|
|
@@ -35134,6 +35480,11 @@ function validateDim(x) {
|
|
|
35134
35480
|
throw new RuntimeError("Size inputs must be nonnegative integers.");
|
|
35135
35481
|
return Math.max(0, x);
|
|
35136
35482
|
}
|
|
35483
|
+
function toScalarDim(v) {
|
|
35484
|
+
if (isRuntimeTensor(v) && v.data.length !== 1)
|
|
35485
|
+
throw new RuntimeError("Size inputs must be scalar.");
|
|
35486
|
+
return validateDim(toNumber(v));
|
|
35487
|
+
}
|
|
35137
35488
|
function parseShapeArgs(args) {
|
|
35138
35489
|
if (args.length === 1 && isRuntimeTensor(args[0])) {
|
|
35139
35490
|
const t = args[0];
|
|
@@ -35141,7 +35492,7 @@ function parseShapeArgs(args) {
|
|
|
35141
35492
|
for (let i = 0; i < t.data.length; i++) shape.push(validateDim(t.data[i]));
|
|
35142
35493
|
return shape;
|
|
35143
35494
|
}
|
|
35144
|
-
return args.map(
|
|
35495
|
+
return args.map(toScalarDim);
|
|
35145
35496
|
}
|
|
35146
35497
|
function arrayConstructorCases(fillFn, scalarValue, opts) {
|
|
35147
35498
|
const cases = [
|
|
@@ -35182,12 +35533,14 @@ function arrayConstructorCases(fillFn, scalarValue, opts) {
|
|
|
35182
35533
|
return fillFn(shape);
|
|
35183
35534
|
}
|
|
35184
35535
|
},
|
|
35185
|
-
// Multiple scalar args
|
|
35536
|
+
// Multiple scalar args. A 1×1 array counts as a scalar dimension, so
|
|
35537
|
+
// accept `tensor` here too (apply-time validates each is scalar).
|
|
35186
35538
|
{
|
|
35187
35539
|
match: (argTypes) => {
|
|
35188
35540
|
if (argTypes.length <= 1) return null;
|
|
35189
35541
|
for (const a of argTypes) {
|
|
35190
|
-
if (a.kind !== "number" && a.kind !== "boolean"
|
|
35542
|
+
if (a.kind !== "number" && a.kind !== "boolean" && a.kind !== "tensor")
|
|
35543
|
+
return null;
|
|
35191
35544
|
}
|
|
35192
35545
|
const shape = argTypes.map(
|
|
35193
35546
|
(a) => a.kind === "number" && typeof a.exact === "number" ? a.exact : -1
|
|
@@ -35852,7 +36205,6 @@ function anyAllApply(name, mode) {
|
|
|
35852
36205
|
if (isRuntimeComplexNumber(v)) return RTV.logical(v.re !== 0 || v.im !== 0);
|
|
35853
36206
|
if (isRuntimeTensor(v)) {
|
|
35854
36207
|
if (args.length === 1) {
|
|
35855
|
-
if (v.data.length === 0) return RTV.logical(mode === "all");
|
|
35856
36208
|
const d = firstReduceDim(v.shape);
|
|
35857
36209
|
if (d === 0) return RTV.logical(scanLogical(v.data, v.imag, mode));
|
|
35858
36210
|
return logicalAlongDim(v, d, mode);
|
|
@@ -36122,7 +36474,12 @@ function applyTextFn(v, fn) {
|
|
|
36122
36474
|
}
|
|
36123
36475
|
return RTV.cell(out, [...v.shape]);
|
|
36124
36476
|
}
|
|
36125
|
-
if (isRuntimeChar(v))
|
|
36477
|
+
if (isRuntimeChar(v)) {
|
|
36478
|
+
if (v.shape && (v.shape[0] ?? 1) > 1) {
|
|
36479
|
+
return charRowsToMatrix(valueToCharRows(v).map(fn));
|
|
36480
|
+
}
|
|
36481
|
+
return RTV.char(fn(v.value));
|
|
36482
|
+
}
|
|
36126
36483
|
if (isRuntimeString(v)) return RTV.string(fn(toString(v)));
|
|
36127
36484
|
return v;
|
|
36128
36485
|
}
|
|
@@ -36274,7 +36631,7 @@ registerIBuiltin({
|
|
|
36274
36631
|
const str = toString(args[0]);
|
|
36275
36632
|
const pat = toString(args[1]);
|
|
36276
36633
|
const rep = toString(args[2]);
|
|
36277
|
-
let flags = "
|
|
36634
|
+
let flags = "gs";
|
|
36278
36635
|
for (let i = 3; i < args.length; i++) {
|
|
36279
36636
|
const opt = toString(args[i]).toLowerCase();
|
|
36280
36637
|
if (opt === "ignorecase") flags += "i";
|
|
@@ -36638,6 +36995,38 @@ registerIBuiltin({
|
|
|
36638
36995
|
};
|
|
36639
36996
|
}
|
|
36640
36997
|
});
|
|
36998
|
+
registerIBuiltin({
|
|
36999
|
+
name: "isspace",
|
|
37000
|
+
help: {
|
|
37001
|
+
signatures: ["TF = isspace(str)"],
|
|
37002
|
+
description: "Return a logical array the same size as str, true where the character is whitespace. Numeric input is treated as Unicode code points."
|
|
37003
|
+
},
|
|
37004
|
+
resolve: (argTypes) => {
|
|
37005
|
+
if (argTypes.length !== 1) return null;
|
|
37006
|
+
const k = argTypes[0].kind;
|
|
37007
|
+
if (k !== "char" && k !== "string" && k !== "number" && k !== "boolean" && k !== "tensor") {
|
|
37008
|
+
return null;
|
|
37009
|
+
}
|
|
37010
|
+
const pred = (cp) => RE_WSPACE.test(String.fromCodePoint(cp));
|
|
37011
|
+
return {
|
|
37012
|
+
outputTypes: [{ kind: "tensor", isComplex: false, isLogical: true }],
|
|
37013
|
+
apply: (args) => {
|
|
37014
|
+
const v = args[0];
|
|
37015
|
+
if (isRuntimeChar(v)) {
|
|
37016
|
+
return logicalRowFromString(
|
|
37017
|
+
v.value,
|
|
37018
|
+
pred,
|
|
37019
|
+
v.shape ? [...v.shape] : void 0
|
|
37020
|
+
);
|
|
37021
|
+
}
|
|
37022
|
+
if (isRuntimeString(v)) return logicalRowFromString(toString(v), pred);
|
|
37023
|
+
if (isRuntimeTensor(v))
|
|
37024
|
+
return logicalFromNumericTensor(v.data, v.shape, pred);
|
|
37025
|
+
return logicalFromNumericTensor([toNumber(v)], [1, 1], pred);
|
|
37026
|
+
}
|
|
37027
|
+
};
|
|
37028
|
+
}
|
|
37029
|
+
});
|
|
36641
37030
|
registerIBuiltin({
|
|
36642
37031
|
name: "contains",
|
|
36643
37032
|
resolve: (argTypes) => {
|
|
@@ -37085,12 +37474,102 @@ registerIBuiltin({
|
|
|
37085
37474
|
};
|
|
37086
37475
|
}
|
|
37087
37476
|
});
|
|
37477
|
+
function collectRows(v) {
|
|
37478
|
+
if (isRuntimeCell(v)) {
|
|
37479
|
+
const rows = [];
|
|
37480
|
+
for (const el of v.data) rows.push(...valueToCharRows(el));
|
|
37481
|
+
return rows;
|
|
37482
|
+
}
|
|
37483
|
+
return valueToCharRows(v);
|
|
37484
|
+
}
|
|
37485
|
+
registerIBuiltin({
|
|
37486
|
+
name: "strmatch",
|
|
37487
|
+
help: {
|
|
37488
|
+
signatures: [
|
|
37489
|
+
"x = strmatch(str, strarray)",
|
|
37490
|
+
"x = strmatch(str, strarray, 'exact')"
|
|
37491
|
+
],
|
|
37492
|
+
description: "(Legacy) Find rows of STRARRAY that begin with STR, or that equal STR when 'exact' is given. Returns a column vector of matching row indices."
|
|
37493
|
+
},
|
|
37494
|
+
resolve: (argTypes) => {
|
|
37495
|
+
if (argTypes.length < 2 || argTypes.length > 3) return null;
|
|
37496
|
+
if (!isTextType(argTypes[0])) return null;
|
|
37497
|
+
const sa = argTypes[1];
|
|
37498
|
+
if (sa.kind !== "char" && sa.kind !== "string" && sa.kind !== "cell")
|
|
37499
|
+
return null;
|
|
37500
|
+
return {
|
|
37501
|
+
outputTypes: [{ kind: "tensor", isComplex: false }],
|
|
37502
|
+
apply: (args) => {
|
|
37503
|
+
const str = toString(args[0]);
|
|
37504
|
+
let rows = collectRows(args[1]);
|
|
37505
|
+
const n = rows.length === 0 ? 0 : Math.max(...rows.map((r) => r.length));
|
|
37506
|
+
rows = rows.map((r) => r.padEnd(n, " "));
|
|
37507
|
+
const exactMatch = args.length === 3;
|
|
37508
|
+
let s = str;
|
|
37509
|
+
let len = s.length;
|
|
37510
|
+
if (len > n) {
|
|
37511
|
+
return RTV.tensor(allocFloat64Array(0), [0, 1]);
|
|
37512
|
+
}
|
|
37513
|
+
if (exactMatch && len < n) {
|
|
37514
|
+
const useNull = rows.some((r) => r.charCodeAt(n - 1) === 0);
|
|
37515
|
+
s = s.padEnd(n, useNull ? "\0" : " ");
|
|
37516
|
+
len = n;
|
|
37517
|
+
}
|
|
37518
|
+
const matches2 = [];
|
|
37519
|
+
for (let r = 0; r < rows.length; r++) {
|
|
37520
|
+
let ok = true;
|
|
37521
|
+
for (let i = 0; i < len; i++) {
|
|
37522
|
+
if (rows[r][i] !== s[i]) {
|
|
37523
|
+
ok = false;
|
|
37524
|
+
break;
|
|
37525
|
+
}
|
|
37526
|
+
}
|
|
37527
|
+
if (ok) matches2.push(r + 1);
|
|
37528
|
+
}
|
|
37529
|
+
return RTV.tensor(allocFloat64Array(matches2), [matches2.length, 1]);
|
|
37530
|
+
}
|
|
37531
|
+
};
|
|
37532
|
+
}
|
|
37533
|
+
});
|
|
37534
|
+
function valueToCharRows(v) {
|
|
37535
|
+
if (isRuntimeChar(v)) {
|
|
37536
|
+
const cols = v.shape ? v.shape[1] ?? v.value.length : v.value.length;
|
|
37537
|
+
const numRows = v.shape ? v.shape[0] ?? 1 : 1;
|
|
37538
|
+
if (numRows <= 1) return [v.value];
|
|
37539
|
+
const out = [];
|
|
37540
|
+
for (let r = 0; r < numRows; r++)
|
|
37541
|
+
out.push(v.value.slice(r * cols, (r + 1) * cols));
|
|
37542
|
+
return out;
|
|
37543
|
+
}
|
|
37544
|
+
if (isRuntimeString(v)) return [v];
|
|
37545
|
+
if (isRuntimeNumber(v)) return [String.fromCharCode(Math.round(v))];
|
|
37546
|
+
if (isRuntimeTensor(v)) {
|
|
37547
|
+
const rows = v.shape.length >= 2 ? v.shape[0] ?? 1 : 1;
|
|
37548
|
+
const cols = v.shape.length >= 2 ? v.shape[1] ?? 0 : v.data.length;
|
|
37549
|
+
const out = [];
|
|
37550
|
+
for (let r = 0; r < rows; r++) {
|
|
37551
|
+
let s = "";
|
|
37552
|
+
for (let c = 0; c < cols; c++)
|
|
37553
|
+
s += String.fromCharCode(Math.round(v.data[c * rows + r]));
|
|
37554
|
+
out.push(s);
|
|
37555
|
+
}
|
|
37556
|
+
return out;
|
|
37557
|
+
}
|
|
37558
|
+
throw new RuntimeError("char: unsupported cell element type");
|
|
37559
|
+
}
|
|
37560
|
+
function charRowsToMatrix(rows) {
|
|
37561
|
+
if (rows.length === 0) return RTV.char("");
|
|
37562
|
+
const width = Math.max(...rows.map((r) => r.length));
|
|
37563
|
+
const padded = rows.map((r) => r.padEnd(width, " "));
|
|
37564
|
+
if (rows.length === 1) return RTV.char(padded[0]);
|
|
37565
|
+
return new RuntimeChar(padded.join(""), [rows.length, width]);
|
|
37566
|
+
}
|
|
37088
37567
|
registerIBuiltin({
|
|
37089
37568
|
name: "char",
|
|
37090
37569
|
resolve: (argTypes) => {
|
|
37091
37570
|
if (argTypes.length !== 1) return null;
|
|
37092
37571
|
const a = argTypes[0];
|
|
37093
|
-
if (a.kind !== "char" && a.kind !== "string" && a.kind !== "number" && a.kind !== "tensor")
|
|
37572
|
+
if (a.kind !== "char" && a.kind !== "string" && a.kind !== "number" && a.kind !== "tensor" && a.kind !== "cell")
|
|
37094
37573
|
return null;
|
|
37095
37574
|
return {
|
|
37096
37575
|
outputTypes: [{ kind: "char" }],
|
|
@@ -37107,6 +37586,11 @@ registerIBuiltin({
|
|
|
37107
37586
|
}
|
|
37108
37587
|
return RTV.char(chars.join(""));
|
|
37109
37588
|
}
|
|
37589
|
+
if (isRuntimeCell(v)) {
|
|
37590
|
+
const rows = [];
|
|
37591
|
+
for (const el of v.data) rows.push(...valueToCharRows(el));
|
|
37592
|
+
return charRowsToMatrix(rows);
|
|
37593
|
+
}
|
|
37110
37594
|
throw new RuntimeError("char: unsupported arguments");
|
|
37111
37595
|
}
|
|
37112
37596
|
};
|
|
@@ -37174,6 +37658,8 @@ registerIBuiltin({
|
|
|
37174
37658
|
if (!isTextType(argTypes[0]) || !isTextType(argTypes[1])) return null;
|
|
37175
37659
|
const outputTypes = [{ kind: "number" }];
|
|
37176
37660
|
if (nargout >= 2) outputTypes.push({ kind: "number" });
|
|
37661
|
+
if (nargout >= 3) outputTypes.push({ kind: "char" });
|
|
37662
|
+
if (nargout >= 4) outputTypes.push({ kind: "number" });
|
|
37177
37663
|
return {
|
|
37178
37664
|
outputTypes,
|
|
37179
37665
|
apply: (args, nout) => {
|
|
@@ -37183,6 +37669,7 @@ registerIBuiltin({
|
|
|
37183
37669
|
const results = [];
|
|
37184
37670
|
let strPos = 0;
|
|
37185
37671
|
let fmtPos = 0;
|
|
37672
|
+
let matchFailure = false;
|
|
37186
37673
|
while (fmtPos < fmt.length && strPos < str.length && results.length < maxCount) {
|
|
37187
37674
|
if (fmt[fmtPos] === "%") {
|
|
37188
37675
|
fmtPos++;
|
|
@@ -37194,22 +37681,34 @@ registerIBuiltin({
|
|
|
37194
37681
|
}
|
|
37195
37682
|
if (spec === "d" || spec === "i") {
|
|
37196
37683
|
const m = str.slice(strPos).match(/^[+-]?\d+/);
|
|
37197
|
-
if (!m)
|
|
37684
|
+
if (!m) {
|
|
37685
|
+
matchFailure = true;
|
|
37686
|
+
break;
|
|
37687
|
+
}
|
|
37198
37688
|
results.push(parseInt(m[0], 10));
|
|
37199
37689
|
strPos += m[0].length;
|
|
37200
37690
|
} else if (spec === "f" || spec === "e" || spec === "g") {
|
|
37201
37691
|
const m = str.slice(strPos).match(/^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/);
|
|
37202
|
-
if (!m)
|
|
37692
|
+
if (!m) {
|
|
37693
|
+
matchFailure = true;
|
|
37694
|
+
break;
|
|
37695
|
+
}
|
|
37203
37696
|
results.push(parseFloat(m[0]));
|
|
37204
37697
|
strPos += m[0].length;
|
|
37205
37698
|
} else if (spec === "x") {
|
|
37206
37699
|
const m = str.slice(strPos).match(/^[+-]?[0-9a-fA-F]+/);
|
|
37207
|
-
if (!m)
|
|
37700
|
+
if (!m) {
|
|
37701
|
+
matchFailure = true;
|
|
37702
|
+
break;
|
|
37703
|
+
}
|
|
37208
37704
|
results.push(parseInt(m[0], 16));
|
|
37209
37705
|
strPos += m[0].length;
|
|
37210
37706
|
} else if (spec === "o") {
|
|
37211
37707
|
const m = str.slice(strPos).match(/^[+-]?[0-7]+/);
|
|
37212
|
-
if (!m)
|
|
37708
|
+
if (!m) {
|
|
37709
|
+
matchFailure = true;
|
|
37710
|
+
break;
|
|
37711
|
+
}
|
|
37213
37712
|
results.push(parseInt(m[0], 8));
|
|
37214
37713
|
strPos += m[0].length;
|
|
37215
37714
|
} else if (spec === "c") {
|
|
@@ -37217,7 +37716,10 @@ registerIBuiltin({
|
|
|
37217
37716
|
strPos++;
|
|
37218
37717
|
} else if (spec === "s") {
|
|
37219
37718
|
const m = str.slice(strPos).match(/^\S+/);
|
|
37220
|
-
if (!m)
|
|
37719
|
+
if (!m) {
|
|
37720
|
+
matchFailure = true;
|
|
37721
|
+
break;
|
|
37722
|
+
}
|
|
37221
37723
|
for (let ci = 0; ci < m[0].length && results.length < maxCount; ci++) {
|
|
37222
37724
|
results.push(m[0].charCodeAt(ci));
|
|
37223
37725
|
}
|
|
@@ -37227,7 +37729,10 @@ registerIBuiltin({
|
|
|
37227
37729
|
fmtPos++;
|
|
37228
37730
|
while (strPos < str.length && /\s/.test(str[strPos])) strPos++;
|
|
37229
37731
|
} else {
|
|
37230
|
-
if (str[strPos] !== fmt[fmtPos])
|
|
37732
|
+
if (str[strPos] !== fmt[fmtPos]) {
|
|
37733
|
+
matchFailure = true;
|
|
37734
|
+
break;
|
|
37735
|
+
}
|
|
37231
37736
|
strPos++;
|
|
37232
37737
|
fmtPos++;
|
|
37233
37738
|
}
|
|
@@ -37237,7 +37742,16 @@ registerIBuiltin({
|
|
|
37237
37742
|
}
|
|
37238
37743
|
const vals = results.length === 1 ? RTV.num(results[0]) : RTV.tensor(allocFloat64Array(results), [results.length, 1]);
|
|
37239
37744
|
if (nout >= 2) {
|
|
37240
|
-
|
|
37745
|
+
const out = [vals, RTV.num(results.length)];
|
|
37746
|
+
if (nout >= 3) {
|
|
37747
|
+
out.push(
|
|
37748
|
+
RTV.char(matchFailure ? "Matching failure in format." : "")
|
|
37749
|
+
);
|
|
37750
|
+
}
|
|
37751
|
+
if (nout >= 4) {
|
|
37752
|
+
out.push(RTV.num(strPos + 1));
|
|
37753
|
+
}
|
|
37754
|
+
return out;
|
|
37241
37755
|
}
|
|
37242
37756
|
return vals;
|
|
37243
37757
|
}
|
|
@@ -38648,8 +39162,34 @@ function normImplTensor(v, args) {
|
|
|
38648
39162
|
return RTV.num(maxRowSum);
|
|
38649
39163
|
}
|
|
38650
39164
|
if (p2 === 2) {
|
|
39165
|
+
let anyNaN = false;
|
|
39166
|
+
let anyInf = false;
|
|
39167
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
39168
|
+
const re = v.data[i];
|
|
39169
|
+
const im = imag2 ? imag2[i] : 0;
|
|
39170
|
+
if (Number.isNaN(re) || Number.isNaN(im)) anyNaN = true;
|
|
39171
|
+
else if (!isFinite(re) || !isFinite(im)) anyInf = true;
|
|
39172
|
+
}
|
|
39173
|
+
if (anyNaN) return RTV.num(NaN);
|
|
39174
|
+
if (anyInf) return RTV.num(Infinity);
|
|
38651
39175
|
const bridge = getEffectiveBridge("norm", "svd");
|
|
38652
39176
|
if (bridge && bridge.svd) {
|
|
39177
|
+
if (imag2) {
|
|
39178
|
+
const R = allocFloat64Array(4 * rows * cols);
|
|
39179
|
+
const tm = 2 * rows;
|
|
39180
|
+
for (let j = 0; j < cols; j++) {
|
|
39181
|
+
for (let i = 0; i < rows; i++) {
|
|
39182
|
+
const a = v.data[j * rows + i];
|
|
39183
|
+
const b = imag2[j * rows + i];
|
|
39184
|
+
R[j * tm + i] = a;
|
|
39185
|
+
R[j * tm + (rows + i)] = b;
|
|
39186
|
+
R[(cols + j) * tm + i] = -b;
|
|
39187
|
+
R[(cols + j) * tm + (rows + i)] = a;
|
|
39188
|
+
}
|
|
39189
|
+
}
|
|
39190
|
+
const result2 = bridge.svd(R, tm, 2 * cols, false, false);
|
|
39191
|
+
return RTV.num(result2.S[0]);
|
|
39192
|
+
}
|
|
38653
39193
|
const f64 = v.data instanceof Float64Array ? v.data : allocFloat64Array(v.data);
|
|
38654
39194
|
const result = bridge.svd(f64, rows, cols, false, false);
|
|
38655
39195
|
return RTV.num(result.S[0]);
|
|
@@ -39409,6 +39949,100 @@ function svdApply(args, nargout) {
|
|
|
39409
39949
|
[k, 1]
|
|
39410
39950
|
);
|
|
39411
39951
|
}
|
|
39952
|
+
function nullApply(args) {
|
|
39953
|
+
let A = args[0];
|
|
39954
|
+
if (isRuntimeNumber(A) || isRuntimeComplexNumber(A)) {
|
|
39955
|
+
A = isRuntimeNumber(A) ? RTV.tensor(allocFloat64Array([A]), [1, 1]) : RTV.tensor(
|
|
39956
|
+
allocFloat64Array([A.re]),
|
|
39957
|
+
[1, 1],
|
|
39958
|
+
allocFloat64Array([A.im])
|
|
39959
|
+
);
|
|
39960
|
+
}
|
|
39961
|
+
if (!isRuntimeTensor(A))
|
|
39962
|
+
throw new RuntimeError("null: argument must be a numeric matrix");
|
|
39963
|
+
const [m, n] = tensorSize2D(A);
|
|
39964
|
+
const [, Sdiag, V] = svdApply([A], 3);
|
|
39965
|
+
const k = Math.min(m, n);
|
|
39966
|
+
const s = [];
|
|
39967
|
+
for (let i = 0; i < k; i++) s.push(Sdiag.data[colMajorIndex(i, i, m)]);
|
|
39968
|
+
const maxS = s.length > 0 ? Math.max(...s) : 0;
|
|
39969
|
+
const tol = args.length > 1 && args[1] !== void 0 ? toNumber(args[1]) : Math.max(m, n) * epsOf(maxS);
|
|
39970
|
+
let r = 0;
|
|
39971
|
+
for (const sv of s) if (sv > tol) r++;
|
|
39972
|
+
const cols = n - r;
|
|
39973
|
+
const out = allocFloat64Array(n * cols);
|
|
39974
|
+
const outImag = V.imag ? allocFloat64Array(n * cols) : void 0;
|
|
39975
|
+
for (let c = 0; c < cols; c++) {
|
|
39976
|
+
for (let i = 0; i < n; i++) {
|
|
39977
|
+
const src = colMajorIndex(i, r + c, n);
|
|
39978
|
+
out[colMajorIndex(i, c, n)] = V.data[src];
|
|
39979
|
+
if (outImag) outImag[colMajorIndex(i, c, n)] = V.imag[src];
|
|
39980
|
+
}
|
|
39981
|
+
}
|
|
39982
|
+
return RTV.tensor(out, [n, cols], outImag);
|
|
39983
|
+
}
|
|
39984
|
+
registerIBuiltin({
|
|
39985
|
+
name: "null",
|
|
39986
|
+
resolve: (argTypes, nargout) => {
|
|
39987
|
+
if (nargout > 1 || argTypes.length < 1 || argTypes.length > 2) return null;
|
|
39988
|
+
if (!isNumericJitType(argTypes[0])) return null;
|
|
39989
|
+
const isComplex = argTypes[0].kind === "tensor" && argTypes[0].isComplex;
|
|
39990
|
+
return {
|
|
39991
|
+
outputTypes: [tensorType(isComplex || void 0)],
|
|
39992
|
+
apply: (args) => nullApply(args)
|
|
39993
|
+
};
|
|
39994
|
+
}
|
|
39995
|
+
});
|
|
39996
|
+
function computeBandwidth(A) {
|
|
39997
|
+
let lower = 0;
|
|
39998
|
+
let upper = 0;
|
|
39999
|
+
const note = (i, j) => {
|
|
40000
|
+
if (i > j) lower = Math.max(lower, i - j);
|
|
40001
|
+
else if (j > i) upper = Math.max(upper, j - i);
|
|
40002
|
+
};
|
|
40003
|
+
if (isRuntimeNumber(A) || isRuntimeComplexNumber(A)) return [0, 0];
|
|
40004
|
+
if (isRuntimeSparseMatrix(A)) {
|
|
40005
|
+
for (let j = 0; j < A.n; j++) {
|
|
40006
|
+
for (let k = A.jc[j]; k < A.jc[j + 1]; k++) {
|
|
40007
|
+
if (A.pr[k] === 0 && (!A.pi || A.pi[k] === 0)) continue;
|
|
40008
|
+
note(A.ir[k], j);
|
|
40009
|
+
}
|
|
40010
|
+
}
|
|
40011
|
+
return [lower, upper];
|
|
40012
|
+
}
|
|
40013
|
+
if (isRuntimeTensor(A)) {
|
|
40014
|
+
const [m, n] = tensorSize2D(A);
|
|
40015
|
+
for (let j = 0; j < n; j++) {
|
|
40016
|
+
for (let i = 0; i < m; i++) {
|
|
40017
|
+
const idx = colMajorIndex(i, j, m);
|
|
40018
|
+
if (A.data[idx] === 0 && (!A.imag || A.imag[idx] === 0)) continue;
|
|
40019
|
+
note(i, j);
|
|
40020
|
+
}
|
|
40021
|
+
}
|
|
40022
|
+
return [lower, upper];
|
|
40023
|
+
}
|
|
40024
|
+
throw new RuntimeError("bandwidth: first argument must be a numeric matrix");
|
|
40025
|
+
}
|
|
40026
|
+
function bandwidthApply(args, nargout) {
|
|
40027
|
+
const [lower, upper] = computeBandwidth(args[0]);
|
|
40028
|
+
if (args.length >= 2 && args[1] !== void 0) {
|
|
40029
|
+
const type = parseStringArgLower(args[1]);
|
|
40030
|
+
if (type === "lower") return RTV.num(lower);
|
|
40031
|
+
if (type === "upper") return RTV.num(upper);
|
|
40032
|
+
throw new RuntimeError("bandwidth: TYPE must be 'lower' or 'upper'");
|
|
40033
|
+
}
|
|
40034
|
+
if (nargout >= 2) return [RTV.num(lower), RTV.num(upper)];
|
|
40035
|
+
return RTV.num(lower);
|
|
40036
|
+
}
|
|
40037
|
+
registerIBuiltin({
|
|
40038
|
+
name: "bandwidth",
|
|
40039
|
+
resolve: (argTypes, nargout) => {
|
|
40040
|
+
if (nargout > 2 || argTypes.length < 1 || argTypes.length > 2) return null;
|
|
40041
|
+
if (!isNumericJitType(argTypes[0])) return null;
|
|
40042
|
+
const outs = nargout >= 2 ? [NUM, NUM] : [NUM];
|
|
40043
|
+
return { outputTypes: outs, apply: (args, n) => bandwidthApply(args, n) };
|
|
40044
|
+
}
|
|
40045
|
+
});
|
|
39412
40046
|
function computeATA(A_data, m, n) {
|
|
39413
40047
|
const result = allocFloat64Array(n * n);
|
|
39414
40048
|
for (let j = 0; j < n; j++)
|
|
@@ -41279,6 +41913,33 @@ function validateSizeArg(x) {
|
|
|
41279
41913
|
}
|
|
41280
41914
|
return x < 0 ? 0 : x;
|
|
41281
41915
|
}
|
|
41916
|
+
function parseReshapeDims(args, total) {
|
|
41917
|
+
let rawDims;
|
|
41918
|
+
if (args.length === 2 && isRuntimeTensor(args[1]) && args[1].data.length > 1) {
|
|
41919
|
+
rawDims = Array.from(args[1].data).map((x) => validateSizeArg(x));
|
|
41920
|
+
} else {
|
|
41921
|
+
rawDims = args.slice(1).map((a) => {
|
|
41922
|
+
if (isRuntimeTensor(a) && a.data.length === 0) return null;
|
|
41923
|
+
return validateSizeArg(toNumber(a));
|
|
41924
|
+
});
|
|
41925
|
+
}
|
|
41926
|
+
const autoCount = rawDims.filter((d) => d === null).length;
|
|
41927
|
+
if (autoCount > 1)
|
|
41928
|
+
throw new RuntimeError("reshape: only one dimension size can be []");
|
|
41929
|
+
let shape;
|
|
41930
|
+
if (autoCount === 1) {
|
|
41931
|
+
const known = rawDims.filter((d) => d !== null);
|
|
41932
|
+
const knownProduct = known.reduce((a, b) => a * b, 1);
|
|
41933
|
+
if (knownProduct === 0 || total % knownProduct !== 0)
|
|
41934
|
+
throw new RuntimeError("reshape: number of elements must not change");
|
|
41935
|
+
shape = rawDims.map((d) => d === null ? total / knownProduct : d);
|
|
41936
|
+
} else {
|
|
41937
|
+
shape = rawDims;
|
|
41938
|
+
}
|
|
41939
|
+
if (numel(shape) !== total)
|
|
41940
|
+
throw new RuntimeError("reshape: number of elements must not change");
|
|
41941
|
+
return shape;
|
|
41942
|
+
}
|
|
41282
41943
|
defineBuiltin({
|
|
41283
41944
|
name: "reshape",
|
|
41284
41945
|
cases: [
|
|
@@ -41290,31 +41951,31 @@ defineBuiltin({
|
|
|
41290
41951
|
const v = args[0];
|
|
41291
41952
|
if (isRuntimeSparseMatrix(v)) {
|
|
41292
41953
|
const totalEl = v.m * v.n;
|
|
41293
|
-
let
|
|
41954
|
+
let rawDims;
|
|
41294
41955
|
if (args.length === 2 && isRuntimeTensor(args[1]) && args[1].data.length > 1) {
|
|
41295
|
-
|
|
41956
|
+
rawDims = Array.from(args[1].data).map((x) => Math.round(x));
|
|
41296
41957
|
} else {
|
|
41297
|
-
|
|
41958
|
+
rawDims = args.slice(1).map((a) => {
|
|
41298
41959
|
if (isRuntimeTensor(a) && a.data.length === 0) return null;
|
|
41299
41960
|
return Math.round(toNumber(a));
|
|
41300
41961
|
});
|
|
41301
41962
|
}
|
|
41302
|
-
const
|
|
41303
|
-
if (
|
|
41963
|
+
const autoCount = rawDims.filter((d) => d === null).length;
|
|
41964
|
+
if (autoCount > 1)
|
|
41304
41965
|
throw new RuntimeError(
|
|
41305
41966
|
"reshape: only one dimension size can be []"
|
|
41306
41967
|
);
|
|
41307
41968
|
let shape2;
|
|
41308
|
-
if (
|
|
41309
|
-
const known =
|
|
41969
|
+
if (autoCount === 1) {
|
|
41970
|
+
const known = rawDims.filter((d) => d !== null);
|
|
41310
41971
|
const knownProduct = known.reduce((a, b) => a * b, 1);
|
|
41311
41972
|
if (totalEl % knownProduct !== 0)
|
|
41312
41973
|
throw new RuntimeError(
|
|
41313
41974
|
"reshape: number of elements must not change"
|
|
41314
41975
|
);
|
|
41315
|
-
shape2 =
|
|
41976
|
+
shape2 = rawDims.map((d) => d === null ? totalEl / knownProduct : d);
|
|
41316
41977
|
} else {
|
|
41317
|
-
shape2 =
|
|
41978
|
+
shape2 = rawDims;
|
|
41318
41979
|
}
|
|
41319
41980
|
if (shape2.length !== 2)
|
|
41320
41981
|
throw new RuntimeError("reshape: sparse matrices must be 2-D");
|
|
@@ -41352,40 +42013,32 @@ defineBuiltin({
|
|
|
41352
42013
|
jc[newN] = ti;
|
|
41353
42014
|
return RTV.sparseMatrix(newM, newN, ir, jc, pr, pi2);
|
|
41354
42015
|
}
|
|
42016
|
+
if (isRuntimeChar(v)) {
|
|
42017
|
+
const srcRows = v.shape ? v.shape[0] : 1;
|
|
42018
|
+
const srcCols = v.shape ? v.shape[1] ?? 0 : v.value.length;
|
|
42019
|
+
const total = v.value.length;
|
|
42020
|
+
const reqShape = parseReshapeDims(args, total);
|
|
42021
|
+
const s = [...reqShape];
|
|
42022
|
+
while (s.length > 2 && s[s.length - 1] === 1) s.pop();
|
|
42023
|
+
if (s.length > 2)
|
|
42024
|
+
throw new RuntimeError("reshape: char arrays must be 2-D");
|
|
42025
|
+
const nr = s[0];
|
|
42026
|
+
const nc = s.length >= 2 ? s[1] : 1;
|
|
42027
|
+
const linear = new Array(total);
|
|
42028
|
+
for (let j = 0; j < srcCols; j++)
|
|
42029
|
+
for (let i = 0; i < srcRows; i++)
|
|
42030
|
+
linear[j * srcRows + i] = v.value[i * srcCols + j];
|
|
42031
|
+
const chars = new Array(total);
|
|
42032
|
+
for (let j2 = 0; j2 < nc; j2++)
|
|
42033
|
+
for (let i2 = 0; i2 < nr; i2++)
|
|
42034
|
+
chars[i2 * nc + j2] = linear[j2 * nr + i2];
|
|
42035
|
+
return new RuntimeChar(chars.join(""), [nr, nc]);
|
|
42036
|
+
}
|
|
41355
42037
|
if (!isRuntimeTensor(v) && !isRuntimeNumber(v) && !isRuntimeComplexNumber(v))
|
|
41356
42038
|
throw new RuntimeError("reshape: first argument must be numeric");
|
|
41357
42039
|
const data = isRuntimeTensor(v) ? v.data : isRuntimeComplexNumber(v) ? allocFloat64Array([v.re]) : allocFloat64Array([v]);
|
|
41358
42040
|
const imag2 = isRuntimeTensor(v) ? v.imag : isRuntimeComplexNumber(v) ? allocFloat64Array([v.im]) : void 0;
|
|
41359
|
-
|
|
41360
|
-
if (args.length === 2 && isRuntimeTensor(args[1]) && args[1].data.length > 1) {
|
|
41361
|
-
rawDims = Array.from(args[1].data).map((x) => validateSizeArg(x));
|
|
41362
|
-
} else {
|
|
41363
|
-
rawDims = args.slice(1).map((a) => {
|
|
41364
|
-
if (isRuntimeTensor(a) && a.data.length === 0) return null;
|
|
41365
|
-
return validateSizeArg(toNumber(a));
|
|
41366
|
-
});
|
|
41367
|
-
}
|
|
41368
|
-
const autoCount = rawDims.filter((d) => d === null).length;
|
|
41369
|
-
if (autoCount > 1)
|
|
41370
|
-
throw new RuntimeError("reshape: only one dimension size can be []");
|
|
41371
|
-
let shape;
|
|
41372
|
-
if (autoCount === 1) {
|
|
41373
|
-
const known = rawDims.filter((d) => d !== null);
|
|
41374
|
-
const knownProduct = known.reduce((a, b) => a * b, 1);
|
|
41375
|
-
if (data.length % knownProduct !== 0)
|
|
41376
|
-
throw new RuntimeError(
|
|
41377
|
-
"reshape: number of elements must not change"
|
|
41378
|
-
);
|
|
41379
|
-
shape = rawDims.map(
|
|
41380
|
-
(d) => d === null ? data.length / knownProduct : d
|
|
41381
|
-
);
|
|
41382
|
-
} else {
|
|
41383
|
-
shape = rawDims;
|
|
41384
|
-
}
|
|
41385
|
-
const n = numel(shape);
|
|
41386
|
-
if (n !== data.length) {
|
|
41387
|
-
throw new RuntimeError("reshape: number of elements must not change");
|
|
41388
|
-
}
|
|
42041
|
+
const shape = parseReshapeDims(args, data.length);
|
|
41389
42042
|
if (isRuntimeTensor(v)) {
|
|
41390
42043
|
const dataCopy = allocFloat64Array(data);
|
|
41391
42044
|
const imagCopy = imag2 ? allocFloat64Array(imag2) : void 0;
|
|
@@ -41797,6 +42450,35 @@ defineBuiltin({
|
|
|
41797
42450
|
}
|
|
41798
42451
|
]
|
|
41799
42452
|
});
|
|
42453
|
+
function repmatObjects(v, repArgs) {
|
|
42454
|
+
const srcElements = isRuntimeClassInstanceArray(v) ? v.elements : [v];
|
|
42455
|
+
const [rows, cols] = isRuntimeClassInstanceArray(v) ? v.shape : [1, 1];
|
|
42456
|
+
const className = v.className;
|
|
42457
|
+
let reps;
|
|
42458
|
+
if (repArgs.length === 1) {
|
|
42459
|
+
const arg1 = repArgs[0];
|
|
42460
|
+
if (isRuntimeTensor(arg1)) {
|
|
42461
|
+
reps = Array.from(arg1.data).map((x) => validateSizeArg(x));
|
|
42462
|
+
} else {
|
|
42463
|
+
const n = validateSizeArg(toNumber(arg1));
|
|
42464
|
+
reps = [n, n];
|
|
42465
|
+
}
|
|
42466
|
+
} else {
|
|
42467
|
+
reps = repArgs.map((a) => validateSizeArg(toNumber(a)));
|
|
42468
|
+
}
|
|
42469
|
+
const rRep = reps[0] ?? 1;
|
|
42470
|
+
const cRep = reps.length >= 2 ? reps[1] : reps[0] ?? 1;
|
|
42471
|
+
const newRows = rows * rRep;
|
|
42472
|
+
const newCols = cols * cRep;
|
|
42473
|
+
const out = new Array(Math.max(0, newRows * newCols));
|
|
42474
|
+
for (let J = 0; J < newCols; J++) {
|
|
42475
|
+
for (let I = 0; I < newRows; I++) {
|
|
42476
|
+
const src = srcElements[I % rows + J % cols * rows];
|
|
42477
|
+
out[I + J * newRows] = copyClassInstance(src);
|
|
42478
|
+
}
|
|
42479
|
+
}
|
|
42480
|
+
return out.length === 1 ? out[0] : RTV.classInstanceArray(className, out, [newRows, newCols]);
|
|
42481
|
+
}
|
|
41800
42482
|
defineBuiltin({
|
|
41801
42483
|
name: "repmat",
|
|
41802
42484
|
cases: [
|
|
@@ -41821,6 +42503,8 @@ defineBuiltin({
|
|
|
41821
42503
|
if (args.length < 2)
|
|
41822
42504
|
throw new RuntimeError("repmat requires at least 2 arguments");
|
|
41823
42505
|
let v = args[0];
|
|
42506
|
+
if (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v))
|
|
42507
|
+
return repmatObjects(v, args.slice(1));
|
|
41824
42508
|
if (isRuntimeSparseMatrix(v)) v = sparseToDense(v);
|
|
41825
42509
|
let reps;
|
|
41826
42510
|
if (args.length === 2) {
|
|
@@ -41985,6 +42669,62 @@ defineBuiltin({
|
|
|
41985
42669
|
}
|
|
41986
42670
|
]
|
|
41987
42671
|
});
|
|
42672
|
+
function copyClassInstance(inst) {
|
|
42673
|
+
if (inst.isHandleClass) return inst;
|
|
42674
|
+
return new RuntimeClassInstance(
|
|
42675
|
+
inst.className,
|
|
42676
|
+
new Map(inst.fields),
|
|
42677
|
+
inst.isHandleClass,
|
|
42678
|
+
inst._builtinData
|
|
42679
|
+
);
|
|
42680
|
+
}
|
|
42681
|
+
function repelemObjects(v, repArgs) {
|
|
42682
|
+
const srcElements = isRuntimeClassInstanceArray(v) ? v.elements : [v];
|
|
42683
|
+
const [rows, cols] = isRuntimeClassInstanceArray(v) ? v.shape : [1, 1];
|
|
42684
|
+
const className = v.className;
|
|
42685
|
+
const wrap = (elements, shape) => elements.length === 1 ? elements[0] : RTV.classInstanceArray(className, elements, shape);
|
|
42686
|
+
if (repArgs.length === 1) {
|
|
42687
|
+
const repArg = repArgs[0];
|
|
42688
|
+
if (isRuntimeTensor(repArg) && repArg.data.length > 1) {
|
|
42689
|
+
const counts = repArg.data;
|
|
42690
|
+
if (counts.length !== srcElements.length)
|
|
42691
|
+
throw new RuntimeError(
|
|
42692
|
+
`repelem: counts vector length (${counts.length}) must match the number of elements (${srcElements.length})`
|
|
42693
|
+
);
|
|
42694
|
+
const out3 = [];
|
|
42695
|
+
for (let i = 0; i < srcElements.length; i++) {
|
|
42696
|
+
const c = Math.max(0, Math.round(counts[i]));
|
|
42697
|
+
for (let j = 0; j < c; j++) out3.push(copyClassInstance(srcElements[i]));
|
|
42698
|
+
}
|
|
42699
|
+
const isCol2 = cols === 1 && rows !== 1;
|
|
42700
|
+
return wrap(out3, isCol2 ? [out3.length, 1] : [1, out3.length]);
|
|
42701
|
+
}
|
|
42702
|
+
const n = Math.max(0, Math.round(toNumber(repArg)));
|
|
42703
|
+
const out2 = [];
|
|
42704
|
+
for (const el of srcElements)
|
|
42705
|
+
for (let j = 0; j < n; j++) out2.push(copyClassInstance(el));
|
|
42706
|
+
const isCol = cols === 1 && rows !== 1;
|
|
42707
|
+
return wrap(out2, isCol ? [out2.length, 1] : [1, out2.length]);
|
|
42708
|
+
}
|
|
42709
|
+
const rRep = Math.max(0, Math.round(toNumber(repArgs[0])));
|
|
42710
|
+
const cRep = Math.max(0, Math.round(toNumber(repArgs[1])));
|
|
42711
|
+
const newRows = rows * rRep;
|
|
42712
|
+
const newCols = cols * cRep;
|
|
42713
|
+
const out = new Array(newRows * newCols);
|
|
42714
|
+
for (let c = 0; c < cols; c++) {
|
|
42715
|
+
for (let r = 0; r < rows; r++) {
|
|
42716
|
+
const src = srcElements[c * rows + r];
|
|
42717
|
+
for (let dc = 0; dc < cRep; dc++) {
|
|
42718
|
+
for (let dr = 0; dr < rRep; dr++) {
|
|
42719
|
+
const dstRow = r * rRep + dr;
|
|
42720
|
+
const dstCol = c * cRep + dc;
|
|
42721
|
+
out[dstCol * newRows + dstRow] = copyClassInstance(src);
|
|
42722
|
+
}
|
|
42723
|
+
}
|
|
42724
|
+
}
|
|
42725
|
+
}
|
|
42726
|
+
return wrap(out, [newRows, newCols]);
|
|
42727
|
+
}
|
|
41988
42728
|
defineBuiltin({
|
|
41989
42729
|
name: "repelem",
|
|
41990
42730
|
cases: [
|
|
@@ -41994,6 +42734,8 @@ defineBuiltin({
|
|
|
41994
42734
|
if (args.length < 2)
|
|
41995
42735
|
throw new RuntimeError("repelem requires at least 2 arguments");
|
|
41996
42736
|
const v = args[0];
|
|
42737
|
+
if (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v))
|
|
42738
|
+
return repelemObjects(v, args.slice(1));
|
|
41997
42739
|
if (args.length === 2) {
|
|
41998
42740
|
const repArg = args[1];
|
|
41999
42741
|
if (isRuntimeTensor(repArg) && repArg.data.length > 1) {
|
|
@@ -42116,7 +42858,15 @@ defineBuiltin({
|
|
|
42116
42858
|
}
|
|
42117
42859
|
return RTV.tensor(dataCopy, newShape, imagCopy);
|
|
42118
42860
|
}
|
|
42119
|
-
|
|
42861
|
+
if (isRuntimeCell(v)) {
|
|
42862
|
+
const shape = [...v.shape];
|
|
42863
|
+
while (shape.length > 2 && shape[shape.length - 1] === 1) shape.pop();
|
|
42864
|
+
if (shape.length <= 2) return RTV.cell(v.data, shape);
|
|
42865
|
+
const newShape = shape.filter((d) => d !== 1);
|
|
42866
|
+
while (newShape.length < 2) newShape.push(1);
|
|
42867
|
+
return RTV.cell(v.data, newShape);
|
|
42868
|
+
}
|
|
42869
|
+
return v;
|
|
42120
42870
|
}
|
|
42121
42871
|
}
|
|
42122
42872
|
]
|
|
@@ -42786,6 +43536,8 @@ defineBuiltin({
|
|
|
42786
43536
|
]
|
|
42787
43537
|
});
|
|
42788
43538
|
function bitwiseOp(a, b, op, name) {
|
|
43539
|
+
if (typeof a === "boolean") a = a ? 1 : 0;
|
|
43540
|
+
if (typeof b === "boolean") b = b ? 1 : 0;
|
|
42789
43541
|
if (isRuntimeNumber(a) && isRuntimeNumber(b)) {
|
|
42790
43542
|
return RTV.num(op(Math.round(a), Math.round(b)));
|
|
42791
43543
|
}
|
|
@@ -45053,6 +45805,56 @@ defineBuiltin({
|
|
|
45053
45805
|
}
|
|
45054
45806
|
]
|
|
45055
45807
|
});
|
|
45808
|
+
function froundArray(src) {
|
|
45809
|
+
const out = allocFloat64Array(src.length);
|
|
45810
|
+
for (let i = 0; i < src.length; i++) out[i] = Math.fround(src[i]);
|
|
45811
|
+
return out;
|
|
45812
|
+
}
|
|
45813
|
+
function singleApply(v) {
|
|
45814
|
+
if (isRuntimeChar(v)) {
|
|
45815
|
+
if (v.value.length === 0) return RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
45816
|
+
if (v.value.length === 1)
|
|
45817
|
+
return RTV.num(Math.fround(v.value.charCodeAt(0)));
|
|
45818
|
+
return RTV.row(Array.from(v.value).map((c) => Math.fround(c.charCodeAt(0))));
|
|
45819
|
+
}
|
|
45820
|
+
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
45821
|
+
if (isRuntimeNumber(v)) return RTV.num(Math.fround(v));
|
|
45822
|
+
if (isRuntimeComplexNumber(v))
|
|
45823
|
+
return RTV.complex(Math.fround(v.re), Math.fround(v.im));
|
|
45824
|
+
if (isRuntimeTensor(v)) {
|
|
45825
|
+
const imag2 = v.imag ? froundArray(v.imag) : void 0;
|
|
45826
|
+
return RTV.tensor(froundArray(v.data), v.shape.slice(), imag2);
|
|
45827
|
+
}
|
|
45828
|
+
if (isRuntimeClassInstance(v) && v._builtinData !== void 0)
|
|
45829
|
+
return singleApply(v._builtinData);
|
|
45830
|
+
return RTV.num(Math.fround(toNumber(v)));
|
|
45831
|
+
}
|
|
45832
|
+
defineBuiltin({
|
|
45833
|
+
name: "single",
|
|
45834
|
+
cases: [
|
|
45835
|
+
{
|
|
45836
|
+
match: (argTypes) => {
|
|
45837
|
+
if (argTypes.length !== 1) return null;
|
|
45838
|
+
const a = argTypes[0];
|
|
45839
|
+
if (a.kind === "number" || a.kind === "boolean" || a.kind === "char" || a.kind === "class_instance")
|
|
45840
|
+
return [{ kind: "number" }];
|
|
45841
|
+
if (a.kind === "complex_or_number")
|
|
45842
|
+
return [{ kind: "complex_or_number" }];
|
|
45843
|
+
if (a.kind === "tensor")
|
|
45844
|
+
return [
|
|
45845
|
+
{
|
|
45846
|
+
kind: "tensor",
|
|
45847
|
+
isComplex: a.isComplex,
|
|
45848
|
+
shape: a.shape,
|
|
45849
|
+
ndim: a.ndim
|
|
45850
|
+
}
|
|
45851
|
+
];
|
|
45852
|
+
return null;
|
|
45853
|
+
},
|
|
45854
|
+
apply: (args) => singleApply(args[0])
|
|
45855
|
+
}
|
|
45856
|
+
]
|
|
45857
|
+
});
|
|
45056
45858
|
var INT_RANGES = [
|
|
45057
45859
|
{ name: "int8", min: -128, max: 127 },
|
|
45058
45860
|
{ name: "int16", min: -32768, max: 32767 },
|
|
@@ -45607,11 +46409,20 @@ defineBuiltin({
|
|
|
45607
46409
|
},
|
|
45608
46410
|
apply: (args) => {
|
|
45609
46411
|
const v = args[0];
|
|
45610
|
-
|
|
45611
|
-
|
|
45612
|
-
|
|
45613
|
-
return
|
|
45614
|
-
|
|
46412
|
+
const hasField = (name) => {
|
|
46413
|
+
if (isRuntimeStructArray(v)) return v.fieldNames.includes(name);
|
|
46414
|
+
if (!isRuntimeStruct(v) && !isRuntimeClassInstance(v)) return false;
|
|
46415
|
+
return v.fields.has(name);
|
|
46416
|
+
};
|
|
46417
|
+
if (isRuntimeCell(args[1])) {
|
|
46418
|
+
const cell = args[1];
|
|
46419
|
+
const result = allocFloat64Array(cell.data.length);
|
|
46420
|
+
for (let i = 0; i < cell.data.length; i++) {
|
|
46421
|
+
result[i] = hasField(toString(cell.data[i])) ? 1 : 0;
|
|
46422
|
+
}
|
|
46423
|
+
return new RuntimeTensor(result, cell.shape.slice(), void 0, true);
|
|
46424
|
+
}
|
|
46425
|
+
return RTV.logical(hasField(toString(args[1])));
|
|
45615
46426
|
}
|
|
45616
46427
|
}
|
|
45617
46428
|
]
|
|
@@ -45728,7 +46539,7 @@ function regexpImpl(caseSensitive, name, args, nargout) {
|
|
|
45728
46539
|
if (outModes.length === 0) {
|
|
45729
46540
|
outModes.push("start", "end", "tokenextents", "match", "tokens", "names");
|
|
45730
46541
|
}
|
|
45731
|
-
const flags = caseSensitive ? "
|
|
46542
|
+
const flags = caseSensitive ? "gs" : "gis";
|
|
45732
46543
|
const re = new RegExp(pat, flags);
|
|
45733
46544
|
const starts = [];
|
|
45734
46545
|
const ends = [];
|
|
@@ -46448,6 +47259,13 @@ registerIBuiltin({
|
|
|
46448
47259
|
if (args.length === 1) return RTV.cell([A], [1, 1]);
|
|
46449
47260
|
A = RTV.tensor(allocFloat64Array([A ? 1 : 0]), [1, 1]);
|
|
46450
47261
|
}
|
|
47262
|
+
if (isRuntimeStruct(A)) {
|
|
47263
|
+
return RTV.cell([A], [1, 1]);
|
|
47264
|
+
}
|
|
47265
|
+
if (isRuntimeStructArray(A)) {
|
|
47266
|
+
const elems = A.elements;
|
|
47267
|
+
return RTV.cell([...elems], [1, elems.length]);
|
|
47268
|
+
}
|
|
46451
47269
|
if (!isRuntimeTensor(A))
|
|
46452
47270
|
throw new RuntimeError(
|
|
46453
47271
|
"num2cell: first argument must be a numeric array"
|
|
@@ -46571,6 +47389,69 @@ registerIBuiltin({
|
|
|
46571
47389
|
};
|
|
46572
47390
|
}
|
|
46573
47391
|
});
|
|
47392
|
+
registerIBuiltin({
|
|
47393
|
+
name: "getfield",
|
|
47394
|
+
resolve: (argTypes) => {
|
|
47395
|
+
if (argTypes.length < 2) return null;
|
|
47396
|
+
return {
|
|
47397
|
+
outputTypes: [{ kind: "unknown" }],
|
|
47398
|
+
apply: (args) => {
|
|
47399
|
+
let v = args[0];
|
|
47400
|
+
for (let i = 1; i < args.length; i++) {
|
|
47401
|
+
if (isRuntimeCell(args[i]))
|
|
47402
|
+
throw new RuntimeError(
|
|
47403
|
+
"getfield: index ({}) subscripts are not supported"
|
|
47404
|
+
);
|
|
47405
|
+
if (!isRuntimeStruct(v))
|
|
47406
|
+
throw new RuntimeError("getfield: argument must be a structure");
|
|
47407
|
+
const name = toString(args[i]);
|
|
47408
|
+
if (!v.fields.has(name))
|
|
47409
|
+
throw new RuntimeError(
|
|
47410
|
+
`Reference to non-existent field '${name}'.`
|
|
47411
|
+
);
|
|
47412
|
+
v = v.fields.get(name);
|
|
47413
|
+
}
|
|
47414
|
+
return v;
|
|
47415
|
+
}
|
|
47416
|
+
};
|
|
47417
|
+
}
|
|
47418
|
+
});
|
|
47419
|
+
registerIBuiltin({
|
|
47420
|
+
name: "setfield",
|
|
47421
|
+
resolve: (argTypes) => {
|
|
47422
|
+
if (argTypes.length < 3) return null;
|
|
47423
|
+
return {
|
|
47424
|
+
outputTypes: [{ kind: "struct", fields: {} }],
|
|
47425
|
+
apply: (args) => {
|
|
47426
|
+
const value = args[args.length - 1];
|
|
47427
|
+
const fieldArgs = args.slice(1, args.length - 1);
|
|
47428
|
+
const setChain = (s, depth) => {
|
|
47429
|
+
const fa = fieldArgs[depth];
|
|
47430
|
+
if (isRuntimeCell(fa))
|
|
47431
|
+
throw new RuntimeError(
|
|
47432
|
+
"setfield: index ({}) subscripts are not supported"
|
|
47433
|
+
);
|
|
47434
|
+
const name = toString(fa);
|
|
47435
|
+
const base = isRuntimeStruct(s) ? s.fields : /* @__PURE__ */ new Map();
|
|
47436
|
+
if (!isRuntimeStruct(s) && !(isRuntimeTensor(s) && s.data.length === 0))
|
|
47437
|
+
throw new RuntimeError("setfield: argument must be a structure");
|
|
47438
|
+
const newFields = new Map(base);
|
|
47439
|
+
if (depth === fieldArgs.length - 1) {
|
|
47440
|
+
newFields.set(name, value);
|
|
47441
|
+
} else {
|
|
47442
|
+
const child = newFields.get(name);
|
|
47443
|
+
newFields.set(
|
|
47444
|
+
name,
|
|
47445
|
+
setChain(child ?? RTV.struct(/* @__PURE__ */ new Map()), depth + 1)
|
|
47446
|
+
);
|
|
47447
|
+
}
|
|
47448
|
+
return RTV.struct(newFields);
|
|
47449
|
+
};
|
|
47450
|
+
return setChain(args[0], 0);
|
|
47451
|
+
}
|
|
47452
|
+
};
|
|
47453
|
+
}
|
|
47454
|
+
});
|
|
46574
47455
|
registerIBuiltin({
|
|
46575
47456
|
name: "namedargs2cell",
|
|
46576
47457
|
resolve: (argTypes) => {
|
|
@@ -46592,6 +47473,10 @@ registerIBuiltin({
|
|
|
46592
47473
|
};
|
|
46593
47474
|
}
|
|
46594
47475
|
});
|
|
47476
|
+
function rmfieldNames(arg) {
|
|
47477
|
+
if (isRuntimeCell(arg)) return arg.data.map(toString);
|
|
47478
|
+
return [toString(arg)];
|
|
47479
|
+
}
|
|
46595
47480
|
registerIBuiltin({
|
|
46596
47481
|
name: "rmfield",
|
|
46597
47482
|
resolve: (argTypes) => {
|
|
@@ -46600,25 +47485,26 @@ registerIBuiltin({
|
|
|
46600
47485
|
outputTypes: [{ kind: "struct", fields: {} }],
|
|
46601
47486
|
apply: (args) => {
|
|
46602
47487
|
const v = args[0];
|
|
47488
|
+
const names = rmfieldNames(args[1]);
|
|
46603
47489
|
if (isRuntimeStructArray(v)) {
|
|
46604
|
-
const
|
|
46605
|
-
|
|
46606
|
-
|
|
46607
|
-
const newFieldNames = v.fieldNames.filter((n) => n
|
|
47490
|
+
for (const name of names)
|
|
47491
|
+
if (!v.fieldNames.includes(name))
|
|
47492
|
+
throw new RuntimeError(`rmfield: field '${name}' does not exist`);
|
|
47493
|
+
const newFieldNames = v.fieldNames.filter((n) => !names.includes(n));
|
|
46608
47494
|
const newElements = v.elements.map((el) => {
|
|
46609
47495
|
const newFields2 = new Map(el.fields);
|
|
46610
|
-
newFields2.delete(
|
|
47496
|
+
for (const name of names) newFields2.delete(name);
|
|
46611
47497
|
return RTV.struct(newFields2);
|
|
46612
47498
|
});
|
|
46613
47499
|
return RTV.structArray(newFieldNames, newElements);
|
|
46614
47500
|
}
|
|
46615
47501
|
if (!isRuntimeStruct(v))
|
|
46616
47502
|
throw new RuntimeError("rmfield: first argument must be a struct");
|
|
46617
|
-
const name
|
|
46618
|
-
|
|
46619
|
-
|
|
47503
|
+
for (const name of names)
|
|
47504
|
+
if (!v.fields.has(name))
|
|
47505
|
+
throw new RuntimeError(`rmfield: field '${name}' does not exist`);
|
|
46620
47506
|
const newFields = new Map(v.fields);
|
|
46621
|
-
newFields.delete(name);
|
|
47507
|
+
for (const name of names) newFields.delete(name);
|
|
46622
47508
|
return RTV.struct(newFields);
|
|
46623
47509
|
}
|
|
46624
47510
|
};
|
|
@@ -47259,6 +48145,23 @@ registerIBuiltin({
|
|
|
47259
48145
|
}
|
|
47260
48146
|
})
|
|
47261
48147
|
});
|
|
48148
|
+
registerIBuiltin({
|
|
48149
|
+
name: "spalloc",
|
|
48150
|
+
resolve: () => ({
|
|
48151
|
+
outputTypes: [{ kind: "unknown" }],
|
|
48152
|
+
apply: (args) => {
|
|
48153
|
+
const m = args.length >= 1 ? Math.round(toNumber(args[0])) : 0;
|
|
48154
|
+
const n = args.length >= 2 ? Math.round(toNumber(args[1])) : 0;
|
|
48155
|
+
return RTV.sparseMatrix(
|
|
48156
|
+
m,
|
|
48157
|
+
n,
|
|
48158
|
+
new Int32Array(0),
|
|
48159
|
+
new Int32Array(n + 1),
|
|
48160
|
+
allocFloat64Array(0)
|
|
48161
|
+
);
|
|
48162
|
+
}
|
|
48163
|
+
})
|
|
48164
|
+
});
|
|
47262
48165
|
registerIBuiltin({
|
|
47263
48166
|
name: "speye",
|
|
47264
48167
|
resolve: () => ({
|
|
@@ -47544,6 +48447,598 @@ registerIBuiltin({
|
|
|
47544
48447
|
}
|
|
47545
48448
|
})
|
|
47546
48449
|
});
|
|
48450
|
+
var SPPARMS_KEYS = [
|
|
48451
|
+
"spumoni",
|
|
48452
|
+
"thr_rel",
|
|
48453
|
+
"thr_abs",
|
|
48454
|
+
"exact_d",
|
|
48455
|
+
"supernd",
|
|
48456
|
+
"rreduce",
|
|
48457
|
+
"wh_frac",
|
|
48458
|
+
"autommd",
|
|
48459
|
+
"autoamd",
|
|
48460
|
+
"piv_tol",
|
|
48461
|
+
"bandden",
|
|
48462
|
+
"umfpack",
|
|
48463
|
+
"sym_tol",
|
|
48464
|
+
"ldl_tol",
|
|
48465
|
+
"usema57",
|
|
48466
|
+
"spqrtol",
|
|
48467
|
+
"sp_ctor",
|
|
48468
|
+
"reorder",
|
|
48469
|
+
"no_redo"
|
|
48470
|
+
];
|
|
48471
|
+
var SPPARMS_DEFAULTS = [
|
|
48472
|
+
0,
|
|
48473
|
+
1.1,
|
|
48474
|
+
1,
|
|
48475
|
+
0,
|
|
48476
|
+
3,
|
|
48477
|
+
3,
|
|
48478
|
+
0.5,
|
|
48479
|
+
1,
|
|
48480
|
+
1,
|
|
48481
|
+
0.1,
|
|
48482
|
+
0.5,
|
|
48483
|
+
1,
|
|
48484
|
+
1e-3,
|
|
48485
|
+
0.01,
|
|
48486
|
+
1,
|
|
48487
|
+
-2,
|
|
48488
|
+
0,
|
|
48489
|
+
0,
|
|
48490
|
+
0
|
|
48491
|
+
];
|
|
48492
|
+
var spparmsState = Float64Array.from(SPPARMS_DEFAULTS);
|
|
48493
|
+
function spparmsVector() {
|
|
48494
|
+
return RTV.tensor(allocFloat64Array(Array.from(spparmsState)), [
|
|
48495
|
+
spparmsState.length,
|
|
48496
|
+
1
|
|
48497
|
+
]);
|
|
48498
|
+
}
|
|
48499
|
+
registerIBuiltin({
|
|
48500
|
+
name: "spparms",
|
|
48501
|
+
resolve: (argTypes, nargout) => {
|
|
48502
|
+
if (argTypes.length > 2) return null;
|
|
48503
|
+
const tensorOut = { kind: "tensor", isComplex: false };
|
|
48504
|
+
const outputTypes = nargout >= 2 ? [{ kind: "char" }, tensorOut] : [tensorOut];
|
|
48505
|
+
return {
|
|
48506
|
+
outputTypes,
|
|
48507
|
+
apply: (args, n) => {
|
|
48508
|
+
if (args.length === 0) {
|
|
48509
|
+
if (n >= 2) {
|
|
48510
|
+
const width = Math.max(...SPPARMS_KEYS.map((k) => k.length));
|
|
48511
|
+
const padded = SPPARMS_KEYS.map((k) => k.padEnd(width)).join("");
|
|
48512
|
+
return [
|
|
48513
|
+
new RuntimeChar(padded, [SPPARMS_KEYS.length, width]),
|
|
48514
|
+
spparmsVector()
|
|
48515
|
+
];
|
|
48516
|
+
}
|
|
48517
|
+
return spparmsVector();
|
|
48518
|
+
}
|
|
48519
|
+
const first = args[0];
|
|
48520
|
+
if (isRuntimeChar(first) || isRuntimeString(first)) {
|
|
48521
|
+
const key = parseStringArgLower(first);
|
|
48522
|
+
if (args.length >= 2) {
|
|
48523
|
+
const idx2 = SPPARMS_KEYS.indexOf(key);
|
|
48524
|
+
if (idx2 >= 0) spparmsState[idx2] = toNumber(args[1]);
|
|
48525
|
+
return RTV.num(0);
|
|
48526
|
+
}
|
|
48527
|
+
if (key === "default") {
|
|
48528
|
+
spparmsState = Float64Array.from(SPPARMS_DEFAULTS);
|
|
48529
|
+
return RTV.num(0);
|
|
48530
|
+
}
|
|
48531
|
+
if (key === "tight") {
|
|
48532
|
+
return RTV.num(0);
|
|
48533
|
+
}
|
|
48534
|
+
const idx = SPPARMS_KEYS.indexOf(key);
|
|
48535
|
+
if (idx >= 0) return RTV.num(spparmsState[idx]);
|
|
48536
|
+
throw new RuntimeError(`spparms: unknown parameter '${key}'`);
|
|
48537
|
+
}
|
|
48538
|
+
const vals = isRuntimeNumber(first) ? [first] : isRuntimeTensor(first) ? Array.from(first.data) : null;
|
|
48539
|
+
if (vals === null)
|
|
48540
|
+
throw new RuntimeError(
|
|
48541
|
+
"spparms: argument must be a parameter name or value vector"
|
|
48542
|
+
);
|
|
48543
|
+
const next = Float64Array.from(spparmsState);
|
|
48544
|
+
for (let i = 0; i < Math.min(vals.length, next.length); i++)
|
|
48545
|
+
next[i] = vals[i];
|
|
48546
|
+
spparmsState = next;
|
|
48547
|
+
return RTV.num(0);
|
|
48548
|
+
}
|
|
48549
|
+
};
|
|
48550
|
+
}
|
|
48551
|
+
});
|
|
48552
|
+
|
|
48553
|
+
// src/numbl-core/interpreter/builtins/graph.ts
|
|
48554
|
+
function isGraph(v) {
|
|
48555
|
+
return isRuntimeClassInstance(v) && v.className === "graph";
|
|
48556
|
+
}
|
|
48557
|
+
function requireGraph(v, fn) {
|
|
48558
|
+
if (!isGraph(v)) {
|
|
48559
|
+
throw new RuntimeError(`${fn}: first argument must be a graph`);
|
|
48560
|
+
}
|
|
48561
|
+
return v;
|
|
48562
|
+
}
|
|
48563
|
+
function graphN(g) {
|
|
48564
|
+
return toNumber(g.fields.get("_n") ?? 0);
|
|
48565
|
+
}
|
|
48566
|
+
function graphWeighted(g) {
|
|
48567
|
+
const w = g.fields.get("_weighted");
|
|
48568
|
+
return w === true;
|
|
48569
|
+
}
|
|
48570
|
+
function graphAdj(g) {
|
|
48571
|
+
const a = g.fields.get("_A");
|
|
48572
|
+
if (a === void 0 || !isRuntimeSparseMatrix(a)) {
|
|
48573
|
+
throw new RuntimeError("graph: corrupt internal adjacency");
|
|
48574
|
+
}
|
|
48575
|
+
return a;
|
|
48576
|
+
}
|
|
48577
|
+
function buildSymAdj(n, edges) {
|
|
48578
|
+
const triplets = [];
|
|
48579
|
+
for (const e of edges) {
|
|
48580
|
+
if (e.w === 0) continue;
|
|
48581
|
+
const u = e.u - 1;
|
|
48582
|
+
const v = e.v - 1;
|
|
48583
|
+
if (u === v) {
|
|
48584
|
+
triplets.push({ col: u, row: u, val: e.w });
|
|
48585
|
+
} else {
|
|
48586
|
+
triplets.push({ col: v, row: u, val: e.w });
|
|
48587
|
+
triplets.push({ col: u, row: v, val: e.w });
|
|
48588
|
+
}
|
|
48589
|
+
}
|
|
48590
|
+
triplets.sort((a, b) => a.col - b.col || a.row - b.row);
|
|
48591
|
+
const ir = [];
|
|
48592
|
+
const pr = [];
|
|
48593
|
+
const cols = [];
|
|
48594
|
+
let prevCol = -1;
|
|
48595
|
+
let prevRow = -1;
|
|
48596
|
+
for (const t of triplets) {
|
|
48597
|
+
if (t.col === prevCol && t.row === prevRow) {
|
|
48598
|
+
pr[pr.length - 1] += t.val;
|
|
48599
|
+
} else {
|
|
48600
|
+
ir.push(t.row);
|
|
48601
|
+
pr.push(t.val);
|
|
48602
|
+
cols.push(t.col);
|
|
48603
|
+
prevCol = t.col;
|
|
48604
|
+
prevRow = t.row;
|
|
48605
|
+
}
|
|
48606
|
+
}
|
|
48607
|
+
const jc = new Int32Array(n + 1);
|
|
48608
|
+
let ci = 0;
|
|
48609
|
+
for (let c = 0; c < n; c++) {
|
|
48610
|
+
jc[c] = ci;
|
|
48611
|
+
while (ci < cols.length && cols[ci] === c) ci++;
|
|
48612
|
+
}
|
|
48613
|
+
jc[n] = ci;
|
|
48614
|
+
return RTV.sparseMatrix(n, n, new Int32Array(ir), jc, allocFloat64Array(pr));
|
|
48615
|
+
}
|
|
48616
|
+
function makeGraph(n, edges, weighted) {
|
|
48617
|
+
const fields = /* @__PURE__ */ new Map();
|
|
48618
|
+
fields.set("_n", n);
|
|
48619
|
+
fields.set("_A", buildSymAdj(n, edges));
|
|
48620
|
+
fields.set("_weighted", weighted);
|
|
48621
|
+
return new RuntimeClassInstance("graph", fields, false);
|
|
48622
|
+
}
|
|
48623
|
+
function eachNeighbor(A, c, cb) {
|
|
48624
|
+
for (let k = A.jc[c]; k < A.jc[c + 1]; k++) {
|
|
48625
|
+
const r = A.ir[k];
|
|
48626
|
+
if (r !== c) cb(r, A.pr[k]);
|
|
48627
|
+
}
|
|
48628
|
+
}
|
|
48629
|
+
function edgesFromAdj(A) {
|
|
48630
|
+
const edges = [];
|
|
48631
|
+
for (let c = 0; c < A.n; c++) {
|
|
48632
|
+
for (let k = A.jc[c]; k < A.jc[c + 1]; k++) {
|
|
48633
|
+
const r = A.ir[k];
|
|
48634
|
+
if (r < c) edges.push({ u: r + 1, v: c + 1, w: A.pr[k] });
|
|
48635
|
+
else if (r === c) edges.push({ u: r + 1, v: r + 1, w: A.pr[k] });
|
|
48636
|
+
}
|
|
48637
|
+
}
|
|
48638
|
+
return edges;
|
|
48639
|
+
}
|
|
48640
|
+
function squareDim(A, fn) {
|
|
48641
|
+
if (isRuntimeNumber(A) || isRuntimeLogical(A)) return 1;
|
|
48642
|
+
if (isRuntimeSparseMatrix(A)) {
|
|
48643
|
+
if (A.m !== A.n) throw new RuntimeError(`${fn}: adjacency must be square`);
|
|
48644
|
+
return A.n;
|
|
48645
|
+
}
|
|
48646
|
+
if (isRuntimeTensor(A)) {
|
|
48647
|
+
const rows = A.shape[0] ?? 1;
|
|
48648
|
+
const cols = A.shape[1] ?? 1;
|
|
48649
|
+
if (rows !== cols)
|
|
48650
|
+
throw new RuntimeError(`${fn}: adjacency must be square`);
|
|
48651
|
+
return rows;
|
|
48652
|
+
}
|
|
48653
|
+
throw new RuntimeError(`${fn}: adjacency must be a numeric matrix`);
|
|
48654
|
+
}
|
|
48655
|
+
function takeEntry(r, c, triangle) {
|
|
48656
|
+
if (r === c) return true;
|
|
48657
|
+
if (triangle === "lower") return r > c;
|
|
48658
|
+
return r < c;
|
|
48659
|
+
}
|
|
48660
|
+
function adjToEdges(A, omitSelfLoops, triangle, fn) {
|
|
48661
|
+
const n = squareDim(A, fn);
|
|
48662
|
+
const weighted = !(isRuntimeTensor(A) && A._isLogical);
|
|
48663
|
+
const edges = [];
|
|
48664
|
+
const push = (r, c, val) => {
|
|
48665
|
+
if (val === 0) return;
|
|
48666
|
+
if (r === c) {
|
|
48667
|
+
if (!omitSelfLoops) edges.push({ u: r + 1, v: r + 1, w: val });
|
|
48668
|
+
} else if (takeEntry(r, c, triangle)) {
|
|
48669
|
+
edges.push({ u: Math.min(r, c) + 1, v: Math.max(r, c) + 1, w: val });
|
|
48670
|
+
}
|
|
48671
|
+
};
|
|
48672
|
+
if (isRuntimeSparseMatrix(A)) {
|
|
48673
|
+
for (let c = 0; c < A.n; c++) {
|
|
48674
|
+
for (let k = A.jc[c]; k < A.jc[c + 1]; k++) push(A.ir[k], c, A.pr[k]);
|
|
48675
|
+
}
|
|
48676
|
+
} else if (isRuntimeTensor(A)) {
|
|
48677
|
+
const m = A.shape[0] ?? 1;
|
|
48678
|
+
for (let c = 0; c < n; c++) {
|
|
48679
|
+
for (let r = 0; r < n; r++) {
|
|
48680
|
+
const val = A.data[c * m + r];
|
|
48681
|
+
if (val !== 0) push(r, c, val);
|
|
48682
|
+
}
|
|
48683
|
+
}
|
|
48684
|
+
} else if (isRuntimeNumber(A) || isRuntimeLogical(A)) {
|
|
48685
|
+
const val = isRuntimeNumber(A) ? A : A ? 1 : 0;
|
|
48686
|
+
if (val !== 0) push(0, 0, val);
|
|
48687
|
+
}
|
|
48688
|
+
return { n, edges, weighted };
|
|
48689
|
+
}
|
|
48690
|
+
function isNumericArg2(v) {
|
|
48691
|
+
return isRuntimeNumber(v) || isRuntimeLogical(v) || isRuntimeTensor(v) || isRuntimeSparseMatrix(v);
|
|
48692
|
+
}
|
|
48693
|
+
function toNumArray2(v) {
|
|
48694
|
+
if (isRuntimeNumber(v)) return [v];
|
|
48695
|
+
if (isRuntimeLogical(v)) return [v ? 1 : 0];
|
|
48696
|
+
if (isRuntimeTensor(v)) return Array.from(v.data);
|
|
48697
|
+
throw new RuntimeError("graph: node/weight arguments must be numeric");
|
|
48698
|
+
}
|
|
48699
|
+
function argString(v) {
|
|
48700
|
+
if (isRuntimeString(v)) return v;
|
|
48701
|
+
if (isRuntimeChar(v)) return v.value;
|
|
48702
|
+
return null;
|
|
48703
|
+
}
|
|
48704
|
+
registerIBuiltin({
|
|
48705
|
+
name: "graph",
|
|
48706
|
+
help: {
|
|
48707
|
+
signatures: [
|
|
48708
|
+
"G = graph(A)",
|
|
48709
|
+
"G = graph(A, 'omitselfloops')",
|
|
48710
|
+
"G = graph(A, 'upper' | 'lower')",
|
|
48711
|
+
"G = graph(s, t)",
|
|
48712
|
+
"G = graph(s, t, w)",
|
|
48713
|
+
"G = graph(s, t, w, num)"
|
|
48714
|
+
],
|
|
48715
|
+
description: "Create an undirected graph from an adjacency matrix A (which must be symmetric) or from edge endpoint lists s and t with optional weights w."
|
|
48716
|
+
},
|
|
48717
|
+
resolve: () => ({
|
|
48718
|
+
outputTypes: [
|
|
48719
|
+
{
|
|
48720
|
+
kind: "class_instance",
|
|
48721
|
+
className: "graph",
|
|
48722
|
+
isHandleClass: false,
|
|
48723
|
+
fields: {}
|
|
48724
|
+
}
|
|
48725
|
+
],
|
|
48726
|
+
apply: (args) => {
|
|
48727
|
+
if (args.length === 0) return makeGraph(0, [], false);
|
|
48728
|
+
if (args.length >= 2 && isNumericArg2(args[1])) {
|
|
48729
|
+
const s = toNumArray2(args[0]);
|
|
48730
|
+
const t = toNumArray2(args[1]);
|
|
48731
|
+
if (s.length !== t.length) {
|
|
48732
|
+
throw new RuntimeError("graph: s and t must have the same length");
|
|
48733
|
+
}
|
|
48734
|
+
let weighted2 = false;
|
|
48735
|
+
let w = null;
|
|
48736
|
+
let num = null;
|
|
48737
|
+
let omitSelfLoops2 = false;
|
|
48738
|
+
if (args.length >= 3 && isNumericArg2(args[2])) {
|
|
48739
|
+
w = toNumArray2(args[2]);
|
|
48740
|
+
weighted2 = true;
|
|
48741
|
+
if (args.length >= 4 && isNumericArg2(args[3])) {
|
|
48742
|
+
num = Math.floor(toNumber(args[3]));
|
|
48743
|
+
}
|
|
48744
|
+
}
|
|
48745
|
+
for (let i = 2; i < args.length; i++) {
|
|
48746
|
+
const str = argString(args[i]);
|
|
48747
|
+
if (str && str.toLowerCase() === "omitselfloops")
|
|
48748
|
+
omitSelfLoops2 = true;
|
|
48749
|
+
}
|
|
48750
|
+
let n2 = num ?? 0;
|
|
48751
|
+
for (let i = 0; i < s.length; i++) n2 = Math.max(n2, s[i], t[i]);
|
|
48752
|
+
const edges2 = [];
|
|
48753
|
+
for (let i = 0; i < s.length; i++) {
|
|
48754
|
+
const u = Math.min(s[i], t[i]);
|
|
48755
|
+
const v = Math.max(s[i], t[i]);
|
|
48756
|
+
if (omitSelfLoops2 && u === v) continue;
|
|
48757
|
+
edges2.push({ u, v, w: w ? w[w.length === 1 ? 0 : i] : 1 });
|
|
48758
|
+
}
|
|
48759
|
+
return makeGraph(n2, edges2, weighted2);
|
|
48760
|
+
}
|
|
48761
|
+
let omitSelfLoops = false;
|
|
48762
|
+
let triangle = "sym";
|
|
48763
|
+
for (let i = 1; i < args.length; i++) {
|
|
48764
|
+
const str = argString(args[i]);
|
|
48765
|
+
if (!str) continue;
|
|
48766
|
+
const lc = str.toLowerCase();
|
|
48767
|
+
if (lc === "omitselfloops") omitSelfLoops = true;
|
|
48768
|
+
else if (lc === "upper") triangle = "upper";
|
|
48769
|
+
else if (lc === "lower") triangle = "lower";
|
|
48770
|
+
}
|
|
48771
|
+
const { n, edges, weighted } = adjToEdges(
|
|
48772
|
+
args[0],
|
|
48773
|
+
omitSelfLoops,
|
|
48774
|
+
triangle,
|
|
48775
|
+
"graph"
|
|
48776
|
+
);
|
|
48777
|
+
return makeGraph(n, edges, weighted);
|
|
48778
|
+
}
|
|
48779
|
+
})
|
|
48780
|
+
});
|
|
48781
|
+
registerIBuiltin({
|
|
48782
|
+
name: "conncomp",
|
|
48783
|
+
help: {
|
|
48784
|
+
signatures: ["bins = conncomp(G)", "[bins, binsizes] = conncomp(G)"],
|
|
48785
|
+
description: "Connected components of an undirected graph G. Returns a row vector labeling each node with its component index, and optionally the size of each component."
|
|
48786
|
+
},
|
|
48787
|
+
resolve: () => ({
|
|
48788
|
+
outputTypes: [{ kind: "unknown" }, { kind: "unknown" }],
|
|
48789
|
+
apply: (args, nargout) => {
|
|
48790
|
+
const g = requireGraph(args[0], "conncomp");
|
|
48791
|
+
const n = graphN(g);
|
|
48792
|
+
const A = graphAdj(g);
|
|
48793
|
+
const bins = new Float64Array(n);
|
|
48794
|
+
const sizes = [];
|
|
48795
|
+
let comp = 0;
|
|
48796
|
+
const stack = [];
|
|
48797
|
+
for (let start = 0; start < n; start++) {
|
|
48798
|
+
if (bins[start] !== 0) continue;
|
|
48799
|
+
comp++;
|
|
48800
|
+
let count = 0;
|
|
48801
|
+
bins[start] = comp;
|
|
48802
|
+
stack.length = 0;
|
|
48803
|
+
stack.push(start);
|
|
48804
|
+
while (stack.length > 0) {
|
|
48805
|
+
const node = stack.pop();
|
|
48806
|
+
count++;
|
|
48807
|
+
eachNeighbor(A, node, (r) => {
|
|
48808
|
+
if (bins[r] === 0) {
|
|
48809
|
+
bins[r] = comp;
|
|
48810
|
+
stack.push(r);
|
|
48811
|
+
}
|
|
48812
|
+
});
|
|
48813
|
+
}
|
|
48814
|
+
sizes.push(count);
|
|
48815
|
+
}
|
|
48816
|
+
const binsT = RTV.tensor(bins, [1, n]);
|
|
48817
|
+
if (nargout >= 2) {
|
|
48818
|
+
return [binsT, RTV.tensor(allocFloat64Array(sizes), [1, sizes.length])];
|
|
48819
|
+
}
|
|
48820
|
+
return binsT;
|
|
48821
|
+
}
|
|
48822
|
+
})
|
|
48823
|
+
});
|
|
48824
|
+
registerIBuiltin({
|
|
48825
|
+
name: "laplacian",
|
|
48826
|
+
help: {
|
|
48827
|
+
signatures: ["L = laplacian(G)"],
|
|
48828
|
+
description: "Graph Laplacian matrix L = D - A of an undirected graph G, where A is the (binary, unweighted) adjacency matrix and D the diagonal node-degree matrix. Returns a sparse matrix."
|
|
48829
|
+
},
|
|
48830
|
+
resolve: () => ({
|
|
48831
|
+
outputTypes: [{ kind: "unknown" }],
|
|
48832
|
+
apply: (args) => {
|
|
48833
|
+
const g = requireGraph(args[0], "laplacian");
|
|
48834
|
+
const n = graphN(g);
|
|
48835
|
+
const A = graphAdj(g);
|
|
48836
|
+
const edges = [];
|
|
48837
|
+
for (let c = 0; c < n; c++) {
|
|
48838
|
+
let degree = 0;
|
|
48839
|
+
eachNeighbor(A, c, (r) => {
|
|
48840
|
+
degree++;
|
|
48841
|
+
if (r < c) edges.push({ u: r + 1, v: c + 1, w: -1 });
|
|
48842
|
+
});
|
|
48843
|
+
edges.push({ u: c + 1, v: c + 1, w: degree });
|
|
48844
|
+
}
|
|
48845
|
+
return buildSymAdj(n, edges);
|
|
48846
|
+
}
|
|
48847
|
+
})
|
|
48848
|
+
});
|
|
48849
|
+
registerIBuiltin({
|
|
48850
|
+
name: "addedge",
|
|
48851
|
+
help: {
|
|
48852
|
+
signatures: ["H = addedge(G, s, t)", "H = addedge(G, s, t, w)"],
|
|
48853
|
+
description: "Add one or more edges between nodes s and t to graph G, returning a new graph. Weights w are required when G is a weighted graph."
|
|
48854
|
+
},
|
|
48855
|
+
resolve: () => ({
|
|
48856
|
+
outputTypes: [
|
|
48857
|
+
{
|
|
48858
|
+
kind: "class_instance",
|
|
48859
|
+
className: "graph",
|
|
48860
|
+
isHandleClass: false,
|
|
48861
|
+
fields: {}
|
|
48862
|
+
}
|
|
48863
|
+
],
|
|
48864
|
+
apply: (args) => {
|
|
48865
|
+
const g = requireGraph(args[0], "addedge");
|
|
48866
|
+
if (args.length < 3) {
|
|
48867
|
+
throw new RuntimeError("addedge: requires nodes s and t");
|
|
48868
|
+
}
|
|
48869
|
+
const weighted = graphWeighted(g);
|
|
48870
|
+
const s = toNumArray2(args[1]);
|
|
48871
|
+
const t = toNumArray2(args[2]);
|
|
48872
|
+
if (s.length !== t.length) {
|
|
48873
|
+
throw new RuntimeError("addedge: s and t must have the same length");
|
|
48874
|
+
}
|
|
48875
|
+
let w = null;
|
|
48876
|
+
if (args.length >= 4) {
|
|
48877
|
+
w = toNumArray2(args[3]);
|
|
48878
|
+
} else if (weighted) {
|
|
48879
|
+
throw new RuntimeError(
|
|
48880
|
+
"addedge: Must specify weights when adding an edge to a weighted graph."
|
|
48881
|
+
);
|
|
48882
|
+
}
|
|
48883
|
+
const edges = edgesFromAdj(graphAdj(g));
|
|
48884
|
+
let n = graphN(g);
|
|
48885
|
+
for (let i = 0; i < s.length; i++) {
|
|
48886
|
+
const u = Math.min(s[i], t[i]);
|
|
48887
|
+
const v = Math.max(s[i], t[i]);
|
|
48888
|
+
n = Math.max(n, u, v);
|
|
48889
|
+
edges.push({ u, v, w: w ? w[w.length === 1 ? 0 : i] : 1 });
|
|
48890
|
+
}
|
|
48891
|
+
return makeGraph(n, edges, weighted);
|
|
48892
|
+
}
|
|
48893
|
+
})
|
|
48894
|
+
});
|
|
48895
|
+
registerIBuiltin({
|
|
48896
|
+
name: "numnodes",
|
|
48897
|
+
help: {
|
|
48898
|
+
signatures: ["n = numnodes(G)"],
|
|
48899
|
+
description: "Number of nodes in graph G."
|
|
48900
|
+
},
|
|
48901
|
+
resolve: () => ({
|
|
48902
|
+
outputTypes: [{ kind: "number" }],
|
|
48903
|
+
apply: (args) => RTV.num(graphN(requireGraph(args[0], "numnodes")))
|
|
48904
|
+
})
|
|
48905
|
+
});
|
|
48906
|
+
registerIBuiltin({
|
|
48907
|
+
name: "numedges",
|
|
48908
|
+
help: {
|
|
48909
|
+
signatures: ["m = numedges(G)"],
|
|
48910
|
+
description: "Number of edges in graph G."
|
|
48911
|
+
},
|
|
48912
|
+
resolve: () => ({
|
|
48913
|
+
outputTypes: [{ kind: "number" }],
|
|
48914
|
+
apply: (args) => {
|
|
48915
|
+
const g = requireGraph(args[0], "numedges");
|
|
48916
|
+
return RTV.num(edgesFromAdj(graphAdj(g)).length);
|
|
48917
|
+
}
|
|
48918
|
+
})
|
|
48919
|
+
});
|
|
48920
|
+
registerIBuiltin({
|
|
48921
|
+
name: "degree",
|
|
48922
|
+
help: {
|
|
48923
|
+
signatures: ["d = degree(G)"],
|
|
48924
|
+
description: "Degree of each node in graph G, returned as a column vector of edge counts (self-loops excluded)."
|
|
48925
|
+
},
|
|
48926
|
+
resolve: () => ({
|
|
48927
|
+
outputTypes: [{ kind: "unknown" }],
|
|
48928
|
+
apply: (args) => {
|
|
48929
|
+
const g = requireGraph(args[0], "degree");
|
|
48930
|
+
const n = graphN(g);
|
|
48931
|
+
const A = graphAdj(g);
|
|
48932
|
+
const d = new Float64Array(n);
|
|
48933
|
+
for (let c = 0; c < n; c++) eachNeighbor(A, c, () => d[c] += 1);
|
|
48934
|
+
return RTV.tensor(d, [n, 1]);
|
|
48935
|
+
}
|
|
48936
|
+
})
|
|
48937
|
+
});
|
|
48938
|
+
|
|
48939
|
+
// src/numbl-core/interpreter/builtins/gallery.ts
|
|
48940
|
+
function toNumArray3(v, what) {
|
|
48941
|
+
if (isRuntimeNumber(v)) return [v];
|
|
48942
|
+
if (isRuntimeLogical(v)) return [v ? 1 : 0];
|
|
48943
|
+
if (isRuntimeTensor(v)) return Array.from(v.data);
|
|
48944
|
+
if (isRuntimeComplexNumber(v)) return [v.re];
|
|
48945
|
+
throw new RuntimeError(`gallery: ${what} must be numeric`);
|
|
48946
|
+
}
|
|
48947
|
+
function buildTridiag(sub2, diag2, sup) {
|
|
48948
|
+
const n = diag2.length;
|
|
48949
|
+
if (sub2.length !== n - 1 || sup.length !== n - 1) {
|
|
48950
|
+
throw new RuntimeError(
|
|
48951
|
+
"gallery: tridiag sub/superdiagonal must have length one less than the diagonal"
|
|
48952
|
+
);
|
|
48953
|
+
}
|
|
48954
|
+
const ir = [];
|
|
48955
|
+
const pr = [];
|
|
48956
|
+
const jc = new Int32Array(n + 1);
|
|
48957
|
+
for (let c = 0; c < n; c++) {
|
|
48958
|
+
jc[c] = ir.length;
|
|
48959
|
+
if (c >= 1 && sup[c - 1] !== 0) {
|
|
48960
|
+
ir.push(c - 1);
|
|
48961
|
+
pr.push(sup[c - 1]);
|
|
48962
|
+
}
|
|
48963
|
+
if (diag2[c] !== 0) {
|
|
48964
|
+
ir.push(c);
|
|
48965
|
+
pr.push(diag2[c]);
|
|
48966
|
+
}
|
|
48967
|
+
if (c <= n - 2 && sub2[c] !== 0) {
|
|
48968
|
+
ir.push(c + 1);
|
|
48969
|
+
pr.push(sub2[c]);
|
|
48970
|
+
}
|
|
48971
|
+
}
|
|
48972
|
+
jc[n] = ir.length;
|
|
48973
|
+
return RTV.sparseMatrix(n, n, new Int32Array(ir), jc, allocFloat64Array(pr));
|
|
48974
|
+
}
|
|
48975
|
+
function buildTridiagToeplitz(n, c, d, e) {
|
|
48976
|
+
const off = Math.max(0, n - 1);
|
|
48977
|
+
return buildTridiag(
|
|
48978
|
+
new Array(off).fill(c),
|
|
48979
|
+
new Array(n).fill(d),
|
|
48980
|
+
new Array(off).fill(e)
|
|
48981
|
+
);
|
|
48982
|
+
}
|
|
48983
|
+
function galleryTridiag(rest) {
|
|
48984
|
+
if (rest.length === 1) {
|
|
48985
|
+
return buildTridiagToeplitz(Math.round(toNumber(rest[0])), -1, 2, -1);
|
|
48986
|
+
}
|
|
48987
|
+
if (rest.length === 4) {
|
|
48988
|
+
return buildTridiagToeplitz(
|
|
48989
|
+
Math.round(toNumber(rest[0])),
|
|
48990
|
+
toNumber(rest[1]),
|
|
48991
|
+
toNumber(rest[2]),
|
|
48992
|
+
toNumber(rest[3])
|
|
48993
|
+
);
|
|
48994
|
+
}
|
|
48995
|
+
if (rest.length === 3) {
|
|
48996
|
+
const sub2 = toNumArray3(rest[0], "subdiagonal");
|
|
48997
|
+
const diag2 = toNumArray3(rest[1], "diagonal");
|
|
48998
|
+
const sup = toNumArray3(rest[2], "superdiagonal");
|
|
48999
|
+
if (sub2.length === 1 && diag2.length === 1 && sup.length === 1) {
|
|
49000
|
+
return buildTridiag([], diag2, []);
|
|
49001
|
+
}
|
|
49002
|
+
return buildTridiag(sub2, diag2, sup);
|
|
49003
|
+
}
|
|
49004
|
+
throw new RuntimeError("gallery: tridiag expects (n), (n,c,d,e), or (x,y,z)");
|
|
49005
|
+
}
|
|
49006
|
+
registerIBuiltin({
|
|
49007
|
+
name: "gallery",
|
|
49008
|
+
help: {
|
|
49009
|
+
signatures: [
|
|
49010
|
+
"A = gallery('tridiag', n)",
|
|
49011
|
+
"A = gallery('tridiag', n, c, d, e)",
|
|
49012
|
+
"A = gallery('tridiag', x, y, z)"
|
|
49013
|
+
],
|
|
49014
|
+
description: "Test matrices. gallery('tridiag', ...) returns a sparse tridiagonal matrix: gallery('tridiag', n) is the order-n matrix with -1 on the sub/superdiagonals and 2 on the diagonal (the negative second-difference matrix); gallery('tridiag', n, c, d, e) is the order-n Toeplitz tridiagonal with scalar sub c, diagonal d, super e; gallery('tridiag', x, y, z) uses vectors x (subdiagonal), y (diagonal), z (superdiagonal), where x and z have length one less than y."
|
|
49015
|
+
},
|
|
49016
|
+
resolve: () => ({
|
|
49017
|
+
outputTypes: [{ kind: "unknown" }],
|
|
49018
|
+
apply: (args) => {
|
|
49019
|
+
if (args.length < 1) {
|
|
49020
|
+
throw new RuntimeError("gallery: not enough input arguments");
|
|
49021
|
+
}
|
|
49022
|
+
const name = parseStringArgLower(args[0]);
|
|
49023
|
+
let rest = args.slice(1);
|
|
49024
|
+
if (rest.length >= 1) {
|
|
49025
|
+
const last = rest[rest.length - 1];
|
|
49026
|
+
if (isRuntimeString(last) || isRuntimeChar(last)) {
|
|
49027
|
+
const cn = parseStringArgLower(last);
|
|
49028
|
+
if (cn === "single" || cn === "double") rest = rest.slice(0, -1);
|
|
49029
|
+
}
|
|
49030
|
+
}
|
|
49031
|
+
switch (name) {
|
|
49032
|
+
case "tridiag":
|
|
49033
|
+
return galleryTridiag(rest);
|
|
49034
|
+
default:
|
|
49035
|
+
throw new RuntimeError(
|
|
49036
|
+
`gallery: matrix family '${name}' is not supported`
|
|
49037
|
+
);
|
|
49038
|
+
}
|
|
49039
|
+
}
|
|
49040
|
+
})
|
|
49041
|
+
});
|
|
47547
49042
|
|
|
47548
49043
|
// src/numbl-core/interpreter/builtins/special-math.ts
|
|
47549
49044
|
function binaryApply(a, b, fn) {
|
|
@@ -48027,12 +49522,19 @@ registerIBuiltin({
|
|
|
48027
49522
|
|
|
48028
49523
|
// src/numbl-core/native/geometry-bridge.ts
|
|
48029
49524
|
var backend = null;
|
|
49525
|
+
var hullBackend = null;
|
|
48030
49526
|
function setDelaunayBackend(fn) {
|
|
48031
49527
|
backend = fn;
|
|
48032
49528
|
}
|
|
48033
49529
|
function getDelaunayBackend() {
|
|
48034
49530
|
return backend;
|
|
48035
49531
|
}
|
|
49532
|
+
function setConvexHullBackend(fn) {
|
|
49533
|
+
hullBackend = fn;
|
|
49534
|
+
}
|
|
49535
|
+
function getConvexHullBackend() {
|
|
49536
|
+
return hullBackend;
|
|
49537
|
+
}
|
|
48036
49538
|
|
|
48037
49539
|
// src/numbl-core/interpreter/builtins/geometry.ts
|
|
48038
49540
|
function toFlatArray(v, name) {
|
|
@@ -48085,7 +49587,7 @@ function simplexVolume(points, cell, dim) {
|
|
|
48085
49587
|
for (let k = 2; k <= dim; k++) fact *= k;
|
|
48086
49588
|
return Math.abs(det) / fact;
|
|
48087
49589
|
}
|
|
48088
|
-
function triangulateToTensor(points, dim) {
|
|
49590
|
+
function triangulateToTensor(points, dim, orientCCW = false) {
|
|
48089
49591
|
const backend2 = getDelaunayBackend();
|
|
48090
49592
|
if (!backend2)
|
|
48091
49593
|
throw new RuntimeError(
|
|
@@ -48105,6 +49607,16 @@ function triangulateToTensor(points, dim) {
|
|
|
48105
49607
|
const cells = volTol > 0 ? raw.filter((cell) => simplexVolume(points, cell, dim) > volTol) : raw;
|
|
48106
49608
|
const numCells = cells.length;
|
|
48107
49609
|
const cols = dim + 1;
|
|
49610
|
+
if (orientCCW && dim === 2) {
|
|
49611
|
+
for (const cell of cells) {
|
|
49612
|
+
const [a, b, c] = cell;
|
|
49613
|
+
const signedArea2 = (points[b][0] - points[a][0]) * (points[c][1] - points[a][1]) - (points[c][0] - points[a][0]) * (points[b][1] - points[a][1]);
|
|
49614
|
+
if (signedArea2 < 0) {
|
|
49615
|
+
cell[1] = c;
|
|
49616
|
+
cell[2] = b;
|
|
49617
|
+
}
|
|
49618
|
+
}
|
|
49619
|
+
}
|
|
48108
49620
|
const out = allocFloat64Array(numCells * cols);
|
|
48109
49621
|
for (let i = 0; i < numCells; i++) {
|
|
48110
49622
|
const cell = cells[i];
|
|
@@ -48158,7 +49670,7 @@ defineBuiltin({
|
|
|
48158
49670
|
throw new RuntimeError(
|
|
48159
49671
|
`delaunay: need at least ${dim + 1} points for a ${dim}-D triangulation`
|
|
48160
49672
|
);
|
|
48161
|
-
return triangulateToTensor(points, dim);
|
|
49673
|
+
return triangulateToTensor(points, dim, true);
|
|
48162
49674
|
}
|
|
48163
49675
|
}
|
|
48164
49676
|
]
|
|
@@ -48201,6 +49713,203 @@ defineBuiltin({
|
|
|
48201
49713
|
}
|
|
48202
49714
|
]
|
|
48203
49715
|
});
|
|
49716
|
+
var CONVHULLN_MAX_DIM = 3;
|
|
49717
|
+
function convexHullFacets(points, dim, name) {
|
|
49718
|
+
const backend2 = getConvexHullBackend();
|
|
49719
|
+
if (!backend2)
|
|
49720
|
+
throw new RuntimeError(
|
|
49721
|
+
`${name}: convex-hull backend not initialized. In Node call loadQhullNodeBackend() (the CLI and library do this automatically); in the browser worker it loads on startup.`
|
|
49722
|
+
);
|
|
49723
|
+
return backend2(points, dim);
|
|
49724
|
+
}
|
|
49725
|
+
function hullInteriorPoint(points, facets, dim) {
|
|
49726
|
+
const used = /* @__PURE__ */ new Set();
|
|
49727
|
+
for (const f of facets) for (const idx of f) used.add(idx);
|
|
49728
|
+
const c = new Array(dim).fill(0);
|
|
49729
|
+
for (const idx of used) {
|
|
49730
|
+
const p2 = points[idx];
|
|
49731
|
+
for (let k = 0; k < dim; k++) c[k] += p2[k];
|
|
49732
|
+
}
|
|
49733
|
+
const m = used.size || 1;
|
|
49734
|
+
for (let k = 0; k < dim; k++) c[k] /= m;
|
|
49735
|
+
return c;
|
|
49736
|
+
}
|
|
49737
|
+
function hullMeasure(points, facets, dim) {
|
|
49738
|
+
const c = hullInteriorPoint(points, facets, dim);
|
|
49739
|
+
let total = 0;
|
|
49740
|
+
if (dim === 2) {
|
|
49741
|
+
for (const f of facets) {
|
|
49742
|
+
const a = points[f[0]];
|
|
49743
|
+
const b = points[f[1]];
|
|
49744
|
+
const ax = a[0] - c[0], ay = a[1] - c[1];
|
|
49745
|
+
const bx = b[0] - c[0], by = b[1] - c[1];
|
|
49746
|
+
total += Math.abs(ax * by - ay * bx) / 2;
|
|
49747
|
+
}
|
|
49748
|
+
} else {
|
|
49749
|
+
for (const f of facets) {
|
|
49750
|
+
const a = points[f[0]];
|
|
49751
|
+
const b = points[f[1]];
|
|
49752
|
+
const d = points[f[2]];
|
|
49753
|
+
const ax = a[0] - c[0], ay = a[1] - c[1], az = a[2] - c[2];
|
|
49754
|
+
const bx = b[0] - c[0], by = b[1] - c[1], bz = b[2] - c[2];
|
|
49755
|
+
const dx = d[0] - c[0], dy = d[1] - c[1], dz = d[2] - c[2];
|
|
49756
|
+
const det = ax * (by * dz - bz * dy) - ay * (bx * dz - bz * dx) + az * (bx * dy - by * dx);
|
|
49757
|
+
total += Math.abs(det) / 6;
|
|
49758
|
+
}
|
|
49759
|
+
}
|
|
49760
|
+
return total;
|
|
49761
|
+
}
|
|
49762
|
+
function facetsToTensor(facets, cols) {
|
|
49763
|
+
const n = facets.length;
|
|
49764
|
+
const out = allocFloat64Array(n * cols);
|
|
49765
|
+
for (let i = 0; i < n; i++) {
|
|
49766
|
+
const f = facets[i];
|
|
49767
|
+
for (let j = 0; j < cols; j++) out[j * n + i] = f[j] + 1;
|
|
49768
|
+
}
|
|
49769
|
+
return RTV.tensor(out, [n, cols]);
|
|
49770
|
+
}
|
|
49771
|
+
function orderHull2D(facets, points) {
|
|
49772
|
+
const adj = /* @__PURE__ */ new Map();
|
|
49773
|
+
for (const [a, b] of facets) {
|
|
49774
|
+
(adj.get(a) ?? adj.set(a, []).get(a)).push(b);
|
|
49775
|
+
(adj.get(b) ?? adj.set(b, []).get(b)).push(a);
|
|
49776
|
+
}
|
|
49777
|
+
const start = facets[0][0];
|
|
49778
|
+
const loop = [start];
|
|
49779
|
+
let prev = -1;
|
|
49780
|
+
let cur = start;
|
|
49781
|
+
for (let guard = 0; guard <= facets.length; guard++) {
|
|
49782
|
+
const nbrs = adj.get(cur);
|
|
49783
|
+
const next = nbrs[0] === prev ? nbrs[1] : nbrs[0];
|
|
49784
|
+
if (next === void 0 || next === start) break;
|
|
49785
|
+
loop.push(next);
|
|
49786
|
+
prev = cur;
|
|
49787
|
+
cur = next;
|
|
49788
|
+
}
|
|
49789
|
+
let signed = 0;
|
|
49790
|
+
for (let i = 0; i < loop.length; i++) {
|
|
49791
|
+
const p2 = points[loop[i]];
|
|
49792
|
+
const q = points[loop[(i + 1) % loop.length]];
|
|
49793
|
+
signed += p2[0] * q[1] - q[0] * p2[1];
|
|
49794
|
+
}
|
|
49795
|
+
if (signed < 0) loop.reverse();
|
|
49796
|
+
loop.push(loop[0]);
|
|
49797
|
+
const out = allocFloat64Array(loop.length);
|
|
49798
|
+
for (let i = 0; i < loop.length; i++) out[i] = loop[i] + 1;
|
|
49799
|
+
return RTV.tensor(out, [loop.length, 1]);
|
|
49800
|
+
}
|
|
49801
|
+
defineBuiltin({
|
|
49802
|
+
name: "convhull",
|
|
49803
|
+
help: {
|
|
49804
|
+
signatures: [
|
|
49805
|
+
"k = convhull(P)",
|
|
49806
|
+
"k = convhull(x,y)",
|
|
49807
|
+
"k = convhull(x,y,z)",
|
|
49808
|
+
"k = convhull(___,'Simplify',tf)",
|
|
49809
|
+
"[k,av] = convhull(___)"
|
|
49810
|
+
],
|
|
49811
|
+
description: "Convex hull of a set of 2-D or 3-D points. With a single matrix P (N-by-2 or N-by-3), or coordinate vectors x,y (2-D) or x,y,z (3-D). For 2-D input, k is a column vector of 1-based point indices tracing the hull boundary counter-clockwise (closed: k(1)==k(end)). For 3-D input, k is a numFacets-by-3 matrix of triangle vertex indices. The second output av is the area (2-D) or volume (3-D). The 'Simplify' name-value pair is accepted for compatibility; the hull is always returned in minimal (simplified) form."
|
|
49812
|
+
},
|
|
49813
|
+
cases: [
|
|
49814
|
+
{
|
|
49815
|
+
match: (argTypes, nargout) => {
|
|
49816
|
+
if (nargout > 2) return null;
|
|
49817
|
+
if (argTypes.length < 1 || argTypes.length > 5) return null;
|
|
49818
|
+
const ok = (t) => t.kind === "number" || t.kind === "boolean" || t.kind === "tensor" || t.kind === "string" || t.kind === "char";
|
|
49819
|
+
if (!argTypes.every(ok)) return null;
|
|
49820
|
+
const k = { kind: "tensor", isComplex: false };
|
|
49821
|
+
return nargout > 1 ? [k, { kind: "number" }] : [k];
|
|
49822
|
+
},
|
|
49823
|
+
apply: (args, nargout) => {
|
|
49824
|
+
let coordArgs = args;
|
|
49825
|
+
const tail = args[args.length - 2];
|
|
49826
|
+
const isSimplifyName = (v) => typeof v === "string" && v.toLowerCase() === "simplify" || isRuntimeChar(v) && v.value.toLowerCase() === "simplify";
|
|
49827
|
+
if (args.length >= 3 && isSimplifyName(tail)) {
|
|
49828
|
+
coordArgs = args.slice(0, args.length - 2);
|
|
49829
|
+
}
|
|
49830
|
+
let points;
|
|
49831
|
+
let dim;
|
|
49832
|
+
if (coordArgs.length === 1) {
|
|
49833
|
+
const P = coordArgs[0];
|
|
49834
|
+
if (!isRuntimeTensor(P))
|
|
49835
|
+
throw new RuntimeError(
|
|
49836
|
+
"convhull: P must be an N-by-2 or N-by-3 matrix"
|
|
49837
|
+
);
|
|
49838
|
+
const [, d] = tensorSize2D(P);
|
|
49839
|
+
if (d !== 2 && d !== 3)
|
|
49840
|
+
throw new RuntimeError("convhull: P must have 2 or 3 columns");
|
|
49841
|
+
points = matrixToPoints(P, "convhull");
|
|
49842
|
+
dim = d;
|
|
49843
|
+
} else if (coordArgs.length === 2 || coordArgs.length === 3) {
|
|
49844
|
+
const coords = coordArgs.map((a) => toFlatArray(a, "convhull"));
|
|
49845
|
+
const n = coords[0].length;
|
|
49846
|
+
if (coords.some((c) => c.length !== n))
|
|
49847
|
+
throw new RuntimeError(
|
|
49848
|
+
"convhull: coordinate vectors must have the same length"
|
|
49849
|
+
);
|
|
49850
|
+
points = new Array(n);
|
|
49851
|
+
for (let i = 0; i < n; i++) points[i] = coords.map((c) => c[i]);
|
|
49852
|
+
dim = coordArgs.length;
|
|
49853
|
+
} else {
|
|
49854
|
+
throw new RuntimeError("convhull: invalid arguments");
|
|
49855
|
+
}
|
|
49856
|
+
if (points.length < dim + 1)
|
|
49857
|
+
throw new RuntimeError(
|
|
49858
|
+
`convhull: need at least ${dim + 1} points for a ${dim}-D hull`
|
|
49859
|
+
);
|
|
49860
|
+
const facets = convexHullFacets(points, dim, "convhull");
|
|
49861
|
+
const k = dim === 2 ? orderHull2D(facets, points) : facetsToTensor(facets, 3);
|
|
49862
|
+
if (nargout > 1) return [k, hullMeasure(points, facets, dim)];
|
|
49863
|
+
return k;
|
|
49864
|
+
}
|
|
49865
|
+
}
|
|
49866
|
+
]
|
|
49867
|
+
});
|
|
49868
|
+
defineBuiltin({
|
|
49869
|
+
name: "convhulln",
|
|
49870
|
+
help: {
|
|
49871
|
+
signatures: [
|
|
49872
|
+
"k = convhulln(P)",
|
|
49873
|
+
"k = convhulln(P,opts)",
|
|
49874
|
+
"[k,vol] = convhulln(___)"
|
|
49875
|
+
],
|
|
49876
|
+
description: "N-D convex hull. P is an m-by-n matrix of m points in n-dimensional space. Returns a numFacets-by-n matrix where each row holds the 1-based point indices of one simplicial facet (edges for n=2, triangles for n=3). The second output is the area (n=2) or volume (n=3). The opts argument (Qhull options) is accepted for MATLAB compatibility but ignored. Note: only n = 2 and n = 3 are supported (see source comments)."
|
|
49877
|
+
},
|
|
49878
|
+
cases: [
|
|
49879
|
+
{
|
|
49880
|
+
match: (argTypes, nargout) => {
|
|
49881
|
+
if (nargout > 2) return null;
|
|
49882
|
+
if (argTypes.length < 1 || argTypes.length > 2) return null;
|
|
49883
|
+
const x = argTypes[0];
|
|
49884
|
+
if (x.kind !== "tensor" && x.kind !== "number" && x.kind !== "boolean")
|
|
49885
|
+
return null;
|
|
49886
|
+
const k = { kind: "tensor", isComplex: false };
|
|
49887
|
+
return nargout > 1 ? [k, { kind: "number" }] : [k];
|
|
49888
|
+
},
|
|
49889
|
+
apply: (args, nargout) => {
|
|
49890
|
+
const P = args[0];
|
|
49891
|
+
if (!isRuntimeTensor(P))
|
|
49892
|
+
throw new RuntimeError("convhulln: P must be an m-by-n matrix");
|
|
49893
|
+
const [m, n] = tensorSize2D(P);
|
|
49894
|
+
if (n < 2)
|
|
49895
|
+
throw new RuntimeError("convhulln: P must have at least 2 columns");
|
|
49896
|
+
if (n > CONVHULLN_MAX_DIM)
|
|
49897
|
+
throw new RuntimeError(
|
|
49898
|
+
`convhulln: only 2-D and 3-D hulls are supported (got ${n}-D); higher dimensions are not yet validated`
|
|
49899
|
+
);
|
|
49900
|
+
if (m < n + 1)
|
|
49901
|
+
throw new RuntimeError(
|
|
49902
|
+
`convhulln: need at least ${n + 1} points for a ${n}-D hull`
|
|
49903
|
+
);
|
|
49904
|
+
const points = matrixToPoints(P, "convhulln");
|
|
49905
|
+
const facets = convexHullFacets(points, n, "convhulln");
|
|
49906
|
+
const k = facetsToTensor(facets, n);
|
|
49907
|
+
if (nargout > 1) return [k, hullMeasure(points, facets, n)];
|
|
49908
|
+
return k;
|
|
49909
|
+
}
|
|
49910
|
+
}
|
|
49911
|
+
]
|
|
49912
|
+
});
|
|
48204
49913
|
function getQueryValues(v, name) {
|
|
48205
49914
|
if (typeof v === "number") return { data: [v], shape: null };
|
|
48206
49915
|
if (typeof v === "boolean") return { data: [v ? 1 : 0], shape: null };
|
|
@@ -48698,6 +50407,13 @@ registerIBuiltin({
|
|
|
48698
50407
|
apply: (_args, nargout) => nargout >= 1 ? RTV.dummyHandle() : void 0
|
|
48699
50408
|
})
|
|
48700
50409
|
});
|
|
50410
|
+
registerIBuiltin({
|
|
50411
|
+
name: "waitbar",
|
|
50412
|
+
resolve: () => ({
|
|
50413
|
+
outputTypes: [{ kind: "unknown" }],
|
|
50414
|
+
apply: (_args, nargout) => nargout >= 1 ? RTV.dummyHandle() : void 0
|
|
50415
|
+
})
|
|
50416
|
+
});
|
|
48701
50417
|
registerIBuiltin({
|
|
48702
50418
|
name: "get",
|
|
48703
50419
|
resolve: () => ({
|
|
@@ -49836,6 +51552,10 @@ var H = {
|
|
|
49836
51552
|
signatures: ["C = class(A)"],
|
|
49837
51553
|
description: "Returns the class name of A as a character vector."
|
|
49838
51554
|
},
|
|
51555
|
+
superclasses: {
|
|
51556
|
+
signatures: ["S = superclasses(ClassName)", "S = superclasses(obj)"],
|
|
51557
|
+
description: "Names of the superclasses of a class, returned as a column cell array of character vectors. Accepts a class name (char/string) or an object. Returns an empty cell for built-in types or classes with no superclasses."
|
|
51558
|
+
},
|
|
49839
51559
|
fieldnames: {
|
|
49840
51560
|
signatures: ["F = fieldnames(S)"],
|
|
49841
51561
|
description: "Returns cell array of field names of struct or object S."
|
|
@@ -50239,6 +51959,14 @@ var H = {
|
|
|
50239
51959
|
signatures: ["B = pinv(A)", "B = pinv(A, TOL)"],
|
|
50240
51960
|
description: "Moore-Penrose pseudoinverse."
|
|
50241
51961
|
},
|
|
51962
|
+
null: {
|
|
51963
|
+
signatures: ["Z = null(A)", "Z = null(A, TOL)"],
|
|
51964
|
+
description: "Orthonormal basis for the null space of A (columns of Z), computed via the SVD. TOL overrides the singular-value tolerance."
|
|
51965
|
+
},
|
|
51966
|
+
bandwidth: {
|
|
51967
|
+
signatures: ["[lower, upper] = bandwidth(A)", "B = bandwidth(A, TYPE)"],
|
|
51968
|
+
description: "Lower and upper matrix bandwidth. TYPE is 'lower' or 'upper'; a single output without TYPE returns the lower bandwidth."
|
|
51969
|
+
},
|
|
50242
51970
|
cond: {
|
|
50243
51971
|
signatures: ["C = cond(A)", "C = cond(A, P)"],
|
|
50244
51972
|
description: "Condition number of matrix."
|
|
@@ -50468,6 +52196,10 @@ var H = {
|
|
|
50468
52196
|
signatures: ["Y = double(X)"],
|
|
50469
52197
|
description: "Convert to double precision."
|
|
50470
52198
|
},
|
|
52199
|
+
single: {
|
|
52200
|
+
signatures: ["Y = single(X)"],
|
|
52201
|
+
description: "Round to single precision. numbl stores all numerics as double, so the result reports class 'double', but the low-order bits are dropped as in MATLAB."
|
|
52202
|
+
},
|
|
50471
52203
|
logical: {
|
|
50472
52204
|
signatures: ["Y = logical(X)"],
|
|
50473
52205
|
description: "Convert to logical (boolean) array."
|
|
@@ -50838,6 +52570,18 @@ var H = {
|
|
|
50838
52570
|
],
|
|
50839
52571
|
description: "Extract or create sparse banded/diagonal matrices."
|
|
50840
52572
|
},
|
|
52573
|
+
spparms: {
|
|
52574
|
+
signatures: [
|
|
52575
|
+
"spparms",
|
|
52576
|
+
"values = spparms",
|
|
52577
|
+
"[keys, values] = spparms",
|
|
52578
|
+
"value = spparms(KEY)",
|
|
52579
|
+
"spparms(KEY, VALUE)",
|
|
52580
|
+
"spparms('default')",
|
|
52581
|
+
"spparms(values)"
|
|
52582
|
+
],
|
|
52583
|
+
description: "Get/set sparse direct-solver parameters. numbl's sparse solver ignores these knobs; values are stored so they round-trip through get/set/restore but have no effect."
|
|
52584
|
+
},
|
|
50841
52585
|
// ── Linear algebra extras ─────────────────────────────────────────────
|
|
50842
52586
|
qz: {
|
|
50843
52587
|
signatures: [
|
|
@@ -52459,7 +54203,9 @@ function dispatchPlotBuiltin(name, args, instructions, state) {
|
|
|
52459
54203
|
return true;
|
|
52460
54204
|
}
|
|
52461
54205
|
case "close": {
|
|
52462
|
-
|
|
54206
|
+
const a0 = args[0];
|
|
54207
|
+
const isText3 = a0 !== void 0 && (isRuntimeChar(a0) || isRuntimeString(a0));
|
|
54208
|
+
if (isText3 && toString(a0) === "all") {
|
|
52463
54209
|
plotInstr(instructions, { type: "close_all" });
|
|
52464
54210
|
} else {
|
|
52465
54211
|
plotInstr(instructions, { type: "close" });
|
|
@@ -53386,6 +55132,8 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
53386
55132
|
"delete",
|
|
53387
55133
|
"rmdir",
|
|
53388
55134
|
"movefile",
|
|
55135
|
+
"copyfile",
|
|
55136
|
+
"fileattrib",
|
|
53389
55137
|
"unzip",
|
|
53390
55138
|
"dir",
|
|
53391
55139
|
"warning",
|
|
@@ -53395,6 +55143,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
53395
55143
|
"userpath",
|
|
53396
55144
|
"getenv",
|
|
53397
55145
|
"setenv",
|
|
55146
|
+
"maxNumCompThreads",
|
|
53398
55147
|
"pwd",
|
|
53399
55148
|
"cd",
|
|
53400
55149
|
"ode45",
|
|
@@ -53502,8 +55251,8 @@ function registerSpecialBuiltins(rt) {
|
|
|
53502
55251
|
if (args.length === 0) return nargout >= 1 ? RTV.num(0) : void 0;
|
|
53503
55252
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
53504
55253
|
if (margs.length === 2 && isRuntimeChar(margs[0]) && isRuntimeChar(margs[1])) {
|
|
53505
|
-
const
|
|
53506
|
-
if (
|
|
55254
|
+
const mode = toString(margs[0]);
|
|
55255
|
+
if (mode === "on" || mode === "off") {
|
|
53507
55256
|
if (nargout === 0) return void 0;
|
|
53508
55257
|
return RTV.struct(
|
|
53509
55258
|
/* @__PURE__ */ new Map([
|
|
@@ -53512,6 +55261,14 @@ function registerSpecialBuiltins(rt) {
|
|
|
53512
55261
|
])
|
|
53513
55262
|
);
|
|
53514
55263
|
}
|
|
55264
|
+
if (mode === "query") {
|
|
55265
|
+
return RTV.struct(
|
|
55266
|
+
/* @__PURE__ */ new Map([
|
|
55267
|
+
["state", RTV.char("on")],
|
|
55268
|
+
["identifier", margs[1]]
|
|
55269
|
+
])
|
|
55270
|
+
);
|
|
55271
|
+
}
|
|
53515
55272
|
}
|
|
53516
55273
|
let fmtIdx = 0;
|
|
53517
55274
|
if (margs.length >= 2 && isRuntimeChar(margs[0]) && toString(margs[0]).includes(":")) {
|
|
@@ -54328,6 +56085,65 @@ function registerSpecialBuiltins(rt) {
|
|
|
54328
56085
|
RTV.char("")
|
|
54329
56086
|
];
|
|
54330
56087
|
});
|
|
56088
|
+
registerSpecial("copyfile", (nargout, args) => {
|
|
56089
|
+
const io = requireFileIO();
|
|
56090
|
+
if (!io.copyfile)
|
|
56091
|
+
throw new RuntimeError("copyfile is not available in this environment");
|
|
56092
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
56093
|
+
if (margs.length < 1)
|
|
56094
|
+
throw new RuntimeError("copyfile requires at least 1 argument");
|
|
56095
|
+
const source = toString(margs[0]);
|
|
56096
|
+
const destination = margs.length >= 2 ? toString(margs[1]) : rt.system?.cwd() ?? ".";
|
|
56097
|
+
let force = false;
|
|
56098
|
+
if (margs.length >= 3) {
|
|
56099
|
+
const third = toString(margs[2]);
|
|
56100
|
+
if (third.toLowerCase() === "f") force = true;
|
|
56101
|
+
}
|
|
56102
|
+
const ok = io.copyfile(source, destination, force);
|
|
56103
|
+
if (nargout === 0) {
|
|
56104
|
+
if (!ok)
|
|
56105
|
+
throw new RuntimeError(
|
|
56106
|
+
`copyfile: cannot copy '${source}' to '${destination}'`
|
|
56107
|
+
);
|
|
56108
|
+
return void 0;
|
|
56109
|
+
}
|
|
56110
|
+
return nargout <= 1 ? RTV.num(ok ? 1 : 0) : [
|
|
56111
|
+
RTV.num(ok ? 1 : 0),
|
|
56112
|
+
RTV.char(ok ? "" : `Cannot copy '${source}' to '${destination}'`),
|
|
56113
|
+
RTV.char("")
|
|
56114
|
+
];
|
|
56115
|
+
});
|
|
56116
|
+
registerSpecial("fileattrib", (nargout, args) => {
|
|
56117
|
+
const io = requireFileIO();
|
|
56118
|
+
if (!io.fileattrib)
|
|
56119
|
+
throw new RuntimeError("fileattrib is not available in this environment");
|
|
56120
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
56121
|
+
if (margs.length < 1)
|
|
56122
|
+
throw new RuntimeError("fileattrib requires at least 1 argument");
|
|
56123
|
+
const p2 = toString(margs[0]);
|
|
56124
|
+
const info = io.fileattrib(p2);
|
|
56125
|
+
if (nargout === 0) {
|
|
56126
|
+
if (!info)
|
|
56127
|
+
throw new RuntimeError(
|
|
56128
|
+
`fileattrib: cannot find '${p2}': No such file or directory`
|
|
56129
|
+
);
|
|
56130
|
+
return void 0;
|
|
56131
|
+
}
|
|
56132
|
+
const values = info ? RTV.struct(
|
|
56133
|
+
/* @__PURE__ */ new Map([
|
|
56134
|
+
["Name", RTV.char(info.Name)],
|
|
56135
|
+
["archive", RTV.num(0)],
|
|
56136
|
+
["system", RTV.num(0)],
|
|
56137
|
+
["hidden", RTV.num(0)],
|
|
56138
|
+
["directory", RTV.num(info.directory ? 1 : 0)],
|
|
56139
|
+
["UserRead", RTV.num(info.UserRead ? 1 : 0)],
|
|
56140
|
+
["UserWrite", RTV.num(info.UserWrite ? 1 : 0)],
|
|
56141
|
+
["UserExecute", RTV.num(info.UserExecute ? 1 : 0)]
|
|
56142
|
+
])
|
|
56143
|
+
) : RTV.char(`No such file or directory: ${p2}`);
|
|
56144
|
+
if (nargout <= 1) return RTV.num(info ? 1 : 0);
|
|
56145
|
+
return [RTV.num(info ? 1 : 0), values, RTV.char("")];
|
|
56146
|
+
});
|
|
54331
56147
|
registerSpecial("unzip", (nargout, args) => {
|
|
54332
56148
|
const io = requireFileIO();
|
|
54333
56149
|
if (!io.unzip)
|
|
@@ -54653,6 +56469,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
54653
56469
|
}
|
|
54654
56470
|
return RTV.char(sys?.getEnv(toString(args[0])) ?? "");
|
|
54655
56471
|
});
|
|
56472
|
+
registerSpecial("maxNumCompThreads", () => RTV.num(1));
|
|
54656
56473
|
registerSpecialVoid("setenv", (args) => {
|
|
54657
56474
|
const sys = rt.system;
|
|
54658
56475
|
if (args.length === 2) {
|
|
@@ -55034,6 +56851,10 @@ function _eigsImpl(rt, nargout, args) {
|
|
|
55034
56851
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
55035
56852
|
if (margs.length < 1)
|
|
55036
56853
|
throw new RuntimeError("eigs requires at least 1 argument");
|
|
56854
|
+
for (let i = 0; i < margs.length; i++) {
|
|
56855
|
+
const mi = margs[i];
|
|
56856
|
+
if (isRuntimeSparseMatrix(mi)) margs[i] = sparseToDense(mi);
|
|
56857
|
+
}
|
|
55037
56858
|
let afun = null;
|
|
55038
56859
|
let A = null;
|
|
55039
56860
|
let n;
|
|
@@ -56258,43 +58079,40 @@ function methodDispatch(rt, name, nargout, args) {
|
|
|
56258
58079
|
}
|
|
56259
58080
|
}
|
|
56260
58081
|
}
|
|
56261
|
-
|
|
56262
|
-
|
|
56263
|
-
|
|
56264
|
-
if (
|
|
56265
|
-
const
|
|
56266
|
-
|
|
56267
|
-
|
|
56268
|
-
|
|
56269
|
-
|
|
56270
|
-
);
|
|
56271
|
-
|
|
56272
|
-
|
|
56273
|
-
|
|
56274
|
-
RTV.
|
|
56275
|
-
|
|
56276
|
-
|
|
56277
|
-
|
|
56278
|
-
RTV.
|
|
56279
|
-
|
|
56280
|
-
|
|
56281
|
-
|
|
56282
|
-
|
|
56283
|
-
|
|
56284
|
-
|
|
56285
|
-
|
|
56286
|
-
|
|
56287
|
-
|
|
56288
|
-
|
|
56289
|
-
|
|
56290
|
-
} finally {
|
|
56291
|
-
rt.activeAccessors.delete(guardKey);
|
|
56292
|
-
}
|
|
58082
|
+
const methodExists = rt.cachedResolveClassMethod(firstRV.className, name) !== null;
|
|
58083
|
+
if (!methodExists) {
|
|
58084
|
+
const guardKey = `${firstRV.className}.subsref`;
|
|
58085
|
+
if (!rt.activeAccessors.has(guardKey)) {
|
|
58086
|
+
const subsrefFn = rt.cachedResolveClassMethod(
|
|
58087
|
+
firstRV.className,
|
|
58088
|
+
"subsref"
|
|
58089
|
+
);
|
|
58090
|
+
if (subsrefFn) {
|
|
58091
|
+
const remaining = args.slice(1);
|
|
58092
|
+
const sEntries = [
|
|
58093
|
+
RTV.struct({
|
|
58094
|
+
type: RTV.char("."),
|
|
58095
|
+
subs: RTV.char(name)
|
|
58096
|
+
}),
|
|
58097
|
+
RTV.struct({
|
|
58098
|
+
type: RTV.char("()"),
|
|
58099
|
+
subs: RTV.cell(
|
|
58100
|
+
remaining.map((a) => ensureRuntimeValue(a)),
|
|
58101
|
+
[1, remaining.length]
|
|
58102
|
+
)
|
|
58103
|
+
})
|
|
58104
|
+
];
|
|
58105
|
+
const S = RTV.structArray(["type", "subs"], sEntries);
|
|
58106
|
+
rt.activeAccessors.add(guardKey);
|
|
58107
|
+
try {
|
|
58108
|
+
return subsrefFn(nargout, first, S);
|
|
58109
|
+
} finally {
|
|
58110
|
+
rt.activeAccessors.delete(guardKey);
|
|
56293
58111
|
}
|
|
56294
58112
|
}
|
|
56295
58113
|
}
|
|
56296
|
-
throw e;
|
|
56297
58114
|
}
|
|
58115
|
+
return callClassMethod(rt, firstRV.className, name, nargout, args);
|
|
56298
58116
|
}
|
|
56299
58117
|
}
|
|
56300
58118
|
const builtin = rt.builtins[name];
|
|
@@ -56351,11 +58169,13 @@ function arrayfunCellfunImpl(rt, name, nargout, args) {
|
|
|
56351
58169
|
const getElem = (arr, i) => {
|
|
56352
58170
|
if (isRuntimeCell(arr)) return arr.data[i];
|
|
56353
58171
|
if (isRuntimeTensor(arr)) return arr.data[i];
|
|
58172
|
+
if (isRuntimeStructArray(arr)) return arr.elements[i];
|
|
56354
58173
|
return arr;
|
|
56355
58174
|
};
|
|
56356
58175
|
const getLen = (arr) => {
|
|
56357
58176
|
if (isRuntimeCell(arr)) return arr.data.length;
|
|
56358
58177
|
if (isRuntimeTensor(arr)) return arr.data.length;
|
|
58178
|
+
if (isRuntimeStructArray(arr)) return arr.elements.length;
|
|
56359
58179
|
return 1;
|
|
56360
58180
|
};
|
|
56361
58181
|
const collectArgs = (i) => {
|
|
@@ -56391,9 +58211,9 @@ function arrayfunCellfunImpl(rt, name, nargout, args) {
|
|
|
56391
58211
|
if (allLogical && arrArg.data.length > 0) result._isLogical = true;
|
|
56392
58212
|
return result;
|
|
56393
58213
|
}
|
|
56394
|
-
if (isRuntimeCell(arrArg) || extraInputs.length > 0 || nargout > 1) {
|
|
58214
|
+
if (isRuntimeCell(arrArg) || isRuntimeStructArray(arrArg) || extraInputs.length > 0 || nargout > 1) {
|
|
56395
58215
|
const len = getLen(arrArg);
|
|
56396
|
-
const shape = isRuntimeCell(arrArg)
|
|
58216
|
+
const shape = isRuntimeCell(arrArg) || isRuntimeTensor(arrArg) ? [...arrArg.shape] : [1, len];
|
|
56397
58217
|
if (nargout > 1) {
|
|
56398
58218
|
const allResults = Array.from(
|
|
56399
58219
|
{ length: nargout },
|
|
@@ -57228,6 +59048,28 @@ function indexStore(rt, base, indices, rhs, skipSubsasgn = false) {
|
|
|
57228
59048
|
if (isRuntimeStruct(mv)) {
|
|
57229
59049
|
return ensureRuntimeValue(rhs);
|
|
57230
59050
|
}
|
|
59051
|
+
if (indices.length === 1 && isRuntimeClassInstance(ensureRuntimeValue(rhs)) && // Object-array growth uses a numeric position. A char/string index (e.g. a
|
|
59052
|
+
// key into a containers.Map whose value happens to be a class instance)
|
|
59053
|
+
// must fall through to the subsasgn dispatch below, not be coerced to a
|
|
59054
|
+
// number — `toNumber` on a multi-char value throws.
|
|
59055
|
+
!isRuntimeChar(ensureRuntimeValue(indices[0]))) {
|
|
59056
|
+
const k = Math.round(toNumber(ensureRuntimeValue(indices[0]))) - 1;
|
|
59057
|
+
const growsArray = isRuntimeClassInstanceArray(mv) || isRuntimeTensor(mv) && mv.data.length === 0 || isRuntimeClassInstance(mv) && k >= 1;
|
|
59058
|
+
if (growsArray) {
|
|
59059
|
+
if (k < 0) throw new RuntimeError("Index must be a positive integer");
|
|
59060
|
+
const rhsInst = ensureRuntimeValue(rhs);
|
|
59061
|
+
const existing = isRuntimeClassInstanceArray(mv) ? [...mv.elements] : isRuntimeClassInstance(mv) ? [mv] : [];
|
|
59062
|
+
const className = isRuntimeClassInstanceArray(mv) ? mv.className : isRuntimeClassInstance(mv) ? mv.className : rhsInst.className;
|
|
59063
|
+
while (existing.length < k) {
|
|
59064
|
+
existing.push(
|
|
59065
|
+
RTV.classInstance(className, [...rhsInst.fields.keys()], false)
|
|
59066
|
+
);
|
|
59067
|
+
}
|
|
59068
|
+
existing[k] = rhsInst;
|
|
59069
|
+
if (existing.length === 1) return existing[0];
|
|
59070
|
+
return RTV.classInstanceArray(className, existing, [1, existing.length]);
|
|
59071
|
+
}
|
|
59072
|
+
}
|
|
57231
59073
|
if (isRuntimeClassInstance(mv)) {
|
|
57232
59074
|
const guardKey = `${mv.className}.subsasgn`;
|
|
57233
59075
|
if (!skipSubsasgn && !rt.activeAccessors.has(guardKey)) {
|
|
@@ -57385,12 +59227,17 @@ function getMember(rt, base, name) {
|
|
|
57385
59227
|
`No property or method '${name}' for class '${mv.className}'`
|
|
57386
59228
|
);
|
|
57387
59229
|
}
|
|
59230
|
+
if (isRuntimeClassInstanceArray(mv)) {
|
|
59231
|
+
const values = mv.elements.map(
|
|
59232
|
+
(el) => ensureRuntimeValue(getMember(rt, el, name))
|
|
59233
|
+
);
|
|
59234
|
+
return horzcat(...values);
|
|
59235
|
+
}
|
|
57388
59236
|
return getRTValueField(mv, name);
|
|
57389
59237
|
}
|
|
57390
|
-
function getMemberDynamic(base, nameExpr) {
|
|
57391
|
-
const mv = ensureRuntimeValue(base);
|
|
59238
|
+
function getMemberDynamic(rt, base, nameExpr) {
|
|
57392
59239
|
const name = toString(ensureRuntimeValue(nameExpr));
|
|
57393
|
-
return
|
|
59240
|
+
return ensureRuntimeValue(getMember(rt, base, name));
|
|
57394
59241
|
}
|
|
57395
59242
|
function getMemberOrEmpty(base, name) {
|
|
57396
59243
|
try {
|
|
@@ -57412,7 +59259,7 @@ function setMemberReturn(rt, base, name, rhs) {
|
|
|
57412
59259
|
if (setter) {
|
|
57413
59260
|
rt.activeAccessors.add(accessorKey);
|
|
57414
59261
|
try {
|
|
57415
|
-
const result = setter(
|
|
59262
|
+
const result = setter(0, base, rhs);
|
|
57416
59263
|
return result !== void 0 ? result : base;
|
|
57417
59264
|
} finally {
|
|
57418
59265
|
rt.activeAccessors.delete(accessorKey);
|
|
@@ -57424,10 +59271,8 @@ function setMemberReturn(rt, base, name, rhs) {
|
|
|
57424
59271
|
return setRTValueField(mv, name, rhsMv, rt);
|
|
57425
59272
|
}
|
|
57426
59273
|
function setMemberDynamicReturn(rt, base, nameExpr, rhs) {
|
|
57427
|
-
const mv = ensureRuntimeValue(base);
|
|
57428
59274
|
const name = toString(ensureRuntimeValue(nameExpr));
|
|
57429
|
-
|
|
57430
|
-
return setRTValueField(mv, name, rhsMv, rt);
|
|
59275
|
+
return ensureRuntimeValue(setMemberReturn(rt, base, name, rhs));
|
|
57431
59276
|
}
|
|
57432
59277
|
function subsrefCall(rt, base, names) {
|
|
57433
59278
|
const mv = ensureRuntimeValue(base);
|
|
@@ -58722,7 +60567,7 @@ function marchingCubes(dims, getVal, getCoord, iso, opts) {
|
|
|
58722
60567
|
}
|
|
58723
60568
|
return { vertices, faces, colors };
|
|
58724
60569
|
}
|
|
58725
|
-
function
|
|
60570
|
+
function isNumericArg3(v) {
|
|
58726
60571
|
return typeof v === "number" || typeof v === "boolean" || isRuntimeTensor(v);
|
|
58727
60572
|
}
|
|
58728
60573
|
function dims3(v) {
|
|
@@ -58739,7 +60584,7 @@ function isosurfaceFromArgs(args) {
|
|
|
58739
60584
|
if (isRuntimeChar(a) || isRuntimeString(a)) {
|
|
58740
60585
|
const s = toString(a).toLowerCase();
|
|
58741
60586
|
if (s === "noshare") share = false;
|
|
58742
|
-
} else if (
|
|
60587
|
+
} else if (isNumericArg3(a)) {
|
|
58743
60588
|
nums.push(a);
|
|
58744
60589
|
}
|
|
58745
60590
|
}
|
|
@@ -60076,7 +61921,7 @@ var Runtime = class _Runtime {
|
|
|
60076
61921
|
return getMember(this, base, name);
|
|
60077
61922
|
}
|
|
60078
61923
|
getMemberDynamic(base, nameExpr) {
|
|
60079
|
-
return getMemberDynamic(base, nameExpr);
|
|
61924
|
+
return getMemberDynamic(this, base, nameExpr);
|
|
60080
61925
|
}
|
|
60081
61926
|
getMemberOrEmpty(base, name) {
|
|
60082
61927
|
return getMemberOrEmpty(base, name);
|
|
@@ -60274,6 +62119,13 @@ function defaultClassInstanceVertcat(rows) {
|
|
|
60274
62119
|
}
|
|
60275
62120
|
|
|
60276
62121
|
// src/numbl-core/jsUserFunctions.ts
|
|
62122
|
+
function callHandle(handle, args, nargout = 1) {
|
|
62123
|
+
const rt = getCurrentRuntime();
|
|
62124
|
+
if (!rt) {
|
|
62125
|
+
throw new RuntimeError("callHandle: no active runtime to invoke handle");
|
|
62126
|
+
}
|
|
62127
|
+
return rt.index(handle, args, nargout);
|
|
62128
|
+
}
|
|
60277
62129
|
function funcNameFromFile(fileName) {
|
|
60278
62130
|
const base = fileName.split("/").pop();
|
|
60279
62131
|
return base.replace(/\.numbl\.js$/, "");
|
|
@@ -60319,6 +62171,8 @@ function instantiateWasm(wasmData) {
|
|
|
60319
62171
|
const moduleImports = WebAssembly.Module.imports(wasmModule);
|
|
60320
62172
|
const importObject = {};
|
|
60321
62173
|
const neededModules = new Set(moduleImports.map((i) => i.module));
|
|
62174
|
+
const callbacks = /* @__PURE__ */ new Map();
|
|
62175
|
+
let nextCbId = 1;
|
|
60322
62176
|
if (neededModules.has("wasi_snapshot_preview1")) {
|
|
60323
62177
|
importObject.wasi_snapshot_preview1 = {
|
|
60324
62178
|
fd_write: () => 0,
|
|
@@ -60338,10 +62192,36 @@ function instantiateWasm(wasmData) {
|
|
|
60338
62192
|
if (neededModules.has("env")) {
|
|
60339
62193
|
importObject.env = {
|
|
60340
62194
|
emscripten_notify_memory_growth: () => {
|
|
62195
|
+
},
|
|
62196
|
+
// Scalar callback: WASM calls back into a registered handle with one
|
|
62197
|
+
// f64 and receives an f64. Exceptions thrown here (incl. a missing id)
|
|
62198
|
+
// propagate out through the WASM call into the apply.
|
|
62199
|
+
numbl_cb_d: (id, x) => {
|
|
62200
|
+
const fn = callbacks.get(id);
|
|
62201
|
+
if (!fn) {
|
|
62202
|
+
throw new RuntimeError(
|
|
62203
|
+
`numbl_cb_d: no callback registered for id ${id}`
|
|
62204
|
+
);
|
|
62205
|
+
}
|
|
62206
|
+
return fn(x);
|
|
60341
62207
|
}
|
|
60342
62208
|
};
|
|
60343
62209
|
}
|
|
60344
|
-
|
|
62210
|
+
const instance = new WebAssembly.Instance(
|
|
62211
|
+
wasmModule,
|
|
62212
|
+
importObject
|
|
62213
|
+
);
|
|
62214
|
+
instance.callbacks = {
|
|
62215
|
+
add(fn) {
|
|
62216
|
+
const id = nextCbId++;
|
|
62217
|
+
callbacks.set(id, fn);
|
|
62218
|
+
return id;
|
|
62219
|
+
},
|
|
62220
|
+
remove(id) {
|
|
62221
|
+
callbacks.delete(id);
|
|
62222
|
+
}
|
|
62223
|
+
};
|
|
62224
|
+
return instance;
|
|
60345
62225
|
}
|
|
60346
62226
|
function resolveBindings(file, directives, getWasmInstance, nativeBridge) {
|
|
60347
62227
|
const wasmInstance = directives.wasm ? getWasmInstance(directives.wasm) : void 0;
|
|
@@ -60416,6 +62296,8 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge) {
|
|
|
60416
62296
|
"wasm",
|
|
60417
62297
|
"native",
|
|
60418
62298
|
"importJS",
|
|
62299
|
+
"callHandle",
|
|
62300
|
+
"toNumber",
|
|
60419
62301
|
libFile.source
|
|
60420
62302
|
);
|
|
60421
62303
|
const exports = factory(
|
|
@@ -60425,7 +62307,9 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge) {
|
|
|
60425
62307
|
dummyRegister,
|
|
60426
62308
|
wasmInstance,
|
|
60427
62309
|
nativeLib,
|
|
60428
|
-
importJS
|
|
62310
|
+
importJS,
|
|
62311
|
+
callHandle,
|
|
62312
|
+
toNumber
|
|
60429
62313
|
);
|
|
60430
62314
|
libCache.set(name, exports);
|
|
60431
62315
|
return exports;
|
|
@@ -60463,6 +62347,8 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge) {
|
|
|
60463
62347
|
"wasm",
|
|
60464
62348
|
"native",
|
|
60465
62349
|
"importJS",
|
|
62350
|
+
"callHandle",
|
|
62351
|
+
"toNumber",
|
|
60466
62352
|
file.source
|
|
60467
62353
|
);
|
|
60468
62354
|
factory(
|
|
@@ -60472,7 +62358,9 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge) {
|
|
|
60472
62358
|
registerFn,
|
|
60473
62359
|
wasmInstance,
|
|
60474
62360
|
nativeLib,
|
|
60475
|
-
importJS
|
|
62361
|
+
importJS,
|
|
62362
|
+
callHandle,
|
|
62363
|
+
toNumber
|
|
60476
62364
|
);
|
|
60477
62365
|
if (!builtin) {
|
|
60478
62366
|
throw new Error(
|
|
@@ -60724,6 +62612,7 @@ function resolveFunctionImpl(name, argTypes, callSite, index2) {
|
|
|
60724
62612
|
for (const argType of argTypes) {
|
|
60725
62613
|
if (argType?.kind === "ClassInstance") {
|
|
60726
62614
|
const className = argType.className;
|
|
62615
|
+
if (index2.classConstructors.get(className) === name) continue;
|
|
60727
62616
|
if (!candidates.includes(className) && (index2.classInstanceMethods.get(className)?.has(name) || index2.classStaticMethods.get(className)?.has(name))) {
|
|
60728
62617
|
candidates.push(className);
|
|
60729
62618
|
}
|
|
@@ -60832,12 +62721,25 @@ var Environment = class _Environment {
|
|
|
60832
62721
|
}
|
|
60833
62722
|
/** Function ID for persistent variable storage */
|
|
60834
62723
|
persistentFuncId;
|
|
62724
|
+
/** Call-site variable names of this frame's arguments, for `inputname`.
|
|
62725
|
+
* Entry i is the name of the variable passed as argument i+1, or '' if
|
|
62726
|
+
* that argument was not a plain variable. Undefined when the call did
|
|
62727
|
+
* not originate from an interpreted call expression (e.g. feval, JIT).
|
|
62728
|
+
* Read directly off the executing frame — the interpreter has only
|
|
62729
|
+
* function-level scoping, so `this.env` is the frame while a body runs. */
|
|
62730
|
+
inputArgNames;
|
|
60835
62731
|
/** Back-reference to the runtime (needed for global/persistent access) */
|
|
60836
62732
|
rt = null;
|
|
60837
62733
|
/** Set when a `@nestedFn` handle has been created that captures this env
|
|
60838
62734
|
* (or an ancestor). Tells the function-exit cleanup that clearing this
|
|
60839
62735
|
* env would strand the handle's closure, so locals must be left alive. */
|
|
60840
62736
|
nestedHandleCreated = false;
|
|
62737
|
+
/** For a nested-function frame: the names of this function's own formal
|
|
62738
|
+
* input/output arguments. These are always local — a write must never be
|
|
62739
|
+
* redirected to a same-named variable in the parent, even before the
|
|
62740
|
+
* output has been assigned. (MATLAB scopes a nested function's formal
|
|
62741
|
+
* arguments to that function; only other variables are shared.) */
|
|
62742
|
+
nestedLocalNames;
|
|
60841
62743
|
get(name) {
|
|
60842
62744
|
if (this._globalNames !== void 0 && this._globalNames.has(name) && this.rt) {
|
|
60843
62745
|
const v = this.rt.$g[name];
|
|
@@ -60856,7 +62758,7 @@ var Environment = class _Environment {
|
|
|
60856
62758
|
if (old !== void 0) decref(this.rt, old);
|
|
60857
62759
|
return;
|
|
60858
62760
|
}
|
|
60859
|
-
if (this.isNested && !this.vars.has(name) && this.parent) {
|
|
62761
|
+
if (this.isNested && !this.vars.has(name) && this.parent && !this.nestedLocalNames?.has(name)) {
|
|
60860
62762
|
const owner = this.findOwner(name);
|
|
60861
62763
|
if (owner) {
|
|
60862
62764
|
owner.setLocal(name, value);
|
|
@@ -62051,6 +63953,7 @@ function makeRootContext(interp, registry3) {
|
|
|
62051
63953
|
var interpreterExec_exports = {};
|
|
62052
63954
|
__export(interpreterExec_exports, {
|
|
62053
63955
|
assignLValue: () => assignLValue,
|
|
63956
|
+
computeInputNames: () => computeInputNames,
|
|
62054
63957
|
evalAnonFunc: () => evalAnonFunc,
|
|
62055
63958
|
evalArgs: () => evalArgs,
|
|
62056
63959
|
evalBinary: () => evalBinary,
|
|
@@ -62077,6 +63980,15 @@ __export(interpreterExec_exports, {
|
|
|
62077
63980
|
writeLValueBase: () => writeLValueBase
|
|
62078
63981
|
});
|
|
62079
63982
|
|
|
63983
|
+
// src/numbl-core/jitDeclineDiagnostics.ts
|
|
63984
|
+
var lastDecline = null;
|
|
63985
|
+
function recordJitDecline(d) {
|
|
63986
|
+
lastDecline = d;
|
|
63987
|
+
}
|
|
63988
|
+
function getLastJitDecline() {
|
|
63989
|
+
return lastDecline;
|
|
63990
|
+
}
|
|
63991
|
+
|
|
62080
63992
|
// src/numbl-core/runtime/cow.ts
|
|
62081
63993
|
function cowCopy(v) {
|
|
62082
63994
|
if (isRuntimeTensor(v)) {
|
|
@@ -62353,6 +64265,11 @@ function execStmtInner(stmt) {
|
|
|
62353
64265
|
case "Global": {
|
|
62354
64266
|
for (const name of stmt.names) {
|
|
62355
64267
|
this.env.globalNames.add(name);
|
|
64268
|
+
if (this.rt && !(name in this.rt.$g)) {
|
|
64269
|
+
const empty = RTV.tensor(allocFloat64Array(0), [0, 0]);
|
|
64270
|
+
incref(empty);
|
|
64271
|
+
this.rt.$g[name] = empty;
|
|
64272
|
+
}
|
|
62356
64273
|
}
|
|
62357
64274
|
return null;
|
|
62358
64275
|
}
|
|
@@ -62374,14 +64291,16 @@ function execStmtInner(stmt) {
|
|
|
62374
64291
|
case "Directive": {
|
|
62375
64292
|
if (stmt.directive === "assert_jit") {
|
|
62376
64293
|
const wantC = stmt.args.includes("c");
|
|
64294
|
+
const decline = getLastJitDecline();
|
|
64295
|
+
const why = decline ? ` Most recent JIT decline (${decline.where}, ${decline.kind}): ${decline.message}` : ` (no JIT decline reason was recorded \u2014 the unit may have been declined before lowering, e.g. an unsupported input type.)`;
|
|
62377
64296
|
if (this.optimization === "1") {
|
|
62378
64297
|
throw new RuntimeError(
|
|
62379
|
-
`%!numbl:assert_jit: expected the enclosing loop/function/script to be JS-JIT-compiled at --opt 1, but it ran in the interpreter
|
|
64298
|
+
`%!numbl:assert_jit: expected the enclosing loop/function/script to be JS-JIT-compiled at --opt 1, but it ran in the interpreter.${why} (Run with --opt 0 to silence.)`
|
|
62380
64299
|
);
|
|
62381
64300
|
}
|
|
62382
64301
|
if (this.optimization === "2" && wantC) {
|
|
62383
64302
|
throw new RuntimeError(
|
|
62384
|
-
`%!numbl:assert_jit c: expected the enclosing loop/function/script to be C-JIT-compiled at --opt 2, but it ran in the interpreter
|
|
64303
|
+
`%!numbl:assert_jit c: expected the enclosing loop/function/script to be C-JIT-compiled at --opt 2, but it ran in the interpreter.${why} (Run with --opt 0 to silence.)`
|
|
62385
64304
|
);
|
|
62386
64305
|
}
|
|
62387
64306
|
}
|
|
@@ -62464,6 +64383,10 @@ function evalExprNargout(expr, nargout) {
|
|
|
62464
64383
|
if (isRuntimeStructArray(rv)) {
|
|
62465
64384
|
return rv.elements.length;
|
|
62466
64385
|
}
|
|
64386
|
+
if (isRuntimeClassInstanceArray(rv)) {
|
|
64387
|
+
if (ctx.numIndices === 1) return rv.elements.length;
|
|
64388
|
+
return ctx.dimIndex < rv.shape.length ? rv.shape[ctx.dimIndex] : 1;
|
|
64389
|
+
}
|
|
62467
64390
|
if (isRuntimeSparseMatrix(rv)) {
|
|
62468
64391
|
if (ctx.numIndices === 1) return rv.m * rv.n;
|
|
62469
64392
|
return ctx.dimIndex === 0 ? rv.m : ctx.dimIndex === 1 ? rv.n : 1;
|
|
@@ -62624,6 +64547,23 @@ function evalExprNargout(expr, nargout) {
|
|
|
62624
64547
|
throw new RuntimeError("Interpreter does not yet support meta.class");
|
|
62625
64548
|
}
|
|
62626
64549
|
}
|
|
64550
|
+
function computeInputNames(argExprs, callerEnv) {
|
|
64551
|
+
const names = [];
|
|
64552
|
+
let blanked = false;
|
|
64553
|
+
for (const a of argExprs) {
|
|
64554
|
+
if (blanked) {
|
|
64555
|
+
names.push("");
|
|
64556
|
+
} else if (a.type === "Ident" && callerEnv.has(a.name)) {
|
|
64557
|
+
names.push(a.name);
|
|
64558
|
+
} else if (a.type === "IndexCell" || a.type === "Member" || a.type === "MemberDynamic") {
|
|
64559
|
+
names.push("");
|
|
64560
|
+
blanked = true;
|
|
64561
|
+
} else {
|
|
64562
|
+
names.push("");
|
|
64563
|
+
}
|
|
64564
|
+
}
|
|
64565
|
+
return names;
|
|
64566
|
+
}
|
|
62627
64567
|
function evalArgs(argExprs) {
|
|
62628
64568
|
const args = [];
|
|
62629
64569
|
for (const a of argExprs) {
|
|
@@ -62753,6 +64693,7 @@ function evalFuncCall(expr, nargout) {
|
|
|
62753
64693
|
const c = getConstant(expr.name);
|
|
62754
64694
|
if (c !== void 0) return c;
|
|
62755
64695
|
}
|
|
64696
|
+
this.pendingInputNames = expr.args.length > 0 ? computeInputNames(expr.args, this.env) : void 0;
|
|
62756
64697
|
return this.callFunction(expr.name, args, nargout);
|
|
62757
64698
|
}
|
|
62758
64699
|
function evalMember(expr, nargout) {
|
|
@@ -62932,7 +64873,14 @@ function makeFuncHandle(name) {
|
|
|
62932
64873
|
);
|
|
62933
64874
|
};
|
|
62934
64875
|
fn.jsFnExpectsNargout = true;
|
|
62935
|
-
|
|
64876
|
+
let narg = getIBuiltinNargin(name);
|
|
64877
|
+
if (narg === void 0) {
|
|
64878
|
+
try {
|
|
64879
|
+
narg = this.declaredNargin(name);
|
|
64880
|
+
} catch {
|
|
64881
|
+
narg = void 0;
|
|
64882
|
+
}
|
|
64883
|
+
}
|
|
62936
64884
|
if (narg !== void 0) fn.nargin = narg;
|
|
62937
64885
|
if (isNested) {
|
|
62938
64886
|
fn.releaseExtra = () => capturedEnv.clearLocals();
|
|
@@ -63221,6 +65169,7 @@ __export(interpreterFunctions_exports, {
|
|
|
63221
65169
|
callNestedFunction: () => callNestedFunction,
|
|
63222
65170
|
callUserFunction: () => callUserFunction,
|
|
63223
65171
|
collectClassProperties: () => collectClassProperties,
|
|
65172
|
+
declaredNargin: () => declaredNargin,
|
|
63224
65173
|
evalInLocalScope: () => evalInLocalScope,
|
|
63225
65174
|
findExternalMethod: () => findExternalMethod,
|
|
63226
65175
|
findFunctionInClassFile: () => findFunctionInClassFile,
|
|
@@ -63523,6 +65472,30 @@ register("isa", (ctx, args) => {
|
|
|
63523
65472
|
if (args.length !== 2) return FALL_THROUGH;
|
|
63524
65473
|
return ctx.rt.isa(args[0], args[1]);
|
|
63525
65474
|
});
|
|
65475
|
+
register("superclasses", (ctx, args) => {
|
|
65476
|
+
if (args.length !== 1) return FALL_THROUGH;
|
|
65477
|
+
const v = ensureRuntimeValue(args[0]);
|
|
65478
|
+
let className;
|
|
65479
|
+
if (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v)) {
|
|
65480
|
+
className = v.className;
|
|
65481
|
+
} else if (isRuntimeChar(v) || isRuntimeString(v)) {
|
|
65482
|
+
className = toString(v);
|
|
65483
|
+
}
|
|
65484
|
+
const names = [];
|
|
65485
|
+
if (className) {
|
|
65486
|
+
const seen = /* @__PURE__ */ new Set([className]);
|
|
65487
|
+
let current = ctx.rt.getClassParentName(className);
|
|
65488
|
+
while (current && !seen.has(current)) {
|
|
65489
|
+
names.push(current);
|
|
65490
|
+
seen.add(current);
|
|
65491
|
+
current = ctx.rt.getClassParentName(current);
|
|
65492
|
+
}
|
|
65493
|
+
}
|
|
65494
|
+
return RTV.cell(
|
|
65495
|
+
names.map((n) => RTV.string(n)),
|
|
65496
|
+
[names.length, 1]
|
|
65497
|
+
);
|
|
65498
|
+
});
|
|
63526
65499
|
register("__inferred_type_str", (_ctx, args) => {
|
|
63527
65500
|
if (args.length !== 1) return FALL_THROUGH;
|
|
63528
65501
|
const rv = ensureRuntimeValue(args[0]);
|
|
@@ -63547,6 +65520,44 @@ register("nargout", (ctx, args) => {
|
|
|
63547
65520
|
const v = ctx.env.get("$nargout");
|
|
63548
65521
|
return v !== void 0 ? v : 0;
|
|
63549
65522
|
});
|
|
65523
|
+
register("inputname", (ctx, args) => {
|
|
65524
|
+
if (args.length !== 1) return FALL_THROUGH;
|
|
65525
|
+
const narginVal = ctx.env.get("$nargin");
|
|
65526
|
+
if (typeof narginVal !== "number") {
|
|
65527
|
+
throw new RuntimeError(
|
|
65528
|
+
"You can only call 'inputname' from within a MATLAB function."
|
|
65529
|
+
);
|
|
65530
|
+
}
|
|
65531
|
+
const k = toNumber(ensureRuntimeValue(args[0]));
|
|
65532
|
+
if (!Number.isInteger(k) || k < 1) {
|
|
65533
|
+
throw new RuntimeError(
|
|
65534
|
+
"Argument number must be a positive integer scalar."
|
|
65535
|
+
);
|
|
65536
|
+
}
|
|
65537
|
+
if (k > narginVal) {
|
|
65538
|
+
throw new RuntimeError(
|
|
65539
|
+
"Argument number exceeds number of function input arguments."
|
|
65540
|
+
);
|
|
65541
|
+
}
|
|
65542
|
+
const names = ctx.env.inputArgNames;
|
|
65543
|
+
const name = names && k <= names.length ? names[k - 1] : "";
|
|
65544
|
+
return RTV.char(name);
|
|
65545
|
+
});
|
|
65546
|
+
register("properties", (ctx, args) => {
|
|
65547
|
+
if (args.length !== 1) return FALL_THROUGH;
|
|
65548
|
+
const v = ensureRuntimeValue(args[0]);
|
|
65549
|
+
let names;
|
|
65550
|
+
if (isRuntimeClassInstance(v) || isRuntimeClassInstanceArray(v)) {
|
|
65551
|
+
names = ctx.classPublicProperties(v.className);
|
|
65552
|
+
} else if (isRuntimeChar(v) || isRuntimeString(v)) {
|
|
65553
|
+
names = ctx.classPublicProperties(toString(v));
|
|
65554
|
+
}
|
|
65555
|
+
if (!names) return RTV.cell([], [0, 1]);
|
|
65556
|
+
return RTV.cell(
|
|
65557
|
+
names.map((n) => RTV.string(n)),
|
|
65558
|
+
[names.length, 1]
|
|
65559
|
+
);
|
|
65560
|
+
});
|
|
63550
65561
|
register("narginchk", (ctx, args) => {
|
|
63551
65562
|
if (args.length !== 2) return FALL_THROUGH;
|
|
63552
65563
|
const narginVal = ctx.env.get("$nargin");
|
|
@@ -63651,10 +65662,14 @@ function callFunction(name, args, nargout) {
|
|
|
63651
65662
|
source: ""
|
|
63652
65663
|
};
|
|
63653
65664
|
return void 0;
|
|
63654
|
-
}
|
|
65665
|
+
},
|
|
65666
|
+
classPublicProperties: (n) => classPublicProperties(this, n)
|
|
63655
65667
|
};
|
|
63656
65668
|
const result = specialHandler(ctx, args, nargout);
|
|
63657
|
-
if (result !== FALL_THROUGH)
|
|
65669
|
+
if (result !== FALL_THROUGH) {
|
|
65670
|
+
this.pendingInputNames = void 0;
|
|
65671
|
+
return result;
|
|
65672
|
+
}
|
|
63658
65673
|
}
|
|
63659
65674
|
const nested = this.env.getNestedFunction(name);
|
|
63660
65675
|
if (nested) {
|
|
@@ -63674,6 +65689,75 @@ function callFunction(name, args, nargout) {
|
|
|
63674
65689
|
}
|
|
63675
65690
|
throw new RuntimeError(`Undefined function or variable '${name}'`);
|
|
63676
65691
|
}
|
|
65692
|
+
function narginFromParams(params) {
|
|
65693
|
+
const hasVarargin = params.length > 0 && params[params.length - 1] === "varargin";
|
|
65694
|
+
return hasVarargin ? -params.length : params.length;
|
|
65695
|
+
}
|
|
65696
|
+
function paramsInFile(interp, fileName, funcName) {
|
|
65697
|
+
const ast = interp.ctx.getCachedAST(fileName);
|
|
65698
|
+
for (const stmt of ast.body) {
|
|
65699
|
+
if (stmt.type === "Function" && stmt.name === funcName) return stmt.params;
|
|
65700
|
+
}
|
|
65701
|
+
return void 0;
|
|
65702
|
+
}
|
|
65703
|
+
function declaredNargin(name) {
|
|
65704
|
+
const nested = this.env.getNestedFunction(name);
|
|
65705
|
+
if (nested) return narginFromParams(nested.fn.params);
|
|
65706
|
+
const callSite = {
|
|
65707
|
+
file: this.currentFile,
|
|
65708
|
+
...this.currentClassName ? { className: this.currentClassName } : {},
|
|
65709
|
+
...this.currentMethodName ? { methodName: this.currentMethodName } : {}
|
|
65710
|
+
};
|
|
65711
|
+
const target = resolveFunction(name, [], callSite, this.functionIndex);
|
|
65712
|
+
if (!target) return void 0;
|
|
65713
|
+
let params;
|
|
65714
|
+
switch (target.kind) {
|
|
65715
|
+
case "localFunction": {
|
|
65716
|
+
const { source } = target;
|
|
65717
|
+
if (source.from === "main") {
|
|
65718
|
+
params = this.mainLocalFunctions.get(target.name)?.params;
|
|
65719
|
+
} else if (source.from === "workspaceFile") {
|
|
65720
|
+
params = this.findFunctionInWorkspaceFile(source.wsName, target.name)?.params ?? void 0;
|
|
65721
|
+
} else if (source.from === "classFile") {
|
|
65722
|
+
params = this.findFunctionInClassFile(
|
|
65723
|
+
source.className,
|
|
65724
|
+
target.name,
|
|
65725
|
+
source.methodScope
|
|
65726
|
+
)?.params ?? void 0;
|
|
65727
|
+
} else if (source.from === "privateFile") {
|
|
65728
|
+
params = paramsInFile(this, source.callerFile, target.name);
|
|
65729
|
+
}
|
|
65730
|
+
break;
|
|
65731
|
+
}
|
|
65732
|
+
case "workspaceFunction": {
|
|
65733
|
+
const dotIdx = target.name.lastIndexOf(".");
|
|
65734
|
+
const primaryName = dotIdx >= 0 ? target.name.slice(dotIdx + 1) : target.name;
|
|
65735
|
+
params = this.findFunctionInWorkspaceFile(target.name, primaryName)?.params ?? void 0;
|
|
65736
|
+
if (params === void 0) {
|
|
65737
|
+
const entry = this.ctx.registry.filesByFuncName.get(target.name);
|
|
65738
|
+
if (entry) {
|
|
65739
|
+
const ast = this.ctx.getCachedAST(entry.fileName);
|
|
65740
|
+
for (const stmt of ast.body) {
|
|
65741
|
+
if (stmt.type === "Function") {
|
|
65742
|
+
params = stmt.params;
|
|
65743
|
+
break;
|
|
65744
|
+
}
|
|
65745
|
+
}
|
|
65746
|
+
}
|
|
65747
|
+
}
|
|
65748
|
+
break;
|
|
65749
|
+
}
|
|
65750
|
+
case "privateFunction": {
|
|
65751
|
+
const entry = this.ctx.getPrivateFileEntry(
|
|
65752
|
+
target.callerFile,
|
|
65753
|
+
target.name
|
|
65754
|
+
);
|
|
65755
|
+
if (entry) params = paramsInFile(this, entry.fileName, target.name);
|
|
65756
|
+
break;
|
|
65757
|
+
}
|
|
65758
|
+
}
|
|
65759
|
+
return params !== void 0 ? narginFromParams(params) : void 0;
|
|
65760
|
+
}
|
|
63677
65761
|
function interpretTarget(target, args, nargout) {
|
|
63678
65762
|
switch (target.kind) {
|
|
63679
65763
|
case "builtin": {
|
|
@@ -63842,18 +65926,12 @@ function interpretWorkspaceFunction(target, args, nargout) {
|
|
|
63842
65926
|
if (entry) {
|
|
63843
65927
|
const ast = this.ctx.getCachedAST(entry.fileName);
|
|
63844
65928
|
return this.withFileContext(entry.fileName, void 0, void 0, () => {
|
|
63845
|
-
const
|
|
63846
|
-
|
|
63847
|
-
|
|
63848
|
-
|
|
63849
|
-
if (stmt.type === "Function") continue;
|
|
63850
|
-
const signal = this.execStmt(stmt);
|
|
63851
|
-
if (signal instanceof ReturnSignal) break;
|
|
63852
|
-
}
|
|
63853
|
-
return this.ans;
|
|
63854
|
-
} finally {
|
|
63855
|
-
this.env = savedEnv;
|
|
65929
|
+
for (const stmt of ast.body) {
|
|
65930
|
+
if (stmt.type === "Function") continue;
|
|
65931
|
+
const signal = this.execStmt(stmt);
|
|
65932
|
+
if (signal instanceof ReturnSignal) break;
|
|
63856
65933
|
}
|
|
65934
|
+
return this.ans;
|
|
63857
65935
|
});
|
|
63858
65936
|
}
|
|
63859
65937
|
throw new RuntimeError(`Workspace function '${target.name}' not found`);
|
|
@@ -63920,6 +65998,21 @@ function instantiateClass(className, args, nargout) {
|
|
|
63920
65998
|
if (!classInfo) {
|
|
63921
65999
|
return this.rt.callClassMethod(className, className, nargout, args);
|
|
63922
66000
|
}
|
|
66001
|
+
if (classInfo.isOldStyle) {
|
|
66002
|
+
const ctorName = classInfo.constructorName ?? className;
|
|
66003
|
+
const ctorFn = this.findExternalMethod(classInfo, ctorName);
|
|
66004
|
+
if (!ctorFn)
|
|
66005
|
+
throw new RuntimeError(
|
|
66006
|
+
`Constructor for old-style class '${className}' not found`
|
|
66007
|
+
);
|
|
66008
|
+
const fileName = classInfo.externalMethodFiles.get(ctorName)?.fileName ?? classInfo.fileName;
|
|
66009
|
+
return this.withFileContext(
|
|
66010
|
+
fileName,
|
|
66011
|
+
className,
|
|
66012
|
+
ctorName,
|
|
66013
|
+
() => this.callUserFunction(ctorFn, args, nargout)
|
|
66014
|
+
);
|
|
66015
|
+
}
|
|
63923
66016
|
const { propertyNames, propertyDefaults } = this.collectClassProperties(classInfo);
|
|
63924
66017
|
const defaults = /* @__PURE__ */ new Map();
|
|
63925
66018
|
for (const [propName, defaultExpr] of propertyDefaults) {
|
|
@@ -63943,7 +66036,7 @@ function instantiateClass(className, args, nargout) {
|
|
|
63943
66036
|
function interpretConstructor(classInfo, args, nargout) {
|
|
63944
66037
|
const constructorName = classInfo.constructorName;
|
|
63945
66038
|
if (!constructorName) return args[0];
|
|
63946
|
-
for (const member of classInfo.ast
|
|
66039
|
+
for (const member of classInfo.ast?.members ?? []) {
|
|
63947
66040
|
if (member.type !== "Methods") continue;
|
|
63948
66041
|
for (const methodStmt of member.body) {
|
|
63949
66042
|
if (methodStmt.type === "Function" && methodStmt.name === constructorName) {
|
|
@@ -63985,6 +66078,8 @@ function callUserFunction(fn, args, nargout, narginOverride) {
|
|
|
63985
66078
|
if (!hasVarargoutDecl && nargout > declaredRegularOutputs) {
|
|
63986
66079
|
throw new RuntimeError("Too many output arguments.");
|
|
63987
66080
|
}
|
|
66081
|
+
const callInputNames = this.pendingInputNames;
|
|
66082
|
+
this.pendingInputNames = void 0;
|
|
63988
66083
|
const sharedArgs = args;
|
|
63989
66084
|
if (narginOverride === void 0 && this.registry.size > 0) {
|
|
63990
66085
|
const r = this.registry.dispatchCall(fn, sharedArgs, nargout, this);
|
|
@@ -64018,6 +66113,7 @@ function callUserFunction(fn, args, nargout, narginOverride) {
|
|
|
64018
66113
|
}
|
|
64019
66114
|
fnEnv.set("$nargin", narginOverride ?? args.length);
|
|
64020
66115
|
fnEnv.set("$nargout", nargout);
|
|
66116
|
+
fnEnv.inputArgNames = callInputNames;
|
|
64021
66117
|
for (const stmt of fn.body) {
|
|
64022
66118
|
if (stmt.type === "Function") {
|
|
64023
66119
|
fnEnv.nestedFunctions.set(stmt.name, {
|
|
@@ -64094,10 +66190,13 @@ function callUserFunction(fn, args, nargout, narginOverride) {
|
|
|
64094
66190
|
}
|
|
64095
66191
|
}
|
|
64096
66192
|
function callNestedFunction(fn, parentEnv, args, nargout) {
|
|
66193
|
+
const callInputNames = this.pendingInputNames;
|
|
66194
|
+
this.pendingInputNames = void 0;
|
|
64097
66195
|
const fnEnv = new Environment(parentEnv);
|
|
64098
66196
|
fnEnv.isNested = true;
|
|
64099
66197
|
fnEnv.rt = this.rt;
|
|
64100
66198
|
fnEnv.persistentFuncId = `${this.currentFile}:${fn.name}`;
|
|
66199
|
+
fnEnv.nestedLocalNames = /* @__PURE__ */ new Set([...fn.params, ...fn.outputs]);
|
|
64101
66200
|
const hasVarargin = fn.params.length > 0 && fn.params[fn.params.length - 1] === "varargin";
|
|
64102
66201
|
const regularParams = hasVarargin ? fn.params.slice(0, -1) : fn.params;
|
|
64103
66202
|
for (let i = 0; i < regularParams.length; i++) {
|
|
@@ -64111,6 +66210,15 @@ function callNestedFunction(fn, parentEnv, args, nargout) {
|
|
|
64111
66210
|
}
|
|
64112
66211
|
fnEnv.setLocal("$nargin", args.length);
|
|
64113
66212
|
fnEnv.setLocal("$nargout", nargout);
|
|
66213
|
+
fnEnv.inputArgNames = callInputNames;
|
|
66214
|
+
for (const stmt of fn.body) {
|
|
66215
|
+
if (stmt.type === "Function") {
|
|
66216
|
+
fnEnv.nestedFunctions.set(stmt.name, {
|
|
66217
|
+
fn: funcDefFromStmt(stmt),
|
|
66218
|
+
env: fnEnv
|
|
66219
|
+
});
|
|
66220
|
+
}
|
|
66221
|
+
}
|
|
64114
66222
|
const savedEnv = this.env;
|
|
64115
66223
|
this.env = fnEnv;
|
|
64116
66224
|
this.rt.pushCleanupScope();
|
|
@@ -64249,7 +66357,7 @@ function findMethodInClass(classInfo, methodName) {
|
|
|
64249
66357
|
const cacheKey = `method:${classInfo.name}:${methodName}`;
|
|
64250
66358
|
const cached = this.functionDefCache.get(cacheKey);
|
|
64251
66359
|
if (cached) return cached;
|
|
64252
|
-
for (const member of classInfo.ast
|
|
66360
|
+
for (const member of classInfo.ast?.members ?? []) {
|
|
64253
66361
|
if (member.type !== "Methods") continue;
|
|
64254
66362
|
for (const methodStmt of member.body) {
|
|
64255
66363
|
if (methodStmt.type === "Function" && methodStmt.name === methodName) {
|
|
@@ -64306,6 +66414,36 @@ function collectClassProperties(classInfo) {
|
|
|
64306
66414
|
}
|
|
64307
66415
|
return { propertyNames, propertyDefaults };
|
|
64308
66416
|
}
|
|
66417
|
+
function classPublicProperties(interp, className) {
|
|
66418
|
+
let info = interp.ctx.getClassInfo(className);
|
|
66419
|
+
if (!info) return void 0;
|
|
66420
|
+
const out = [];
|
|
66421
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66422
|
+
while (info) {
|
|
66423
|
+
const ast = info.ast;
|
|
66424
|
+
if (ast) {
|
|
66425
|
+
for (const member of ast.members) {
|
|
66426
|
+
if (member.type !== "Properties") continue;
|
|
66427
|
+
const hidden = member.attributes.some((a) => {
|
|
66428
|
+
const n = a.name.toLowerCase();
|
|
66429
|
+
if (n !== "access" && n !== "getaccess") return false;
|
|
66430
|
+
const val = (a.value ?? "").toLowerCase();
|
|
66431
|
+
return val === "private" || val === "protected";
|
|
66432
|
+
});
|
|
66433
|
+
if (hidden) continue;
|
|
66434
|
+
for (const pn of member.names) {
|
|
66435
|
+
if (!seen.has(pn)) {
|
|
66436
|
+
seen.add(pn);
|
|
66437
|
+
out.push(pn);
|
|
66438
|
+
}
|
|
66439
|
+
}
|
|
66440
|
+
}
|
|
66441
|
+
}
|
|
66442
|
+
if (!info.superClass || info.superClass === "handle") break;
|
|
66443
|
+
info = interp.ctx.getClassInfo(info.superClass);
|
|
66444
|
+
}
|
|
66445
|
+
return out;
|
|
66446
|
+
}
|
|
64309
66447
|
function isHandleClass(classInfo) {
|
|
64310
66448
|
let parentName = classInfo.superClass;
|
|
64311
66449
|
while (parentName) {
|
|
@@ -64424,6 +66562,10 @@ var Interpreter = class {
|
|
|
64424
66562
|
workspaceEnv;
|
|
64425
66563
|
/** @internal The caller's environment — for evalin/assignin('caller', ...) */
|
|
64426
66564
|
callerEnv;
|
|
66565
|
+
/** @internal Call-site variable names for the next user-function call, set
|
|
66566
|
+
* by `evalFuncCall` and consumed by `callUserFunction` to support
|
|
66567
|
+
* `inputname`. One-shot: cleared as soon as it is consumed. */
|
|
66568
|
+
pendingInputNames;
|
|
64427
66569
|
/** @internal Stack of [base, dimIndex, numIndices] for resolving `end` keyword in indexing. */
|
|
64428
66570
|
endContextStack = [];
|
|
64429
66571
|
/** @internal Number of enclosing `for` / `while` loop bodies the
|
|
@@ -64685,6 +66827,37 @@ function extractClassInfo(classDef, qualifiedName, fileName, source) {
|
|
|
64685
66827
|
externalMethodFiles: /* @__PURE__ */ new Map()
|
|
64686
66828
|
};
|
|
64687
66829
|
}
|
|
66830
|
+
function makeOldStyleClassInfo(qualifiedName, baseName, constructorFile, methodFiles) {
|
|
66831
|
+
const externalMethodFiles = /* @__PURE__ */ new Map();
|
|
66832
|
+
externalMethodFiles.set(baseName, {
|
|
66833
|
+
fileName: constructorFile.fileName,
|
|
66834
|
+
source: constructorFile.source
|
|
66835
|
+
});
|
|
66836
|
+
const methodNames = /* @__PURE__ */ new Set();
|
|
66837
|
+
for (const mf of methodFiles) {
|
|
66838
|
+
externalMethodFiles.set(mf.name, {
|
|
66839
|
+
fileName: mf.fileName,
|
|
66840
|
+
source: mf.source
|
|
66841
|
+
});
|
|
66842
|
+
methodNames.add(mf.name);
|
|
66843
|
+
}
|
|
66844
|
+
return {
|
|
66845
|
+
name: baseName,
|
|
66846
|
+
qualifiedName,
|
|
66847
|
+
fileName: constructorFile.fileName,
|
|
66848
|
+
source: constructorFile.source,
|
|
66849
|
+
superClass: null,
|
|
66850
|
+
propertyNames: [],
|
|
66851
|
+
propertyDefaults: /* @__PURE__ */ new Map(),
|
|
66852
|
+
methodNames,
|
|
66853
|
+
staticMethodNames: /* @__PURE__ */ new Set(),
|
|
66854
|
+
constructorName: baseName,
|
|
66855
|
+
inferiorClasses: [],
|
|
66856
|
+
ast: null,
|
|
66857
|
+
isOldStyle: true,
|
|
66858
|
+
externalMethodFiles
|
|
66859
|
+
};
|
|
66860
|
+
}
|
|
64688
66861
|
|
|
64689
66862
|
// src/numbl-core/lowering/loweringContext.ts
|
|
64690
66863
|
function createWorkspaceRegistry() {
|
|
@@ -64877,8 +67050,41 @@ var LoweringContext = class _LoweringContext {
|
|
|
64877
67050
|
}
|
|
64878
67051
|
}
|
|
64879
67052
|
}
|
|
67053
|
+
const startsWithClassdef = (source) => {
|
|
67054
|
+
let t = source.trimStart();
|
|
67055
|
+
while (t.startsWith("%")) {
|
|
67056
|
+
const nl = t.indexOf("\n");
|
|
67057
|
+
if (nl < 0) return false;
|
|
67058
|
+
t = t.slice(nl + 1).trimStart();
|
|
67059
|
+
}
|
|
67060
|
+
return t.startsWith("classdef");
|
|
67061
|
+
};
|
|
64880
67062
|
for (const [className, group] of classFolderGroups) {
|
|
64881
|
-
|
|
67063
|
+
const hasRealClassdef = !!group.classDefFile && startsWithClassdef(group.classDefFile.source);
|
|
67064
|
+
if (!hasRealClassdef) {
|
|
67065
|
+
const dotIdx = className.lastIndexOf(".");
|
|
67066
|
+
const baseName = dotIdx >= 0 ? className.slice(dotIdx + 1) : className;
|
|
67067
|
+
const methodBase = (f) => f.name.split("/").pop().replace(/\.m$/, "");
|
|
67068
|
+
const ctorFile = group.classDefFile ?? group.methodFiles.find((f) => methodBase(f) === baseName);
|
|
67069
|
+
if (!ctorFile) {
|
|
67070
|
+
continue;
|
|
67071
|
+
}
|
|
67072
|
+
const methodFiles = group.methodFiles.filter((f) => f !== ctorFile).map((f) => ({
|
|
67073
|
+
name: methodBase(f),
|
|
67074
|
+
fileName: f.name,
|
|
67075
|
+
source: f.source
|
|
67076
|
+
}));
|
|
67077
|
+
if (!this.registry.classesByName.has(className)) {
|
|
67078
|
+
this.registry.classesByName.set(
|
|
67079
|
+
className,
|
|
67080
|
+
makeOldStyleClassInfo(
|
|
67081
|
+
className,
|
|
67082
|
+
baseName,
|
|
67083
|
+
{ fileName: ctorFile.name, source: ctorFile.source },
|
|
67084
|
+
methodFiles
|
|
67085
|
+
)
|
|
67086
|
+
);
|
|
67087
|
+
}
|
|
64882
67088
|
continue;
|
|
64883
67089
|
}
|
|
64884
67090
|
this.registerWorkspaceClass(className, group.classDefFile);
|
|
@@ -65114,7 +67320,7 @@ var LoweringContext = class _LoweringContext {
|
|
|
65114
67320
|
if (!info) return null;
|
|
65115
67321
|
if (info.ctx) return info.ctx;
|
|
65116
67322
|
const ctx = new _LoweringContext(info.source, info.fileName);
|
|
65117
|
-
for (const member of info.ast
|
|
67323
|
+
for (const member of info.ast?.members ?? []) {
|
|
65118
67324
|
if (member.type !== "Methods") continue;
|
|
65119
67325
|
for (const methodStmt of member.body) {
|
|
65120
67326
|
if (methodStmt.type !== "Function") continue;
|
|
@@ -65273,6 +67479,7 @@ var LoweringContext = class _LoweringContext {
|
|
|
65273
67479
|
for (const m of info.methodNames) instanceMethods.add(m);
|
|
65274
67480
|
for (const m of info.staticMethodNames) staticMethods.add(m);
|
|
65275
67481
|
for (const m of info.externalMethodFiles.keys()) {
|
|
67482
|
+
if (info.isOldStyle && m === info.constructorName) continue;
|
|
65276
67483
|
if (!info.staticMethodNames.has(m)) {
|
|
65277
67484
|
instanceMethods.add(m);
|
|
65278
67485
|
}
|
|
@@ -65316,10 +67523,43 @@ var LoweringContext = class _LoweringContext {
|
|
|
65316
67523
|
}
|
|
65317
67524
|
}
|
|
65318
67525
|
const fileImports = /* @__PURE__ */ new Map();
|
|
67526
|
+
const gatherImports = (body, out) => {
|
|
67527
|
+
for (const stmt of body) {
|
|
67528
|
+
switch (stmt.type) {
|
|
67529
|
+
case "Import":
|
|
67530
|
+
out.push(stmt);
|
|
67531
|
+
break;
|
|
67532
|
+
case "Function":
|
|
67533
|
+
case "While":
|
|
67534
|
+
case "For":
|
|
67535
|
+
gatherImports(stmt.body, out);
|
|
67536
|
+
break;
|
|
67537
|
+
case "If":
|
|
67538
|
+
gatherImports(stmt.thenBody, out);
|
|
67539
|
+
for (const b of stmt.elseifBlocks) gatherImports(b.body, out);
|
|
67540
|
+
if (stmt.elseBody) gatherImports(stmt.elseBody, out);
|
|
67541
|
+
break;
|
|
67542
|
+
case "Switch":
|
|
67543
|
+
for (const c of stmt.cases) gatherImports(c.body, out);
|
|
67544
|
+
if (stmt.otherwise) gatherImports(stmt.otherwise, out);
|
|
67545
|
+
break;
|
|
67546
|
+
case "TryCatch":
|
|
67547
|
+
gatherImports(stmt.tryBody, out);
|
|
67548
|
+
gatherImports(stmt.catchBody, out);
|
|
67549
|
+
break;
|
|
67550
|
+
case "ClassDef":
|
|
67551
|
+
for (const member of stmt.members) {
|
|
67552
|
+
if (member.type === "Methods") gatherImports(member.body, out);
|
|
67553
|
+
}
|
|
67554
|
+
break;
|
|
67555
|
+
}
|
|
67556
|
+
}
|
|
67557
|
+
};
|
|
65319
67558
|
const collectImportsFromBody = (body, fileName) => {
|
|
65320
67559
|
const entries = [];
|
|
65321
|
-
|
|
65322
|
-
|
|
67560
|
+
const importStmts = [];
|
|
67561
|
+
gatherImports(body, importStmts);
|
|
67562
|
+
for (const stmt of importStmts) {
|
|
65323
67563
|
if (stmt.wildcard) {
|
|
65324
67564
|
entries.push({ wildcard: true, namespace: stmt.path.join(".") });
|
|
65325
67565
|
} else {
|
|
@@ -65394,6 +67634,10 @@ var LoweringContext = class _LoweringContext {
|
|
|
65394
67634
|
|
|
65395
67635
|
// src/numbl-core/stdlib-bundle.ts
|
|
65396
67636
|
var stdlibFiles = [
|
|
67637
|
+
{
|
|
67638
|
+
name: "TriRep.m",
|
|
67639
|
+
source: "classdef TriRep < triangulation\n % (Not recommended) Triangulation representation. Provided for legacy\n % code; use triangulation instead. TriRep inherits freeBoundary,\n % vertexAttachments, etc. from triangulation and exposes the legacy\n % property names X (vertex coordinates) and Triangulation (connectivity).\n %\n % TR = TriRep(tri, x, y)\n % TR = TriRep(tri, x, y, z)\n % TR = TriRep(tri, P)\n properties\n X\n Triangulation\n end\n methods\n function obj = TriRep(tri, varargin)\n obj = obj@triangulation(tri, varargin{:});\n obj.X = obj.Points;\n obj.Triangulation = obj.ConnectivityList;\n end\n end\nend\n"
|
|
67640
|
+
},
|
|
65397
67641
|
{
|
|
65398
67642
|
name: "addOptional.m",
|
|
65399
67643
|
source: "function addOptional(obj, name, default, validator)\n if nargin < 4\n obj.addOptional(name, default);\n else\n obj.addOptional(name, default, validator);\n end\nend\n"
|
|
@@ -65421,6 +67665,10 @@ var stdlibFiles = [
|
|
|
65421
67665
|
{
|
|
65422
67666
|
name: "readmatrix.m",
|
|
65423
67667
|
source: "function A = readmatrix(filename, varargin)\n % Parse name-value pairs\n delimiter = '';\n numHeaderLines = -1; % -1 means auto-detect\n\n i = 1;\n while i <= length(varargin)\n if ischar(varargin{i}) || isstring(varargin{i})\n key = lower(char(varargin{i}));\n if strcmp(key, 'delimiter')\n delimiter = char(varargin{i+1});\n i = i + 2;\n elseif strcmp(key, 'numheaderlines')\n numHeaderLines = varargin{i+1};\n i = i + 2;\n else\n % Skip unknown name-value pairs\n i = i + 2;\n end\n else\n i = i + 1;\n end\n end\n\n % Auto-detect delimiter from extension if not specified\n if isempty(delimiter)\n [~, ~, ext] = fileparts(filename);\n if strcmp(ext, '.csv')\n delimiter = ',';\n else\n delimiter = ''; % will split on whitespace\n end\n end\n\n % Read the entire file\n txt = fileread(filename);\n\n % Split into lines\n lines = strsplit(txt, sprintf('\\n'));\n\n % Remove trailing empty line (from trailing newline)\n if ~isempty(lines) && strcmp(strtrim(char(lines{end})), '')\n lines = lines(1:end-1);\n end\n\n if isempty(lines)\n A = [];\n return;\n end\n\n % Auto-detect header lines: skip lines that can't be fully parsed as numbers\n if numHeaderLines < 0\n numHeaderLines = 0;\n for k = 1:length(lines)\n line = strtrim(char(lines{k}));\n if strcmp(line, '')\n numHeaderLines = numHeaderLines + 1;\n continue;\n end\n if ~isempty(delimiter)\n parts = strsplit(line, delimiter);\n else\n parts = strsplit(line);\n end\n allNumeric = true;\n for j = 1:length(parts)\n val = str2double(strtrim(char(parts{j})));\n if isnan(val)\n token = strtrim(char(parts{j}));\n % Allow NaN, Inf, -Inf as valid numeric tokens\n if ~strcmpi(token, 'nan') && ~strcmpi(token, 'inf') && ~strcmpi(token, '-inf')\n allNumeric = false;\n break;\n end\n end\n end\n if allNumeric\n break;\n else\n numHeaderLines = numHeaderLines + 1;\n end\n end\n end\n\n % Parse data lines\n dataLines = lines(numHeaderLines+1:end);\n nRows = length(dataLines);\n if nRows == 0\n A = [];\n return;\n end\n\n % First pass: determine number of columns from first data line\n firstLine = strtrim(char(dataLines{1}));\n if ~isempty(delimiter)\n parts = strsplit(firstLine, delimiter);\n else\n parts = strsplit(firstLine);\n end\n nCols = length(parts);\n\n A = zeros(nRows, nCols);\n for r = 1:nRows\n line = strtrim(char(dataLines{r}));\n if strcmp(line, '')\n A(r, :) = NaN;\n continue;\n end\n if ~isempty(delimiter)\n parts = strsplit(line, delimiter);\n else\n parts = strsplit(line);\n end\n for c = 1:min(length(parts), nCols)\n val = str2double(strtrim(char(parts{c})));\n if isnan(val)\n token = strtrim(char(parts{c}));\n if strcmpi(token, 'nan')\n A(r, c) = NaN;\n elseif strcmpi(token, 'inf')\n A(r, c) = Inf;\n elseif strcmpi(token, '-inf')\n A(r, c) = -Inf;\n else\n A(r, c) = NaN; % non-numeric data becomes NaN\n end\n else\n A(r, c) = val;\n end\n end\n % Fill missing columns with NaN\n if length(parts) < nCols\n A(r, length(parts)+1:nCols) = NaN;\n end\n end\nend\n"
|
|
67668
|
+
},
|
|
67669
|
+
{
|
|
67670
|
+
name: "triangulation.m",
|
|
67671
|
+
source: "classdef triangulation\n % Triangulation representation providing topological queries over a\n % triangle (or tetrahedron) mesh. Mirrors a subset of MATLAB's\n % triangulation class.\n %\n % TR = triangulation(tri, P) % P is an n-by-d coordinate matrix\n % TR = triangulation(tri, x, y) % 2-D vertex coordinate columns\n % TR = triangulation(tri, x, y, z) % 3-D vertex coordinate columns\n properties\n Points\n ConnectivityList\n end\n methods\n function obj = triangulation(tri, varargin)\n if nargin == 0\n return;\n end\n obj.ConnectivityList = tri;\n if numel(varargin) == 1\n obj.Points = varargin{1};\n elseif numel(varargin) >= 2\n obj.Points = [varargin{:}];\n else\n error('triangulation: vertex coordinates are required');\n end\n end\n\n function [F, P] = freeBoundary(obj)\n % Free boundary facets: the edges referenced by exactly one\n % triangle, ordered into connected, consistently oriented loops.\n tri = obj.ConnectivityList;\n E = [tri(:, [1 2]); tri(:, [2 3]); tri(:, [3 1])];\n Es = sort(E, 2);\n [~, ~, ic] = unique(Es, 'rows');\n counts = accumarray(ic, 1);\n isB = counts(ic) == 1;\n bedges = E(isB, :);\n\n n = size(bedges, 1);\n F = zeros(n, 2);\n used = false(n, 1);\n pos = 1;\n while pos <= n\n startRow = find(~used, 1);\n if isempty(startRow)\n break;\n end\n cur = startRow;\n loopStart = bedges(cur, 1);\n while true\n F(pos, :) = bedges(cur, :);\n used(cur) = true;\n pos = pos + 1;\n nextv = bedges(cur, 2);\n if nextv == loopStart\n break;\n end\n cand = find(~used & bedges(:, 1) == nextv, 1);\n if isempty(cand)\n break;\n end\n cur = cand;\n end\n end\n\n if nargout > 1\n vid = unique(F(:));\n P = obj.Points(vid, :);\n remap = zeros(max(vid), 1);\n remap(vid) = 1:numel(vid);\n F = remap(F);\n end\n end\n\n function V = vertexAttachments(obj, id)\n % IDs of the triangles attached to each vertex, returned as a\n % cell array with one row vector of triangle IDs per vertex.\n tri = obj.ConnectivityList;\n nv = size(obj.Points, 1);\n if nargin < 2\n id = (1:nv)';\n end\n id = id(:);\n V = cell(numel(id), 1);\n for k = 1:numel(id)\n V{k} = find(any(tri == id(k), 2))';\n end\n end\n end\nend\n"
|
|
65424
67672
|
}
|
|
65425
67673
|
];
|
|
65426
67674
|
var shimFiles = [
|
|
@@ -74963,6 +77211,30 @@ var sin = defineUnaryRealMath({
|
|
|
74963
77211
|
complex: { cFnComplex: "mtoc2_csin", jsFnComplex: cSin }
|
|
74964
77212
|
});
|
|
74965
77213
|
|
|
77214
|
+
// src/numbl-core/jit/builtins/defs/math/rand.ts
|
|
77215
|
+
var rand = {
|
|
77216
|
+
name: "rand",
|
|
77217
|
+
transfer(argTypes, nargout) {
|
|
77218
|
+
if (nargout > 1) {
|
|
77219
|
+
throw new UnsupportedConstruct(
|
|
77220
|
+
`'rand' does not support multi-output (nargout=${nargout})`
|
|
77221
|
+
);
|
|
77222
|
+
}
|
|
77223
|
+
if (argTypes.length !== 0) {
|
|
77224
|
+
throw new UnsupportedConstruct(
|
|
77225
|
+
`JS-JIT 'rand' supports only the scalar form rand() so far (got ${argTypes.length} arg(s)); matrix/seed forms run in the interpreter`
|
|
77226
|
+
);
|
|
77227
|
+
}
|
|
77228
|
+
return [scalarDouble("nonneg")];
|
|
77229
|
+
},
|
|
77230
|
+
emitJs() {
|
|
77231
|
+
return "$rand()";
|
|
77232
|
+
},
|
|
77233
|
+
call() {
|
|
77234
|
+
return [rngRandom()];
|
|
77235
|
+
}
|
|
77236
|
+
};
|
|
77237
|
+
|
|
74966
77238
|
// src/numbl-core/jit/builtins/defs/math/tan.ts
|
|
74967
77239
|
var tan = defineUnaryRealMath({
|
|
74968
77240
|
name: "tan",
|
|
@@ -80346,6 +82618,7 @@ for (const b of [
|
|
|
80346
82618
|
stdBuiltin,
|
|
80347
82619
|
min,
|
|
80348
82620
|
max,
|
|
82621
|
+
rand,
|
|
80349
82622
|
any,
|
|
80350
82623
|
all,
|
|
80351
82624
|
zeros,
|
|
@@ -86131,12 +88404,13 @@ function emitJsProgram(prog, opts = {}) {
|
|
|
86131
88404
|
const wrapperLines = [];
|
|
86132
88405
|
if (opts.exposeSpec !== void 0) {
|
|
86133
88406
|
wrapperLines.push(
|
|
86134
|
-
`return function ($h) { globalThis.$write = $h.write; globalThis.$plotDispatch = $h.plotDispatch; return ${opts.exposeSpec}; };`
|
|
88407
|
+
`return function ($h) { globalThis.$write = $h.write; globalThis.$plotDispatch = $h.plotDispatch; globalThis.$rand = $h.rand; return ${opts.exposeSpec}; };`
|
|
86135
88408
|
);
|
|
86136
88409
|
} else {
|
|
86137
88410
|
wrapperLines.push("function run($h) {");
|
|
86138
88411
|
wrapperLines.push(" globalThis.$write = $h.write;");
|
|
86139
88412
|
wrapperLines.push(" globalThis.$plotDispatch = $h.plotDispatch;");
|
|
88413
|
+
wrapperLines.push(" globalThis.$rand = $h.rand;");
|
|
86140
88414
|
const locals = collectAssignedLocals(prog.topLevelStmts);
|
|
86141
88415
|
if (locals.length > 0) {
|
|
86142
88416
|
wrapperLines.push(` let ${locals.join(", ")};`);
|
|
@@ -87684,6 +89958,7 @@ var Workspace = class _Workspace {
|
|
|
87684
89958
|
}
|
|
87685
89959
|
};
|
|
87686
89960
|
for (const [name, info] of this.ctx.registry.classesByName) {
|
|
89961
|
+
if (info.isOldStyle) continue;
|
|
87687
89962
|
registerOrDefer(
|
|
87688
89963
|
name,
|
|
87689
89964
|
() => registerClassDef(
|
|
@@ -87697,7 +89972,7 @@ var Workspace = class _Workspace {
|
|
|
87697
89972
|
if (this.classes.has(name) || this.failedClassValidations.has(name)) {
|
|
87698
89973
|
throw new UnsupportedConstruct(
|
|
87699
89974
|
`class '${name}' is defined both locally and as a workspace class`,
|
|
87700
|
-
info.ast
|
|
89975
|
+
info.ast?.span
|
|
87701
89976
|
);
|
|
87702
89977
|
}
|
|
87703
89978
|
registerOrDefer(name, () => registerClassDef(info.ast, info.fileName));
|
|
@@ -87791,7 +90066,7 @@ var Workspace = class _Workspace {
|
|
|
87791
90066
|
if (!ast) {
|
|
87792
90067
|
throw new UnsupportedConstruct(
|
|
87793
90068
|
`internal: external method file '${mf.fileName}' for '${info.qualifiedName}.${methodName}' was not parsed`,
|
|
87794
|
-
info.ast
|
|
90069
|
+
info.ast?.span
|
|
87795
90070
|
);
|
|
87796
90071
|
}
|
|
87797
90072
|
let primary = null;
|
|
@@ -87807,7 +90082,7 @@ var Workspace = class _Workspace {
|
|
|
87807
90082
|
if (!primary) {
|
|
87808
90083
|
throw new UnsupportedConstruct(
|
|
87809
90084
|
`external method file '${mf.fileName}' has no function`,
|
|
87810
|
-
info.ast
|
|
90085
|
+
info.ast?.span
|
|
87811
90086
|
);
|
|
87812
90087
|
}
|
|
87813
90088
|
out.set(methodName, primary);
|
|
@@ -88172,6 +90447,7 @@ function getOrCreateSession(interp) {
|
|
|
88172
90447
|
function buildHostHelpers(rt) {
|
|
88173
90448
|
return {
|
|
88174
90449
|
write: (s) => rt.output(s),
|
|
90450
|
+
rand: () => rngRandom(),
|
|
88175
90451
|
plotDispatch: (name, args) => {
|
|
88176
90452
|
const runtimeArgs = args.map((a) => jitToNumbl(a));
|
|
88177
90453
|
const handled = dispatchPlotBuiltin(
|
|
@@ -88264,6 +90540,11 @@ var jitCallExecutor = {
|
|
|
88264
90540
|
return { specFn };
|
|
88265
90541
|
} catch (e) {
|
|
88266
90542
|
if (e instanceof UnsupportedConstruct || e instanceof TypeError2) {
|
|
90543
|
+
recordJitDecline({
|
|
90544
|
+
message: e.message,
|
|
90545
|
+
kind: e.constructor.name,
|
|
90546
|
+
where: "jit-call"
|
|
90547
|
+
});
|
|
88267
90548
|
return null;
|
|
88268
90549
|
}
|
|
88269
90550
|
throw e;
|
|
@@ -88390,6 +90671,11 @@ var jitLoopExecutor = {
|
|
|
88390
90671
|
return { specFn };
|
|
88391
90672
|
} catch (e) {
|
|
88392
90673
|
if (e instanceof UnsupportedConstruct || e instanceof TypeError2) {
|
|
90674
|
+
recordJitDecline({
|
|
90675
|
+
message: e.message,
|
|
90676
|
+
kind: e.constructor.name,
|
|
90677
|
+
where: "jit-loop"
|
|
90678
|
+
});
|
|
88393
90679
|
return null;
|
|
88394
90680
|
}
|
|
88395
90681
|
throw e;
|
|
@@ -88530,6 +90816,11 @@ var jitTopLevelExecutor = {
|
|
|
88530
90816
|
return { specFn, nargout };
|
|
88531
90817
|
} catch (e) {
|
|
88532
90818
|
if (e instanceof UnsupportedConstruct || e instanceof TypeError2) {
|
|
90819
|
+
recordJitDecline({
|
|
90820
|
+
message: e.message,
|
|
90821
|
+
kind: e.constructor.name,
|
|
90822
|
+
where: "jit-top-level"
|
|
90823
|
+
});
|
|
88533
90824
|
return null;
|
|
88534
90825
|
}
|
|
88535
90826
|
throw e;
|
|
@@ -89191,10 +91482,783 @@ async function load() {
|
|
|
89191
91482
|
const { loadQhull } = await import("qhull-wasm");
|
|
89192
91483
|
const qhull = await loadQhull();
|
|
89193
91484
|
setDelaunayBackend((points, dim) => qhull.delaunay(points, dim).facets);
|
|
91485
|
+
setConvexHullBackend((points, dim) => qhull.convexHull(points, dim).facets);
|
|
89194
91486
|
}
|
|
91487
|
+
|
|
91488
|
+
// src/vfs/VirtualFileSystem.ts
|
|
91489
|
+
var VirtualFileSystem = class {
|
|
91490
|
+
files = /* @__PURE__ */ new Map();
|
|
91491
|
+
directories = /* @__PURE__ */ new Set();
|
|
91492
|
+
cwd = "/project";
|
|
91493
|
+
// Change tracking
|
|
91494
|
+
createdFiles = /* @__PURE__ */ new Set();
|
|
91495
|
+
modifiedFiles = /* @__PURE__ */ new Set();
|
|
91496
|
+
deletedFiles = /* @__PURE__ */ new Set();
|
|
91497
|
+
/** Clear change tracking. Call after populating the VFS with initial files. */
|
|
91498
|
+
clearChangeTracking() {
|
|
91499
|
+
this.createdFiles.clear();
|
|
91500
|
+
this.modifiedFiles.clear();
|
|
91501
|
+
this.deletedFiles.clear();
|
|
91502
|
+
}
|
|
91503
|
+
/** Normalize a path to absolute form. */
|
|
91504
|
+
normalizePath(p2) {
|
|
91505
|
+
if (!p2.startsWith("/")) {
|
|
91506
|
+
p2 = this.cwd + "/" + p2;
|
|
91507
|
+
}
|
|
91508
|
+
const parts = p2.split("/");
|
|
91509
|
+
const resolved = [];
|
|
91510
|
+
for (const part of parts) {
|
|
91511
|
+
if (part === "" || part === ".") continue;
|
|
91512
|
+
if (part === "..") {
|
|
91513
|
+
if (resolved.length > 0) resolved.pop();
|
|
91514
|
+
} else {
|
|
91515
|
+
resolved.push(part);
|
|
91516
|
+
}
|
|
91517
|
+
}
|
|
91518
|
+
return "/" + resolved.join("/");
|
|
91519
|
+
}
|
|
91520
|
+
getCwd() {
|
|
91521
|
+
return this.cwd;
|
|
91522
|
+
}
|
|
91523
|
+
setCwd(dir) {
|
|
91524
|
+
this.cwd = this.normalizePath(dir);
|
|
91525
|
+
}
|
|
91526
|
+
readFile(path) {
|
|
91527
|
+
const norm2 = this.normalizePath(path);
|
|
91528
|
+
const file = this.files.get(norm2);
|
|
91529
|
+
if (!file) throw new Error(`File not found: ${path}`);
|
|
91530
|
+
return file.content;
|
|
91531
|
+
}
|
|
91532
|
+
writeFile(path, content) {
|
|
91533
|
+
const norm2 = this.normalizePath(path);
|
|
91534
|
+
const existed = this.files.has(norm2);
|
|
91535
|
+
this.files.set(norm2, { content, mtimeMs: Date.now() });
|
|
91536
|
+
this.ensureParentDirs(norm2);
|
|
91537
|
+
if (this.deletedFiles.has(norm2)) {
|
|
91538
|
+
this.deletedFiles.delete(norm2);
|
|
91539
|
+
this.modifiedFiles.add(norm2);
|
|
91540
|
+
} else if (!existed) {
|
|
91541
|
+
this.createdFiles.add(norm2);
|
|
91542
|
+
} else if (!this.createdFiles.has(norm2)) {
|
|
91543
|
+
this.modifiedFiles.add(norm2);
|
|
91544
|
+
}
|
|
91545
|
+
}
|
|
91546
|
+
deleteFile(path) {
|
|
91547
|
+
const norm2 = this.normalizePath(path);
|
|
91548
|
+
if (!this.files.has(norm2)) return false;
|
|
91549
|
+
this.files.delete(norm2);
|
|
91550
|
+
if (this.createdFiles.has(norm2)) {
|
|
91551
|
+
this.createdFiles.delete(norm2);
|
|
91552
|
+
this.modifiedFiles.delete(norm2);
|
|
91553
|
+
} else {
|
|
91554
|
+
this.modifiedFiles.delete(norm2);
|
|
91555
|
+
this.deletedFiles.add(norm2);
|
|
91556
|
+
}
|
|
91557
|
+
return true;
|
|
91558
|
+
}
|
|
91559
|
+
exists(path) {
|
|
91560
|
+
const norm2 = this.normalizePath(path);
|
|
91561
|
+
if (this.files.has(norm2)) return "file";
|
|
91562
|
+
if (this.directories.has(norm2)) return "dir";
|
|
91563
|
+
const prefix = norm2 + "/";
|
|
91564
|
+
for (const key of this.files.keys()) {
|
|
91565
|
+
if (key.startsWith(prefix)) return "dir";
|
|
91566
|
+
}
|
|
91567
|
+
return null;
|
|
91568
|
+
}
|
|
91569
|
+
fileSize(path) {
|
|
91570
|
+
const norm2 = this.normalizePath(path);
|
|
91571
|
+
const file = this.files.get(norm2);
|
|
91572
|
+
return file ? file.content.length : 0;
|
|
91573
|
+
}
|
|
91574
|
+
mkdir(dirPath) {
|
|
91575
|
+
const norm2 = this.normalizePath(dirPath);
|
|
91576
|
+
this.directories.add(norm2);
|
|
91577
|
+
this.ensureParentDirs(norm2 + "/placeholder");
|
|
91578
|
+
return true;
|
|
91579
|
+
}
|
|
91580
|
+
/** Move/rename a file or directory tree. Returns true on success. */
|
|
91581
|
+
movefile(source, destination) {
|
|
91582
|
+
const srcNorm = this.normalizePath(source);
|
|
91583
|
+
const srcType = this.exists(srcNorm);
|
|
91584
|
+
if (srcType === null) return false;
|
|
91585
|
+
let dstNorm = this.normalizePath(destination);
|
|
91586
|
+
const dstType = this.exists(dstNorm);
|
|
91587
|
+
if (dstType === "dir") {
|
|
91588
|
+
const lastSlash = srcNorm.lastIndexOf("/");
|
|
91589
|
+
const baseName = lastSlash >= 0 ? srcNorm.slice(lastSlash + 1) : srcNorm;
|
|
91590
|
+
dstNorm = (dstNorm === "/" ? "" : dstNorm) + "/" + baseName;
|
|
91591
|
+
}
|
|
91592
|
+
if (srcType === "dir" && this.exists(dstNorm) === "file") return false;
|
|
91593
|
+
if (srcType === "file") {
|
|
91594
|
+
const content = this.files.get(srcNorm).content;
|
|
91595
|
+
if (this.exists(dstNorm) === "file") this.deleteFile(dstNorm);
|
|
91596
|
+
this.writeFile(dstNorm, content);
|
|
91597
|
+
this.deleteFile(srcNorm);
|
|
91598
|
+
return true;
|
|
91599
|
+
}
|
|
91600
|
+
const srcPrefix = srcNorm + "/";
|
|
91601
|
+
const filesToMove = [];
|
|
91602
|
+
for (const [path, file] of this.files) {
|
|
91603
|
+
if (path === srcNorm || path.startsWith(srcPrefix)) {
|
|
91604
|
+
const rest = path === srcNorm ? "" : path.slice(srcNorm.length);
|
|
91605
|
+
filesToMove.push({
|
|
91606
|
+
from: path,
|
|
91607
|
+
to: dstNorm + rest,
|
|
91608
|
+
content: file.content
|
|
91609
|
+
});
|
|
91610
|
+
}
|
|
91611
|
+
}
|
|
91612
|
+
const dirsToMove = [];
|
|
91613
|
+
for (const dir of this.directories) {
|
|
91614
|
+
if (dir === srcNorm || dir.startsWith(srcPrefix)) {
|
|
91615
|
+
const rest = dir === srcNorm ? "" : dir.slice(srcNorm.length);
|
|
91616
|
+
dirsToMove.push({ from: dir, to: dstNorm + rest });
|
|
91617
|
+
}
|
|
91618
|
+
}
|
|
91619
|
+
for (const { from } of filesToMove) this.deleteFile(from);
|
|
91620
|
+
for (const { from } of dirsToMove) this.directories.delete(from);
|
|
91621
|
+
this.directories.add(dstNorm);
|
|
91622
|
+
for (const { to } of dirsToMove) this.directories.add(to);
|
|
91623
|
+
for (const { to, content } of filesToMove) this.writeFile(to, content);
|
|
91624
|
+
return true;
|
|
91625
|
+
}
|
|
91626
|
+
/** Copy a file or directory tree (source is left in place). True on success. */
|
|
91627
|
+
copyfile(source, destination) {
|
|
91628
|
+
const srcNorm = this.normalizePath(source);
|
|
91629
|
+
const srcType = this.exists(srcNorm);
|
|
91630
|
+
if (srcType === null) return false;
|
|
91631
|
+
let dstNorm = this.normalizePath(destination);
|
|
91632
|
+
if (this.exists(dstNorm) === "dir") {
|
|
91633
|
+
const lastSlash = srcNorm.lastIndexOf("/");
|
|
91634
|
+
const baseName = lastSlash >= 0 ? srcNorm.slice(lastSlash + 1) : srcNorm;
|
|
91635
|
+
dstNorm = (dstNorm === "/" ? "" : dstNorm) + "/" + baseName;
|
|
91636
|
+
}
|
|
91637
|
+
if (srcType === "dir" && this.exists(dstNorm) === "file") return false;
|
|
91638
|
+
if (srcType === "file") {
|
|
91639
|
+
const content = this.files.get(srcNorm).content;
|
|
91640
|
+
if (this.exists(dstNorm) === "file") this.deleteFile(dstNorm);
|
|
91641
|
+
this.writeFile(dstNorm, content);
|
|
91642
|
+
return true;
|
|
91643
|
+
}
|
|
91644
|
+
const srcPrefix = srcNorm + "/";
|
|
91645
|
+
for (const [path, file] of [...this.files]) {
|
|
91646
|
+
if (path === srcNorm || path.startsWith(srcPrefix)) {
|
|
91647
|
+
const rest = path === srcNorm ? "" : path.slice(srcNorm.length);
|
|
91648
|
+
this.writeFile(dstNorm + rest, file.content);
|
|
91649
|
+
}
|
|
91650
|
+
}
|
|
91651
|
+
for (const dir of [...this.directories]) {
|
|
91652
|
+
if (dir === srcNorm || dir.startsWith(srcPrefix)) {
|
|
91653
|
+
const rest = dir === srcNorm ? "" : dir.slice(srcNorm.length);
|
|
91654
|
+
this.directories.add(dstNorm + rest);
|
|
91655
|
+
}
|
|
91656
|
+
}
|
|
91657
|
+
this.directories.add(dstNorm);
|
|
91658
|
+
return true;
|
|
91659
|
+
}
|
|
91660
|
+
/** Resolve a path to its (normalized) absolute path + attributes, or null. */
|
|
91661
|
+
fileattrib(path) {
|
|
91662
|
+
const norm2 = this.normalizePath(path);
|
|
91663
|
+
const t = this.exists(norm2);
|
|
91664
|
+
if (t === null) return null;
|
|
91665
|
+
return {
|
|
91666
|
+
Name: norm2,
|
|
91667
|
+
directory: t === "dir",
|
|
91668
|
+
UserRead: true,
|
|
91669
|
+
UserWrite: true,
|
|
91670
|
+
UserExecute: t === "dir"
|
|
91671
|
+
};
|
|
91672
|
+
}
|
|
91673
|
+
rmdir(dirPath, recursive) {
|
|
91674
|
+
const norm2 = this.normalizePath(dirPath);
|
|
91675
|
+
if (this.exists(norm2) !== "dir") return false;
|
|
91676
|
+
if (recursive) {
|
|
91677
|
+
const prefix = norm2 + "/";
|
|
91678
|
+
for (const key of [...this.files.keys()]) {
|
|
91679
|
+
if (key.startsWith(prefix)) {
|
|
91680
|
+
this.deleteFile(key);
|
|
91681
|
+
}
|
|
91682
|
+
}
|
|
91683
|
+
for (const dir of [...this.directories]) {
|
|
91684
|
+
if (dir === norm2 || dir.startsWith(prefix)) {
|
|
91685
|
+
this.directories.delete(dir);
|
|
91686
|
+
}
|
|
91687
|
+
}
|
|
91688
|
+
} else {
|
|
91689
|
+
const prefix = norm2 + "/";
|
|
91690
|
+
for (const key of this.files.keys()) {
|
|
91691
|
+
if (key.startsWith(prefix)) return false;
|
|
91692
|
+
}
|
|
91693
|
+
this.directories.delete(norm2);
|
|
91694
|
+
}
|
|
91695
|
+
return true;
|
|
91696
|
+
}
|
|
91697
|
+
/** List entries in a directory. */
|
|
91698
|
+
listDir(dirPath) {
|
|
91699
|
+
const norm2 = this.normalizePath(dirPath);
|
|
91700
|
+
const prefix = norm2 === "/" ? "/" : norm2 + "/";
|
|
91701
|
+
const results = [];
|
|
91702
|
+
const now = Date.now();
|
|
91703
|
+
results.push({
|
|
91704
|
+
name: ".",
|
|
91705
|
+
folder: norm2,
|
|
91706
|
+
bytes: 0,
|
|
91707
|
+
isdir: true,
|
|
91708
|
+
mtimeMs: now
|
|
91709
|
+
});
|
|
91710
|
+
results.push({
|
|
91711
|
+
name: "..",
|
|
91712
|
+
folder: norm2,
|
|
91713
|
+
bytes: 0,
|
|
91714
|
+
isdir: true,
|
|
91715
|
+
mtimeMs: now
|
|
91716
|
+
});
|
|
91717
|
+
const seen = /* @__PURE__ */ new Set();
|
|
91718
|
+
for (const [path, file] of this.files) {
|
|
91719
|
+
if (!path.startsWith(prefix)) continue;
|
|
91720
|
+
const rest = path.slice(prefix.length);
|
|
91721
|
+
const slashIdx = rest.indexOf("/");
|
|
91722
|
+
if (slashIdx === -1) {
|
|
91723
|
+
results.push({
|
|
91724
|
+
name: rest,
|
|
91725
|
+
folder: norm2,
|
|
91726
|
+
bytes: file.content.length,
|
|
91727
|
+
isdir: false,
|
|
91728
|
+
mtimeMs: file.mtimeMs
|
|
91729
|
+
});
|
|
91730
|
+
} else {
|
|
91731
|
+
const dirName = rest.slice(0, slashIdx);
|
|
91732
|
+
if (!seen.has(dirName)) {
|
|
91733
|
+
seen.add(dirName);
|
|
91734
|
+
results.push({
|
|
91735
|
+
name: dirName,
|
|
91736
|
+
folder: norm2,
|
|
91737
|
+
bytes: 0,
|
|
91738
|
+
isdir: true,
|
|
91739
|
+
mtimeMs: now
|
|
91740
|
+
});
|
|
91741
|
+
}
|
|
91742
|
+
}
|
|
91743
|
+
}
|
|
91744
|
+
for (const dir of this.directories) {
|
|
91745
|
+
if (!dir.startsWith(prefix)) continue;
|
|
91746
|
+
const rest = dir.slice(prefix.length);
|
|
91747
|
+
if (!rest.includes("/") && rest.length > 0 && !seen.has(rest)) {
|
|
91748
|
+
seen.add(rest);
|
|
91749
|
+
results.push({
|
|
91750
|
+
name: rest,
|
|
91751
|
+
folder: norm2,
|
|
91752
|
+
bytes: 0,
|
|
91753
|
+
isdir: true,
|
|
91754
|
+
mtimeMs: now
|
|
91755
|
+
});
|
|
91756
|
+
}
|
|
91757
|
+
}
|
|
91758
|
+
return results;
|
|
91759
|
+
}
|
|
91760
|
+
/** List all file paths in the VFS. */
|
|
91761
|
+
allFiles() {
|
|
91762
|
+
return [...this.files.keys()];
|
|
91763
|
+
}
|
|
91764
|
+
/** Get the changes since the VFS was created. */
|
|
91765
|
+
getChanges() {
|
|
91766
|
+
const created = [];
|
|
91767
|
+
const modified = [];
|
|
91768
|
+
for (const path of this.createdFiles) {
|
|
91769
|
+
const file = this.files.get(path);
|
|
91770
|
+
if (file) created.push({ path, content: file.content });
|
|
91771
|
+
}
|
|
91772
|
+
for (const path of this.modifiedFiles) {
|
|
91773
|
+
const file = this.files.get(path);
|
|
91774
|
+
if (file) modified.push({ path, content: file.content });
|
|
91775
|
+
}
|
|
91776
|
+
return {
|
|
91777
|
+
created,
|
|
91778
|
+
modified,
|
|
91779
|
+
deleted: [...this.deletedFiles]
|
|
91780
|
+
};
|
|
91781
|
+
}
|
|
91782
|
+
ensureParentDirs(path) {
|
|
91783
|
+
const parts = path.split("/").filter(Boolean);
|
|
91784
|
+
for (let i = 1; i < parts.length; i++) {
|
|
91785
|
+
const dir = "/" + parts.slice(0, i).join("/");
|
|
91786
|
+
this.directories.add(dir);
|
|
91787
|
+
}
|
|
91788
|
+
}
|
|
91789
|
+
};
|
|
91790
|
+
|
|
91791
|
+
// src/vfs/BrowserFileIOAdapter.ts
|
|
91792
|
+
import { unzipSync } from "fflate";
|
|
91793
|
+
var TEXT_DECODER = new TextDecoder("utf-8");
|
|
91794
|
+
var TEXT_ENCODER = new TextEncoder();
|
|
91795
|
+
var READ_CHUNK_SIZE = 8192;
|
|
91796
|
+
var BrowserFileIOAdapter = class {
|
|
91797
|
+
constructor(vfs) {
|
|
91798
|
+
this.vfs = vfs;
|
|
91799
|
+
}
|
|
91800
|
+
nextFid = 3;
|
|
91801
|
+
// 0=stdin, 1=stdout, 2=stderr reserved
|
|
91802
|
+
openFiles = /* @__PURE__ */ new Map();
|
|
91803
|
+
fopen(filename, permission) {
|
|
91804
|
+
const perm = permission.replace(/b/g, "");
|
|
91805
|
+
const path = this.vfs.normalizePath(filename);
|
|
91806
|
+
try {
|
|
91807
|
+
let data;
|
|
91808
|
+
let pos = 0;
|
|
91809
|
+
if (perm === "r" || perm === "r+") {
|
|
91810
|
+
if (this.vfs.exists(filename) !== "file") return -1;
|
|
91811
|
+
data = new Uint8Array(this.vfs.readFile(filename));
|
|
91812
|
+
} else if (perm === "w" || perm === "w+") {
|
|
91813
|
+
data = new Uint8Array(0);
|
|
91814
|
+
} else if (perm === "a" || perm === "a+") {
|
|
91815
|
+
if (this.vfs.exists(filename) === "file") {
|
|
91816
|
+
data = new Uint8Array(this.vfs.readFile(filename));
|
|
91817
|
+
pos = data.length;
|
|
91818
|
+
} else {
|
|
91819
|
+
data = new Uint8Array(0);
|
|
91820
|
+
}
|
|
91821
|
+
} else {
|
|
91822
|
+
return -1;
|
|
91823
|
+
}
|
|
91824
|
+
const fid = this.nextFid++;
|
|
91825
|
+
this.openFiles.set(fid, {
|
|
91826
|
+
path,
|
|
91827
|
+
permission: perm,
|
|
91828
|
+
lastError: "",
|
|
91829
|
+
buffer: "",
|
|
91830
|
+
eof: false,
|
|
91831
|
+
pos,
|
|
91832
|
+
data,
|
|
91833
|
+
dataLen: data.length,
|
|
91834
|
+
dirty: perm === "w" || perm === "a"
|
|
91835
|
+
// w starts dirty (truncated or new)
|
|
91836
|
+
});
|
|
91837
|
+
return fid;
|
|
91838
|
+
} catch {
|
|
91839
|
+
return -1;
|
|
91840
|
+
}
|
|
91841
|
+
}
|
|
91842
|
+
fclose(fidOrAll) {
|
|
91843
|
+
if (fidOrAll === "all") {
|
|
91844
|
+
for (const [, entry2] of this.openFiles) {
|
|
91845
|
+
this.flushEntry(entry2);
|
|
91846
|
+
}
|
|
91847
|
+
this.openFiles.clear();
|
|
91848
|
+
return 0;
|
|
91849
|
+
}
|
|
91850
|
+
const entry = this.openFiles.get(fidOrAll);
|
|
91851
|
+
if (!entry) return -1;
|
|
91852
|
+
this.flushEntry(entry);
|
|
91853
|
+
this.openFiles.delete(fidOrAll);
|
|
91854
|
+
return 0;
|
|
91855
|
+
}
|
|
91856
|
+
fgetl(fid) {
|
|
91857
|
+
const entry = this.getEntry(fid);
|
|
91858
|
+
if (!entry) return -1;
|
|
91859
|
+
return this.readLine(entry, false);
|
|
91860
|
+
}
|
|
91861
|
+
fgets(fid) {
|
|
91862
|
+
const entry = this.getEntry(fid);
|
|
91863
|
+
if (!entry) return -1;
|
|
91864
|
+
return this.readLine(entry, true);
|
|
91865
|
+
}
|
|
91866
|
+
fileread(filename) {
|
|
91867
|
+
const data = this.vfs.readFile(filename);
|
|
91868
|
+
return TEXT_DECODER.decode(data);
|
|
91869
|
+
}
|
|
91870
|
+
feof(fid) {
|
|
91871
|
+
const entry = this.getEntry(fid);
|
|
91872
|
+
if (!entry) return 1;
|
|
91873
|
+
if (entry.buffer.length > 0) return 0;
|
|
91874
|
+
if (entry.eof) return 1;
|
|
91875
|
+
if (entry.pos >= entry.dataLen) {
|
|
91876
|
+
entry.eof = true;
|
|
91877
|
+
return 1;
|
|
91878
|
+
}
|
|
91879
|
+
return 0;
|
|
91880
|
+
}
|
|
91881
|
+
ferror(fid) {
|
|
91882
|
+
const entry = this.getEntry(fid);
|
|
91883
|
+
if (!entry) return "Invalid file identifier";
|
|
91884
|
+
return entry.lastError;
|
|
91885
|
+
}
|
|
91886
|
+
fwrite(fid, text) {
|
|
91887
|
+
const entry = this.getEntry(fid);
|
|
91888
|
+
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
91889
|
+
const bytes = TEXT_ENCODER.encode(text);
|
|
91890
|
+
this.writeBytes(entry, bytes);
|
|
91891
|
+
entry.lastError = "";
|
|
91892
|
+
}
|
|
91893
|
+
freadBytes(fid, count) {
|
|
91894
|
+
const entry = this.getEntry(fid);
|
|
91895
|
+
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
91896
|
+
if (entry.buffer.length > 0) {
|
|
91897
|
+
entry.buffer = "";
|
|
91898
|
+
}
|
|
91899
|
+
const available = entry.dataLen - entry.pos;
|
|
91900
|
+
const toRead = Math.min(count, available);
|
|
91901
|
+
if (toRead <= 0) {
|
|
91902
|
+
entry.eof = true;
|
|
91903
|
+
return new Uint8Array(0);
|
|
91904
|
+
}
|
|
91905
|
+
const result = new Uint8Array(toRead);
|
|
91906
|
+
result.set(entry.data.subarray(entry.pos, entry.pos + toRead));
|
|
91907
|
+
entry.pos += toRead;
|
|
91908
|
+
if (entry.pos >= entry.dataLen) entry.eof = true;
|
|
91909
|
+
entry.lastError = "";
|
|
91910
|
+
return result;
|
|
91911
|
+
}
|
|
91912
|
+
fwriteBytes(fid, data) {
|
|
91913
|
+
const entry = this.getEntry(fid);
|
|
91914
|
+
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
91915
|
+
this.writeBytes(entry, data);
|
|
91916
|
+
entry.lastError = "";
|
|
91917
|
+
return data.length;
|
|
91918
|
+
}
|
|
91919
|
+
fseek(fid, offset, origin) {
|
|
91920
|
+
const entry = this.getEntry(fid);
|
|
91921
|
+
if (!entry) return -1;
|
|
91922
|
+
entry.buffer = "";
|
|
91923
|
+
entry.eof = false;
|
|
91924
|
+
if (origin === -1) {
|
|
91925
|
+
entry.pos = offset;
|
|
91926
|
+
} else if (origin === 0) {
|
|
91927
|
+
entry.pos += offset;
|
|
91928
|
+
} else {
|
|
91929
|
+
entry.pos = entry.dataLen + offset;
|
|
91930
|
+
}
|
|
91931
|
+
return 0;
|
|
91932
|
+
}
|
|
91933
|
+
ftell(fid) {
|
|
91934
|
+
const entry = this.getEntry(fid);
|
|
91935
|
+
if (!entry) return -1;
|
|
91936
|
+
return entry.pos;
|
|
91937
|
+
}
|
|
91938
|
+
scanDirectory(dirPath) {
|
|
91939
|
+
const norm2 = this.vfs.normalizePath(dirPath);
|
|
91940
|
+
const prefix = norm2 === "/" ? "/" : norm2 + "/";
|
|
91941
|
+
const results = [];
|
|
91942
|
+
for (const filePath of this.vfs.allFiles()) {
|
|
91943
|
+
if (!filePath.startsWith(prefix)) continue;
|
|
91944
|
+
const relativePath = filePath.slice(prefix.length);
|
|
91945
|
+
if (!relativePath) continue;
|
|
91946
|
+
const segments = relativePath.split("/");
|
|
91947
|
+
const dirs = segments.slice(0, -1);
|
|
91948
|
+
const allSpecial = dirs.every(
|
|
91949
|
+
(d) => d.startsWith("@") || d.startsWith("+") || d === "private"
|
|
91950
|
+
);
|
|
91951
|
+
if (!allSpecial) continue;
|
|
91952
|
+
if (!relativePath.endsWith(".m") && !relativePath.endsWith(".numbl.js") && !relativePath.endsWith(".wasm")) {
|
|
91953
|
+
continue;
|
|
91954
|
+
}
|
|
91955
|
+
try {
|
|
91956
|
+
const content = this.vfs.readFile(filePath);
|
|
91957
|
+
if (relativePath.endsWith(".wasm")) {
|
|
91958
|
+
results.push({
|
|
91959
|
+
name: filePath,
|
|
91960
|
+
source: "",
|
|
91961
|
+
data: new Uint8Array(content)
|
|
91962
|
+
});
|
|
91963
|
+
} else {
|
|
91964
|
+
results.push({
|
|
91965
|
+
name: filePath,
|
|
91966
|
+
source: TEXT_DECODER.decode(content)
|
|
91967
|
+
});
|
|
91968
|
+
}
|
|
91969
|
+
} catch {
|
|
91970
|
+
}
|
|
91971
|
+
}
|
|
91972
|
+
return results;
|
|
91973
|
+
}
|
|
91974
|
+
resolvePath(dirPath) {
|
|
91975
|
+
return this.vfs.normalizePath(dirPath);
|
|
91976
|
+
}
|
|
91977
|
+
existsPath(path) {
|
|
91978
|
+
return this.vfs.exists(path);
|
|
91979
|
+
}
|
|
91980
|
+
mkdir(dirPath) {
|
|
91981
|
+
return this.vfs.mkdir(dirPath);
|
|
91982
|
+
}
|
|
91983
|
+
tempdir() {
|
|
91984
|
+
return "/tmp";
|
|
91985
|
+
}
|
|
91986
|
+
userpath() {
|
|
91987
|
+
return "/system";
|
|
91988
|
+
}
|
|
91989
|
+
deleteFile(pattern) {
|
|
91990
|
+
const norm2 = this.vfs.normalizePath(pattern);
|
|
91991
|
+
if (norm2.includes("*") || norm2.includes("?")) {
|
|
91992
|
+
const lastSlash = norm2.lastIndexOf("/");
|
|
91993
|
+
const dir = norm2.slice(0, lastSlash);
|
|
91994
|
+
const globPat = norm2.slice(lastSlash + 1);
|
|
91995
|
+
const re = new RegExp(
|
|
91996
|
+
"^" + globPat.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$"
|
|
91997
|
+
);
|
|
91998
|
+
const entries = this.vfs.listDir(dir);
|
|
91999
|
+
for (const entry of entries) {
|
|
92000
|
+
if (!entry.isdir && re.test(entry.name)) {
|
|
92001
|
+
this.vfs.deleteFile(dir + "/" + entry.name);
|
|
92002
|
+
}
|
|
92003
|
+
}
|
|
92004
|
+
} else {
|
|
92005
|
+
this.vfs.deleteFile(norm2);
|
|
92006
|
+
}
|
|
92007
|
+
}
|
|
92008
|
+
rmdir(dirPath, recursive) {
|
|
92009
|
+
return this.vfs.rmdir(dirPath, recursive);
|
|
92010
|
+
}
|
|
92011
|
+
movefile(source, destination) {
|
|
92012
|
+
return this.vfs.movefile(source, destination);
|
|
92013
|
+
}
|
|
92014
|
+
copyfile(source, destination) {
|
|
92015
|
+
return this.vfs.copyfile(source, destination);
|
|
92016
|
+
}
|
|
92017
|
+
fileattrib(path) {
|
|
92018
|
+
return this.vfs.fileattrib(path);
|
|
92019
|
+
}
|
|
92020
|
+
listDir(dirPath) {
|
|
92021
|
+
const norm2 = this.vfs.normalizePath(dirPath);
|
|
92022
|
+
if (dirPath.includes("**")) {
|
|
92023
|
+
return this.listDirRecursive(dirPath);
|
|
92024
|
+
}
|
|
92025
|
+
if (dirPath.includes("*") || dirPath.includes("?")) {
|
|
92026
|
+
return this.listDirGlob(dirPath);
|
|
92027
|
+
}
|
|
92028
|
+
const type = this.vfs.exists(dirPath);
|
|
92029
|
+
if (type === "file") {
|
|
92030
|
+
const lastSlash = norm2.lastIndexOf("/");
|
|
92031
|
+
const name = lastSlash >= 0 ? norm2.slice(lastSlash + 1) : norm2;
|
|
92032
|
+
const folder = lastSlash >= 0 ? norm2.slice(0, lastSlash) : "/";
|
|
92033
|
+
return [
|
|
92034
|
+
{
|
|
92035
|
+
name,
|
|
92036
|
+
folder,
|
|
92037
|
+
bytes: this.vfs.fileSize(dirPath),
|
|
92038
|
+
isdir: false,
|
|
92039
|
+
mtimeMs: Date.now()
|
|
92040
|
+
}
|
|
92041
|
+
];
|
|
92042
|
+
}
|
|
92043
|
+
return this.vfs.listDir(dirPath);
|
|
92044
|
+
}
|
|
92045
|
+
websave(url, filename, options) {
|
|
92046
|
+
url = filterUrl(url);
|
|
92047
|
+
const method = options?.requestMethod?.toUpperCase() || "GET";
|
|
92048
|
+
const xhr = new XMLHttpRequest();
|
|
92049
|
+
xhr.open(method, url, false);
|
|
92050
|
+
if (options?.timeout) xhr.timeout = Math.round(options.timeout * 1e3);
|
|
92051
|
+
if (options?.username && options?.password) {
|
|
92052
|
+
xhr.setRequestHeader(
|
|
92053
|
+
"Authorization",
|
|
92054
|
+
"Basic " + btoa(`${options.username}:${options.password}`)
|
|
92055
|
+
);
|
|
92056
|
+
}
|
|
92057
|
+
if (options?.keyName && options?.keyValue) {
|
|
92058
|
+
xhr.setRequestHeader(options.keyName, options.keyValue);
|
|
92059
|
+
}
|
|
92060
|
+
xhr.responseType = "arraybuffer";
|
|
92061
|
+
xhr.send();
|
|
92062
|
+
if (xhr.status < 200 || xhr.status >= 300) {
|
|
92063
|
+
throw new Error(`websave: HTTP ${xhr.status} for ${url}`);
|
|
92064
|
+
}
|
|
92065
|
+
const data = new Uint8Array(xhr.response);
|
|
92066
|
+
this.vfs.writeFile(filename, data);
|
|
92067
|
+
}
|
|
92068
|
+
webread(url, options) {
|
|
92069
|
+
url = filterUrl(url);
|
|
92070
|
+
const method = options?.requestMethod?.toUpperCase() || "GET";
|
|
92071
|
+
const xhr = new XMLHttpRequest();
|
|
92072
|
+
xhr.open(method, url, false);
|
|
92073
|
+
if (options?.timeout) xhr.timeout = Math.round(options.timeout * 1e3);
|
|
92074
|
+
if (options?.username && options?.password) {
|
|
92075
|
+
xhr.setRequestHeader(
|
|
92076
|
+
"Authorization",
|
|
92077
|
+
"Basic " + btoa(`${options.username}:${options.password}`)
|
|
92078
|
+
);
|
|
92079
|
+
}
|
|
92080
|
+
if (options?.keyName && options?.keyValue) {
|
|
92081
|
+
xhr.setRequestHeader(options.keyName, options.keyValue);
|
|
92082
|
+
}
|
|
92083
|
+
xhr.send();
|
|
92084
|
+
if (xhr.status < 200 || xhr.status >= 300) {
|
|
92085
|
+
throw new Error(`webread: HTTP ${xhr.status} for ${url}`);
|
|
92086
|
+
}
|
|
92087
|
+
return xhr.responseText;
|
|
92088
|
+
}
|
|
92089
|
+
unzip(zipfilename, outputfolder) {
|
|
92090
|
+
zipfilename = filterUrl(zipfilename);
|
|
92091
|
+
const zipData = this.vfs.readFile(zipfilename);
|
|
92092
|
+
this.vfs.mkdir(outputfolder);
|
|
92093
|
+
const files = unzipSync(zipData);
|
|
92094
|
+
const extracted = [];
|
|
92095
|
+
for (const [entryName, fileData] of Object.entries(files)) {
|
|
92096
|
+
if (entryName.endsWith("/")) {
|
|
92097
|
+
this.vfs.mkdir(outputfolder + "/" + entryName);
|
|
92098
|
+
continue;
|
|
92099
|
+
}
|
|
92100
|
+
const outPath = outputfolder + "/" + entryName;
|
|
92101
|
+
const lastSlash = outPath.lastIndexOf("/");
|
|
92102
|
+
if (lastSlash > 0) {
|
|
92103
|
+
this.vfs.mkdir(outPath.slice(0, lastSlash));
|
|
92104
|
+
}
|
|
92105
|
+
this.vfs.writeFile(outPath, fileData);
|
|
92106
|
+
extracted.push(this.vfs.normalizePath(outPath));
|
|
92107
|
+
}
|
|
92108
|
+
return extracted;
|
|
92109
|
+
}
|
|
92110
|
+
/** Get the VFS changes for syncing back to the main thread. */
|
|
92111
|
+
getChanges() {
|
|
92112
|
+
for (const [, entry] of this.openFiles) {
|
|
92113
|
+
this.flushEntry(entry);
|
|
92114
|
+
}
|
|
92115
|
+
return this.vfs.getChanges();
|
|
92116
|
+
}
|
|
92117
|
+
getEntry(fid) {
|
|
92118
|
+
return this.openFiles.get(fid);
|
|
92119
|
+
}
|
|
92120
|
+
flushEntry(entry) {
|
|
92121
|
+
if (entry.dirty) {
|
|
92122
|
+
const finalData = entry.dataLen === entry.data.length ? entry.data : entry.data.subarray(0, entry.dataLen);
|
|
92123
|
+
this.vfs.writeFile(entry.path, finalData);
|
|
92124
|
+
entry.dirty = false;
|
|
92125
|
+
}
|
|
92126
|
+
}
|
|
92127
|
+
writeBytes(entry, bytes) {
|
|
92128
|
+
const needed = entry.pos + bytes.length;
|
|
92129
|
+
if (needed > entry.data.length) {
|
|
92130
|
+
const newSize = Math.max(needed, entry.data.length * 2, 256);
|
|
92131
|
+
const newData = new Uint8Array(newSize);
|
|
92132
|
+
newData.set(entry.data.subarray(0, entry.dataLen));
|
|
92133
|
+
entry.data = newData;
|
|
92134
|
+
}
|
|
92135
|
+
entry.data.set(bytes, entry.pos);
|
|
92136
|
+
entry.pos += bytes.length;
|
|
92137
|
+
if (entry.pos > entry.dataLen) {
|
|
92138
|
+
entry.dataLen = entry.pos;
|
|
92139
|
+
}
|
|
92140
|
+
entry.dirty = true;
|
|
92141
|
+
}
|
|
92142
|
+
readLine(entry, keepNewline) {
|
|
92143
|
+
while (!entry.eof) {
|
|
92144
|
+
const nlIdx2 = entry.buffer.indexOf("\n");
|
|
92145
|
+
if (nlIdx2 !== -1) break;
|
|
92146
|
+
const available = entry.dataLen - entry.pos;
|
|
92147
|
+
if (available <= 0) {
|
|
92148
|
+
entry.eof = true;
|
|
92149
|
+
break;
|
|
92150
|
+
}
|
|
92151
|
+
const toRead = Math.min(READ_CHUNK_SIZE, available);
|
|
92152
|
+
const chunk = entry.data.subarray(entry.pos, entry.pos + toRead);
|
|
92153
|
+
entry.pos += toRead;
|
|
92154
|
+
entry.buffer += TEXT_DECODER.decode(chunk, { stream: true });
|
|
92155
|
+
}
|
|
92156
|
+
if (entry.buffer.length === 0) {
|
|
92157
|
+
return -1;
|
|
92158
|
+
}
|
|
92159
|
+
const nlIdx = entry.buffer.indexOf("\n");
|
|
92160
|
+
if (nlIdx !== -1) {
|
|
92161
|
+
const line2 = keepNewline ? entry.buffer.slice(0, nlIdx + 1) : entry.buffer.slice(0, nlIdx);
|
|
92162
|
+
entry.buffer = entry.buffer.slice(nlIdx + 1);
|
|
92163
|
+
return line2;
|
|
92164
|
+
}
|
|
92165
|
+
const line = entry.buffer;
|
|
92166
|
+
entry.buffer = "";
|
|
92167
|
+
return line;
|
|
92168
|
+
}
|
|
92169
|
+
listDirGlob(pattern) {
|
|
92170
|
+
const norm2 = this.vfs.normalizePath(pattern);
|
|
92171
|
+
const lastSlash = norm2.lastIndexOf("/");
|
|
92172
|
+
const dir = lastSlash >= 0 ? norm2.slice(0, lastSlash) : "/";
|
|
92173
|
+
const globPat = lastSlash >= 0 ? norm2.slice(lastSlash + 1) : norm2;
|
|
92174
|
+
const re = new RegExp(
|
|
92175
|
+
"^" + globPat.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$"
|
|
92176
|
+
);
|
|
92177
|
+
const entries = this.vfs.listDir(dir);
|
|
92178
|
+
return entries.filter(
|
|
92179
|
+
(e) => e.name !== "." && e.name !== ".." && re.test(e.name)
|
|
92180
|
+
);
|
|
92181
|
+
}
|
|
92182
|
+
listDirRecursive(pattern) {
|
|
92183
|
+
const idx = pattern.indexOf("**");
|
|
92184
|
+
let baseDir = pattern.slice(0, idx);
|
|
92185
|
+
if (baseDir.endsWith("/")) baseDir = baseDir.slice(0, -1);
|
|
92186
|
+
if (!baseDir) baseDir = ".";
|
|
92187
|
+
const results = [];
|
|
92188
|
+
const walkDir = (dir) => {
|
|
92189
|
+
const entries = this.vfs.listDir(dir);
|
|
92190
|
+
results.push(...entries);
|
|
92191
|
+
for (const entry of entries) {
|
|
92192
|
+
if (entry.isdir && entry.name !== "." && entry.name !== "..") {
|
|
92193
|
+
walkDir(entry.folder + "/" + entry.name);
|
|
92194
|
+
}
|
|
92195
|
+
}
|
|
92196
|
+
};
|
|
92197
|
+
walkDir(this.vfs.normalizePath(baseDir));
|
|
92198
|
+
return results;
|
|
92199
|
+
}
|
|
92200
|
+
};
|
|
92201
|
+
function filterUrl(url) {
|
|
92202
|
+
if (/^https:\/\/github\.com\/.+\/releases\/download\/.+/.test(url)) {
|
|
92203
|
+
url = url.replace(
|
|
92204
|
+
"https://github.com/",
|
|
92205
|
+
"https://mip-cors-proxy.figurl.workers.dev/gh/"
|
|
92206
|
+
);
|
|
92207
|
+
url += url.includes("?") ? "&" : "?";
|
|
92208
|
+
url += "t=" + Date.now();
|
|
92209
|
+
}
|
|
92210
|
+
return url;
|
|
92211
|
+
}
|
|
92212
|
+
|
|
92213
|
+
// src/vfs/BrowserSystemAdapter.ts
|
|
92214
|
+
var BrowserSystemAdapter = class {
|
|
92215
|
+
vars = /* @__PURE__ */ new Map();
|
|
92216
|
+
vfs = null;
|
|
92217
|
+
// Used only when no VFS is attached (e.g. tests that don't need files).
|
|
92218
|
+
fallbackCwd = "/";
|
|
92219
|
+
constructor(vfs) {
|
|
92220
|
+
if (vfs) this.vfs = vfs;
|
|
92221
|
+
}
|
|
92222
|
+
/** Attach (or replace) the VFS used as the cwd source of truth. */
|
|
92223
|
+
setVfs(vfs) {
|
|
92224
|
+
this.vfs = vfs;
|
|
92225
|
+
}
|
|
92226
|
+
getEnv(name) {
|
|
92227
|
+
return this.vars.get(name);
|
|
92228
|
+
}
|
|
92229
|
+
getAllEnv() {
|
|
92230
|
+
const result = {};
|
|
92231
|
+
for (const [k, v] of this.vars) {
|
|
92232
|
+
result[k] = v;
|
|
92233
|
+
}
|
|
92234
|
+
return result;
|
|
92235
|
+
}
|
|
92236
|
+
setEnv(name, value) {
|
|
92237
|
+
this.vars.set(name, value);
|
|
92238
|
+
}
|
|
92239
|
+
cwd() {
|
|
92240
|
+
return this.vfs ? this.vfs.getCwd() : this.fallbackCwd;
|
|
92241
|
+
}
|
|
92242
|
+
chdir(dir) {
|
|
92243
|
+
if (this.vfs) {
|
|
92244
|
+
this.vfs.setCwd(dir);
|
|
92245
|
+
} else {
|
|
92246
|
+
this.fallbackCwd = dir.startsWith("/") ? dir : this.fallbackCwd.replace(/\/$/, "") + "/" + dir;
|
|
92247
|
+
}
|
|
92248
|
+
}
|
|
92249
|
+
platform() {
|
|
92250
|
+
return "linux";
|
|
92251
|
+
}
|
|
92252
|
+
arch() {
|
|
92253
|
+
return "x64";
|
|
92254
|
+
}
|
|
92255
|
+
};
|
|
89195
92256
|
export {
|
|
92257
|
+
BrowserFileIOAdapter,
|
|
92258
|
+
BrowserSystemAdapter,
|
|
89196
92259
|
RTV,
|
|
89197
92260
|
RuntimeError,
|
|
92261
|
+
VirtualFileSystem,
|
|
89198
92262
|
displayValue,
|
|
89199
92263
|
executeCode,
|
|
89200
92264
|
loadQhullNodeBackend as loadDelaunayBackend,
|