numbl 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-browser/browser.js +1 -1
- package/dist-browser/numbl-core/fileIOAdapter.d.ts +4 -0
- package/dist-browser/numbl-core/native/lapack-bridge.d.ts +1 -1
- package/dist-browser/numbl-core/native/wasm-lapack-bridge.d.ts +114 -0
- package/dist-browser/numbl-core/native/wasm-lapack-browser.d.ts +34 -0
- package/dist-browser/numbl-core/runtime/datetime-format.d.ts +10 -0
- package/dist-browser/numbl-core/runtime/display.d.ts +5 -1
- package/dist-browser/numbl-core/runtime/index.d.ts +1 -1
- package/dist-browser/numbl-core/version.d.ts +1 -1
- package/dist-browser/vfs/BrowserFileIOAdapter.d.ts +1 -0
- package/dist-cli/cli.js +434 -131
- package/dist-lib/cli-fileio.d.ts +62 -0
- package/dist-lib/cli-scan.d.ts +6 -0
- package/dist-lib/cli-system.d.ts +13 -0
- package/dist-lib/lib.js +368 -73
- package/dist-lib/node.d.ts +30 -0
- package/dist-lib/node.js +829 -0
- package/dist-lib/numbl-core/fileIOAdapter.d.ts +4 -0
- package/dist-lib/numbl-core/native/lapack-bridge.d.ts +1 -1
- package/dist-lib/numbl-core/native/wasm-lapack-bridge.d.ts +114 -0
- package/dist-lib/numbl-core/native/wasm-lapack-browser.d.ts +34 -0
- package/dist-lib/numbl-core/runtime/datetime-format.d.ts +10 -0
- package/dist-lib/numbl-core/runtime/display.d.ts +5 -1
- package/dist-lib/numbl-core/runtime/index.d.ts +1 -1
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/dist-lib/vfs/BrowserFileIOAdapter.d.ts +1 -0
- package/dist-site-viewer/assets/{index-fhKbvuOM.js → index-C2ItFYSf.js} +322 -322
- package/dist-site-viewer/assets/{numbl-worker-BFP9xj5e.js → numbl-worker-CtfdLxJh.js} +114 -102
- package/dist-site-viewer/index.html +1 -1
- package/package.json +6 -2
package/dist-cli/cli.js
CHANGED
|
@@ -312,7 +312,7 @@ import {
|
|
|
312
312
|
delimiter,
|
|
313
313
|
dirname as dirname3,
|
|
314
314
|
join as join7,
|
|
315
|
-
relative,
|
|
315
|
+
relative as relative2,
|
|
316
316
|
resolve as resolve2,
|
|
317
317
|
sep
|
|
318
318
|
} from "path";
|
|
@@ -21701,6 +21701,114 @@ var valuesAreEqual = (a, b) => {
|
|
|
21701
21701
|
}
|
|
21702
21702
|
};
|
|
21703
21703
|
|
|
21704
|
+
// src/numbl-core/runtime/datetime-format.ts
|
|
21705
|
+
var MONTH_ABBR = [
|
|
21706
|
+
"Jan",
|
|
21707
|
+
"Feb",
|
|
21708
|
+
"Mar",
|
|
21709
|
+
"Apr",
|
|
21710
|
+
"May",
|
|
21711
|
+
"Jun",
|
|
21712
|
+
"Jul",
|
|
21713
|
+
"Aug",
|
|
21714
|
+
"Sep",
|
|
21715
|
+
"Oct",
|
|
21716
|
+
"Nov",
|
|
21717
|
+
"Dec"
|
|
21718
|
+
];
|
|
21719
|
+
var MONTH_FULL = [
|
|
21720
|
+
"January",
|
|
21721
|
+
"February",
|
|
21722
|
+
"March",
|
|
21723
|
+
"April",
|
|
21724
|
+
"May",
|
|
21725
|
+
"June",
|
|
21726
|
+
"July",
|
|
21727
|
+
"August",
|
|
21728
|
+
"September",
|
|
21729
|
+
"October",
|
|
21730
|
+
"November",
|
|
21731
|
+
"December"
|
|
21732
|
+
];
|
|
21733
|
+
function pad(n, width) {
|
|
21734
|
+
return String(n).padStart(width, "0");
|
|
21735
|
+
}
|
|
21736
|
+
function formatDatetimePattern(pattern, year, month, day, hour, minute, second) {
|
|
21737
|
+
const wholeSec = Math.floor(second);
|
|
21738
|
+
const frac = second - wholeSec;
|
|
21739
|
+
const monthIdx = Math.max(0, Math.min(11, Math.floor(month) - 1));
|
|
21740
|
+
const formatToken = (c, n) => {
|
|
21741
|
+
switch (c) {
|
|
21742
|
+
case "y":
|
|
21743
|
+
case "u":
|
|
21744
|
+
if (n === 2) return pad(Math.floor(year) % 100, 2);
|
|
21745
|
+
return pad(Math.floor(year), n);
|
|
21746
|
+
case "M":
|
|
21747
|
+
if (n === 1) return String(Math.floor(month));
|
|
21748
|
+
if (n === 2) return pad(Math.floor(month), 2);
|
|
21749
|
+
if (n === 3) return MONTH_ABBR[monthIdx];
|
|
21750
|
+
return MONTH_FULL[monthIdx];
|
|
21751
|
+
case "d":
|
|
21752
|
+
return pad(Math.floor(day), n);
|
|
21753
|
+
case "H":
|
|
21754
|
+
return pad(Math.floor(hour), n);
|
|
21755
|
+
case "h":
|
|
21756
|
+
return pad(Math.floor(hour) % 12 || 12, n);
|
|
21757
|
+
case "m":
|
|
21758
|
+
return pad(Math.floor(minute), n);
|
|
21759
|
+
case "s":
|
|
21760
|
+
return pad(wholeSec, n);
|
|
21761
|
+
case "S":
|
|
21762
|
+
return pad(Math.floor(frac * Math.pow(10, n)), n);
|
|
21763
|
+
case "a":
|
|
21764
|
+
return hour < 12 ? "AM" : "PM";
|
|
21765
|
+
default:
|
|
21766
|
+
throw new RuntimeError(
|
|
21767
|
+
`datetime: unsupported format token '${c.repeat(n)}' in '${pattern}'`
|
|
21768
|
+
);
|
|
21769
|
+
}
|
|
21770
|
+
};
|
|
21771
|
+
let out = "";
|
|
21772
|
+
let i = 0;
|
|
21773
|
+
while (i < pattern.length) {
|
|
21774
|
+
const c = pattern[i];
|
|
21775
|
+
if (c === "'") {
|
|
21776
|
+
i++;
|
|
21777
|
+
let lit = "";
|
|
21778
|
+
let closed = false;
|
|
21779
|
+
while (i < pattern.length) {
|
|
21780
|
+
if (pattern[i] === "'") {
|
|
21781
|
+
if (pattern[i + 1] === "'") {
|
|
21782
|
+
lit += "'";
|
|
21783
|
+
i += 2;
|
|
21784
|
+
continue;
|
|
21785
|
+
}
|
|
21786
|
+
i++;
|
|
21787
|
+
closed = true;
|
|
21788
|
+
break;
|
|
21789
|
+
}
|
|
21790
|
+
lit += pattern[i++];
|
|
21791
|
+
}
|
|
21792
|
+
if (!closed && lit !== "")
|
|
21793
|
+
throw new RuntimeError(
|
|
21794
|
+
`datetime: unterminated quoted literal in format '${pattern}'`
|
|
21795
|
+
);
|
|
21796
|
+
out += lit === "" ? "'" : lit;
|
|
21797
|
+
continue;
|
|
21798
|
+
}
|
|
21799
|
+
if (!/[a-zA-Z]/.test(c)) {
|
|
21800
|
+
out += c;
|
|
21801
|
+
i++;
|
|
21802
|
+
continue;
|
|
21803
|
+
}
|
|
21804
|
+
let j = i;
|
|
21805
|
+
while (j < pattern.length && pattern[j] === c) j++;
|
|
21806
|
+
out += formatToken(c, j - i);
|
|
21807
|
+
i = j;
|
|
21808
|
+
}
|
|
21809
|
+
return out;
|
|
21810
|
+
}
|
|
21811
|
+
|
|
21704
21812
|
// src/numbl-core/runtime/display.ts
|
|
21705
21813
|
function displayValue(v) {
|
|
21706
21814
|
if (isRuntimeNumber(v)) {
|
|
@@ -21975,6 +22083,13 @@ function formatDatetimeOrDuration(v) {
|
|
|
21975
22083
|
if (v.className === "duration") return formatDurationInstance(v);
|
|
21976
22084
|
return null;
|
|
21977
22085
|
}
|
|
22086
|
+
function textField(v, name) {
|
|
22087
|
+
const fv = v.fields.get(name);
|
|
22088
|
+
if (fv === void 0) return null;
|
|
22089
|
+
if (isRuntimeString(fv)) return fv;
|
|
22090
|
+
if (isRuntimeChar(fv)) return fv.value;
|
|
22091
|
+
return null;
|
|
22092
|
+
}
|
|
21978
22093
|
function formatDatetimeInstance(v) {
|
|
21979
22094
|
const year = numField(v, "Year");
|
|
21980
22095
|
const month = numField(v, "Month");
|
|
@@ -21984,6 +22099,10 @@ function formatDatetimeInstance(v) {
|
|
|
21984
22099
|
const second = numField(v, "Second");
|
|
21985
22100
|
if (year === null || month === null || day === null || hour === null || minute === null || second === null)
|
|
21986
22101
|
return null;
|
|
22102
|
+
const fmt = textField(v, "Format");
|
|
22103
|
+
if (fmt !== null && fmt !== "") {
|
|
22104
|
+
return formatDatetimePattern(fmt, year, month, day, hour, minute, second);
|
|
22105
|
+
}
|
|
21987
22106
|
const mIdx = Math.max(0, Math.min(11, Math.floor(month) - 1));
|
|
21988
22107
|
const mon = DATETIME_MONTH_ABBR[mIdx];
|
|
21989
22108
|
const dd = String(Math.floor(day)).padStart(2, "0");
|
|
@@ -23069,7 +23188,7 @@ function indexIntoTensorWithTensor(base, idx) {
|
|
|
23069
23188
|
if (hasImag) imIndices.push(base.imag[k]);
|
|
23070
23189
|
}
|
|
23071
23190
|
const idxIs0x0 = idx.data.length === 0 && idx.shape.length === 2 && idx.shape[0] === 0 && idx.shape[1] === 0;
|
|
23072
|
-
const baseIsVector = base.shape.length <= 2 && (base.shape[0] === 1 || base.shape[1] === 1 || base.shape.length === 1);
|
|
23191
|
+
const baseIsVector = base.data.length !== 1 && base.shape.length <= 2 && (base.shape[0] === 1 || base.shape[1] === 1 || base.shape.length === 1);
|
|
23073
23192
|
const idxIsVector = idx.shape.length <= 2 && (idx.shape[0] === 1 || idx.shape[1] === 1 || idx.shape.length === 1);
|
|
23074
23193
|
const outShape = idxIs0x0 ? [0, 0] : baseIsVector && idxIsVector ? base.shape[0] === 1 ? [1, resultData.length] : [resultData.length, 1] : idx.shape;
|
|
23075
23194
|
const imOut = hasImag && imIndices.some((x) => x !== 0) ? allocFloat64Array(imIndices) : void 0;
|
|
@@ -23131,6 +23250,17 @@ function indexIntoRTValue(base, indices) {
|
|
|
23131
23250
|
return base.elements[i];
|
|
23132
23251
|
}
|
|
23133
23252
|
if (isRuntimeTensor(idx)) {
|
|
23253
|
+
if (idx._isLogical) {
|
|
23254
|
+
const newElements2 = [];
|
|
23255
|
+
for (let k = 0; k < idx.data.length; k++) {
|
|
23256
|
+
if (idx.data[k] !== 0) {
|
|
23257
|
+
if (k >= base.elements.length)
|
|
23258
|
+
throw new RuntimeError("Index exceeds struct array bounds");
|
|
23259
|
+
newElements2.push(base.elements[k]);
|
|
23260
|
+
}
|
|
23261
|
+
}
|
|
23262
|
+
return RTV.structArray(base.fieldNames, newElements2);
|
|
23263
|
+
}
|
|
23134
23264
|
const newElements = [];
|
|
23135
23265
|
for (let k = 0; k < idx.data.length; k++) {
|
|
23136
23266
|
const i = Math.round(idx.data[k]) - 1;
|
|
@@ -27482,8 +27612,8 @@ function sprintfFormat(fmt, args) {
|
|
|
27482
27612
|
if (width > 0) {
|
|
27483
27613
|
const padChar = zeroPad ? "0" : " ";
|
|
27484
27614
|
const padLen = Math.max(0, width - sign.length - s.length);
|
|
27485
|
-
const
|
|
27486
|
-
result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign +
|
|
27615
|
+
const pad2 = padChar.repeat(padLen);
|
|
27616
|
+
result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad2 + s : pad2 + sign + s;
|
|
27487
27617
|
} else {
|
|
27488
27618
|
result += sign + s;
|
|
27489
27619
|
}
|
|
@@ -37818,6 +37948,32 @@ function datetimeFromUtcMs(ms) {
|
|
|
37818
37948
|
function datetimeFromDatenum(dn) {
|
|
37819
37949
|
return datetimeFromUtcMs((dn - MATLAB_EPOCH_DAYS) * 864e5);
|
|
37820
37950
|
}
|
|
37951
|
+
function withTimeZoneFormat(dt, timeZone, format) {
|
|
37952
|
+
if (timeZone === void 0 && format === void 0) return dt;
|
|
37953
|
+
const fields = new Map(dt.fields);
|
|
37954
|
+
if (timeZone !== void 0) fields.set("TimeZone", RTV.char(timeZone));
|
|
37955
|
+
if (format !== void 0) fields.set("Format", RTV.char(format));
|
|
37956
|
+
return new RuntimeClassInstance("datetime", fields, false);
|
|
37957
|
+
}
|
|
37958
|
+
function todayParts(offsetDays, utc) {
|
|
37959
|
+
const now = /* @__PURE__ */ new Date();
|
|
37960
|
+
if (utc) {
|
|
37961
|
+
const d2 = new Date(
|
|
37962
|
+
Date.UTC(
|
|
37963
|
+
now.getUTCFullYear(),
|
|
37964
|
+
now.getUTCMonth(),
|
|
37965
|
+
now.getUTCDate() + offsetDays
|
|
37966
|
+
)
|
|
37967
|
+
);
|
|
37968
|
+
return [d2.getUTCFullYear(), d2.getUTCMonth() + 1, d2.getUTCDate()];
|
|
37969
|
+
}
|
|
37970
|
+
const d = new Date(
|
|
37971
|
+
now.getFullYear(),
|
|
37972
|
+
now.getMonth(),
|
|
37973
|
+
now.getDate() + offsetDays
|
|
37974
|
+
);
|
|
37975
|
+
return [d.getFullYear(), d.getMonth() + 1, d.getDate()];
|
|
37976
|
+
}
|
|
37821
37977
|
function makeDuration(totalSeconds) {
|
|
37822
37978
|
const fields = /* @__PURE__ */ new Map([
|
|
37823
37979
|
["Seconds", RTV.num(totalSeconds)]
|
|
@@ -37867,9 +38023,10 @@ registerIBuiltin({
|
|
|
37867
38023
|
"t = datetime('now' | 'today' | 'yesterday' | 'tomorrow')",
|
|
37868
38024
|
"t = datetime(Y, M, D)",
|
|
37869
38025
|
"t = datetime(Y, M, D, H, MI, S)",
|
|
37870
|
-
"t = datetime(X, 'ConvertFrom', dateType)"
|
|
38026
|
+
"t = datetime(X, 'ConvertFrom', dateType)",
|
|
38027
|
+
"t = datetime(..., 'TimeZone', tz, 'Format', fmt)"
|
|
37871
38028
|
],
|
|
37872
|
-
description: "Create a datetime value. Supported dateType values for ConvertFrom: 'datenum', 'posixtime', 'excel', 'excel1904'."
|
|
38029
|
+
description: "Create a datetime value. Supported dateType values for ConvertFrom: 'datenum', 'posixtime', 'excel', 'excel1904'. Trailing 'TimeZone' (only '', 'local', 'UTC') and 'Format' name-value pairs are supported; the Format pattern is used by char() and display."
|
|
37873
38030
|
},
|
|
37874
38031
|
resolve: () => ({
|
|
37875
38032
|
outputTypes: [
|
|
@@ -37881,75 +38038,83 @@ registerIBuiltin({
|
|
|
37881
38038
|
}
|
|
37882
38039
|
],
|
|
37883
38040
|
apply: (args) => {
|
|
37884
|
-
|
|
37885
|
-
|
|
38041
|
+
let timeZone;
|
|
38042
|
+
let format;
|
|
38043
|
+
let positional = args;
|
|
38044
|
+
while (positional.length >= 2) {
|
|
38045
|
+
const name = argToString(positional[positional.length - 2]);
|
|
38046
|
+
if (name === null) break;
|
|
38047
|
+
const lc = name.toLowerCase();
|
|
38048
|
+
if (lc !== "timezone" && lc !== "format") break;
|
|
38049
|
+
const value = argToString(positional[positional.length - 1]);
|
|
38050
|
+
if (value === null)
|
|
38051
|
+
throw new RuntimeError(`datetime: ${name} value must be text`);
|
|
38052
|
+
if (lc === "timezone") timeZone = value;
|
|
38053
|
+
else format = value;
|
|
38054
|
+
positional = positional.slice(0, -2);
|
|
38055
|
+
}
|
|
38056
|
+
const tzLc = timeZone?.toLowerCase();
|
|
38057
|
+
if (tzLc !== void 0 && tzLc !== "" && tzLc !== "local" && tzLc !== "utc") {
|
|
38058
|
+
throw new RuntimeError(
|
|
38059
|
+
`datetime: unsupported TimeZone '${timeZone}' (supported: '', 'local', 'UTC')`
|
|
38060
|
+
);
|
|
37886
38061
|
}
|
|
37887
|
-
|
|
37888
|
-
|
|
38062
|
+
const utc = tzLc === "utc";
|
|
38063
|
+
const finish = (dt) => withTimeZoneFormat(dt, timeZone, format);
|
|
38064
|
+
if (positional.length === 0) {
|
|
38065
|
+
return finish(
|
|
38066
|
+
utc ? datetimeFromUtcMs(Date.now()) : datetimeFromDate(/* @__PURE__ */ new Date())
|
|
38067
|
+
);
|
|
38068
|
+
}
|
|
38069
|
+
if (positional.length === 1) {
|
|
38070
|
+
const s = argToString(positional[0]);
|
|
37889
38071
|
if (s !== null) {
|
|
37890
|
-
const now = /* @__PURE__ */ new Date();
|
|
37891
38072
|
const lc = s.toLowerCase();
|
|
37892
|
-
if (lc === "now")
|
|
37893
|
-
|
|
37894
|
-
|
|
37895
|
-
now.getFullYear(),
|
|
37896
|
-
now.getMonth() + 1,
|
|
37897
|
-
now.getDate(),
|
|
37898
|
-
0,
|
|
37899
|
-
0,
|
|
37900
|
-
0
|
|
38073
|
+
if (lc === "now") {
|
|
38074
|
+
return finish(
|
|
38075
|
+
utc ? datetimeFromUtcMs(Date.now()) : datetimeFromDate(/* @__PURE__ */ new Date())
|
|
37901
38076
|
);
|
|
37902
38077
|
}
|
|
37903
|
-
if (lc === "yesterday" || lc === "tomorrow") {
|
|
37904
|
-
const
|
|
37905
|
-
|
|
37906
|
-
|
|
37907
|
-
now.getDate() + (lc === "tomorrow" ? 1 : -1)
|
|
37908
|
-
);
|
|
37909
|
-
return makeDatetime(
|
|
37910
|
-
d.getFullYear(),
|
|
37911
|
-
d.getMonth() + 1,
|
|
37912
|
-
d.getDate(),
|
|
37913
|
-
0,
|
|
37914
|
-
0,
|
|
37915
|
-
0
|
|
37916
|
-
);
|
|
38078
|
+
if (lc === "today" || lc === "yesterday" || lc === "tomorrow") {
|
|
38079
|
+
const offset = lc === "tomorrow" ? 1 : lc === "yesterday" ? -1 : 0;
|
|
38080
|
+
const [Y, M, D] = todayParts(offset, utc);
|
|
38081
|
+
return finish(makeDatetime(Y, M, D, 0, 0, 0));
|
|
37917
38082
|
}
|
|
37918
38083
|
throw new RuntimeError(
|
|
37919
38084
|
`datetime: unrecognized relative-day string '${s}'`
|
|
37920
38085
|
);
|
|
37921
38086
|
}
|
|
37922
38087
|
}
|
|
37923
|
-
if (
|
|
37924
|
-
const flag = argToString(
|
|
37925
|
-
const kind = argToString(
|
|
38088
|
+
if (positional.length === 3) {
|
|
38089
|
+
const flag = argToString(positional[1]);
|
|
38090
|
+
const kind = argToString(positional[2]);
|
|
37926
38091
|
if (flag !== null && flag.toLowerCase() === "convertfrom") {
|
|
37927
38092
|
if (kind === null)
|
|
37928
38093
|
throw new RuntimeError("datetime: dateType must be text");
|
|
37929
|
-
const x = toNumber(
|
|
38094
|
+
const x = toNumber(positional[0]);
|
|
37930
38095
|
const k = kind.toLowerCase();
|
|
37931
|
-
if (k === "datenum") return datetimeFromDatenum(x);
|
|
37932
|
-
if (k === "posixtime") return datetimeFromUtcMs(x * 1e3);
|
|
38096
|
+
if (k === "datenum") return finish(datetimeFromDatenum(x));
|
|
38097
|
+
if (k === "posixtime") return finish(datetimeFromUtcMs(x * 1e3));
|
|
37933
38098
|
if (k === "excel") {
|
|
37934
|
-
return datetimeFromUtcMs((x - 25569) * 864e5);
|
|
38099
|
+
return finish(datetimeFromUtcMs((x - 25569) * 864e5));
|
|
37935
38100
|
}
|
|
37936
38101
|
if (k === "excel1904") {
|
|
37937
|
-
return datetimeFromUtcMs((x - 24107) * 864e5);
|
|
38102
|
+
return finish(datetimeFromUtcMs((x - 24107) * 864e5));
|
|
37938
38103
|
}
|
|
37939
38104
|
throw new RuntimeError(
|
|
37940
38105
|
`datetime: unsupported ConvertFrom type '${kind}'`
|
|
37941
38106
|
);
|
|
37942
38107
|
}
|
|
37943
38108
|
}
|
|
37944
|
-
if (
|
|
37945
|
-
const Y = toNumber(
|
|
37946
|
-
const M = toNumber(
|
|
37947
|
-
const D = toNumber(
|
|
37948
|
-
const H2 =
|
|
37949
|
-
const MI =
|
|
37950
|
-
const S =
|
|
37951
|
-
const MS =
|
|
37952
|
-
return makeDatetime(Y, M, D, H2, MI, S + MS / 1e3);
|
|
38109
|
+
if (positional.length === 3 || positional.length === 6 || positional.length === 7) {
|
|
38110
|
+
const Y = toNumber(positional[0]);
|
|
38111
|
+
const M = toNumber(positional[1]);
|
|
38112
|
+
const D = toNumber(positional[2]);
|
|
38113
|
+
const H2 = positional.length >= 6 ? toNumber(positional[3]) : 0;
|
|
38114
|
+
const MI = positional.length >= 6 ? toNumber(positional[4]) : 0;
|
|
38115
|
+
const S = positional.length >= 6 ? toNumber(positional[5]) : 0;
|
|
38116
|
+
const MS = positional.length >= 7 ? toNumber(positional[6]) : 0;
|
|
38117
|
+
return finish(makeDatetime(Y, M, D, H2, MI, S + MS / 1e3));
|
|
37953
38118
|
}
|
|
37954
38119
|
throw new RuntimeError(
|
|
37955
38120
|
`datetime: unsupported argument pattern (nargin=${args.length})`
|
|
@@ -39906,6 +40071,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
39906
40071
|
"copyfile",
|
|
39907
40072
|
"fileattrib",
|
|
39908
40073
|
"unzip",
|
|
40074
|
+
"zip",
|
|
39909
40075
|
"dir",
|
|
39910
40076
|
"warning",
|
|
39911
40077
|
"input",
|
|
@@ -41018,6 +41184,26 @@ function registerSpecialBuiltins(rt) {
|
|
|
41018
41184
|
}
|
|
41019
41185
|
return void 0;
|
|
41020
41186
|
});
|
|
41187
|
+
registerSpecial("zip", (nargout, args) => {
|
|
41188
|
+
const io = requireFileIO();
|
|
41189
|
+
if (!io.zip)
|
|
41190
|
+
throw new RuntimeError("zip is not available in this environment");
|
|
41191
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
41192
|
+
if (margs.length < 2)
|
|
41193
|
+
throw new RuntimeError("zip requires at least 2 arguments");
|
|
41194
|
+
let zipfilename = toString(margs[0]);
|
|
41195
|
+
const base = zipfilename.split(/[/\\]/).pop() ?? zipfilename;
|
|
41196
|
+
if (!base.includes(".")) zipfilename += ".zip";
|
|
41197
|
+
const fnames = margs[1];
|
|
41198
|
+
const filenames = isRuntimeCell(fnames) ? fnames.data.map((v) => toString(ensureRuntimeValue(v))) : [toString(fnames)];
|
|
41199
|
+
const rootdir = margs.length >= 3 ? toString(margs[2]) : ".";
|
|
41200
|
+
const entryNames = io.zip(zipfilename, filenames, rootdir);
|
|
41201
|
+
if (nargout >= 1) {
|
|
41202
|
+
const cellData = entryNames.map((f) => RTV.char(f));
|
|
41203
|
+
return RTV.cell(cellData, [1, cellData.length]);
|
|
41204
|
+
}
|
|
41205
|
+
return void 0;
|
|
41206
|
+
});
|
|
41021
41207
|
registerSpecial("dir", (nargout, args) => {
|
|
41022
41208
|
const io = requireFileIO();
|
|
41023
41209
|
if (!io.listDir)
|
|
@@ -43278,8 +43464,8 @@ function padExtent(e, tight) {
|
|
|
43278
43464
|
return [min2, max2];
|
|
43279
43465
|
}
|
|
43280
43466
|
if (tight) return [min2, max2];
|
|
43281
|
-
const
|
|
43282
|
-
return [min2 -
|
|
43467
|
+
const pad2 = (max2 - min2) * 0.05;
|
|
43468
|
+
return [min2 - pad2, max2 + pad2];
|
|
43283
43469
|
}
|
|
43284
43470
|
function applyExplicit(auto, explicit) {
|
|
43285
43471
|
if (!explicit) return auto;
|
|
@@ -49484,13 +49670,19 @@ registerIBuiltin({
|
|
|
49484
49670
|
resolve: (argTypes) => {
|
|
49485
49671
|
if (argTypes.length !== 1) return null;
|
|
49486
49672
|
const a = argTypes[0];
|
|
49487
|
-
if (a.kind !== "char" && a.kind !== "string" && a.kind !== "number" && a.kind !== "tensor" && a.kind !== "cell" && a.kind !== "unknown"
|
|
49673
|
+
if (a.kind !== "char" && a.kind !== "string" && a.kind !== "number" && a.kind !== "tensor" && a.kind !== "cell" && a.kind !== "unknown" && // datetime/duration only — other classes keep their own char methods
|
|
49674
|
+
// (or the generic "does not support these argument types" error).
|
|
49675
|
+
!(a.kind === "class_instance" && (a.className === "datetime" || a.className === "duration")))
|
|
49488
49676
|
return null;
|
|
49489
49677
|
return {
|
|
49490
49678
|
outputTypes: [{ kind: "char" }],
|
|
49491
49679
|
apply: (args) => {
|
|
49492
49680
|
const v = args[0];
|
|
49493
49681
|
if (isRuntimeChar(v)) return v;
|
|
49682
|
+
if (isRuntimeClassInstance(v)) {
|
|
49683
|
+
const s = formatDatetimeOrDuration(v);
|
|
49684
|
+
if (s !== null) return RTV.char(s);
|
|
49685
|
+
}
|
|
49494
49686
|
if (isRuntimeString(v)) return RTV.char(v);
|
|
49495
49687
|
if (isRuntimeNumber(v))
|
|
49496
49688
|
return RTV.char(String.fromCharCode(Math.round(v)));
|
|
@@ -51878,7 +52070,7 @@ defineBuiltin({
|
|
|
51878
52070
|
const result = invComplexJS(A.data, A.imag, n);
|
|
51879
52071
|
return RTV.tensor(result.re, [n, n], result.im);
|
|
51880
52072
|
}
|
|
51881
|
-
const bridge = getEffectiveBridge("inv");
|
|
52073
|
+
const bridge = getEffectiveBridge("inv", "inv");
|
|
51882
52074
|
return RTV.tensor(bridge.inv(toF64(A.data), n), [n, n]);
|
|
51883
52075
|
}
|
|
51884
52076
|
}
|
|
@@ -54225,6 +54417,16 @@ defineBuiltin({
|
|
|
54225
54417
|
parseReshapeDims(args, 1);
|
|
54226
54418
|
return v;
|
|
54227
54419
|
}
|
|
54420
|
+
if (isRuntimeCell(v)) {
|
|
54421
|
+
const total = v.data.length;
|
|
54422
|
+
const s = parseReshapeDims(args, total);
|
|
54423
|
+
while (s.length > 2 && s[s.length - 1] === 1) s.pop();
|
|
54424
|
+
if (s.length > 2)
|
|
54425
|
+
throw new RuntimeError("reshape: cell arrays must be 2-D");
|
|
54426
|
+
const nr = s[0];
|
|
54427
|
+
const nc = s.length >= 2 ? s[1] : 1;
|
|
54428
|
+
return RTV.cell(v.data.slice(), [nr, nc]);
|
|
54429
|
+
}
|
|
54228
54430
|
if (isRuntimeClassInstanceArray(v)) {
|
|
54229
54431
|
const total = v.elements.length;
|
|
54230
54432
|
const s = parseReshapeDims(args, total);
|
|
@@ -64075,7 +64277,7 @@ function getSourceLine(getSource, file, line) {
|
|
|
64075
64277
|
}
|
|
64076
64278
|
|
|
64077
64279
|
// src/numbl-core/version.ts
|
|
64078
|
-
var NUMBL_VERSION = "0.4.
|
|
64280
|
+
var NUMBL_VERSION = "0.4.13";
|
|
64079
64281
|
|
|
64080
64282
|
// src/cli-repl.ts
|
|
64081
64283
|
import { createInterface } from "readline";
|
|
@@ -66709,6 +66911,12 @@ function evalMember(expr, nargout) {
|
|
|
66709
66911
|
}
|
|
66710
66912
|
}
|
|
66711
66913
|
const base = this.evalExpr(expr.base);
|
|
66914
|
+
const baseRv = ensureRuntimeValue(base);
|
|
66915
|
+
if (isRuntimeStructArray(baseRv) && baseRv.elements.length !== 1) {
|
|
66916
|
+
return baseRv.elements.map(
|
|
66917
|
+
(el) => ensureRuntimeValue(this.rt.getMember(el, expr.name))
|
|
66918
|
+
);
|
|
66919
|
+
}
|
|
66712
66920
|
return this.rt.getMember(base, expr.name);
|
|
66713
66921
|
}
|
|
66714
66922
|
function tryExtractDottedName(expr) {
|
|
@@ -66920,12 +67128,31 @@ function evalCellLiteral(expr) {
|
|
|
66920
67128
|
}
|
|
66921
67129
|
return RTV.cell(elements2, [1, elements2.length]);
|
|
66922
67130
|
}
|
|
66923
|
-
const
|
|
66924
|
-
|
|
67131
|
+
const rowValues = expr.rows.map((row) => {
|
|
67132
|
+
const vals = [];
|
|
67133
|
+
for (const e of row) {
|
|
67134
|
+
const v = this.evalExpr(e);
|
|
67135
|
+
if (Array.isArray(v)) {
|
|
67136
|
+
for (const elem of v) vals.push(ensureRuntimeValue(elem));
|
|
67137
|
+
} else {
|
|
67138
|
+
vals.push(ensureRuntimeValue(v));
|
|
67139
|
+
}
|
|
67140
|
+
}
|
|
67141
|
+
return vals;
|
|
67142
|
+
});
|
|
67143
|
+
const numRows = rowValues.length;
|
|
67144
|
+
const numCols = rowValues[0].length;
|
|
67145
|
+
for (const rv of rowValues) {
|
|
67146
|
+
if (rv.length !== numCols) {
|
|
67147
|
+
throw new RuntimeError(
|
|
67148
|
+
"Cell array rows must have the same number of columns"
|
|
67149
|
+
);
|
|
67150
|
+
}
|
|
67151
|
+
}
|
|
66925
67152
|
const elements = [];
|
|
66926
67153
|
for (let c = 0; c < numCols; c++) {
|
|
66927
67154
|
for (let r = 0; r < numRows; r++) {
|
|
66928
|
-
elements.push(
|
|
67155
|
+
elements.push(rowValues[r][c]);
|
|
66929
67156
|
}
|
|
66930
67157
|
}
|
|
66931
67158
|
return RTV.cell(elements, [numRows, numCols]);
|
|
@@ -71400,8 +71627,8 @@ function mtoc2_sprintf_format(fmt, args) {
|
|
|
71400
71627
|
if (width > 0) {
|
|
71401
71628
|
const padChar = zeroPad ? "0" : " ";
|
|
71402
71629
|
const padLen = Math.max(0, width - sign.length - s.length);
|
|
71403
|
-
const
|
|
71404
|
-
result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign +
|
|
71630
|
+
const pad2 = padChar.repeat(padLen);
|
|
71631
|
+
result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad2 + s : pad2 + sign + s;
|
|
71405
71632
|
} else {
|
|
71406
71633
|
result += sign + s;
|
|
71407
71634
|
}
|
|
@@ -71686,8 +71913,8 @@ function disp_complex_slice(re, im, offset, rows, cols) {
|
|
|
71686
71913
|
for (let c = 0; c < cols; c++) {
|
|
71687
71914
|
const idx = r + c * rows;
|
|
71688
71915
|
const cell = cells[idx];
|
|
71689
|
-
const
|
|
71690
|
-
for (let i = 0; i <
|
|
71916
|
+
const pad2 = colWidths[c] - cell.length;
|
|
71917
|
+
for (let i = 0; i < pad2; i++) line += " ";
|
|
71691
71918
|
line += cell;
|
|
71692
71919
|
if (c < cols - 1) line += " ";
|
|
71693
71920
|
}
|
|
@@ -73099,6 +73326,14 @@ function mtoc2_tensor_mtimes_real(a, b) {
|
|
|
73099
73326
|
`mtoc2_tensor_mtimes_real: inner dimensions disagree (${k} vs ${k2})`
|
|
73100
73327
|
);
|
|
73101
73328
|
}
|
|
73329
|
+
if (typeof $matmulAccel === "function") {
|
|
73330
|
+
const accel = $matmulAccel(a.data, m, k, b.data, n);
|
|
73331
|
+
if (accel) {
|
|
73332
|
+
const acc = mtoc2_tensor_alloc(m, n);
|
|
73333
|
+
acc.data.set(accel);
|
|
73334
|
+
return acc;
|
|
73335
|
+
}
|
|
73336
|
+
}
|
|
73102
73337
|
const r = mtoc2_tensor_alloc(m, n);
|
|
73103
73338
|
for (let j = 0; j < n; j++) {
|
|
73104
73339
|
for (let i = 0; i < m; i++) {
|
|
@@ -74310,7 +74545,7 @@ var JS_SNIPPETS = {
|
|
|
74310
74545
|
"tensor_logspace.js": "// JS sibling of `tensor_logspace.h`. Build a 1\xD7n row tensor of n\n// logarithmically-spaced values from 10^a to 10^b. Byte-for-byte with\n// numbl's interpreter `logspace`, including the MATLAB special case\n// where an upper limit of exactly `pi` makes the last point `pi`.\n\n\nfunction mtoc2_tensor_logspace(a, b, n) {\n if (n <= 0) return mtoc2_tensor_alloc(1, 0);\n const isPi = b === Math.PI;\n const endVal = isPi ? Math.PI : Math.pow(10, b);\n const out = mtoc2_tensor_alloc(1, n);\n if (n === 1) {\n out.data[0] = endVal;\n return out;\n }\n if (isPi) {\n const logStart = Math.log10(Math.pow(10, a));\n const logEnd = Math.log10(Math.PI);\n for (let i = 0; i < n; i++) {\n const t = logStart + ((logEnd - logStart) * i) / (n - 1);\n out.data[i] = Math.pow(10, t);\n }\n } else {\n for (let i = 0; i < n; i++) {\n const t = a + ((b - a) * i) / (n - 1);\n out.data[i] = Math.pow(10, t);\n }\n }\n return out;\n}\n",
|
|
74311
74546
|
"tensor_meshgrid.js": "// JS sibling of `tensor_meshgrid.h`. MATLAB-style coordinate grid.\n\n\nfunction numel(t) {\n let n = 1;\n for (const s of t.shape) n *= s;\n return n;\n}\n\nfunction mtoc2_meshgrid_x(x, y) {\n const M = numel(x);\n const N = numel(y);\n const X = mtoc2_tensor_alloc(N, M);\n for (let j = 0; j < M; j++) {\n const xj = x.data[j];\n for (let i = 0; i < N; i++) X.data[i + j * N] = xj;\n }\n return X;\n}\n\nfunction mtoc2_meshgrid(x, y) {\n const M = numel(x);\n const N = numel(y);\n const X = mtoc2_tensor_alloc(N, M);\n const Y = mtoc2_tensor_alloc(N, M);\n for (let j = 0; j < M; j++) {\n const xj = x.data[j];\n for (let i = 0; i < N; i++) {\n X.data[i + j * N] = xj;\n Y.data[i + j * N] = y.data[i];\n }\n }\n return { X, Y };\n}\n\nfunction mtoc2_meshgrid_1arg(x) {\n return mtoc2_meshgrid(x, x);\n}\n",
|
|
74312
74547
|
"tensor_mtimes_complex.js": '// JS sibling of `tensor_mtimes_complex.h`. 2-D matrix multiplication\n// producing a complex result. Handles all three mixed cases\n// (complex \xD7 complex, complex \xD7 real, real \xD7 complex) by treating an\n// undefined imag lane as implicit zeros.\n\n\nfunction mtoc2_tensor_mtimes_complex_scalar(a, b) {\n if (a.shape.length !== 2 || b.shape.length !== 2) {\n throw new Error("mtoc2_tensor_mtimes_complex_scalar: inputs must be 2-D");\n }\n if (a.shape[0] !== 1 || b.shape[1] !== 1) {\n throw new Error("mtoc2_tensor_mtimes_complex_scalar: requires 1\xD7k * k\xD71");\n }\n if (a.shape[1] !== b.shape[0]) {\n throw new Error("mtoc2_tensor_mtimes_complex_scalar: inner-dim mismatch");\n }\n const k = a.shape[1];\n const aim = a.imag;\n const bim = b.imag;\n let accR = 0;\n let accI = 0;\n for (let p = 0; p < k; p++) {\n const ar = a.data[p];\n const ai = aim !== undefined ? aim[p] : 0;\n const br = b.data[p];\n const bi = bim !== undefined ? bim[p] : 0;\n accR += ar * br - ai * bi;\n accI += ar * bi + ai * br;\n }\n return { re: accR, im: accI };\n}\n\nfunction mtoc2_tensor_mtimes_complex(a, b) {\n if (a.shape.length !== 2 || b.shape.length !== 2) {\n throw new Error("mtoc2_tensor_mtimes_complex: inputs must be 2-D");\n }\n const m = a.shape[0];\n const k = a.shape[1];\n const k2 = b.shape[0];\n const n = b.shape[1];\n if (k !== k2) {\n throw new Error(\n `mtoc2_tensor_mtimes_complex: inner-dim mismatch (${m}\xD7${k} * ${k2}\xD7${n})`\n );\n }\n const out = mtoc2_tensor_alloc_complex(m, n);\n const aim = a.imag;\n const bim = b.imag;\n for (let j = 0; j < n; j++) {\n for (let i = 0; i < m; i++) {\n let accR = 0;\n let accI = 0;\n for (let p = 0; p < k; p++) {\n const ar = a.data[i + p * m];\n const ai = aim !== undefined ? aim[i + p * m] : 0;\n const br = b.data[p + j * k];\n const bi = bim !== undefined ? bim[p + j * k] : 0;\n accR += ar * br - ai * bi;\n accI += ar * bi + ai * br;\n }\n out.data[i + j * m] = accR;\n out.imag[i + j * m] = accI;\n }\n }\n return out;\n}\n',
|
|
74313
|
-
"tensor_mtimes_real.js": '// JS sibling of `tensor_mtimes_real.h`. Real 2-D matrix\n// multiplication A * B. Column-major in, column-major out.\n// `mtoc2_tensor_mtimes_real_scalar` mirrors the C 1\xD7k * k\xD71\n// inner-product path that returns a bare number instead of a\n// freshly-allocated 1\xD71 tensor.\n\n\nfunction mtoc2_tensor_mtimes_real(a, b) {\n if (a.shape.length !== 2 || b.shape.length !== 2) {\n throw new Error("mtoc2_tensor_mtimes_real: inputs must be 2-D");\n }\n const m = a.shape[0];\n const k = a.shape[1];\n const k2 = b.shape[0];\n const n = b.shape[1];\n if (k !== k2) {\n throw new Error(\n `mtoc2_tensor_mtimes_real: inner dimensions disagree (${k} vs ${k2})`\n );\n }\n const r = mtoc2_tensor_alloc(m, n);\n for (let j = 0; j < n; j++) {\n for (let i = 0; i < m; i++) {\n let s = 0;\n for (let p = 0; p < k; p++) {\n s += a.data[i + p * m] * b.data[p + j * k];\n }\n r.data[i + j * m] = s;\n }\n }\n return r;\n}\n\nfunction mtoc2_tensor_mtimes_real_scalar(a, b) {\n if (a.shape.length !== 2 || b.shape.length !== 2) {\n throw new Error("mtoc2_tensor_mtimes_real_scalar: inputs must be 2-D");\n }\n // The translate-time type system has already proven a is 1\xD7k and b\n // is k\xD71; this helper trusts that and just runs the inner product.\n const k = a.shape[1];\n let s = 0;\n for (let p = 0; p < k; p++) {\n s += a.data[p * a.shape[0]] * b.data[p];\n }\n return s;\n}\n',
|
|
74548
|
+
"tensor_mtimes_real.js": '// JS sibling of `tensor_mtimes_real.h`. Real 2-D matrix\n// multiplication A * B. Column-major in, column-major out.\n// `mtoc2_tensor_mtimes_real_scalar` mirrors the C 1\xD7k * k\xD71\n// inner-product path that returns a bare number instead of a\n// freshly-allocated 1\xD71 tensor.\n\n\nfunction mtoc2_tensor_mtimes_real(a, b) {\n if (a.shape.length !== 2 || b.shape.length !== 2) {\n throw new Error("mtoc2_tensor_mtimes_real: inputs must be 2-D");\n }\n const m = a.shape[0];\n const k = a.shape[1];\n const k2 = b.shape[0];\n const n = b.shape[1];\n if (k !== k2) {\n throw new Error(\n `mtoc2_tensor_mtimes_real: inner dimensions disagree (${k} vs ${k2})`\n );\n }\n // Optional WASM LAPACK accelerator. When a host installs `$matmulAccel`\n // (browser worker, after loading a bridge), delegate the multiply; a\n // falsy return means "declined" (too small / error) and we fall through\n // to the JS loop below. `typeof` guard is safe even when unset.\n if (typeof $matmulAccel === "function") {\n const accel = $matmulAccel(a.data, m, k, b.data, n);\n if (accel) {\n const acc = mtoc2_tensor_alloc(m, n);\n acc.data.set(accel);\n return acc;\n }\n }\n const r = mtoc2_tensor_alloc(m, n);\n for (let j = 0; j < n; j++) {\n for (let i = 0; i < m; i++) {\n let s = 0;\n for (let p = 0; p < k; p++) {\n s += a.data[i + p * m] * b.data[p + j * k];\n }\n r.data[i + j * m] = s;\n }\n }\n return r;\n}\n\nfunction mtoc2_tensor_mtimes_real_scalar(a, b) {\n if (a.shape.length !== 2 || b.shape.length !== 2) {\n throw new Error("mtoc2_tensor_mtimes_real_scalar: inputs must be 2-D");\n }\n // The translate-time type system has already proven a is 1\xD7k and b\n // is k\xD71; this helper trusts that and just runs the inner product.\n const k = a.shape[1];\n let s = 0;\n for (let p = 0; p < k; p++) {\n s += a.data[p * a.shape[0]] * b.data[p];\n }\n return s;\n}\n',
|
|
74314
74549
|
"tensor_norm.js": "// JS sibling of `tensor_norm.h`. Vector norms for real and complex\n// tensors. The complex variants tolerate a missing imag lane (real\n// tensor flowing through a complex-typed norm route) by treating it\n// as zero.\n\nfunction mtoc2_norm2_real(a) {\n let acc = 0;\n for (let i = 0; i < a.data.length; i++) {\n const x = a.data[i];\n acc += x * x;\n }\n return Math.sqrt(acc);\n}\n\nfunction mtoc2_norm2_complex(a) {\n let acc = 0;\n const im = a.imag;\n for (let i = 0; i < a.data.length; i++) {\n const re = a.data[i];\n const imv = im !== undefined ? im[i] : 0;\n acc += re * re + imv * imv;\n }\n return Math.sqrt(acc);\n}\n\nfunction mtoc2_norm_p_real(a, p) {\n const n = a.data.length;\n if (n === 0) return 0;\n if (p === Infinity) {\n let m = 0;\n for (let i = 0; i < n; i++) {\n const x = Math.abs(a.data[i]);\n if (x > m) m = x;\n }\n return m;\n }\n if (p === -Infinity) {\n let m = Math.abs(a.data[0]);\n for (let i = 1; i < n; i++) {\n const x = Math.abs(a.data[i]);\n if (x < m) m = x;\n }\n return m;\n }\n if (p === 1) {\n let acc = 0;\n for (let i = 0; i < n; i++) acc += Math.abs(a.data[i]);\n return acc;\n }\n if (p === 2) return mtoc2_norm2_real(a);\n let acc = 0;\n for (let i = 0; i < n; i++) acc += Math.pow(Math.abs(a.data[i]), p);\n return Math.pow(acc, 1 / p);\n}\n\nfunction mtoc2_norm_p_complex(a, p) {\n const n = a.data.length;\n if (n === 0) return 0;\n const im = a.imag;\n const abs = i => {\n const re = a.data[i];\n const imv = im !== undefined ? im[i] : 0;\n return Math.hypot(re, imv);\n };\n if (p === Infinity) {\n let m = 0;\n for (let i = 0; i < n; i++) {\n const x = abs(i);\n if (x > m) m = x;\n }\n return m;\n }\n if (p === -Infinity) {\n let m = abs(0);\n for (let i = 1; i < n; i++) {\n const x = abs(i);\n if (x < m) m = x;\n }\n return m;\n }\n if (p === 2) return mtoc2_norm2_complex(a);\n if (p === 1) {\n let acc = 0;\n for (let i = 0; i < n; i++) acc += abs(i);\n return acc;\n }\n let acc = 0;\n for (let i = 0; i < n; i++) acc += Math.pow(abs(i), p);\n return Math.pow(acc, 1 / p);\n}\n",
|
|
74315
74550
|
"tensor_ones_nd.js": "// JS sibling of `tensor_ones_nd.h`. Fill the freshly-allocated\n// tensor with `1.0`.\n\n\nfunction mtoc2_tensor_ones_nd(ndim, dims) {\n const t = mtoc2_tensor_alloc_nd(ndim, dims);\n t.data.fill(1);\n return t;\n}\n",
|
|
74316
74551
|
"tensor_ones_square.js": "// JS sibling of `tensor_ones_square.h`. See `tensor_zeros_square.js`\n// for the rationale.\n\n\nfunction mtoc2_tensor_ones_square(n) {\n return mtoc2_tensor_ones_nd(2, [n, n]);\n}\n",
|
|
@@ -82980,9 +83215,9 @@ function tileExact(src, padShape2, padReps) {
|
|
|
82980
83215
|
}
|
|
82981
83216
|
return out;
|
|
82982
83217
|
}
|
|
82983
|
-
function padTo(arr,
|
|
83218
|
+
function padTo(arr, pad2, len) {
|
|
82984
83219
|
const out = arr.slice();
|
|
82985
|
-
while (out.length < len) out.push(
|
|
83220
|
+
while (out.length < len) out.push(pad2);
|
|
82986
83221
|
return out;
|
|
82987
83222
|
}
|
|
82988
83223
|
function trimTrailingOnes(shape) {
|
|
@@ -96988,10 +97223,10 @@ import {
|
|
|
96988
97223
|
chmodSync,
|
|
96989
97224
|
realpathSync
|
|
96990
97225
|
} from "fs";
|
|
96991
|
-
import { unzipSync } from "fflate";
|
|
97226
|
+
import { unzipSync, zipSync } from "fflate";
|
|
96992
97227
|
import { execFileSync } from "child_process";
|
|
96993
97228
|
import { homedir, tmpdir } from "os";
|
|
96994
|
-
import { join as join3, resolve, dirname, basename } from "path";
|
|
97229
|
+
import { join as join3, resolve, relative, dirname, basename } from "path";
|
|
96995
97230
|
|
|
96996
97231
|
// src/cli-scan.ts
|
|
96997
97232
|
import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
@@ -97474,6 +97709,69 @@ var NodeFileIOAdapter = class {
|
|
|
97474
97709
|
}
|
|
97475
97710
|
return extracted;
|
|
97476
97711
|
}
|
|
97712
|
+
zip(zipfilename, filenames, rootDir) {
|
|
97713
|
+
const root = resolve(expandTilde(rootDir));
|
|
97714
|
+
const dest = resolve(expandTilde(zipfilename));
|
|
97715
|
+
const entries = {};
|
|
97716
|
+
const names = [];
|
|
97717
|
+
const toEntryName = (abs2) => {
|
|
97718
|
+
const rel = relative(root, abs2);
|
|
97719
|
+
if (rel.startsWith("..")) return basename(abs2);
|
|
97720
|
+
return rel.split("\\").join("/");
|
|
97721
|
+
};
|
|
97722
|
+
const addFile = (abs2) => {
|
|
97723
|
+
const name = toEntryName(abs2);
|
|
97724
|
+
const buf = readFileSync3(abs2);
|
|
97725
|
+
entries[name] = new Uint8Array(
|
|
97726
|
+
buf.buffer,
|
|
97727
|
+
buf.byteOffset,
|
|
97728
|
+
buf.byteLength
|
|
97729
|
+
);
|
|
97730
|
+
names.push(name);
|
|
97731
|
+
};
|
|
97732
|
+
const addDir = (absDir) => {
|
|
97733
|
+
for (const entry of readdirSync2(absDir)) {
|
|
97734
|
+
const abs2 = join3(absDir, entry);
|
|
97735
|
+
let st2;
|
|
97736
|
+
try {
|
|
97737
|
+
st2 = statSync2(abs2);
|
|
97738
|
+
} catch {
|
|
97739
|
+
continue;
|
|
97740
|
+
}
|
|
97741
|
+
if (st2.isDirectory()) addDir(abs2);
|
|
97742
|
+
else addFile(abs2);
|
|
97743
|
+
}
|
|
97744
|
+
};
|
|
97745
|
+
const addPath = (abs2) => {
|
|
97746
|
+
const st2 = statSync2(abs2);
|
|
97747
|
+
if (st2.isDirectory()) addDir(abs2);
|
|
97748
|
+
else addFile(abs2);
|
|
97749
|
+
};
|
|
97750
|
+
for (const f of filenames) {
|
|
97751
|
+
const p2 = expandTilde(f);
|
|
97752
|
+
const abs2 = resolve(root, p2);
|
|
97753
|
+
const last = basename(p2);
|
|
97754
|
+
if (last.includes("*") || last.includes("?")) {
|
|
97755
|
+
const dir = dirname(abs2);
|
|
97756
|
+
const re = new RegExp(
|
|
97757
|
+
"^" + last.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$"
|
|
97758
|
+
);
|
|
97759
|
+
let dirEntries;
|
|
97760
|
+
try {
|
|
97761
|
+
dirEntries = readdirSync2(dir);
|
|
97762
|
+
} catch {
|
|
97763
|
+
continue;
|
|
97764
|
+
}
|
|
97765
|
+
for (const entry of dirEntries) {
|
|
97766
|
+
if (re.test(entry)) addPath(join3(dir, entry));
|
|
97767
|
+
}
|
|
97768
|
+
} else {
|
|
97769
|
+
addPath(abs2);
|
|
97770
|
+
}
|
|
97771
|
+
}
|
|
97772
|
+
writeFileSync(dest, zipSync(entries));
|
|
97773
|
+
return names;
|
|
97774
|
+
}
|
|
97477
97775
|
listDir(dirPath) {
|
|
97478
97776
|
const p2 = expandTilde(dirPath);
|
|
97479
97777
|
if (p2.includes("**")) {
|
|
@@ -97579,51 +97877,43 @@ var NodeFileIOAdapter = class {
|
|
|
97579
97877
|
return results;
|
|
97580
97878
|
}
|
|
97581
97879
|
listDirRecursive(pattern) {
|
|
97582
|
-
const
|
|
97583
|
-
|
|
97584
|
-
|
|
97880
|
+
const norm2 = pattern.replace(/\\/g, "/");
|
|
97881
|
+
const idx = norm2.indexOf("**");
|
|
97882
|
+
let baseDir = norm2.slice(0, idx);
|
|
97883
|
+
if (baseDir.endsWith("/")) {
|
|
97585
97884
|
baseDir = baseDir.slice(0, -1);
|
|
97586
97885
|
}
|
|
97587
97886
|
if (!baseDir) baseDir = ".";
|
|
97588
97887
|
const absBase = resolve(baseDir);
|
|
97888
|
+
try {
|
|
97889
|
+
if (!statSync2(absBase).isDirectory()) return [];
|
|
97890
|
+
} catch {
|
|
97891
|
+
return [];
|
|
97892
|
+
}
|
|
97893
|
+
const suffix = norm2.slice(idx);
|
|
97894
|
+
const DIRS = "\0";
|
|
97895
|
+
const ANY = "";
|
|
97896
|
+
const re = new RegExp(
|
|
97897
|
+
"^" + suffix.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, DIRS).replace(/\*\*/g, ANY).replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(new RegExp(DIRS, "g"), "(?:.*/)?").replace(new RegExp(ANY, "g"), ".*") + "$"
|
|
97898
|
+
);
|
|
97589
97899
|
const results = [];
|
|
97590
|
-
const
|
|
97900
|
+
const pushIfMatch = (rel, name, folder, bytes, isdir, mtimeMs) => {
|
|
97901
|
+
if (re.test(rel)) results.push({ name, folder, bytes, isdir, mtimeMs });
|
|
97902
|
+
};
|
|
97903
|
+
const walkDir = (dir, rel) => {
|
|
97904
|
+
const relPrefix = rel ? rel + "/" : "";
|
|
97905
|
+
let dirMtime = 0;
|
|
97591
97906
|
try {
|
|
97592
|
-
|
|
97593
|
-
results.push({
|
|
97594
|
-
name: ".",
|
|
97595
|
-
folder: dir,
|
|
97596
|
-
bytes: 0,
|
|
97597
|
-
isdir: true,
|
|
97598
|
-
mtimeMs: ds.mtimeMs
|
|
97599
|
-
});
|
|
97907
|
+
dirMtime = statSync2(dir).mtimeMs;
|
|
97600
97908
|
} catch {
|
|
97601
|
-
results.push({
|
|
97602
|
-
name: ".",
|
|
97603
|
-
folder: dir,
|
|
97604
|
-
bytes: 0,
|
|
97605
|
-
isdir: true,
|
|
97606
|
-
mtimeMs: 0
|
|
97607
|
-
});
|
|
97608
97909
|
}
|
|
97910
|
+
pushIfMatch(relPrefix + ".", ".", dir, 0, true, dirMtime);
|
|
97911
|
+
let parentMtime = 0;
|
|
97609
97912
|
try {
|
|
97610
|
-
|
|
97611
|
-
results.push({
|
|
97612
|
-
name: "..",
|
|
97613
|
-
folder: dir,
|
|
97614
|
-
bytes: 0,
|
|
97615
|
-
isdir: true,
|
|
97616
|
-
mtimeMs: ps.mtimeMs
|
|
97617
|
-
});
|
|
97913
|
+
parentMtime = statSync2(resolve(dir, "..")).mtimeMs;
|
|
97618
97914
|
} catch {
|
|
97619
|
-
results.push({
|
|
97620
|
-
name: "..",
|
|
97621
|
-
folder: dir,
|
|
97622
|
-
bytes: 0,
|
|
97623
|
-
isdir: true,
|
|
97624
|
-
mtimeMs: 0
|
|
97625
|
-
});
|
|
97626
97915
|
}
|
|
97916
|
+
pushIfMatch(relPrefix + "..", "..", dir, 0, true, parentMtime);
|
|
97627
97917
|
let entries;
|
|
97628
97918
|
try {
|
|
97629
97919
|
entries = readdirSync2(dir);
|
|
@@ -97634,22 +97924,23 @@ var NodeFileIOAdapter = class {
|
|
|
97634
97924
|
for (const entry of entries) {
|
|
97635
97925
|
try {
|
|
97636
97926
|
const es = statSync2(join3(dir, entry));
|
|
97637
|
-
|
|
97638
|
-
|
|
97639
|
-
|
|
97640
|
-
|
|
97641
|
-
|
|
97642
|
-
|
|
97643
|
-
|
|
97927
|
+
pushIfMatch(
|
|
97928
|
+
relPrefix + entry,
|
|
97929
|
+
entry,
|
|
97930
|
+
dir,
|
|
97931
|
+
es.isDirectory() ? 0 : es.size,
|
|
97932
|
+
es.isDirectory(),
|
|
97933
|
+
es.mtimeMs
|
|
97934
|
+
);
|
|
97644
97935
|
if (es.isDirectory()) subdirs.push(entry);
|
|
97645
97936
|
} catch {
|
|
97646
97937
|
}
|
|
97647
97938
|
}
|
|
97648
97939
|
for (const sub2 of subdirs) {
|
|
97649
|
-
walkDir(join3(dir, sub2));
|
|
97940
|
+
walkDir(join3(dir, sub2), relPrefix + sub2);
|
|
97650
97941
|
}
|
|
97651
97942
|
};
|
|
97652
|
-
walkDir(absBase);
|
|
97943
|
+
walkDir(absBase, "");
|
|
97653
97944
|
return results;
|
|
97654
97945
|
}
|
|
97655
97946
|
getEntry(fid) {
|
|
@@ -100069,7 +100360,7 @@ function unzipToFiles(zipData) {
|
|
|
100069
100360
|
}
|
|
100070
100361
|
|
|
100071
100362
|
// src/cli.ts
|
|
100072
|
-
import { zipSync } from "fflate";
|
|
100363
|
+
import { zipSync as zipSync2 } from "fflate";
|
|
100073
100364
|
|
|
100074
100365
|
// src/numbl-core/native/qhull-node.ts
|
|
100075
100366
|
var promise = null;
|
|
@@ -100094,8 +100385,8 @@ function variantAddonPath(fastMath) {
|
|
|
100094
100385
|
const name = fastMath ? "numbl_addon.fastmath.node" : "numbl_addon.nofastmath.node";
|
|
100095
100386
|
return join7(packageDir, "build", "Release", name);
|
|
100096
100387
|
}
|
|
100097
|
-
function loadNativeAddon(fastMath) {
|
|
100098
|
-
if (process.env.NUMBL_NO_NATIVE) return;
|
|
100388
|
+
function loadNativeAddon(fastMath, noNative = false) {
|
|
100389
|
+
if (noNative || process.env.NUMBL_NO_NATIVE) return;
|
|
100099
100390
|
const variantPath = variantAddonPath(fastMath);
|
|
100100
100391
|
const flag = fastMath ? " --fast-math" : "";
|
|
100101
100392
|
if (!existsSync3(variantPath)) {
|
|
@@ -100219,8 +100510,8 @@ function findTestFiles(dir) {
|
|
|
100219
100510
|
walk2(dir);
|
|
100220
100511
|
return results;
|
|
100221
100512
|
}
|
|
100222
|
-
async function runTests(dir, optimization, fastMath) {
|
|
100223
|
-
loadNativeAddon(fastMath ?? false);
|
|
100513
|
+
async function runTests(dir, optimization, fastMath, noNative) {
|
|
100514
|
+
loadNativeAddon(fastMath ?? false, noNative ?? false);
|
|
100224
100515
|
await loadQhullBackend();
|
|
100225
100516
|
const absDir = resolve2(process.cwd(), dir);
|
|
100226
100517
|
const testFiles = findTestFiles(absDir);
|
|
@@ -100232,7 +100523,7 @@ async function runTests(dir, optimization, fastMath) {
|
|
|
100232
100523
|
let fail = 0;
|
|
100233
100524
|
const failedScripts = [];
|
|
100234
100525
|
for (const filepath of testFiles) {
|
|
100235
|
-
const rel =
|
|
100526
|
+
const rel = relative2(process.cwd(), filepath);
|
|
100236
100527
|
const source = readFileSync6(filepath, "utf-8");
|
|
100237
100528
|
const mainFileName = filepath;
|
|
100238
100529
|
const scriptDir = dirname3(filepath);
|
|
@@ -100351,9 +100642,12 @@ Options (for run and eval):
|
|
|
100351
100642
|
across --opt levels). Off by default so all --opt
|
|
100352
100643
|
levels agree; --no-fast-math is accepted as the
|
|
100353
100644
|
(now default) opt-out.
|
|
100645
|
+
--no-native Do not load the native LAPACK addon; use the pure-JS
|
|
100646
|
+
fallbacks (same effect as NUMBL_NO_NATIVE=1)
|
|
100354
100647
|
|
|
100355
100648
|
Environment variables:
|
|
100356
|
-
NUMBL_PATH Extra workspace directories (separated by ${delimiter})
|
|
100649
|
+
NUMBL_PATH Extra workspace directories (separated by ${delimiter})
|
|
100650
|
+
NUMBL_NO_NATIVE If set, do not load the native LAPACK addon`);
|
|
100357
100651
|
}
|
|
100358
100652
|
function parseOptions(args) {
|
|
100359
100653
|
const opts = {
|
|
@@ -100372,7 +100666,8 @@ function parseOptions(args) {
|
|
|
100372
100666
|
// and vectorizes transcendentals, so results drift from the JIT
|
|
100373
100667
|
// kernels and diverge across --opt levels. Opt back in with
|
|
100374
100668
|
// `--fast-math` (and a matching `build-addon --fast-math`).
|
|
100375
|
-
fastMath: false
|
|
100669
|
+
fastMath: false,
|
|
100670
|
+
noNative: false
|
|
100376
100671
|
};
|
|
100377
100672
|
const envPath = process.env.NUMBL_PATH;
|
|
100378
100673
|
if (envPath) {
|
|
@@ -100410,6 +100705,9 @@ function parseOptions(args) {
|
|
|
100410
100705
|
case "--no-fast-math":
|
|
100411
100706
|
opts.fastMath = false;
|
|
100412
100707
|
break;
|
|
100708
|
+
case "--no-native":
|
|
100709
|
+
opts.noNative = true;
|
|
100710
|
+
break;
|
|
100413
100711
|
case "--dump-ast":
|
|
100414
100712
|
opts.dumpAst = true;
|
|
100415
100713
|
break;
|
|
@@ -100583,7 +100881,7 @@ async function cmdEval(args) {
|
|
|
100583
100881
|
);
|
|
100584
100882
|
}
|
|
100585
100883
|
async function executeWithOptions(code, mainFileName, workspaceFiles, opts, searchPaths) {
|
|
100586
|
-
loadNativeAddon(opts.fastMath);
|
|
100884
|
+
loadNativeAddon(opts.fastMath, opts.noNative);
|
|
100587
100885
|
await loadQhullBackend();
|
|
100588
100886
|
const profiling = !!opts.profileOutput;
|
|
100589
100887
|
const totalStart = performance.now();
|
|
@@ -100895,7 +101193,7 @@ function collectSiteFiles(projectDir, outDirAbs, ignore) {
|
|
|
100895
101193
|
for (const e of entries) {
|
|
100896
101194
|
const full = join7(dir, e.name);
|
|
100897
101195
|
if (resolve2(full) === outDirAbs) continue;
|
|
100898
|
-
const rel =
|
|
101196
|
+
const rel = relative2(projectDir, full).split(sep).join("/");
|
|
100899
101197
|
if (matchesIgnore(rel)) continue;
|
|
100900
101198
|
if (e.isDirectory()) {
|
|
100901
101199
|
if (SITE_DEFAULT_IGNORE_DIRS.has(e.name)) continue;
|
|
@@ -101006,7 +101304,7 @@ async function cmdBuildSite(args) {
|
|
|
101006
101304
|
zipEntries["numbl-project.json"] = new TextEncoder().encode(
|
|
101007
101305
|
JSON.stringify(manifest, null, 2)
|
|
101008
101306
|
);
|
|
101009
|
-
const zip =
|
|
101307
|
+
const zip = zipSync2(zipEntries, { level: 6 });
|
|
101010
101308
|
writeFileSync4(join7(outDirAbs, "project.zip"), zip);
|
|
101011
101309
|
const totalMb = zip.length / 1048576;
|
|
101012
101310
|
console.log(
|
|
@@ -101071,7 +101369,7 @@ function cmdListBuiltins(flags) {
|
|
|
101071
101369
|
}
|
|
101072
101370
|
async function cmdRepl(args) {
|
|
101073
101371
|
const opts = parseOptions(args);
|
|
101074
|
-
loadNativeAddon(opts.fastMath);
|
|
101372
|
+
loadNativeAddon(opts.fastMath, opts.noNative);
|
|
101075
101373
|
await ensureMipCorePackage();
|
|
101076
101374
|
const replSearchPaths = [...opts.extraPaths];
|
|
101077
101375
|
const replFiles = opts.extraPaths.flatMap((d) => scanMFiles(d));
|
|
@@ -101104,7 +101402,7 @@ function cmdShowProfile(args) {
|
|
|
101104
101402
|
}
|
|
101105
101403
|
const data = JSON.parse(readFileSync6(filepath, "utf-8"));
|
|
101106
101404
|
const fmt = (n, decimals = 1) => n.toFixed(decimals);
|
|
101107
|
-
const
|
|
101405
|
+
const pad2 = (s, w) => s.padStart(w);
|
|
101108
101406
|
const execTime = data.executionTimeMs || 1;
|
|
101109
101407
|
const jitTime = data.jitCompileTimeMs ?? 0;
|
|
101110
101408
|
const dispatches = data.dispatches ?? [];
|
|
@@ -101132,27 +101430,27 @@ function cmdShowProfile(args) {
|
|
|
101132
101430
|
console.log("\nAll timings are self-time (exclusive) and mutually disjoint.");
|
|
101133
101431
|
if (dispatches.length > 0) {
|
|
101134
101432
|
const nameW = Math.max(20, ...dispatches.map((b) => b.name.length)) + 2;
|
|
101135
|
-
const header = "Function".padEnd(nameW) +
|
|
101433
|
+
const header = "Function".padEnd(nameW) + pad2("Calls", 10) + pad2("Self (ms)", 13) + pad2("Avg (ms)", 11) + pad2("% Exec", 9);
|
|
101136
101434
|
console.log("\nDispatched functions (user-defined / workspace):");
|
|
101137
101435
|
console.log(header);
|
|
101138
101436
|
console.log("\u2500".repeat(header.length));
|
|
101139
101437
|
for (const b of dispatches) {
|
|
101140
101438
|
const avg = b.callCount > 0 ? b.totalTimeMs / b.callCount : 0;
|
|
101141
101439
|
const pct = b.totalTimeMs / execTime * 100;
|
|
101142
|
-
const line = b.name.padEnd(nameW) +
|
|
101440
|
+
const line = b.name.padEnd(nameW) + pad2(String(b.callCount), 10) + pad2(fmt(b.totalTimeMs, 2), 13) + pad2(fmt(avg, 3), 11) + pad2(fmt(pct, 1) + "%", 9);
|
|
101143
101441
|
console.log(line);
|
|
101144
101442
|
}
|
|
101145
101443
|
}
|
|
101146
101444
|
if (builtins.length > 0) {
|
|
101147
101445
|
const nameW = Math.max(20, ...builtins.map((b) => b.name.length)) + 2;
|
|
101148
|
-
const header = "Builtin".padEnd(nameW) +
|
|
101446
|
+
const header = "Builtin".padEnd(nameW) + pad2("Interp", 10) + pad2("Fallback", 10) + pad2("JIT", 10) + pad2("Self (ms)", 13) + pad2("% Exec", 9);
|
|
101149
101447
|
console.log("\nBuiltin functions (call counts by source):");
|
|
101150
101448
|
console.log(header);
|
|
101151
101449
|
console.log("\u2500".repeat(header.length));
|
|
101152
101450
|
for (const b of builtins) {
|
|
101153
101451
|
const totalTime = b.fallback.totalTimeMs + b.interp.totalTimeMs + b.jit.totalTimeMs;
|
|
101154
101452
|
const pct = totalTime / execTime * 100;
|
|
101155
|
-
const line = b.name.padEnd(nameW) +
|
|
101453
|
+
const line = b.name.padEnd(nameW) + pad2(String(b.interp.callCount), 10) + pad2(String(b.fallback.callCount), 10) + pad2(String(b.jit.callCount), 10) + pad2(fmt(totalTime, 2), 13) + pad2(fmt(pct, 1) + "%", 9);
|
|
101156
101454
|
console.log(line);
|
|
101157
101455
|
}
|
|
101158
101456
|
} else {
|
|
@@ -101162,13 +101460,13 @@ function cmdShowProfile(args) {
|
|
|
101162
101460
|
if (hotLoops.length > 0) {
|
|
101163
101461
|
hotLoops.sort((a, b) => b.totalTimeMs - a.totalTimeMs);
|
|
101164
101462
|
const locW = Math.max(20, ...hotLoops.map((l) => `${l.file}:${l.line}`.length)) + 2;
|
|
101165
|
-
const header = "Location".padEnd(locW) +
|
|
101463
|
+
const header = "Location".padEnd(locW) + pad2("Kind", 8) + pad2("Calls", 8) + pad2("Max Iters", 12) + pad2("Total (ms)", 13);
|
|
101166
101464
|
console.log("\nInterpreted loops (>1000 iterations):");
|
|
101167
101465
|
console.log(header);
|
|
101168
101466
|
console.log("\u2500".repeat(header.length));
|
|
101169
101467
|
for (const l of hotLoops) {
|
|
101170
101468
|
const loc = `${l.file}:${l.line}`;
|
|
101171
|
-
const line = loc.padEnd(locW) +
|
|
101469
|
+
const line = loc.padEnd(locW) + pad2(l.kind, 8) + pad2(String(l.callCount ?? 1), 8) + pad2(String(l.iterations), 12) + pad2(fmt(l.totalTimeMs ?? 0, 2), 13);
|
|
101172
101470
|
console.log(line);
|
|
101173
101471
|
}
|
|
101174
101472
|
}
|
|
@@ -101230,7 +101528,12 @@ async function main() {
|
|
|
101230
101528
|
case "run-tests": {
|
|
101231
101529
|
const testOpts = parseOptions(rest);
|
|
101232
101530
|
const dir = testOpts.positional.length > 0 ? testOpts.positional[0] : join7(packageDir, "numbl_test_scripts");
|
|
101233
|
-
await runTests(
|
|
101531
|
+
await runTests(
|
|
101532
|
+
dir,
|
|
101533
|
+
testOpts.optimization,
|
|
101534
|
+
testOpts.fastMath,
|
|
101535
|
+
testOpts.noNative
|
|
101536
|
+
);
|
|
101234
101537
|
break;
|
|
101235
101538
|
}
|
|
101236
101539
|
case "build-addon":
|