metanum 1.4.0 → 2.0.1

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/metanum.js CHANGED
@@ -1,14 +1,13 @@
1
- //Author: dlsdl v1.4
2
- //Support hyper operation >MSI and fix format-metanum bugs
1
+ //Author: dlsdl v2.0
2
+ //v2.0: Add hyper-root & hyper-log, hardy function, fractional hyperoperation inputs, fix BEAF operation level and format
3
3
  //Code snippets and templates from OmegaNum.js
4
4
 
5
5
  ;(function (globalScope) {
6
6
  "use strict";
7
7
 
8
8
  var MetaNum = {
9
- maxRows: 100,
10
- maxCols: 100,
11
- maxArrow: Number.MAX_SAFE_INTEGER,
9
+ maxRows: 20,
10
+ maxCols: 20,
12
11
  serializeMode: 0,
13
12
  debug: 0
14
13
  },
@@ -43,13 +42,14 @@
43
42
  R.NaN = NaN;
44
43
  R.POSITIVE_INFINITY = Infinity;
45
44
  R.NEGATIVE_INFINITY = -Infinity;
45
+ R.infinity = Infinity; // alias of POSITIVE_INFINITY
46
46
  R.E_MAX_SAFE_INTEGER = "E" + MAX_SAFE_INTEGER;
47
47
  R.EE_MAX_SAFE_INTEGER = "EE" + MAX_SAFE_INTEGER;
48
48
  R.TETRATED_MAX_SAFE_INTEGER = "F" + MAX_SAFE_INTEGER;
49
49
  R.PENTATED_MAX_SAFE_INTEGER = "G" + MAX_SAFE_INTEGER;
50
50
  R.TRITRI = "[[3638334640023.7783, 7625597484984]]";
51
51
  R.GRAHAMS_NUMBER = "[[3638334640023.7783,7625597484984,0,1],[63,0,1]]";
52
- R.TERR3 = "[[10],[1,374389,2],[1,374387,2],[1,374385,2],[1,374383,2],[1,374381,2],[1,374379,2],[1,374377,2],[1,374375,2],[1,374373,2],[1,374371,2]]"; //https://www.bilibili.com/video/BV1X94y1n7D1
52
+ R.TERR3 = "[[10],[1,374389,2],[1,374387,2],[1,374385,2],[1,374383,2],[1,374381,2],[1,374379,2],[1,374377,2],[1,374375,2],[1,374373,2],[1,374371,2]]";
53
53
  R.QqQe308 = "QqQe308";
54
54
 
55
55
  function cmpArr(a, b) {
@@ -352,12 +352,40 @@
352
352
  }
353
353
 
354
354
  if (x.array.length > MetaNum.maxRows) {
355
- x.array = x.array.slice(x.array.length - MetaNum.maxRows);
355
+ // Truncation keeps the base row and the largest maxRows-1 ordinal rows;
356
+ // only the smallest ordinal rows are sacrificed. The transient
357
+ // _ordTrunc flag lets the hyperoperation entry points detect the
358
+ // overflow and apply the issues.md truncation marker (array[1][0]+1,
359
+ // array[0] = [10]) — clone() does not copy it.
360
+ x._ordTrunc = true;
361
+ x.array = [x.array[0]].concat(x.array.slice(x.array.length - (MetaNum.maxRows - 1)));
356
362
  b = true;
357
363
  }
358
364
 
365
+ // r0 wider than maxCols: convert the overflow levels (>= maxCols) into
366
+ // finite-level ordinal rows [count, level] instead of dropping them.
367
+ // Deferred until the r0 cascade has settled so that high-level counts
368
+ // can still decompose into lower levels (e.g. "Z10" must fully expand
369
+ // into its level chain before levels >= maxCols freeze into rows).
370
+ if (r0.length > MetaNum.maxCols && !b) {
371
+ var r0Settled = !(r0[0] > MAX_SAFE_INTEGER)
372
+ && !(r0[1] && r0[0] < MAX_E)
373
+ && !(!r0[1] && r0.length > 2);
374
+ if (r0Settled) {
375
+ var pushedOverflow = false;
376
+ for (var ov = MetaNum.maxCols; ov < r0.length; ov++) {
377
+ if (r0[ov] > 0) {
378
+ x.array.push([r0[ov], ov]);
379
+ r0[ov] = 0;
380
+ pushedOverflow = true;
381
+ }
382
+ }
383
+ if (pushedOverflow) b = true;
384
+ }
385
+ }
386
+
359
387
  for (var i = 0; i < x.array.length; i++) {
360
- if (x.array[i].length > MetaNum.maxCols) {
388
+ if (i > 0 && x.array[i].length > MetaNum.maxCols) {
361
389
  x.array[i] = x.array[i].slice(0, MetaNum.maxCols);
362
390
  b = true;
363
391
  }
@@ -773,14 +801,6 @@
773
801
  x.array[0].length === 1 && isFinite(x.array[0][0]);
774
802
  }
775
803
 
776
- function computeLayer(arr) {
777
- // Layer represents ω^ nesting level above the ordinal represented by the array.
778
- // For all normal ordinal operations (up to ω^(maxcols-1) level), layer is 0.
779
- // Layer 1 = ω^(array ordinal), layer 2 = ω^ω^(array ordinal), etc.
780
- // Layer is managed explicitly by layerUp/layerDown, not computed from array.
781
- return 0;
782
- }
783
-
784
804
  function toNormalizedSign(s) {
785
805
  // Map sign=2/-2 to the corresponding normal sign for the array data
786
806
  return s === 2 ? 1 : s === -2 ? -1 : s;
@@ -794,7 +814,15 @@
794
814
  return new MetaNum([arr]);
795
815
  }
796
816
 
817
+ // Threshold values 10{n}val depend only on (n, val) and are only ever used
818
+ // in read-only comparisons — cache them: rebuilding an r0 of length n+1 on
819
+ // every arrow call cost ~1.8ms each (several per call, ~70% of the
820
+ // structured fast path).
821
+ var hyperLevelSafeCache = {};
797
822
  function hyperLevelSafe(n, val) {
823
+ var key = n + "|" + val;
824
+ var cached = hyperLevelSafeCache[key];
825
+ if (cached) return cached;
798
826
  var arr = new Array(n + 1);
799
827
  for (var i = 0; i <= n; i++) arr[i] = 0;
800
828
  arr[0] = val;
@@ -803,6 +831,7 @@
803
831
  MetaNum.maxCols = Math.max(oldMaxCols, n + 1);
804
832
  var r = new MetaNum([arr]);
805
833
  MetaNum.maxCols = oldMaxCols;
834
+ if (n >= 0 && n <= 100000) hyperLevelSafeCache[key] = r;
806
835
  return r;
807
836
  }
808
837
 
@@ -832,7 +861,6 @@
832
861
  // numbers (e.g. 10^16 stored as [[16,1]]) instead of Infinity. This is used
833
862
  // by hyperoperation functions (expande/multiexpande/powerexpande) to compute
834
863
  // iteration counts `count = y - 2` when y is a large-but-finite MetaNum.
835
- //
836
864
  // toNumber() returns Infinity whenever r0.length > 1 (E-notation) or the
837
865
  // array has ordinal rows, which is too conservative for count extraction:
838
866
  // 10^16 is a perfectly finite JS number. We only return Infinity for genuine
@@ -868,6 +896,11 @@
868
896
  if (x.isInfinite()) return x;
869
897
  if (other.isInfinite()) return other;
870
898
 
899
+ // Layer swallowing: an ω-tower plus a layer-0 value is the tower; two
900
+ // towers keep the larger one (ordinal addition, same layer).
901
+ var domAdd = layerDominant(x, other);
902
+ if (domAdd !== null) return domAdd.clone().normalize();
903
+
871
904
  // For simple numbers, use direct numeric addition
872
905
  if (isSimple(x) && isSimple(other)) {
873
906
  var directSum = x.toNumber() + other.toNumber();
@@ -973,6 +1006,11 @@
973
1006
 
974
1007
  if (x.max(other).gt(MetaNum.EE_MAX_SAFE_INTEGER)) return x.max(other);
975
1008
 
1009
+ // Layer swallowing: multiplying a tower (layer≥1) by any layer-0 value
1010
+ // leaves the tower unchanged; two towers keep the larger one.
1011
+ var domMul = layerDominant(x, other);
1012
+ if (domMul !== null) return domMul.clone().normalize();
1013
+
976
1014
  if (isSimple(x) && isSimple(other) && !isSmall(x) && !isSmall(other)) {
977
1015
  var nx = x.array[0][0];
978
1016
  var ny = other.array[0][0];
@@ -1795,11 +1833,243 @@
1795
1833
  return new MetaNum(x).pentate_root(height);
1796
1834
  };
1797
1835
 
1836
+ // Layer swallowing (README representation L17): a layer≥1 value is a
1837
+ // 10{ω^ω^…}10 tower and dominates every operation with a layer-0 operand
1838
+ // — the result keeps the tower's layer. Returns the dominating MetaNum,
1839
+ // or null when both operands carry the same layer>0.
1840
+ function layerDominant(a, b) {
1841
+ if (a.layer > 0 && b.layer === 0) return a;
1842
+ if (b.layer > 0 && a.layer === 0) return b;
1843
+ if (a.layer > b.layer) return a;
1844
+ if (b.layer > a.layer) return b;
1845
+ return null;
1846
+ }
1847
+
1848
+ // Fast construction of the diagonal chain D(L) = t{L}t for a plain finite
1849
+ // integer base t. The generic successor-rule recursion recomputes the whole
1850
+ // chain at every level (each level re-invokes t{n-1}(t)), which is ~O(n^3)
1851
+ // for plain diagonals (3{99}3 at maxCols=100 took ~5.5s). Unrolling rule 2
1852
+ // once builds the identical normalized array bottom-up:
1853
+ // D(1) = t{1}t ; D(n+1) = t{n}^{t-1}(t) = t{n}^{t-2}(D(n))
1854
+ // Each t{n}(D(n)) step is the engine's own structured-value fast path, so
1855
+ // the result is array-identical to the recursive evaluation, in O(L^2).
1856
+ function canFastDiagonal(t) {
1857
+ if (t.layer !== 0 || t.array.length !== 1) return false;
1858
+ var n = t.toNumber();
1859
+ if (!isFinite(n) || n < 1 || Math.floor(n) !== n) return false;
1860
+ return (n - 2) <= 1000;
1861
+ }
1862
+ function diagonalChain(t, L) {
1863
+ var repeat = Math.max(Math.floor(t.toNumber()) - 2, 0);
1864
+ var r = t.pow(t); // D(1) = t{1}t
1865
+ for (var n = 1; n < L; n++) {
1866
+ // D(n+1) = t{n}^{repeat}(D(n)) with repeat = t-2.
1867
+ // n=1,2 keep pow/tetr (their own structuralization). For n>=3 every
1868
+ // step is the engine's structured-value fast path verbatim
1869
+ // (0 + D(n), then one count at column n, normalize) — do it directly
1870
+ // instead of re-entering arrow() (whose threshold guards cost ~7ms).
1871
+ for (var k = 0; k < repeat; k++) {
1872
+ if (n >= 3) {
1873
+ var j = MetaNum.ZERO.add(r);
1874
+ if (j.array.length === 1) {
1875
+ while (j.array[0].length <= n) j.array[0].push(0);
1876
+ j.array[0][n] = (j.array[0][n] || 0) + 1;
1877
+ }
1878
+ j.normalize();
1879
+ r = j;
1880
+ } else {
1881
+ r = t.arrow(n)(r);
1882
+ }
1883
+ }
1884
+ }
1885
+ return r;
1886
+ }
1887
+
1888
+ // Convert a structured raw-application COUNT C at finite operation level n
1889
+ // ({n}^C(10)) to the dlsdl Aa-band smooth argument α (v = 10{n+2}(α)),
1890
+ // α ∈ [2,10). A count given canonically as 10{k}(t), t∈[1,10]:
1891
+ // t = 10 rewrites exactly to α-anchor 2 one level up (10{k}10=10{k+1}2);
1892
+ // each further level promotion is the geometric smooth-log step
1893
+ // f → 1 + log10(f) (the same step the low-level polarize produces).
1894
+ // Matches dlsdl rule (iii)-(v): {99}^{10{93}10}(10) = 10{101}(2.001607…).
1895
+ // Raw application COUNT C at operation level n ({n}^C(10)) -> the dlsdl
1896
+ // diagonal-letter smooth argument α in [2,10) with v = 10{n+2}(α).
1897
+ // Start from C=10{level}(t) (polarize: a scalar C starts at level 1 with
1898
+ // t=log10(C)), then each level promotion is the geometric smooth-log step
1899
+ // t → 1+log10(t) (exact t=10 rewrites to the α-anchor 2). The final value
1900
+ // lands in [1,2); the diagonal mantissa is α=1+t (2 at the anchor).
1901
+ function countToDiagonalAlpha(C, n, r0OfC, rowsOfC) {
1902
+ var t, level;
1903
+ if (r0OfC === undefined || r0OfC === null) {
1904
+ t = Math.log10(C); level = 1;
1905
+ } else {
1906
+ // Truncation marker normalization: when rows overflowed the budget the
1907
+ // base was reset to [10] and the LOWEST kept finite row got +1 over the
1908
+ // uniform per-level fill (xCnt). That +1 marks the dropped cascade —
1909
+ // read it as the same count as the next kept row so the count climb
1910
+ // matches the untruncated anchor across configs.
1911
+ var pr0 = r0OfC.slice();
1912
+ var prows = rowsOfC ? rowsOfC.slice() : [];
1913
+ if (pr0[0] === 10 && prows.length > 0) {
1914
+ var li = 0;
1915
+ for (var pi = 1; pi < prows.length; pi++) {
1916
+ if (prows[pi][1] < prows[li][1]) li = pi;
1917
+ }
1918
+ var sortedLv = prows.slice().sort(function (a, b) { return a[1] - b[1]; });
1919
+ var c0v = sortedLv[0][0] || 0;
1920
+ var c1v = sortedLv.length > 1 ? (sortedLv[1][0] || 0) : 0;
1921
+ if (c0v === c1v + 1) {
1922
+ prows[li] = [c1v, prows[li][1]];
1923
+ pr0[0] = 10000000000;
1924
+ }
1925
+ }
1926
+ var pol = polarizeLike(pr0, prows);
1927
+ if (!pol) return null;
1928
+ t = Math.log10(pol.bottom) + pol.repeation;
1929
+ level = pol.arrows + 1; // C = 10{level}(t)
1930
+ }
1931
+ while (level < n + 2) {
1932
+ t = (t >= 9.999999999) ? 2 : 1 + Math.log10(t);
1933
+ level++;
1934
+ if (!(t > 0)) return null;
1935
+ }
1936
+ if (t >= 9.999999999) t = 2;
1937
+ return t < 2 ? 1 + t : (t > 10 ? 10 : t);
1938
+ }
1939
+
1940
+ // Minimal local structural polarize (faithful port of format-metanum's
1941
+ // refPolarize) so the engine need not import the formatter: returns
1942
+ // {bottom, repeation, arrows} for an r0 + finite [count,level] rows chain,
1943
+ // i.e. the value behaves as 10{arrows+1}(log10(bottom)+repeation).
1944
+ function polarizeLike(r0, finiteRows) {
1945
+ var array = [r0[0]];
1946
+ for (var i = 1; i < r0.length; i++) if ((r0[i] || 0) > 0) array.push([i, r0[i], 1, 1]);
1947
+ if (finiteRows) for (i = 0; i < finiteRows.length; i++) {
1948
+ var fr0 = finiteRows[i];
1949
+ if (fr0 && fr0.length === 2 && (fr0[0] || 0) > 0) array.push([fr0[1], fr0[0], 1, 1]);
1950
+ }
1951
+ function arraySort() {
1952
+ array.sort(function (a, b) {
1953
+ if (typeof a == 'number') return
1954
+ else if (a[3] > b[3]) return -1
1955
+ else if (a[3] < b[3]) return 1
1956
+ else if (a[2] == 'x' && b[2] != 'x') return -1
1957
+ else if (a[2] != 'x' && b[2] == 'x') return 1
1958
+ else if (a[2] == 'x' && b[2] == 'x') return -1
1959
+ else if (a[2] > b[2]) return -1
1960
+ else if (a[2] < b[2]) return 1
1961
+ else if (a[0] == 'x' && b[0] != 'x') return -1
1962
+ else if (a[0] != 'x' && b[0] == 'x') return 1
1963
+ else if (a[0] == 'x' && b[0] == 'x') return -1
1964
+ else if (a[0] > b[0]) return -1
1965
+ else if (a[0] < b[0]) return 1
1966
+ else if (a[1] > b[1]) return -1
1967
+ else if (a[1] < b[1]) return 1
1968
+ return -1
1969
+ });
1970
+ }
1971
+ function arrayMerge() {
1972
+ var elemOffset = 0;
1973
+ for (var mi = 0; mi < array.length - 2; ++mi) {
1974
+ if (array[mi][0] == array[mi + 1][0] &&
1975
+ array[mi][2] == array[mi + 1][2] && array[mi][3] == array[mi + 1][3]) {
1976
+ array[mi][1] += array[mi + 1][1]
1977
+ array.splice(mi + 1, 1)
1978
+ --mi
1979
+ elemOffset++
1980
+ }
1981
+ }
1982
+ return elemOffset
1983
+ }
1984
+ arraySort(); arrayMerge();
1985
+ var ptr = array.length - 2
1986
+ var b = function () { return array[array.length - 1] }
1987
+ var c = function (x) { array[array.length - 1] = x }
1988
+ var repeatResult = 500000
1989
+ while (--repeatResult >= 0) {
1990
+ if (b() >= 10) {
1991
+ var a = Math.log10(b())
1992
+ array.push([1, 1, 1, 1]); ptr++; arraySort()
1993
+ var offset = arrayMerge(); ptr -= offset; c(a)
1994
+ } else {
1995
+ if (ptr == 0 && typeof array[ptr + 1] == 'number') break
1996
+ if (ptr != 0 && typeof array[ptr + 1] == 'number' && typeof array[ptr][0] == 'number' &&
1997
+ array[ptr][1] == 1 &&
1998
+ (array[ptr - 1][0] == 'x' || array[ptr - 1][2] > array[ptr][2] || array[ptr - 1][3] > array[ptr][3]) &&
1999
+ array[ptr][0] > 2 && (ptr != 0 || array[ptr - 1][0] == 'x')) {
2000
+ var arrow_count = array[ptr][0]
2001
+ var base = b()
2002
+ var Jx = arrow_count == 3 ? base : arrow_count - 1 + Math.log(base / 2) / Math.log(5)
2003
+ array[ptr][0] = 'x'
2004
+ c(Jx); arraySort(); var off2 = arrayMerge(); ptr -= off2
2005
+ }
2006
+ if (typeof array[ptr + 1] == 'number' && array[ptr][0] == 'x' && b() < 10 && ptr != 0) {
2007
+ var base2 = b()
2008
+ var JRepeation = array[ptr][1]
2009
+ var Kx = JRepeation + Math.log10(base2)
2010
+ array[ptr][1] = 1
2011
+ array[ptr][0] = 1
2012
+ array[ptr][2]++
2013
+ c(Kx); arraySort(); var off3 = arrayMerge(); ptr -= off3
2014
+ }
2015
+ if (((ptr == 0) || ptr != 0) && array[ptr][0] != 'x' && b() < 10) {
2016
+ if (b() == 1 && ptr > 0 && array[ptr - 1][0] > array[ptr][0] && array[ptr][1] == 1) {
2017
+ array[ptr][0] = array[ptr - 1][0]
2018
+ } else {
2019
+ var right = array[ptr][1] + Math.log10(b())
2020
+ array[ptr][0]++
2021
+ array[ptr][1] = 1
2022
+ c(right)
2023
+ }
2024
+ arraySort(); var off4 = arrayMerge(); ptr -= off4
2025
+ }
2026
+ }
2027
+ }
2028
+ if (typeof array[ptr][0] !== 'number' || !isFinite(b())) return null;
2029
+ return { bottom: b(), repeation: array[ptr][1], arrows: array[ptr][0] };
2030
+ }
2031
+
2032
+ // Canonical compact form of the smooth diagonal value 10{L}(α) with a
2033
+ // NUMERIC α in [1,10): r0=[1] plus one finite row [α, L-1]. The fractional
2034
+ // row count survives normalization (only r0 integer columns are floored)
2035
+ // and polarize climbs it straight back to t=α at level L-1, so the smooth
2036
+ // mantissa is preserved at arbitrary finite levels (used where the iterated
2037
+ // arrow loop would MSI-dump the fraction away).
2038
+ function compactSmoothValue(L, alpha) {
2039
+ var m = new MetaNum({ sign: 1, layer: 0, array: [[1], [alpha, L - 1]] });
2040
+ return m.normalize();
2041
+ }
2042
+
1798
2043
  // region >=ω level operations
1799
2044
  P.arrow = function (arrows) {
1800
2045
  var t = this.clone();
1801
2046
  arrows = new MetaNum(arrows);
1802
- if (!arrows.isint() || arrows.sign === -1 || arrows.sign === -2) return function () { return MetaNum.NaN.clone(); };
2047
+ if (arrows.sign === -1 || arrows.sign === -2) return function () { return MetaNum.NaN.clone(); };
2048
+ if (!arrows.isint()) {
2049
+ // Fractional hyperoperation level.
2050
+ // Geometric interpolation per README rule (i): level n+f acts as the (n+1)-level
2051
+ // op on a geometrically interpolated argument — for the canonical
2052
+ // diagonal 10{n+f}10 = 10{n+1}(2·5^f). General anchors: θ0 satisfies
2053
+ // x{n+1}θ0 = x{n}y (recovered via hyper_log), θ1 = y, θf = θ0·(y/θ0)^f,
2054
+ // so x{n+f}y = x{n+1}(θf), continuous in f with
2055
+ // x{n}y at f=0 and x{n+1}y at f=1.
2056
+ if (arrows.gte(MetaNum.ONE)) {
2057
+ var nLev = arrows.floor();
2058
+ var frac = arrows.sub(nLev);
2059
+ var self = t;
2060
+ return function (other) {
2061
+ other = new MetaNum(other);
2062
+ if (other.eq(MetaNum.ZERO)) return MetaNum.ONE.clone();
2063
+ if (other.eq(MetaNum.ONE)) return self.clone();
2064
+ if (frac.eq(MetaNum.ZERO)) return self.arrow(nLev)(other);
2065
+ var target = self.arrow(nLev)(other);
2066
+ var theta0 = target.hyper_log(self)(nLev.add(MetaNum.ONE));
2067
+ var theta = theta0.mul(other.div(theta0).pow(frac));
2068
+ return self.arrow(nLev.add(MetaNum.ONE))(theta);
2069
+ };
2070
+ }
2071
+ return function () { return MetaNum.NaN.clone(); };
2072
+ }
1803
2073
  if (arrows.eq(MetaNum.ZERO)) return function (other) { return t.mul(other); };
1804
2074
  if (arrows.eq(MetaNum.ONE)) return function (other) { return t.pow(other); };
1805
2075
  if (arrows.eq(2)) return function (other) { return t.tetr(other); };
@@ -1808,7 +2078,25 @@
1808
2078
  if (other.sign === -1 || other.sign === -2) return MetaNum.NaN.clone();
1809
2079
  if (other.eq(MetaNum.ZERO)) return MetaNum.ONE.clone();
1810
2080
  if (other.eq(MetaNum.ONE)) return t.clone();
1811
- if (other.eq(2)) return t.arrow(arrows.sub(MetaNum.ONE))(t);
2081
+ if (other.eq(2)) {
2082
+ var diagArrowsNum = arrows.toNumber();
2083
+ // Only build directly when the whole diagonal fits r0; at/above
2084
+ // maxCols the value must go through the truncating branch below
2085
+ // (base [10] + first-kept row count +1), reached via the ordinary
2086
+ // t{L-1}t call which itself reuses the fast diagonal for its tail.
2087
+ if (isFinite(diagArrowsNum) && diagArrowsNum >= 2 &&
2088
+ diagArrowsNum <= MetaNum.maxCols && canFastDiagonal(t)) {
2089
+ return diagonalChain(t, diagArrowsNum - 1);
2090
+ }
2091
+ return t.arrow(arrows.sub(MetaNum.ONE))(t);
2092
+ }
2093
+ // Layer swallowing: any ω-tower operand (layer≥1) dominates a layer-0
2094
+ // operand under every (finite or ordinal) hyperoperation; equal layers
2095
+ // take the supremum (higher ordinal rows win). The layer itself is the
2096
+ // ω^-tower height and must survive unchanged.
2097
+ var dom = layerDominant(t, other);
2098
+ if (dom !== null) return dom.clone().normalize();
2099
+ if (t.layer > 0) return t.max(other).normalize();
1812
2100
  var arrowsNum = arrows.toNumber();
1813
2101
  if (!isFinite(arrowsNum)) {
1814
2102
  // arrows is a huge MetaNum (ω-level): result inherits the largest structure
@@ -1817,17 +2105,45 @@
1817
2105
  j.normalize();
1818
2106
  return j;
1819
2107
  }
1820
- if (arrows.gte(MetaNum.maxArrow)) {
2108
+ if (arrows.gte(Number.MAX_SAFE_INTEGER)) {
1821
2109
  // arrows is very large but still a JS number; use approximate overflow
1822
2110
  var j = t.max(other).max(arrows).clone();
1823
2111
  j.array.push([1, 0, 1]);
1824
2112
  j.normalize();
1825
2113
  return j;
1826
2114
  }
2115
+ // Fractional argument exactly at the boundary level (L == maxCols):
2116
+ // 10{L}(α) with numeric α in (1,10) carries the smooth diagonal
2117
+ // mantissa directly (compact form). Levels beyond maxCols with a
2118
+ // numeric argument keep the structural integer cascade below.
2119
+ var yNumPre = other.toNumber();
2120
+ var boundaryFractional = isFinite(yNumPre) && yNumPre !== Math.floor(yNumPre);
2121
+ if (arrowsNum === MetaNum.maxCols && boundaryFractional) {
2122
+ return compactSmoothValue(arrowsNum, yNumPre);
2123
+ }
2124
+ // Structured finite argument at/below the boundary level
2125
+ // (e.g. 10{L}(10{k}10)): convert the raw application count to the
2126
+ // dlsdl smooth diagonal argument α and return 10{L+1}(α).
2127
+ var otherFiniteChain = other.layer === 0 &&
2128
+ other.array.slice(1).every(function (rr) { return rr.length === 2; });
2129
+ var otherHasChain = other.array[0].length >= 2 || other.array.length >= 2;
2130
+ if (arrowsNum >= MetaNum.maxCols &&
2131
+ otherFiniteChain && otherHasChain && !isFinite(yNumPre) &&
2132
+ t.layer === 0 && t.array.length === 1) {
2133
+ var alphaC = countToDiagonalAlpha(null, arrowsNum - 1,
2134
+ other.array[0], other.array.slice(1));
2135
+ if (alphaC !== null && alphaC >= 2) return compactSmoothValue(arrowsNum + 1, alphaC);
2136
+ }
1827
2137
  if (arrowsNum >= MetaNum.maxCols) {
1828
- // Compact ordinal-row representation: 10{1000}10 → [[10],[1,1000]].
1829
- // One [1|arrowsNum] row on top of the larger operand; finite arrow
1830
- // levels beyond r0 capacity no longer expand into a cascade of rows.
2138
+ // Finite arrow level beyond r0 capacity:
2139
+ // expand the level chain exactly as far as the array budget allows —
2140
+ // r0 filled to maxCols (levels 1..maxCols-1, the top one being the
2141
+ // anchor level L-1 col) + [count, level] rows for levels
2142
+ // maxCols..L-1 (maxRows-1 rows max; the top level L itself is the
2143
+ // 10{L}2 = 10{L-1}10 anchor and takes no row) —
2144
+ // and approximate beyond the budget: keep the LARGEST maxRows-1
2145
+ // ordinal rows, the ARRAY's second row (first-kept ordinal row) first column +1,
2146
+ // first row [10].
1831
2147
  // Swallowing: a finite level sits below any existing ω-level row.
1832
2148
  var j = t.max(other).clone();
1833
2149
  if (j.layer > 0) return j; // ω^ω-tower swallows any finite level
@@ -1836,23 +2152,124 @@
1836
2152
  var row = j.array[i];
1837
2153
  if (row && row.length >= 2 && (row[0] || 0) > 0) { idx = i; break; }
1838
2154
  }
1839
- if (idx < 0) {
1840
- j.array.push([1, arrowsNum]);
2155
+ // value below already carries an ordinal row: merge or swallow
2156
+ if (idx >= 0) {
2157
+ var belowRow = j.array[idx];
2158
+ var belowIsTower = belowRow.length >= 3;
2159
+ var belowLevel = belowIsTower ? Infinity : belowRow[1];
2160
+ if (belowIsTower || belowLevel > arrowsNum) { j.normalize(); return j; }
2161
+ if (belowLevel === arrowsNum) {
2162
+ belowRow[0] = Math.min((belowRow[0] || 0) + 1, MAX_SAFE_INTEGER);
2163
+ j.normalize();
2164
+ return j;
2165
+ }
2166
+ // belowLevel < arrowsNum: stack rows on top of the existing chain
2167
+ var rowBudgetA = MetaNum.maxRows - 1;
2168
+ var startA = Math.max(MetaNum.maxCols, belowLevel + 1);
2169
+ var endA = arrowsNum - 1;
2170
+ if (endA - startA + 1 <= rowBudgetA) {
2171
+ for (var la = startA; la <= endA; la++) j.array.push([1, la]);
2172
+ } else {
2173
+ var keptFromA = endA - rowBudgetA + 1;
2174
+ for (var lb = keptFromA; lb <= endA; lb++) {
2175
+ var cntA = (lb === endA) ? yCnt : xCnt;
2176
+ if (lb === keptFromA) cntA += 1;
2177
+ j.array.push([cntA, lb]);
2178
+ }
2179
+ j.array[0] = [10];
2180
+ }
2181
+ j.normalize();
2182
+ return j;
2183
+ }
2184
+ // plain finite base: expand the diagonal chain bottom-up.
2185
+ // Exact law (matches the engine's own low-level path and the
2186
+ // reference): x{L}y = x{L-1}^{y-2}(x{L-1}x), so the top level L-1
2187
+ // carries (y-2) ops and every level below — the x{L-1}x tail —
2188
+ // carries (x-2) ops:
2189
+ // 3{9}3 → 1 op/level, 4{9}4 → 2, 10{25}10 → 8 ops/level (the
2190
+ // canonical all-8s form). The top level L itself is the
2191
+ // 10{L}2 = 10{L-1}10 anchor and takes no row.
2192
+ var subDepth = MetaNum.maxCols - 1;
2193
+ var xBase = t.toNumber();
2194
+ var yBase = other.toNumber();
2195
+ var xCnt = isFinite(xBase) ? Math.min(Math.max(xBase - 2, 0), MAX_SAFE_INTEGER) : MAX_SAFE_INTEGER;
2196
+ // Top-of-chain count: x{L}y = x{L-1}^{y-1}(x), so every level below the
2197
+ // top carries (x-2) ops while level L-1 carries (y-2) ops for y>=3
2198
+ // (the y=2 anchor x{L}2=x{L-1}x carries x-2 there). This makes
2199
+ // 10{100}11 = 10{99}(10{100}10) exact (col 99 = 9, not 8).
2200
+ var topCnt;
2201
+ if (!isFinite(yBase)) topCnt = MAX_SAFE_INTEGER;
2202
+ else if (yBase <= 2) topCnt = xCnt;
2203
+ else topCnt = Math.min(Math.max(yBase - 2, 1), MAX_SAFE_INTEGER);
2204
+ // Base-2 with y≥3: 2{L-1}(2{L}2)=2{L-1}4 expands like a base-10 tail
2205
+ // (8 ops per level), with the fixed law level L-2 = 2 ops and
2206
+ // level L-1 = (y-3) ops (matches the exact main-loop arrays:
2207
+ // 2{100}3 -> cols 1..97=8, col98=2; 2{100}10 -> col99=7).
2208
+ var base2mode = (xCnt === 0 && isFinite(yBase) && yBase >= 3);
2209
+ var fillCnt = base2mode ? 8 : xCnt;
2210
+ function countAt(lv) {
2211
+ if (base2mode) {
2212
+ if (lv === arrowsNum - 2) return 2;
2213
+ if (lv === arrowsNum - 1) return Math.max(yBase - 3, 0);
2214
+ }
2215
+ return (lv === arrowsNum - 1) ? topCnt : fillCnt;
2216
+ }
2217
+ // base sub-chain: the tail's bottom x{subDepth}x
2218
+ var sub;
2219
+ if (subDepth >= 2 && subDepth < arrowsNum) {
2220
+ if (base2mode) sub = diagonalChain(MetaNum(10), subDepth);
2221
+ else sub = canFastDiagonal(t) ? diagonalChain(t, subDepth) : t.arrow(subDepth)(t);
1841
2222
  } else {
1842
- var top = j.array[idx].slice(1);
1843
- while (top.length > 0 && top[top.length - 1] === 0) top.pop();
1844
- var c = cmpCoeffsLevel([arrowsNum], top);
1845
- if (c > 0) {
1846
- j.array.push([1, arrowsNum]);
1847
- } else if (c === 0) {
1848
- j.array[idx][0] = Math.min((j.array[idx][0] || 0) + 1, MAX_SAFE_INTEGER);
2223
+ sub = t.max(other).clone();
2224
+ }
2225
+ if (sub.layer > 0) { sub.normalize(); return sub; }
2226
+ // top count at the anchor column (subDepth = L-1 when L == maxCols)
2227
+ if (sub.array.length === 1) {
2228
+ var wantLen = subDepth + 1;
2229
+ while (sub.array[0].length < wantLen) sub.array[0].push(0);
2230
+ if (arrowsNum === MetaNum.maxCols) {
2231
+ // no rows above: write the exact per-level counts into r0
2232
+ if (base2mode) {
2233
+ for (var bl = 1; bl <= arrowsNum - 3; bl++) sub.array[0][bl] = 8;
2234
+ sub.array[0][arrowsNum - 2] = 2;
2235
+ sub.array[0][arrowsNum - 1] = Math.max(yBase - 3, 0);
2236
+ if (sub.array[0][arrowsNum - 1] === 0) sub.array[0].pop();
2237
+ } else if (topCnt > 0) {
2238
+ sub.array[0][subDepth] = topCnt;
2239
+ }
2240
+ } else if (fillCnt > 0) {
2241
+ sub.array[0][subDepth] = (sub.array[0][subDepth] || 0) + fillCnt;
1849
2242
  }
1850
- // c < 0: swallowed by the larger ordinal structure already present
1851
2243
  }
1852
- j.normalize();
1853
- return j;
2244
+ // rows for levels maxCols..arrowsNum-1 within the budget
2245
+ var rowBudget = MetaNum.maxRows - 1;
2246
+ var startLv = subDepth + 1;
2247
+ var endLv = arrowsNum - 1; // top level L is the anchor, no row
2248
+ var nRows = endLv - startLv + 1;
2249
+ if (nRows > rowBudget) {
2250
+ // beyond budget: keep the largest rowBudget rows; the array's
2251
+ // SECOND row (= the first-kept ordinal row) gets its first column
2252
+ // +1 (the dropped lower chain collapses into one extra op there);
2253
+ // first row [10] (issues.md v2.1)
2254
+ var keptFrom = endLv - rowBudget + 1;
2255
+ for (var lv = keptFrom; lv <= endLv; lv++) {
2256
+ var cnt = countAt(lv);
2257
+ if (lv === keptFrom) cnt += 1;
2258
+ if (cnt > 0) sub.array.push([cnt, lv]);
2259
+ }
2260
+ sub.array[0] = [10];
2261
+ } else {
2262
+ for (var lv2 = startLv; lv2 <= endLv; lv2++) {
2263
+ var cnt2 = countAt(lv2);
2264
+ if (cnt2 > 0) sub.array.push([cnt2, lv2]);
2265
+ }
2266
+ }
2267
+ sub.normalize();
2268
+ return sub;
2269
+ }
2270
+ if (t.max(other).gt(hyperLevelSafe(arrowsNum + 1, MAX_SAFE_INTEGER))) {
2271
+ return t.max(other);
1854
2272
  }
1855
- if (t.max(other).gt(hyperLevelSafe(arrowsNum + 1, MAX_SAFE_INTEGER))) return t.max(other);
1856
2273
  if (t.gt(hyperLevelSafe(arrowsNum, MAX_SAFE_INTEGER)) || other.gt(MetaNum.MAX_SAFE_INTEGER)) {
1857
2274
  var r;
1858
2275
  if (t.gt(hyperLevelSafe(arrowsNum, MAX_SAFE_INTEGER))) {
@@ -1886,20 +2303,45 @@
1886
2303
  return j;
1887
2304
  }
1888
2305
  var y = other.toNumber();
1889
- if (arrowsNum >= 23 && y !== Math.floor(y)) {
2306
+ var fastDiag = isFinite(y) && Math.floor(y) === y && canFastDiagonal(t);
2307
+ if (arrowsNum >= 23 && y !== Math.floor(y) && Math.floor(y) > 2) {
2308
+ // Large integer part with a fractional tail at a high level: the tail
2309
+ // would be amplified by the many iterations (e.g. 10{69}69.6 ≈
2310
+ // 10{69}10), so use the discrete 10 anchor (accepted convention).
2311
+ // y with floor ≤ 2 keeps the smooth fractional path — the recursion
2312
+ // bottoms out numerically and carries the smooth Aa-diagonal mantissa
2313
+ // (e.g. 10{101}(2.001607)).
1890
2314
  y = 10;
2315
+ fastDiag = false;
1891
2316
  }
1892
2317
  var f = Math.floor(y);
1893
2318
  var arrows_m1 = arrows.sub(MetaNum.ONE);
1894
- var r = t.arrow(arrows_m1)(y - f);
1895
2319
  var initFloor = Math.floor(other.toNumber());
1896
- for (var i = 0; f !== 0 && r.lt(hyperLevelSafe(arrowsNum - 1, MAX_SAFE_INTEGER)) && i < 100; i++) {
1897
- if (f > 0) {
1898
- r = t.arrow(arrows_m1)(r);
1899
- f--;
2320
+ var r, i;
2321
+ if (fastDiag && arrowsNum >= 2 && f >= 2) {
2322
+ // x{L}y = x{L-1}^{y-1}(x) = x{L-1}^{y-2}(x{L-1}x): seed with the
2323
+ // diagonal D(L-1) built bottom-up and run the remaining successor
2324
+ // iterations — same loop/guard/dump semantics as the path below,
2325
+ // minus the two recomputed seed iterations.
2326
+ r = diagonalChain(t, arrowsNum - 1);
2327
+ f -= 2;
2328
+ for (i = 0; f !== 0 && r.lt(hyperLevelSafe(arrowsNum - 1, MAX_SAFE_INTEGER)) && i < 98; i++) {
2329
+ if (f > 0) {
2330
+ r = t.arrow(arrows_m1)(r);
2331
+ f--;
2332
+ }
1900
2333
  }
2334
+ if (i === 98) f = 0;
2335
+ } else {
2336
+ r = t.arrow(arrows_m1)(y - f);
2337
+ for (i = 0; f !== 0 && r.lt(hyperLevelSafe(arrowsNum - 1, MAX_SAFE_INTEGER)) && i < 100; i++) {
2338
+ if (f > 0) {
2339
+ r = t.arrow(arrows_m1)(r);
2340
+ f--;
2341
+ }
2342
+ }
2343
+ if (i === 100) f = 0;
1901
2344
  }
1902
- if (i === 100) f = 0;
1903
2345
  if (arrowsNum - 1 < MetaNum.maxCols) {
1904
2346
  if (f > 0) {
1905
2347
  r.array[0][arrowsNum - 1] = (r.array[0][arrowsNum - 1] || 0) + f;
@@ -1920,14 +2362,81 @@
1920
2362
  Q.arrow = function (x, arrows, y) {
1921
2363
  return new MetaNum(x).arrow(arrows)(y);
1922
2364
  };
2365
+
2366
+ // ==================== hyper_log / hyper_root ====================
2367
+ // Inverses of the hyperoperation a{b}c = d (arrow-style chained API):
2368
+ // d.hyper_log(a)(b) = c (recover the right operand / argument)
2369
+ // d.hyper_root(c)(b) = a (recover the base / left operand)
2370
+ // b = 0 and b = 1 use exact division and logarithms; b ≥ 2 bisects on the
2371
+ // monotone arrow engine (issues.md addition 2). Note: for levels b beyond
2372
+ // maxCols the forward arrow diagonalizes into one [1|b] marker row and the
2373
+ // argument is no longer recoverable — the bisection then returns the
2374
+ // smallest argument that reproduces d.
2375
+ function hyperBisect(f, target, bound) {
2376
+ // smallest integer x ≥ 1 with f(x) ≥ target (f monotone nondecreasing)
2377
+ var lo = MetaNum.ONE.clone();
2378
+ var hi = new MetaNum(2);
2379
+ var iters = 0;
2380
+ while (f(hi).lt(target)) {
2381
+ lo = hi.clone();
2382
+ hi = hi.mul(2);
2383
+ if (++iters > bound) return hi; // bracketing budget exhausted
2384
+ }
2385
+ iters = 0;
2386
+ while (hi.sub(lo).gt(MetaNum.ONE) && iters++ < bound) {
2387
+ var mid = lo.add(hi).div(2);
2388
+ if (mid.lte(lo)) mid = lo.add(MetaNum.ONE);
2389
+ if (mid.gte(hi)) mid = hi.sub(MetaNum.ONE);
2390
+ if (f(mid).lt(target)) lo = mid.clone();
2391
+ else hi = mid.clone();
2392
+ }
2393
+ return hi;
2394
+ }
2395
+
2396
+ P.hyper_log = function (a) {
2397
+ var d = this.clone();
2398
+ a = new MetaNum(a);
2399
+ return function (b) {
2400
+ b = new MetaNum(b);
2401
+ if (b.lt(MetaNum.ZERO) || d.lte(MetaNum.ZERO) || a.lte(MetaNum.ZERO) || a.eq(MetaNum.ONE)) {
2402
+ return MetaNum.NaN.clone();
2403
+ }
2404
+ if (b.eq(MetaNum.ZERO)) return d.div(a); // a·c = d
2405
+ if (b.eq(MetaNum.ONE)) return d.log10().div(a.log10()); // a^c = d
2406
+ return hyperBisect(function (x) { return a.arrow(b)(x); }, d, 200);
2407
+ };
2408
+ };
2409
+ Q.hyper_log = function (d, a, b) {
2410
+ return new MetaNum(d).hyper_log(a)(b);
2411
+ };
2412
+
2413
+ P.hyper_root = function (c) {
2414
+ var d = this.clone();
2415
+ c = new MetaNum(c);
2416
+ return function (b) {
2417
+ b = new MetaNum(b);
2418
+ if (b.lt(MetaNum.ZERO) || d.lte(MetaNum.ZERO) || c.lte(MetaNum.ZERO)) {
2419
+ return MetaNum.NaN.clone();
2420
+ }
2421
+ if (b.eq(MetaNum.ZERO)) return d.div(c); // a·c = d
2422
+ if (c.eq(MetaNum.ONE)) return d.clone(); // a{b}1 = a
2423
+ return hyperBisect(function (x) { return x.arrow(b)(c); }, d, 200);
2424
+ };
2425
+ };
2426
+ Q.hyper_root = function (d, c, b) {
2427
+ return new MetaNum(d).hyper_root(c)(b);
2428
+ };
1923
2429
  Q.chain = function (x, y, arrows) {
1924
2430
  return new MetaNum(x).arrow(arrows)(y);
1925
2431
  };
1926
2432
 
1927
- //calc level ω: x{ω}y = x{y}y (fundamental sequence ω[y] = y)
1928
- // aperiote(x,0) = x{0}0 = 0; aperiote(x,1) = x{1}1 = x; aperiote(x,2) = x{2}2 = x^x; ...
2433
+ // level ω, rule 3 with the fundamental sequence ω[y] = y:
2434
+ // x{ω}y = x{ω[y]}x = x{y}x
2435
+ // (the final operand is the base x, NOT the FS index y)
2436
+ // aperiote(3,0) = 3{0}3 = 9; aperiote(3,1) = 3{1}3 = 27;
2437
+ // aperiote(3,2) = 3{2}3 = 3^^3 = 7625597484987; ...
1929
2438
  P.aperiote = P.aper = P.h10 = function (y) {
1930
- return this.arrow(y)(y);
2439
+ return this.arrow(y)(this);
1931
2440
  };
1932
2441
  Q.aperiote = Q.aper = Q.h10 = function (x, y) {
1933
2442
  return new MetaNum(x).aperiote(y);
@@ -1977,7 +2486,8 @@
1977
2486
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
1978
2487
  var base = x.aperiote(x); // expande(x, 2) = x{x}x = x{ω}x
1979
2488
  if (y.eq(2)) return base.clone();
1980
- if (y.lt(2)) return base.clone(); // 1 < y < 2: the aperiote base
2489
+ // 1 < y < 2 follows the successor rule too: x{ω+1}y = x{ω} applied
2490
+ // floor(y) times to x^frac(y) (continuous with y=1 → x, y=2 → x{ω}x)
1981
2491
  return Q._hyperopFromOrdinal(x, y, [1, 1]);
1982
2492
  };
1983
2493
  Q.expande = Q.expa = Q.h11 = function (x, y) {
@@ -2027,7 +2537,7 @@
2027
2537
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
2028
2538
  var base = x.expande(x); // multiexpande(x, 2)
2029
2539
  if (y.eq(2)) return base.clone();
2030
- if (y.lt(2)) return base.clone(); // 1 < y < 2
2540
+ // 1 < y < 2 follows the successor rule (continuous with the integers)
2031
2541
  return Q._hyperopFromOrdinal(x, y, [2, 1]);
2032
2542
  };
2033
2543
  Q.multiexpande = Q.muea = Q.h12 = function (x, y) {
@@ -2075,7 +2585,7 @@
2075
2585
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
2076
2586
  var base = x.multiexpande(x); // powerexpande(x, 2)
2077
2587
  if (y.eq(2)) return base.clone();
2078
- if (y.lt(2)) return base.clone(); // 1 < y < 2
2588
+ // 1 < y < 2 follows the successor rule (continuous with the integers)
2079
2589
  return Q._hyperopFromOrdinal(x, y, [3, 1]);
2080
2590
  };
2081
2591
  Q.powerexpande = Q.poea = Q.h13 = function (x, y) {
@@ -2220,6 +2730,9 @@
2220
2730
  } else {
2221
2731
  var c = cmpCoeffsLevel(bt, rowToCoeffs(x.array[idx]));
2222
2732
  if (c > 0) {
2733
+ // Push the larger level; if this exceeds the row budget, normalize
2734
+ // keeps the base + the largest rows (the new row is never the one
2735
+ // dropped — it ranks among the largest)
2223
2736
  x.array.push([k].concat(bt));
2224
2737
  } else if (c === 0) {
2225
2738
  var cnt = (x.array[idx][0] || 0) + k;
@@ -2230,6 +2743,112 @@
2230
2743
  return x.normalize();
2231
2744
  };
2232
2745
 
2746
+ // issues.md truncation rule for ordinal expansions: when the expansion
2747
+ // reaches row capacity (maxRows-1 ordinal rows), the base defaults to [10]
2748
+ // and the first (smallest kept) ordinal row's count increments by 1 —
2749
+ // marking that the exact expansion was truncated to its largest ordinals.
2750
+ Q._applyExpansionTruncation = function (x) {
2751
+ x = x.normalize();
2752
+ var maxOrdinalRows = MetaNum.maxRows - 1;
2753
+ if (x.array.length >= 2 && x.array.length - 1 >= maxOrdinalRows) {
2754
+ x.array[0] = [10];
2755
+ x.array[1][0] = (x.array[1][0] || 0) + 1;
2756
+ if (x.array[1][0] > MAX_SAFE_INTEGER) x.array[1][0] = MAX_SAFE_INTEGER;
2757
+ }
2758
+ return x;
2759
+ };
2760
+
2761
+ // ---------------------------------------------------------------------------
2762
+ // Compact "layer marker" values for levels at or above ω^ω (README L17).
2763
+ // Such a level has no finite CNF coefficient row, so the result of x{α}y is
2764
+ // stored as the diagonal value of the reduced level (one rule-3 step):
2765
+ // layer L >= 1, rows [count, a1, …, ap] →
2766
+ // 10{ ω^ω^…((L-1) ω^'s)…^( Σ_i ω^(ord_i)·count_i + Σ_j ω^j·r_j ) }10
2767
+ // with ord_i = ω^(p-1)·ap + … + ω·a2 + a1.
2768
+ // Examples: 10{ω^y}10 = L1 [[0],[1,y]]; 10{ω^ω}10 = L1 [[0],[1,0,1]];
2769
+ // 10{ω^ω·y}10 = L1 [[0],[y,0,1]]; 10{ω^(ω+y)}10 = L1 [[0],[1,y,1]];
2770
+ // 10{ω^(ω·y)}10 = L2 [[0],[y,1]]; 10{ω^(ω^y)}10 = L3 [[y]];
2771
+ // 10{ω^ω^…^ω(y ω's)}10 = L_y [[0],[1,1]].
2772
+ // A marker is always stored in STANDARD FORM (Q._standardizeLayerValue):
2773
+ // finite-level rows merge into r0 and the layer drops as far as it can.
2774
+ // ---------------------------------------------------------------------------
2775
+ Q._layerMarker = function (r0, layer, rows) {
2776
+ var v = new MetaNum(0);
2777
+ v.array = [(r0 && r0.length) ? r0.slice() : [0]];
2778
+ for (var i = 0; i < (rows ? rows.length : 0); i++) {
2779
+ if (rows[i] && rows[i].length > 1) v.array.push(rows[i].slice());
2780
+ }
2781
+ v.layer = layer > 0 ? layer : 0;
2782
+ return Q._standardizeLayerValue(v);
2783
+ };
2784
+
2785
+ // Standard form of a layer >= 1 value (README L17). Two rewrites, both
2786
+ // preserving the encoded ordinal, applied until no longer possible:
2787
+ // (a) merge: an ordinal row [count, k] holds the finite level k, i.e. the
2788
+ // bracket term ω^k·count — the very term r0's own k-th entry spells
2789
+ // (Σ_j ω^j·r_j). So whenever k < maxCols the row folds into r0:
2790
+ // cube(10,3): [[10],[1,3],[1,0,1]] → [[10,0,0,1],[1,0,1]].
2791
+ // (b) de-layer: a layer-L value whose bracket is the finite ω-polynomial β
2792
+ // (no row above ω survives) equals the layer-(L-1) value carrying the
2793
+ // single row [1|β] (bracket ω^β, one ω^ less above it):
2794
+ // layer2 [[5],[3,1]] → layer2 [[5,3]] → layer1 [[10],[1,5,3]]
2795
+ // = 10{ω^(ω*3+5)}10;
2796
+ // layer3 [[3]] → layer2 [[0,0,0,1]] → layer1 [[10],[1,0,0,0,1]]
2797
+ // = 10{ω^ω^3}10.
2798
+ // Each de-layer step strictly lowers `layer`, so the loop terminates; the
2799
+ // innermost base is written as 10 (the 10{…}10 diagonal marker).
2800
+ function mergeFiniteRowsIntoR0(arr) {
2801
+ var r0 = arr[0];
2802
+ var keep = [];
2803
+ for (var i = 1; i < arr.length; i++) {
2804
+ var row = arr[i];
2805
+ if (row && row.length === 2 && row[1] >= 1 && row[1] < MetaNum.maxCols) {
2806
+ var k = row[1];
2807
+ while (r0.length <= k) r0.push(0);
2808
+ r0[k] += (row[0] || 0);
2809
+ continue;
2810
+ }
2811
+ keep.push(row);
2812
+ }
2813
+ arr.length = 1;
2814
+ for (var j = 0; j < keep.length; j++) arr.push(keep[j]);
2815
+ }
2816
+
2817
+ Q._standardizeLayerValue = function (v) {
2818
+ if (!v || v.layer < 1) return v.normalize();
2819
+ var L = v.layer;
2820
+ var arr = [v.array[0].slice()];
2821
+ for (var i = 1; i < v.array.length; i++) arr.push(v.array[i].slice());
2822
+ mergeFiniteRowsIntoR0(arr);
2823
+ while (L >= 2 && arr.length === 1) {
2824
+ var poly = arr[0].slice();
2825
+ while (poly.length > 0 && poly[poly.length - 1] === 0) poly.pop();
2826
+ if (poly.length === 0) break;
2827
+ var row = [1].concat(poly);
2828
+ if (row.length > MetaNum.maxCols) break; // row would not fit
2829
+ arr = [[0], row];
2830
+ L--;
2831
+ mergeFiniteRowsIntoR0(arr);
2832
+ }
2833
+ if ((arr[0][0] || 0) === 0) arr[0][0] = 10; // innermost base marker
2834
+ v.array = arr;
2835
+ v.layer = L;
2836
+ return v.normalize();
2837
+ };
2838
+
2839
+ // x{α}y when the operand y is itself an ordinal (or beyond MSI): the
2840
+ // iteration count is unrepresentable, so the engine convention applies —
2841
+ // "y plus one α-level marker row" (the supremum of the count-limited
2842
+ // iterations). `row` is the marker row of α at the given `layer`.
2843
+ Q._ordinalOperandOp = function (y, layer, row) {
2844
+ var v = y.clone();
2845
+ if (v.layer < layer) v.layer = layer;
2846
+ var bt = trimCoeffs((row || []).slice(1));
2847
+ var k = (row && row[0] > 0) ? row[0] : 1;
2848
+ if (bt.length === 0) return v.normalize();
2849
+ return Q._applyOrdinalRows(v, bt, k).normalize();
2850
+ };
2851
+
2233
2852
  Q._ordinalHyperop = function (x, y, coeffs, depth) {
2234
2853
  x = new MetaNum(x);
2235
2854
  y = new MetaNum(y);
@@ -2268,7 +2887,8 @@
2268
2887
  // the diagonalized single-row form (supremum of the iteration hierarchy).
2269
2888
  var hugeFs = yCnt > COEFF_BOUND && (pL >= 2 || (cf[1] || 0) > 1);
2270
2889
  if (hugeFs) return Q._applyOrdinalRows(x.max(y), cf, 1);
2271
- return Q._ordinalHyperop(x, y, fsCoeffs(cf, yCnt), depth + 1);
2890
+ // rule 3: x{λ}y = x{λ[y]}x — the final operand is the base x
2891
+ return Q._ordinalHyperop(x, x, fsCoeffs(cf, yCnt), depth + 1);
2272
2892
  };
2273
2893
 
2274
2894
  Q._iterateOrdinal = function (x, beta, V0, iters, depth) {
@@ -2296,7 +2916,7 @@
2296
2916
  // enumeration representation (one row per ordinal below α, count = y-2)
2297
2917
  // - everything else (any operand beyond MSI, x = 2, or enumeration too large):
2298
2918
  // unified ordinal engine (README rules 1-4)
2299
- Q._hyperopFromOrdinal = function (x, y, coeffs) {
2919
+ Q._hyperopFromOrdinalRaw = function (x, y, coeffs, skipFrac) {
2300
2920
  x = new MetaNum(x);
2301
2921
  y = new MetaNum(y);
2302
2922
  if (x.isNaN() || y.isNaN()) return MetaNum.NaN.clone();
@@ -2304,217 +2924,264 @@
2304
2924
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
2305
2925
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
2306
2926
  if (y.eq(MetaNum.ONE)) return x.clone();
2307
- var cf = trimCoeffs((coeffs || []).slice());
2308
- if (cf.length === 0) return x.mul(y); // rule 1: x{0}y = x*y
2927
+
2928
+ var cf0 = trimCoeffs((coeffs || []).slice());
2929
+ if (cf0.length === 0) return x.mul(y); // rule 1: x{0}y = x*y
2930
+ // Fractional level coefficients come from a fundamental sequence taken at a
2931
+ // non-integer index. On the diagonal ω = x, so ω^(k)·(c+f) = ω^(k)·c +
2932
+ // ω^(k-1)·(x·f) — resolve top-down until only the constant term can still be
2933
+ // fractional, then turn that leftover into a fractional argument one level
2934
+ // higher: x{γ+f}x = x{γ+1}(2·(x/2)^f) (README: 10{ω*2}2.1 = 10{ω+2.1}10 =
2935
+ // 10{ω+3}2·5^0.1; continuous at f=0 since x{γ+1}2 = x{γ}x).
2936
+ if (coeffsHaveFraction(cf0)) {
2937
+ var xnf = x.toNumber();
2938
+ if (isFinite(xnf) && xnf >= 2) {
2939
+ var rs = Q._resolveFracLevel(cf0, xnf);
2940
+ if (rs.frac > 0) {
2941
+ var up = rs.ord.slice();
2942
+ while (up.length < 1) up.push(0);
2943
+ up[0] = (up[0] || 0) + 1;
2944
+ var argF = 2 * Math.pow(xnf / 2, rs.frac);
2945
+ return Q._hyperopFromOrdinal(x, new MetaNum(argF), trimCoeffs(up));
2946
+ }
2947
+ cf0 = rs.ord;
2948
+ }
2949
+ }
2950
+ // Non-integer argument at ordinal levels (issues.md addition 3):
2951
+ // successor level α (c0 > 0): x{α}(m+f) = x{α-1} applied m times to x^f
2952
+ // (e.g. expa(10,2.1) = 10{ω+1}2.1 = 10{ω}10{ω}(10^0.1); continuous at
2953
+ // the integers since x^0 = 1 and x{α-1}1 = x)
2954
+ // limit level λ (c0 = 0): fundamental sequence at m = floor(y)
2955
+ var yFracNum = y.toNumber();
2956
+ if (!y.isint() && y.gt(MetaNum.ONE) && y.array.length === 1 && isFinite(yFracNum)) {
2957
+ // Finite levels delegate to arrow()'s own fractional-argument machinery
2958
+ if (!coeffsHaveOmegaPart(cf0)) return x.arrow(cf0[0])(y);
2959
+ // ω level: match P.aperiote exactly (x{ω}y = x.arrow(y)(x)), so the
2960
+ // successor rule composes as expa(10,2.1) = 10{ω}10{ω}(10^0.1)
2961
+ if (cf0.length === 2 && cf0[1] === 1 && !(cf0[0] > 0)) return x.aperiote(y);
2962
+ var ym = Math.floor(yFracNum);
2963
+ // toPrecision(15) strips double-rounding noise in y - floor(y)
2964
+ // (2.1 - 2 = 0.10000000000000009), so x^frac(y) reproduces x.pow(0.1)
2965
+ // exactly and composition identities stay stable across paths
2966
+ var yf = new MetaNum(Number((yFracNum - ym).toPrecision(15)));
2967
+ if ((cf0[0] || 0) > 0) {
2968
+ var xnfS = x.toNumber();
2969
+ var xOkS = isFinite(xnfS) && xnfS >= 3 && xnfS <= MAX_SAFE_INTEGER;
2970
+ // α-1 ≥ ω*2 only: for the ω+1/ω+2/ω+3 levels the applications after the
2971
+ // first still have an operand inside MSI, so the engine evaluates them by
2972
+ // the definition (10{ω}(10{ω}(10^0.1))) and that identity is exact.
2973
+ var pred = succCoeffs(cf0);
2974
+ var bigLevel = (pred[1] || 0) >= 2;
2975
+ for (var bi = 2; bi < pred.length; bi++) if ((pred[bi] || 0) > 0) bigLevel = true;
2976
+ if (xOkS && bigLevel && ym <= 100000) {
2977
+ // successor rule written in the EXPANDED form (the same generator the
2978
+ // integer arguments use): x{α}(m+f) = x{α-1}^m(x^f) means the α-1 row
2979
+ // carries m applications — ceil(y)-2 = m-1 — and the cascade below it
2980
+ // takes its first fundamental sequence at the fractional start value
2981
+ // x^f, which is what interpolates the cascade depth between the two
2982
+ // neighbouring integers (exactly what the finite levels do: 10{3}2.1
2983
+ // starts from 10^0.1). The base is x{x^f}x when that descent is the
2984
+ // ω one (ω+1 levels), x{x}x otherwise.
2985
+ return Q._expandedHyperop(x, new MetaNum(ym + 1), cf0,
2986
+ Math.pow(xnfS, Number((yFracNum - ym).toPrecision(15))));
2987
+ }
2988
+ if (ym <= 100000) {
2989
+ // successor rule: x{α}(m+f) = x{α-1} applied m times to x^f
2990
+ var succ = cf0.slice();
2991
+ succ[0] = succ[0] - 1;
2992
+ succ = trimCoeffs(succ);
2993
+ var v = x.pow(yf);
2994
+ for (var it = 0; it < ym; it++) v = Q._hyperopFromOrdinalRaw(x, v, succ, true);
2995
+ return v;
2996
+ }
2997
+ // Successor level with an iteration count beyond direct evaluation:
2998
+ // successors have no fundamental sequence, so fall through to the
2999
+ // engine's huge-y supremum convention (y + one α-row marker)
3000
+ return Q._ordinalHyperop(x, y, cf0);
3001
+ }
3002
+ if (ym >= 1) {
3003
+ // limit level: rule 3 with the FULL (fractional) index — x{λ}y =
3004
+ // x{λ[y]}x. λ[y] can carry fractional coefficients (10{ω*2}2.1 =
3005
+ // 10{ω+2.1}10), which the fractional-level rule above resolves, so the
3006
+ // fraction of y is never thrown away (flooring it would make
3007
+ // h20(10,2.1) = h20(10,2)).
3008
+ // Nested (skipFrac: the successor rule is already iterating a fractional
3009
+ // start value) the index is floored — otherwise every application would
3010
+ // take another fractional fundamental sequence and recurse forever.
3011
+ var fsIdx = skipFrac ? Math.floor(yFracNum) : yFracNum;
3012
+ return Q._hyperopFromOrdinalRaw(x, x, fsCoeffs(cf0, fsIdx), skipFrac);
3013
+ }
3014
+ }
3015
+ var cf = cf0;
2309
3016
  var deg = 0;
2310
3017
  for (var di = 1; di < cf.length; di++) if ((cf[di] || 0) !== 0) deg = di;
2311
3018
  if (deg >= 1 && x.array.length === 1 && x.layer === 0
2312
3019
  && y.array.length === 1 && y.layer === 0) {
2313
3020
  var xC = metaFiniteCount(x), yC = metaFiniteCount(y);
2314
- if (xC >= 3 && xC <= MAX_SAFE_INTEGER && yC >= 3 && yC <= MAX_SAFE_INTEGER
2315
- && Math.pow(yC, deg) <= MetaNum.maxRows) {
2316
- return Q._enumHyperop(x, y, cf);
3021
+ // Finite operands in [3, MSI] always take the EXPANDED cascade form — a
3022
+ // limit operation keeps its fundamental-sequence rows all the way up to
3023
+ // MSI (100 < y ≤ MSI included), truncated to the largest maxRows-1 rows.
3024
+ if (xC >= 3 && xC <= MAX_SAFE_INTEGER && yC >= 3 && yC <= MAX_SAFE_INTEGER) {
3025
+ return Q._expandedHyperop(x, y, cf);
2317
3026
  }
2318
3027
  }
2319
3028
  return Q._ordinalHyperop(x, y, cf);
2320
3029
  };
2321
3030
 
2322
- // Legacy (HEAD-compatible) enumeration-based hyperoperation for small operands.
2323
- Q._enumHyperop = function (x, y, coeffs) {
2324
- var xNum = x.toNumber();
2325
- var yNum = y.toNumber();
2326
- var maxRows = MetaNum.maxRows; // 100
2327
- var baseArrowLevel = Math.max(Math.floor(isFinite(xNum) ? xNum : 3), 3);
2328
- var baseResult = x.arrow(baseArrowLevel)(x);
2329
- var rows = Q._generateOrdinalRows(coeffs,
2330
- isFinite(xNum) ? Math.floor(xNum) : baseArrowLevel,
2331
- isFinite(yNum) ? Math.floor(yNum) : baseArrowLevel,
2332
- maxRows);
2333
- var result = baseResult.clone();
2334
- result.array = [baseResult.array[0].slice()];
2335
- for (var i = 0; i < rows.length; i++) result.array.push(rows[i]);
2336
- if (result.array.length > 1) result.layer = 0;
2337
- return result;
3031
+ // Public entry point of the ordinal-level hyperoperations. The expansion is
3032
+ // exact while it fits the array budget; once the rule-1..4 cascade overflows
3033
+ // maxRows the issues.md truncation rule applies (keep the largest maxRows-1
3034
+ // ordinal rows sorted ascending, array[1][0] += 1 as the truncation marker,
3035
+ // array[0] = [10]) — the same convention arrow() and BEAF already use.
3036
+ Q._hyperopFromOrdinal = function (x, y, coeffs) {
3037
+ var r = Q._hyperopFromOrdinalRaw(x, y, coeffs);
3038
+ if (r && r._ordTrunc) {
3039
+ delete r._ordTrunc;
3040
+ r = Q._applyExpansionTruncation(r);
3041
+ }
3042
+ return r;
2338
3043
  };
2339
3044
 
2340
- // Legacy (HEAD-compatible) ordinal row enumeration: one row per ordinal below
2341
- // `coeffs` (coefficients bounded by `cardinal`), each with count = cardinal-2.
2342
- Q._generateOrdinalRows = function (coeffs, base, cardinal, maxRows) {
3045
+ // ---------------------------------------------------------------------------
3046
+ // Expanded (cascade) form of x{α}y for FINITE operands in [3, MSI] — README
3047
+ // rules 1-4 written out row by row. The rows are generated TOP-DOWN so a
3048
+ // huge fundamental sequence (y up to MSI) costs nothing: generation stops as
3049
+ // soon as the array budget is filled, keeping the LARGEST rows.
3050
+ //
3051
+ // successor α = β + m (m = c0 > 0): x{α}y = x{β+m-1}^(y-2)(x{β+m-1}x),
3052
+ // so the row at β+m-1 carries y-2 applications and every row below it
3053
+ // (β+m-2 … β, then the cascade of β) comes from decomposing with the
3054
+ // BASE x as operand and therefore carries x-2 (h13(10,20) → [8,0,1],
3055
+ // [8,1,1], [18,2,1] — only the top row follows y).
3056
+ // limit α (c0 = 0): rule 3 gives x{α}opd = x{α[opd]}x, so the operand turns
3057
+ // into the base x and every row carries x-2 — including for 100 < y ≤ MSI
3058
+ // (h20(10,1000) stays an expanded cascade, not a one-row marker).
3059
+ // ---------------------------------------------------------------------------
3060
+ // `fsOpd` is the operand of the FIRST fundamental-sequence step. The default
3061
+ // is the base x; the fractional successor rule passes the fractional start
3062
+ // value x^f instead (x{α}(m+f) = x{α-1}^m(x^f)), which is what interpolates the
3063
+ // cascade depth between two integers. baseIdx (returned as `.baseIdx`) is the
3064
+ // index used by the last descent — the finite level the cascade bottoms out at.
3065
+ Q._cascadeRows = function (xn, cf, yn, budget, fsOpd) {
2343
3066
  var rows = [];
2344
- var m = base;
2345
- var n = cardinal;
2346
-
2347
- function compareOrd(a, b) {
2348
- var maxLen = Math.max(a.length, b.length);
2349
- for (var i = maxLen - 1; i >= 0; i--) {
2350
- var va = (i < a.length) ? (a[i] || 0) : 0;
2351
- var vb = (i < b.length) ? (b[i] || 0) : 0;
2352
- if (va < vb) return -1;
2353
- if (va > vb) return 1;
2354
- }
2355
- return 0;
2356
- }
2357
-
2358
- function addOrd(a, b) {
2359
- if (!b || b.length === 0 || (b.length === 1 && b[0] === 0)) return a.slice();
2360
- if (!a || a.length === 0 || (a.length === 1 && a[0] === 0)) return b.slice();
2361
- var result = a.slice();
2362
- var k = 0;
2363
- while (k < result.length && (result[k] || 0) === 0) k++;
2364
- if (k >= result.length) {
2365
- return b.slice();
2366
- } else if (k === 0) {
2367
- result[0] = (result[0] || 0) + (b[0] || 0);
2368
- for (var i = 1; i < b.length; i++) {
2369
- result[i] = (result[i] || 0) + (b[i] || 0);
3067
+ if (!(budget >= 1)) return { rows: rows, baseIdx: xn };
3068
+ var cfs = trimCoeffs((cf || []).slice());
3069
+ var opd = Math.min(yn, MAX_SAFE_INTEGER);
3070
+ var first = (cfs[0] || 0) > 0; // successor: the outer count is y-2
3071
+ var fracOpd = (fsOpd === undefined) ? null : fsOpd;
3072
+ var baseIdx = xn;
3073
+ var fracRem = 0; // fractional constant carried to the base
3074
+ var guard = 0;
3075
+ while (rows.length < budget && guard++ < 10000) {
3076
+ if (!coeffsHaveOmegaPart(cfs)) break; // finite level: no row
3077
+ if ((cfs[0] || 0) > 0) {
3078
+ var mRaw = cfs[0];
3079
+ var m = Math.floor(mRaw);
3080
+ // a fractional constant term (from a fundamental sequence taken at a
3081
+ // fractional index) is not a valid CNF coefficient — keep the integer
3082
+ // part as rows and carry the remainder into the base's finite level
3083
+ // index (x{10.16}x), which is exactly how the ω level interpolates
3084
+ var mFr = Number((mRaw - m).toPrecision(15));
3085
+ if (mFr > 1e-9) fracRem = mFr;
3086
+ var beta = trimCoeffs(cfs.slice());
3087
+ beta[0] = 0;
3088
+ beta = trimCoeffs(beta);
3089
+ var steps = Math.min(m, budget - rows.length + 1);
3090
+ for (var s = 0; s < steps; s++) {
3091
+ var j = m - 1 - s; // rows β+m-1 … β
3092
+ var cnt = (first ? opd : xn) - 2;
3093
+ first = false;
3094
+ if (cnt < 1) continue;
3095
+ if (cnt > MAX_SAFE_INTEGER) cnt = MAX_SAFE_INTEGER;
3096
+ var ord = beta.slice();
3097
+ if (j > 0) ord[0] = (ord[0] || 0) + j; // β + j
3098
+ ord = trimCoeffs(ord);
3099
+ if (!coeffsHaveOmegaPart(ord)) continue; // finite: lives in r0
3100
+ rows.push([cnt].concat(ord));
2370
3101
  }
3102
+ cfs = beta; // continue below β
3103
+ opd = Math.min(xn, MAX_SAFE_INTEGER); // everything below the top
3104
+ continue; // row is base-operand
3105
+ }
3106
+ // limit: fundamental sequence at the current operand (rule 3)
3107
+ var idx = (fracOpd !== null) ? fracOpd : opd;
3108
+ fracOpd = null;
3109
+ baseIdx = idx;
3110
+ var nxt = fsCoeffs(cfs, idx);
3111
+ if (coeffsHaveFraction(nxt)) {
3112
+ // a fractional index makes the coefficients fractional (ω^k·(c+f)) —
3113
+ // resolve them against the base so every row coefficient stays an
3114
+ // integer, carrying the leftover constant fraction into the base
3115
+ var rs2 = Q._resolveFracLevel(nxt, xn);
3116
+ cfs = rs2.ord;
3117
+ if (rs2.frac > 0) fracRem = rs2.frac;
2371
3118
  } else {
2372
- result[k] = 0;
2373
- result = result.slice(0, k);
2374
- for (var i = 0; i < b.length; i++) {
2375
- result.push(b[i] || 0);
2376
- }
2377
- }
2378
- while (result.length > 0 && result[result.length - 1] === 0) result.pop();
2379
- return result;
2380
- }
2381
-
2382
- function isZero(ord) {
2383
- if (!ord || ord.length === 0) return true;
2384
- for (var i = 0; i < ord.length; i++) {
2385
- if ((ord[i] || 0) !== 0) return false;
3119
+ cfs = trimCoeffs(nxt);
2386
3120
  }
2387
- return true;
2388
- }
2389
-
2390
- function buildRow(ord, count) {
2391
- var maxIdx = ord.length - 1;
2392
- while (maxIdx >= 0 && (ord[maxIdx] || 0) === 0) maxIdx--;
2393
- if (maxIdx < 0) return null;
2394
- var row = [count];
2395
- for (var i = 0; i <= maxIdx - 1; i++) row.push(ord[i] || 0);
2396
- row.push(ord[maxIdx]);
2397
- return row;
3121
+ opd = Math.min(xn, MAX_SAFE_INTEGER); // operand becomes x
2398
3122
  }
3123
+ rows.baseIdx = baseIdx + fracRem; // descending by ordinal
3124
+ return rows;
3125
+ };
2399
3126
 
2400
- // Enumerate all ordinals below ω^k with coefficients < n
2401
- function enumBelowOmegaK(k, n) {
2402
- if (k === 0) {
2403
- return [[0]];
2404
- }
2405
- if (k === 1) {
2406
- var result = [];
2407
- for (var i = 0; i < n; i++) {
2408
- result.push([i]);
2409
- }
2410
- return result;
2411
- }
2412
- var result = [];
2413
- for (var a = 0; a < n; a++) {
2414
- var sub = enumBelowOmegaK(k - 1, n);
2415
- for (var i = 0; i < sub.length; i++) {
2416
- var combined = sub[i].slice();
2417
- while (combined.length < k) combined.push(0);
2418
- combined[k - 1] = a;
2419
- result.push(combined);
2420
- }
2421
- }
2422
- return result;
3127
+ Q._expandedHyperop = function (x, y, cf, fsOpd) {
3128
+ var maxRows = MetaNum.maxRows;
3129
+ var xn = Math.floor(metaFiniteCount(x));
3130
+ var yn = Math.floor(metaFiniteCount(y));
3131
+ var budget = maxRows - 1; // ordinal rows the array holds
3132
+ var desc = Q._cascadeRows(xn, cf, yn, budget + 1, fsOpd); // +1 detects truncation
3133
+ var truncated = desc.length > budget;
3134
+ if (truncated) desc = desc.slice(0, budget); // keep the LARGEST rows
3135
+ var rows = desc.reverse(); // ascending
3136
+ // base r0 = x{idx}x (rule 3 at the ω level: x{ω}x = x{x}x) — the finite part;
3137
+ // idx is the operand of the descent that bottoms out, i.e. the fractional
3138
+ // start value x^f when the cascade came from the fractional successor rule
3139
+ var baseIdx = (desc.baseIdx === undefined) ? xn : desc.baseIdx;
3140
+ // arrow() evaluates fractional levels too (10{10.2589}10 ≠ 10{10}10), so the
3141
+ // carried fraction survives into the base
3142
+ var baseResult = x.arrow(Math.max(baseIdx, 3))(x);
3143
+ var result = baseResult.clone();
3144
+ if (truncated) {
3145
+ result.array = [[10]];
3146
+ rows[0][0] = (rows[0][0] || 0) + 1; // truncation marker
3147
+ if (rows[0][0] > MAX_SAFE_INTEGER) rows[0][0] = MAX_SAFE_INTEGER;
3148
+ } else {
3149
+ result.array = [baseResult.array[0].slice()];
2423
3150
  }
3151
+ for (var i = 0; i < rows.length; i++) result.array.push(rows[i]);
3152
+ result.layer = 0;
3153
+ return result.normalize();
3154
+ };
2424
3155
 
2425
- // Enumerate all ordinals below a given ordinal
2426
- function enumBelow(alpha, n) {
2427
- if (isZero(alpha)) return [];
2428
-
2429
- if ((alpha[0] || 0) > 0) {
2430
- var pred = alpha.slice();
2431
- pred[0]--;
2432
- while (pred.length > 0 && pred[pred.length - 1] === 0) pred.pop();
2433
- if (pred.length === 0) pred = [0];
2434
- var result = enumBelow(pred, n);
2435
- result.push(pred.slice());
2436
- return result;
2437
- }
2438
-
2439
- var k = alpha.length - 1;
2440
- while (k >= 0 && (alpha[k] || 0) === 0) k--;
2441
- if (k < 0) return [];
2442
-
2443
- var ck = alpha[k] || 0;
2444
- var rest = alpha.slice(0, k);
2445
- while (rest.length > 0 && rest[rest.length - 1] === 0) rest.pop();
2446
-
2447
- var result = [];
2448
-
2449
- for (var j = 0; j < ck; j++) {
2450
- var sub = enumBelowOmegaK(k, n);
2451
- for (var i = 0; i < sub.length; i++) {
2452
- var combined = sub[i].slice();
2453
- while (combined.length <= k) combined.push(0);
2454
- combined[k] = j;
2455
- result.push(combined);
2456
- }
2457
- }
2458
-
2459
- if (!isZero(rest)) {
2460
- var restSub = enumBelow(rest, n);
2461
- for (var i = 0; i < restSub.length; i++) {
2462
- var combined = restSub[i].slice();
2463
- while (combined.length <= k) combined.push(0);
2464
- combined[k] = ck;
2465
- result.push(combined);
2466
- }
2467
- }
2468
-
2469
- return result;
3156
+ // Any coefficient with a non-zero fractional part?
3157
+ function coeffsHaveFraction(coeffs) {
3158
+ for (var i = 0; i < coeffs.length; i++) {
3159
+ var c = coeffs[i] || 0;
3160
+ if (c !== Math.floor(c)) return true;
2470
3161
  }
3162
+ return false;
3163
+ }
2471
3164
 
2472
- var count = n - 2;
2473
- if (count < 1) return rows;
2474
-
2475
- var allOrdinals = enumBelow(coeffs, n);
2476
-
2477
- var seen = {};
2478
- var uniqueOrdinals = [];
2479
- for (var i = 0; i < allOrdinals.length; i++) {
2480
- var ord = allOrdinals[i];
2481
- if (isZero(ord)) continue;
2482
-
2483
- // Normalize: remove trailing zeros
2484
- var normalized = ord.slice();
2485
- while (normalized.length > 0 && normalized[normalized.length - 1] === 0) {
2486
- normalized.pop();
3165
+ // Resolve fractional CNF coefficients against the base x (see the comment in
3166
+ // _hyperopFromOrdinalRaw): ω^(k)·(c+f) = ω^(k)·c + ω^(k-1)·(x·f) top-down.
3167
+ // Returns the integer level plus the fractional part left in the constant term.
3168
+ Q._resolveFracLevel = function (cf, xn) {
3169
+ var r = trimCoeffs((cf || []).slice());
3170
+ for (var k = r.length - 1; k >= 1; k--) {
3171
+ var c = r[k] || 0;
3172
+ var fl = Math.floor(c);
3173
+ var fr = Number((c - fl).toPrecision(15));
3174
+ if (fr > 1e-9) {
3175
+ r[k] = fl;
3176
+ r[k - 1] = (r[k - 1] || 0) + xn * fr;
2487
3177
  }
2488
-
2489
- // Skip ordinals below ω (finite ordinals: only constant term, length <= 1)
2490
- if (normalized.length <= 1) continue;
2491
-
2492
- var key = normalized.join(',');
2493
- if (seen[key]) continue;
2494
- seen[key] = true;
2495
- uniqueOrdinals.push(normalized);
2496
3178
  }
2497
-
2498
- uniqueOrdinals.sort(function (a, b) {
2499
- return compareOrd(a, b);
2500
- });
2501
-
2502
- var allRows = [];
2503
- for (var i = 0; i < uniqueOrdinals.length; i++) {
2504
- var row = buildRow(uniqueOrdinals[i], count);
2505
- if (row) allRows.push(row);
2506
- }
2507
-
2508
- var maxOrdinalRows = maxRows - 1;
2509
- if (allRows.length > maxOrdinalRows) {
2510
- allRows = allRows.slice(allRows.length - maxOrdinalRows);
2511
- }
2512
-
2513
- for (var i = 0; i < allRows.length; i++) {
2514
- rows.push(allRows[i]);
2515
- }
2516
-
2517
- return rows;
3179
+ var c0 = r[0] || 0;
3180
+ var fl0 = Math.floor(c0);
3181
+ var fr0 = Number((c0 - fl0).toPrecision(15));
3182
+ if (!(fr0 > 1e-9)) fr0 = 0;
3183
+ r[0] = fl0;
3184
+ return { ord: trimCoeffs(r), frac: fr0 };
2518
3185
  };
2519
3186
 
2520
3187
  // Helper: number of leading iterate applications (of level `beta`) starting
@@ -2532,6 +3199,26 @@
2532
3199
  return steps + 1;
2533
3200
  }
2534
3201
 
3202
+ // Inverse of a LIMIT level taken through the expanded cascade: x{λ}y = x{λ[y]}x
3203
+ // makes every row depend on y only through the fundamental sequence, so instead
3204
+ // of reading a count row we search the (monotone) forward map.
3205
+ Q._invExpandedLimit = function (base, value, coeffs) {
3206
+ var lo = 3, hi = MAX_SAFE_INTEGER, best = 0;
3207
+ var v3 = Q._expandedHyperop(base, new MetaNum(3), coeffs);
3208
+ if (value.lt(v3)) return base.clone();
3209
+ while (lo <= hi) {
3210
+ var mid = lo + Math.floor((hi - lo) / 2);
3211
+ if (Q._expandedHyperop(base, new MetaNum(mid), coeffs).lte(value)) {
3212
+ best = mid; lo = mid + 1;
3213
+ } else {
3214
+ hi = mid - 1;
3215
+ }
3216
+ }
3217
+ if (best === 0) return base.clone();
3218
+ var vb = Q._expandedHyperop(base, new MetaNum(best), coeffs);
3219
+ return vb.eq(value) ? new MetaNum(best) : base.clone();
3220
+ };
3221
+
2535
3222
  // Helper: generic inverse hyperoperation from ordinal level.
2536
3223
  // Forward paths and the rows they leave:
2537
3224
  // - small x ∈ [3, MSI] & small y (enumeration path): rows for each ordinal
@@ -2564,14 +3251,29 @@
2564
3251
  }
2565
3252
  if (cf.length === 0) return z;
2566
3253
 
2567
- // enumeration path (base z is a small finite number ≥ 3): top row count = y-2
3254
+ // expanded cascade path (base z is a small finite number ≥ 3): the forward
3255
+ // operation wrote the rule-1..4 cascade rows.
3256
+ // successor α: the row at α-1 carries exactly y-2 applications → +2
3257
+ // limit α: every row carries x-2 and y only appears inside the
3258
+ // fundamental-sequence rows, so it is recovered from the forward map
2568
3259
  var zC = metaFiniteCount(z);
2569
3260
  if (z.array.length === 1 && z.layer === 0 && zC >= 3 && zC <= MAX_SAFE_INTEGER) {
2570
- var lastRow = x.array[x.array.length - 1];
2571
- if (lastRow && lastRow.length >= 2 && (lastRow[0] || 0) > 0) {
2572
- return new MetaNum((lastRow[0] || 0) + 2);
3261
+ if ((cf[0] || 0) > 0) {
3262
+ var pred = succCoeffs(cf);
3263
+ var predRow = null;
3264
+ for (var pi = x.array.length - 1; pi >= 1; pi--) {
3265
+ var prow = x.array[pi];
3266
+ if (prow && prow.length >= 2 && (prow[0] || 0) > 0 &&
3267
+ cmpCoeffsLevel(rowToCoeffs(prow), pred) === 0) { predRow = prow; break; }
3268
+ }
3269
+ if (predRow) return new MetaNum((predRow[0] || 0) + 2);
3270
+ var lastRow = x.array[x.array.length - 1];
3271
+ if (lastRow && lastRow.length >= 2 && (lastRow[0] || 0) > 0) {
3272
+ return new MetaNum((lastRow[0] || 0) + 2);
3273
+ }
3274
+ return z;
2573
3275
  }
2574
- return z;
3276
+ return Q._invExpandedLimit(z, x, cf);
2575
3277
  }
2576
3278
 
2577
3279
  // engine path: count row [c | β] with β = α-1 (successor α only)
@@ -2909,78 +3611,72 @@
2909
3611
  // Hyperoperations from ω^ω up to ε₀
2910
3612
  // ---------------------------------------------------------------------------
2911
3613
 
2912
- // iter (ω^ω): diagonalizes ω^x operations
2913
- // k <= maxCols-2: layer 0, multi-index; k >= maxCols-1: layer 1
2914
- // e.g. iter(3,5)=3{ω^ω}5=3{ω^5}5=3{ω^4*4+ω^3*4+ω^2*4+ω*4+5}5=(3{ω^4*4+ω^3*4+ω^2*4+ω*4+4})^3...
2915
- // so iter(3,5) → layer=0, max array row=[3,4,4,4,4,4]
2916
- // for maxcol-1 <= k <= MSI, iter(3,k)=3{ω^ω}k=3{ω^k}k
2917
- // reference to README.md, when layer=1, array=[[0],[1,k]] represents 10{ω^k}10
2918
- // array [[1], [1,k]] represents 10{ω^k+1}10=10{ω^k}^9 10
2919
- // so iter(3,k)≈10{ω^k}10 → layer=1, max array row=[[0],[1,k]]
2920
- // for k > MSI, iter(3,k)≈10{ω^ω}MSI → layer=1, array=[[0],[1,0,1]], which represents 10{ω^ω}MSI
2921
- // 10{ω^ω+1}x (2<=x<=10, =10{ω^ω+1}(>MSI) if x=2) should be treated as 10{ω^ω+a}10, a=log5(x/2)
2922
- // iter(10,iter(10,10))=10{ω^ω}10{ω^ω}10=10{ω^ω+1}3→array=[[log5(3/2)],[1,0,1]]
2923
- P.iteration = P.iter = P.hww = function (y) {
3614
+ // ---------------------------------------------------------------------------
3615
+ // Hyperoperations from ω^ω up to ε₀ — README rules 1-4 with the unified
3616
+ // limit rule n{λ}b = n{λ[b]}n (the final operand is the BASE n, never b).
3617
+ // Levels ≥ ω^ω have no finite CNF coefficient row, so — except where the
3618
+ // reduced level λ[y] still fits a layer-0 ordinal row — the result is stored
3619
+ // as the compact layer marker of λ[y] (see Q._layerMarker).
3620
+ // ---------------------------------------------------------------------------
3621
+
3622
+ // iter (ω^ω): (ω^ω)[y] = ω^y → x{ω^ω}y = x{ω^y}x
3623
+ // e.g. iter(3,5) = 3{ω^5}3 = 3{ω^4*3}3 = … = 3{ω^4*2+ω^3*2+ω^2*2+ω*2+2}3…
3624
+ // (whole fundamental-sequence cascade → layer 0 multi-row array)
3625
+ // for y >= maxCols the ω^y row no longer fits → layer=1 marker [[r0],[1,y]]
3626
+ // (= 10{ω^y}10), and for y > MSI the operand is unrepresentable → the
3627
+ // ω^ω marker row [1,0,1] (= 10{ω^ω}10).
3628
+ P.iterate = P.iter = P.hww = function (y) {
2924
3629
  var x = this.clone();
2925
3630
  y = new MetaNum(y);
2926
3631
  if (x.isNaN() || y.isNaN()) return MetaNum.NaN.clone();
2927
3632
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
2928
3633
  if (y.eq(MetaNum.ONE)) return x.clone();
2929
3634
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
2930
-
2931
- if (y.layer === 0 && y.array.length <= 1) {
2932
- var yn = y.toNumber();
2933
- var maxLevel = MetaNum.maxCols - 1;
2934
- if (yn < maxLevel) {
2935
- // y fits within ordinal levels: create ω^y at layer 0
2936
- // Multi-index format: [1, 0, 0, ..., 0, 1] with yn zeros
2937
- var result = x.clone();
2938
- var row = [1];
2939
- for (var i = 0; i < yn; i++) row.push(0);
2940
- row.push(1);
2941
- result.layer = 0;
2942
- result.array.push(row);
2943
- result.normalize();
2944
- return result;
2945
- } else {
2946
- // y >= maxLevel: promote to layer 1, compact format [[x],[1,yn]]
2947
- // ordinal level ω^y needs a row longer than maxCols, so it is stored
2948
- // as layer=1 (level = ω^P with P = yn constant); cap at MSI
2949
- var result = x.clone();
2950
- result.layer = 1;
2951
- var yv = yn > MAX_SAFE_INTEGER ? MAX_SAFE_INTEGER : yn;
2952
- result.array.push([1, yv]);
2953
- result.normalize();
2954
- return result;
2955
- }
2956
- }
2957
-
2958
- // y is ordinal: iter on ordinal
2959
- // Promote: absorb y's ordinal rows into r0, add iter marker
2960
- // Layer promotion consumes one level: skip the first value
2961
- var result = y.clone();
2962
- var newR0 = x.array[0].slice();
2963
- // Absorb y's ordinal rows into r0 (skip count and first value)
2964
- for (var ir = 1; ir < y.array.length; ir++) {
2965
- var yrow = y.array[ir];
2966
- // Start from index 2 to skip count and first ordinal value
2967
- for (var jc = 2; jc < yrow.length; jc++) {
2968
- newR0.push(yrow[jc]);
2969
- }
2970
- }
2971
- result.array[0] = newR0;
2972
- result.array = [newR0];
2973
- // Add iter's own ordinal marker
2974
- result.array.push([1, 0, 1]);
2975
- result.layer = y.layer + 1;
2976
- result.normalize();
2977
- return result;
2978
- };
2979
- Q.iteration = Q.iter = Q.hww = function (x, y) {
2980
- return new MetaNum(x).iteration(y);
2981
- };
2982
3635
 
2983
- P.inv_iteration = P.inv_iter = P.iww = function (z) {
3636
+ // iterate(x,y) = x{ω^ω}y. Rule 3 with the fundamental sequence
3637
+ // (ω^ω)[y] = ω^y: x{ω^ω}y = x{ω^y}x — final operand is the base x.
3638
+ var yc = metaFiniteCount(y);
3639
+ if (yc === Math.floor(yc) && yc <= MAX_SAFE_INTEGER) {
3640
+ var m = Math.max(2, Math.floor(yc));
3641
+ if (m < MetaNum.maxCols) {
3642
+ // ω^y is a layer-0 ordinal (coeffs with 1 at index y): evaluate
3643
+ // x{ω^y}x through the unified rule-1..3 engine. E.g.
3644
+ // iterate(3,5) = 3{ω^5}3 = the full FS cascade (truncated when it
3645
+ // overflows the row budget).
3646
+ var coeffs = [];
3647
+ for (var ci = 0; ci < m; ci++) coeffs.push(0);
3648
+ coeffs.push(1);
3649
+ return Q._hyperopFromOrdinal(x, x, coeffs);
3650
+ }
3651
+ // y >= maxCols: ω^y needs a row longer than maxCols — store as the
3652
+ // layer-1 compact marker 10{ω^y}10, capped at MSI
3653
+ return Q._layerMarker([10], 1, [[1, m]]);
3654
+ }
3655
+ if (yc <= MAX_SAFE_INTEGER) {
3656
+ // fractional y: (ω^ω)[y] = ω^y = ω^(m+f) = ω^m·ω^f, and on the diagonal
3657
+ // ω^f reads as x^f — so the level is ω^m·(x^f), whose coefficients carry
3658
+ // x^f at index m (README: 10{ω^ω}2.1 = 10{ω^2.1}10 = 10{ω^2*10^0.1}10).
3659
+ // Flooring y would lose the fraction and make iterate(10,2.1)=iterate(10,2).
3660
+ var mf = Math.max(2, Math.floor(yc));
3661
+ var ff = Number((yc - Math.floor(yc)).toPrecision(15));
3662
+ var xnf = x.toNumber();
3663
+ var cfac = (isFinite(xnf) && xnf >= 2 && ff > 0) ? Math.pow(xnf, ff) : 1;
3664
+ if (mf < MetaNum.maxCols) {
3665
+ var cfw = [];
3666
+ for (var cw = 0; cw < mf; cw++) cfw.push(0);
3667
+ cfw.push(cfac);
3668
+ return Q._hyperopFromOrdinal(x, x, cfw);
3669
+ }
3670
+ return Q._layerMarker([10], 1, [[cfac, mf]]);
3671
+ }
3672
+ // ordinal / out-of-range operand: y plus one ω^ω marker row
3673
+ return Q._ordinalOperandOp(y, 1, [1, 0, 1]);
3674
+ };
3675
+ Q.iterate = Q.iter = Q.hww = function (x, y) {
3676
+ return new MetaNum(x).iterate(y);
3677
+ };
3678
+
3679
+ P.inv_iterate = P.inv_iter = P.iww = function (z) {
2984
3680
  var x = this.clone();
2985
3681
  z = new MetaNum(z);
2986
3682
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
@@ -3029,14 +3725,17 @@
3029
3725
  }
3030
3726
  return z;
3031
3727
  };
3032
- Q.inv_iteration = Q.inv_iter = Q.iww = function (x, z) {
3033
- return new MetaNum(x).inv_iteration(z);
3728
+ Q.inv_iterate = Q.inv_iter = Q.iww = function (x, z) {
3729
+ return new MetaNum(x).inv_iterate(z);
3034
3730
  };
3035
3731
 
3036
- // itermult (ω^ω+1): iterates ω^ω level operations
3037
- // for k <= MSI, itmu(3,k)=3{ω^ω+1}k=3{ω^ω}3{ω^ω}...3 with k 3's
3038
- // ≈10{ω^ω+1}k → layer=1, array=[[n],[1,0,1]] (n=log5(k/2) if 2<=k<10, n=1 if k>=10)
3039
- // for k > MSI, itmu(3,k)≈10{ω^ω+1}MSI → layer=1, array=[[1],[1,0,1]]
3732
+ // itermult (ω^ω+1): successor level — x{ω^ω+1}y = x{ω^ω} applied y-1 times
3733
+ // to x (rule 2), i.e. itmu(3,k) = 3{ω^ω}3{ω^ω}…3 with k 3's.
3734
+ // k = 2 → x{ω^ω}x = iterate(x,x) exactly; 1 < k < 2 → x{ω^ω}(x^(k-1)).
3735
+ // k > 2 → layer=1 marker [[k-1],[1,0,1]] = 10{ω^ω+(k-1)}10: any finite
3736
+ // number of ω^ω applications stays strictly below ω^ω·2, so the count
3737
+ // lives in the constant term (ω^ω + n) — monotone in k and still below
3738
+ // cuboiter's ω^ω+ω^k.
3040
3739
  P.itermult = P.itmu = P.hw01 = function (y) {
3041
3740
  var x = this.clone();
3042
3741
  y = new MetaNum(y);
@@ -3044,24 +3743,20 @@
3044
3743
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3045
3744
  if (y.eq(MetaNum.ONE)) return x.clone();
3046
3745
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3047
- if (y.layer === 0 && y.array.length <= 1) {
3048
- var yn = y.toNumber();
3049
- var base = x.iter(x);
3050
- if (y.eq(2)) return base;
3051
- var result = base.clone();
3052
- result.layer = 1;
3053
- result.array = [base.array[0].slice()];
3054
- result.array[0] = [yn];
3055
- result.array.push([1, yn, 1]);
3056
- result.normalize();
3057
- return result;
3746
+ var yc = metaFiniteCount(y);
3747
+ if (yc <= MAX_SAFE_INTEGER) {
3748
+ if (yc <= 2) {
3749
+ // rule 2 with one iteration: x{ω^ω+1}k = x{ω^ω}(x^(k-1)) (x^1 = x)
3750
+ var f = y.sub(MetaNum.ONE);
3751
+ return f.eq(MetaNum.ZERO) ? x.iterate(x) : x.iterate(x.pow(f));
3752
+ }
3753
+ var n = Math.ceil(yc) - 1; // number of ω^ω applications
3754
+ if (n < 1) n = 1;
3755
+ if (n > MAX_SAFE_INTEGER) n = MAX_SAFE_INTEGER;
3756
+ return Q._layerMarker([n], 1, [[1, 0, 1]]);
3058
3757
  }
3059
- var result = y.clone();
3060
- result.layer = Math.max(result.layer, 1);
3061
- var base = x.iter(x);
3062
- result.array[0] = base.array[0].slice();
3063
- result.normalize();
3064
- return result;
3758
+ // ordinal / out-of-range operand: y plus one ω^ω marker row
3759
+ return Q._ordinalOperandOp(y, 1, [1, 0, 1]);
3065
3760
  };
3066
3761
  Q.itermult = Q.itmu = Q.hw01 = function (x, y) {
3067
3762
  return new MetaNum(x).itermult(y);
@@ -3071,13 +3766,24 @@
3071
3766
  var x = this.clone();
3072
3767
  z = new MetaNum(z);
3073
3768
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
3769
+ // marker [[n],[1,0,1]] = 10{ω^ω+n}10: the iteration count n sits in the
3770
+ // constant term, so y = n + 1 applications of the ω^ω level.
3771
+ if (x.layer >= 1) {
3772
+ for (var i = x.array.length - 1; i >= 1; i--) {
3773
+ var row = x.array[i];
3774
+ if (row.length === 3 && row[1] === 0 && row[2] === 1 && row[0] === 1) {
3775
+ var n = Math.round(x.array[0][0] || 0);
3776
+ return new MetaNum(n + 1);
3777
+ }
3778
+ }
3779
+ }
3074
3780
  if (x.array.length >= 2) {
3075
3781
  var result = x.clone();
3076
- for (var i = result.array.length - 1; i >= 1; i--) {
3077
- var row = result.array[i];
3078
- if (row.length >= 3 && row[0] > 0) {
3079
- row[0]--;
3080
- if (row[0] <= 0) result.array.splice(i, 1);
3782
+ for (var j = result.array.length - 1; j >= 1; j--) {
3783
+ var row2 = result.array[j];
3784
+ if (row2.length >= 3 && row2[0] > 0) {
3785
+ row2[0]--;
3786
+ if (row2[0] <= 0) result.array.splice(j, 1);
3081
3787
  result.normalize();
3082
3788
  if (result.array.length <= 1) result.layer = 0;
3083
3789
  return result;
@@ -3091,10 +3797,10 @@
3091
3797
  return new MetaNum(x).inv_itermult(z);
3092
3798
  };
3093
3799
 
3094
- // cuboiter (ω^ω*2): x{(ω^ω)*2}y = x{ω^ω+ω^y}y
3095
- // for k <= MSI, cube(3,k)=3{ω^ω+ω^k}k
3096
- // ≈10{ω^ω+ω^k}k → layer=1, array=[[0],[1,k],[1,0,1]]
3097
- // for k > MSI, cube(3,k)≈10{ω^ω*2}MSI → layer=1, array=[[0],[2,0,1]]
3800
+ // cuboiter (ω^ω*2): (ω^ω*2)[y] = ω^ω + ω^y → x{ω^ω*2}y = x{ω^ω+ω^y}x
3801
+ // for k <= MSI, cube(3,k)=3{ω^ω+ω^k}3
3802
+ // ≈10{ω^ω+ω^k}10 → layer=1, array=[[10],[1,k],[1,0,1]] (ω^k + ω^ω)
3803
+ // for k > MSI, cube(3,k)≈10{ω^ω*2}10 → layer=1, array=[[10],[2,0,1]]
3098
3804
  P.cuboiter = P.cube = P.hwx2 = function (y) {
3099
3805
  var x = this.clone();
3100
3806
  y = new MetaNum(y);
@@ -3102,24 +3808,14 @@
3102
3808
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3103
3809
  if (y.eq(MetaNum.ONE)) return x.clone();
3104
3810
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3105
- var base = x.itermult(x);
3106
- if (y.layer === 0 && y.array.length <= 1) {
3107
- var yn = y.toNumber();
3108
- if (y.eq(2)) return base;
3109
- var result = base.clone();
3110
- result.layer = 1;
3111
- result.array = [[1]];
3112
- result.array.push([1, yn, 1]);
3113
- result.array.push([1, 0, 1]);
3114
- result.normalize();
3115
- return result;
3811
+ var yc = metaFiniteCount(y);
3812
+ if (yc <= MAX_SAFE_INTEGER) {
3813
+ var m = Math.max(2, Math.floor(yc));
3814
+ if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
3815
+ return Q._layerMarker([10], 1, [[1, m], [1, 0, 1]]);
3116
3816
  }
3117
- var result = y.clone();
3118
- result.layer = 1;
3119
- result.array[0] = base.array[0].slice();
3120
- result.array.push([1, 0, 1]);
3121
- result.normalize();
3122
- return result;
3817
+ // ordinal / out-of-range operand: y plus two ω^ω marker rows (ω^ω*2)
3818
+ return Q._ordinalOperandOp(y, 1, [2, 0, 1]);
3123
3819
  };
3124
3820
  Q.cuboiter = Q.cube = Q.hwx2 = function (x, y) {
3125
3821
  return new MetaNum(x).cuboiter(y);
@@ -3130,20 +3826,26 @@
3130
3826
  z = new MetaNum(z);
3131
3827
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
3132
3828
  if (x.array.length >= 2) {
3133
- // For finite y: find [1, yn, 1] with yn > 0 and return yn
3134
- // (skip [1, 0, 1] which is the cuboiter marker)
3135
- for (var i = x.array.length - 1; i >= 1; i--) {
3136
- var row = x.array[i];
3137
- if (row.length === 3 && row[0] === 1 && row[2] === 1 && row[1] > 0) {
3138
- return new MetaNum(row[1]);
3829
+ // standard marker [[…,1@y,…],[1,0,1]] = 10{ω^ω+ω^y}10: the ω^y term is
3830
+ // merged into r0 (index y) whenever y < maxCols, else it is the row [1,y]
3831
+ if (x.layer >= 1) {
3832
+ var r0 = x.array[0];
3833
+ for (var j = r0.length - 1; j >= 1; j--) {
3834
+ if ((r0[j] || 0) > 0) return new MetaNum(j);
3835
+ }
3836
+ for (var i = x.array.length - 1; i >= 1; i--) {
3837
+ var row = x.array[i];
3838
+ if (row.length === 2 && row[0] === 1 && row[1] > 0) {
3839
+ return new MetaNum(row[1]);
3840
+ }
3139
3841
  }
3140
3842
  }
3141
3843
  // For ordinal y: find [1, 0, 1] marker and return y
3142
- for (var i = x.array.length - 1; i >= 1; i--) {
3143
- var row = x.array[i];
3144
- if (row.length >= 3 && row[1] === 0 && row[2] === 1 && row[0] === 1) {
3844
+ for (var k = x.array.length - 1; k >= 1; k--) {
3845
+ var row2 = x.array[k];
3846
+ if (row2.length >= 3 && row2[1] === 0 && row2[2] === 1 && row2[0] === 1) {
3145
3847
  var result = x.clone();
3146
- result.array.splice(i, 1);
3848
+ result.array.splice(k, 1);
3147
3849
  result.normalize();
3148
3850
  if (result.array.length <= 1) result.layer = 0;
3149
3851
  return result;
@@ -3156,10 +3858,10 @@
3156
3858
  return new MetaNum(x).inv_cuboiter(z);
3157
3859
  };
3158
3860
 
3159
- // expoiter (ω^(ω+1)): x{ω^(ω+1)}y = x{ω^ω * y}y
3160
- // for k <= MSI, expo(3,k)=3{ω^ω*k}k
3161
- // ≈10{ω^ω*k}k → layer=1, array=[[0],[k,0,1]]
3162
- // for k > MSI, expo(3,k)≈10{ω^(ω+1)}MSI → layer=1, array=[[0],[1,1,1]]
3861
+ // expoiter (ω^(ω+1)): (ω^(ω+1))[y] = ω^ω*y → x{ω^(ω+1)}y = x{ω^ω*y}x
3862
+ // for k <= MSI, expo(3,k)=3{ω^ω*k}3
3863
+ // ≈10{ω^ω*k}10 → layer=1, array=[[10],[k,0,1]]
3864
+ // for k > MSI, expo(3,k)≈10{ω^(ω+1)}10 → layer=1, array=[[10],[1,1,1]]
3163
3865
  P.expoiter = P.expo = P.hwa1 = function (y) {
3164
3866
  var x = this.clone();
3165
3867
  y = new MetaNum(y);
@@ -3167,23 +3869,14 @@
3167
3869
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3168
3870
  if (y.eq(MetaNum.ONE)) return x.clone();
3169
3871
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3170
- var base = x.iter(x);
3171
- if (y.layer === 0 && y.array.length <= 1) {
3172
- var yn = y.toNumber();
3173
- if (y.eq(2)) return x.cuboiter(x);
3174
- var result = base.clone();
3175
- result.layer = 1;
3176
- result.array = [[1]];
3177
- result.array.push([yn, 0, 1]);
3178
- result.normalize();
3179
- return result;
3872
+ var yc = metaFiniteCount(y);
3873
+ if (yc <= MAX_SAFE_INTEGER) {
3874
+ var m = Math.max(2, Math.floor(yc));
3875
+ if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
3876
+ return Q._layerMarker([10], 1, [[m, 0, 1]]);
3180
3877
  }
3181
- var result = y.clone();
3182
- result.layer = 1;
3183
- result.array[0] = base.array[0].slice();
3184
- result.array.push([1, 0, 1]);
3185
- result.normalize();
3186
- return result;
3878
+ // ordinal / out-of-range operand: y plus one ω^(ω+1) marker row
3879
+ return Q._ordinalOperandOp(y, 1, [1, 1, 1]);
3187
3880
  };
3188
3881
  Q.expoiter = Q.expo = Q.hwa1 = function (x, y) {
3189
3882
  return new MetaNum(x).expoiter(y);
@@ -3194,24 +3887,24 @@
3194
3887
  z = new MetaNum(z);
3195
3888
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
3196
3889
  if (x.array.length >= 2) {
3197
- // For ordinal y: find [1, 0, 1] marker and return y
3890
+ // marker [y,0,1] = 10{ω^ω·y}10 → the count carries y
3198
3891
  for (var i = x.array.length - 1; i >= 1; i--) {
3199
3892
  var row = x.array[i];
3200
- if (row.length >= 3 && row[1] === 0 && row[2] === 1 && row[0] === 1) {
3893
+ if (row.length === 3 && row[1] === 0 && row[2] === 1 && row[0] > 0) {
3894
+ return new MetaNum(row[0]);
3895
+ }
3896
+ }
3897
+ // For ordinal y: find [1, 0, 1] marker and return y
3898
+ for (var k = x.array.length - 1; k >= 1; k--) {
3899
+ var row2 = x.array[k];
3900
+ if (row2.length >= 3 && row2[1] === 0 && row2[2] === 1 && row2[0] === 1) {
3201
3901
  var result = x.clone();
3202
- result.array.splice(i, 1);
3902
+ result.array.splice(k, 1);
3203
3903
  result.normalize();
3204
3904
  if (result.array.length <= 1) result.layer = 0;
3205
3905
  return result;
3206
3906
  }
3207
3907
  }
3208
- // For finite y: find [yn, 0, 1] and return yn
3209
- for (var i = x.array.length - 1; i >= 1; i--) {
3210
- var row = x.array[i];
3211
- if (row.length === 3 && row[1] === 0 && row[2] === 1 && row[0] > 0) {
3212
- return new MetaNum(row[0]);
3213
- }
3214
- }
3215
3908
  }
3216
3909
  return z;
3217
3910
  };
@@ -3219,10 +3912,10 @@
3219
3912
  return new MetaNum(x).inv_expoiter(z);
3220
3913
  };
3221
3914
 
3222
- // trioterate (ω^(ω*2)): x{ω^(ω*2)}y = x{ω^(ω+y)}y
3223
- // for k <= MSI, tria(3,k)=3{ω^(ω+k)}k
3224
- // ≈10{ω^(ω+k)}k → layer=1, array=[[0],[1,k,1]]
3225
- // for k > MSI, tria(3,k)≈10{ω^(ω*2)}MSI → layer=1, array=[[0],[1,0,2]]
3915
+ // trioterate (ω^(ω*2)): (ω^(ω*2))[y] = ω^(ω+y) → x{ω^(ω*2)}y = x{ω^(ω+y)}x
3916
+ // for k <= MSI, tria(3,k)=3{ω^(ω+k)}3
3917
+ // ≈10{ω^(ω+k)}10 → layer=1, array=[[10],[1,k,1]] (ord = ω+k)
3918
+ // for k > MSI, tria(3,k)≈10{ω^(ω*2)}10 → layer=1, array=[[10],[1,0,2]]
3226
3919
  P.trioterate = P.tria = P.hwm2 = function (y) {
3227
3920
  var x = this.clone();
3228
3921
  y = new MetaNum(y);
@@ -3230,23 +3923,14 @@
3230
3923
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3231
3924
  if (y.eq(MetaNum.ONE)) return x.clone();
3232
3925
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3233
- if (y.layer === 0 && y.array.length <= 1) {
3234
- var yn = y.toNumber();
3235
- var base = x.expoiter(x);
3236
- if (y.eq(2)) return base;
3237
- var result = base.clone();
3238
- result.layer = 1;
3239
- result.array = [[1]];
3240
- result.array.push([1, yn, 1]);
3241
- result.normalize();
3242
- return result;
3926
+ var yc = metaFiniteCount(y);
3927
+ if (yc <= MAX_SAFE_INTEGER) {
3928
+ var m = Math.max(2, Math.floor(yc));
3929
+ if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
3930
+ return Q._layerMarker([10], 1, [[1, m, 1]]);
3243
3931
  }
3244
- var result = y.clone();
3245
- result.layer = 1;
3246
- var base = x.iter(x);
3247
- result.array[0] = base.array[0].slice();
3248
- result.normalize();
3249
- return result;
3932
+ // ordinal / out-of-range operand: y plus one ω^(ω*2) marker row
3933
+ return Q._ordinalOperandOp(y, 1, [1, 0, 2]);
3250
3934
  };
3251
3935
  Q.trioterate = Q.tria = Q.hwm2 = function (x, y) {
3252
3936
  return new MetaNum(x).trioterate(y);
@@ -3282,10 +3966,10 @@
3282
3966
  return new MetaNum(x).inv_trioterate(z);
3283
3967
  };
3284
3968
 
3285
- // trixxate (ω^(ω^2)): x{ω^(ω^2)}y=x{ω^(ω*y)}y
3286
- // for k <= MSI, trix(3,k)=3{ω^(ω*k)}k
3287
- // ≈10{ω^(ω*k)}k → layer=1, array=[[0],[1,0,k]]
3288
- // for k > MSI, trix(3,k)≈10{ω^(ω^2)}MSI → layer=1, array=[[0],[1,0,0,1]]
3969
+ // trixxate (ω^(ω^2)): (ω^(ω^2))[y] = ω^(ω*y) → x{ω^(ω^2)}y = x{ω^(ω*y)}x
3970
+ // for k <= MSI, trix(3,k)=3{ω^(ω*k)}3
3971
+ // ≈10{ω^(ω*k)}10 → layer=2, array=[[10],[k,1]] (bracket = ω*k, ω^bracket)
3972
+ // for k > MSI, trix(3,k)≈10{ω^(ω^2)}10 → layer=2, array=[[10],[1,2]]
3289
3973
  P.trixxate = P.trix = P.hwp2 = function (y) {
3290
3974
  var x = this.clone();
3291
3975
  y = new MetaNum(y);
@@ -3293,23 +3977,14 @@
3293
3977
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3294
3978
  if (y.eq(MetaNum.ONE)) return x.clone();
3295
3979
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3296
- if (y.layer === 0 && y.array.length <= 1) {
3297
- var yn = y.toNumber();
3298
- var base = x.trioterate(x);
3299
- if (y.eq(2)) return base;
3300
- var result = base.clone();
3301
- result.layer = 2;
3302
- result.array = [[1]];
3303
- result.array.push([1, yn, 1]);
3304
- result.normalize();
3305
- return result;
3980
+ var yc = metaFiniteCount(y);
3981
+ if (yc <= MAX_SAFE_INTEGER) {
3982
+ var m = Math.max(2, Math.floor(yc));
3983
+ if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
3984
+ return Q._layerMarker([10], 2, [[m, 1]]);
3306
3985
  }
3307
- var result = y.clone();
3308
- result.layer = 2;
3309
- var base = x.trioterate(x);
3310
- result.array[0] = base.array[0].slice();
3311
- result.normalize();
3312
- return result;
3986
+ // ordinal / out-of-range operand: y plus one ω^(ω^2) marker row
3987
+ return Q._ordinalOperandOp(y, 2, [1, 2]);
3313
3988
  };
3314
3989
  Q.trixxate = Q.trix = Q.hwp2 = function (x, y) {
3315
3990
  return new MetaNum(x).trixxate(y);
@@ -3319,6 +3994,12 @@
3319
3994
  var x = this.clone();
3320
3995
  z = new MetaNum(z);
3321
3996
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
3997
+ // standard marker [1,10,y] = 10{ω^(ω*y+10)}10 (layer 1) or [y,1] (layer 2)
3998
+ for (var k = x.array.length - 1; k >= 1; k--) {
3999
+ var rw = x.array[k];
4000
+ if (rw.length === 2 && rw[0] > 0 && rw[1] === 1) return new MetaNum(rw[0]);
4001
+ if (rw.length === 3 && rw[0] === 1 && rw[2] >= 2) return new MetaNum(rw[2]);
4002
+ }
3322
4003
  if (x.array.length >= 2) {
3323
4004
  // For ordinal y: find [1, 0, 1] marker and return y
3324
4005
  for (var i = x.array.length - 1; i >= 1; i--) {
@@ -3345,11 +4026,11 @@
3345
4026
  return new MetaNum(x).inv_trixxate(z);
3346
4027
  };
3347
4028
 
3348
- // aperixxate (ω^(ω^ω)): x{ω^(ω^ω)}y=x{ω^(ω^y)}y, can reach layer 2
3349
- // for k < maxCol-1, apix(3,k)≈10{ω^(ω^k)}k → layer=1, array=[[0],[1,0,0,...(k zeroes)...,0,1]]
3350
- // for maxCol-1 <= k <= MSI → layer=2, array=[[0],[1,k]]
3351
- // for k > MSI, apix(3,k)≈10{ω^(ω^2)}MSI → layer=2, array=[[0],[1,0,1]]
3352
- // Repetition count negligible for layer >= 2 (defaults to 1)
4029
+ // aperixxate (ω^(ω^ω)): (ω^(ω^ω))[y] = ω^(ω^y) → x{ω^(ω^ω)}y = x{ω^(ω^y)}x
4030
+ // for k <= MSI, apix(3,k)=3{ω^(ω^k)}3
4031
+ // ≈10{ω^(ω^k)}10 → layer=3, array=[[k]] (bracket = the constant k, so the
4032
+ // ordinal reads ω^(ω^k)); layer 3 is the ω^(ω^ω) level (README).
4033
+ // for k > MSI, apix(3,k)≈10{ω^(ω^ω)}10 → layer=3, array=[[10],[1,1]]
3353
4034
  P.aperixxate = P.apix = P.hwpw = function (y) {
3354
4035
  var x = this.clone();
3355
4036
  y = new MetaNum(y);
@@ -3357,23 +4038,14 @@
3357
4038
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3358
4039
  if (y.eq(MetaNum.ONE)) return x.clone();
3359
4040
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3360
- if (y.layer === 0 && y.array.length <= 1) {
3361
- var yn = y.toNumber();
3362
- var base = x.trixxate(x);
3363
- if (y.eq(2)) return base;
3364
- var result = base.clone();
3365
- result.layer = 3;
3366
- result.array = [[1]];
3367
- result.array.push([1, yn, 1]);
3368
- result.normalize();
3369
- return result;
4041
+ var yc = metaFiniteCount(y);
4042
+ if (yc <= MAX_SAFE_INTEGER) {
4043
+ var m = Math.max(2, Math.floor(yc));
4044
+ if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
4045
+ return Q._layerMarker([m], 3, []);
3370
4046
  }
3371
- var result = y.clone();
3372
- result.layer = 3;
3373
- var base = x.trixxate(x);
3374
- result.array[0] = base.array[0].slice();
3375
- result.normalize();
3376
- return result;
4047
+ // ordinal / out-of-range operand: y plus one ω^(ω^ω) marker row
4048
+ return Q._ordinalOperandOp(y, 3, [1, 1]);
3377
4049
  };
3378
4050
  Q.aperixxate = Q.apix = Q.hwpw = function (x, y) {
3379
4051
  return new MetaNum(x).aperixxate(y);
@@ -3383,6 +4055,24 @@
3383
4055
  var x = this.clone();
3384
4056
  z = new MetaNum(z);
3385
4057
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
4058
+ // standard marker [[10],[1,0,…,0,1]] = 10{ω^(ω^y)}10 → y+1 zeros-and-one
4059
+ // row length (layer 1), or the layer-≥2 merged form r0 = [...,1@y]
4060
+ for (var k = x.array.length - 1; k >= 1; k--) {
4061
+ var rw = x.array[k];
4062
+ if (rw.length >= 3 && rw[0] === 1 && rw[rw.length - 1] === 1) {
4063
+ var zeros = 0;
4064
+ for (var j = 1; j < rw.length - 1; j++) {
4065
+ if ((rw[j] || 0) === 0) zeros++; else break;
4066
+ }
4067
+ if (zeros === rw.length - 2 && zeros > 0) return new MetaNum(zeros);
4068
+ }
4069
+ }
4070
+ if (x.layer >= 2 && x.array.length === 1) {
4071
+ var rr = x.array[0];
4072
+ for (var j2 = rr.length - 1; j2 >= 1; j2--) {
4073
+ if ((rr[j2] || 0) > 0) return new MetaNum(j2);
4074
+ }
4075
+ }
3386
4076
  if (x.array.length >= 2) {
3387
4077
  // For ordinal y: find [1, 0, 1] marker and return y
3388
4078
  for (var i = x.array.length - 1; i >= 1; i--) {
@@ -3409,8 +4099,11 @@
3409
4099
  return new MetaNum(x).inv_aperixxate(z);
3410
4100
  };
3411
4101
 
3412
- // epsilonate (ε₀ = ω↑↑ω): x{ε₀}y=x{ω^ω^...(y ω's)}y
3413
- // layer varies with y
4102
+ // epsilonate (ε₀ = ω↑↑ω): ε₀[y] = ω^ω^…(y ω's) → x{ε₀}y = x{ω↑↑y}x
4103
+ // layer = y (README L17: layer L holds an ω-tower of height L), so
4104
+ // epsl(3,k) ≈ 10{ω^ω^…^ω(k ω's)}10 → layer=k, array=[[10],[1,1]]
4105
+ // (bracket = ω, (k-1) ω^'s above it → a tower of k ω's).
4106
+ // k > MSI → the ε-tower cap: layer=MSI (the MetaNum limit).
3414
4107
  P.epsilonate = P.epsl = P.hepsl = function (y) {
3415
4108
  var x = this.clone();
3416
4109
  y = new MetaNum(y);
@@ -3418,23 +4111,17 @@
3418
4111
  if (x.eq(MetaNum.ONE)) return MetaNum.ONE.clone();
3419
4112
  if (y.eq(MetaNum.ONE)) return x.clone();
3420
4113
  if (y.lte(MetaNum.ZERO)) return MetaNum.NaN.clone();
3421
- if (y.layer === 0 && y.array.length <= 1) {
3422
- var yn = y.toNumber();
3423
- var base = x.aperixxate(x);
3424
- if (y.eq(2)) return base;
3425
- var result = base.clone();
3426
- result.layer = yn;
3427
- result.array = [[1]];
3428
- result.array.push([1, yn, 1]);
3429
- result.normalize();
3430
- return result;
3431
- }
3432
- var result = y.clone();
3433
- result.layer = y.layer;
3434
- var base = x.aperixxate(x);
3435
- result.array[0] = base.array[0].slice();
3436
- result.normalize();
3437
- return result;
4114
+ // ε₀[2] = ω^ω, so epsilonate(x,2) = x{ω^ω}x = iterate(x,x) exactly (the
4115
+ // same value itermult(x,2) produces — x{ε₀}2 = x{ω^ω+1}2).
4116
+ if (y.eq(2)) return x.iterate(x);
4117
+ var yc = metaFiniteCount(y);
4118
+ if (yc <= MAX_SAFE_INTEGER) {
4119
+ var m = Math.max(2, Math.floor(yc));
4120
+ if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
4121
+ return Q._layerMarker([10], m, [[1, 1]]);
4122
+ }
4123
+ // ordinal / out-of-range operand: ε₀ caps the library → the MSI ω-tower
4124
+ return Q._layerMarker([10], MAX_SAFE_INTEGER, [[1, 1]]);
3438
4125
  };
3439
4126
  Q.epsilonate = Q.epsl = Q.hepsl = function (x, y) {
3440
4127
  return new MetaNum(x).epsilonate(y);
@@ -3444,6 +4131,15 @@
3444
4131
  var x = this.clone();
3445
4132
  z = new MetaNum(z);
3446
4133
  if (x.isNaN() || z.isNaN()) return MetaNum.NaN.clone();
4134
+ // standard marker: layer = y-1 with the de-layered tower row [1,10,1]
4135
+ if (x.layer >= 1) {
4136
+ for (var k = x.array.length - 1; k >= 1; k--) {
4137
+ var rw = x.array[k];
4138
+ if (rw.length === 3 && rw[0] === 1 && rw[2] === 1 && (rw[1] || 0) >= 2) {
4139
+ return new MetaNum(x.layer + 1);
4140
+ }
4141
+ }
4142
+ }
3447
4143
  if (x.array.length >= 2) {
3448
4144
  // For ordinal y: find [1, 0, 1] marker and return y
3449
4145
  for (var i = x.array.length - 1; i >= 1; i--) {
@@ -3867,17 +4563,19 @@
3867
4563
  var lastRow = this.array[this.array.length - 1];
3868
4564
  return lastRow[0] + "Aa" + lastRow[1];
3869
4565
  }
3870
- // Non-truncated: show all rows
4566
+ // Non-truncated: show all rows as space-separated "countAalevel"
4567
+ // tokens (count always included, so the parser can re-split them)
3871
4568
  var tokens = [];
3872
4569
  for (var i = this.array.length - 1; i >= 1; i--) {
3873
4570
  var row = this.array[i];
3874
- var tok = row[0] > 1 ? row[0] + "Aa" + row[1] : "Aa" + row[1];
3875
- tokens.push(tok);
4571
+ tokens.push(row[0] + "Aa" + row[1]);
3876
4572
  }
3877
4573
  var finOps = formatFiniteOps(this.array[0]);
3878
4574
  var hasAa = finOps && finOps.indexOf("Aa") !== -1;
3879
4575
  var baseNum = hasAa ? "" : decimalPlaces(this.array[0][0], 6);
3880
- return tokens.join("") + (finOps ? finOps : "") + baseNum;
4576
+ var tokStr = tokens.join(" ");
4577
+ if (tokStr !== "" && (finOps !== "" || baseNum !== "")) tokStr += " ";
4578
+ return tokStr + (finOps ? finOps : "") + baseNum;
3881
4579
  }
3882
4580
 
3883
4581
  var ordTokens = [];
@@ -3971,6 +4669,19 @@
3971
4669
  return this.toString();
3972
4670
  };
3973
4671
 
4672
+ // dlsdl letter-notation formatting (format-metanum.js, README "Format"
4673
+ // section). The module is resolved lazily to avoid a circular require:
4674
+ // format-metanum reads the MetaNum constructor from the global scope.
4675
+ // MetaNum("G600").format() → "1.000G600"
4676
+ // MetaNum.hardy(4166).format() → "2.397G5"
4677
+ P.format = function (precision, small) {
4678
+ var formatter = null;
4679
+ if (typeof require == 'function') {
4680
+ try { formatter = require('./format-metanum.js').format; } catch (e) { formatter = null; }
4681
+ }
4682
+ return format(this, precision, small);
4683
+ };
4684
+
3974
4685
  P.toExponential = function (places) {
3975
4686
  if (this.sign === -1 || this.sign === -2) return "-" + this.abs().toExponential(places);
3976
4687
  if (this.isNaN()) return "NaN";
@@ -4036,7 +4747,7 @@
4036
4747
  else x.sign = sign < 0 ? -1 : 1;
4037
4748
  } else x.sign = 1;
4038
4749
  if (typeof layer === "number" && isFinite(layer) && layer >= 0) x.layer = Math.floor(layer);
4039
- else x.layer = computeLayer(x.array);
4750
+ else x.layer = 0;
4040
4751
  return x.normalize();
4041
4752
  };
4042
4753
 
@@ -4626,14 +5337,16 @@
4626
5337
  cCount = parseInt(chainTokM[2], 10);
4627
5338
  for (var cli = 0; cli < cLetters.length; cli++) {
4628
5339
  var clLevel = cLetters.charCodeAt(cli) - 68; // E->1, F->2, ...
4629
- if (clLevel < 1 || clLevel >= MetaNum.maxCols - 1) { chainOk = false; break; }
5340
+ if (clLevel < 1 || clLevel > 99) { chainOk = false; break; }
4630
5341
  chainFin[clLevel] = (chainFin[clLevel] || 0) + (cli === cLetters.length - 1 ? cCount : 1);
4631
5342
  }
4632
5343
  if (!chainOk) break;
4633
5344
  } else {
4634
5345
  cLevel = parseInt(chainTokM[4], 10);
4635
5346
  cCount = parseInt(chainTokM[3], 10);
4636
- if (cLevel < 1 || cLevel >= MetaNum.maxCols - 1) { chainOk = false; break; }
5347
+ // Levels beyond maxCols are fine: normalize converts the r0
5348
+ // overflow into finite-level ordinal rows [count, level]
5349
+ if (cLevel < 1 || cLevel > 99) { chainOk = false; break; }
4637
5350
  chainFin[cLevel] = (chainFin[cLevel] || 0) + cCount;
4638
5351
  }
4639
5352
  }
@@ -4641,7 +5354,7 @@
4641
5354
  var chainCompact = chainMatch[3] || "";
4642
5355
  for (var cci = 0; cci < chainCompact.length && chainOk; cci++) {
4643
5356
  var cclLevel = chainCompact.charCodeAt(cci) - 68;
4644
- if (cclLevel >= 1 && cclLevel < MetaNum.maxCols - 1) {
5357
+ if (cclLevel >= 1 && cclLevel <= 99) {
4645
5358
  chainFin[cclLevel] = (chainFin[cclLevel] || 0) + 1;
4646
5359
  }
4647
5360
  }
@@ -4728,6 +5441,56 @@
4728
5441
  }
4729
5442
  }
4730
5443
 
5444
+ // Stacked layer symbols: peel the outermost symbol and add its layer
5445
+ // to the parsed remainder ("@!2.000Aaaa10" = parse of !form at one
5446
+ // higher layer).
5447
+ var stackedSym = rem.match(/^([!@#\$%&~<>?])([!@#\$%&~<>?]+\S*)$/);
5448
+ if (stackedSym) {
5449
+ var innerS = Q.fromString(stackedSym[2]);
5450
+ // each outer symbol is exactly one more ω^-tower layer
5451
+ innerS.layer = (innerS.layer || 0) + 1;
5452
+ if (negateIt) innerS.sign = -1;
5453
+ return innerS.normalize();
5454
+ }
5455
+
5456
+ // Canonical diagonal-letter output "mantissa LETTER β" where LETTER is
5457
+ // any multi-letter token ending in 'a' (Aa, Ba, Aaa, Aaaa, …), with the
5458
+ // dlsdl diagonal mantissa α ∈ [2,10):
5459
+ // exact anchor α=2.000 -> the plain letter application LETTER(β)
5460
+ // (2·5^0=2 adds nothing);
5461
+ // fractional α -> compact smooth row [α, β] (r0=[1]), the same
5462
+ // representation the engine emits for 10{β}(structured counts).
5463
+ var diagBinMatch = rem.match(/^([!@#\$%&~<>?]?)(\d+\.\d+)([A-Z][a-z]+)(\d[\d,]*)\s*$/);
5464
+ if (diagBinMatch) {
5465
+ var dbSym = diagBinMatch[1];
5466
+ var dbMant = Number(diagBinMatch[2]);
5467
+ var dbTok = diagBinMatch[3];
5468
+ var dbBeta = Number(String(diagBinMatch[4]).replace(/,/g, ""));
5469
+ if (isFinite(dbMant) && isFinite(dbBeta) &&
5470
+ dbTok[dbTok.length - 1] === "a" && dbMant >= 2 && dbMant < 10) {
5471
+ var dbVal;
5472
+ if (Math.abs(dbMant - 2) < 1e-9) {
5473
+ dbVal = Q.fromString(dbSym + dbTok + String(dbBeta));
5474
+ } else {
5475
+ // compact smooth form 10{β+1}(α): row [α, β] with r0=[1]
5476
+ dbVal = new MetaNum({ sign: 1, layer: 0, array: [[1], [dbMant, dbBeta]] });
5477
+ dbVal.normalize();
5478
+ if (dbSym) {
5479
+ dbVal.layer = "!@#$%&~<>?".indexOf(dbSym) + 1;
5480
+ dbVal.normalize();
5481
+ }
5482
+ }
5483
+ if (negateIt) dbVal.sign = -1;
5484
+ return dbVal;
5485
+ }
5486
+ }
5487
+
5488
+ // Binary-form α prefix with α = 1.000 exactly: Γ(β + log 1) = Γβ, so the
5489
+ // mantissa carries no information and can be stripped before matching
5490
+ // (e.g. "!1.000Aa5" ≡ "!Aa5", "1.000F300" ≡ "F300"). Non-unit α needs
5491
+ // the fractional-argument machinery and is not accepted here.
5492
+ rem = rem.replace(/^([!@#\$%&~<>?]?)1\.0+(?=[A-Z])/, '$1');
5493
+
4731
5494
  // Handle layer symbol prefix + letter pattern + optional finOps + number (e.g., !Abcd1234, !AaE16, @Bcde500)
4732
5495
  var symPrefixMatch = rem.match(/^([!@#\$%&~<>?])([A-Z][a-z]+(?:[A-Z][a-z]+)*)([A-Z]*)(\d+)\s*$/);
4733
5496
  if (symPrefixMatch) {
@@ -4737,12 +5500,17 @@
4737
5500
  rem = symPrefixMatch[2] + (symPrefixMatch[3] || '') + symPrefixMatch[4];
4738
5501
  }
4739
5502
 
4740
- var oaMatch = rem.match(/^((?:[A-Z][a-z]+)+)([A-Z]*)(\d+)/);
5503
+ // Ordinal-prefix chain with a full number argument — the argument may be
5504
+ // a plain integer ("AaG5"), a decimal ("AaG5.5"), or a sci-notation value
5505
+ // ("AaGF7.626E12", the round-trip of format() displays like "AaGF7.626E12"
5506
+ // whose letter chain carries a huge finite-arg). The old (\d+) regex ate
5507
+ // only "7" and silently dropped ".626E12".
5508
+ var oaMatch = rem.match(/^((?:[A-Z][a-z]+)+)([A-Z]*)((?:\d+(?:\.\d+)?(?:[Ee]\d+)?))$/);
4741
5509
  if (oaMatch) {
4742
5510
  var oaFullPrefix = oaMatch[1];
4743
5511
  var oaFinOps = oaMatch[2];
4744
5512
  var oaN = Number(oaMatch[3]);
4745
- if (!isNaN(oaN) && isFinite(oaN) && oaN >= 1 && oaN === Math.floor(oaN)) {
5513
+ if (!isNaN(oaN) && isFinite(oaN) && oaN >= 0) {
4746
5514
  var oaTokens = [];
4747
5515
  var oaTokenRegex = /[A-Z][a-z]+/g;
4748
5516
  var oaTm;
@@ -4925,9 +5693,9 @@
4925
5693
 
4926
5694
 
4927
5695
  // ==================== BEAF Ordinal Helpers ====================
4928
- // Build ordinal coefficient array from BEAF args (each arg contributes arg-1):
4929
- // BEAF(a,b,c,d,e,f,...) = a{...+ω^3*(f-1)+ω^2*(e-1)+ω*(d-1)+(c-1)}b
4930
- // coeffs[0] = c-1 (ω^0 = constant term)
5696
+ // Build ordinal coefficient array from BEAF args:
5697
+ // BEAF(a,b,c,d,e,f,...) = a{...+ω^3*(f-1)+ω^2*(e-1)+ω*(d-1)+c}b
5698
+ // coeffs[0] = c (ω^0 = constant term, no decrement)
4931
5699
  // coeffs[1] = d-1 (ω^1 coefficient)
4932
5700
  // coeffs[2] = e-1 (ω^2 coefficient)
4933
5701
  // coeffs[3] = f-1 (ω^3 coefficient)
@@ -4947,7 +5715,8 @@
4947
5715
  hugeArgs.push(arg.clone());
4948
5716
  coeffs.push(Infinity);
4949
5717
  } else {
4950
- coeffs.push(Math.max(0, Math.floor(eff) - 1));
5718
+ // constant term (i=2) keeps its value; ω^k coefficients (i>=3) decrement
5719
+ coeffs.push(i === 2 ? Math.max(0, Math.floor(eff)) : Math.max(0, Math.floor(eff) - 1));
4951
5720
  }
4952
5721
  }
4953
5722
  return { coeffs: coeffs, hugeArgs: hugeArgs };
@@ -4972,7 +5741,7 @@
4972
5741
  var cf = trimCoeffs(coeffs.map(function (c) { return Math.max(0, Math.floor(c)); }));
4973
5742
  if (cf.length === 0) return a.pow(b); // level 0 → a^b (b arg is the level-1 op)
4974
5743
  if (!coeffsHaveOmegaPart(cf)) return a.arrow(cf[0])(b); // finite level c
4975
- return Q._ordinalHyperop(a, b, cf);
5744
+ return Q._applyExpansionTruncation(Q._ordinalHyperop(a, b, cf));
4976
5745
  }
4977
5746
  // collapse at the highest huge coefficient: coeffs[iHuge+1] += 1, zero the rest below
4978
5747
  var cf = coeffs.slice();
@@ -4983,7 +5752,183 @@
4983
5752
  // anchor: the largest operand dominates (right-to-left composition)
4984
5753
  var anchor = a.max(b);
4985
5754
  for (var j = 0; j < (hugeArgs || []).length; j++) anchor = anchor.max(hugeArgs[j]);
4986
- return Q._applyOrdinalRows(anchor, cf, 1);
5755
+ return Q._applyExpansionTruncation(Q._applyOrdinalRows(anchor, cf, 1));
5756
+ };
5757
+
5758
+ // ==================== Hardy Hierarchy ====================
5759
+ // H_α(n) via transfinite recursion (issues.md / README):
5760
+ // H_0(n) = n
5761
+ // H_{α+1}(n) = H_α(n+1) (successor step: only +1, never iterated)
5762
+ // H_λ(n) = H_{λ[n]}(n) (limit step: CNF fundamental sequence at n)
5763
+ // where λ[n] acts on the lowest limit term: (… + ω^j·c_j)[n] = … + ω^j·(c_j−1)
5764
+ // + ω^{j−1}·n. Closed forms keep the recursion finite:
5765
+ // H_{β+c}(n) = H_β(n+c) (c successor steps)
5766
+ // H_{β+ω·c}(n) = H_β(n·2^c) (c ω-level limit steps)
5767
+ // For ω^j·c segments with c beyond the exact-iteration bound (j ≥ 2) the
5768
+ // value collapses into the hyperoperation engine, mirroring the classic
5769
+ // identity F_j = H^{ω^j} (F_2(n)=n·2^n, F_3(n)≈2↑↑n, …):
5770
+ // H_{β+ω^j·c}(n) ≈ H_β(2{c}^j) i.e. 2.arrow(j)(c)
5771
+ var HARDY_EXACT_BOUND = 50;
5772
+ // H_α(n) — ITERATIVE (the original tail recursion grew hundreds of frames
5773
+ // deep for inputs like hardy(1e10+20) where n1≈40 makes every ω^j segment
5774
+ // take the exact branch: Maximum call stack size exceeded).
5775
+ Q._hardyH = function (coeffs, nArg) {
5776
+ function MN(v) { return (v instanceof MetaNum) ? v.clone() : new MetaNum(v || 0); }
5777
+ var c = [];
5778
+ for (var i0 = 0; i0 < coeffs.length; i0++) c.push(MN(coeffs[i0]));
5779
+ var n = MN(nArg);
5780
+ var guard2 = 200000;
5781
+ // The exact limit-step expansion is only feasible while the running base n
5782
+ // stays a small plain integer; once n is structured (or the step budget is
5783
+ // exhausted) the nested expansion would take ~n^degree steps, so take the
5784
+ // same supremum collapse the engine uses above HARDY_EXACT_BOUND.
5785
+ function nIsSmallPlain() {
5786
+ if (n.layer !== 0 || n.array.length !== 1) return false;
5787
+ var nv = n.toNumber();
5788
+ return isFinite(nv) && nv === Math.floor(nv) && Math.abs(nv) <= HARDY_EXACT_BOUND;
5789
+ }
5790
+ while (--guard2 >= 0) {
5791
+ while (c.length > 0 && c[c.length - 1].eq(MetaNum.ZERO)) c.pop();
5792
+ if (c.length === 0) return n; // H_0(n) = n
5793
+ if (c.length === 1) return n.add(c[0]); // H_c(n) = n + c
5794
+ if (c[0].gt(MetaNum.ZERO)) { // successor strip
5795
+ n = n.add(c[0]);
5796
+ c[0] = MetaNum.ZERO.clone();
5797
+ continue;
5798
+ }
5799
+ var j = 1;
5800
+ while (j < c.length && !c[j].gt(MetaNum.ZERO)) j++;
5801
+ if (j === 1) { // ω-segment closed form
5802
+ // H_{β + ω·c1}(n) = H_β(n · 2^{c1}) — evaluate with the OLD c1
5803
+ var nWf = n.mul(new MetaNum(2).pow(c[1]));
5804
+ var beta = [MetaNum.ZERO.clone(), MetaNum.ZERO.clone()];
5805
+ for (var k = 2; k < c.length; k++) beta.push(c[k]);
5806
+ c = beta;
5807
+ n = nWf;
5808
+ continue;
5809
+ }
5810
+ if (c[j].gt(HARDY_EXACT_BOUND)) { // engine collapse
5811
+ // H_{β + ω^j·c}(n) ≈ H_β(2{c}j) — evaluate with the OLD c[j]
5812
+ var nCol = new MetaNum(2).arrow(j)(c[j]);
5813
+ var beta2 = [MetaNum.ZERO.clone()];
5814
+ for (var k2 = 0; k2 < j; k2++) beta2.push(MetaNum.ZERO.clone());
5815
+ for (var k3 = j + 1; k3 < c.length; k3++) beta2.push(c[k3]);
5816
+ c = beta2;
5817
+ n = nCol;
5818
+ continue;
5819
+ }
5820
+ // exact limit step on ω^j·c_j: c_j-=1, c_{j-1}=n
5821
+ c[j] = c[j].sub(MetaNum.ONE);
5822
+ c[j - 1] = n.clone();
5823
+ }
5824
+ // budget exhausted: keep whatever was accumulated (monotone)
5825
+ return n;
5826
+ };
5827
+
5828
+ // MetaNum.hardy(n): the Hardy level of n.
5829
+ // n < 10 → 10 + n; otherwise the decimal digits of n become the CNF
5830
+ // coefficients of an ordinal α (hardy(1234) = H_{ω³+ω²·2+ω·3+4}(10)) and
5831
+ // the result is H_α(10).
5832
+ Q.hardy = function (n) {
5833
+ n = new MetaNum(n);
5834
+ if (n.sign !== 1) {
5835
+ throw Error(metaNumError + 'hardy: n must be a non-negative integer');
5836
+ }
5837
+ // v2.1 (issues.md): MetaNum-object input. Values beyond double range or
5838
+ // carrying ordinal rows/layers read their STRUCTURE as the ordinal:
5839
+ // a power tower 10^^k shadows to ω^ω^…^ω (k ω's), and H there is the
5840
+ // engine diagonal 10{ω^ω^…^ω(k ω's)}10 = 10.epsilonate(k) — so
5841
+ // hardy(10^^MSI) = the MetaNum limit exactly (slog(10^^MSI) = MSI).
5842
+ // Ordinal-row / ε-layer values sit at their own Hardy position
5843
+ // (H_{ω^β}(10) = 10{β}10) and map to themselves.
5844
+ var num = (n.layer === 0 && n.array.length === 1) ? n.toNumber() : Infinity;
5845
+ if (!isFinite(num)) {
5846
+ if (n.layer === 0 && n.array.length === 1) {
5847
+ var hVal = n.slog();
5848
+ // a clean power tower shadows to ω^ω^…^ω (k ω's); slog(10^^k) = [[k]]
5849
+ // (a plain single number — NOT the structured slog of, say, G600)
5850
+ if (hVal.layer === 0 && hVal.array.length === 1 && hVal.array[0].length === 1) {
5851
+ var hNum = hVal.toNumber();
5852
+ if (isFinite(hNum) && hNum >= 2 && hNum <= Number.MAX_SAFE_INTEGER) {
5853
+ // k ≤ MSI: the tower fits the engine limit (f_ε₀); k > MSI is
5854
+ // beyond ε₀ and the Hardy hierarchy is undefined there → Infinity
5855
+ return MetaNum.TEN.epsilonate(hNum).normalize();
5856
+ }
5857
+ }
5858
+ // layer-0 value beyond a clean 10^^k with k ≤ MSI: finite
5859
+ // hyperoperations above tetration (G600, 3{9}3, …) or a tower taller
5860
+ // than 10^^MSI exceed the library's ε₀ ceiling → Infinity
5861
+ return new MetaNum(Infinity);
5862
+ }
5863
+ // ordinal-row / ε-layer / letter-chain values sit at their own Hardy
5864
+ // position (H_{ω^β}(10) = 10{β}10): map to themselves
5865
+ return n.clone().normalize();
5866
+ }
5867
+ var s = String(num);
5868
+ // > 1e20 arrives in scientific notation ('1e+21') — expand to the exact
5869
+ // decimal digits so the digit-reading stays monotone (issues.md v2.1:
5870
+ // hardy must support > 1e15 inputs)
5871
+ var eMatch = s.match(/^(\d)(?:\.(\d+))?e\+?(\d+)$/);
5872
+ if (eMatch) {
5873
+ var eFrac = eMatch[2] || '';
5874
+ var eZeros = Number(eMatch[3]) - eFrac.length;
5875
+ if (eZeros > 0) s = eMatch[1] + eFrac + '0'.repeat(eZeros);
5876
+ }
5877
+ if (s.length >= 11) {
5878
+ // n ≥ 1e10 (issues.md v2.0): the ordinal is built per definition, then
5879
+ // evaluated from below on the engine's own representation:
5880
+ // n = dk·10^kExp + rest → α = ω^ord(kExp)·dk + ord(rest)
5881
+ // H_α(10) = H_{ω^ord(kExp)·dk}(H_ord(rest)(10)) — the lower part acts
5882
+ // first: n1 = H_ord(rest)(10) (recursive, exact path for rest < 1e10).
5883
+ // n1 = H_rest(10) becomes the fundamental-sequence argument of the
5884
+ // leading term:
5885
+ // kExp = 10 (ord = ω): H_{ω^ω·dk}(n1) = H_{ω^n1}(n1) exact (first
5886
+ // segment), the remaining dk−1 ω^ω-segments each add one ω-row —
5887
+ // hardy(1e10) = H_{ω^10}(10) = [3086.036065328153, 9×8] EXACTLY,
5888
+ // strictly below 10{10}10 (issues.md);
5889
+ // kExp ≥ 11 (ord = ω+c): mirror the engine's own ordinal rows for
5890
+ // 10{ω+c}(9+dk) on the from-below base H_{ω^n1}(n1) — hardy(1e11)
5891
+ // = H_{ω^(ω+1)}(10) keeps expande(10,10)'s row structure with the
5892
+ // strictly smaller definitional base, so hardy(1e11) < 10{ω+1}10
5893
+ // (issues.md).
5894
+ var kExp = s.length - 1;
5895
+ var dk = s.charCodeAt(0) - 48;
5896
+ var restNum = Number(s.slice(1));
5897
+ var n1 = MetaNum.TEN.clone();
5898
+ if (restNum > 0) n1 = Q.hardy(restNum);
5899
+ // from-below base: H_{ω^n1}(n1) — exact for small finite n1, one
5900
+ // ω-diagonal row (engine convention) for huge n1
5901
+ var base;
5902
+ var n1Num = (n1.array.length === 1 && n1.layer === 0) ? n1.toNumber() : Infinity;
5903
+ if (isFinite(n1Num) && n1Num === Math.floor(n1Num) && n1Num >= 2 && n1Num <= 100) {
5904
+ var ec = [];
5905
+ for (var zi = 0; zi < n1Num; zi++) ec.push(0);
5906
+ ec.push(1);
5907
+ base = Q._hardyH(ec, n1);
5908
+ } else {
5909
+ base = Q._applyOrdinalRows(n1, [0, 1], 1);
5910
+ }
5911
+ if (kExp === 10) {
5912
+ return Q._applyOrdinalRows(base, [0, 1], dk - 1).normalize();
5913
+ }
5914
+ // kExp ≥ 11 (ord = ω+c): mirror the engine's own ordinal rows for
5915
+ // 10{ω+c}(9+dk) onto the from-below base — hardy(1e11) keeps
5916
+ // expande(10,10)'s row structure with the strictly smaller
5917
+ // definitional base, so hardy(1e11) < 10{ω+1}10 (issues.md)
5918
+ var ks = String(kExp);
5919
+ var ordCoeffs = [];
5920
+ for (var oi = ks.length - 1; oi >= 0; oi--) ordCoeffs.push(ks.charCodeAt(oi) - 48);
5921
+ var mir = Q._hyperopFromOrdinalRaw(MetaNum.TEN.clone(), new MetaNum(9 + dk), ordCoeffs);
5922
+ var out = base.clone();
5923
+ for (var ri = 1; ri < mir.array.length; ri++) {
5924
+ out = Q._applyOrdinalRows(out, mir.array[ri].slice(1), mir.array[ri][0]);
5925
+ }
5926
+ return out.normalize();
5927
+ }
5928
+ if (num < 10) return new MetaNum(10 + num);
5929
+ var coeffs = [];
5930
+ for (var i = s.length - 1; i >= 0; i--) coeffs.push(s.charCodeAt(i) - 48);
5931
+ return Q._hardyH(coeffs, MetaNum.TEN.clone());
4987
5932
  };
4988
5933
 
4989
5934
  // ==================== BEAF Array Notation ====================
@@ -5019,7 +5964,7 @@
5019
5964
  var cNum = c.toNumber();
5020
5965
  if (isFinite(cNum)) {
5021
5966
  // any finite integer level: arrow() covers small, compact ordinal-row
5022
- // (level ≥ maxCols) and the ≥ maxArrow approximation branches
5967
+ // (level ≥ maxCols) approximation branches
5023
5968
  return args[0].arrow(cNum)(args[1]);
5024
5969
  }
5025
5970
  }
@@ -5116,7 +6061,7 @@
5116
6061
  if (allNonNegative) {
5117
6062
  var a = decimalPlaces(x.array[0][0], 6);
5118
6063
  // Reconstruct BEAF: {a, ?, c, d, e, ...} from ordinal row [1, c, d, e, ..., 1]
5119
- // (raw coefficient convention: BEAF(a,b,c,d,...) = a{...+ω*d+c}b)
6064
+ // (issues.md convention: BEAF(a,b,c,d,...) = a{...+ω*(d-1)+c}b)
5120
6065
  var beafParts = [a, '?'];
5121
6066
  for (var i = 0; i < vals.length; i++) {
5122
6067
  beafParts.push(String(vals[i]));
@@ -5312,7 +6257,7 @@
5312
6257
 
5313
6258
  if (obj === void 0) obj = {};
5314
6259
  if (obj) {
5315
- ps = ['maxRows', 'maxCols', 'maxArrow', 'serializeMode', 'debug'];
6260
+ ps = ['maxRows', 'maxCols', 'serializeMode', 'debug'];
5316
6261
  for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];
5317
6262
  }
5318
6263
 
@@ -5322,6 +6267,27 @@
5322
6267
  }
5323
6268
 
5324
6269
  function defineConstants(obj) {
6270
+ // maxRows / maxCols are clamped to [10, 1000] on every write, direct or
6271
+ // through config() — outside the range the array structures lose their
6272
+ // invariants (r0 diagonal needs ≥ 2 levels, row budgets exceed the
6273
+ // ordinal-row machinery).
6274
+ if (Object.defineProperty) {
6275
+ ['maxRows', 'maxCols'].forEach(function (p) {
6276
+ var store = obj[p];
6277
+ Object.defineProperty(obj, p, {
6278
+ configurable: true,
6279
+ enumerable: true,
6280
+ get: function () { return store; },
6281
+ set: function (v) {
6282
+ var n = Math.floor(Number(v));
6283
+ if (!isFinite(n)) return;
6284
+ if (n < 10) n = 10;
6285
+ if (n > 1000) n = 1000;
6286
+ store = n;
6287
+ }
6288
+ });
6289
+ });
6290
+ }
5325
6291
  for (var prop in R) {
5326
6292
  if (R.hasOwnProperty(prop)) {
5327
6293
  var val = R[prop];
@@ -5350,7 +6316,6 @@
5350
6316
  ps = [
5351
6317
  'maxRows', 10, 1000,
5352
6318
  'maxCols', 10, 1000,
5353
- 'maxArrow', 1, Number.MAX_SAFE_INTEGER,
5354
6319
  'serializeMode', 0, 1,
5355
6320
  'debug', 0, 2
5356
6321
  ];