metanum 2.0.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/README.md CHANGED
@@ -367,7 +367,7 @@ MetaNum(10).arrow(3.2)(10); // monotone between 10{3}10 and 10{4}10
367
367
 
368
368
  The same continuity applies to the ω-and-above operations. Successor levels
369
369
  follow `x{α}(m+f) = x{α-1}` applied m times to `x^f`; the ω level matches
370
- `aperiote` exactly, so the issue's composition identity holds verbatim:
370
+ `aperiote` exactly, so composition identity holds verbatim:
371
371
 
372
372
  ```javascript
373
373
  MetaNum(10).expande(2.1); // 10{ω+1}2.1 = 10{ω}10{ω}(10^0.1)
@@ -375,9 +375,45 @@ MetaNum(10).expande(2); // 10{ω}10 (continuous at the integers)
375
375
  MetaNum(10).multiexpande(2.1); // (10{ω+1})²(10^0.1)
376
376
  ```
377
377
 
378
- Limit levels take the fundamental sequence at `floor(y)`; successor levels
379
- with an iteration count beyond direct evaluation diagonalize through the
380
- engine's huge-argument convention (y plus one α-level marker row).
378
+ **Limit levels take the fundamental sequence at the full (fractional) `y`**, so
379
+ the fraction is never dropped (`h20(10,2.1)` ≠ `h20(10,2)`). The sequence can
380
+ then carry fractional coefficients, which resolve against the base x because on
381
+ the diagonal ω reads as x:
382
+
383
+ - ω^(k)·(c+f) = ω^(k)·c + ω^(k-1)·(x·f), applied top-down (ω^0.1 = x^0.1), so
384
+ only the constant term can still be fractional;
385
+ - a leftover fractional constant γ+f is one level of interpolation:
386
+ **x{γ+f}x = x{γ+1}(2·(x/2)^f)** — continuous at f=0 because x{γ+1}2 = x{γ}x.
387
+
388
+ **Successor levels** keep `x{α}(m+f) = x{α-1}` applied m times to `x^f`, and they
389
+ are stored in the same **expanded** form as the integer arguments: the α-1 row
390
+ carries the m applications (`ceil(y)-2 = m-1`) and the cascade below it is
391
+ generated at the fundamental-sequence index `x^f`, so the value grows with f
392
+ inside the interval and converges to the next integer as f → 1:
393
+
394
+ ```javascript
395
+ MetaNum(10).h21(2.0001); // Ba2.218Ab9 f → 0: cascade bottoming at ω
396
+ MetaNum(10).h21(2.5); // Ba1.772Ad9 the cascade deepens with f
397
+ MetaNum(10).h21(2.99); // Ba2.447Aj9 → converges to h21(10,3) = Ba1.000Ak9
398
+ ```
399
+
400
+ For the ω+1 / ω+2 / ω+3 levels the applications after the first still have an
401
+ operand inside MSI, so those are evaluated directly by the rule (that is the
402
+ `10{ω}10{ω}(10^0.1)` composition above) — which is also the exact identity.
403
+ An iteration count beyond direct evaluation diagonalizes through the engine's
404
+ huge-argument convention (y plus one α-level marker row). Then we have:
405
+
406
+ 10{ω\*2}2.1=10{ω+2.1}10=10{ω+3}2\*5^0.1 (because 10{ω+2}10=10{ω+3}2)
407
+
408
+ 3{ω\*2}2.1=3{ω+2.1}3=3{ω+3}2\*1.5^0.1
409
+
410
+ 10{ω^2}2.1=10{ω\*2.1}10=10{ω\*2+10\*0.1}10=10{ω\*2+1}10
411
+
412
+ 3{ω^2}2.1=3{ω\*2.1}3=3{ω\*2+3\*0.1}10=3{ω\*2+0.3}3=3{ω\*2+1}2\*1.5^0.3
413
+
414
+ 10{ω^ω}2.1=10{ω^2.1}10=10{ω^2\*10^0.1}10=10{ω^2\*1.258925}10=10{ω^2\*1+ω\*2+5.8925}10=10{ω^2\*1+ω\*2+6}2*5^0.8925
415
+
416
+ 3{ω^ω}2.1=3{ω^2.1}3=3{ω^2\*3^0.1}3=3{ω^2\*1.116123}3=3{ω^2\*1+1.045107}3=3{ω^2\*1+2}2*1.5^0.045107
381
417
 
382
418
  ## BEAF Operations
383
419
 
@@ -555,6 +591,50 @@ where α\[b] denotes the b-th element of the fundamental sequence assign to the
555
591
  - (ω^(α_1)+ω^(α_2)+...+ω^(α_k))\[n]=ω^(α_1)+ω^(α_2)+...+ω^(α_k)\[n], where α_1>=α_2>=...>=α_k
556
592
  - ε₀\[0]=1 and ε₀\[n+1]=ω^ε₀\[n]
557
593
 
594
+ ### The application count of each ordinal row
595
+
596
+ Expanding rules 2-3 all the way down shows that **only the top row depends on
597
+ the argument b** — every row below it is produced by decomposing with the base
598
+ n as the operand:
599
+
600
+ - successor α: n{α}b = n{α-1}^(b-2) (n{α-1}n), so the α-1 row carries **b-2**
601
+ applications and every lower row (which comes from n{α-1}n, n{α-2}n, …
602
+ whose operand is n) carries **n-2**;
603
+ - limit α: rule 3 first rewrites n{α}b = n{α\[b]}n, so the operand is n at
604
+ every level and **all** rows carry **n-2**.
605
+
606
+ ```javascript
607
+ MetaNum(10).h13(20); // 10{ω+3}20 = 10{ω+2}^18 10{ω+1}^8 10{ω}^8 10{ω}10
608
+ // array → [[1e10,8,8,8,8,8,8,8,8], [8,0,1], [8,1,1], [18,2,1]]
609
+ // ω+2 row = 18 = y-2, ω+1 and ω rows = 8 = x-2
610
+ MetaNum(10).h12(20); // 10{ω+2}20 → [8,0,1] [18,1,1]
611
+ MetaNum(3).h13(20); // 3{ω+3}20 → [1,0,1] [1,1,1] [18,2,1] (x-2 = 1)
612
+ ```
613
+
614
+ The same n-2 count is what the finite r0 coefficients carry (10{10}10 → all-8s),
615
+ so a row below the top one never moves when b changes.
616
+
617
+ The law is uniform for **every** level from ω+1 to ω^4:
618
+
619
+ | kind | rows | top row count | lower rows |
620
+ |---|---|---|---|
621
+ | successor α = β+1 | rows of n{β}n, then one β-row | **b-2** | **n-2** |
622
+ | limit α | rows of n{α\[b]}n | **n-2** | **n-2** |
623
+
624
+ ```javascript
625
+ MetaNum(10).h21(20); // 10{ω*2+1}20 = 10{ω*2}^18 (10{ω*2}10)
626
+ // 10{ω*2}10 = 10{ω+10}10 → the ω..ω+9 cascade, every count x-2 = 8
627
+ // array → [[…,8,…], [8,0,1] … [8,9,1], [18,0,2]]
628
+ MetaNum(10).h22(20); // … + [8,0,2] + [18,1,2] (ω*2 row = 8, ω*2+1 row = 18)
629
+ MetaNum(3).h21(20); // 3{ω*2+1}20 → [1,0,1] [1,1,1] [1,2,1] [18,0,2] (x-2 = 1)
630
+ ```
631
+
632
+ A limit operation stays **expanded** for every argument up to MSI: rule 3 turns
633
+ b into a fundamental-sequence index, so 100 < b ≤ MSI still yields the largest
634
+ `maxRows-1` fundamental-sequence rows (with the standard truncation marker)
635
+ instead of collapsing to a one-row marker — `h20(10,1000)` keeps 19 rows whose
636
+ top one is ω+999, and `h20(10,MSI)` keeps rows up to ω+(MSI-1).
637
+
558
638
  ## Examples
559
639
 
560
640
  642663{0}178187=642663×178187=114514191981
@@ -902,8 +982,8 @@ Implementation of dlsdl's letter notation for large number library, currently me
902
982
  - **Γ-canonical α/β (bisect law)**: the true α and β of a value v at letter Γ
903
983
  are recovered by bisecting 10{L}x = v on the engine's own smooth arrow curve
904
984
  (Γ = E,F,G,... single letters, L = level). α = 10^frac(x), β = floor(x):
905
- `format(arrow(3,4.1,3))` → `G1.161G897` (not `G1.000G898`),
906
- `format(arrow(3,4.3,3))` → `1.285H8` (not `1.000H8`),
985
+ `format(arrow(3,4.1,3))` → `G1.161G897`,
986
+ `format(arrow(3,4.3,3))` → `1.285H8`,
907
987
  `format(hardy(4166))` → `2.397G5`.
908
988
  - **+count collapse**: n operations of level L applied to a Γ^{L+1}-structured
909
989
  value collapse to ONE Γ^{L+1} with arg + n (F⁴(G(1.3796)) = G(5.3796)),
@@ -922,7 +1002,7 @@ Implementation of dlsdl's letter notation for large number library, currently me
922
1002
  22→21, 23→22 stay two-letter (`Y2.376X2`, `Z2.376Y2`), level ≥ 23 cascades
923
1003
  display as the αΓβ polarize diagonal. Diagonal letter combinations
924
1004
  (multi-letter tokens whose last lowercase letter is `a`: Aa, Ba, Ca, Aaa,
925
- Aaaa, …) use the **pure dlsdl α=2·5^f ∈ [2,10) convention**; the other
1005
+ Aaaa, …) use the **pure dlsdl α=2·5^f ∈[2,10) convention**; the other
926
1006
  letters (Ab, Bb, …) keep the ordinary α∈[1,10) convention. The polarize
927
1007
  triple t = log₁₀(bottom)+repeation maps as: t∈[2,10) smooth → α=t,
928
1008
  β=arrows; discrete integer arguments (10{L}b with 2≤b≤100) all sit at the
@@ -934,7 +1014,7 @@ Implementation of dlsdl's letter notation for large number library, currently me
934
1014
  nested ordinals prefix the ω-row letter:
935
1015
  3{3{100}3}3 → `Aa2.376Aa99`, 3{10{10000}10}3 → `Aa2.000Aa10,000`.
936
1016
  Symbol de-layering follows the same convention: !Aa3 = 10{ω³}10 →
937
- `2.000Aaaa10` (layer 0), @Aa3 = 10{ω^{ω³}}10 → `!2.000Aaaa10`.
1017
+ `2.000Aaaa10` (layer 0), @Aa3 = 10{ω^(ω³)}10 → `!2.000Aaaa10`.
938
1018
  - **multiLetterLimit symbol carry**: a multi-letter combination of k letters
939
1019
  sits at level ω^(k-1). Once it would be longer than multiLetterLimit the
940
1020
  notation switches to the next one instead of growing another letter: the
@@ -952,9 +1032,23 @@ Implementation of dlsdl's letter notation for large number library, currently me
952
1032
  table the ε form takes over (`format(epsilonate(3,15))` → `1.000Ak10ε14`).
953
1033
  Diagonal combinations in symbol forms keep the pure dlsdl α = 2·5^f ∈ [2,10)
954
1034
  mantissa (integer exponents anchor 2.000).
955
- - **Cascade compression**: a 20-row ordinal cascade that would spell 20 letter
956
- types keeps its top two levels and folds the rest into the second letter's
957
- repeat count: `format(h10000(3,10))` → `1.000Iccc19`.
1035
+ - **Cascade compression**: the ordinal rows are a COMPOSITION, so the top row
1036
+ leads the display and the row below it (which collapses from its repeat count)
1037
+ keeps the single α and β — a 20-row cascade keeps its top two levels:
1038
+ `format(h10000(3,10))` → `Iccc1.000Iccb10`.
1039
+ - **Stacking the same function nests the letter** (issue #14): `n{α}(n{α}y)` is
1040
+ one more application of the same level on top of the inner value, so the
1041
+ letter appears twice. `poea(10,poea(10,100))` = Ad(Ad(99)) → `Ad1.000Ad99`
1042
+ (before: the rows were folded into one letter, `1.000Ad114`), and the same
1043
+ holds for ω+1, ω+2, ω*2+1, ω*2+2, ω²+1, ω²+2, ω³+1 —
1044
+ `Ab2.398Ab99`, `Ac1.000Ac99`, `Bb1.000Bb99`, `Bc1.000Bc99`,
1045
+ `Abb1.000Abb99`, `Aac1.000Aac99`, `Aaab1.000Aaab99`; with an operand above
1046
+ MSI, `apea(apea(1e16))` → `BaBa1.000E16`.
1047
+ - **A coefficient above 25 has no letter in the grid** (the letters hold
1048
+ ω·d+v with 0 ≤ v ≤ 25), so a ω*2 fundamental-sequence row (ω+81, ω+99, …)
1049
+ clamps down to the largest letter below it instead of wrapping into a higher,
1050
+ wrong letter: `format(apea(10,100))` → `1.000Ba154` (the ω*2 level), not the
1051
+ wrapped ω*4+3 letter.
958
1052
  Formats are identical at maxRows=maxCols=10/20/50/100.
959
1053
 
960
1054
  ### Precision budget (maxRows / maxCols)
package/format-metanum.js CHANGED
@@ -1472,7 +1472,19 @@ function formatOrdinal(num, precision, precision4) {
1472
1472
  // as one more symbol with the chain as its argument
1473
1473
  return tokAa.sym + regularFormat(2, precision4) + tokAa.letter + argStr
1474
1474
  }
1475
- return letter.repeat(totalAaCount) + argStr
1475
+ // past the collapse threshold the repeats shift the argument and
1476
+ // advance the letter — a raw repeat would try to build a string
1477
+ // with `count` copies (Aaa repeated 1e9 times cannot be built)
1478
+ let repArgStr = argStr
1479
+ if (totalAaCount > 64) {
1480
+ let r0Bottom = Math.pow(10, r0[0] - Math.floor(r0[0]))
1481
+ let repParam = totalAaCount + 1
1482
+ let mantissa = Math.log10(Math.max(r0Bottom, 0.001)) +
1483
+ Math.log10(Math.max(repParam, 1)) * 0.4 + 1.6
1484
+ return regularFormat(mantissa, precision4) +
1485
+ letterName(baseHeight + 1) + commaFormat(repParam)
1486
+ }
1487
+ return letter.repeat(totalAaCount) + repArgStr
1476
1488
  } else {
1477
1489
  // Single Aa
1478
1490
  let tokAa = letterTokenOf(baseHeight)
@@ -1494,11 +1506,16 @@ function formatOrdinal(num, precision, precision4) {
1494
1506
  let collapseAt = effThreshold + 1
1495
1507
 
1496
1508
  if (totalAaCount >= collapseAt) {
1497
- // Collapse to next letter (Aa→Ab, Ab→Ac, etc.)
1498
- let mantissa = Math.log10(Math.max(alpha, 0.001)) + totalAaCount
1509
+ // Collapse to next letter (Aa→Ab, Ab→Ac, etc.): the repeats
1510
+ // shift the argument (arg = count+1) and the mantissa keeps
1511
+ // the [1,10) convention (2.398Ab99 — the same α the GRAHAMS
1512
+ // branch above produces), never the raw count as α
1513
+ let arg = totalAaCount + 1
1514
+ let mantVal = Math.log10(Math.max(alpha, 0.001)) +
1515
+ Math.log10(Math.max(arg, 1)) * 0.4 + 1.6
1499
1516
  let newHeight = baseHeight + 1
1500
1517
  let newLetter = letterName(newHeight)
1501
- return regularFormat(mantissa, precision4) + newLetter + betaStr
1518
+ return regularFormat(mantVal, precision4) + newLetter + formatR0Arg(arg, precision4)
1502
1519
  } else if (totalAaCount > 1) {
1503
1520
  // Repeated letters: outerLetters + α + lastLetter + β
1504
1521
  let outerLetters = letter.repeat(totalAaCount - 1)
@@ -1543,8 +1560,12 @@ function formatOrdinal(num, precision, precision4) {
1543
1560
  // Calculate height for this letter
1544
1561
  let height = 0
1545
1562
  if (nVals === 1) {
1546
- // 2-letter: Aa=23, Ab=24, ..., Az=48, Ba=49, ...
1547
- height = 23 + (diag - 1) * 26 + vals[0]
1563
+ // 2-letter: Aa=23, Ab=24, ..., Az=48, Ba=49, ... A coefficient
1564
+ // above 25 (ω+81, ω+99, … from a ω*2 fundamental sequence) has no
1565
+ // letter in the grid — clamp down to the largest letter below it
1566
+ // rather than wrapping into a higher, wrong letter.
1567
+ let v0 = vals[0] > 25 ? 25 : vals[0]
1568
+ height = 23 + (diag - 1) * 26 + v0
1548
1569
  } else {
1549
1570
  // 3+ letters: need to calculate offset
1550
1571
  // vals are stored in reverse letter order (e.g. "bc" -> [2,1]),
@@ -1597,13 +1618,18 @@ function formatOrdinal(num, precision, precision4) {
1597
1618
  tokAdv.letter + r0Str
1598
1619
  }
1599
1620
  if (totalRepeat >= collapseAt) {
1600
- // Collapse to next letter
1621
+ // Collapse to next letter — the repeat count shifts the
1622
+ // argument, so the mantissa keeps the [1,10) convention
1601
1623
  let mantissa = Math.log10(Math.max(alpha, 0.001)) + totalRepeat
1624
+ let mantVal = Math.pow(10, mantissa - Math.floor(mantissa))
1625
+ if (mantVal < 1) mantVal *= 10
1602
1626
  let newLetter = letterName(baseLetterHeight + 1)
1603
- return regularFormat(mantissa, precision4) + newLetter + r0Str
1627
+ return regularFormat(mantVal, precision4) + newLetter + r0Str
1604
1628
  } else if (totalRepeat > 1) {
1605
- // Repeated letters + chain
1606
- let outerLetters = letter.repeat(totalRepeat - 1)
1629
+ // Repeated letters + chain: one token per application, the
1630
+ // innermost one in front of the chain (Ba(Ba(1e16)) → the
1631
+ // stacked "BaBa1.000E16" — apea(apea(a)) must stay visible)
1632
+ let outerLetters = letter.repeat(totalRepeat)
1607
1633
  return outerLetters + r0Str
1608
1634
  } else {
1609
1635
  // Single letter + chain
@@ -1620,9 +1646,18 @@ function formatOrdinal(num, precision, precision4) {
1620
1646
  return emitLetterToken(tokAdv, regularFormat(tokAdv.mant, precision4), betaStr, precision4)
1621
1647
  }
1622
1648
  let mantissa = Math.log10(Math.max(alpha, 0.001)) + totalRepeat
1649
+ // the repeat count shifts the argument, so the mantissa keeps the
1650
+ // [1,10) convention (the ω-level form recovers the base mantissa
1651
+ // the way the single-row Aa cascade does: 2.398Ab99)
1652
+ let mantVal = (baseLetterHeight === 23)
1653
+ ? Math.log10(Math.max(alpha, 0.001)) +
1654
+ Math.log10(Math.max(totalRepeat + 1, 1)) * 0.4 + 1.6
1655
+ : Math.pow(10, mantissa - Math.floor(mantissa))
1656
+ if (mantVal < 1) mantVal *= 10
1623
1657
  let newHeight = baseLetterHeight + 1
1624
1658
  let letter = letterName(newHeight)
1625
- return regularFormat(mantissa, precision4) + letter + betaStr
1659
+ return regularFormat(mantVal, precision4) + letter +
1660
+ formatR0Arg(totalRepeat + 1, precision4)
1626
1661
  } else if (totalRepeat > 1) {
1627
1662
  // Repeated letters: outerLetters + α + lastLetter + β
1628
1663
  let letter = letterName(baseLetterHeight)
@@ -1678,12 +1713,22 @@ function formatOrdinal(num, precision, precision4) {
1678
1713
  let vals = row.slice(1, row.length - 1)
1679
1714
  let nVals = vals.length
1680
1715
  if (nVals === 1) {
1681
- height = 23 + (diag - 1) * 26 + vals[0]
1716
+ // the letter grid holds ω·d+v with 0 ≤ v ≤ 25; a larger
1717
+ // coefficient (a ω*2 fundamental sequence produces ω+81,
1718
+ // ω+99, …) has no letter, so clamp it down to the largest
1719
+ // letter below the ordinal instead of wrapping into a
1720
+ // higher, wrong letter (ω+81 must not display as ω*4+3)
1721
+ let v0 = vals[0] > 25 ? 25 : vals[0]
1722
+ height = 23 + (diag - 1) * 26 + v0
1682
1723
  } else {
1724
+ // vals are the CNF coefficients a1, a2, …, a(x-1) of
1725
+ // ord = ω^(x-1)·ax + … + ω·a2 + a1 — little-endian, the same
1726
+ // order letterName()/getOrdinalLetter() decode the letter:
1727
+ // the LAST val is the first lowercase letter of the token.
1683
1728
  let offset = 0
1684
1729
  for (let k = 2; k <= nVals; k++) offset += Math.pow(26, k)
1685
1730
  let n = (diag - 1) * Math.pow(26, nVals)
1686
- for (let j = 0; j < nVals; j++) n += vals[j] * Math.pow(26, nVals - 1 - j)
1731
+ for (let j = 0; j < nVals; j++) n += vals[j] * Math.pow(26, j)
1687
1732
  height = 23 + offset + n
1688
1733
  }
1689
1734
  }
@@ -1694,109 +1739,107 @@ function formatOrdinal(num, precision, precision4) {
1694
1739
  letterCounts[height] = (letterCounts[height] || 0) + count
1695
1740
  }
1696
1741
 
1697
- if (heights.length >= 2) {
1742
+ if (heights.length >= 1) {
1698
1743
  // Sort heights ascending
1699
1744
  heights.sort((a, b) => a - b)
1700
1745
 
1701
1746
  // README: at most TWO finite letter types survive — a longer
1702
- // cascade keeps only its top two levels and compresses the rest
1703
- // into the second letter's binary form (its repeat count).
1747
+ // cascade keeps only its top two levels, every lower row
1748
+ // compresses into the second letter's argument (they are below
1749
+ // display precision, and folding them into its repeat COUNT would
1750
+ // overstate the level: 8 ω's + 8 (ω+1)'s ≠ 16 more (ω+2)'s).
1704
1751
  if (heights.length > 2) {
1705
1752
  let keepLo = heights[heights.length - 2]
1706
- for (let i = 0; i < heights.length - 2; i++) {
1707
- letterCounts[keepLo] = (letterCounts[keepLo] || 0) + (letterCounts[heights[i]] || 0)
1708
- delete letterCounts[heights[i]]
1709
- }
1753
+ for (let i = 0; i < heights.length - 2; i++) delete letterCounts[heights[i]]
1710
1754
  heights = Object.keys(letterCounts).map(Number).sort((a, b) => a - b)
1711
1755
  }
1712
1756
 
1713
- // Collapse from lowest to highest
1714
- let effThreshold = Math.max(2, FORMAT_OPTIONS.multiLetterRepeatThreshold)
1715
- let collapseAt = effThreshold + 1
1716
- let collapseInfo = {} // height -> collapsedFromCount
1717
-
1718
- for (let h of heights.slice()) {
1719
- let count = letterCounts[h] || 0
1720
- if (count >= collapseAt) {
1721
- let nextH = h + 1
1722
- if (!(nextH in letterCounts) && heights.indexOf(nextH) < 0) heights.push(nextH)
1723
- letterCounts[nextH] = (letterCounts[nextH] || 0) + 1
1724
- collapseInfo[nextH] = count
1725
- delete letterCounts[h]
1726
- }
1727
- }
1728
-
1729
- // Re-sort after collapse
1730
- heights = Object.keys(letterCounts).map(Number).sort((a, b) => a - b)
1731
-
1732
1757
  if (heights.length >= 1) {
1733
1758
  // ── Display rules (README "format-metanum rules (v2.0)") ──
1734
- // * at most TWO finite letter types survive (VαEβ … VαVβ):
1735
- // a longer cascade keeps its top two levels and compresses
1736
- // the rest into the second letter's binary form;
1737
- // * exactly one α, attached to the innermost (lowest) letter;
1759
+ // * the rows are a COMPOSITION: the top row is the outermost
1760
+ // operation, so it leads the display and the row below it
1761
+ // supplies the single α and β (at most TWO letter types —
1762
+ // every lower row compresses into that inner argument);
1763
+ // * "+count collapse": count >= multiLetterRepeatThreshold+1
1764
+ // repeats of a letter collapse to ONE next letter with
1765
+ // arg count+1 (F⁴(G(1.3796)) = G(5.3796));
1766
+ // * stacking the same function therefore nests the letter:
1767
+ // poea(10,poea(10,100)) = Ad(Ad(99)) → "Ad1.000Ad99";
1738
1768
  // * a combination longer than multiLetterLimit carries to the
1739
- // symbol notation !αAaβ instead of growing another letter.
1769
+ // symbol notation !αAaβ.
1740
1770
  let effTh = Math.max(2, FORMAT_OPTIONS.multiLetterRepeatThreshold)
1771
+ let collapseAt = effTh + 1
1741
1772
 
1742
- // (1) the single α / β pair
1743
1773
  let base = r0[0]
1744
1774
  let r0Alpha = Math.pow(10, base - Math.floor(base))
1745
1775
  if (r0Alpha < 1) r0Alpha *= 10
1746
1776
  let frac = base - Math.floor(base)
1747
1777
  if (frac < 0) frac += 1
1748
1778
 
1749
- let collapseCount = 0
1750
- for (let ci = 0; ci < heights.length; ci++) {
1751
- collapseCount += collapseInfo[heights[ci]] || 0
1779
+ // α of a "+count collapse" (the ω-level form recovers the base
1780
+ // mantissa the way the single-row Aa cascade does: 2.398Ab99)
1781
+ let collapseMant = function (h, count) {
1782
+ let arg = count + 1
1783
+ if (h === 23) {
1784
+ return regularFormat(Math.log10(Math.max(r0Alpha, 0.001)) +
1785
+ Math.log10(Math.max(arg, 1)) * 0.4 + 1.6, precision4)
1786
+ }
1787
+ return regularFormat(r0Alpha, precision4)
1788
+ }
1789
+ // one collapsed level: α + next letter + (count+1)
1790
+ let collapseStr = function (h, count) {
1791
+ let tok = letterTokenOf(h + 1)
1792
+ if (tok.sym) {
1793
+ return tok.sym + regularFormat(tok.mant, precision4) +
1794
+ tok.letter + formatR0Arg(count + 1, precision4)
1795
+ }
1796
+ return collapseMant(h, count) + tok.letter + formatR0Arg(count + 1, precision4)
1752
1797
  }
1753
1798
 
1754
- let alphaStr, betaStr
1755
- if (collapseCount > 0) {
1756
- // Collapsed repeats: α and β come from the mantissa
1757
- // α = 10^(fractional part) ∈ [1, 10), β = floor(mantissa)
1758
- let mantissa = Math.log10(Math.max(r0Alpha, 0.001)) + collapseCount
1759
- let alphaVal = Math.pow(10, mantissa - Math.floor(mantissa))
1760
- if (alphaVal < 1) alphaVal *= 10
1761
- alphaStr = regularFormat(alphaVal, precision4)
1762
- betaStr = commaFormat(Math.floor(mantissa))
1763
- } else {
1764
- alphaStr = regularFormat(r0Alpha, precision4)
1765
- betaStr = formatR0Arg(Math.floor(base), precision4)
1799
+ let hTop = heights[heights.length - 1]
1800
+ let cTop = letterCounts[hTop] || 1
1801
+ let hLow = heights.length >= 2 ? heights[heights.length - 2] : -1
1802
+ let cLow = hLow < 0 ? 0 : (letterCounts[hLow] || 1)
1803
+
1804
+ // (1) a single row level: collapse, or repeats with α + letter + β
1805
+ if (hLow < 0) {
1806
+ if (cTop >= collapseAt) return collapseStr(hTop, cTop)
1807
+ let tok = letterTokenOf(hTop)
1808
+ if (tok.sym) return emitLetterToken(tok, regularFormat(r0Alpha, precision4),
1809
+ formatR0Arg(Math.floor(base), precision4), precision4)
1810
+ let aStr = (tok.letter.length >= 2 && tok.letter[tok.letter.length - 1] === "a")
1811
+ ? regularFormat(2 * Math.pow(5, frac), precision4)
1812
+ : regularFormat(r0Alpha, precision4)
1813
+ return tok.letter.repeat(Math.max(cTop - 1, 0)) + aStr + tok.letter +
1814
+ formatR0Arg(Math.floor(base), precision4)
1766
1815
  }
1767
- // Diagonal combinations (letters ending in 'a': Aa, Ba, Aaa, …)
1768
- // use the pure dlsdl mantissa α = 2·5^f ∈ [2, 10) — but only
1769
- // when the diagonal letter IS the value's canonical letter
1770
- // (single-type display). Inside a cascade the α is the inner
1771
- // value's own mantissa and keeps the ordinary [1,10) form
1772
- // (AbAa600 → Ab1.000Aa600).
1773
- let diagMant = function (tok) {
1774
- if (collapseCount > 0) return alphaStr
1775
- if (descHeights.length > 1) return alphaStr
1776
- if (!(tok.letter.length >= 2 && tok.letter[tok.letter.length - 1] === "a")) return alphaStr
1777
- return regularFormat(2 * Math.pow(5, frac), precision4)
1816
+
1817
+ // (2) the inner (second) level carries the single α and β
1818
+ let lowTok = letterTokenOf(hLow)
1819
+ let innerStr
1820
+ if (cLow >= collapseAt) {
1821
+ innerStr = collapseStr(hLow, cLow)
1822
+ } else {
1823
+ let aStr = regularFormat(r0Alpha, precision4)
1824
+ innerStr = lowTok.letter.repeat(Math.max(cLow - 1, 0)) + aStr + lowTok.letter +
1825
+ formatR0Arg(Math.floor(base), precision4)
1778
1826
  }
1779
1827
 
1780
- // (3) compose: descending order (highest first = outermost)
1781
- let descHeights = heights.slice().reverse()
1782
- let topTok = letterTokenOf(descHeights[0])
1828
+ // (3) the top level leads: collapse when it repeats enough, else
1829
+ // one token per application (or the symbol-carried !αAaβ)
1830
+ if (cTop >= collapseAt) return collapseStr(hTop, cTop)
1831
+ let topTok = letterTokenOf(hTop)
1783
1832
  if (topTok.sym) {
1784
- // the top level needs the symbol notation — it dwarfs every
1785
- // lower level, so the display is the single !αAaβ form
1786
- return emitLetterToken(topTok, alphaStr, betaStr, precision4)
1787
- }
1788
- let outerLetters = topTok.letter.repeat(
1789
- Math.min(letterCounts[descHeights[0]] || 1, effTh))
1790
- if (descHeights.length >= 2) {
1791
- let loH = descHeights[1]
1792
- let loTok = letterTokenOf(loH)
1793
- let loCnt = letterCounts[loH] || 1
1794
- if (loCnt > 1) {
1795
- outerLetters += loTok.letter.repeat(Math.min(loCnt - 1, effTh))
1833
+ // multiLetterLimit carry: !αAaβ, β = the ω-exponent; the
1834
+ // inner level only survives when it collapses on its own
1835
+ if (cLow >= collapseAt) {
1836
+ return topTok.sym + regularFormat(topTok.mant, precision4) +
1837
+ topTok.letter + collapseStr(hLow, cLow)
1796
1838
  }
1797
- return outerLetters + diagMant(loTok) + loTok.letter + betaStr
1839
+ return topTok.sym + regularFormat(topTok.mant, precision4) +
1840
+ topTok.letter + formatR0Arg(topTok.arg, precision4)
1798
1841
  }
1799
- return diagMant(topTok) + topTok.letter + betaStr
1842
+ return topTok.letter.repeat(Math.min(cTop, effTh)) + innerStr
1800
1843
  }
1801
1844
  }
1802
1845
  }