numbl 0.4.12 → 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.
Files changed (30) hide show
  1. package/dist-browser/browser.js +1 -1
  2. package/dist-browser/numbl-core/fileIOAdapter.d.ts +4 -0
  3. package/dist-browser/numbl-core/native/lapack-bridge.d.ts +1 -1
  4. package/dist-browser/numbl-core/native/wasm-lapack-bridge.d.ts +114 -0
  5. package/dist-browser/numbl-core/native/wasm-lapack-browser.d.ts +34 -0
  6. package/dist-browser/numbl-core/runtime/datetime-format.d.ts +10 -0
  7. package/dist-browser/numbl-core/runtime/display.d.ts +5 -1
  8. package/dist-browser/numbl-core/runtime/index.d.ts +1 -1
  9. package/dist-browser/numbl-core/version.d.ts +1 -1
  10. package/dist-browser/vfs/BrowserFileIOAdapter.d.ts +1 -0
  11. package/dist-cli/cli.js +433 -130
  12. package/dist-lib/cli-fileio.d.ts +62 -0
  13. package/dist-lib/cli-scan.d.ts +6 -0
  14. package/dist-lib/cli-system.d.ts +13 -0
  15. package/dist-lib/lib.js +367 -72
  16. package/dist-lib/node.d.ts +30 -0
  17. package/dist-lib/node.js +829 -0
  18. package/dist-lib/numbl-core/fileIOAdapter.d.ts +4 -0
  19. package/dist-lib/numbl-core/native/lapack-bridge.d.ts +1 -1
  20. package/dist-lib/numbl-core/native/wasm-lapack-bridge.d.ts +114 -0
  21. package/dist-lib/numbl-core/native/wasm-lapack-browser.d.ts +34 -0
  22. package/dist-lib/numbl-core/runtime/datetime-format.d.ts +10 -0
  23. package/dist-lib/numbl-core/runtime/display.d.ts +5 -1
  24. package/dist-lib/numbl-core/runtime/index.d.ts +1 -1
  25. package/dist-lib/numbl-core/version.d.ts +1 -1
  26. package/dist-lib/vfs/BrowserFileIOAdapter.d.ts +1 -0
  27. package/dist-site-viewer/assets/{index-CGE1_vZ-.js → index-C2ItFYSf.js} +322 -322
  28. package/dist-site-viewer/assets/{numbl-worker-DddtCPW_.js → numbl-worker-CtfdLxJh.js} +114 -102
  29. package/dist-site-viewer/index.html +1 -1
  30. package/package.json +6 -2
package/dist-lib/lib.js CHANGED
@@ -819,6 +819,114 @@ var valuesAreEqual = (a, b) => {
819
819
  }
820
820
  };
821
821
 
822
+ // src/numbl-core/runtime/datetime-format.ts
823
+ var MONTH_ABBR = [
824
+ "Jan",
825
+ "Feb",
826
+ "Mar",
827
+ "Apr",
828
+ "May",
829
+ "Jun",
830
+ "Jul",
831
+ "Aug",
832
+ "Sep",
833
+ "Oct",
834
+ "Nov",
835
+ "Dec"
836
+ ];
837
+ var MONTH_FULL = [
838
+ "January",
839
+ "February",
840
+ "March",
841
+ "April",
842
+ "May",
843
+ "June",
844
+ "July",
845
+ "August",
846
+ "September",
847
+ "October",
848
+ "November",
849
+ "December"
850
+ ];
851
+ function pad(n, width) {
852
+ return String(n).padStart(width, "0");
853
+ }
854
+ function formatDatetimePattern(pattern, year, month, day, hour, minute, second) {
855
+ const wholeSec = Math.floor(second);
856
+ const frac = second - wholeSec;
857
+ const monthIdx = Math.max(0, Math.min(11, Math.floor(month) - 1));
858
+ const formatToken = (c, n) => {
859
+ switch (c) {
860
+ case "y":
861
+ case "u":
862
+ if (n === 2) return pad(Math.floor(year) % 100, 2);
863
+ return pad(Math.floor(year), n);
864
+ case "M":
865
+ if (n === 1) return String(Math.floor(month));
866
+ if (n === 2) return pad(Math.floor(month), 2);
867
+ if (n === 3) return MONTH_ABBR[monthIdx];
868
+ return MONTH_FULL[monthIdx];
869
+ case "d":
870
+ return pad(Math.floor(day), n);
871
+ case "H":
872
+ return pad(Math.floor(hour), n);
873
+ case "h":
874
+ return pad(Math.floor(hour) % 12 || 12, n);
875
+ case "m":
876
+ return pad(Math.floor(minute), n);
877
+ case "s":
878
+ return pad(wholeSec, n);
879
+ case "S":
880
+ return pad(Math.floor(frac * Math.pow(10, n)), n);
881
+ case "a":
882
+ return hour < 12 ? "AM" : "PM";
883
+ default:
884
+ throw new RuntimeError(
885
+ `datetime: unsupported format token '${c.repeat(n)}' in '${pattern}'`
886
+ );
887
+ }
888
+ };
889
+ let out = "";
890
+ let i = 0;
891
+ while (i < pattern.length) {
892
+ const c = pattern[i];
893
+ if (c === "'") {
894
+ i++;
895
+ let lit = "";
896
+ let closed = false;
897
+ while (i < pattern.length) {
898
+ if (pattern[i] === "'") {
899
+ if (pattern[i + 1] === "'") {
900
+ lit += "'";
901
+ i += 2;
902
+ continue;
903
+ }
904
+ i++;
905
+ closed = true;
906
+ break;
907
+ }
908
+ lit += pattern[i++];
909
+ }
910
+ if (!closed && lit !== "")
911
+ throw new RuntimeError(
912
+ `datetime: unterminated quoted literal in format '${pattern}'`
913
+ );
914
+ out += lit === "" ? "'" : lit;
915
+ continue;
916
+ }
917
+ if (!/[a-zA-Z]/.test(c)) {
918
+ out += c;
919
+ i++;
920
+ continue;
921
+ }
922
+ let j = i;
923
+ while (j < pattern.length && pattern[j] === c) j++;
924
+ out += formatToken(c, j - i);
925
+ i = j;
926
+ }
927
+ return out;
928
+ }
929
+
822
930
  // src/numbl-core/runtime/display.ts
823
931
  function displayValue(v) {
824
932
  if (isRuntimeNumber(v)) {
@@ -1093,6 +1201,13 @@ function formatDatetimeOrDuration(v) {
1093
1201
  if (v.className === "duration") return formatDurationInstance(v);
1094
1202
  return null;
1095
1203
  }
1204
+ function textField(v, name) {
1205
+ const fv = v.fields.get(name);
1206
+ if (fv === void 0) return null;
1207
+ if (isRuntimeString(fv)) return fv;
1208
+ if (isRuntimeChar(fv)) return fv.value;
1209
+ return null;
1210
+ }
1096
1211
  function formatDatetimeInstance(v) {
1097
1212
  const year = numField(v, "Year");
1098
1213
  const month = numField(v, "Month");
@@ -1102,6 +1217,10 @@ function formatDatetimeInstance(v) {
1102
1217
  const second = numField(v, "Second");
1103
1218
  if (year === null || month === null || day === null || hour === null || minute === null || second === null)
1104
1219
  return null;
1220
+ const fmt = textField(v, "Format");
1221
+ if (fmt !== null && fmt !== "") {
1222
+ return formatDatetimePattern(fmt, year, month, day, hour, minute, second);
1223
+ }
1105
1224
  const mIdx = Math.max(0, Math.min(11, Math.floor(month) - 1));
1106
1225
  const mon = DATETIME_MONTH_ABBR[mIdx];
1107
1226
  const dd = String(Math.floor(day)).padStart(2, "0");
@@ -22321,8 +22440,8 @@ function sprintfFormat(fmt, args) {
22321
22440
  if (width > 0) {
22322
22441
  const padChar = zeroPad ? "0" : " ";
22323
22442
  const padLen = Math.max(0, width - sign.length - s.length);
22324
- const pad = padChar.repeat(padLen);
22325
- result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad + s : pad + sign + s;
22443
+ const pad2 = padChar.repeat(padLen);
22444
+ result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad2 + s : pad2 + sign + s;
22326
22445
  } else {
22327
22446
  result += sign + s;
22328
22447
  }
@@ -25046,6 +25165,17 @@ function indexIntoRTValue(base, indices) {
25046
25165
  return base.elements[i];
25047
25166
  }
25048
25167
  if (isRuntimeTensor(idx)) {
25168
+ if (idx._isLogical) {
25169
+ const newElements2 = [];
25170
+ for (let k = 0; k < idx.data.length; k++) {
25171
+ if (idx.data[k] !== 0) {
25172
+ if (k >= base.elements.length)
25173
+ throw new RuntimeError("Index exceeds struct array bounds");
25174
+ newElements2.push(base.elements[k]);
25175
+ }
25176
+ }
25177
+ return RTV.structArray(base.fieldNames, newElements2);
25178
+ }
25049
25179
  const newElements = [];
25050
25180
  for (let k = 0; k < idx.data.length; k++) {
25051
25181
  const i = Math.round(idx.data[k]) - 1;
@@ -38167,13 +38297,19 @@ registerIBuiltin({
38167
38297
  resolve: (argTypes) => {
38168
38298
  if (argTypes.length !== 1) return null;
38169
38299
  const a = argTypes[0];
38170
- if (a.kind !== "char" && a.kind !== "string" && a.kind !== "number" && a.kind !== "tensor" && a.kind !== "cell" && a.kind !== "unknown")
38300
+ 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
38301
+ // (or the generic "does not support these argument types" error).
38302
+ !(a.kind === "class_instance" && (a.className === "datetime" || a.className === "duration")))
38171
38303
  return null;
38172
38304
  return {
38173
38305
  outputTypes: [{ kind: "char" }],
38174
38306
  apply: (args) => {
38175
38307
  const v = args[0];
38176
38308
  if (isRuntimeChar(v)) return v;
38309
+ if (isRuntimeClassInstance(v)) {
38310
+ const s = formatDatetimeOrDuration(v);
38311
+ if (s !== null) return RTV.char(s);
38312
+ }
38177
38313
  if (isRuntimeString(v)) return RTV.char(v);
38178
38314
  if (isRuntimeNumber(v))
38179
38315
  return RTV.char(String.fromCharCode(Math.round(v)));
@@ -40561,7 +40697,7 @@ defineBuiltin({
40561
40697
  const result = invComplexJS(A.data, A.imag, n);
40562
40698
  return RTV.tensor(result.re, [n, n], result.im);
40563
40699
  }
40564
- const bridge = getEffectiveBridge("inv");
40700
+ const bridge = getEffectiveBridge("inv", "inv");
40565
40701
  return RTV.tensor(bridge.inv(toF64(A.data), n), [n, n]);
40566
40702
  }
40567
40703
  }
@@ -42908,6 +43044,16 @@ defineBuiltin({
42908
43044
  parseReshapeDims(args, 1);
42909
43045
  return v;
42910
43046
  }
43047
+ if (isRuntimeCell(v)) {
43048
+ const total = v.data.length;
43049
+ const s = parseReshapeDims(args, total);
43050
+ while (s.length > 2 && s[s.length - 1] === 1) s.pop();
43051
+ if (s.length > 2)
43052
+ throw new RuntimeError("reshape: cell arrays must be 2-D");
43053
+ const nr = s[0];
43054
+ const nc = s.length >= 2 ? s[1] : 1;
43055
+ return RTV.cell(v.data.slice(), [nr, nc]);
43056
+ }
42911
43057
  if (isRuntimeClassInstanceArray(v)) {
42912
43058
  const total = v.elements.length;
42913
43059
  const s = parseReshapeDims(args, total);
@@ -48654,6 +48800,32 @@ function datetimeFromUtcMs(ms) {
48654
48800
  function datetimeFromDatenum(dn) {
48655
48801
  return datetimeFromUtcMs((dn - MATLAB_EPOCH_DAYS) * 864e5);
48656
48802
  }
48803
+ function withTimeZoneFormat(dt, timeZone, format) {
48804
+ if (timeZone === void 0 && format === void 0) return dt;
48805
+ const fields = new Map(dt.fields);
48806
+ if (timeZone !== void 0) fields.set("TimeZone", RTV.char(timeZone));
48807
+ if (format !== void 0) fields.set("Format", RTV.char(format));
48808
+ return new RuntimeClassInstance("datetime", fields, false);
48809
+ }
48810
+ function todayParts(offsetDays, utc) {
48811
+ const now = /* @__PURE__ */ new Date();
48812
+ if (utc) {
48813
+ const d2 = new Date(
48814
+ Date.UTC(
48815
+ now.getUTCFullYear(),
48816
+ now.getUTCMonth(),
48817
+ now.getUTCDate() + offsetDays
48818
+ )
48819
+ );
48820
+ return [d2.getUTCFullYear(), d2.getUTCMonth() + 1, d2.getUTCDate()];
48821
+ }
48822
+ const d = new Date(
48823
+ now.getFullYear(),
48824
+ now.getMonth(),
48825
+ now.getDate() + offsetDays
48826
+ );
48827
+ return [d.getFullYear(), d.getMonth() + 1, d.getDate()];
48828
+ }
48657
48829
  function makeDuration(totalSeconds) {
48658
48830
  const fields = /* @__PURE__ */ new Map([
48659
48831
  ["Seconds", RTV.num(totalSeconds)]
@@ -48703,9 +48875,10 @@ registerIBuiltin({
48703
48875
  "t = datetime('now' | 'today' | 'yesterday' | 'tomorrow')",
48704
48876
  "t = datetime(Y, M, D)",
48705
48877
  "t = datetime(Y, M, D, H, MI, S)",
48706
- "t = datetime(X, 'ConvertFrom', dateType)"
48878
+ "t = datetime(X, 'ConvertFrom', dateType)",
48879
+ "t = datetime(..., 'TimeZone', tz, 'Format', fmt)"
48707
48880
  ],
48708
- description: "Create a datetime value. Supported dateType values for ConvertFrom: 'datenum', 'posixtime', 'excel', 'excel1904'."
48881
+ 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."
48709
48882
  },
48710
48883
  resolve: () => ({
48711
48884
  outputTypes: [
@@ -48717,75 +48890,83 @@ registerIBuiltin({
48717
48890
  }
48718
48891
  ],
48719
48892
  apply: (args) => {
48720
- if (args.length === 0) {
48721
- return datetimeFromDate(/* @__PURE__ */ new Date());
48893
+ let timeZone;
48894
+ let format;
48895
+ let positional = args;
48896
+ while (positional.length >= 2) {
48897
+ const name = argToString(positional[positional.length - 2]);
48898
+ if (name === null) break;
48899
+ const lc = name.toLowerCase();
48900
+ if (lc !== "timezone" && lc !== "format") break;
48901
+ const value = argToString(positional[positional.length - 1]);
48902
+ if (value === null)
48903
+ throw new RuntimeError(`datetime: ${name} value must be text`);
48904
+ if (lc === "timezone") timeZone = value;
48905
+ else format = value;
48906
+ positional = positional.slice(0, -2);
48907
+ }
48908
+ const tzLc = timeZone?.toLowerCase();
48909
+ if (tzLc !== void 0 && tzLc !== "" && tzLc !== "local" && tzLc !== "utc") {
48910
+ throw new RuntimeError(
48911
+ `datetime: unsupported TimeZone '${timeZone}' (supported: '', 'local', 'UTC')`
48912
+ );
48722
48913
  }
48723
- if (args.length === 1) {
48724
- const s = argToString(args[0]);
48914
+ const utc = tzLc === "utc";
48915
+ const finish = (dt) => withTimeZoneFormat(dt, timeZone, format);
48916
+ if (positional.length === 0) {
48917
+ return finish(
48918
+ utc ? datetimeFromUtcMs(Date.now()) : datetimeFromDate(/* @__PURE__ */ new Date())
48919
+ );
48920
+ }
48921
+ if (positional.length === 1) {
48922
+ const s = argToString(positional[0]);
48725
48923
  if (s !== null) {
48726
- const now = /* @__PURE__ */ new Date();
48727
48924
  const lc = s.toLowerCase();
48728
- if (lc === "now") return datetimeFromDate(now);
48729
- if (lc === "today") {
48730
- return makeDatetime(
48731
- now.getFullYear(),
48732
- now.getMonth() + 1,
48733
- now.getDate(),
48734
- 0,
48735
- 0,
48736
- 0
48925
+ if (lc === "now") {
48926
+ return finish(
48927
+ utc ? datetimeFromUtcMs(Date.now()) : datetimeFromDate(/* @__PURE__ */ new Date())
48737
48928
  );
48738
48929
  }
48739
- if (lc === "yesterday" || lc === "tomorrow") {
48740
- const d = new Date(
48741
- now.getFullYear(),
48742
- now.getMonth(),
48743
- now.getDate() + (lc === "tomorrow" ? 1 : -1)
48744
- );
48745
- return makeDatetime(
48746
- d.getFullYear(),
48747
- d.getMonth() + 1,
48748
- d.getDate(),
48749
- 0,
48750
- 0,
48751
- 0
48752
- );
48930
+ if (lc === "today" || lc === "yesterday" || lc === "tomorrow") {
48931
+ const offset = lc === "tomorrow" ? 1 : lc === "yesterday" ? -1 : 0;
48932
+ const [Y, M, D] = todayParts(offset, utc);
48933
+ return finish(makeDatetime(Y, M, D, 0, 0, 0));
48753
48934
  }
48754
48935
  throw new RuntimeError(
48755
48936
  `datetime: unrecognized relative-day string '${s}'`
48756
48937
  );
48757
48938
  }
48758
48939
  }
48759
- if (args.length === 3) {
48760
- const flag = argToString(args[1]);
48761
- const kind = argToString(args[2]);
48940
+ if (positional.length === 3) {
48941
+ const flag = argToString(positional[1]);
48942
+ const kind = argToString(positional[2]);
48762
48943
  if (flag !== null && flag.toLowerCase() === "convertfrom") {
48763
48944
  if (kind === null)
48764
48945
  throw new RuntimeError("datetime: dateType must be text");
48765
- const x = toNumber(args[0]);
48946
+ const x = toNumber(positional[0]);
48766
48947
  const k = kind.toLowerCase();
48767
- if (k === "datenum") return datetimeFromDatenum(x);
48768
- if (k === "posixtime") return datetimeFromUtcMs(x * 1e3);
48948
+ if (k === "datenum") return finish(datetimeFromDatenum(x));
48949
+ if (k === "posixtime") return finish(datetimeFromUtcMs(x * 1e3));
48769
48950
  if (k === "excel") {
48770
- return datetimeFromUtcMs((x - 25569) * 864e5);
48951
+ return finish(datetimeFromUtcMs((x - 25569) * 864e5));
48771
48952
  }
48772
48953
  if (k === "excel1904") {
48773
- return datetimeFromUtcMs((x - 24107) * 864e5);
48954
+ return finish(datetimeFromUtcMs((x - 24107) * 864e5));
48774
48955
  }
48775
48956
  throw new RuntimeError(
48776
48957
  `datetime: unsupported ConvertFrom type '${kind}'`
48777
48958
  );
48778
48959
  }
48779
48960
  }
48780
- if (args.length === 3 || args.length === 6 || args.length === 7) {
48781
- const Y = toNumber(args[0]);
48782
- const M = toNumber(args[1]);
48783
- const D = toNumber(args[2]);
48784
- const H2 = args.length >= 6 ? toNumber(args[3]) : 0;
48785
- const MI = args.length >= 6 ? toNumber(args[4]) : 0;
48786
- const S = args.length >= 6 ? toNumber(args[5]) : 0;
48787
- const MS = args.length >= 7 ? toNumber(args[6]) : 0;
48788
- return makeDatetime(Y, M, D, H2, MI, S + MS / 1e3);
48961
+ if (positional.length === 3 || positional.length === 6 || positional.length === 7) {
48962
+ const Y = toNumber(positional[0]);
48963
+ const M = toNumber(positional[1]);
48964
+ const D = toNumber(positional[2]);
48965
+ const H2 = positional.length >= 6 ? toNumber(positional[3]) : 0;
48966
+ const MI = positional.length >= 6 ? toNumber(positional[4]) : 0;
48967
+ const S = positional.length >= 6 ? toNumber(positional[5]) : 0;
48968
+ const MS = positional.length >= 7 ? toNumber(positional[6]) : 0;
48969
+ return finish(makeDatetime(Y, M, D, H2, MI, S + MS / 1e3));
48789
48970
  }
48790
48971
  throw new RuntimeError(
48791
48972
  `datetime: unsupported argument pattern (nargin=${args.length})`
@@ -56090,6 +56271,7 @@ var SPECIAL_BUILTIN_NAMES = [
56090
56271
  "copyfile",
56091
56272
  "fileattrib",
56092
56273
  "unzip",
56274
+ "zip",
56093
56275
  "dir",
56094
56276
  "warning",
56095
56277
  "input",
@@ -57202,6 +57384,26 @@ function registerSpecialBuiltins(rt) {
57202
57384
  }
57203
57385
  return void 0;
57204
57386
  });
57387
+ registerSpecial("zip", (nargout, args) => {
57388
+ const io = requireFileIO();
57389
+ if (!io.zip)
57390
+ throw new RuntimeError("zip is not available in this environment");
57391
+ const margs = args.map((a) => ensureRuntimeValue(a));
57392
+ if (margs.length < 2)
57393
+ throw new RuntimeError("zip requires at least 2 arguments");
57394
+ let zipfilename = toString(margs[0]);
57395
+ const base = zipfilename.split(/[/\\]/).pop() ?? zipfilename;
57396
+ if (!base.includes(".")) zipfilename += ".zip";
57397
+ const fnames = margs[1];
57398
+ const filenames = isRuntimeCell(fnames) ? fnames.data.map((v) => toString(ensureRuntimeValue(v))) : [toString(fnames)];
57399
+ const rootdir = margs.length >= 3 ? toString(margs[2]) : ".";
57400
+ const entryNames = io.zip(zipfilename, filenames, rootdir);
57401
+ if (nargout >= 1) {
57402
+ const cellData = entryNames.map((f) => RTV.char(f));
57403
+ return RTV.cell(cellData, [1, cellData.length]);
57404
+ }
57405
+ return void 0;
57406
+ });
57205
57407
  registerSpecial("dir", (nargout, args) => {
57206
57408
  const io = requireFileIO();
57207
57409
  if (!io.listDir)
@@ -61069,8 +61271,8 @@ function padExtent(e, tight) {
61069
61271
  return [min2, max2];
61070
61272
  }
61071
61273
  if (tight) return [min2, max2];
61072
- const pad = (max2 - min2) * 0.05;
61073
- return [min2 - pad, max2 + pad];
61274
+ const pad2 = (max2 - min2) * 0.05;
61275
+ return [min2 - pad2, max2 + pad2];
61074
61276
  }
61075
61277
  function applyExplicit(auto, explicit) {
61076
61278
  if (!explicit) return auto;
@@ -65895,6 +66097,12 @@ function evalMember(expr, nargout) {
65895
66097
  }
65896
66098
  }
65897
66099
  const base = this.evalExpr(expr.base);
66100
+ const baseRv = ensureRuntimeValue(base);
66101
+ if (isRuntimeStructArray(baseRv) && baseRv.elements.length !== 1) {
66102
+ return baseRv.elements.map(
66103
+ (el) => ensureRuntimeValue(this.rt.getMember(el, expr.name))
66104
+ );
66105
+ }
65898
66106
  return this.rt.getMember(base, expr.name);
65899
66107
  }
65900
66108
  function tryExtractDottedName(expr) {
@@ -66106,12 +66314,31 @@ function evalCellLiteral(expr) {
66106
66314
  }
66107
66315
  return RTV.cell(elements2, [1, elements2.length]);
66108
66316
  }
66109
- const numRows = expr.rows.length;
66110
- const numCols = expr.rows[0].length;
66317
+ const rowValues = expr.rows.map((row) => {
66318
+ const vals = [];
66319
+ for (const e of row) {
66320
+ const v = this.evalExpr(e);
66321
+ if (Array.isArray(v)) {
66322
+ for (const elem of v) vals.push(ensureRuntimeValue(elem));
66323
+ } else {
66324
+ vals.push(ensureRuntimeValue(v));
66325
+ }
66326
+ }
66327
+ return vals;
66328
+ });
66329
+ const numRows = rowValues.length;
66330
+ const numCols = rowValues[0].length;
66331
+ for (const rv of rowValues) {
66332
+ if (rv.length !== numCols) {
66333
+ throw new RuntimeError(
66334
+ "Cell array rows must have the same number of columns"
66335
+ );
66336
+ }
66337
+ }
66111
66338
  const elements = [];
66112
66339
  for (let c = 0; c < numCols; c++) {
66113
66340
  for (let r = 0; r < numRows; r++) {
66114
- elements.push(ensureRuntimeValue(this.evalExpr(expr.rows[r][c])));
66341
+ elements.push(rowValues[r][c]);
66115
66342
  }
66116
66343
  }
66117
66344
  return RTV.cell(elements, [numRows, numCols]);
@@ -70586,8 +70813,8 @@ function mtoc2_sprintf_format(fmt, args) {
70586
70813
  if (width > 0) {
70587
70814
  const padChar = zeroPad ? "0" : " ";
70588
70815
  const padLen = Math.max(0, width - sign.length - s.length);
70589
- const pad = padChar.repeat(padLen);
70590
- result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad + s : pad + sign + s;
70816
+ const pad2 = padChar.repeat(padLen);
70817
+ result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad2 + s : pad2 + sign + s;
70591
70818
  } else {
70592
70819
  result += sign + s;
70593
70820
  }
@@ -70872,8 +71099,8 @@ function disp_complex_slice(re, im, offset, rows, cols) {
70872
71099
  for (let c = 0; c < cols; c++) {
70873
71100
  const idx = r + c * rows;
70874
71101
  const cell = cells[idx];
70875
- const pad = colWidths[c] - cell.length;
70876
- for (let i = 0; i < pad; i++) line += " ";
71102
+ const pad2 = colWidths[c] - cell.length;
71103
+ for (let i = 0; i < pad2; i++) line += " ";
70877
71104
  line += cell;
70878
71105
  if (c < cols - 1) line += " ";
70879
71106
  }
@@ -72285,6 +72512,14 @@ function mtoc2_tensor_mtimes_real(a, b) {
72285
72512
  `mtoc2_tensor_mtimes_real: inner dimensions disagree (${k} vs ${k2})`
72286
72513
  );
72287
72514
  }
72515
+ if (typeof $matmulAccel === "function") {
72516
+ const accel = $matmulAccel(a.data, m, k, b.data, n);
72517
+ if (accel) {
72518
+ const acc = mtoc2_tensor_alloc(m, n);
72519
+ acc.data.set(accel);
72520
+ return acc;
72521
+ }
72522
+ }
72288
72523
  const r = mtoc2_tensor_alloc(m, n);
72289
72524
  for (let j = 0; j < n; j++) {
72290
72525
  for (let i = 0; i < m; i++) {
@@ -73496,7 +73731,7 @@ var JS_SNIPPETS = {
73496
73731
  "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",
73497
73732
  "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",
73498
73733
  "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',
73499
- "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',
73734
+ "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',
73500
73735
  "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",
73501
73736
  "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",
73502
73737
  "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",
@@ -82065,9 +82300,9 @@ function tileExact(src, padShape2, padReps) {
82065
82300
  }
82066
82301
  return out;
82067
82302
  }
82068
- function padTo(arr, pad, len) {
82303
+ function padTo(arr, pad2, len) {
82069
82304
  const out = arr.slice();
82070
- while (out.length < len) out.push(pad);
82305
+ while (out.length < len) out.push(pad2);
82071
82306
  return out;
82072
82307
  }
82073
82308
  function trimTrailingOnes(shape) {
@@ -93152,7 +93387,7 @@ var VirtualFileSystem = class {
93152
93387
  };
93153
93388
 
93154
93389
  // src/vfs/BrowserFileIOAdapter.ts
93155
- import { unzipSync } from "fflate";
93390
+ import { unzipSync, zipSync } from "fflate";
93156
93391
  var TEXT_DECODER = new TextDecoder("utf-8");
93157
93392
  var TEXT_ENCODER = new TextEncoder();
93158
93393
  var READ_CHUNK_SIZE = 8192;
@@ -93470,6 +93705,57 @@ var BrowserFileIOAdapter = class {
93470
93705
  }
93471
93706
  return extracted;
93472
93707
  }
93708
+ zip(zipfilename, filenames, rootDir) {
93709
+ const root = this.vfs.normalizePath(rootDir);
93710
+ const dest = this.vfs.normalizePath(zipfilename);
93711
+ const entries = {};
93712
+ const names = [];
93713
+ const toEntryName = (abs2) => {
93714
+ const prefix = root === "/" ? "/" : root + "/";
93715
+ if (!abs2.startsWith(prefix)) return abs2.slice(abs2.lastIndexOf("/") + 1);
93716
+ return abs2.slice(prefix.length);
93717
+ };
93718
+ const addFile = (abs2) => {
93719
+ const name = toEntryName(abs2);
93720
+ entries[name] = this.vfs.readFile(abs2);
93721
+ names.push(name);
93722
+ };
93723
+ const addDir = (absDir) => {
93724
+ for (const entry of this.vfs.listDir(absDir)) {
93725
+ if (entry.name === "." || entry.name === "..") continue;
93726
+ const abs2 = absDir + "/" + entry.name;
93727
+ if (entry.isdir) addDir(abs2);
93728
+ else addFile(abs2);
93729
+ }
93730
+ };
93731
+ const addPath = (abs2) => {
93732
+ const type = this.vfs.exists(abs2);
93733
+ if (type === null) throw new Error(`zip: cannot find '${abs2}'`);
93734
+ if (type === "dir") addDir(abs2);
93735
+ else addFile(abs2);
93736
+ };
93737
+ for (const f of filenames) {
93738
+ const p2 = f.replace(/\\/g, "/");
93739
+ const abs2 = p2.startsWith("/") ? this.vfs.normalizePath(p2) : this.vfs.normalizePath(root + "/" + p2);
93740
+ const last = p2.split("/").pop() ?? p2;
93741
+ if (last.includes("*") || last.includes("?")) {
93742
+ const lastSlash = abs2.lastIndexOf("/");
93743
+ const dir = lastSlash > 0 ? abs2.slice(0, lastSlash) : "/";
93744
+ const re = new RegExp(
93745
+ "^" + last.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$"
93746
+ );
93747
+ if (this.vfs.exists(dir) !== "dir") continue;
93748
+ for (const entry of this.vfs.listDir(dir)) {
93749
+ if (entry.name === "." || entry.name === "..") continue;
93750
+ if (re.test(entry.name)) addPath(dir + "/" + entry.name);
93751
+ }
93752
+ } else {
93753
+ addPath(abs2);
93754
+ }
93755
+ }
93756
+ this.vfs.writeFile(dest, zipSync(entries));
93757
+ return names;
93758
+ }
93473
93759
  /** Get the VFS changes for syncing back to the main thread. */
93474
93760
  getChanges() {
93475
93761
  for (const [, entry] of this.openFiles) {
@@ -93552,21 +93838,30 @@ var BrowserFileIOAdapter = class {
93552
93838
  );
93553
93839
  }
93554
93840
  listDirRecursive(pattern) {
93555
- const idx = pattern.indexOf("**");
93556
- let baseDir = pattern.slice(0, idx);
93841
+ const norm2 = pattern.replace(/\\/g, "/");
93842
+ const idx = norm2.indexOf("**");
93843
+ let baseDir = norm2.slice(0, idx);
93557
93844
  if (baseDir.endsWith("/")) baseDir = baseDir.slice(0, -1);
93558
93845
  if (!baseDir) baseDir = ".";
93846
+ const absBase = this.vfs.normalizePath(baseDir);
93847
+ if (this.vfs.exists(absBase) !== "dir") return [];
93848
+ const suffix = norm2.slice(idx);
93849
+ const DIRS = "\0";
93850
+ const ANY = "";
93851
+ const re = new RegExp(
93852
+ "^" + suffix.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, DIRS).replace(/\*\*/g, ANY).replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(new RegExp(DIRS, "g"), "(?:.*/)?").replace(new RegExp(ANY, "g"), ".*") + "$"
93853
+ );
93559
93854
  const results = [];
93560
- const walkDir = (dir) => {
93561
- const entries = this.vfs.listDir(dir);
93562
- results.push(...entries);
93563
- for (const entry of entries) {
93855
+ const walkDir = (dir, rel) => {
93856
+ const relPrefix = rel ? rel + "/" : "";
93857
+ for (const entry of this.vfs.listDir(dir)) {
93858
+ if (re.test(relPrefix + entry.name)) results.push(entry);
93564
93859
  if (entry.isdir && entry.name !== "." && entry.name !== "..") {
93565
- walkDir(entry.folder + "/" + entry.name);
93860
+ walkDir(entry.folder + "/" + entry.name, relPrefix + entry.name);
93566
93861
  }
93567
93862
  }
93568
93863
  };
93569
- walkDir(this.vfs.normalizePath(baseDir));
93864
+ walkDir(absBase, "");
93570
93865
  return results;
93571
93866
  }
93572
93867
  };