@descix/egpt-math-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +224 -0
  2. package/dist/egpt-math-sdk.browser.js +5 -0
  3. package/dist/index.d.ts +100 -0
  4. package/dist/index.js +985 -0
  5. package/dist/notebooks/arithmetic-basics.html +166 -0
  6. package/dist/notebooks/complex-twiddle.html +148 -0
  7. package/dist/notebooks/double-slit-rosetta-qft.html +154 -0
  8. package/dist/notebooks/egpt-fft-test.html +202 -0
  9. package/dist/notebooks/egpt-matrix-test.html +241 -0
  10. package/dist/notebooks/egpt-polynomial-test.html +703 -0
  11. package/dist/notebooks/egpt-prime-composite-test.html +561 -0
  12. package/dist/notebooks/egpt-test-suite.html +1387 -0
  13. package/dist/notebooks/egpt-topology-test.html +410 -0
  14. package/dist/notebooks/factorization-basics.html +131 -0
  15. package/dist/notebooks/fft.html +155 -0
  16. package/dist/notebooks/frqtl-qft-benchmark.html +207 -0
  17. package/dist/notebooks/gallery-atomic-model.html +51 -0
  18. package/dist/notebooks/gallery-big-bang.html +62 -0
  19. package/dist/notebooks/gallery-blackbody.html +52 -0
  20. package/dist/notebooks/gallery-circuit-sat.html +104 -0
  21. package/dist/notebooks/gallery-collision-matrix-3d.html +51 -0
  22. package/dist/notebooks/gallery-double-slit.html +53 -0
  23. package/dist/notebooks/gallery-gun-chamber.html +62 -0
  24. package/dist/notebooks/gallery-particle-walk-3d.html +53 -0
  25. package/dist/notebooks/gallery-wave-interference.html +52 -0
  26. package/dist/notebooks/getting-started-hello-frqtl.html +53 -0
  27. package/dist/notebooks/iso-canonical-chain.html +203 -0
  28. package/dist/notebooks/iso-entropy-log.html +127 -0
  29. package/dist/notebooks/iso-fft-polynomial.html +136 -0
  30. package/dist/notebooks/iso-matrix-four-views.html +131 -0
  31. package/dist/notebooks/iso-number-theory-four-views.html +99 -0
  32. package/dist/notebooks/iso-pi-log-fraction-loop.html +140 -0
  33. package/dist/notebooks/matrix.html +202 -0
  34. package/dist/notebooks/notebooks.json +240 -0
  35. package/dist/notebooks/polynomials.html +201 -0
  36. package/dist/notebooks/prime-composite.html +268 -0
  37. package/dist/notebooks/rational-core.html +179 -0
  38. package/dist/notebooks/reference-egpt-fft-test.html +187 -0
  39. package/dist/notebooks/reference-order-finder-test.html +196 -0
  40. package/dist/notebooks/reference-prime-atom-polynomial-test.html +542 -0
  41. package/dist/notebooks/reference-solve-polynomial-system-test.html +471 -0
  42. package/dist/notebooks/scaled-vectors.html +112 -0
  43. package/dist/notebooks/stats.html +206 -0
  44. package/dist/notebooks/transcendentals.html +195 -0
  45. package/dist/notebooks/view-vendored-d3.html +78 -0
  46. package/dist/vendor/d3-array/src/array.js +4 -0
  47. package/dist/vendor/d3-array/src/ascending.js +3 -0
  48. package/dist/vendor/d3-array/src/bin.js +125 -0
  49. package/dist/vendor/d3-array/src/bisect.js +9 -0
  50. package/dist/vendor/d3-array/src/bisector.js +56 -0
  51. package/dist/vendor/d3-array/src/blur.js +115 -0
  52. package/dist/vendor/d3-array/src/constant.js +3 -0
  53. package/dist/vendor/d3-array/src/count.js +18 -0
  54. package/dist/vendor/d3-array/src/cross.js +33 -0
  55. package/dist/vendor/d3-array/src/cumsum.js +6 -0
  56. package/dist/vendor/d3-array/src/descending.js +7 -0
  57. package/dist/vendor/d3-array/src/deviation.js +6 -0
  58. package/dist/vendor/d3-array/src/difference.js +11 -0
  59. package/dist/vendor/d3-array/src/disjoint.js +15 -0
  60. package/dist/vendor/d3-array/src/every.js +10 -0
  61. package/dist/vendor/d3-array/src/extent.js +29 -0
  62. package/dist/vendor/d3-array/src/filter.js +11 -0
  63. package/dist/vendor/d3-array/src/fsum.js +69 -0
  64. package/dist/vendor/d3-array/src/greatest.js +29 -0
  65. package/dist/vendor/d3-array/src/greatestIndex.js +19 -0
  66. package/dist/vendor/d3-array/src/group.js +65 -0
  67. package/dist/vendor/d3-array/src/groupSort.js +10 -0
  68. package/dist/vendor/d3-array/src/identity.js +3 -0
  69. package/dist/vendor/d3-array/src/index.js +57 -0
  70. package/dist/vendor/d3-array/src/intersection.js +19 -0
  71. package/dist/vendor/d3-array/src/least.js +29 -0
  72. package/dist/vendor/d3-array/src/leastIndex.js +19 -0
  73. package/dist/vendor/d3-array/src/map.js +5 -0
  74. package/dist/vendor/d3-array/src/max.js +20 -0
  75. package/dist/vendor/d3-array/src/maxIndex.js +22 -0
  76. package/dist/vendor/d3-array/src/mean.js +19 -0
  77. package/dist/vendor/d3-array/src/median.js +9 -0
  78. package/dist/vendor/d3-array/src/merge.js +9 -0
  79. package/dist/vendor/d3-array/src/min.js +20 -0
  80. package/dist/vendor/d3-array/src/minIndex.js +22 -0
  81. package/dist/vendor/d3-array/src/mode.js +28 -0
  82. package/dist/vendor/d3-array/src/nice.js +18 -0
  83. package/dist/vendor/d3-array/src/number.js +20 -0
  84. package/dist/vendor/d3-array/src/pairs.js +15 -0
  85. package/dist/vendor/d3-array/src/permute.js +3 -0
  86. package/dist/vendor/d3-array/src/quantile.js +47 -0
  87. package/dist/vendor/d3-array/src/quickselect.js +53 -0
  88. package/dist/vendor/d3-array/src/range.js +13 -0
  89. package/dist/vendor/d3-array/src/rank.js +24 -0
  90. package/dist/vendor/d3-array/src/reduce.js +14 -0
  91. package/dist/vendor/d3-array/src/reverse.js +4 -0
  92. package/dist/vendor/d3-array/src/scan.js +6 -0
  93. package/dist/vendor/d3-array/src/shuffle.js +13 -0
  94. package/dist/vendor/d3-array/src/some.js +10 -0
  95. package/dist/vendor/d3-array/src/sort.js +39 -0
  96. package/dist/vendor/d3-array/src/subset.js +5 -0
  97. package/dist/vendor/d3-array/src/sum.js +18 -0
  98. package/dist/vendor/d3-array/src/superset.js +19 -0
  99. package/dist/vendor/d3-array/src/threshold/freedmanDiaconis.js +7 -0
  100. package/dist/vendor/d3-array/src/threshold/scott.js +7 -0
  101. package/dist/vendor/d3-array/src/threshold/sturges.js +5 -0
  102. package/dist/vendor/d3-array/src/ticks.js +55 -0
  103. package/dist/vendor/d3-array/src/transpose.js +15 -0
  104. package/dist/vendor/d3-array/src/union.js +11 -0
  105. package/dist/vendor/d3-array/src/variance.js +25 -0
  106. package/dist/vendor/d3-array/src/zip.js +5 -0
  107. package/dist/vendor/internmap/src/index.js +61 -0
  108. package/dist/vendor/manifest.json +11 -0
  109. package/dist/wasm/egpt_math_sdk_wasm.d.ts +214 -0
  110. package/dist/wasm/egpt_math_sdk_wasm.js +1120 -0
  111. package/dist/wasm/egpt_math_sdk_wasm_bg.wasm +0 -0
  112. package/dist/wasm/egpt_math_sdk_wasm_bg.wasm.d.ts +66 -0
  113. package/dist/wasm/manifest.json +5 -0
  114. package/package.json +53 -0
@@ -0,0 +1,127 @@
1
+ <frqtl-notebook version="1" title="E — Entropy-Log Bijection (log₂ N ≡ H(Uniform(N)))">
2
+
3
+ <cell type="markdown">
4
+ # E — Entropy-Log Bijection
5
+
6
+ The hub of the canonical EGPTMath chain:
7
+
8
+ > **log₂ N ≡ H(Uniform(N))**
9
+
10
+ The binary logarithm of a natural number IS the Shannon entropy of a uniform distribution on N outcomes. This is not a metaphor — it is formally proven in EGPT's Lean chain (`RotaUniformTheorem` + `entropy_of_fair_coin_is_one_bit`, `RET.lean`).
11
+
12
+ Three statements, with honest provenance:
13
+
14
+ - **E1** `log₂ N ≡ H(Uniform(N))` — pedagogical (both sides transcendental). Lean-backed.
15
+ - **E2** `H(N) ≡ Σ_{p|N} v_p(N)·H(p)` — entropy is additive over prime atoms (LFTA in entropy form). Lean-backed.
16
+ - **E3** `N ≡ ∏_p p^{v_p(N)}` — the exponentiated form of E2, **bit-exact** over BigInt. This is the runnable witness.
17
+
18
+ Every downstream theorem (T/W/N/M four-views, OrderFinder) is a *projection* of E2. Run the cells below to witness E3 bit-exactly.
19
+
20
+ *(Ported from `lib/egpt/js/model/theorems/E_EntropyLogBijection.js`. Cells reach `PrimeAtomPolynomial` through the injected `math` builtin — no imports.)*
21
+ </cell>
22
+
23
+ <cell type="markdown">
24
+ ## E1 — log₂ N ≡ H(Uniform(N)) (cited, not asserted)
25
+
26
+ E1 and E2 are **print-only citations of Lean theorems** — both sides are transcendental reals and cannot be asserted inside exact EGPTReal arithmetic. The operational meaning: the information content of specifying one of N equally-likely outcomes is log₂(N) bits, and that is the shortest binary description (ParticlePath) length that resolves a 1-of-N selection.
27
+
28
+ Lean theorems cited: `RotaUniformTheorem`, `entropy_of_fair_coin_is_one_bit` (EGPT/Entropy/RET.lean), `H_canonical_ln` (EGPT/Entropy/H.lean), `equivParticleFuturePDFToReal` (EntropyNumber/Basic.lean).
29
+ </cell>
30
+
31
+ <cell type="js" lane="math" id="e1-cite">
32
+ const { display } = caps;
33
+ display('E1 stated and cited — no runtime assertion (transcendental on both sides).');
34
+ display(' log₂ N ≡ H(Uniform(N)) [Lean: RotaUniformTheorem + entropy_of_fair_coin_is_one_bit]');
35
+ </cell>
36
+
37
+ <cell type="markdown">
38
+ ## E2 — H(N) ≡ Σ v_p(N)·H(p) (entropy additive over atoms)
39
+
40
+ Shannon entropy is **additive** over the prime-atom decomposition of N — the LFTA written in entropy form. The primes are the irreducible information atoms; the decomposition is unique. This is why `PrimeAtomPolynomial` can read N's multiplicative structure by reading its additive exponent vector.
41
+
42
+ Lean: `EGPT_Fundamental_Theorem_of_Arithmetic_via_Entropy_Bits` (EGPT/NumberTheory/Analysis.lean).
43
+ </cell>
44
+
45
+ <cell type="js" lane="math" id="e2-cite">
46
+ const { display } = caps;
47
+ display('E2 stated and cited — no runtime assertion (transcendental on both sides).');
48
+ display(' H(N) ≡ Σ_{p|N} v_p(N)·H(p) [Lean: EGPT_Fundamental_Theorem_of_Arithmetic_via_Entropy_Bits]');
49
+ </cell>
50
+
51
+ <cell type="markdown">
52
+ ## E3 — N ≡ ∏_p p^{v_p(N)} (bit-exact witness)
53
+
54
+ Both sides of E3 are integers, so we assert it **bit-exactly** on BigInt. Factorise N into its LFTA exponent vector via `PrimeAtomPolynomial.factorize`, reconstruct N by multiplying atoms raised to their exponents, and check the product equals N. We also check the sparsity bound Ω(N) ≤ bitLength(N) (every atom contributes ≥ log₂(2) = 1 bit).
55
+
56
+ The cell produces `e3ok` (all cases passed) for the closing cell to confirm.
57
+ </cell>
58
+
59
+ <cell type="js" lane="math" id="e3-witness" out="e3ok">
60
+ const { math, display } = caps;
61
+ const { PrimeAtomPolynomial } = math;
62
+
63
+ // Local check helper: in a notebook cell, a failed claim THROWS (no process.exit).
64
+ let anyFailed = false;
65
+ function check(label, cond) {
66
+ display((cond ? ' ✓ ' : ' ✗ ') + label);
67
+ if (!cond) { anyFailed = true; throw new Error('E3 FAILED: ' + label); }
68
+ }
69
+
70
+ // Reconstruct N from its LFTA exponent vector via ∏ p^{v_p}.
71
+ function reconstruct(factors) {
72
+ let N = 1n;
73
+ for (const { prime, exponent } of factors) {
74
+ for (let i = 0n; i < exponent; i++) N *= prime;
75
+ }
76
+ return N;
77
+ }
78
+
79
+ const TEST_CASES = [
80
+ { N: 12n, note: 'small semiprime-with-power (v_2=2, v_3=1)' },
81
+ { N: 21n, note: 'small semiprime (v_3=1, v_7=1)' },
82
+ { N: 35n, note: 'small semiprime (v_5=1, v_7=1)' },
83
+ { N: 391n, note: 'medium semiprime 17·23' },
84
+ { N: 1024n, note: 'pure power of 2 (tight sparsity)' },
85
+ { N: 2310n, note: 'primorial 2·3·5·7·11 (five atoms)' },
86
+ { N: 997n, note: 'large prime (Ω=1)' }
87
+ ];
88
+
89
+ for (const { N, note } of TEST_CASES) {
90
+ const factors = PrimeAtomPolynomial.factorize(N);
91
+ const omega = PrimeAtomPolynomial.bigOmega(N);
92
+ const bits = BigInt(PrimeAtomPolynomial.bitLength(N));
93
+ const recon = reconstruct(factors);
94
+ const vstr = factors.map(f => `(${f.prime}^${f.exponent})`).join(' · ') || '1';
95
+ display(`N=${N} ${note}`);
96
+ display(` v⃗(N) = ${vstr} log₂ form = ${PrimeAtomPolynomial.logspaceSum(N)}`);
97
+ display(` reconstruct ∏ p^{v_p} = ${recon} Ω=${omega} bitLen=${bits}`);
98
+ check(`E3 bit-exact: ${N} ≡ ∏ p^{v_p}`, recon === N);
99
+ check(`sparsity: Ω(${N})=${omega} ≤ bitLen=${bits}`, omega <= bits);
100
+ }
101
+
102
+ display('— sparsity tight at N = 2^k (Ω = k = bitLen − 1) —');
103
+ for (let k = 1n; k <= 20n; k++) {
104
+ const N = 1n << k;
105
+ const omega = PrimeAtomPolynomial.bigOmega(N);
106
+ const bits = BigInt(PrimeAtomPolynomial.bitLength(N));
107
+ check(`Ω(2^${k})=${omega} and bitLen=${bits}`, omega === k && bits === k + 1n);
108
+ }
109
+
110
+ return { e3ok: !anyFailed };
111
+ </cell>
112
+
113
+ <cell type="markdown">
114
+ ## QED
115
+
116
+ The hub is log₂ = H. Every spoke is a projection. E1 and E2 are Lean-backed citations (transcendental on both sides); E3 is their exponentiated form, lives entirely in BigInt, and is the canonical-space witness that the chain is consistent.
117
+ </cell>
118
+
119
+ <cell type="js" lane="math" id="e-qed" in="e3ok">
120
+ const { display } = caps;
121
+ const ok = inputs.e3ok;
122
+ display(ok
123
+ ? 'QED — E3 verified bit-exactly for all test N. log₂ N is the hub; every canonical theorem is a projection.'
124
+ : 'E3 did not pass — see the witness cell above.');
125
+ </cell>
126
+
127
+ </frqtl-notebook>
@@ -0,0 +1,136 @@
1
+ <frqtl-notebook version="1" title="F — FFT-Polynomial Isomorphism (the transform IS Horner evaluation)">
2
+
3
+ <cell type="markdown">
4
+ # F — FFT-Polynomial Isomorphism
5
+
6
+ The DFT/FFT is **not** a matrix object — it is pointwise polynomial evaluation at canonical nodes, with the inverse being polynomial interpolation. No Vandermonde matrix is ever built.
7
+
8
+ - **F1** `EGPTFFT.forward(c) ≡ [ evaluateAt(c, k/N) for k=0..N-1 ]`
9
+ - **F2** `inverse(forward(c)) ≡ c` (Newton divided-difference round-trip)
10
+ - **F3** `toValueRepresentation / fromValueRepresentation ≡ identity` at canonical base x = 2^k
11
+ - **Corollary** `multiply(P,Q)` ↔ pointwise product of `forward(P)`, `forward(Q)` (convolution theorem)
12
+
13
+ *(Ported from `theorems/F_FFTPolynomialIsomorphism.js`. Cells destructure `EGPTReal`, `EGPTMath`, `EGPTPolynomial`, `EGPTFFT` from the injected `math` builtin — no imports. `renderVec` is inlined below.)*
14
+ </cell>
15
+
16
+ <cell type="markdown">
17
+ ## Setup — inline helpers
18
+
19
+ `renderVec` (exact p/q rendering) and `vecEquals` are inlined here because the TraceReport helper is not on the SDK surface. Everything else comes from `caps.math`.
20
+ </cell>
21
+
22
+ <cell type="js" lane="math" id="f-setup" out="fhelp">
23
+ const { math } = caps;
24
+ const { EGPTReal } = math;
25
+ // Inline canonical-string render (mirrors EGPTReal.toCanonicalStr / TraceReport.renderValue).
26
+ function renderValue(v) {
27
+ if (v == null) return String(v);
28
+ if (typeof v._getPPFRationalParts === 'function') {
29
+ const { numerator, denominator } = v._getPPFRationalParts();
30
+ if (denominator === 1n || denominator === -1n) return String(denominator < 0n ? -numerator : numerator);
31
+ return `${numerator}/${denominator}`;
32
+ }
33
+ return String(v);
34
+ }
35
+ function renderVec(v) { return '[ ' + v.map(renderValue).join(', ') + ' ]'; }
36
+ function vecEquals(u, v) {
37
+ if (u.length !== v.length) return false;
38
+ for (let i = 0; i < u.length; i++) if (!u[i].equals(v[i])) return false;
39
+ return true;
40
+ }
41
+ const intN = (n) => EGPTReal.fromBigInt(BigInt(n));
42
+ const frac = (n, d) => EGPTReal.fromRational(BigInt(n), BigInt(d));
43
+ // Expose the helpers to downstream cells as a binding.
44
+ return { fhelp: { renderVec, vecEquals, intN, frac } };
45
+ </cell>
46
+
47
+ <cell type="markdown">
48
+ ## F1 — forward ≡ Horner evaluation at k/N (no matrix)
49
+
50
+ `EGPTFFT.forward(c)` evaluates the polynomial with coefficient vector `c` at the canonical nodes `x_k = k/N`. This is exactly per-point `EGPTPolynomial.evaluateAt(c, k/N)` — no transform matrix is materialised.
51
+ </cell>
52
+
53
+ <cell type="js" lane="math" id="f1" in="fhelp">
54
+ const { math, display } = caps;
55
+ const { EGPTFFT, EGPTPolynomial, EGPTReal, EGPTMath } = math;
56
+ const { renderVec, vecEquals, intN, frac } = inputs.fhelp;
57
+ const ONE = EGPTReal.fromBigInt(1n);
58
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('F1 FAILED: ' + label); }
59
+
60
+ const c1 = [ frac(1, 3), frac(-7, 6), ONE ];
61
+ display('P(x) = 1/3 − (7/6)·x + x² c = ' + renderVec(c1));
62
+ const N1 = c1.length;
63
+ const viaForward = EGPTFFT.forward(c1);
64
+ display('forward(c) = ' + renderVec(viaForward));
65
+ const viaHorner = [];
66
+ for (let k = 0; k < N1; k++) viaHorner.push(EGPTPolynomial.evaluateAt(c1, frac(k, N1)));
67
+ display('[evaluateAt(c,k/N) k=0..2]= ' + renderVec(viaHorner));
68
+ check('forward(c) ≡ Horner-evaluate at k/N (no matrix built)', vecEquals(viaForward, viaHorner));
69
+
70
+ const c1b = [ intN(5), intN(-2), intN(7), intN(-1) ];
71
+ const N1b = 8;
72
+ const fb = EGPTFFT.forward(c1b, N1b);
73
+ const hb = []; for (let k = 0; k < N1b; k++) hb.push(EGPTPolynomial.evaluateAt(c1b, frac(k, N1b)));
74
+ check(`N=${N1b}: forward = pointwise Horner (integer coeffs, fractional nodes)`, vecEquals(fb, hb));
75
+ </cell>
76
+
77
+ <cell type="markdown">
78
+ ## F2 — inverse ∘ forward ≡ identity (Newton DD round-trip)
79
+
80
+ `EGPTFFT.inverse` reconstructs the coefficient vector from the samples via Newton divided differences — again no matrix inversion. The round-trip is bit-exact over rational `EGPTReal`.
81
+ </cell>
82
+
83
+ <cell type="js" lane="math" id="f2" in="fhelp">
84
+ const { math, display } = caps;
85
+ const { EGPTFFT, EGPTReal } = math;
86
+ const { renderVec, vecEquals, intN, frac } = inputs.fhelp;
87
+ const ONE = EGPTReal.fromBigInt(1n);
88
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('F2 FAILED: ' + label); }
89
+
90
+ const c2 = [ frac(1, 3), frac(-7, 6), ONE, frac(2, 5), frac(-1, 2) ];
91
+ display('c (length 5, fractional) = ' + renderVec(c2));
92
+ const samples = EGPTFFT.forward(c2);
93
+ display('forward(c) = ' + renderVec(samples));
94
+ const recovered = EGPTFFT.inverse(samples);
95
+ display('inverse(samples) = ' + renderVec(recovered));
96
+ check('inverse ∘ forward is identity (length-5 fractional)', vecEquals(recovered, c2));
97
+
98
+ const c2b = [ intN(3), intN(1), intN(4), intN(1) ];
99
+ check('inverse ∘ forward is identity (length-4 integer)', vecEquals(EGPTFFT.inverse(EGPTFFT.forward(c2b)), c2b));
100
+ </cell>
101
+
102
+ <cell type="markdown">
103
+ ## F3 — value representation ≡ identity at x = 2^k
104
+
105
+ `toValueRepresentation` samples the polynomial at the canonical EGPT base nodes x = 2^0, 2^1, …, and `fromValueRepresentation` inverts it. Both equal direct Horner evaluation; the pair round-trips exactly.
106
+ </cell>
107
+
108
+ <cell type="js" lane="math" id="f3" in="fhelp">
109
+ const { math, display } = caps;
110
+ const { EGPTPolynomial } = math;
111
+ const { renderVec, vecEquals, intN } = inputs.fhelp;
112
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('F3 FAILED: ' + label); }
113
+
114
+ const c3 = [ intN(-7), intN(11), intN(-2), intN(1) ]; // P(x) = -7 + 11x - 2x² + x³
115
+ display('P(x) = -7 + 11x − 2x² + x³ c = ' + renderVec(c3));
116
+ const samples = EGPTPolynomial.toValueRepresentation(c3);
117
+ display('toValueRepresentation(c) = [P(1),P(2),P(4),P(8)] = ' + renderVec(samples));
118
+ const direct = [1,2,4,8].map(x => EGPTPolynomial.evaluateAt(c3, intN(x)));
119
+ check('toValueRepresentation = direct Horner at x = 2^0..2^D', vecEquals(samples, direct));
120
+ const recovered = EGPTPolynomial.fromValueRepresentation(samples);
121
+ display('fromValueRepresentation = ' + renderVec(recovered));
122
+ check('fromValueRepresentation ∘ toValueRepresentation = identity', vecEquals(recovered, c3));
123
+ </cell>
124
+
125
+ <cell type="markdown">
126
+ ## QED
127
+
128
+ The transform is Horner evaluation; the inverse is interpolation; the convolution theorem follows from pointwise products in the value domain. No Vandermonde, no transform matrix — the FFT corner of the canonical chain is a projection of polynomial evaluation.
129
+ </cell>
130
+
131
+ <cell type="js" lane="math" id="f-qed">
132
+ const { display } = caps;
133
+ display('QED — F1/F2/F3 verified bit-exactly. The FFT IS polynomial evaluate/interpolate, matrix-free.');
134
+ </cell>
135
+
136
+ </frqtl-notebook>
@@ -0,0 +1,131 @@
1
+ <frqtl-notebook version="1" title="M — Matrix Four Views (one matrix, four projections of its row-product polynomial)">
2
+
3
+ <cell type="markdown">
4
+ # M — Matrix Four Views
5
+
6
+ A single matrix M projects through four surfaces of the EGPT bijective chain — all projections of one object, the row-product polynomial `P_M(x) = ∏_i row_i(x)`:
7
+
8
+ - **M1** matrix coefficient form ≡ M itself (rows ARE polynomials)
9
+ - **M2** product polynomial ≡ `∏_i row_i(x)` (`EGPTPolynomial.multiply` reducer)
10
+ - **M3** integer u-space root multiset ≡ `toNatRoots(P_M)` (rational-root theorem + lcm clearing)
11
+ - **M4** prime-atom multiset / composite Nat ≡ `toNat(P_M)` (LFTA closure)
12
+
13
+ Provenance: `Translation5/6/7.lean`. For atom-root fixtures the closure `toNat(P_M) ≡ EGPTPrimeComposite.fromEGPTReal(N)` holds at records AND value.
14
+
15
+ *(Ported from `theorems/M_MatrixFourViews.js`. `EGPTReal/EGPTPolynomial/EGPTPrimeComposite/EGPTMatrix` come from `caps.math` — no imports. The `runFourViews` runner + render helpers are inlined.)*
16
+ </cell>
17
+
18
+ <cell type="markdown">
19
+ ## Setup — the four-view runner
20
+
21
+ The runner mirrors the source `runFourViews`: compute P_M, its rational roots, integer u-roots, and the LFTA prime-atom composite; assert internal consistency (composite value = ∏ u-roots) and, for atom-root fixtures, the closure to N. Produced as a binding the fixture cells call.
22
+ </cell>
23
+
24
+ <cell type="js" lane="math" id="m-setup" out="mrun">
25
+ const { math, display } = caps;
26
+ const { EGPTReal, EGPTPolynomial, EGPTPrimeComposite, EGPTMatrix } = math;
27
+ const ZERO = EGPTReal.fromBigInt(0n);
28
+ const ONE = EGPTReal.fromBigInt(1n);
29
+ const intN = (n) => EGPTReal.fromBigInt(BigInt(n));
30
+ const frac = (n, d) => EGPTReal.fromRational(BigInt(n), BigInt(d));
31
+ function renderValue(v) {
32
+ if (v == null) return String(v);
33
+ if (typeof v._getPPFRationalParts === 'function') {
34
+ const { numerator, denominator } = v._getPPFRationalParts();
35
+ if (denominator === 1n || denominator === -1n) return String(denominator < 0n ? -numerator : numerator);
36
+ return `${numerator}/${denominator}`;
37
+ }
38
+ return String(v);
39
+ }
40
+ function showRecords(records) {
41
+ if (records.length === 0) return '(empty multiset, value = 1)';
42
+ const numCount = new Map(), denCount = new Map();
43
+ for (const r of records) {
44
+ const m = r.location === 'numerator' ? numCount : denCount;
45
+ m.set(r.prime, (m.get(r.prime) || 0n) + 1n);
46
+ }
47
+ const parts = [];
48
+ for (const p of [...numCount.keys()].sort((a,b)=>(a<b?-1:a>b?1:0))) { const k = numCount.get(p); parts.push(k === 1n ? `(${p})` : `(${p}^${k})`); }
49
+ for (const p of [...denCount.keys()].sort((a,b)=>(a<b?-1:a>b?1:0))) { const k = denCount.get(p); parts.push(k === 1n ? `(${p})⁻¹` : `(${p}^${k})⁻¹`); }
50
+ return parts.join(' · ');
51
+ }
52
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('M FAILED: ' + label); }
53
+
54
+ function runFourViews(label, M, expectedClosingN) {
55
+ display('── ' + label);
56
+ const { rows, cols } = EGPTMatrix.shape(M);
57
+ display(` M1 shape ${rows} × ${cols}`);
58
+ const P_M = M.reduce((acc, row) => EGPTPolynomial.multiply(acc, row), [ONE]);
59
+ display(` M2 P_M(x) = [ ${P_M.map(renderValue).join(', ')} ] deg = ${EGPTPolynomial.degree(P_M)}`);
60
+ const rRoots = EGPTPolynomial.rationalRoots(P_M);
61
+ display(` M3 rationalRoots = [${rRoots.map(renderValue).join(', ')}]`);
62
+ for (const r of rRoots) check(`P_M(${renderValue(r)}) = 0`, EGPTPolynomial.evaluateAt(P_M, r).equals(ZERO));
63
+ const uRoots = EGPTPolynomial.toNatRoots(P_M);
64
+ display(` toNatRoots = [${uRoots.map(u => u.breakSymbolicToApproximateBigInt().toString()).join(', ')}]`);
65
+ check('every u-root is integer-valued', uRoots.every(u => u._getPPFRationalParts().denominator === 1n));
66
+ const composite = EGPTPolynomial.toNat(P_M);
67
+ const compositeN = composite.breakSymbolicToApproximateBigInt();
68
+ display(` M4 toNat(P_M) = ${compositeN} records = ${showRecords(composite.records)}`);
69
+ let uProduct = 1n; for (const u of uRoots) uProduct *= u.breakSymbolicToApproximateBigInt();
70
+ check(`composite value = ∏ u-roots = ${uProduct}`, compositeN === uProduct);
71
+ if (expectedClosingN !== null) {
72
+ const expected = EGPTPrimeComposite.fromEGPTReal(intN(expectedClosingN));
73
+ check(`closure: toNat(P_M) === ${expectedClosingN}n`, compositeN === BigInt(expectedClosingN));
74
+ const aKey = EGPTPrimeComposite.recordsMultisetKey(composite.records);
75
+ const eKey = EGPTPrimeComposite.recordsMultisetKey(expected.records);
76
+ check('closure: records multiset matches fromEGPTReal(N)', aKey === eKey);
77
+ }
78
+ return { composite, compositeN };
79
+ }
80
+ return { mrun: { runFourViews, intN, frac, EGPTMatrix } };
81
+ </cell>
82
+
83
+ <cell type="markdown">
84
+ ## Fixtures A–D — single matrices
85
+
86
+ Fixture A: `[[(x−2)(x−3)]] = [[6,-5,1]]` (closes to N=6). Fixture B: `[[(x−2)²(x−3)]]` (N=12). Fixture C: two-row `[[(x−2)(x−3)],[(x−3)(x−5)]]` (N=90). Fixture D: fractional roots `[[1/3,-7/6,1]]` → u-roots [3,4], N=12 (the lcm-clearing demo).
87
+ </cell>
88
+
89
+ <cell type="js" lane="math" id="m-abcd" in="mrun">
90
+ const { display } = caps;
91
+ const { runFourViews, intN, frac, EGPTMatrix } = inputs.mrun;
92
+ runFourViews('Fixture A — [[6,-5,1]] = [[(x−2)(x−3)]] (N=6)', EGPTMatrix.from([[6, -5, 1]]), 6n);
93
+ runFourViews('Fixture B — [[-12,16,-7,1]] = [[(x−2)²(x−3)]] (N=12)', EGPTMatrix.from([[-12, 16, -7, 1]]), 12n);
94
+ runFourViews('Fixture C — two-row, roots {2,3,3,5} (N=90)', EGPTMatrix.from([[6, -5, 1], [15, -8, 1]]), 90n);
95
+ runFourViews('Fixture D — fractional [[1/3,-7/6,1]] → u-roots [3,4] (N=12)', EGPTMatrix.from([[ frac(1, 3), frac(-7, 6), intN(1) ]]), 12n);
96
+ display('Fixtures A–D complete.');
97
+ </cell>
98
+
99
+ <cell type="markdown">
100
+ ## Fixture E — GEMM observation
101
+
102
+ C = gemm(A, B) with A=[[6,-5,1]] (1×3), B=[[2],[3],[4]] (3×1) → C=[[1]] (1×1). The four-views chain runs end-to-end on each of A, B, C. GEMM is matrix multiplication, not polynomial multiplication — we observe the chain runs on all three, not a pointwise-records identity (the ℕ×ℕ→ℕ correspondence is mediated by Translation5/7).
103
+ </cell>
104
+
105
+ <cell type="js" lane="math" id="m-gemm" in="mrun">
106
+ const { math, display } = caps;
107
+ const { runFourViews, intN, EGPTMatrix } = inputs.mrun;
108
+ const { EGPTReal, EGPTPrimeComposite } = math;
109
+ const ONE = EGPTReal.fromBigInt(1n);
110
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('M-E FAILED: ' + label); }
111
+ const A = EGPTMatrix.from([[6, -5, 1]]);
112
+ const B = EGPTMatrix.from([[2], [3], [4]]);
113
+ const C = EGPTMatrix.gemm(A, B);
114
+ const sC = EGPTMatrix.shape(C);
115
+ check('gemm shape: C is 1×1', sC.rows === 1 && sC.cols === 1);
116
+ check('gemm value: C[0][0] = 1 (= 6·2 − 5·3 + 1·4)', C[0][0].equals(ONE));
117
+ const resA = runFourViews('E.A — A = [[6,-5,1]] (N=6)', A, 6n);
118
+ const resB = runFourViews('E.B — B = [[2],[3],[4]] (column matrix)', B, null);
119
+ const resC = runFourViews('E.C — C = gemm(A,B) = [[1]]', C, null);
120
+ check('E chain ran end-to-end on A,B,C',
121
+ resA.composite instanceof EGPTPrimeComposite &&
122
+ resB.composite instanceof EGPTPrimeComposite &&
123
+ resC.composite instanceof EGPTPrimeComposite);
124
+ </cell>
125
+
126
+ <cell type="js" lane="math" id="m-qed">
127
+ const { display } = caps;
128
+ display('QED — four matrix views, one bijective object (the row-product polynomial), zero runtime heuristics.');
129
+ </cell>
130
+
131
+ </frqtl-notebook>
@@ -0,0 +1,99 @@
1
+ <frqtl-notebook version="1" title="N — Number Theory Four Views (factoring, roots, order, period are one object)">
2
+
3
+ <cell type="markdown">
4
+ # N — Number Theory Four Views
5
+
6
+ A single `(a, N)` pair projects through four classical number-theoretic surfaces, all reading the same prime-atom vector `v⃗(N)`:
7
+
8
+ - **N1** prime factorisation ≡ `v⃗(N)` (LFTA, Lean-backed)
9
+ - **N2** polynomial root finding ≡ roots of `P_N(x) = ∏_p (x−p)^{v_p(N)}` (constructive over EGPTReal)
10
+ - **N3** order finding ≡ min divisor of φ(N) with `a^r ≡ 1` (LFTA + Lagrange)
11
+ - **N4** signal period ≡ direct orbit period of `a^k mod N` (classical Shor, definitional)
12
+
13
+ The four projections agree on r and on the prime set every time — not by tuning, but because they are the same operation under four labels.
14
+
15
+ *(Ported from `theorems/N_NumberTheoryFourViews.js`. `EGPTReal/EGPTPolynomial/PrimeAtomPolynomial/OrderFinder` come from `caps.math` — no imports. The runner + helpers are inlined.)*
16
+ </cell>
17
+
18
+ <cell type="markdown">
19
+ ## Setup — the four-view runner
20
+
21
+ Builds the atom-root polynomial, checks each prime is a root (N1≡N2), finds the order via `OrderFinder` (N3), and the direct orbit period (N4), asserting N3≡N4 and N1≡N2. Produced as a binding the case cells call.
22
+ </cell>
23
+
24
+ <cell type="js" lane="math" id="n-setup" out="nrun">
25
+ const { math, display } = caps;
26
+ const { EGPTReal, EGPTPolynomial, PrimeAtomPolynomial, OrderFinder } = math;
27
+ const ZERO = EGPTReal.fromBigInt(0n);
28
+ const ONE = EGPTReal.fromBigInt(1n);
29
+ const intN = (n) => EGPTReal.fromBigInt(BigInt(n));
30
+
31
+ function buildAtomRootPolynomial(N) {
32
+ const factors = PrimeAtomPolynomial.factorize(N);
33
+ let poly = [ONE];
34
+ for (const { prime, exponent } of factors) {
35
+ const linear = [intN(-prime), ONE];
36
+ for (let k = 0n; k < exponent; k++) poly = EGPTPolynomial.multiply(poly, linear);
37
+ }
38
+ return poly;
39
+ }
40
+ function directPeriodOfOrbit(a, N) {
41
+ const aBi = BigInt(a), NBi = BigInt(N);
42
+ let current = 1n;
43
+ for (let r = 1; r <= Number(NBi); r++) { current = (current * aBi) % NBi; if (current === 1n) return r; }
44
+ return null;
45
+ }
46
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('N FAILED: ' + label); }
47
+
48
+ function runFourViews(a, N, expectedOrder) {
49
+ const aBi = BigInt(a), NBi = BigInt(N);
50
+ display(`── a = ${aBi}, N = ${NBi}`);
51
+ // N1
52
+ const factors = PrimeAtomPolynomial.factorize(NBi);
53
+ const primeSet = factors.map(f => f.prime);
54
+ display(` N1 factorize(${NBi}) = ${factors.map(f => `(${f.prime}^${f.exponent})`).join(' · ') || '1'} Ω=${PrimeAtomPolynomial.bigOmega(NBi)} bitLen=${PrimeAtomPolynomial.bitLength(NBi)}`);
55
+ // N2
56
+ const P = buildAtomRootPolynomial(NBi);
57
+ for (const p of primeSet) check(`N2 P_${NBi}(${p}) = 0`, EGPTPolynomial.evaluateAt(P, intN(p)).equals(ZERO));
58
+ check(`deg(P) = Ω(N) = ${Number(PrimeAtomPolynomial.bigOmega(NBi))}`, EGPTPolynomial.degree(P) === Number(PrimeAtomPolynomial.bigOmega(NBi)));
59
+ // N3
60
+ const phi = PrimeAtomPolynomial.totient(NBi);
61
+ const orderR = OrderFinder.findOrder(aBi, NBi);
62
+ display(` N3 φ(${NBi})=${phi} order(${aBi} mod ${NBi})=${orderR}`);
63
+ check(`order(${aBi} mod ${NBi}) = ${expectedOrder}`, orderR === expectedOrder);
64
+ check(`verify: ${aBi}^${orderR} ≡ 1 (mod ${NBi})`, OrderFinder.verifyOrder(aBi, NBi, orderR));
65
+ // N4
66
+ const directPeriod = directPeriodOfOrbit(aBi, NBi);
67
+ display(` N4 direct orbit period = ${directPeriod}`);
68
+ check(`direct orbit period = ${expectedOrder}`, directPeriod === expectedOrder);
69
+ check('N3 order ≡ N4 period', orderR === directPeriod);
70
+ }
71
+ return { nrun: runFourViews };
72
+ </cell>
73
+
74
+ <cell type="markdown">
75
+ ## Cases — eight (a, N) pairs
76
+
77
+ Each pair runs all four projections and asserts they agree on the order/period and the prime set.
78
+ </cell>
79
+
80
+ <cell type="js" lane="math" id="n-cases" in="nrun">
81
+ const { display } = caps;
82
+ const run = inputs.nrun;
83
+ run(3n, 8n, 2);
84
+ run(7n, 15n, 4);
85
+ run(2n, 7n, 3);
86
+ run(2n, 15n, 4);
87
+ run(4n, 15n, 2);
88
+ run(2n, 21n, 6);
89
+ run(5n, 21n, 6);
90
+ run(3n, 35n, 12);
91
+ display('All eight cases agree across N1/N2/N3/N4.');
92
+ </cell>
93
+
94
+ <cell type="js" lane="math" id="n-qed">
95
+ const { display } = caps;
96
+ display('QED — factoring, polynomial roots, order finding, and signal period are four labels for one object: v⃗(N).');
97
+ </cell>
98
+
99
+ </frqtl-notebook>
@@ -0,0 +1,140 @@
1
+ <frqtl-notebook version="1" title="π — Log-Fraction Unit-Loop Bijection (the PPF address IS a point on the loop)">
2
+
3
+ <cell type="markdown">
4
+ # π — Log-Fraction Unit-Loop Bijection
5
+
6
+ "The address IS the map" at its most visible. Every positive integer N has a PPF decomposition `N = 2^L + offset`; its scaled residue `r(N) = offset/2^L ∈ [0,1)` is an exact rational; and that fraction maps bijectively to a point on the L1 unit loop by four straight-line quadrants — no transcendental angle, no `Math.log2`.
7
+
8
+ - **π1** PPF `{L, offset}` ≡ `(⌊log₂ N⌋, N − 2^L)` — bit-exact over BigInt
9
+ - **π2** `offset / 2^L` ≡ a canonical fraction in [0,1) — exact rational, invertible
10
+ - **π3** that fraction ≡ an L1 unit-loop position (x,y) with |x|+|y|=1 — exact rational bijection
11
+
12
+ All claims are asserted over every N ∈ [2,100] with **no tolerance step**.
13
+
14
+ *(Ported from `theorems/pi_LogFractionUnitLoopBijection.js`. Only `EGPTReal`/`EGPTMath` are needed — both on `caps.math`. The PPF + L1-loop helpers use only those primitives and are inlined.)*
15
+ </cell>
16
+
17
+ <cell type="markdown">
18
+ ## Setup — PPF and L1-loop helpers (inlined)
19
+
20
+ `ppfOf`, the L1 forward/inverse quadrant maps, and `renderValue` are inlined — they call only `EGPTReal`/`EGPTMath`. Exposed as a binding the π cells consume.
21
+ </cell>
22
+
23
+ <cell type="js" lane="math" id="pi-setup" out="pihelp">
24
+ const { math } = caps;
25
+ const { EGPTReal, EGPTMath } = math;
26
+ const H_ZERO = EGPTReal.fromBigInt(0n);
27
+ const H_ONE = EGPTReal.fromBigInt(1n);
28
+ const H_NEG_ONE = EGPTReal.fromRational(-1n, 1n);
29
+ const H_QUARTER = EGPTReal.fromRational(1n, 4n);
30
+ const H_HALF = EGPTReal.fromRational(1n, 2n);
31
+ const H_3QUARTER = EGPTReal.fromRational(3n, 4n);
32
+
33
+ function bitLengthBigInt(n) { let x = n < 0n ? -n : n, b = 0; while (x > 0n) { x >>= 1n; b++; } return b; }
34
+ function bigPow2(k) { return 1n << BigInt(k); }
35
+ function ppfOf(n) {
36
+ if (n <= 0n) throw new Error('ppfOf requires positive n, got ' + n);
37
+ if (n === 1n) return { L: 0, offset: 0n };
38
+ const L = bitLengthBigInt(n) - 1;
39
+ return { L, offset: n - (1n << BigInt(L)) };
40
+ }
41
+ function renderValue(v) {
42
+ if (v == null) return String(v);
43
+ if (typeof v._getPPFRationalParts === 'function') {
44
+ const { numerator, denominator } = v._getPPFRationalParts();
45
+ if (denominator === 1n || denominator === -1n) return String(denominator < 0n ? -numerator : numerator);
46
+ return `${numerator}/${denominator}`;
47
+ }
48
+ return String(v);
49
+ }
50
+ function canonicalFractionToL1Position(H) {
51
+ if (EGPTMath.equals(H, H_ZERO)) return { x: H_ONE, y: H_ZERO };
52
+ if (EGPTMath.equals(H, H_QUARTER)) return { x: H_ZERO, y: H_ONE };
53
+ if (EGPTMath.equals(H, H_HALF)) return { x: H_NEG_ONE, y: H_ZERO };
54
+ if (EGPTMath.equals(H, H_3QUARTER)) return { x: H_ZERO, y: H_NEG_ONE };
55
+ if (EGPTMath.compare(H, H_QUARTER) < 0) { const p = EGPTMath.divide(H, H_QUARTER); return { x: EGPTMath.subtract(H_ONE, p), y: p }; }
56
+ if (EGPTMath.compare(H, H_HALF) < 0) { const p = EGPTMath.divide(EGPTMath.subtract(H, H_QUARTER), H_QUARTER); return { x: EGPTMath.subtract(H_ZERO, p), y: EGPTMath.subtract(H_ONE, p) }; }
57
+ if (EGPTMath.compare(H, H_3QUARTER) < 0) { const p = EGPTMath.divide(EGPTMath.subtract(H, H_HALF), H_QUARTER); return { x: EGPTMath.subtract(p, H_ONE), y: EGPTMath.subtract(H_ZERO, p) }; }
58
+ const p = EGPTMath.divide(EGPTMath.subtract(H, H_3QUARTER), H_QUARTER); return { x: p, y: EGPTMath.subtract(p, H_ONE) };
59
+ }
60
+ function l1PositionToCanonicalFraction({ x, y }) {
61
+ const xPos = EGPTMath.compare(x, H_ZERO) >= 0;
62
+ const yPos = EGPTMath.compare(y, H_ZERO) >= 0;
63
+ if (xPos && yPos) return EGPTMath.multiply(y, H_QUARTER);
64
+ if (!xPos && yPos) return EGPTMath.add(H_QUARTER, EGPTMath.multiply(EGPTMath.subtract(H_ZERO, x), H_QUARTER));
65
+ if (!xPos && !yPos) return EGPTMath.add(H_HALF, EGPTMath.multiply(EGPTMath.add(x, H_ONE), H_QUARTER));
66
+ return EGPTMath.add(H_3QUARTER, EGPTMath.multiply(x, H_QUARTER));
67
+ }
68
+ return { pihelp: { ppfOf, bigPow2, bitLengthBigInt, renderValue, canonicalFractionToL1Position, l1PositionToCanonicalFraction,
69
+ cardinals: { H_ZERO, H_ONE, H_NEG_ONE, H_QUARTER, H_HALF, H_3QUARTER } } };
70
+ </cell>
71
+
72
+ <cell type="markdown">
73
+ ## π1 — PPF {L, offset} ≡ (⌊log₂ N⌋, N − 2^L)
74
+
75
+ `N = 2^L + offset` with `0 ≤ offset < 2^L` and `L = bitLength(N) − 1`. Asserted bit-exactly for every N ∈ [2,100].
76
+ </cell>
77
+
78
+ <cell type="js" lane="math" id="pi1" in="pihelp">
79
+ const { display } = caps;
80
+ const { ppfOf, bigPow2, bitLengthBigInt } = inputs.pihelp;
81
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('π1 FAILED: ' + label); }
82
+ for (const N of [17n, 21n, 35n, 391n]) { const p = ppfOf(N); display(`N=${N}: PPF {L=${p.L}, offset=${p.offset}} → 2^${p.L}+${p.offset} = ${bigPow2(p.L) + p.offset}`); }
83
+ check('π1 reconstruction: 2^L + offset = N for every N ∈ [2,100]', (() => { for (let N = 2n; N <= 100n; N++) { const { L, offset } = ppfOf(N); if (bigPow2(L) + offset !== N) return false; } return true; })());
84
+ check('π1 offset bound: 0 ≤ offset < 2^L for every N ∈ [2,100]', (() => { for (let N = 2n; N <= 100n; N++) { const { L, offset } = ppfOf(N); if (offset < 0n || offset >= bigPow2(L)) return false; } return true; })());
85
+ check('π1 bit-length identity: L = bitLength(N) − 1 for every N ∈ [2,100]', (() => { for (let N = 2n; N <= 100n; N++) { const { L } = ppfOf(N); if (L !== bitLengthBigInt(N) - 1) return false; } return true; })());
86
+ </cell>
87
+
88
+ <cell type="markdown">
89
+ ## π2 — offset / 2^L ≡ a canonical fraction in [0,1)
90
+
91
+ The scaled residue `r(N) = offset/2^L` is an exact rational in [0,1); multiplying back by 2^L recovers offset exactly.
92
+ </cell>
93
+
94
+ <cell type="js" lane="math" id="pi2" in="pihelp">
95
+ const { math, display } = caps;
96
+ const { EGPTReal, EGPTMath } = math;
97
+ const { ppfOf, bigPow2, renderValue, cardinals } = inputs.pihelp;
98
+ const { H_ZERO, H_ONE } = cardinals;
99
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('π2 FAILED: ' + label); }
100
+ for (const N of [17n, 21n, 35n, 391n]) { const { L, offset } = ppfOf(N); const r = EGPTReal.fromRational(offset, bigPow2(L)); display(`N=${N}: r(N) = ${offset}/${bigPow2(L)} = ${renderValue(r)}`); }
101
+ check('π2 range: 0 ≤ r(N) < 1 for every N ∈ [2,100]', (() => { for (let N = 2n; N <= 100n; N++) { const { L, offset } = ppfOf(N); const r = EGPTReal.fromRational(offset, bigPow2(L)); if (EGPTMath.compare(r, H_ZERO) < 0 || EGPTMath.compare(r, H_ONE) >= 0) return false; } return true; })());
102
+ check('π2 inversion: r · 2^L = offset (exact) for every N ∈ [2,100]', (() => { for (let N = 2n; N <= 100n; N++) { const { L, offset } = ppfOf(N); const r = EGPTReal.fromRational(offset, bigPow2(L)); const prod = EGPTMath.multiply(r, EGPTReal.fromBigInt(bigPow2(L)))._getPPFRationalParts(); if (prod.denominator !== 1n || prod.numerator !== offset) return false; } return true; })());
103
+ </cell>
104
+
105
+ <cell type="markdown">
106
+ ## π3 — canonical fraction ≡ L1 unit-loop position (x,y)
107
+
108
+ `r ∈ [0,1)` maps bijectively to (x,y) on |x|+|y|=1 by four straight-line quadrants. Cardinal fractions land on cardinal vertices; the round trip r → (x,y) → r is the identity; the L1 norm is exactly 1. (This is a 1D→2D position readout, not a multiplicative primitive.)
109
+ </cell>
110
+
111
+ <cell type="js" lane="math" id="pi3" in="pihelp">
112
+ const { math, display } = caps;
113
+ const { EGPTReal, EGPTMath } = math;
114
+ const { ppfOf, bigPow2, renderValue, canonicalFractionToL1Position, l1PositionToCanonicalFraction, cardinals } = inputs.pihelp;
115
+ const { H_ZERO, H_ONE, H_NEG_ONE, H_QUARTER, H_HALF, H_3QUARTER } = cardinals;
116
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('π3 FAILED: ' + label); }
117
+
118
+ for (const N of [17n, 21n, 35n, 391n]) { const { L, offset } = ppfOf(N); const r = EGPTReal.fromRational(offset, bigPow2(L)); const pos = canonicalFractionToL1Position(r); display(`N=${N}: r=${renderValue(r)} → (x,y)=(${renderValue(pos.x)}, ${renderValue(pos.y)})`); }
119
+
120
+ for (const [label, H_frac, eX, eY] of [
121
+ ['r=0', H_ZERO, H_ONE, H_ZERO], ['r=1/4', H_QUARTER, H_ZERO, H_ONE],
122
+ ['r=1/2', H_HALF, H_NEG_ONE, H_ZERO], ['r=3/4', H_3QUARTER, H_ZERO, H_NEG_ONE]
123
+ ]) { const pos = canonicalFractionToL1Position(H_frac); check(`cardinal ${label} → (${renderValue(eX)}, ${renderValue(eY)})`, EGPTMath.equals(pos.x, eX) && EGPTMath.equals(pos.y, eY)); }
124
+
125
+ check('π3 L1 norm |x|+|y| = 1 for every N ∈ [2,100]', (() => {
126
+ for (let N = 2n; N <= 100n; N++) { const { L, offset } = ppfOf(N); const r = EGPTReal.fromRational(offset, bigPow2(L)); const pos = canonicalFractionToL1Position(r);
127
+ const px = pos.x._getPPFRationalParts(), py = pos.y._getPPFRationalParts();
128
+ const ax = EGPTReal.fromRational(px.numerator < 0n ? -px.numerator : px.numerator, px.denominator);
129
+ const ay = EGPTReal.fromRational(py.numerator < 0n ? -py.numerator : py.numerator, py.denominator);
130
+ if (!EGPTMath.equals(EGPTMath.add(ax, ay), H_ONE)) return false; } return true; })());
131
+ check('π3 round trip r → (x,y) → r is identity for every N ∈ [2,100]', (() => {
132
+ for (let N = 2n; N <= 100n; N++) { const { L, offset } = ppfOf(N); const r = EGPTReal.fromRational(offset, bigPow2(L)); const pos = canonicalFractionToL1Position(r); if (!EGPTMath.equals(l1PositionToCanonicalFraction(pos), r)) return false; } return true; })());
133
+ </cell>
134
+
135
+ <cell type="js" lane="math" id="pi-qed">
136
+ const { display } = caps;
137
+ display('QED — π1/π2/π3 verified bit-exactly over N ∈ [2,100]. The PPF address of N IS its point on the unit loop — exact, no transcendentals.');
138
+ </cell>
139
+
140
+ </frqtl-notebook>