numbl 0.0.21 → 0.0.23
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/binding.gyp +6 -4
- package/dist-cli/cli.js +767 -170
- package/native/elemwise.cpp +168 -0
- package/native/lapack_chol.cpp +1 -1
- package/native/lapack_eig.cpp +1 -1
- package/native/lapack_fft.cpp +1 -1
- package/native/lapack_fft_batch.cpp +1 -1
- package/native/lapack_inv.cpp +1 -1
- package/native/lapack_linsolve.cpp +1 -1
- package/native/lapack_lu.cpp +1 -1
- package/native/lapack_matmul.cpp +1 -1
- package/native/lapack_matmul_complex.cpp +110 -0
- package/native/lapack_qr.cpp +1 -1
- package/native/lapack_qz.cpp +1 -1
- package/native/lapack_svd.cpp +1 -1
- package/native/{lapack_addon.cpp → numbl_addon.cpp} +30 -3
- package/native/{lapack_common.h → numbl_addon_common.h} +11 -1
- package/package.json +3 -2
package/dist-cli/cli.js
CHANGED
|
@@ -1214,6 +1214,10 @@ var RTV = {
|
|
|
1214
1214
|
while (s.length > 2 && s[s.length - 1] === 1) s.pop();
|
|
1215
1215
|
return { kind: "tensor", data: d, imag: im, shape: s, _rc: 1 };
|
|
1216
1216
|
},
|
|
1217
|
+
/** Fast tensor constructor — data must be FloatXArray, shape already normalized (no trailing singletons). */
|
|
1218
|
+
tensorRaw(data, shape) {
|
|
1219
|
+
return { kind: "tensor", data, imag: void 0, shape, _rc: 1 };
|
|
1220
|
+
},
|
|
1217
1221
|
/** Create a scalar tensor (1x1) */
|
|
1218
1222
|
scalar(value) {
|
|
1219
1223
|
return value;
|
|
@@ -1352,6 +1356,7 @@ var getItemTypeFromRuntimeValue = (value) => {
|
|
|
1352
1356
|
};
|
|
1353
1357
|
|
|
1354
1358
|
// src/numbl-core/native/lapack-bridge.ts
|
|
1359
|
+
var NATIVE_ADDON_EXPECTED_VERSION = 1;
|
|
1355
1360
|
var _bridge = null;
|
|
1356
1361
|
function setLapackBridge(bridge) {
|
|
1357
1362
|
_bridge = bridge;
|
|
@@ -19027,7 +19032,91 @@ function complexBinaryOp(a, b, op) {
|
|
|
19027
19032
|
`Matrix dimensions must agree: [${at.shape.join(",")}] vs [${bt.shape.join(",")}]`
|
|
19028
19033
|
);
|
|
19029
19034
|
}
|
|
19035
|
+
var ELEMWISE_ADD = 0;
|
|
19036
|
+
var ELEMWISE_SUB = 1;
|
|
19037
|
+
var ELEMWISE_MUL = 2;
|
|
19038
|
+
var ELEMWISE_DIV = 3;
|
|
19039
|
+
function matchSameShapeTensors(a, b) {
|
|
19040
|
+
if (typeof a !== "object" || a === null || a.kind !== "tensor" || typeof b !== "object" || b === null || b.kind !== "tensor")
|
|
19041
|
+
return null;
|
|
19042
|
+
const at = a;
|
|
19043
|
+
const bt = b;
|
|
19044
|
+
if (at.data.length !== bt.data.length || at.shape.length !== bt.shape.length || at.shape.some((d, i) => d !== bt.shape[i]))
|
|
19045
|
+
return null;
|
|
19046
|
+
return [at, bt];
|
|
19047
|
+
}
|
|
19048
|
+
function tryNativeElemwiseReal(at, bt, opCode) {
|
|
19049
|
+
const bridge = getLapackBridge();
|
|
19050
|
+
if (!bridge?.elemwise) return null;
|
|
19051
|
+
const result = bridge.elemwise(
|
|
19052
|
+
at.data,
|
|
19053
|
+
bt.data,
|
|
19054
|
+
opCode
|
|
19055
|
+
);
|
|
19056
|
+
return RTV.tensorRaw(result, at.shape);
|
|
19057
|
+
}
|
|
19058
|
+
function tensorElemwiseComplex(at, bt, opCode, jsOp) {
|
|
19059
|
+
const bridge = getLapackBridge();
|
|
19060
|
+
if (bridge?.elemwiseComplex) {
|
|
19061
|
+
const r = bridge.elemwiseComplex(
|
|
19062
|
+
at.data,
|
|
19063
|
+
at.imag ?? null,
|
|
19064
|
+
bt.data,
|
|
19065
|
+
bt.imag ?? null,
|
|
19066
|
+
opCode
|
|
19067
|
+
);
|
|
19068
|
+
if (r.im) return RTV.tensor(r.re, at.shape, r.im);
|
|
19069
|
+
return RTV.tensorRaw(r.re, at.shape);
|
|
19070
|
+
}
|
|
19071
|
+
const len = at.data.length;
|
|
19072
|
+
const aIm = at.imag;
|
|
19073
|
+
const bIm = bt.imag;
|
|
19074
|
+
const resultRe = new FloatXArray(len);
|
|
19075
|
+
const resultIm = new FloatXArray(len);
|
|
19076
|
+
if (aIm && bIm) {
|
|
19077
|
+
for (let i = 0; i < len; i++) {
|
|
19078
|
+
const r = jsOp(at.data[i], aIm[i], bt.data[i], bIm[i]);
|
|
19079
|
+
resultRe[i] = r.re;
|
|
19080
|
+
resultIm[i] = r.im;
|
|
19081
|
+
}
|
|
19082
|
+
} else if (aIm) {
|
|
19083
|
+
for (let i = 0; i < len; i++) {
|
|
19084
|
+
const r = jsOp(at.data[i], aIm[i], bt.data[i], 0);
|
|
19085
|
+
resultRe[i] = r.re;
|
|
19086
|
+
resultIm[i] = r.im;
|
|
19087
|
+
}
|
|
19088
|
+
} else {
|
|
19089
|
+
for (let i = 0; i < len; i++) {
|
|
19090
|
+
const r = jsOp(at.data[i], 0, bt.data[i], bIm[i]);
|
|
19091
|
+
resultRe[i] = r.re;
|
|
19092
|
+
resultIm[i] = r.im;
|
|
19093
|
+
}
|
|
19094
|
+
}
|
|
19095
|
+
const isReal = resultIm.every((x) => x === 0);
|
|
19096
|
+
return RTV.tensor(resultRe, at.shape, isReal ? void 0 : resultIm);
|
|
19097
|
+
}
|
|
19030
19098
|
function mAdd(a, b) {
|
|
19099
|
+
const m = matchSameShapeTensors(a, b);
|
|
19100
|
+
if (m) {
|
|
19101
|
+
const [at, bt] = m;
|
|
19102
|
+
if (!at.imag && !bt.imag) {
|
|
19103
|
+
const nr = tryNativeElemwiseReal(at, bt, ELEMWISE_ADD);
|
|
19104
|
+
if (nr) return nr;
|
|
19105
|
+
const len = at.data.length;
|
|
19106
|
+
const result = new FloatXArray(len);
|
|
19107
|
+
for (let i = 0; i < len; i++) result[i] = at.data[i] + bt.data[i];
|
|
19108
|
+
return RTV.tensorRaw(result, at.shape);
|
|
19109
|
+
}
|
|
19110
|
+
return tensorElemwiseComplex(
|
|
19111
|
+
at,
|
|
19112
|
+
bt,
|
|
19113
|
+
ELEMWISE_ADD,
|
|
19114
|
+
(aRe, aIm, bRe, bIm) => ({
|
|
19115
|
+
re: aRe + bRe,
|
|
19116
|
+
im: aIm + bIm
|
|
19117
|
+
})
|
|
19118
|
+
);
|
|
19119
|
+
}
|
|
19031
19120
|
if (isRuntimeSparseMatrix(a) || isRuntimeSparseMatrix(b))
|
|
19032
19121
|
return mAddSparse(a, b);
|
|
19033
19122
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -19039,6 +19128,27 @@ function mAdd(a, b) {
|
|
|
19039
19128
|
return binaryOp(a, b, (x, y) => x + y);
|
|
19040
19129
|
}
|
|
19041
19130
|
function mSub(a, b) {
|
|
19131
|
+
const m = matchSameShapeTensors(a, b);
|
|
19132
|
+
if (m) {
|
|
19133
|
+
const [at, bt] = m;
|
|
19134
|
+
if (!at.imag && !bt.imag) {
|
|
19135
|
+
const nr = tryNativeElemwiseReal(at, bt, ELEMWISE_SUB);
|
|
19136
|
+
if (nr) return nr;
|
|
19137
|
+
const len = at.data.length;
|
|
19138
|
+
const result = new FloatXArray(len);
|
|
19139
|
+
for (let i = 0; i < len; i++) result[i] = at.data[i] - bt.data[i];
|
|
19140
|
+
return RTV.tensorRaw(result, at.shape);
|
|
19141
|
+
}
|
|
19142
|
+
return tensorElemwiseComplex(
|
|
19143
|
+
at,
|
|
19144
|
+
bt,
|
|
19145
|
+
ELEMWISE_SUB,
|
|
19146
|
+
(aRe, aIm, bRe, bIm) => ({
|
|
19147
|
+
re: aRe - bRe,
|
|
19148
|
+
im: aIm - bIm
|
|
19149
|
+
})
|
|
19150
|
+
);
|
|
19151
|
+
}
|
|
19042
19152
|
if (isRuntimeSparseMatrix(a) || isRuntimeSparseMatrix(b))
|
|
19043
19153
|
return mSubSparse(a, b);
|
|
19044
19154
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -19064,6 +19174,27 @@ function mMul(a, b) {
|
|
|
19064
19174
|
return binaryOp(a, b, (x, y) => x * y);
|
|
19065
19175
|
}
|
|
19066
19176
|
function mElemMul(a, b) {
|
|
19177
|
+
const m = matchSameShapeTensors(a, b);
|
|
19178
|
+
if (m) {
|
|
19179
|
+
const [at, bt] = m;
|
|
19180
|
+
if (!at.imag && !bt.imag) {
|
|
19181
|
+
const nr = tryNativeElemwiseReal(at, bt, ELEMWISE_MUL);
|
|
19182
|
+
if (nr) return nr;
|
|
19183
|
+
const len = at.data.length;
|
|
19184
|
+
const result = new FloatXArray(len);
|
|
19185
|
+
for (let i = 0; i < len; i++) result[i] = at.data[i] * bt.data[i];
|
|
19186
|
+
return RTV.tensorRaw(result, at.shape);
|
|
19187
|
+
}
|
|
19188
|
+
return tensorElemwiseComplex(
|
|
19189
|
+
at,
|
|
19190
|
+
bt,
|
|
19191
|
+
ELEMWISE_MUL,
|
|
19192
|
+
(aRe, aIm, bRe, bIm) => ({
|
|
19193
|
+
re: aRe * bRe - aIm * bIm,
|
|
19194
|
+
im: aRe * bIm + aIm * bRe
|
|
19195
|
+
})
|
|
19196
|
+
);
|
|
19197
|
+
}
|
|
19067
19198
|
if (isRuntimeSparseMatrix(a) || isRuntimeSparseMatrix(b))
|
|
19068
19199
|
return mElemMulSparse(a, b);
|
|
19069
19200
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -19090,6 +19221,19 @@ function mDiv(a, b) {
|
|
|
19090
19221
|
return binaryOp(a, b, (x, y) => x / y);
|
|
19091
19222
|
}
|
|
19092
19223
|
function mElemDiv(a, b) {
|
|
19224
|
+
const m = matchSameShapeTensors(a, b);
|
|
19225
|
+
if (m) {
|
|
19226
|
+
const [at, bt] = m;
|
|
19227
|
+
if (!at.imag && !bt.imag) {
|
|
19228
|
+
const nr = tryNativeElemwiseReal(at, bt, ELEMWISE_DIV);
|
|
19229
|
+
if (nr) return nr;
|
|
19230
|
+
const len = at.data.length;
|
|
19231
|
+
const result = new FloatXArray(len);
|
|
19232
|
+
for (let i = 0; i < len; i++) result[i] = at.data[i] / bt.data[i];
|
|
19233
|
+
return RTV.tensorRaw(result, at.shape);
|
|
19234
|
+
}
|
|
19235
|
+
return tensorElemwiseComplex(at, bt, ELEMWISE_DIV, complexDivide);
|
|
19236
|
+
}
|
|
19093
19237
|
if (isRuntimeSparseMatrix(a) || isRuntimeSparseMatrix(b))
|
|
19094
19238
|
return mElemDivSparse(a, b);
|
|
19095
19239
|
if (isComplexOrMixed(a, b)) {
|
|
@@ -19189,6 +19333,31 @@ function mPow(a, b) {
|
|
|
19189
19333
|
return binaryOp(a, b, (x, y) => Math.pow(x, y));
|
|
19190
19334
|
}
|
|
19191
19335
|
function mElemPow(a, b) {
|
|
19336
|
+
if (isRuntimeTensor(a) && !a.imag && isRuntimeNumber(b)) {
|
|
19337
|
+
const exp = b;
|
|
19338
|
+
if (exp === 2) {
|
|
19339
|
+
const result = new FloatXArray(a.data.length);
|
|
19340
|
+
for (let i = 0; i < result.length; i++) result[i] = a.data[i] * a.data[i];
|
|
19341
|
+
return RTV.tensor(result, a.shape);
|
|
19342
|
+
}
|
|
19343
|
+
if (Number.isInteger(exp) || exp >= 0) {
|
|
19344
|
+
let hasNeg2 = false;
|
|
19345
|
+
if (!Number.isInteger(exp)) {
|
|
19346
|
+
for (let i = 0; i < a.data.length; i++) {
|
|
19347
|
+
if (a.data[i] < 0) {
|
|
19348
|
+
hasNeg2 = true;
|
|
19349
|
+
break;
|
|
19350
|
+
}
|
|
19351
|
+
}
|
|
19352
|
+
}
|
|
19353
|
+
if (!hasNeg2) {
|
|
19354
|
+
const result = new FloatXArray(a.data.length);
|
|
19355
|
+
for (let i = 0; i < result.length; i++)
|
|
19356
|
+
result[i] = Math.pow(a.data[i], exp);
|
|
19357
|
+
return RTV.tensor(result, a.shape);
|
|
19358
|
+
}
|
|
19359
|
+
}
|
|
19360
|
+
}
|
|
19192
19361
|
const complexPow = (aRe, aIm, bRe, bIm) => {
|
|
19193
19362
|
const r = Math.sqrt(aRe * aRe + aIm * aIm);
|
|
19194
19363
|
if (r === 0) {
|
|
@@ -19239,17 +19408,22 @@ function mElemPow(a, b) {
|
|
|
19239
19408
|
return binaryOp(a, b, (x, y) => Math.pow(x, y));
|
|
19240
19409
|
}
|
|
19241
19410
|
function mNeg(v) {
|
|
19242
|
-
if (
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19411
|
+
if (isRuntimeTensor(v)) {
|
|
19412
|
+
if (v.imag !== void 0) {
|
|
19413
|
+
const resultRe2 = new FloatXArray(v.data.length);
|
|
19414
|
+
const resultIm = new FloatXArray(v.imag.length);
|
|
19415
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
19416
|
+
resultRe2[i] = -v.data[i];
|
|
19417
|
+
resultIm[i] = -v.imag[i];
|
|
19418
|
+
}
|
|
19419
|
+
return RTV.tensor(resultRe2, v.shape, resultIm);
|
|
19250
19420
|
}
|
|
19251
|
-
|
|
19421
|
+
const resultRe = new FloatXArray(v.data.length);
|
|
19422
|
+
for (let i = 0; i < v.data.length; i++) resultRe[i] = -v.data[i];
|
|
19423
|
+
return RTV.tensor(resultRe, v.shape);
|
|
19252
19424
|
}
|
|
19425
|
+
if (isRuntimeSparseMatrix(v)) return sparseNeg(v);
|
|
19426
|
+
if (isRuntimeComplexNumber(v)) return RTV.complex(-v.re, -v.im);
|
|
19253
19427
|
return unaryOp(v, (x) => -x);
|
|
19254
19428
|
}
|
|
19255
19429
|
function transposeCellArray(v) {
|
|
@@ -19524,6 +19698,40 @@ function broadcastComparison(a, b, outShape, op) {
|
|
|
19524
19698
|
return t;
|
|
19525
19699
|
}
|
|
19526
19700
|
function binaryOp(a, b, op) {
|
|
19701
|
+
if (isRuntimeTensor(a) && a.data.length > 1) {
|
|
19702
|
+
if (isRuntimeTensor(b) && b.data.length > 1) {
|
|
19703
|
+
if (a.data.length === b.data.length && a.shape.length === b.shape.length && a.shape.every((d, i) => d === b.shape[i])) {
|
|
19704
|
+
const result = new FloatXArray(a.data.length);
|
|
19705
|
+
for (let i = 0; i < result.length; i++) {
|
|
19706
|
+
result[i] = op(a.data[i], b.data[i]);
|
|
19707
|
+
}
|
|
19708
|
+
return RTV.tensor(result, a.shape);
|
|
19709
|
+
}
|
|
19710
|
+
const broadcastShape2 = getBroadcastShape(a.shape, b.shape);
|
|
19711
|
+
if (broadcastShape2 !== null) {
|
|
19712
|
+
return broadcastBinary(a, b, broadcastShape2, op);
|
|
19713
|
+
}
|
|
19714
|
+
throw new RuntimeError(
|
|
19715
|
+
`Matrix dimensions must agree: [${a.shape.join(",")}] vs [${b.shape.join(",")}]`
|
|
19716
|
+
);
|
|
19717
|
+
}
|
|
19718
|
+
if (isRuntimeNumber(b)) {
|
|
19719
|
+
const result = new FloatXArray(a.data.length);
|
|
19720
|
+
const sv = b;
|
|
19721
|
+
for (let i = 0; i < result.length; i++) {
|
|
19722
|
+
result[i] = op(a.data[i], sv);
|
|
19723
|
+
}
|
|
19724
|
+
return RTV.tensor(result, a.shape);
|
|
19725
|
+
}
|
|
19726
|
+
}
|
|
19727
|
+
if (isRuntimeTensor(b) && b.data.length > 1 && isRuntimeNumber(a)) {
|
|
19728
|
+
const result = new FloatXArray(b.data.length);
|
|
19729
|
+
const sv = a;
|
|
19730
|
+
for (let i = 0; i < result.length; i++) {
|
|
19731
|
+
result[i] = op(sv, b.data[i]);
|
|
19732
|
+
}
|
|
19733
|
+
return RTV.tensor(result, b.shape);
|
|
19734
|
+
}
|
|
19527
19735
|
const an = asNumeric(a);
|
|
19528
19736
|
const bn = asNumeric(b);
|
|
19529
19737
|
if (an.scalar && bn.scalar) {
|
|
@@ -19567,6 +19775,13 @@ function binaryOp(a, b, op) {
|
|
|
19567
19775
|
);
|
|
19568
19776
|
}
|
|
19569
19777
|
function unaryOp(v, op) {
|
|
19778
|
+
if (isRuntimeTensor(v) && v.data.length > 1) {
|
|
19779
|
+
const result2 = new FloatXArray(v.data.length);
|
|
19780
|
+
for (let i = 0; i < result2.length; i++) {
|
|
19781
|
+
result2[i] = op(v.data[i]);
|
|
19782
|
+
}
|
|
19783
|
+
return RTV.tensor(result2, v.shape);
|
|
19784
|
+
}
|
|
19570
19785
|
const n = asNumeric(v);
|
|
19571
19786
|
if (n.scalar) {
|
|
19572
19787
|
const val = n.isComplex ? n.re : n.value;
|
|
@@ -19645,14 +19860,37 @@ function matMul(a, b) {
|
|
|
19645
19860
|
}
|
|
19646
19861
|
const isComplex2 = a.imag !== void 0 || b.imag !== void 0;
|
|
19647
19862
|
if (!isComplex2) {
|
|
19648
|
-
const
|
|
19863
|
+
const bridge2 = getEffectiveBridge("matmul", "matmul");
|
|
19649
19864
|
const f64A = a.data instanceof Float64Array ? a.data : new Float64Array(a.data);
|
|
19650
19865
|
const f64B = b.data instanceof Float64Array ? b.data : new Float64Array(b.data);
|
|
19651
|
-
const raw =
|
|
19866
|
+
const raw = bridge2.matmul(f64A, aRows, aCols, f64B, bCols);
|
|
19652
19867
|
return unwrap1x1(RTV.tensor(new FloatXArray(raw), [aRows, bCols]));
|
|
19653
19868
|
}
|
|
19654
19869
|
const aIm = a.imag || new FloatXArray(a.data.length);
|
|
19655
19870
|
const bIm = b.imag || new FloatXArray(b.data.length);
|
|
19871
|
+
const bridge = getEffectiveBridge("matmul", "matmulComplex");
|
|
19872
|
+
if (bridge.matmulComplex) {
|
|
19873
|
+
const f64ARe = a.data instanceof Float64Array ? a.data : new Float64Array(a.data);
|
|
19874
|
+
const f64AIm = aIm instanceof Float64Array ? aIm : new Float64Array(aIm);
|
|
19875
|
+
const f64BRe = b.data instanceof Float64Array ? b.data : new Float64Array(b.data);
|
|
19876
|
+
const f64BIm = bIm instanceof Float64Array ? bIm : new Float64Array(bIm);
|
|
19877
|
+
const raw = bridge.matmulComplex(
|
|
19878
|
+
f64ARe,
|
|
19879
|
+
f64AIm,
|
|
19880
|
+
aRows,
|
|
19881
|
+
aCols,
|
|
19882
|
+
f64BRe,
|
|
19883
|
+
f64BIm,
|
|
19884
|
+
bCols
|
|
19885
|
+
);
|
|
19886
|
+
return unwrap1x1(
|
|
19887
|
+
RTV.tensor(
|
|
19888
|
+
new FloatXArray(raw.re),
|
|
19889
|
+
[aRows, bCols],
|
|
19890
|
+
raw.im ? new FloatXArray(raw.im) : void 0
|
|
19891
|
+
)
|
|
19892
|
+
);
|
|
19893
|
+
}
|
|
19656
19894
|
const resultRe = new FloatXArray(aRows * bCols);
|
|
19657
19895
|
const resultIm = new FloatXArray(aRows * bCols);
|
|
19658
19896
|
for (let i = 0; i < aRows; i++) {
|
|
@@ -20148,6 +20386,30 @@ function indexIntoTensor1D(base, idx) {
|
|
|
20148
20386
|
}
|
|
20149
20387
|
function indexIntoTensor2D(base, rowIdx, colIdx) {
|
|
20150
20388
|
const [rows, cols] = tensorSize2D(base);
|
|
20389
|
+
if (isRuntimeNumber(rowIdx) && isColonIndex(colIdx)) {
|
|
20390
|
+
const r = Math.round(rowIdx) - 1;
|
|
20391
|
+
if (r < 0 || r >= rows)
|
|
20392
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
20393
|
+
const resultData2 = new FloatXArray(cols);
|
|
20394
|
+
const resultImag2 = base.imag ? new FloatXArray(cols) : void 0;
|
|
20395
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
20396
|
+
resultData2[ci] = base.data[r + ci * rows];
|
|
20397
|
+
if (resultImag2 && base.imag) resultImag2[ci] = base.imag[r + ci * rows];
|
|
20398
|
+
}
|
|
20399
|
+
return RTV.tensor(resultData2, [1, cols], resultImag2);
|
|
20400
|
+
}
|
|
20401
|
+
if (isColonIndex(rowIdx) && isRuntimeNumber(colIdx)) {
|
|
20402
|
+
const c = Math.round(colIdx) - 1;
|
|
20403
|
+
if (c < 0 || c >= cols)
|
|
20404
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
20405
|
+
const offset = c * rows;
|
|
20406
|
+
const resultData2 = new FloatXArray(rows);
|
|
20407
|
+
for (let ri = 0; ri < rows; ri++) resultData2[ri] = base.data[offset + ri];
|
|
20408
|
+
const resultImag2 = base.imag ? new FloatXArray(rows) : void 0;
|
|
20409
|
+
if (resultImag2 && base.imag)
|
|
20410
|
+
for (let ri = 0; ri < rows; ri++) resultImag2[ri] = base.imag[offset + ri];
|
|
20411
|
+
return RTV.tensor(resultData2, [rows, 1], resultImag2);
|
|
20412
|
+
}
|
|
20151
20413
|
const rowIdxArr = resolveIndex(rowIdx, rows);
|
|
20152
20414
|
const colIdxArr = resolveIndex(colIdx, cols);
|
|
20153
20415
|
const numR = rowIdxArr.length;
|
|
@@ -20486,6 +20748,11 @@ function storeIntoTensor(base, indices, rhs) {
|
|
|
20486
20748
|
return deleteTensorElements(base, indices[0]);
|
|
20487
20749
|
}
|
|
20488
20750
|
if (isRuntimeTensor(rhs) && rhs.data.length === 0 && indices.length === 2) {
|
|
20751
|
+
const nrows = base.shape[0] ?? 1;
|
|
20752
|
+
const ncols = base.shape.length >= 2 ? base.shape[1] : 1;
|
|
20753
|
+
const rowCount = isColonIndex(indices[0]) ? nrows : resolveIndex(indices[0], nrows).length;
|
|
20754
|
+
const colCount = isColonIndex(indices[1]) ? ncols : resolveIndex(indices[1], ncols).length;
|
|
20755
|
+
if (rowCount === 0 || colCount === 0) return base;
|
|
20489
20756
|
return deleteTensorRowsOrCols(base, indices);
|
|
20490
20757
|
}
|
|
20491
20758
|
if (base._rc > 1) {
|
|
@@ -20983,7 +21250,7 @@ function storeIntoTensorND(base, indices, rhs) {
|
|
|
20983
21250
|
}
|
|
20984
21251
|
return base;
|
|
20985
21252
|
}
|
|
20986
|
-
function storeIntoCell(base, indices, rhs) {
|
|
21253
|
+
function storeIntoCell(base, indices, rhs, parenAssign = false) {
|
|
20987
21254
|
if (base._rc > 1) {
|
|
20988
21255
|
base._rc--;
|
|
20989
21256
|
const sharedData = base.data.map((elem) => shareRuntimeValue(elem));
|
|
@@ -20997,14 +21264,20 @@ function storeIntoCell(base, indices, rhs) {
|
|
|
20997
21264
|
c.shape = isColVec ? [newLen, 1] : [1, newLen];
|
|
20998
21265
|
};
|
|
20999
21266
|
if (indices.length === 1) {
|
|
21000
|
-
return storeIntoCell1D(
|
|
21267
|
+
return storeIntoCell1D(
|
|
21268
|
+
base,
|
|
21269
|
+
indices[0],
|
|
21270
|
+
rhs,
|
|
21271
|
+
updateShapeAfterLinearAssign,
|
|
21272
|
+
parenAssign
|
|
21273
|
+
);
|
|
21001
21274
|
}
|
|
21002
21275
|
if (indices.length === 2) {
|
|
21003
|
-
return storeIntoCell2D(base, indices, rhs);
|
|
21276
|
+
return storeIntoCell2D(base, indices, rhs, parenAssign);
|
|
21004
21277
|
}
|
|
21005
21278
|
throw new RuntimeError(`Cannot index-assign into cell`);
|
|
21006
21279
|
}
|
|
21007
|
-
function storeIntoCell1D(base, idx, rhs, updateShape) {
|
|
21280
|
+
function storeIntoCell1D(base, idx, rhs, updateShape, parenAssign = false) {
|
|
21008
21281
|
if (isRuntimeTensor(idx)) {
|
|
21009
21282
|
let positions;
|
|
21010
21283
|
if (idx._isLogical) {
|
|
@@ -21052,11 +21325,11 @@ function storeIntoCell1D(base, idx, rhs, updateShape) {
|
|
|
21052
21325
|
while (base.data.length <= i)
|
|
21053
21326
|
base.data.push(RTV.tensor(new FloatXArray(0), [0, 0]));
|
|
21054
21327
|
}
|
|
21055
|
-
base.data[i] = isRuntimeCell(rhs) && rhs.data.length === 1 ? rhs.data[0] : rhs;
|
|
21328
|
+
base.data[i] = parenAssign && isRuntimeCell(rhs) && rhs.data.length === 1 ? rhs.data[0] : rhs;
|
|
21056
21329
|
updateShape(oldLen);
|
|
21057
21330
|
return base;
|
|
21058
21331
|
}
|
|
21059
|
-
function storeIntoCell2D(base, indices, rhs) {
|
|
21332
|
+
function storeIntoCell2D(base, indices, rhs, parenAssign = false) {
|
|
21060
21333
|
let rows = base.shape[0];
|
|
21061
21334
|
let cols = base.shape.length >= 2 ? base.shape[1] : 1;
|
|
21062
21335
|
const rowIndices = resolveIndex(indices[0], rows, 0);
|
|
@@ -21082,7 +21355,7 @@ function storeIntoCell2D(base, indices, rhs) {
|
|
|
21082
21355
|
const nSelectedRows = rowIndices.length;
|
|
21083
21356
|
const nSelectedCols = colIndices.length;
|
|
21084
21357
|
const totalSelected = nSelectedRows * nSelectedCols;
|
|
21085
|
-
if (isRuntimeCell(rhs)) {
|
|
21358
|
+
if (parenAssign && isRuntimeCell(rhs)) {
|
|
21086
21359
|
if (rhs.data.length !== totalSelected && rhs.data.length !== 1) {
|
|
21087
21360
|
throw new RuntimeError("Subscripted assignment dimension mismatch");
|
|
21088
21361
|
}
|
|
@@ -21100,7 +21373,7 @@ function storeIntoCell2D(base, indices, rhs) {
|
|
|
21100
21373
|
}
|
|
21101
21374
|
return base;
|
|
21102
21375
|
}
|
|
21103
|
-
function storeIntoRTValueIndex(base, indices, rhs) {
|
|
21376
|
+
function storeIntoRTValueIndex(base, indices, rhs, parenAssign = false) {
|
|
21104
21377
|
if (isRuntimeSparseMatrix(base)) {
|
|
21105
21378
|
return storeIntoSparse(base, indices, rhs);
|
|
21106
21379
|
}
|
|
@@ -21121,7 +21394,7 @@ function storeIntoRTValueIndex(base, indices, rhs) {
|
|
|
21121
21394
|
return storeIntoTensor(base, indices, rhs);
|
|
21122
21395
|
}
|
|
21123
21396
|
if (isRuntimeCell(base)) {
|
|
21124
|
-
return storeIntoCell(base, indices, rhs);
|
|
21397
|
+
return storeIntoCell(base, indices, rhs, parenAssign);
|
|
21125
21398
|
}
|
|
21126
21399
|
throw new RuntimeError(`Cannot index-assign into ${kstr(base)}`);
|
|
21127
21400
|
}
|
|
@@ -23031,11 +23304,8 @@ var CommandParser = class extends ExpressionParser {
|
|
|
23031
23304
|
scanPos++;
|
|
23032
23305
|
continue;
|
|
23033
23306
|
}
|
|
23034
|
-
if (ch === "\n" || ch === "\r" || ch === ";" || ch === "%")
|
|
23035
|
-
|
|
23036
|
-
scanPos++;
|
|
23037
|
-
continue;
|
|
23038
|
-
}
|
|
23307
|
+
if (ch === "\n" || ch === "\r" || ch === ";" || ch === "%" || ch === ",")
|
|
23308
|
+
break;
|
|
23039
23309
|
if (ch === "." && scanPos + 2 < this.input.length && this.input[scanPos + 1] === "." && this.input[scanPos + 2] === ".") {
|
|
23040
23310
|
scanPos += 3;
|
|
23041
23311
|
while (scanPos < this.input.length && this.input[scanPos] !== "\n") {
|
|
@@ -25256,6 +25526,13 @@ function complexElemwise(realFn, complexFn, complexOutKind, o) {
|
|
|
25256
25526
|
const isReal = complexOutKind === "Number" || resultIm2.every((x) => x === 0);
|
|
25257
25527
|
return RTV.tensor(resultRe2, v.shape, isReal ? void 0 : resultIm2);
|
|
25258
25528
|
}
|
|
25529
|
+
if (o?.realSafe) {
|
|
25530
|
+
const resultRe2 = new FloatXArray(v.data.length);
|
|
25531
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
25532
|
+
resultRe2[i] = realFn(v.data[i]);
|
|
25533
|
+
}
|
|
25534
|
+
return RTV.tensor(resultRe2, v.shape);
|
|
25535
|
+
}
|
|
25259
25536
|
const resultRe = new FloatXArray(v.data.length);
|
|
25260
25537
|
const resultIm = new FloatXArray(v.data.length);
|
|
25261
25538
|
let hasImag = false;
|
|
@@ -25430,7 +25707,7 @@ function registerMathFunctions() {
|
|
|
25430
25707
|
im: Math.cos(re) * Math.sinh(im)
|
|
25431
25708
|
}),
|
|
25432
25709
|
"ComplexNumber",
|
|
25433
|
-
{ nativeJs: "Math.sin" }
|
|
25710
|
+
{ nativeJs: "Math.sin", realSafe: true }
|
|
25434
25711
|
),
|
|
25435
25712
|
1
|
|
25436
25713
|
);
|
|
@@ -25443,7 +25720,7 @@ function registerMathFunctions() {
|
|
|
25443
25720
|
im: -Math.sin(re) * Math.sinh(im)
|
|
25444
25721
|
}),
|
|
25445
25722
|
"ComplexNumber",
|
|
25446
|
-
{ nativeJs: "Math.cos" }
|
|
25723
|
+
{ nativeJs: "Math.cos", realSafe: true }
|
|
25447
25724
|
),
|
|
25448
25725
|
1
|
|
25449
25726
|
);
|
|
@@ -25456,7 +25733,7 @@ function registerMathFunctions() {
|
|
|
25456
25733
|
return { re: Math.sin(2 * re) / denom, im: Math.sinh(2 * im) / denom };
|
|
25457
25734
|
},
|
|
25458
25735
|
"ComplexNumber",
|
|
25459
|
-
{ nativeJs: "Math.tan" }
|
|
25736
|
+
{ nativeJs: "Math.tan", realSafe: true }
|
|
25460
25737
|
),
|
|
25461
25738
|
1
|
|
25462
25739
|
);
|
|
@@ -25502,7 +25779,7 @@ function registerMathFunctions() {
|
|
|
25502
25779
|
im: Math.cosh(re) * Math.sin(im)
|
|
25503
25780
|
}),
|
|
25504
25781
|
"ComplexNumber",
|
|
25505
|
-
{ nativeJs: "Math.sinh" }
|
|
25782
|
+
{ nativeJs: "Math.sinh", realSafe: true }
|
|
25506
25783
|
),
|
|
25507
25784
|
1
|
|
25508
25785
|
);
|
|
@@ -25515,7 +25792,7 @@ function registerMathFunctions() {
|
|
|
25515
25792
|
im: Math.sinh(re) * Math.sin(im)
|
|
25516
25793
|
}),
|
|
25517
25794
|
"ComplexNumber",
|
|
25518
|
-
{ nativeJs: "Math.cosh" }
|
|
25795
|
+
{ nativeJs: "Math.cosh", realSafe: true }
|
|
25519
25796
|
),
|
|
25520
25797
|
1
|
|
25521
25798
|
);
|
|
@@ -25531,7 +25808,7 @@ function registerMathFunctions() {
|
|
|
25531
25808
|
};
|
|
25532
25809
|
},
|
|
25533
25810
|
"ComplexNumber",
|
|
25534
|
-
{ nativeJs: "Math.tanh" }
|
|
25811
|
+
{ nativeJs: "Math.tanh", realSafe: true }
|
|
25535
25812
|
),
|
|
25536
25813
|
1
|
|
25537
25814
|
);
|
|
@@ -25581,7 +25858,7 @@ function registerMathFunctions() {
|
|
|
25581
25858
|
im: Math.exp(re) * Math.sin(im)
|
|
25582
25859
|
}),
|
|
25583
25860
|
"ComplexNumber",
|
|
25584
|
-
{ nativeJs: "Math.exp" }
|
|
25861
|
+
{ nativeJs: "Math.exp", realSafe: true }
|
|
25585
25862
|
),
|
|
25586
25863
|
1
|
|
25587
25864
|
);
|
|
@@ -25683,7 +25960,7 @@ function registerMathFunctions() {
|
|
|
25683
25960
|
Math.abs,
|
|
25684
25961
|
(re, im) => ({ re: Math.sqrt(re * re + im * im), im: 0 }),
|
|
25685
25962
|
"Number",
|
|
25686
|
-
{ nativeJs: "Math.abs" }
|
|
25963
|
+
{ nativeJs: "Math.abs", realSafe: true }
|
|
25687
25964
|
),
|
|
25688
25965
|
1
|
|
25689
25966
|
);
|
|
@@ -27476,6 +27753,19 @@ function registerArrayManipulationFunctions() {
|
|
|
27476
27753
|
if (n !== data.length) {
|
|
27477
27754
|
throw new RuntimeError("reshape: number of elements must not change");
|
|
27478
27755
|
}
|
|
27756
|
+
if (isRuntimeTensor(v)) {
|
|
27757
|
+
v._rc++;
|
|
27758
|
+
const s = [...shape];
|
|
27759
|
+
while (s.length > 2 && s[s.length - 1] === 1) s.pop();
|
|
27760
|
+
return {
|
|
27761
|
+
kind: "tensor",
|
|
27762
|
+
data,
|
|
27763
|
+
imag,
|
|
27764
|
+
shape: s,
|
|
27765
|
+
_isLogical: v._isLogical,
|
|
27766
|
+
_rc: v._rc
|
|
27767
|
+
};
|
|
27768
|
+
}
|
|
27479
27769
|
return RTV.tensor(
|
|
27480
27770
|
new FloatXArray(data),
|
|
27481
27771
|
shape,
|
|
@@ -29011,6 +29301,27 @@ function dimReduce(v, dim, reduceFn, initialValue, finalizeFn) {
|
|
|
29011
29301
|
const imOut = resultImag && resultImag.some((x) => x !== 0) ? resultImag : void 0;
|
|
29012
29302
|
return RTV.tensor(result, info.resultShape, imOut);
|
|
29013
29303
|
}
|
|
29304
|
+
function dimReduceOmitNaN(v, dim, reduceFn, initialValue, finalizeFn) {
|
|
29305
|
+
if (!isRuntimeTensor(v))
|
|
29306
|
+
throw new RuntimeError("dimReduceOmitNaN: argument must be a tensor");
|
|
29307
|
+
const info = forEachSlice(v.shape, dim, () => {
|
|
29308
|
+
});
|
|
29309
|
+
if (!info) return copyTensor(v);
|
|
29310
|
+
const result = new FloatXArray(info.totalElems);
|
|
29311
|
+
forEachSlice(v.shape, dim, (outIdx, srcIndices) => {
|
|
29312
|
+
let acc = initialValue;
|
|
29313
|
+
let count = 0;
|
|
29314
|
+
for (let k = 0; k < srcIndices.length; k++) {
|
|
29315
|
+
const val = v.data[srcIndices[k]];
|
|
29316
|
+
if (!isNaN(val)) {
|
|
29317
|
+
acc = reduceFn(acc, val);
|
|
29318
|
+
count++;
|
|
29319
|
+
}
|
|
29320
|
+
}
|
|
29321
|
+
result[outIdx] = finalizeFn ? finalizeFn(acc, count) : acc;
|
|
29322
|
+
});
|
|
29323
|
+
return RTV.tensor(result, info.resultShape);
|
|
29324
|
+
}
|
|
29014
29325
|
function sliceDimReduce(v, dim, sliceFn) {
|
|
29015
29326
|
const info = forEachSlice(v.shape, dim, () => {
|
|
29016
29327
|
});
|
|
@@ -29236,23 +29547,44 @@ function preserveTypeCheck(argTypes, nargout) {
|
|
|
29236
29547
|
if (nargout === 2) return { outputTypes: [outType, outType] };
|
|
29237
29548
|
return null;
|
|
29238
29549
|
}
|
|
29239
|
-
function
|
|
29550
|
+
function parseNanFlag(args) {
|
|
29551
|
+
if (args.length >= 2) {
|
|
29552
|
+
const last = args[args.length - 1];
|
|
29553
|
+
if (isRuntimeChar(last)) {
|
|
29554
|
+
const s = toString(last).toLowerCase();
|
|
29555
|
+
if (s === "omitnan") return { args: args.slice(0, -1), omitNaN: true };
|
|
29556
|
+
if (s === "includenan")
|
|
29557
|
+
return { args: args.slice(0, -1), omitNaN: false };
|
|
29558
|
+
}
|
|
29559
|
+
}
|
|
29560
|
+
return { args, omitNaN: false };
|
|
29561
|
+
}
|
|
29562
|
+
function filterNaN(arr) {
|
|
29563
|
+
const out2 = [];
|
|
29564
|
+
for (let i = 0; i < arr.length; i++) {
|
|
29565
|
+
if (!isNaN(arr[i])) out2.push(arr[i]);
|
|
29566
|
+
}
|
|
29567
|
+
return new Float64Array(out2);
|
|
29568
|
+
}
|
|
29569
|
+
function makeReduction(name, kernel, omitNaNKernel) {
|
|
29240
29570
|
return {
|
|
29241
29571
|
check: reductionCheck,
|
|
29242
|
-
apply: (
|
|
29243
|
-
if (
|
|
29572
|
+
apply: (rawArgs) => {
|
|
29573
|
+
if (rawArgs.length < 1)
|
|
29244
29574
|
throw new RuntimeError(`${name} requires at least 1 argument`);
|
|
29575
|
+
const { args, omitNaN } = parseNanFlag(rawArgs);
|
|
29576
|
+
const k = omitNaN && omitNaNKernel ? omitNaNKernel : kernel;
|
|
29245
29577
|
const v = args[0];
|
|
29246
29578
|
if (isRuntimeNumber(v)) return v;
|
|
29247
29579
|
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
29248
29580
|
if (isRuntimeTensor(v)) {
|
|
29249
29581
|
if (args.length >= 2) {
|
|
29250
29582
|
if (isRuntimeChar(args[1]) && toString(args[1]) === "all")
|
|
29251
|
-
return
|
|
29252
|
-
return
|
|
29583
|
+
return k.reduceAll(v);
|
|
29584
|
+
return k.reduceDim(v, Math.round(toNumber(args[1])));
|
|
29253
29585
|
}
|
|
29254
29586
|
const d = firstReduceDim(v.shape);
|
|
29255
|
-
return d === 0 ?
|
|
29587
|
+
return d === 0 ? k.reduceAll(v) : k.reduceDim(v, d);
|
|
29256
29588
|
}
|
|
29257
29589
|
throw new RuntimeError(`${name}: argument must be numeric`);
|
|
29258
29590
|
}
|
|
@@ -29282,6 +29614,42 @@ function sliceKernel(sliceFn) {
|
|
|
29282
29614
|
reduceDim: (v, dim) => sliceDimReduce(v, dim, sliceFn)
|
|
29283
29615
|
};
|
|
29284
29616
|
}
|
|
29617
|
+
function accumKernelOmitNaN(reduceFn, initial, finalizeFn) {
|
|
29618
|
+
return {
|
|
29619
|
+
reduceAll: (v) => {
|
|
29620
|
+
let acc = initial;
|
|
29621
|
+
let count = 0;
|
|
29622
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
29623
|
+
if (!isNaN(v.data[i])) {
|
|
29624
|
+
acc = reduceFn(acc, v.data[i]);
|
|
29625
|
+
count++;
|
|
29626
|
+
}
|
|
29627
|
+
}
|
|
29628
|
+
const re = finalizeFn ? finalizeFn(acc, count) : acc;
|
|
29629
|
+
if (v.imag) {
|
|
29630
|
+
let accIm = initial;
|
|
29631
|
+
let countIm = 0;
|
|
29632
|
+
for (let i = 0; i < v.imag.length; i++) {
|
|
29633
|
+
if (!isNaN(v.imag[i])) {
|
|
29634
|
+
accIm = reduceFn(accIm, v.imag[i]);
|
|
29635
|
+
countIm++;
|
|
29636
|
+
}
|
|
29637
|
+
}
|
|
29638
|
+
const im = finalizeFn ? finalizeFn(accIm, countIm) : accIm;
|
|
29639
|
+
if (im !== 0) return RTV.complex(re, im);
|
|
29640
|
+
}
|
|
29641
|
+
return RTV.num(re);
|
|
29642
|
+
},
|
|
29643
|
+
reduceDim: (v, dim) => dimReduceOmitNaN(v, dim, reduceFn, initial, finalizeFn)
|
|
29644
|
+
};
|
|
29645
|
+
}
|
|
29646
|
+
function sliceKernelOmitNaN(sliceFn) {
|
|
29647
|
+
const filteredFn = (slice) => sliceFn(filterNaN(slice));
|
|
29648
|
+
return {
|
|
29649
|
+
reduceAll: (v) => RTV.num(filteredFn(v.data)),
|
|
29650
|
+
reduceDim: (v, dim) => sliceDimReduce(v, dim, filteredFn)
|
|
29651
|
+
};
|
|
29652
|
+
}
|
|
29285
29653
|
function toNumArray(v, name) {
|
|
29286
29654
|
if (isRuntimeNumber(v)) return [v];
|
|
29287
29655
|
if (isRuntimeTensor(v)) return Array.from(v.data);
|
|
@@ -29293,15 +29661,16 @@ function registerBasicReductions() {
|
|
|
29293
29661
|
register("sum", [
|
|
29294
29662
|
{
|
|
29295
29663
|
check: reductionCheck,
|
|
29296
|
-
apply: (
|
|
29297
|
-
if (
|
|
29664
|
+
apply: (rawArgs) => {
|
|
29665
|
+
if (rawArgs.length < 1)
|
|
29298
29666
|
throw new RuntimeError("sum requires at least 1 argument");
|
|
29667
|
+
const { args, omitNaN } = parseNanFlag(rawArgs);
|
|
29299
29668
|
const v = args[0];
|
|
29300
29669
|
if (isRuntimeSparseMatrix(v)) {
|
|
29301
29670
|
const dim = args.length >= 2 ? Math.round(toNumber(args[1])) : v.m > 1 ? 1 : v.n > 1 ? 2 : 1;
|
|
29302
29671
|
return sparseSum(v, dim);
|
|
29303
29672
|
}
|
|
29304
|
-
const kernel = accumKernel((acc, val) => acc + val, 0);
|
|
29673
|
+
const kernel = omitNaN ? accumKernelOmitNaN((acc, val) => acc + val, 0) : accumKernel((acc, val) => acc + val, 0);
|
|
29305
29674
|
if (isRuntimeNumber(v)) return v;
|
|
29306
29675
|
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
29307
29676
|
if (isRuntimeTensor(v)) {
|
|
@@ -29317,13 +29686,14 @@ function registerBasicReductions() {
|
|
|
29317
29686
|
}
|
|
29318
29687
|
}
|
|
29319
29688
|
]);
|
|
29320
|
-
const prodKernel = accumKernel((acc, val) => acc * val, 1);
|
|
29321
29689
|
register("prod", [
|
|
29322
29690
|
{
|
|
29323
29691
|
check: reductionCheck,
|
|
29324
|
-
apply: (
|
|
29325
|
-
if (
|
|
29692
|
+
apply: (rawArgs) => {
|
|
29693
|
+
if (rawArgs.length < 1)
|
|
29326
29694
|
throw new RuntimeError("prod requires at least 1 argument");
|
|
29695
|
+
const { args: parsedArgs, omitNaN } = parseNanFlag(rawArgs);
|
|
29696
|
+
let args = parsedArgs;
|
|
29327
29697
|
let v = args[0];
|
|
29328
29698
|
if (isRuntimeSparseMatrix(v)) {
|
|
29329
29699
|
v = sparseToDense(v);
|
|
@@ -29337,13 +29707,14 @@ function registerBasicReductions() {
|
|
|
29337
29707
|
args.length >= 2 ? Math.round(toNumber(args[1])) : void 0
|
|
29338
29708
|
);
|
|
29339
29709
|
}
|
|
29710
|
+
const kernel = omitNaN ? accumKernelOmitNaN((acc, val) => acc * val, 1) : accumKernel((acc, val) => acc * val, 1);
|
|
29340
29711
|
if (args.length >= 2) {
|
|
29341
29712
|
if (isRuntimeChar(args[1]) && toString(args[1]) === "all")
|
|
29342
|
-
return
|
|
29343
|
-
return
|
|
29713
|
+
return kernel.reduceAll(v);
|
|
29714
|
+
return kernel.reduceDim(v, Math.round(toNumber(args[1])));
|
|
29344
29715
|
}
|
|
29345
29716
|
const d = firstReduceDim(v.shape);
|
|
29346
|
-
return d === 0 ?
|
|
29717
|
+
return d === 0 ? kernel.reduceAll(v) : kernel.reduceDim(v, d);
|
|
29347
29718
|
}
|
|
29348
29719
|
throw new RuntimeError("prod: argument must be numeric");
|
|
29349
29720
|
}
|
|
@@ -29356,31 +29727,40 @@ function registerBasicReductions() {
|
|
|
29356
29727
|
(acc, val) => acc + val,
|
|
29357
29728
|
0,
|
|
29358
29729
|
(sum, count) => sum / count
|
|
29730
|
+
),
|
|
29731
|
+
accumKernelOmitNaN(
|
|
29732
|
+
(acc, val) => acc + val,
|
|
29733
|
+
0,
|
|
29734
|
+
(sum, count) => count === 0 ? NaN : sum / count
|
|
29359
29735
|
)
|
|
29360
29736
|
)
|
|
29361
29737
|
]);
|
|
29362
|
-
const varianceOf = (slice, w) => {
|
|
29363
|
-
|
|
29738
|
+
const varianceOf = (slice, w, omitNaN) => {
|
|
29739
|
+
let data = slice;
|
|
29740
|
+
if (omitNaN) data = filterNaN(slice);
|
|
29741
|
+
const n = data.length;
|
|
29742
|
+
if (n === 0) return NaN;
|
|
29364
29743
|
if (n <= 1 && w === 0) return 0;
|
|
29365
29744
|
let s = 0;
|
|
29366
|
-
for (let i = 0; i < n; i++) s +=
|
|
29745
|
+
for (let i = 0; i < n; i++) s += data[i];
|
|
29367
29746
|
const m = s / n;
|
|
29368
29747
|
let ss = 0;
|
|
29369
|
-
for (let i = 0; i < n; i++) ss += (
|
|
29748
|
+
for (let i = 0; i < n; i++) ss += (data[i] - m) ** 2;
|
|
29370
29749
|
const denom = w === 1 ? n : n - 1;
|
|
29371
29750
|
return ss / denom;
|
|
29372
29751
|
};
|
|
29373
29752
|
const stdVarApply = (name, transform) => {
|
|
29374
|
-
return (
|
|
29375
|
-
if (
|
|
29753
|
+
return (rawArgs) => {
|
|
29754
|
+
if (rawArgs.length < 1)
|
|
29376
29755
|
throw new RuntimeError(`${name} requires at least 1 argument`);
|
|
29756
|
+
const { args, omitNaN } = parseNanFlag(rawArgs);
|
|
29377
29757
|
const v = args[0];
|
|
29378
29758
|
const w = args.length >= 2 ? toNumber(args[1]) : 0;
|
|
29379
29759
|
const dimArg = args.length >= 3 ? Math.round(toNumber(args[2])) : 0;
|
|
29380
29760
|
if (isRuntimeNumber(v)) return RTV.num(0);
|
|
29381
29761
|
if (isRuntimeTensor(v)) {
|
|
29382
29762
|
const kernel = sliceKernel(
|
|
29383
|
-
(slice) => transform(varianceOf(slice, w))
|
|
29763
|
+
(slice) => transform(varianceOf(slice, w, omitNaN))
|
|
29384
29764
|
);
|
|
29385
29765
|
if (dimArg > 0) return kernel.reduceDim(v, dimArg);
|
|
29386
29766
|
const d = firstReduceDim(v.shape);
|
|
@@ -29408,7 +29788,13 @@ function registerBasicReductions() {
|
|
|
29408
29788
|
if (n % 2 === 1) return sorted[(n - 1) / 2];
|
|
29409
29789
|
return (sorted[n / 2 - 1] + sorted[n / 2]) / 2;
|
|
29410
29790
|
};
|
|
29411
|
-
register("median", [
|
|
29791
|
+
register("median", [
|
|
29792
|
+
makeReduction(
|
|
29793
|
+
"median",
|
|
29794
|
+
sliceKernel(medianOf),
|
|
29795
|
+
sliceKernelOmitNaN(medianOf)
|
|
29796
|
+
)
|
|
29797
|
+
]);
|
|
29412
29798
|
const modeOf = (arr) => {
|
|
29413
29799
|
const counts = /* @__PURE__ */ new Map();
|
|
29414
29800
|
for (let i = 0; i < arr.length; i++) {
|
|
@@ -29423,7 +29809,9 @@ function registerBasicReductions() {
|
|
|
29423
29809
|
}
|
|
29424
29810
|
return bestVal;
|
|
29425
29811
|
};
|
|
29426
|
-
register("mode", [
|
|
29812
|
+
register("mode", [
|
|
29813
|
+
makeReduction("mode", sliceKernel(modeOf), sliceKernelOmitNaN(modeOf))
|
|
29814
|
+
]);
|
|
29427
29815
|
}
|
|
29428
29816
|
|
|
29429
29817
|
// src/numbl-core/builtins/reduction/min-max.ts
|
|
@@ -30051,6 +30439,11 @@ function registerSortUnique() {
|
|
|
30051
30439
|
dim = idx >= 0 ? idx + 1 : 1;
|
|
30052
30440
|
}
|
|
30053
30441
|
const dimIdx = dim - 1;
|
|
30442
|
+
if (!im && !descend && nargout <= 1 && re.length === shape[dimIdx]) {
|
|
30443
|
+
const sorted2 = new FloatXArray(re);
|
|
30444
|
+
sorted2.sort();
|
|
30445
|
+
return RTV.tensor(sorted2, [...shape]);
|
|
30446
|
+
}
|
|
30054
30447
|
if (dimIdx >= shape.length) {
|
|
30055
30448
|
const cp = RTV.tensor(
|
|
30056
30449
|
new FloatXArray(re),
|
|
@@ -30265,10 +30658,10 @@ function registerSortUnique() {
|
|
|
30265
30658
|
}
|
|
30266
30659
|
function uniqueByRows(v, nargout, stable) {
|
|
30267
30660
|
const [rows, cols] = tensorSize2D(v);
|
|
30268
|
-
const rowKey = (r) => {
|
|
30269
|
-
|
|
30270
|
-
for (let c =
|
|
30271
|
-
return
|
|
30661
|
+
const rowKey = cols === 2 ? (r) => v.data[r] + "," + v.data[rows + r] : (r) => {
|
|
30662
|
+
let key = "" + v.data[r];
|
|
30663
|
+
for (let c = 1; c < cols; c++) key += "," + v.data[c * rows + r];
|
|
30664
|
+
return key;
|
|
30272
30665
|
};
|
|
30273
30666
|
const rowHasNaN = (r) => {
|
|
30274
30667
|
for (let c = 0; c < cols; c++) {
|
|
@@ -30321,10 +30714,21 @@ function uniqueByRows(v, nargout, stable) {
|
|
|
30321
30714
|
1
|
|
30322
30715
|
]);
|
|
30323
30716
|
if (!stable) {
|
|
30324
|
-
const
|
|
30717
|
+
const sortedKeyToPos = /* @__PURE__ */ new Map();
|
|
30718
|
+
for (let u = 0; u < nUnique; u++) {
|
|
30719
|
+
sortedKeyToPos.set(rowKey(uniqueRowOrder[u]), u + 1);
|
|
30720
|
+
}
|
|
30325
30721
|
for (let r = 0; r < rows; r++) {
|
|
30326
|
-
|
|
30327
|
-
|
|
30722
|
+
if (rowHasNaN(r)) {
|
|
30723
|
+
for (let u = 0; u < nUnique; u++) {
|
|
30724
|
+
if (uniqueRowOrder[u] === r) {
|
|
30725
|
+
ic[r] = u + 1;
|
|
30726
|
+
break;
|
|
30727
|
+
}
|
|
30728
|
+
}
|
|
30729
|
+
} else {
|
|
30730
|
+
ic[r] = sortedKeyToPos.get(rowKey(r));
|
|
30731
|
+
}
|
|
30328
30732
|
}
|
|
30329
30733
|
}
|
|
30330
30734
|
const icTensor = RTV.tensor(ic, [rows, 1]);
|
|
@@ -32884,51 +33288,61 @@ function registerDet() {
|
|
|
32884
33288
|
register("cross", [
|
|
32885
33289
|
{
|
|
32886
33290
|
check: (argTypes, nargout) => {
|
|
32887
|
-
if (argTypes.length !== 2 || nargout !== 1)
|
|
33291
|
+
if (argTypes.length !== 2 && argTypes.length !== 3 || nargout !== 1)
|
|
33292
|
+
return null;
|
|
32888
33293
|
return { outputTypes: [IType.Unknown] };
|
|
32889
33294
|
},
|
|
32890
33295
|
apply: (args) => {
|
|
32891
|
-
if (args.length
|
|
32892
|
-
throw new RuntimeError("cross requires 2 arguments");
|
|
33296
|
+
if (args.length < 2 || args.length > 3)
|
|
33297
|
+
throw new RuntimeError("cross requires 2 or 3 arguments");
|
|
32893
33298
|
const a = args[0], b = args[1];
|
|
32894
33299
|
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]);
|
|
33300
|
+
throw new RuntimeError("cross: arguments must be vectors or arrays");
|
|
33301
|
+
const shape = a.shape;
|
|
33302
|
+
if (shape.length !== b.shape.length || shape.some((s, i) => s !== b.shape[i]))
|
|
33303
|
+
throw new RuntimeError("cross: A and B must have the same size");
|
|
33304
|
+
let dim;
|
|
33305
|
+
if (args.length === 3) {
|
|
33306
|
+
dim = toNumber(args[2]);
|
|
33307
|
+
if (!Number.isInteger(dim) || dim < 1)
|
|
33308
|
+
throw new RuntimeError("cross: dim must be a positive integer");
|
|
32927
33309
|
} else {
|
|
33310
|
+
dim = shape.indexOf(3) + 1;
|
|
33311
|
+
if (dim === 0)
|
|
33312
|
+
throw new RuntimeError(
|
|
33313
|
+
"cross: A and B must have at least one dimension of length 3"
|
|
33314
|
+
);
|
|
33315
|
+
}
|
|
33316
|
+
const dimIdx = dim - 1;
|
|
33317
|
+
if (dimIdx >= shape.length || shape[dimIdx] !== 3)
|
|
32928
33318
|
throw new RuntimeError(
|
|
32929
|
-
|
|
33319
|
+
`cross: size(A,${dim}) and size(B,${dim}) must be 3`
|
|
32930
33320
|
);
|
|
32931
|
-
|
|
33321
|
+
const totalLen = a.data.length;
|
|
33322
|
+
const result = new FloatXArray(totalLen);
|
|
33323
|
+
const strides = new Array(shape.length);
|
|
33324
|
+
strides[0] = 1;
|
|
33325
|
+
for (let d = 1; d < shape.length; d++)
|
|
33326
|
+
strides[d] = strides[d - 1] * shape[d - 1];
|
|
33327
|
+
const dimStride = strides[dimIdx];
|
|
33328
|
+
const outerStride = dimIdx + 1 < shape.length ? strides[dimIdx + 1] : totalLen;
|
|
33329
|
+
const innerSize = dimStride;
|
|
33330
|
+
const numOuter = totalLen / outerStride;
|
|
33331
|
+
for (let outer = 0; outer < numOuter; outer++) {
|
|
33332
|
+
const blockBase = outer * outerStride;
|
|
33333
|
+
for (let inner = 0; inner < innerSize; inner++) {
|
|
33334
|
+
const base = blockBase + inner;
|
|
33335
|
+
const i0 = base;
|
|
33336
|
+
const i1 = base + dimStride;
|
|
33337
|
+
const i2 = base + 2 * dimStride;
|
|
33338
|
+
const ax = a.data[i0], ay = a.data[i1], az = a.data[i2];
|
|
33339
|
+
const bx = b.data[i0], by = b.data[i1], bz = b.data[i2];
|
|
33340
|
+
result[i0] = ay * bz - az * by;
|
|
33341
|
+
result[i1] = az * bx - ax * bz;
|
|
33342
|
+
result[i2] = ax * by - ay * bx;
|
|
33343
|
+
}
|
|
33344
|
+
}
|
|
33345
|
+
return RTV.tensor(result, [...shape]);
|
|
32932
33346
|
}
|
|
32933
33347
|
}
|
|
32934
33348
|
]);
|
|
@@ -37301,56 +37715,61 @@ function not(v) {
|
|
|
37301
37715
|
return RTV.logical(false);
|
|
37302
37716
|
}
|
|
37303
37717
|
function binop(op, a, b) {
|
|
37304
|
-
|
|
37305
|
-
const bn = asNumber(b);
|
|
37306
|
-
if (an !== null && bn !== null) {
|
|
37718
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
37307
37719
|
switch (op) {
|
|
37308
37720
|
case "Add" /* Add */:
|
|
37309
|
-
return
|
|
37721
|
+
return a + b;
|
|
37310
37722
|
case "Sub" /* Sub */:
|
|
37311
|
-
return
|
|
37723
|
+
return a - b;
|
|
37312
37724
|
case "Mul" /* Mul */:
|
|
37313
|
-
return
|
|
37725
|
+
return a * b;
|
|
37314
37726
|
case "Div" /* Div */:
|
|
37315
|
-
return
|
|
37727
|
+
return a / b;
|
|
37316
37728
|
case "Pow" /* Pow */: {
|
|
37317
|
-
const r = Math.pow(
|
|
37318
|
-
if (isNaN(r) && !isNaN(
|
|
37729
|
+
const r = Math.pow(a, b);
|
|
37730
|
+
if (isNaN(r) && !isNaN(a) && !isNaN(b)) break;
|
|
37319
37731
|
return r;
|
|
37320
37732
|
}
|
|
37321
37733
|
case "ElemMul" /* ElemMul */:
|
|
37322
|
-
return
|
|
37734
|
+
return a * b;
|
|
37323
37735
|
case "ElemDiv" /* ElemDiv */:
|
|
37324
|
-
return
|
|
37736
|
+
return a / b;
|
|
37325
37737
|
case "ElemPow" /* ElemPow */: {
|
|
37326
|
-
const r = Math.pow(
|
|
37327
|
-
if (isNaN(r) && !isNaN(
|
|
37738
|
+
const r = Math.pow(a, b);
|
|
37739
|
+
if (isNaN(r) && !isNaN(a) && !isNaN(b)) break;
|
|
37328
37740
|
return r;
|
|
37329
37741
|
}
|
|
37330
37742
|
case "LeftDiv" /* LeftDiv */:
|
|
37331
|
-
return
|
|
37743
|
+
return b / a;
|
|
37332
37744
|
case "ElemLeftDiv" /* ElemLeftDiv */:
|
|
37333
|
-
return
|
|
37745
|
+
return b / a;
|
|
37334
37746
|
case "Equal" /* Equal */:
|
|
37335
|
-
return RTV.logical(
|
|
37747
|
+
return RTV.logical(a === b);
|
|
37336
37748
|
case "NotEqual" /* NotEqual */:
|
|
37337
|
-
return RTV.logical(
|
|
37749
|
+
return RTV.logical(a !== b);
|
|
37338
37750
|
case "Less" /* Less */:
|
|
37339
|
-
return RTV.logical(
|
|
37751
|
+
return RTV.logical(a < b);
|
|
37340
37752
|
case "LessEqual" /* LessEqual */:
|
|
37341
|
-
return RTV.logical(
|
|
37753
|
+
return RTV.logical(a <= b);
|
|
37342
37754
|
case "Greater" /* Greater */:
|
|
37343
|
-
return RTV.logical(
|
|
37755
|
+
return RTV.logical(a > b);
|
|
37344
37756
|
case "GreaterEqual" /* GreaterEqual */:
|
|
37345
|
-
return RTV.logical(
|
|
37757
|
+
return RTV.logical(a >= b);
|
|
37346
37758
|
case "BitAnd" /* BitAnd */:
|
|
37347
|
-
return RTV.logical(
|
|
37759
|
+
return RTV.logical(a !== 0 && b !== 0);
|
|
37348
37760
|
case "BitOr" /* BitOr */:
|
|
37349
|
-
return RTV.logical(
|
|
37761
|
+
return RTV.logical(a !== 0 || b !== 0);
|
|
37762
|
+
}
|
|
37763
|
+
}
|
|
37764
|
+
if (typeof a !== "object" || typeof b !== "object") {
|
|
37765
|
+
const an = asNumber(a);
|
|
37766
|
+
const bn = asNumber(b);
|
|
37767
|
+
if (an !== null && bn !== null) {
|
|
37768
|
+
return binop(op, an, bn);
|
|
37350
37769
|
}
|
|
37351
37770
|
}
|
|
37352
|
-
const ma = ensureRuntimeValue(a);
|
|
37353
|
-
const mb = ensureRuntimeValue(b);
|
|
37771
|
+
const ma = typeof a === "object" && a !== null && "kind" in a ? a : ensureRuntimeValue(a);
|
|
37772
|
+
const mb = typeof b === "object" && b !== null && "kind" in b ? b : ensureRuntimeValue(b);
|
|
37354
37773
|
let result;
|
|
37355
37774
|
switch (op) {
|
|
37356
37775
|
case "Add" /* Add */:
|
|
@@ -37794,13 +38213,6 @@ function callBuiltin(rt, name, nargout, args) {
|
|
|
37794
38213
|
if (builtin) return builtin(nargout, args);
|
|
37795
38214
|
throw new RuntimeError(`'${name}' is not a builtin function`);
|
|
37796
38215
|
}
|
|
37797
|
-
function callBuiltinSync(rt, name, nargout, args) {
|
|
37798
|
-
const plotResult = dispatchPlotCall(rt, name, args);
|
|
37799
|
-
if (plotResult !== void 0) return plotResult;
|
|
37800
|
-
const builtin = rt.builtins[name];
|
|
37801
|
-
if (builtin) return builtin(nargout, args);
|
|
37802
|
-
throw new RuntimeError(`'${name}' is not a builtin function`);
|
|
37803
|
-
}
|
|
37804
38216
|
function callClassMethod(rt, className, methodName, nargout, args) {
|
|
37805
38217
|
return dispatch(rt, methodName, nargout, args, className);
|
|
37806
38218
|
}
|
|
@@ -38087,6 +38499,22 @@ function structfunImpl(rt, _nargout, args) {
|
|
|
38087
38499
|
return RTV.struct(fields);
|
|
38088
38500
|
}
|
|
38089
38501
|
}
|
|
38502
|
+
var bsxfunOpMap = {
|
|
38503
|
+
plus: mAdd,
|
|
38504
|
+
minus: mSub,
|
|
38505
|
+
times: mElemMul,
|
|
38506
|
+
rdivide: mElemDiv
|
|
38507
|
+
};
|
|
38508
|
+
function resolveKnownBsxfunOp(fnArg) {
|
|
38509
|
+
if (typeof fnArg === "function") {
|
|
38510
|
+
return void 0;
|
|
38511
|
+
}
|
|
38512
|
+
const mv = ensureRuntimeValue(fnArg);
|
|
38513
|
+
if (isRuntimeFunction(mv) && mv.impl === "builtin") {
|
|
38514
|
+
return bsxfunOpMap[mv.name];
|
|
38515
|
+
}
|
|
38516
|
+
return void 0;
|
|
38517
|
+
}
|
|
38090
38518
|
function bsxfunImpl(rt, _nargout, args) {
|
|
38091
38519
|
if (args.length !== 3)
|
|
38092
38520
|
throw new RuntimeError("bsxfun requires exactly 3 arguments");
|
|
@@ -38104,6 +38532,10 @@ function bsxfunImpl(rt, _nargout, args) {
|
|
|
38104
38532
|
);
|
|
38105
38533
|
}
|
|
38106
38534
|
}
|
|
38535
|
+
const knownOp = resolveKnownBsxfunOp(fnArg);
|
|
38536
|
+
if (knownOp) {
|
|
38537
|
+
return knownOp(ensureRuntimeValue(args[1]), ensureRuntimeValue(args[2]));
|
|
38538
|
+
}
|
|
38107
38539
|
const rawA = ensureRuntimeValue(args[1]);
|
|
38108
38540
|
const rawB = ensureRuntimeValue(args[2]);
|
|
38109
38541
|
const a = coerceToTensor2(rawA, "bsxfun", "first");
|
|
@@ -38367,6 +38799,67 @@ function endResolver(mv, numIndices) {
|
|
|
38367
38799
|
};
|
|
38368
38800
|
}
|
|
38369
38801
|
function index(rt, base, indices, nargout = 1, skipSubsref = false) {
|
|
38802
|
+
if (typeof base === "object" && base !== null && base.kind === "tensor") {
|
|
38803
|
+
const t = base;
|
|
38804
|
+
const nIdx = indices.length;
|
|
38805
|
+
if (nIdx === 1) {
|
|
38806
|
+
const idx = indices[0];
|
|
38807
|
+
if (typeof idx === "number") {
|
|
38808
|
+
const i = Math.round(idx) - 1;
|
|
38809
|
+
if (i < 0 || i >= t.data.length)
|
|
38810
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
38811
|
+
if (t.imag !== void 0) {
|
|
38812
|
+
const im = t.imag[i];
|
|
38813
|
+
return im === 0 ? t.data[i] : RTV.complex(t.data[i], im);
|
|
38814
|
+
}
|
|
38815
|
+
return t.data[i];
|
|
38816
|
+
}
|
|
38817
|
+
} else if (nIdx === 2) {
|
|
38818
|
+
const ri = indices[0];
|
|
38819
|
+
const ci = indices[1];
|
|
38820
|
+
if (typeof ri === "number" && typeof ci === "number") {
|
|
38821
|
+
const s = t.shape;
|
|
38822
|
+
const rows = s.length === 0 ? 1 : s.length === 1 ? 1 : s[0];
|
|
38823
|
+
const cols = s.length === 0 ? 1 : s.length === 1 ? s[0] : s[1];
|
|
38824
|
+
const r = Math.round(ri) - 1;
|
|
38825
|
+
const c = Math.round(ci) - 1;
|
|
38826
|
+
if (r < 0 || r >= rows || c < 0 || c >= cols)
|
|
38827
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
38828
|
+
const lin = c * rows + r;
|
|
38829
|
+
if (t.imag !== void 0) {
|
|
38830
|
+
const im = t.imag[lin];
|
|
38831
|
+
return im === 0 ? t.data[lin] : RTV.complex(t.data[lin], im);
|
|
38832
|
+
}
|
|
38833
|
+
return t.data[lin];
|
|
38834
|
+
}
|
|
38835
|
+
} else if (nIdx >= 3) {
|
|
38836
|
+
let allNumeric = true;
|
|
38837
|
+
for (let k = 0; k < nIdx; k++) {
|
|
38838
|
+
if (typeof indices[k] !== "number") {
|
|
38839
|
+
allNumeric = false;
|
|
38840
|
+
break;
|
|
38841
|
+
}
|
|
38842
|
+
}
|
|
38843
|
+
if (allNumeric) {
|
|
38844
|
+
const s = t.shape;
|
|
38845
|
+
let lin = 0;
|
|
38846
|
+
let stride = 1;
|
|
38847
|
+
for (let k = 0; k < nIdx; k++) {
|
|
38848
|
+
const dimSize = k < s.length ? s[k] : 1;
|
|
38849
|
+
const sub = Math.round(indices[k]) - 1;
|
|
38850
|
+
if (sub < 0 || sub >= dimSize)
|
|
38851
|
+
throw new RuntimeError("Index exceeds array bounds");
|
|
38852
|
+
lin += sub * stride;
|
|
38853
|
+
stride *= dimSize;
|
|
38854
|
+
}
|
|
38855
|
+
if (t.imag !== void 0) {
|
|
38856
|
+
const im = t.imag[lin];
|
|
38857
|
+
return im === 0 ? t.data[lin] : RTV.complex(t.data[lin], im);
|
|
38858
|
+
}
|
|
38859
|
+
return t.data[lin];
|
|
38860
|
+
}
|
|
38861
|
+
}
|
|
38862
|
+
}
|
|
38370
38863
|
if (typeof base === "function") {
|
|
38371
38864
|
return base(...indices);
|
|
38372
38865
|
}
|
|
@@ -38451,6 +38944,13 @@ function resolveIndicesForClassInstance(rt, mv, base, indices) {
|
|
|
38451
38944
|
});
|
|
38452
38945
|
}
|
|
38453
38946
|
function indexCell(rt, base, indices) {
|
|
38947
|
+
if (indices.length === 1 && typeof indices[0] === "number" && typeof base === "object" && base !== null && base.kind === "cell") {
|
|
38948
|
+
const cell = base;
|
|
38949
|
+
const i = Math.round(indices[0]) - 1;
|
|
38950
|
+
if (i < 0 || i >= cell.data.length)
|
|
38951
|
+
throw new RuntimeError("Cell index exceeds bounds");
|
|
38952
|
+
return cell.data[i];
|
|
38953
|
+
}
|
|
38454
38954
|
const mv = ensureRuntimeValue(base);
|
|
38455
38955
|
if (isRuntimeClassInstance(mv)) {
|
|
38456
38956
|
const subsrefFn = rt.cachedResolveClassMethod(mv.className, "subsref");
|
|
@@ -38589,7 +39089,7 @@ function indexStore(rt, base, indices, rhs, skipSubsasgn = false) {
|
|
|
38589
39089
|
if (isRuntimeCell(mv)) {
|
|
38590
39090
|
const idxMvals2 = resolveIndices(indices, endResolver(mv, indices.length));
|
|
38591
39091
|
const rhsMv2 = ensureRuntimeValue(rhs);
|
|
38592
|
-
return storeIntoRTValueIndex(mv, idxMvals2, rhsMv2);
|
|
39092
|
+
return storeIntoRTValueIndex(mv, idxMvals2, rhsMv2, true);
|
|
38593
39093
|
}
|
|
38594
39094
|
if (isRuntimeStruct(mv)) {
|
|
38595
39095
|
return ensureRuntimeValue(rhs);
|
|
@@ -38802,7 +39302,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
38802
39302
|
if (fn) {
|
|
38803
39303
|
return fn(nargout, args.slice(1));
|
|
38804
39304
|
}
|
|
38805
|
-
return rt.
|
|
39305
|
+
return rt.callBuiltin(fnName, nargout, args.slice(1));
|
|
38806
39306
|
};
|
|
38807
39307
|
const requireFileIO = () => {
|
|
38808
39308
|
if (!rt.fileIO)
|
|
@@ -40148,15 +40648,23 @@ var Runtime = class _Runtime {
|
|
|
40148
40648
|
// ── Builtin initialization ──────────────────────────────────────────
|
|
40149
40649
|
initBuiltins() {
|
|
40150
40650
|
for (const name of getAllBuiltinNames()) {
|
|
40651
|
+
const builtin = getBuiltin(name);
|
|
40652
|
+
const singleBranch = builtin.length === 1 ? builtin[0] : null;
|
|
40151
40653
|
this.builtins[name] = (nargout, args) => {
|
|
40152
|
-
const builtin = getBuiltin(name);
|
|
40153
40654
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
40154
|
-
|
|
40155
|
-
|
|
40156
|
-
|
|
40157
|
-
|
|
40158
|
-
|
|
40159
|
-
|
|
40655
|
+
let branch;
|
|
40656
|
+
if (singleBranch) {
|
|
40657
|
+
branch = singleBranch;
|
|
40658
|
+
} else {
|
|
40659
|
+
const argItemTypes = margs.map(
|
|
40660
|
+
(arg) => getItemTypeFromRuntimeValue(arg)
|
|
40661
|
+
);
|
|
40662
|
+
branch = builtin[0];
|
|
40663
|
+
for (let i = 0; i < builtin.length; i++) {
|
|
40664
|
+
if (builtin[i].check(argItemTypes, nargout)) {
|
|
40665
|
+
branch = builtin[i];
|
|
40666
|
+
break;
|
|
40667
|
+
}
|
|
40160
40668
|
}
|
|
40161
40669
|
}
|
|
40162
40670
|
if (this.profilingEnabled) {
|
|
@@ -40788,9 +41296,6 @@ var Runtime = class _Runtime {
|
|
|
40788
41296
|
}
|
|
40789
41297
|
return binop(op, a, b);
|
|
40790
41298
|
}
|
|
40791
|
-
binopSync(op, a, b) {
|
|
40792
|
-
return binop(op, a, b);
|
|
40793
|
-
}
|
|
40794
41299
|
range(start, step, end) {
|
|
40795
41300
|
return range(start, step, end);
|
|
40796
41301
|
}
|
|
@@ -40910,9 +41415,6 @@ var Runtime = class _Runtime {
|
|
|
40910
41415
|
callBuiltin(name, nargout, args) {
|
|
40911
41416
|
return callBuiltin(this, name, nargout, args);
|
|
40912
41417
|
}
|
|
40913
|
-
callBuiltinSync(name, nargout, args) {
|
|
40914
|
-
return callBuiltinSync(this, name, nargout, args);
|
|
40915
|
-
}
|
|
40916
41418
|
callClassMethod(className, methodName, nargout, args) {
|
|
40917
41419
|
return callClassMethod(this, className, methodName, nargout, args);
|
|
40918
41420
|
}
|
|
@@ -44052,9 +44554,6 @@ function genBinary(cg, kind) {
|
|
|
44052
44554
|
break;
|
|
44053
44555
|
}
|
|
44054
44556
|
}
|
|
44055
|
-
if (leftType.kind !== "Unknown" && rightType.kind !== "Unknown" && leftType.kind !== "ClassInstance" && rightType.kind !== "ClassInstance") {
|
|
44056
|
-
return `$rt.binopSync(${JSON.stringify(kind.op)}, ${left}, ${right})`;
|
|
44057
|
-
}
|
|
44058
44557
|
return `$rt.binop(${JSON.stringify(kind.op)}, ${left}, ${right})`;
|
|
44059
44558
|
}
|
|
44060
44559
|
function genTensor(cg, kind) {
|
|
@@ -44579,8 +45078,6 @@ function genClassInstantiation(cg, kind) {
|
|
|
44579
45078
|
return createExpr;
|
|
44580
45079
|
}
|
|
44581
45080
|
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
45081
|
abs: "Math.abs",
|
|
44585
45082
|
floor: "Math.floor",
|
|
44586
45083
|
ceil: "Math.ceil",
|
|
@@ -44594,6 +45091,14 @@ var NATIVE_MATH_1 = {
|
|
|
44594
45091
|
log10: "Math.log10",
|
|
44595
45092
|
sign: "Math.sign"
|
|
44596
45093
|
};
|
|
45094
|
+
var GUARDED_MATH_1 = {
|
|
45095
|
+
sqrt: { fn: "Math.sqrt", guard: "$x >= 0" },
|
|
45096
|
+
log: { fn: "Math.log", guard: "$x > 0" },
|
|
45097
|
+
asin: { fn: "Math.asin", guard: "$x >= -1 && $x <= 1" },
|
|
45098
|
+
acos: { fn: "Math.acos", guard: "$x >= -1 && $x <= 1" },
|
|
45099
|
+
acosh: { fn: "Math.acosh", guard: "$x >= 1" },
|
|
45100
|
+
atanh: { fn: "Math.atanh", guard: "$x > -1 && $x < 1" }
|
|
45101
|
+
};
|
|
44597
45102
|
var NATIVE_MATH_2 = {
|
|
44598
45103
|
// Note: max/min are NOT here because Math.max/Math.min propagate NaN,
|
|
44599
45104
|
// but max/min ignore NaN (returning the non-NaN value).
|
|
@@ -44605,6 +45110,15 @@ function tryNativeMathCodegen(cg, name, nargout, irArgs, jsArgs) {
|
|
|
44605
45110
|
if (jsArgs.length === 1 && itemTypeForExprKind(irArgs[0].kind, cg.typeEnv).kind === "Number") {
|
|
44606
45111
|
const fn = NATIVE_MATH_1[name];
|
|
44607
45112
|
if (fn) return `${fn}(${jsArgs[0]})`;
|
|
45113
|
+
const guarded = GUARDED_MATH_1[name];
|
|
45114
|
+
if (guarded) {
|
|
45115
|
+
const arg = jsArgs[0];
|
|
45116
|
+
const tmp = cg.freshTemp("$gm");
|
|
45117
|
+
cg.emit(`var ${tmp};`);
|
|
45118
|
+
const guard = guarded.guard.replace(/\$x/g, tmp);
|
|
45119
|
+
const fallback = `${cg.useBuiltin(name)}(1, [${tmp}])`;
|
|
45120
|
+
return `(${tmp} = ${arg}, ${guard} ? ${guarded.fn}(${tmp}) : ${fallback})`;
|
|
45121
|
+
}
|
|
44608
45122
|
}
|
|
44609
45123
|
if (jsArgs.length === 2 && itemTypeForExprKind(irArgs[0].kind, cg.typeEnv).kind === "Number" && itemTypeForExprKind(irArgs[1].kind, cg.typeEnv).kind === "Number") {
|
|
44610
45124
|
const fn = NATIVE_MATH_2[name];
|
|
@@ -46318,6 +46832,21 @@ function instantiateWasm(wasmData) {
|
|
|
46318
46832
|
}
|
|
46319
46833
|
return new WebAssembly.Instance(wasmModule, importObject);
|
|
46320
46834
|
}
|
|
46835
|
+
function resolveBindings(file, directives, getWasmInstance, nativeBridge2) {
|
|
46836
|
+
const wasmInstance = directives.wasm ? getWasmInstance(directives.wasm) : void 0;
|
|
46837
|
+
let nativeLib;
|
|
46838
|
+
if (directives.native && nativeBridge2) {
|
|
46839
|
+
const libFile = nativeLibFilename(directives.native);
|
|
46840
|
+
const dir = file.name.substring(0, file.name.lastIndexOf("/") + 1);
|
|
46841
|
+
const libPath = dir + libFile;
|
|
46842
|
+
try {
|
|
46843
|
+
nativeLib = nativeBridge2.load(libPath);
|
|
46844
|
+
} catch {
|
|
46845
|
+
}
|
|
46846
|
+
}
|
|
46847
|
+
return { wasmInstance, nativeLib };
|
|
46848
|
+
}
|
|
46849
|
+
var LOADING = /* @__PURE__ */ Symbol("loading");
|
|
46321
46850
|
function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
46322
46851
|
const result = /* @__PURE__ */ new Map();
|
|
46323
46852
|
const wasmMap = wasmFiles ? buildWasmMap(wasmFiles) : /* @__PURE__ */ new Map();
|
|
@@ -46331,7 +46860,68 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46331
46860
|
wasmInstanceCache.set(name, instance);
|
|
46332
46861
|
return instance;
|
|
46333
46862
|
}
|
|
46863
|
+
const libraryFiles = /* @__PURE__ */ new Map();
|
|
46864
|
+
const functionFiles = [];
|
|
46334
46865
|
for (const file of jsFiles) {
|
|
46866
|
+
const base = file.name.split("/").pop();
|
|
46867
|
+
if (base.startsWith("_")) {
|
|
46868
|
+
const libName = base.replace(/\.js$/, "");
|
|
46869
|
+
libraryFiles.set(libName, file);
|
|
46870
|
+
} else {
|
|
46871
|
+
functionFiles.push(file);
|
|
46872
|
+
}
|
|
46873
|
+
}
|
|
46874
|
+
const libCache = /* @__PURE__ */ new Map();
|
|
46875
|
+
function importJS(name) {
|
|
46876
|
+
const cached = libCache.get(name);
|
|
46877
|
+
if (cached === LOADING) {
|
|
46878
|
+
throw new RuntimeError(`Circular dependency detected: ${name}.js`);
|
|
46879
|
+
}
|
|
46880
|
+
if (libCache.has(name)) return cached;
|
|
46881
|
+
const libFile = libraryFiles.get(name);
|
|
46882
|
+
if (!libFile) {
|
|
46883
|
+
throw new RuntimeError(
|
|
46884
|
+
`importJS: library '${name}.js' not found in workspace`
|
|
46885
|
+
);
|
|
46886
|
+
}
|
|
46887
|
+
libCache.set(name, LOADING);
|
|
46888
|
+
const directives = parseDirectives(libFile.source);
|
|
46889
|
+
const { wasmInstance, nativeLib } = resolveBindings(
|
|
46890
|
+
libFile,
|
|
46891
|
+
directives,
|
|
46892
|
+
getWasmInstance,
|
|
46893
|
+
nativeBridge2
|
|
46894
|
+
);
|
|
46895
|
+
const dummyRegister = () => {
|
|
46896
|
+
throw new RuntimeError(
|
|
46897
|
+
`Library file '${name}.js' must not call register(). Use return {...} to export values.`
|
|
46898
|
+
);
|
|
46899
|
+
};
|
|
46900
|
+
const factory = new Function(
|
|
46901
|
+
"RTV",
|
|
46902
|
+
"RuntimeError",
|
|
46903
|
+
"FloatXArray",
|
|
46904
|
+
"IType",
|
|
46905
|
+
"register",
|
|
46906
|
+
"wasm",
|
|
46907
|
+
"native",
|
|
46908
|
+
"importJS",
|
|
46909
|
+
libFile.source
|
|
46910
|
+
);
|
|
46911
|
+
const exports = factory(
|
|
46912
|
+
RTV,
|
|
46913
|
+
RuntimeError,
|
|
46914
|
+
FloatXArray,
|
|
46915
|
+
IType,
|
|
46916
|
+
dummyRegister,
|
|
46917
|
+
wasmInstance,
|
|
46918
|
+
nativeLib,
|
|
46919
|
+
importJS
|
|
46920
|
+
);
|
|
46921
|
+
libCache.set(name, exports);
|
|
46922
|
+
return exports;
|
|
46923
|
+
}
|
|
46924
|
+
for (const file of functionFiles) {
|
|
46335
46925
|
const funcName = funcNameFromFile(file.name);
|
|
46336
46926
|
try {
|
|
46337
46927
|
const branches = [];
|
|
@@ -46345,17 +46935,12 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46345
46935
|
});
|
|
46346
46936
|
};
|
|
46347
46937
|
const directives = parseDirectives(file.source);
|
|
46348
|
-
const wasmInstance
|
|
46349
|
-
|
|
46350
|
-
|
|
46351
|
-
|
|
46352
|
-
|
|
46353
|
-
|
|
46354
|
-
try {
|
|
46355
|
-
nativeLib = nativeBridge2.load(libPath);
|
|
46356
|
-
} catch {
|
|
46357
|
-
}
|
|
46358
|
-
}
|
|
46938
|
+
const { wasmInstance, nativeLib } = resolveBindings(
|
|
46939
|
+
file,
|
|
46940
|
+
directives,
|
|
46941
|
+
getWasmInstance,
|
|
46942
|
+
nativeBridge2
|
|
46943
|
+
);
|
|
46359
46944
|
const factory = new Function(
|
|
46360
46945
|
"RTV",
|
|
46361
46946
|
"RuntimeError",
|
|
@@ -46364,6 +46949,7 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46364
46949
|
"register",
|
|
46365
46950
|
"wasm",
|
|
46366
46951
|
"native",
|
|
46952
|
+
"importJS",
|
|
46367
46953
|
file.source
|
|
46368
46954
|
);
|
|
46369
46955
|
factory(
|
|
@@ -46373,7 +46959,8 @@ function loadJsUserFunctions(jsFiles, wasmFiles, nativeBridge2) {
|
|
|
46373
46959
|
IType,
|
|
46374
46960
|
registerFn,
|
|
46375
46961
|
wasmInstance,
|
|
46376
|
-
nativeLib
|
|
46962
|
+
nativeLib,
|
|
46963
|
+
importJS
|
|
46377
46964
|
);
|
|
46378
46965
|
if (branches.length === 0) {
|
|
46379
46966
|
throw new Error(
|
|
@@ -47189,7 +47776,7 @@ Call stack (most recent call first):`;
|
|
|
47189
47776
|
}
|
|
47190
47777
|
|
|
47191
47778
|
// src/numbl-core/version.ts
|
|
47192
|
-
var NUMBL_VERSION = "0.0.
|
|
47779
|
+
var NUMBL_VERSION = "0.0.23";
|
|
47193
47780
|
|
|
47194
47781
|
// src/cli-repl.ts
|
|
47195
47782
|
import { createInterface } from "readline";
|
|
@@ -47820,16 +48407,26 @@ var NodeFileIOAdapter = class {
|
|
|
47820
48407
|
var __filename = fileURLToPath2(import.meta.url);
|
|
47821
48408
|
var __dirname = dirname3(__filename);
|
|
47822
48409
|
var packageDir2 = join6(__dirname, "..");
|
|
47823
|
-
var addonPath = join6(packageDir2, "build", "Release", "
|
|
48410
|
+
var addonPath = join6(packageDir2, "build", "Release", "numbl_addon.node");
|
|
47824
48411
|
var nativeAddonLoaded = false;
|
|
47825
48412
|
if (!process.env.NUMBL_NO_NATIVE) {
|
|
47826
48413
|
try {
|
|
47827
48414
|
const req = createRequire(import.meta.url);
|
|
47828
48415
|
const addon = req(addonPath);
|
|
47829
|
-
|
|
47830
|
-
|
|
47831
|
-
|
|
48416
|
+
const addonVer = typeof addon.addonVersion === "function" ? addon.addonVersion() : 0;
|
|
48417
|
+
if (addonVer !== NATIVE_ADDON_EXPECTED_VERSION) {
|
|
48418
|
+
console.error(
|
|
48419
|
+
`Warning: native addon version mismatch (got ${addonVer}, expected ${NATIVE_ADDON_EXPECTED_VERSION}). Run "npx numbl build-addon" to rebuild. Using JS fallbacks.`
|
|
48420
|
+
);
|
|
48421
|
+
} else {
|
|
48422
|
+
setLapackBridge(addon);
|
|
48423
|
+
setLapackBridge(addon);
|
|
48424
|
+
nativeAddonLoaded = true;
|
|
48425
|
+
}
|
|
47832
48426
|
} catch {
|
|
48427
|
+
console.error(
|
|
48428
|
+
`Warning: native addon not found. Run "npx numbl build-addon" to build it. Using JS fallbacks.`
|
|
48429
|
+
);
|
|
47833
48430
|
}
|
|
47834
48431
|
}
|
|
47835
48432
|
var nativeBridge;
|