numbl 0.0.20 → 0.0.22
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/README.md +8 -0
- package/dist-cli/cli.js +509 -114
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -53,6 +53,10 @@ Commands:
|
|
|
53
53
|
mip <subcommand> Package manager (install, uninstall, list, avail, info)
|
|
54
54
|
(no command) Start interactive REPL
|
|
55
55
|
|
|
56
|
+
Global options:
|
|
57
|
+
--version, -V Print version and exit
|
|
58
|
+
--help, -h Print this help message
|
|
59
|
+
|
|
56
60
|
Options (for REPL):
|
|
57
61
|
--plot Enable plot server
|
|
58
62
|
--plot-port <port> Set plot server port (implies --plot)
|
|
@@ -73,6 +77,10 @@ Environment variables:
|
|
|
73
77
|
```
|
|
74
78
|
<!-- END CLI HELP -->
|
|
75
79
|
|
|
80
|
+
## VS Code extension
|
|
81
|
+
|
|
82
|
+
The [Numbl extension for VS Code](https://marketplace.visualstudio.com/items?itemName=jmagland.numbl) lets you run `.m` scripts directly in the editor with inline error diagnostics and a built-in figure viewer.
|
|
83
|
+
|
|
76
84
|
## Upgrading
|
|
77
85
|
|
|
78
86
|
```bash
|
package/dist-cli/cli.js
CHANGED
|
@@ -19028,6 +19028,16 @@ function complexBinaryOp(a, b, op) {
|
|
|
19028
19028
|
);
|
|
19029
19029
|
}
|
|
19030
19030
|
function mAdd(a, b) {
|
|
19031
|
+
if (typeof a === "object" && a !== null && a.kind === "tensor" && typeof b === "object" && b !== null && b.kind === "tensor") {
|
|
19032
|
+
const at = a;
|
|
19033
|
+
const bt = b;
|
|
19034
|
+
if (!at.imag && !bt.imag && at.data.length === bt.data.length && at.shape.length === bt.shape.length && at.shape.every((d, i) => d === bt.shape[i])) {
|
|
19035
|
+
const result = new FloatXArray(at.data.length);
|
|
19036
|
+
for (let i = 0; i < result.length; i++)
|
|
19037
|
+
result[i] = at.data[i] + bt.data[i];
|
|
19038
|
+
return RTV.tensor(result, at.shape);
|
|
19039
|
+
}
|
|
19040
|
+
}
|
|
19031
19041
|
if (isRuntimeSparseMatrix(a) || isRuntimeSparseMatrix(b))
|
|
19032
19042
|
return mAddSparse(a, b);
|
|
19033
19043
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -19064,6 +19074,16 @@ function mMul(a, b) {
|
|
|
19064
19074
|
return binaryOp(a, b, (x, y) => x * y);
|
|
19065
19075
|
}
|
|
19066
19076
|
function mElemMul(a, b) {
|
|
19077
|
+
if (typeof a === "object" && a !== null && a.kind === "tensor" && typeof b === "object" && b !== null && b.kind === "tensor") {
|
|
19078
|
+
const at = a;
|
|
19079
|
+
const bt = b;
|
|
19080
|
+
if (!at.imag && !bt.imag && at.data.length === bt.data.length && at.shape.length === bt.shape.length && at.shape.every((d, i) => d === bt.shape[i])) {
|
|
19081
|
+
const result = new FloatXArray(at.data.length);
|
|
19082
|
+
for (let i = 0; i < result.length; i++)
|
|
19083
|
+
result[i] = at.data[i] * bt.data[i];
|
|
19084
|
+
return RTV.tensor(result, at.shape);
|
|
19085
|
+
}
|
|
19086
|
+
}
|
|
19067
19087
|
if (isRuntimeSparseMatrix(a) || isRuntimeSparseMatrix(b))
|
|
19068
19088
|
return mElemMulSparse(a, b);
|
|
19069
19089
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -19189,6 +19209,31 @@ function mPow(a, b) {
|
|
|
19189
19209
|
return binaryOp(a, b, (x, y) => Math.pow(x, y));
|
|
19190
19210
|
}
|
|
19191
19211
|
function mElemPow(a, b) {
|
|
19212
|
+
if (isRuntimeTensor(a) && !a.imag && isRuntimeNumber(b)) {
|
|
19213
|
+
const exp = b;
|
|
19214
|
+
if (exp === 2) {
|
|
19215
|
+
const result = new FloatXArray(a.data.length);
|
|
19216
|
+
for (let i = 0; i < result.length; i++) result[i] = a.data[i] * a.data[i];
|
|
19217
|
+
return RTV.tensor(result, a.shape);
|
|
19218
|
+
}
|
|
19219
|
+
if (Number.isInteger(exp) || exp >= 0) {
|
|
19220
|
+
let hasNeg2 = false;
|
|
19221
|
+
if (!Number.isInteger(exp)) {
|
|
19222
|
+
for (let i = 0; i < a.data.length; i++) {
|
|
19223
|
+
if (a.data[i] < 0) {
|
|
19224
|
+
hasNeg2 = true;
|
|
19225
|
+
break;
|
|
19226
|
+
}
|
|
19227
|
+
}
|
|
19228
|
+
}
|
|
19229
|
+
if (!hasNeg2) {
|
|
19230
|
+
const result = new FloatXArray(a.data.length);
|
|
19231
|
+
for (let i = 0; i < result.length; i++)
|
|
19232
|
+
result[i] = Math.pow(a.data[i], exp);
|
|
19233
|
+
return RTV.tensor(result, a.shape);
|
|
19234
|
+
}
|
|
19235
|
+
}
|
|
19236
|
+
}
|
|
19192
19237
|
const complexPow = (aRe, aIm, bRe, bIm) => {
|
|
19193
19238
|
const r = Math.sqrt(aRe * aRe + aIm * aIm);
|
|
19194
19239
|
if (r === 0) {
|
|
@@ -19239,17 +19284,22 @@ function mElemPow(a, b) {
|
|
|
19239
19284
|
return binaryOp(a, b, (x, y) => Math.pow(x, y));
|
|
19240
19285
|
}
|
|
19241
19286
|
function mNeg(v) {
|
|
19242
|
-
if (
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19287
|
+
if (isRuntimeTensor(v)) {
|
|
19288
|
+
if (v.imag !== void 0) {
|
|
19289
|
+
const resultRe2 = new FloatXArray(v.data.length);
|
|
19290
|
+
const resultIm = new FloatXArray(v.imag.length);
|
|
19291
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
19292
|
+
resultRe2[i] = -v.data[i];
|
|
19293
|
+
resultIm[i] = -v.imag[i];
|
|
19294
|
+
}
|
|
19295
|
+
return RTV.tensor(resultRe2, v.shape, resultIm);
|
|
19250
19296
|
}
|
|
19251
|
-
|
|
19297
|
+
const resultRe = new FloatXArray(v.data.length);
|
|
19298
|
+
for (let i = 0; i < v.data.length; i++) resultRe[i] = -v.data[i];
|
|
19299
|
+
return RTV.tensor(resultRe, v.shape);
|
|
19252
19300
|
}
|
|
19301
|
+
if (isRuntimeSparseMatrix(v)) return sparseNeg(v);
|
|
19302
|
+
if (isRuntimeComplexNumber(v)) return RTV.complex(-v.re, -v.im);
|
|
19253
19303
|
return unaryOp(v, (x) => -x);
|
|
19254
19304
|
}
|
|
19255
19305
|
function transposeCellArray(v) {
|
|
@@ -19524,6 +19574,40 @@ function broadcastComparison(a, b, outShape, op) {
|
|
|
19524
19574
|
return t;
|
|
19525
19575
|
}
|
|
19526
19576
|
function binaryOp(a, b, op) {
|
|
19577
|
+
if (isRuntimeTensor(a) && a.data.length > 1) {
|
|
19578
|
+
if (isRuntimeTensor(b) && b.data.length > 1) {
|
|
19579
|
+
if (a.data.length === b.data.length && a.shape.length === b.shape.length && a.shape.every((d, i) => d === b.shape[i])) {
|
|
19580
|
+
const result = new FloatXArray(a.data.length);
|
|
19581
|
+
for (let i = 0; i < result.length; i++) {
|
|
19582
|
+
result[i] = op(a.data[i], b.data[i]);
|
|
19583
|
+
}
|
|
19584
|
+
return RTV.tensor(result, a.shape);
|
|
19585
|
+
}
|
|
19586
|
+
const broadcastShape2 = getBroadcastShape(a.shape, b.shape);
|
|
19587
|
+
if (broadcastShape2 !== null) {
|
|
19588
|
+
return broadcastBinary(a, b, broadcastShape2, op);
|
|
19589
|
+
}
|
|
19590
|
+
throw new RuntimeError(
|
|
19591
|
+
`Matrix dimensions must agree: [${a.shape.join(",")}] vs [${b.shape.join(",")}]`
|
|
19592
|
+
);
|
|
19593
|
+
}
|
|
19594
|
+
if (isRuntimeNumber(b)) {
|
|
19595
|
+
const result = new FloatXArray(a.data.length);
|
|
19596
|
+
const sv = b;
|
|
19597
|
+
for (let i = 0; i < result.length; i++) {
|
|
19598
|
+
result[i] = op(a.data[i], sv);
|
|
19599
|
+
}
|
|
19600
|
+
return RTV.tensor(result, a.shape);
|
|
19601
|
+
}
|
|
19602
|
+
}
|
|
19603
|
+
if (isRuntimeTensor(b) && b.data.length > 1 && isRuntimeNumber(a)) {
|
|
19604
|
+
const result = new FloatXArray(b.data.length);
|
|
19605
|
+
const sv = a;
|
|
19606
|
+
for (let i = 0; i < result.length; i++) {
|
|
19607
|
+
result[i] = op(sv, b.data[i]);
|
|
19608
|
+
}
|
|
19609
|
+
return RTV.tensor(result, b.shape);
|
|
19610
|
+
}
|
|
19527
19611
|
const an = asNumeric(a);
|
|
19528
19612
|
const bn = asNumeric(b);
|
|
19529
19613
|
if (an.scalar && bn.scalar) {
|
|
@@ -19567,6 +19651,13 @@ function binaryOp(a, b, op) {
|
|
|
19567
19651
|
);
|
|
19568
19652
|
}
|
|
19569
19653
|
function unaryOp(v, op) {
|
|
19654
|
+
if (isRuntimeTensor(v) && v.data.length > 1) {
|
|
19655
|
+
const result2 = new FloatXArray(v.data.length);
|
|
19656
|
+
for (let i = 0; i < result2.length; i++) {
|
|
19657
|
+
result2[i] = op(v.data[i]);
|
|
19658
|
+
}
|
|
19659
|
+
return RTV.tensor(result2, v.shape);
|
|
19660
|
+
}
|
|
19570
19661
|
const n = asNumeric(v);
|
|
19571
19662
|
if (n.scalar) {
|
|
19572
19663
|
const val = n.isComplex ? n.re : n.value;
|
|
@@ -20486,6 +20577,11 @@ function storeIntoTensor(base, indices, rhs) {
|
|
|
20486
20577
|
return deleteTensorElements(base, indices[0]);
|
|
20487
20578
|
}
|
|
20488
20579
|
if (isRuntimeTensor(rhs) && rhs.data.length === 0 && indices.length === 2) {
|
|
20580
|
+
const nrows = base.shape[0] ?? 1;
|
|
20581
|
+
const ncols = base.shape.length >= 2 ? base.shape[1] : 1;
|
|
20582
|
+
const rowCount = isColonIndex(indices[0]) ? nrows : resolveIndex(indices[0], nrows).length;
|
|
20583
|
+
const colCount = isColonIndex(indices[1]) ? ncols : resolveIndex(indices[1], ncols).length;
|
|
20584
|
+
if (rowCount === 0 || colCount === 0) return base;
|
|
20489
20585
|
return deleteTensorRowsOrCols(base, indices);
|
|
20490
20586
|
}
|
|
20491
20587
|
if (base._rc > 1) {
|
|
@@ -20983,7 +21079,7 @@ function storeIntoTensorND(base, indices, rhs) {
|
|
|
20983
21079
|
}
|
|
20984
21080
|
return base;
|
|
20985
21081
|
}
|
|
20986
|
-
function storeIntoCell(base, indices, rhs) {
|
|
21082
|
+
function storeIntoCell(base, indices, rhs, parenAssign = false) {
|
|
20987
21083
|
if (base._rc > 1) {
|
|
20988
21084
|
base._rc--;
|
|
20989
21085
|
const sharedData = base.data.map((elem) => shareRuntimeValue(elem));
|
|
@@ -20997,14 +21093,20 @@ function storeIntoCell(base, indices, rhs) {
|
|
|
20997
21093
|
c.shape = isColVec ? [newLen, 1] : [1, newLen];
|
|
20998
21094
|
};
|
|
20999
21095
|
if (indices.length === 1) {
|
|
21000
|
-
return storeIntoCell1D(
|
|
21096
|
+
return storeIntoCell1D(
|
|
21097
|
+
base,
|
|
21098
|
+
indices[0],
|
|
21099
|
+
rhs,
|
|
21100
|
+
updateShapeAfterLinearAssign,
|
|
21101
|
+
parenAssign
|
|
21102
|
+
);
|
|
21001
21103
|
}
|
|
21002
21104
|
if (indices.length === 2) {
|
|
21003
|
-
return storeIntoCell2D(base, indices, rhs);
|
|
21105
|
+
return storeIntoCell2D(base, indices, rhs, parenAssign);
|
|
21004
21106
|
}
|
|
21005
21107
|
throw new RuntimeError(`Cannot index-assign into cell`);
|
|
21006
21108
|
}
|
|
21007
|
-
function storeIntoCell1D(base, idx, rhs, updateShape) {
|
|
21109
|
+
function storeIntoCell1D(base, idx, rhs, updateShape, parenAssign = false) {
|
|
21008
21110
|
if (isRuntimeTensor(idx)) {
|
|
21009
21111
|
let positions;
|
|
21010
21112
|
if (idx._isLogical) {
|
|
@@ -21052,11 +21154,11 @@ function storeIntoCell1D(base, idx, rhs, updateShape) {
|
|
|
21052
21154
|
while (base.data.length <= i)
|
|
21053
21155
|
base.data.push(RTV.tensor(new FloatXArray(0), [0, 0]));
|
|
21054
21156
|
}
|
|
21055
|
-
base.data[i] = isRuntimeCell(rhs) && rhs.data.length === 1 ? rhs.data[0] : rhs;
|
|
21157
|
+
base.data[i] = parenAssign && isRuntimeCell(rhs) && rhs.data.length === 1 ? rhs.data[0] : rhs;
|
|
21056
21158
|
updateShape(oldLen);
|
|
21057
21159
|
return base;
|
|
21058
21160
|
}
|
|
21059
|
-
function storeIntoCell2D(base, indices, rhs) {
|
|
21161
|
+
function storeIntoCell2D(base, indices, rhs, parenAssign = false) {
|
|
21060
21162
|
let rows = base.shape[0];
|
|
21061
21163
|
let cols = base.shape.length >= 2 ? base.shape[1] : 1;
|
|
21062
21164
|
const rowIndices = resolveIndex(indices[0], rows, 0);
|
|
@@ -21082,7 +21184,7 @@ function storeIntoCell2D(base, indices, rhs) {
|
|
|
21082
21184
|
const nSelectedRows = rowIndices.length;
|
|
21083
21185
|
const nSelectedCols = colIndices.length;
|
|
21084
21186
|
const totalSelected = nSelectedRows * nSelectedCols;
|
|
21085
|
-
if (isRuntimeCell(rhs)) {
|
|
21187
|
+
if (parenAssign && isRuntimeCell(rhs)) {
|
|
21086
21188
|
if (rhs.data.length !== totalSelected && rhs.data.length !== 1) {
|
|
21087
21189
|
throw new RuntimeError("Subscripted assignment dimension mismatch");
|
|
21088
21190
|
}
|
|
@@ -21100,7 +21202,7 @@ function storeIntoCell2D(base, indices, rhs) {
|
|
|
21100
21202
|
}
|
|
21101
21203
|
return base;
|
|
21102
21204
|
}
|
|
21103
|
-
function storeIntoRTValueIndex(base, indices, rhs) {
|
|
21205
|
+
function storeIntoRTValueIndex(base, indices, rhs, parenAssign = false) {
|
|
21104
21206
|
if (isRuntimeSparseMatrix(base)) {
|
|
21105
21207
|
return storeIntoSparse(base, indices, rhs);
|
|
21106
21208
|
}
|
|
@@ -21121,7 +21223,7 @@ function storeIntoRTValueIndex(base, indices, rhs) {
|
|
|
21121
21223
|
return storeIntoTensor(base, indices, rhs);
|
|
21122
21224
|
}
|
|
21123
21225
|
if (isRuntimeCell(base)) {
|
|
21124
|
-
return storeIntoCell(base, indices, rhs);
|
|
21226
|
+
return storeIntoCell(base, indices, rhs, parenAssign);
|
|
21125
21227
|
}
|
|
21126
21228
|
throw new RuntimeError(`Cannot index-assign into ${kstr(base)}`);
|
|
21127
21229
|
}
|
|
@@ -23031,11 +23133,8 @@ var CommandParser = class extends ExpressionParser {
|
|
|
23031
23133
|
scanPos++;
|
|
23032
23134
|
continue;
|
|
23033
23135
|
}
|
|
23034
|
-
if (ch === "\n" || ch === "\r" || ch === ";" || ch === "%")
|
|
23035
|
-
|
|
23036
|
-
scanPos++;
|
|
23037
|
-
continue;
|
|
23038
|
-
}
|
|
23136
|
+
if (ch === "\n" || ch === "\r" || ch === ";" || ch === "%" || ch === ",")
|
|
23137
|
+
break;
|
|
23039
23138
|
if (ch === "." && scanPos + 2 < this.input.length && this.input[scanPos + 1] === "." && this.input[scanPos + 2] === ".") {
|
|
23040
23139
|
scanPos += 3;
|
|
23041
23140
|
while (scanPos < this.input.length && this.input[scanPos] !== "\n") {
|
|
@@ -25256,6 +25355,13 @@ function complexElemwise(realFn, complexFn, complexOutKind, o) {
|
|
|
25256
25355
|
const isReal = complexOutKind === "Number" || resultIm2.every((x) => x === 0);
|
|
25257
25356
|
return RTV.tensor(resultRe2, v.shape, isReal ? void 0 : resultIm2);
|
|
25258
25357
|
}
|
|
25358
|
+
if (o?.realSafe) {
|
|
25359
|
+
const resultRe2 = new FloatXArray(v.data.length);
|
|
25360
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
25361
|
+
resultRe2[i] = realFn(v.data[i]);
|
|
25362
|
+
}
|
|
25363
|
+
return RTV.tensor(resultRe2, v.shape);
|
|
25364
|
+
}
|
|
25259
25365
|
const resultRe = new FloatXArray(v.data.length);
|
|
25260
25366
|
const resultIm = new FloatXArray(v.data.length);
|
|
25261
25367
|
let hasImag = false;
|
|
@@ -25430,7 +25536,7 @@ function registerMathFunctions() {
|
|
|
25430
25536
|
im: Math.cos(re) * Math.sinh(im)
|
|
25431
25537
|
}),
|
|
25432
25538
|
"ComplexNumber",
|
|
25433
|
-
{ nativeJs: "Math.sin" }
|
|
25539
|
+
{ nativeJs: "Math.sin", realSafe: true }
|
|
25434
25540
|
),
|
|
25435
25541
|
1
|
|
25436
25542
|
);
|
|
@@ -25443,7 +25549,7 @@ function registerMathFunctions() {
|
|
|
25443
25549
|
im: -Math.sin(re) * Math.sinh(im)
|
|
25444
25550
|
}),
|
|
25445
25551
|
"ComplexNumber",
|
|
25446
|
-
{ nativeJs: "Math.cos" }
|
|
25552
|
+
{ nativeJs: "Math.cos", realSafe: true }
|
|
25447
25553
|
),
|
|
25448
25554
|
1
|
|
25449
25555
|
);
|
|
@@ -25456,7 +25562,7 @@ function registerMathFunctions() {
|
|
|
25456
25562
|
return { re: Math.sin(2 * re) / denom, im: Math.sinh(2 * im) / denom };
|
|
25457
25563
|
},
|
|
25458
25564
|
"ComplexNumber",
|
|
25459
|
-
{ nativeJs: "Math.tan" }
|
|
25565
|
+
{ nativeJs: "Math.tan", realSafe: true }
|
|
25460
25566
|
),
|
|
25461
25567
|
1
|
|
25462
25568
|
);
|
|
@@ -25502,7 +25608,7 @@ function registerMathFunctions() {
|
|
|
25502
25608
|
im: Math.cosh(re) * Math.sin(im)
|
|
25503
25609
|
}),
|
|
25504
25610
|
"ComplexNumber",
|
|
25505
|
-
{ nativeJs: "Math.sinh" }
|
|
25611
|
+
{ nativeJs: "Math.sinh", realSafe: true }
|
|
25506
25612
|
),
|
|
25507
25613
|
1
|
|
25508
25614
|
);
|
|
@@ -25515,7 +25621,7 @@ function registerMathFunctions() {
|
|
|
25515
25621
|
im: Math.sinh(re) * Math.sin(im)
|
|
25516
25622
|
}),
|
|
25517
25623
|
"ComplexNumber",
|
|
25518
|
-
{ nativeJs: "Math.cosh" }
|
|
25624
|
+
{ nativeJs: "Math.cosh", realSafe: true }
|
|
25519
25625
|
),
|
|
25520
25626
|
1
|
|
25521
25627
|
);
|
|
@@ -25531,7 +25637,7 @@ function registerMathFunctions() {
|
|
|
25531
25637
|
};
|
|
25532
25638
|
},
|
|
25533
25639
|
"ComplexNumber",
|
|
25534
|
-
{ nativeJs: "Math.tanh" }
|
|
25640
|
+
{ nativeJs: "Math.tanh", realSafe: true }
|
|
25535
25641
|
),
|
|
25536
25642
|
1
|
|
25537
25643
|
);
|
|
@@ -25581,7 +25687,7 @@ function registerMathFunctions() {
|
|
|
25581
25687
|
im: Math.exp(re) * Math.sin(im)
|
|
25582
25688
|
}),
|
|
25583
25689
|
"ComplexNumber",
|
|
25584
|
-
{ nativeJs: "Math.exp" }
|
|
25690
|
+
{ nativeJs: "Math.exp", realSafe: true }
|
|
25585
25691
|
),
|
|
25586
25692
|
1
|
|
25587
25693
|
);
|
|
@@ -25683,7 +25789,7 @@ function registerMathFunctions() {
|
|
|
25683
25789
|
Math.abs,
|
|
25684
25790
|
(re, im) => ({ re: Math.sqrt(re * re + im * im), im: 0 }),
|
|
25685
25791
|
"Number",
|
|
25686
|
-
{ nativeJs: "Math.abs" }
|
|
25792
|
+
{ nativeJs: "Math.abs", realSafe: true }
|
|
25687
25793
|
),
|
|
25688
25794
|
1
|
|
25689
25795
|
);
|
|
@@ -29011,6 +29117,27 @@ function dimReduce(v, dim, reduceFn, initialValue, finalizeFn) {
|
|
|
29011
29117
|
const imOut = resultImag && resultImag.some((x) => x !== 0) ? resultImag : void 0;
|
|
29012
29118
|
return RTV.tensor(result, info.resultShape, imOut);
|
|
29013
29119
|
}
|
|
29120
|
+
function dimReduceOmitNaN(v, dim, reduceFn, initialValue, finalizeFn) {
|
|
29121
|
+
if (!isRuntimeTensor(v))
|
|
29122
|
+
throw new RuntimeError("dimReduceOmitNaN: argument must be a tensor");
|
|
29123
|
+
const info = forEachSlice(v.shape, dim, () => {
|
|
29124
|
+
});
|
|
29125
|
+
if (!info) return copyTensor(v);
|
|
29126
|
+
const result = new FloatXArray(info.totalElems);
|
|
29127
|
+
forEachSlice(v.shape, dim, (outIdx, srcIndices) => {
|
|
29128
|
+
let acc = initialValue;
|
|
29129
|
+
let count = 0;
|
|
29130
|
+
for (let k = 0; k < srcIndices.length; k++) {
|
|
29131
|
+
const val = v.data[srcIndices[k]];
|
|
29132
|
+
if (!isNaN(val)) {
|
|
29133
|
+
acc = reduceFn(acc, val);
|
|
29134
|
+
count++;
|
|
29135
|
+
}
|
|
29136
|
+
}
|
|
29137
|
+
result[outIdx] = finalizeFn ? finalizeFn(acc, count) : acc;
|
|
29138
|
+
});
|
|
29139
|
+
return RTV.tensor(result, info.resultShape);
|
|
29140
|
+
}
|
|
29014
29141
|
function sliceDimReduce(v, dim, sliceFn) {
|
|
29015
29142
|
const info = forEachSlice(v.shape, dim, () => {
|
|
29016
29143
|
});
|
|
@@ -29236,23 +29363,44 @@ function preserveTypeCheck(argTypes, nargout) {
|
|
|
29236
29363
|
if (nargout === 2) return { outputTypes: [outType, outType] };
|
|
29237
29364
|
return null;
|
|
29238
29365
|
}
|
|
29239
|
-
function
|
|
29366
|
+
function parseNanFlag(args) {
|
|
29367
|
+
if (args.length >= 2) {
|
|
29368
|
+
const last = args[args.length - 1];
|
|
29369
|
+
if (isRuntimeChar(last)) {
|
|
29370
|
+
const s = toString(last).toLowerCase();
|
|
29371
|
+
if (s === "omitnan") return { args: args.slice(0, -1), omitNaN: true };
|
|
29372
|
+
if (s === "includenan")
|
|
29373
|
+
return { args: args.slice(0, -1), omitNaN: false };
|
|
29374
|
+
}
|
|
29375
|
+
}
|
|
29376
|
+
return { args, omitNaN: false };
|
|
29377
|
+
}
|
|
29378
|
+
function filterNaN(arr) {
|
|
29379
|
+
const out2 = [];
|
|
29380
|
+
for (let i = 0; i < arr.length; i++) {
|
|
29381
|
+
if (!isNaN(arr[i])) out2.push(arr[i]);
|
|
29382
|
+
}
|
|
29383
|
+
return new Float64Array(out2);
|
|
29384
|
+
}
|
|
29385
|
+
function makeReduction(name, kernel, omitNaNKernel) {
|
|
29240
29386
|
return {
|
|
29241
29387
|
check: reductionCheck,
|
|
29242
|
-
apply: (
|
|
29243
|
-
if (
|
|
29388
|
+
apply: (rawArgs) => {
|
|
29389
|
+
if (rawArgs.length < 1)
|
|
29244
29390
|
throw new RuntimeError(`${name} requires at least 1 argument`);
|
|
29391
|
+
const { args, omitNaN } = parseNanFlag(rawArgs);
|
|
29392
|
+
const k = omitNaN && omitNaNKernel ? omitNaNKernel : kernel;
|
|
29245
29393
|
const v = args[0];
|
|
29246
29394
|
if (isRuntimeNumber(v)) return v;
|
|
29247
29395
|
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
29248
29396
|
if (isRuntimeTensor(v)) {
|
|
29249
29397
|
if (args.length >= 2) {
|
|
29250
29398
|
if (isRuntimeChar(args[1]) && toString(args[1]) === "all")
|
|
29251
|
-
return
|
|
29252
|
-
return
|
|
29399
|
+
return k.reduceAll(v);
|
|
29400
|
+
return k.reduceDim(v, Math.round(toNumber(args[1])));
|
|
29253
29401
|
}
|
|
29254
29402
|
const d = firstReduceDim(v.shape);
|
|
29255
|
-
return d === 0 ?
|
|
29403
|
+
return d === 0 ? k.reduceAll(v) : k.reduceDim(v, d);
|
|
29256
29404
|
}
|
|
29257
29405
|
throw new RuntimeError(`${name}: argument must be numeric`);
|
|
29258
29406
|
}
|
|
@@ -29282,6 +29430,42 @@ function sliceKernel(sliceFn) {
|
|
|
29282
29430
|
reduceDim: (v, dim) => sliceDimReduce(v, dim, sliceFn)
|
|
29283
29431
|
};
|
|
29284
29432
|
}
|
|
29433
|
+
function accumKernelOmitNaN(reduceFn, initial, finalizeFn) {
|
|
29434
|
+
return {
|
|
29435
|
+
reduceAll: (v) => {
|
|
29436
|
+
let acc = initial;
|
|
29437
|
+
let count = 0;
|
|
29438
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
29439
|
+
if (!isNaN(v.data[i])) {
|
|
29440
|
+
acc = reduceFn(acc, v.data[i]);
|
|
29441
|
+
count++;
|
|
29442
|
+
}
|
|
29443
|
+
}
|
|
29444
|
+
const re = finalizeFn ? finalizeFn(acc, count) : acc;
|
|
29445
|
+
if (v.imag) {
|
|
29446
|
+
let accIm = initial;
|
|
29447
|
+
let countIm = 0;
|
|
29448
|
+
for (let i = 0; i < v.imag.length; i++) {
|
|
29449
|
+
if (!isNaN(v.imag[i])) {
|
|
29450
|
+
accIm = reduceFn(accIm, v.imag[i]);
|
|
29451
|
+
countIm++;
|
|
29452
|
+
}
|
|
29453
|
+
}
|
|
29454
|
+
const im = finalizeFn ? finalizeFn(accIm, countIm) : accIm;
|
|
29455
|
+
if (im !== 0) return RTV.complex(re, im);
|
|
29456
|
+
}
|
|
29457
|
+
return RTV.num(re);
|
|
29458
|
+
},
|
|
29459
|
+
reduceDim: (v, dim) => dimReduceOmitNaN(v, dim, reduceFn, initial, finalizeFn)
|
|
29460
|
+
};
|
|
29461
|
+
}
|
|
29462
|
+
function sliceKernelOmitNaN(sliceFn) {
|
|
29463
|
+
const filteredFn = (slice) => sliceFn(filterNaN(slice));
|
|
29464
|
+
return {
|
|
29465
|
+
reduceAll: (v) => RTV.num(filteredFn(v.data)),
|
|
29466
|
+
reduceDim: (v, dim) => sliceDimReduce(v, dim, filteredFn)
|
|
29467
|
+
};
|
|
29468
|
+
}
|
|
29285
29469
|
function toNumArray(v, name) {
|
|
29286
29470
|
if (isRuntimeNumber(v)) return [v];
|
|
29287
29471
|
if (isRuntimeTensor(v)) return Array.from(v.data);
|
|
@@ -29293,15 +29477,16 @@ function registerBasicReductions() {
|
|
|
29293
29477
|
register("sum", [
|
|
29294
29478
|
{
|
|
29295
29479
|
check: reductionCheck,
|
|
29296
|
-
apply: (
|
|
29297
|
-
if (
|
|
29480
|
+
apply: (rawArgs) => {
|
|
29481
|
+
if (rawArgs.length < 1)
|
|
29298
29482
|
throw new RuntimeError("sum requires at least 1 argument");
|
|
29483
|
+
const { args, omitNaN } = parseNanFlag(rawArgs);
|
|
29299
29484
|
const v = args[0];
|
|
29300
29485
|
if (isRuntimeSparseMatrix(v)) {
|
|
29301
29486
|
const dim = args.length >= 2 ? Math.round(toNumber(args[1])) : v.m > 1 ? 1 : v.n > 1 ? 2 : 1;
|
|
29302
29487
|
return sparseSum(v, dim);
|
|
29303
29488
|
}
|
|
29304
|
-
const kernel = accumKernel((acc, val) => acc + val, 0);
|
|
29489
|
+
const kernel = omitNaN ? accumKernelOmitNaN((acc, val) => acc + val, 0) : accumKernel((acc, val) => acc + val, 0);
|
|
29305
29490
|
if (isRuntimeNumber(v)) return v;
|
|
29306
29491
|
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
29307
29492
|
if (isRuntimeTensor(v)) {
|
|
@@ -29317,13 +29502,14 @@ function registerBasicReductions() {
|
|
|
29317
29502
|
}
|
|
29318
29503
|
}
|
|
29319
29504
|
]);
|
|
29320
|
-
const prodKernel = accumKernel((acc, val) => acc * val, 1);
|
|
29321
29505
|
register("prod", [
|
|
29322
29506
|
{
|
|
29323
29507
|
check: reductionCheck,
|
|
29324
|
-
apply: (
|
|
29325
|
-
if (
|
|
29508
|
+
apply: (rawArgs) => {
|
|
29509
|
+
if (rawArgs.length < 1)
|
|
29326
29510
|
throw new RuntimeError("prod requires at least 1 argument");
|
|
29511
|
+
const { args: parsedArgs, omitNaN } = parseNanFlag(rawArgs);
|
|
29512
|
+
let args = parsedArgs;
|
|
29327
29513
|
let v = args[0];
|
|
29328
29514
|
if (isRuntimeSparseMatrix(v)) {
|
|
29329
29515
|
v = sparseToDense(v);
|
|
@@ -29337,13 +29523,14 @@ function registerBasicReductions() {
|
|
|
29337
29523
|
args.length >= 2 ? Math.round(toNumber(args[1])) : void 0
|
|
29338
29524
|
);
|
|
29339
29525
|
}
|
|
29526
|
+
const kernel = omitNaN ? accumKernelOmitNaN((acc, val) => acc * val, 1) : accumKernel((acc, val) => acc * val, 1);
|
|
29340
29527
|
if (args.length >= 2) {
|
|
29341
29528
|
if (isRuntimeChar(args[1]) && toString(args[1]) === "all")
|
|
29342
|
-
return
|
|
29343
|
-
return
|
|
29529
|
+
return kernel.reduceAll(v);
|
|
29530
|
+
return kernel.reduceDim(v, Math.round(toNumber(args[1])));
|
|
29344
29531
|
}
|
|
29345
29532
|
const d = firstReduceDim(v.shape);
|
|
29346
|
-
return d === 0 ?
|
|
29533
|
+
return d === 0 ? kernel.reduceAll(v) : kernel.reduceDim(v, d);
|
|
29347
29534
|
}
|
|
29348
29535
|
throw new RuntimeError("prod: argument must be numeric");
|
|
29349
29536
|
}
|
|
@@ -29356,31 +29543,40 @@ function registerBasicReductions() {
|
|
|
29356
29543
|
(acc, val) => acc + val,
|
|
29357
29544
|
0,
|
|
29358
29545
|
(sum, count) => sum / count
|
|
29546
|
+
),
|
|
29547
|
+
accumKernelOmitNaN(
|
|
29548
|
+
(acc, val) => acc + val,
|
|
29549
|
+
0,
|
|
29550
|
+
(sum, count) => count === 0 ? NaN : sum / count
|
|
29359
29551
|
)
|
|
29360
29552
|
)
|
|
29361
29553
|
]);
|
|
29362
|
-
const varianceOf = (slice, w) => {
|
|
29363
|
-
|
|
29554
|
+
const varianceOf = (slice, w, omitNaN) => {
|
|
29555
|
+
let data = slice;
|
|
29556
|
+
if (omitNaN) data = filterNaN(slice);
|
|
29557
|
+
const n = data.length;
|
|
29558
|
+
if (n === 0) return NaN;
|
|
29364
29559
|
if (n <= 1 && w === 0) return 0;
|
|
29365
29560
|
let s = 0;
|
|
29366
|
-
for (let i = 0; i < n; i++) s +=
|
|
29561
|
+
for (let i = 0; i < n; i++) s += data[i];
|
|
29367
29562
|
const m = s / n;
|
|
29368
29563
|
let ss = 0;
|
|
29369
|
-
for (let i = 0; i < n; i++) ss += (
|
|
29564
|
+
for (let i = 0; i < n; i++) ss += (data[i] - m) ** 2;
|
|
29370
29565
|
const denom = w === 1 ? n : n - 1;
|
|
29371
29566
|
return ss / denom;
|
|
29372
29567
|
};
|
|
29373
29568
|
const stdVarApply = (name, transform) => {
|
|
29374
|
-
return (
|
|
29375
|
-
if (
|
|
29569
|
+
return (rawArgs) => {
|
|
29570
|
+
if (rawArgs.length < 1)
|
|
29376
29571
|
throw new RuntimeError(`${name} requires at least 1 argument`);
|
|
29572
|
+
const { args, omitNaN } = parseNanFlag(rawArgs);
|
|
29377
29573
|
const v = args[0];
|
|
29378
29574
|
const w = args.length >= 2 ? toNumber(args[1]) : 0;
|
|
29379
29575
|
const dimArg = args.length >= 3 ? Math.round(toNumber(args[2])) : 0;
|
|
29380
29576
|
if (isRuntimeNumber(v)) return RTV.num(0);
|
|
29381
29577
|
if (isRuntimeTensor(v)) {
|
|
29382
29578
|
const kernel = sliceKernel(
|
|
29383
|
-
(slice) => transform(varianceOf(slice, w))
|
|
29579
|
+
(slice) => transform(varianceOf(slice, w, omitNaN))
|
|
29384
29580
|
);
|
|
29385
29581
|
if (dimArg > 0) return kernel.reduceDim(v, dimArg);
|
|
29386
29582
|
const d = firstReduceDim(v.shape);
|
|
@@ -29408,7 +29604,13 @@ function registerBasicReductions() {
|
|
|
29408
29604
|
if (n % 2 === 1) return sorted[(n - 1) / 2];
|
|
29409
29605
|
return (sorted[n / 2 - 1] + sorted[n / 2]) / 2;
|
|
29410
29606
|
};
|
|
29411
|
-
register("median", [
|
|
29607
|
+
register("median", [
|
|
29608
|
+
makeReduction(
|
|
29609
|
+
"median",
|
|
29610
|
+
sliceKernel(medianOf),
|
|
29611
|
+
sliceKernelOmitNaN(medianOf)
|
|
29612
|
+
)
|
|
29613
|
+
]);
|
|
29412
29614
|
const modeOf = (arr) => {
|
|
29413
29615
|
const counts = /* @__PURE__ */ new Map();
|
|
29414
29616
|
for (let i = 0; i < arr.length; i++) {
|
|
@@ -29423,7 +29625,9 @@ function registerBasicReductions() {
|
|
|
29423
29625
|
}
|
|
29424
29626
|
return bestVal;
|
|
29425
29627
|
};
|
|
29426
|
-
register("mode", [
|
|
29628
|
+
register("mode", [
|
|
29629
|
+
makeReduction("mode", sliceKernel(modeOf), sliceKernelOmitNaN(modeOf))
|
|
29630
|
+
]);
|
|
29427
29631
|
}
|
|
29428
29632
|
|
|
29429
29633
|
// src/numbl-core/builtins/reduction/min-max.ts
|
|
@@ -30051,6 +30255,11 @@ function registerSortUnique() {
|
|
|
30051
30255
|
dim = idx >= 0 ? idx + 1 : 1;
|
|
30052
30256
|
}
|
|
30053
30257
|
const dimIdx = dim - 1;
|
|
30258
|
+
if (!im && !descend && nargout <= 1 && re.length === shape[dimIdx]) {
|
|
30259
|
+
const sorted2 = new FloatXArray(re);
|
|
30260
|
+
sorted2.sort();
|
|
30261
|
+
return RTV.tensor(sorted2, [...shape]);
|
|
30262
|
+
}
|
|
30054
30263
|
if (dimIdx >= shape.length) {
|
|
30055
30264
|
const cp = RTV.tensor(
|
|
30056
30265
|
new FloatXArray(re),
|
|
@@ -32884,51 +33093,61 @@ function registerDet() {
|
|
|
32884
33093
|
register("cross", [
|
|
32885
33094
|
{
|
|
32886
33095
|
check: (argTypes, nargout) => {
|
|
32887
|
-
if (argTypes.length !== 2 || nargout !== 1)
|
|
33096
|
+
if (argTypes.length !== 2 && argTypes.length !== 3 || nargout !== 1)
|
|
33097
|
+
return null;
|
|
32888
33098
|
return { outputTypes: [IType.Unknown] };
|
|
32889
33099
|
},
|
|
32890
33100
|
apply: (args) => {
|
|
32891
|
-
if (args.length
|
|
32892
|
-
throw new RuntimeError("cross requires 2 arguments");
|
|
33101
|
+
if (args.length < 2 || args.length > 3)
|
|
33102
|
+
throw new RuntimeError("cross requires 2 or 3 arguments");
|
|
32893
33103
|
const a = args[0], b = args[1];
|
|
32894
33104
|
if (!isRuntimeTensor(a) || !isRuntimeTensor(b))
|
|
32895
|
-
throw new RuntimeError("cross: arguments must be vectors");
|
|
32896
|
-
const
|
|
32897
|
-
|
|
32898
|
-
|
|
32899
|
-
|
|
32900
|
-
|
|
32901
|
-
|
|
32902
|
-
|
|
32903
|
-
|
|
32904
|
-
if (a.data.length !== 3 || b.data.length !== 3)
|
|
32905
|
-
throw new RuntimeError("cross: vectors must have 3 elements");
|
|
32906
|
-
const ax = a.data[0], ay = a.data[1], az = a.data[2];
|
|
32907
|
-
const bx = b.data[0], by = b.data[1], bz = b.data[2];
|
|
32908
|
-
const result = new FloatXArray(3);
|
|
32909
|
-
result[0] = ay * bz - az * by;
|
|
32910
|
-
result[1] = az * bx - ax * bz;
|
|
32911
|
-
result[2] = ax * by - ay * bx;
|
|
32912
|
-
return RTV.tensor(result, isColVector ? [3, 1] : [1, 3]);
|
|
32913
|
-
} else if (isMatrix) {
|
|
32914
|
-
if (bRows !== 3 || bCols !== aCols)
|
|
32915
|
-
throw new RuntimeError("cross: matrix dimensions must agree");
|
|
32916
|
-
const cols = aCols;
|
|
32917
|
-
const result = new FloatXArray(3 * cols);
|
|
32918
|
-
for (let c = 0; c < cols; c++) {
|
|
32919
|
-
const off = c * 3;
|
|
32920
|
-
const ax = a.data[off], ay = a.data[off + 1], az = a.data[off + 2];
|
|
32921
|
-
const bx = b.data[off], by = b.data[off + 1], bz = b.data[off + 2];
|
|
32922
|
-
result[off] = ay * bz - az * by;
|
|
32923
|
-
result[off + 1] = az * bx - ax * bz;
|
|
32924
|
-
result[off + 2] = ax * by - ay * bx;
|
|
32925
|
-
}
|
|
32926
|
-
return RTV.tensor(result, [3, cols]);
|
|
33105
|
+
throw new RuntimeError("cross: arguments must be vectors or arrays");
|
|
33106
|
+
const shape = a.shape;
|
|
33107
|
+
if (shape.length !== b.shape.length || shape.some((s, i) => s !== b.shape[i]))
|
|
33108
|
+
throw new RuntimeError("cross: A and B must have the same size");
|
|
33109
|
+
let dim;
|
|
33110
|
+
if (args.length === 3) {
|
|
33111
|
+
dim = toNumber(args[2]);
|
|
33112
|
+
if (!Number.isInteger(dim) || dim < 1)
|
|
33113
|
+
throw new RuntimeError("cross: dim must be a positive integer");
|
|
32927
33114
|
} else {
|
|
33115
|
+
dim = shape.indexOf(3) + 1;
|
|
33116
|
+
if (dim === 0)
|
|
33117
|
+
throw new RuntimeError(
|
|
33118
|
+
"cross: A and B must have at least one dimension of length 3"
|
|
33119
|
+
);
|
|
33120
|
+
}
|
|
33121
|
+
const dimIdx = dim - 1;
|
|
33122
|
+
if (dimIdx >= shape.length || shape[dimIdx] !== 3)
|
|
32928
33123
|
throw new RuntimeError(
|
|
32929
|
-
|
|
33124
|
+
`cross: size(A,${dim}) and size(B,${dim}) must be 3`
|
|
32930
33125
|
);
|
|
32931
|
-
|
|
33126
|
+
const totalLen = a.data.length;
|
|
33127
|
+
const result = new FloatXArray(totalLen);
|
|
33128
|
+
const strides = new Array(shape.length);
|
|
33129
|
+
strides[0] = 1;
|
|
33130
|
+
for (let d = 1; d < shape.length; d++)
|
|
33131
|
+
strides[d] = strides[d - 1] * shape[d - 1];
|
|
33132
|
+
const dimStride = strides[dimIdx];
|
|
33133
|
+
const outerStride = dimIdx + 1 < shape.length ? strides[dimIdx + 1] : totalLen;
|
|
33134
|
+
const innerSize = dimStride;
|
|
33135
|
+
const numOuter = totalLen / outerStride;
|
|
33136
|
+
for (let outer = 0; outer < numOuter; outer++) {
|
|
33137
|
+
const blockBase = outer * outerStride;
|
|
33138
|
+
for (let inner = 0; inner < innerSize; inner++) {
|
|
33139
|
+
const base = blockBase + inner;
|
|
33140
|
+
const i0 = base;
|
|
33141
|
+
const i1 = base + dimStride;
|
|
33142
|
+
const i2 = base + 2 * dimStride;
|
|
33143
|
+
const ax = a.data[i0], ay = a.data[i1], az = a.data[i2];
|
|
33144
|
+
const bx = b.data[i0], by = b.data[i1], bz = b.data[i2];
|
|
33145
|
+
result[i0] = ay * bz - az * by;
|
|
33146
|
+
result[i1] = az * bx - ax * bz;
|
|
33147
|
+
result[i2] = ax * by - ay * bx;
|
|
33148
|
+
}
|
|
33149
|
+
}
|
|
33150
|
+
return RTV.tensor(result, [...shape]);
|
|
32932
33151
|
}
|
|
32933
33152
|
}
|
|
32934
33153
|
]);
|
|
@@ -38367,6 +38586,67 @@ function endResolver(mv, numIndices) {
|
|
|
38367
38586
|
};
|
|
38368
38587
|
}
|
|
38369
38588
|
function index(rt, base, indices, nargout = 1, skipSubsref = false) {
|
|
38589
|
+
if (typeof base === "object" && base !== null && base.kind === "tensor") {
|
|
38590
|
+
const t = base;
|
|
38591
|
+
const nIdx = indices.length;
|
|
38592
|
+
if (nIdx === 1) {
|
|
38593
|
+
const idx = indices[0];
|
|
38594
|
+
if (typeof idx === "number") {
|
|
38595
|
+
const i = Math.round(idx) - 1;
|
|
38596
|
+
if (i < 0 || i >= t.data.length)
|
|
38597
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
38598
|
+
if (t.imag !== void 0) {
|
|
38599
|
+
const im = t.imag[i];
|
|
38600
|
+
return im === 0 ? t.data[i] : RTV.complex(t.data[i], im);
|
|
38601
|
+
}
|
|
38602
|
+
return t.data[i];
|
|
38603
|
+
}
|
|
38604
|
+
} else if (nIdx === 2) {
|
|
38605
|
+
const ri = indices[0];
|
|
38606
|
+
const ci = indices[1];
|
|
38607
|
+
if (typeof ri === "number" && typeof ci === "number") {
|
|
38608
|
+
const s = t.shape;
|
|
38609
|
+
const rows = s.length === 0 ? 1 : s.length === 1 ? 1 : s[0];
|
|
38610
|
+
const cols = s.length === 0 ? 1 : s.length === 1 ? s[0] : s[1];
|
|
38611
|
+
const r = Math.round(ri) - 1;
|
|
38612
|
+
const c = Math.round(ci) - 1;
|
|
38613
|
+
if (r < 0 || r >= rows || c < 0 || c >= cols)
|
|
38614
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
38615
|
+
const lin = c * rows + r;
|
|
38616
|
+
if (t.imag !== void 0) {
|
|
38617
|
+
const im = t.imag[lin];
|
|
38618
|
+
return im === 0 ? t.data[lin] : RTV.complex(t.data[lin], im);
|
|
38619
|
+
}
|
|
38620
|
+
return t.data[lin];
|
|
38621
|
+
}
|
|
38622
|
+
} else if (nIdx >= 3) {
|
|
38623
|
+
let allNumeric = true;
|
|
38624
|
+
for (let k = 0; k < nIdx; k++) {
|
|
38625
|
+
if (typeof indices[k] !== "number") {
|
|
38626
|
+
allNumeric = false;
|
|
38627
|
+
break;
|
|
38628
|
+
}
|
|
38629
|
+
}
|
|
38630
|
+
if (allNumeric) {
|
|
38631
|
+
const s = t.shape;
|
|
38632
|
+
let lin = 0;
|
|
38633
|
+
let stride = 1;
|
|
38634
|
+
for (let k = 0; k < nIdx; k++) {
|
|
38635
|
+
const dimSize = k < s.length ? s[k] : 1;
|
|
38636
|
+
const sub = Math.round(indices[k]) - 1;
|
|
38637
|
+
if (sub < 0 || sub >= dimSize)
|
|
38638
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
38639
|
+
lin += sub * stride;
|
|
38640
|
+
stride *= dimSize;
|
|
38641
|
+
}
|
|
38642
|
+
if (t.imag !== void 0) {
|
|
38643
|
+
const im = t.imag[lin];
|
|
38644
|
+
return im === 0 ? t.data[lin] : RTV.complex(t.data[lin], im);
|
|
38645
|
+
}
|
|
38646
|
+
return t.data[lin];
|
|
38647
|
+
}
|
|
38648
|
+
}
|
|
38649
|
+
}
|
|
38370
38650
|
if (typeof base === "function") {
|
|
38371
38651
|
return base(...indices);
|
|
38372
38652
|
}
|
|
@@ -38451,6 +38731,13 @@ function resolveIndicesForClassInstance(rt, mv, base, indices) {
|
|
|
38451
38731
|
});
|
|
38452
38732
|
}
|
|
38453
38733
|
function indexCell(rt, base, indices) {
|
|
38734
|
+
if (indices.length === 1 && typeof indices[0] === "number" && typeof base === "object" && base !== null && base.kind === "cell") {
|
|
38735
|
+
const cell = base;
|
|
38736
|
+
const i = Math.round(indices[0]) - 1;
|
|
38737
|
+
if (i < 0 || i >= cell.data.length)
|
|
38738
|
+
throw new RuntimeError("Cell index exceeds bounds");
|
|
38739
|
+
return cell.data[i];
|
|
38740
|
+
}
|
|
38454
38741
|
const mv = ensureRuntimeValue(base);
|
|
38455
38742
|
if (isRuntimeClassInstance(mv)) {
|
|
38456
38743
|
const subsrefFn = rt.cachedResolveClassMethod(mv.className, "subsref");
|
|
@@ -38589,7 +38876,7 @@ function indexStore(rt, base, indices, rhs, skipSubsasgn = false) {
|
|
|
38589
38876
|
if (isRuntimeCell(mv)) {
|
|
38590
38877
|
const idxMvals2 = resolveIndices(indices, endResolver(mv, indices.length));
|
|
38591
38878
|
const rhsMv2 = ensureRuntimeValue(rhs);
|
|
38592
|
-
return storeIntoRTValueIndex(mv, idxMvals2, rhsMv2);
|
|
38879
|
+
return storeIntoRTValueIndex(mv, idxMvals2, rhsMv2, true);
|
|
38593
38880
|
}
|
|
38594
38881
|
if (isRuntimeStruct(mv)) {
|
|
38595
38882
|
return ensureRuntimeValue(rhs);
|
|
@@ -40148,15 +40435,23 @@ var Runtime = class _Runtime {
|
|
|
40148
40435
|
// ── Builtin initialization ──────────────────────────────────────────
|
|
40149
40436
|
initBuiltins() {
|
|
40150
40437
|
for (const name of getAllBuiltinNames()) {
|
|
40438
|
+
const builtin = getBuiltin(name);
|
|
40439
|
+
const singleBranch = builtin.length === 1 ? builtin[0] : null;
|
|
40151
40440
|
this.builtins[name] = (nargout, args) => {
|
|
40152
|
-
const builtin = getBuiltin(name);
|
|
40153
40441
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
40154
|
-
|
|
40155
|
-
|
|
40156
|
-
|
|
40157
|
-
|
|
40158
|
-
|
|
40159
|
-
|
|
40442
|
+
let branch;
|
|
40443
|
+
if (singleBranch) {
|
|
40444
|
+
branch = singleBranch;
|
|
40445
|
+
} else {
|
|
40446
|
+
const argItemTypes = margs.map(
|
|
40447
|
+
(arg) => getItemTypeFromRuntimeValue(arg)
|
|
40448
|
+
);
|
|
40449
|
+
branch = builtin[0];
|
|
40450
|
+
for (let i = 0; i < builtin.length; i++) {
|
|
40451
|
+
if (builtin[i].check(argItemTypes, nargout)) {
|
|
40452
|
+
branch = builtin[i];
|
|
40453
|
+
break;
|
|
40454
|
+
}
|
|
40160
40455
|
}
|
|
40161
40456
|
}
|
|
40162
40457
|
if (this.profilingEnabled) {
|
|
@@ -44579,8 +44874,6 @@ function genClassInstantiation(cg, kind) {
|
|
|
44579
44874
|
return createExpr;
|
|
44580
44875
|
}
|
|
44581
44876
|
var NATIVE_MATH_1 = {
|
|
44582
|
-
// Note: sqrt, asin, acos, log are NOT here because they can produce
|
|
44583
|
-
// complex results from real inputs (e.g., sqrt(-1) = 1i).
|
|
44584
44877
|
abs: "Math.abs",
|
|
44585
44878
|
floor: "Math.floor",
|
|
44586
44879
|
ceil: "Math.ceil",
|
|
@@ -44594,6 +44887,14 @@ var NATIVE_MATH_1 = {
|
|
|
44594
44887
|
log10: "Math.log10",
|
|
44595
44888
|
sign: "Math.sign"
|
|
44596
44889
|
};
|
|
44890
|
+
var GUARDED_MATH_1 = {
|
|
44891
|
+
sqrt: { fn: "Math.sqrt", guard: "$x >= 0" },
|
|
44892
|
+
log: { fn: "Math.log", guard: "$x > 0" },
|
|
44893
|
+
asin: { fn: "Math.asin", guard: "$x >= -1 && $x <= 1" },
|
|
44894
|
+
acos: { fn: "Math.acos", guard: "$x >= -1 && $x <= 1" },
|
|
44895
|
+
acosh: { fn: "Math.acosh", guard: "$x >= 1" },
|
|
44896
|
+
atanh: { fn: "Math.atanh", guard: "$x > -1 && $x < 1" }
|
|
44897
|
+
};
|
|
44597
44898
|
var NATIVE_MATH_2 = {
|
|
44598
44899
|
// Note: max/min are NOT here because Math.max/Math.min propagate NaN,
|
|
44599
44900
|
// but max/min ignore NaN (returning the non-NaN value).
|
|
@@ -44605,6 +44906,15 @@ function tryNativeMathCodegen(cg, name, nargout, irArgs, jsArgs) {
|
|
|
44605
44906
|
if (jsArgs.length === 1 && itemTypeForExprKind(irArgs[0].kind, cg.typeEnv).kind === "Number") {
|
|
44606
44907
|
const fn = NATIVE_MATH_1[name];
|
|
44607
44908
|
if (fn) return `${fn}(${jsArgs[0]})`;
|
|
44909
|
+
const guarded = GUARDED_MATH_1[name];
|
|
44910
|
+
if (guarded) {
|
|
44911
|
+
const arg = jsArgs[0];
|
|
44912
|
+
const tmp = cg.freshTemp("$gm");
|
|
44913
|
+
cg.emit(`var ${tmp};`);
|
|
44914
|
+
const guard = guarded.guard.replace(/\$x/g, tmp);
|
|
44915
|
+
const fallback = `${cg.useBuiltin(name)}(1, [${tmp}])`;
|
|
44916
|
+
return `(${tmp} = ${arg}, ${guard} ? ${guarded.fn}(${tmp}) : ${fallback})`;
|
|
44917
|
+
}
|
|
44608
44918
|
}
|
|
44609
44919
|
if (jsArgs.length === 2 && itemTypeForExprKind(irArgs[0].kind, cg.typeEnv).kind === "Number" && itemTypeForExprKind(irArgs[1].kind, cg.typeEnv).kind === "Number") {
|
|
44610
44920
|
const fn = NATIVE_MATH_2[name];
|
|
@@ -46318,6 +46628,21 @@ function instantiateWasm(wasmData) {
|
|
|
46318
46628
|
}
|
|
46319
46629
|
return new WebAssembly.Instance(wasmModule, importObject);
|
|
46320
46630
|
}
|
|
46631
|
+
function resolveBindings(file, directives, getWasmInstance, nativeBridge2) {
|
|
46632
|
+
const wasmInstance = directives.wasm ? getWasmInstance(directives.wasm) : void 0;
|
|
46633
|
+
let nativeLib;
|
|
46634
|
+
if (directives.native && nativeBridge2) {
|
|
46635
|
+
const libFile = nativeLibFilename(directives.native);
|
|
46636
|
+
const dir = file.name.substring(0, file.name.lastIndexOf("/") + 1);
|
|
46637
|
+
const libPath = dir + libFile;
|
|
46638
|
+
try {
|
|
46639
|
+
nativeLib = nativeBridge2.load(libPath);
|
|
46640
|
+
} catch {
|
|
46641
|
+
}
|
|
46642
|
+
}
|
|
46643
|
+
return { wasmInstance, nativeLib };
|
|
46644
|
+
}
|
|
46645
|
+
var LOADING = /* @__PURE__ */ Symbol("loading");
|
|
46321
46646
|
function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
46322
46647
|
const result = /* @__PURE__ */ new Map();
|
|
46323
46648
|
const wasmMap = wasmFiles ? buildWasmMap(wasmFiles) : /* @__PURE__ */ new Map();
|
|
@@ -46331,7 +46656,68 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46331
46656
|
wasmInstanceCache.set(name, instance);
|
|
46332
46657
|
return instance;
|
|
46333
46658
|
}
|
|
46659
|
+
const libraryFiles = /* @__PURE__ */ new Map();
|
|
46660
|
+
const functionFiles = [];
|
|
46334
46661
|
for (const file of jsFiles) {
|
|
46662
|
+
const base = file.name.split("/").pop();
|
|
46663
|
+
if (base.startsWith("_")) {
|
|
46664
|
+
const libName = base.replace(/\.js$/, "");
|
|
46665
|
+
libraryFiles.set(libName, file);
|
|
46666
|
+
} else {
|
|
46667
|
+
functionFiles.push(file);
|
|
46668
|
+
}
|
|
46669
|
+
}
|
|
46670
|
+
const libCache = /* @__PURE__ */ new Map();
|
|
46671
|
+
function importJS(name) {
|
|
46672
|
+
const cached = libCache.get(name);
|
|
46673
|
+
if (cached === LOADING) {
|
|
46674
|
+
throw new RuntimeError(`Circular dependency detected: ${name}.js`);
|
|
46675
|
+
}
|
|
46676
|
+
if (libCache.has(name)) return cached;
|
|
46677
|
+
const libFile = libraryFiles.get(name);
|
|
46678
|
+
if (!libFile) {
|
|
46679
|
+
throw new RuntimeError(
|
|
46680
|
+
`importJS: library '${name}.js' not found in workspace`
|
|
46681
|
+
);
|
|
46682
|
+
}
|
|
46683
|
+
libCache.set(name, LOADING);
|
|
46684
|
+
const directives = parseDirectives(libFile.source);
|
|
46685
|
+
const { wasmInstance, nativeLib } = resolveBindings(
|
|
46686
|
+
libFile,
|
|
46687
|
+
directives,
|
|
46688
|
+
getWasmInstance,
|
|
46689
|
+
nativeBridge2
|
|
46690
|
+
);
|
|
46691
|
+
const dummyRegister = () => {
|
|
46692
|
+
throw new RuntimeError(
|
|
46693
|
+
`Library file '${name}.js' must not call register(). Use return {...} to export values.`
|
|
46694
|
+
);
|
|
46695
|
+
};
|
|
46696
|
+
const factory = new Function(
|
|
46697
|
+
"RTV",
|
|
46698
|
+
"RuntimeError",
|
|
46699
|
+
"FloatXArray",
|
|
46700
|
+
"IType",
|
|
46701
|
+
"register",
|
|
46702
|
+
"wasm",
|
|
46703
|
+
"native",
|
|
46704
|
+
"importJS",
|
|
46705
|
+
libFile.source
|
|
46706
|
+
);
|
|
46707
|
+
const exports = factory(
|
|
46708
|
+
RTV,
|
|
46709
|
+
RuntimeError,
|
|
46710
|
+
FloatXArray,
|
|
46711
|
+
IType,
|
|
46712
|
+
dummyRegister,
|
|
46713
|
+
wasmInstance,
|
|
46714
|
+
nativeLib,
|
|
46715
|
+
importJS
|
|
46716
|
+
);
|
|
46717
|
+
libCache.set(name, exports);
|
|
46718
|
+
return exports;
|
|
46719
|
+
}
|
|
46720
|
+
for (const file of functionFiles) {
|
|
46335
46721
|
const funcName = funcNameFromFile(file.name);
|
|
46336
46722
|
try {
|
|
46337
46723
|
const branches = [];
|
|
@@ -46345,17 +46731,12 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46345
46731
|
});
|
|
46346
46732
|
};
|
|
46347
46733
|
const directives = parseDirectives(file.source);
|
|
46348
|
-
const wasmInstance
|
|
46349
|
-
|
|
46350
|
-
|
|
46351
|
-
|
|
46352
|
-
|
|
46353
|
-
|
|
46354
|
-
try {
|
|
46355
|
-
nativeLib = nativeBridge2.load(libPath);
|
|
46356
|
-
} catch {
|
|
46357
|
-
}
|
|
46358
|
-
}
|
|
46734
|
+
const { wasmInstance, nativeLib } = resolveBindings(
|
|
46735
|
+
file,
|
|
46736
|
+
directives,
|
|
46737
|
+
getWasmInstance,
|
|
46738
|
+
nativeBridge2
|
|
46739
|
+
);
|
|
46359
46740
|
const factory = new Function(
|
|
46360
46741
|
"RTV",
|
|
46361
46742
|
"RuntimeError",
|
|
@@ -46364,6 +46745,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46364
46745
|
"register",
|
|
46365
46746
|
"wasm",
|
|
46366
46747
|
"native",
|
|
46748
|
+
"importJS",
|
|
46367
46749
|
file.source
|
|
46368
46750
|
);
|
|
46369
46751
|
factory(
|
|
@@ -46373,7 +46755,8 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46373
46755
|
IType,
|
|
46374
46756
|
registerFn,
|
|
46375
46757
|
wasmInstance,
|
|
46376
|
-
nativeLib
|
|
46758
|
+
nativeLib,
|
|
46759
|
+
importJS
|
|
46377
46760
|
);
|
|
46378
46761
|
if (branches.length === 0) {
|
|
46379
46762
|
throw new Error(
|
|
@@ -47188,6 +47571,9 @@ Call stack (most recent call first):`;
|
|
|
47188
47571
|
return result;
|
|
47189
47572
|
}
|
|
47190
47573
|
|
|
47574
|
+
// src/numbl-core/version.ts
|
|
47575
|
+
var NUMBL_VERSION = "0.0.22";
|
|
47576
|
+
|
|
47191
47577
|
// src/cli-repl.ts
|
|
47192
47578
|
import { createInterface } from "readline";
|
|
47193
47579
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, appendFileSync } from "fs";
|
|
@@ -47982,6 +48368,10 @@ Commands:
|
|
|
47982
48368
|
mip <subcommand> Package manager (install, uninstall, list, avail, info)
|
|
47983
48369
|
(no command) Start interactive REPL
|
|
47984
48370
|
|
|
48371
|
+
Global options:
|
|
48372
|
+
--version, -V Print version and exit
|
|
48373
|
+
--help, -h Print this help message
|
|
48374
|
+
|
|
47985
48375
|
Options (for REPL):
|
|
47986
48376
|
--plot Enable plot server
|
|
47987
48377
|
--plot-port <port> Set plot server port (implies --plot)
|
|
@@ -48376,6 +48766,7 @@ async function cmdBuildAddon() {
|
|
|
48376
48766
|
function cmdInfo() {
|
|
48377
48767
|
process.stdout.write(
|
|
48378
48768
|
JSON.stringify({
|
|
48769
|
+
version: NUMBL_VERSION,
|
|
48379
48770
|
nativeAddon: nativeAddonLoaded,
|
|
48380
48771
|
nativeAddonPath: addonPath,
|
|
48381
48772
|
packageDir: packageDir2
|
|
@@ -48534,6 +48925,10 @@ function cmdShowProfile(args) {
|
|
|
48534
48925
|
}
|
|
48535
48926
|
async function main() {
|
|
48536
48927
|
const args = process.argv.slice(2);
|
|
48928
|
+
if (args.includes("--version") || args.includes("-V")) {
|
|
48929
|
+
console.log(NUMBL_VERSION);
|
|
48930
|
+
process.exit(0);
|
|
48931
|
+
}
|
|
48537
48932
|
if (args.includes("--help") || args.includes("-h")) {
|
|
48538
48933
|
printHelp();
|
|
48539
48934
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "numbl",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "Run .m source files in the browser and on the command line by compiling to JavaScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -106,10 +106,11 @@
|
|
|
106
106
|
"vitest": "^4.0.18"
|
|
107
107
|
},
|
|
108
108
|
"lint-staged": {
|
|
109
|
-
"*.{
|
|
109
|
+
"*.{ts,tsx}": [
|
|
110
110
|
"prettier --write",
|
|
111
111
|
"eslint"
|
|
112
112
|
],
|
|
113
|
+
"*.{js,jsx}": "prettier --write",
|
|
113
114
|
"*.{json,css,md,yml}": "prettier --write"
|
|
114
115
|
},
|
|
115
116
|
"optionalDependencies": {
|