@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,703 @@
1
+ <frqtl-notebook version="1" title="EGPT Polynomial Test Suite — Arithmetic, Transforms, and Factor Detection">
2
+
3
+ <cell type="markdown">
4
+ # EGPT Polynomial Test Suite
5
+
6
+ This notebook ports the canonical polynomial test suite authored by E. Abadir. It exercises `EGPTPolynomial` — the polynomial algebra layer over `EGPTReal` exact rationals — at three transform sizes (N=32, N=64, N=128) and verifies that the library stays entirely in canonical space (no `toFloat()`, no `toBigInt()` for comparisons).
7
+
8
+ **What is tested:**
9
+
10
+ - **Phase 1 — Basic arithmetic:** `add`, `subtract`, `multiply`, `divide`, `evaluateAt`, `equals`, `trimZeros`, `degree` on small integer and rational polynomials.
11
+ - **Phases 2–3 — N=32 transforms:** forward evaluation at k/N sample points, and the inverse round-trip (forward then inverse recovers the original coefficients exactly), including polynomials with fractional coefficients.
12
+ - **Phases 4–5 — N=64 transforms:** same battery at the next size.
13
+ - **Phases 6–7 — N=128 transforms:** same battery at the largest size.
14
+ - **Phase 8 — Value representation:** `evaluateValueRepresentation(k, p)` returns an integer result exactly when `p` is a factor of `k`, and a non-integer otherwise.
15
+
16
+ All comparisons use `.equals()` on `EGPTReal` values — the canonical exactness criterion.
17
+ </cell>
18
+
19
+ <cell type="markdown">
20
+ ## Test harness setup
21
+
22
+ `TestFramework` is not on the SDK surface — it is inlined here. The harness accumulates pass/fail results so the final summary cell can report totals.
23
+ </cell>
24
+
25
+ <cell type="js" lane="math" id="poly-harness" out="suite">
26
+ const { math } = caps;
27
+
28
+ class TestFramework {
29
+ constructor() {
30
+ this.tests = [];
31
+ this.categories = {};
32
+ }
33
+
34
+ test(description, category, testFunction) {
35
+ const result = { description, category, passed: false, error: null };
36
+ try {
37
+ result.passed = testFunction();
38
+ if (result.passed === undefined) result.passed = true;
39
+ } catch (error) {
40
+ result.passed = false;
41
+ result.error = error.message;
42
+ }
43
+ this.tests.push(result);
44
+ if (!this.categories[category]) this.categories[category] = [];
45
+ this.categories[category].push(result);
46
+ const status = result.passed ? 'PASS' : 'FAIL';
47
+ const errMsg = result.error ? ` (${result.error})` : '';
48
+ console.log(`${status}: ${description}${errMsg}`);
49
+ }
50
+
51
+ getSummary() {
52
+ const total = this.tests.length;
53
+ const passed = this.tests.filter(t => t.passed).length;
54
+ const failed = total - passed;
55
+ const lines = [];
56
+ lines.push('='.repeat(60));
57
+ lines.push('TEST SUMMARY');
58
+ lines.push('='.repeat(60));
59
+ for (const [cat, catTests] of Object.entries(this.categories)) {
60
+ const cp = catTests.filter(t => t.passed).length;
61
+ lines.push(` ${cat}: ${cp}/${catTests.length} passed`);
62
+ }
63
+ lines.push('-'.repeat(60));
64
+ lines.push(`TOTAL: ${passed}/${total} tests passed`);
65
+ lines.push(`SUCCESS RATE: ${((passed / total) * 100).toFixed(1)}%`);
66
+ if (failed > 0) {
67
+ lines.push('\nFAILED TESTS:');
68
+ for (const t of this.tests.filter(t => !t.passed)) {
69
+ lines.push(` - [${t.category}] ${t.description}${t.error ? ': ' + t.error : ''}`);
70
+ }
71
+ }
72
+ lines.push('='.repeat(60));
73
+ return lines.join('\n');
74
+ }
75
+ }
76
+
77
+ const test = new TestFramework();
78
+ return { suite: test };
79
+ </cell>
80
+
81
+ <cell type="markdown">
82
+ ## Phase 1 — Basic arithmetic
83
+
84
+ These tests cover the foundational operations: `add`, `subtract`, `multiply`, `divide`, `evaluateAt`, `equals`, `trimZeros`, and `degree`. Polynomials are represented as coefficient arrays `[a₀, a₁, …, aₙ]` where index `i` is the coefficient of `xⁱ`. Every coefficient is an `EGPTReal` exact rational.
85
+ </cell>
86
+
87
+ <cell type="js" lane="math" id="poly-phase1" in="suite" out="suite">
88
+ const { math } = caps;
89
+ const { EGPTReal, EGPTPolynomial } = math;
90
+ const test = inputs.suite;
91
+
92
+ console.log('--- PHASE 1: Basic Arithmetic Tests ---');
93
+
94
+ // Polynomial addition: same length
95
+ test.test('Polynomial addition: [1,2] + [3,4] = [4,6]', 'Arithmetic', () => {
96
+ const poly1 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n)];
97
+ const poly2 = [EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(4n)];
98
+ const result = EGPTPolynomial.add(poly1, poly2);
99
+ const expected = [EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(6n)];
100
+ return EGPTPolynomial.equals(result, expected);
101
+ });
102
+
103
+ // Polynomial addition: different lengths — longer wins
104
+ test.test('Polynomial addition with different lengths', 'Arithmetic', () => {
105
+ const poly1 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
106
+ const poly2 = [EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(7n)];
107
+ const result = EGPTPolynomial.add(poly1, poly2);
108
+ const expected = [EGPTReal.fromBigInt(6n), EGPTReal.fromBigInt(9n), EGPTReal.fromBigInt(3n)];
109
+ return EGPTPolynomial.equals(result, expected);
110
+ });
111
+
112
+ // Polynomial subtraction
113
+ test.test('Polynomial subtraction: [5,8] - [2,3] = [3,5]', 'Arithmetic', () => {
114
+ const poly1 = [EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(8n)];
115
+ const poly2 = [EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
116
+ const result = EGPTPolynomial.subtract(poly1, poly2);
117
+ const expected = [EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(5n)];
118
+ return EGPTPolynomial.equals(result, expected);
119
+ });
120
+
121
+ // Polynomial multiplication: (1 + 2x)(3 + 4x) = 3 + 10x + 8x²
122
+ test.test('Polynomial multiplication: [1,2] * [3,4] = [3,10,8]', 'Arithmetic', () => {
123
+ const poly1 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n)];
124
+ const poly2 = [EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(4n)];
125
+ const result = EGPTPolynomial.multiply(poly1, poly2);
126
+ const expected = [EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(10n), EGPTReal.fromBigInt(8n)];
127
+ return EGPTPolynomial.equals(result, expected);
128
+ });
129
+
130
+ // Multiplication by a constant scalar polynomial
131
+ test.test('Polynomial multiplication by constant', 'Arithmetic', () => {
132
+ const poly1 = [EGPTReal.fromBigInt(5n)];
133
+ const poly2 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
134
+ const result = EGPTPolynomial.multiply(poly1, poly2);
135
+ const expected = [EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(10n), EGPTReal.fromBigInt(15n)];
136
+ return EGPTPolynomial.equals(result, expected);
137
+ });
138
+
139
+ // Division with a fractional quotient
140
+ // (6 + 11x + 6x² + x³) ÷ (2 + 3x) — quotient has rational coefficients
141
+ test.test('Polynomial division with fractional quotient', 'Arithmetic', () => {
142
+ const dividend = [
143
+ EGPTReal.fromBigInt(6n), EGPTReal.fromBigInt(11n),
144
+ EGPTReal.fromBigInt(6n), EGPTReal.fromBigInt(1n)
145
+ ];
146
+ const divisor = [EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
147
+ const { quotient, remainder } = EGPTPolynomial.divide(dividend, divisor);
148
+ const expectedQuot = [
149
+ EGPTReal.fromRational(67n, 27n),
150
+ EGPTReal.fromRational(16n, 9n),
151
+ EGPTReal.fromRational(1n, 3n)
152
+ ];
153
+ const expectedRem = [EGPTReal.fromRational(28n, 27n)];
154
+ return EGPTPolynomial.equals(quotient, expectedQuot) &&
155
+ EGPTPolynomial.equals(remainder, expectedRem);
156
+ });
157
+
158
+ // Division with integer remainder — verify via reconstruction
159
+ // (5 + 4x + 3x²) ÷ (2 + x): dividend = divisor * quotient + remainder
160
+ test.test('Polynomial division with remainder (reconstruction check)', 'Arithmetic', () => {
161
+ const dividend = [EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(3n)];
162
+ const divisor = [EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(1n)];
163
+ const { quotient, remainder } = EGPTPolynomial.divide(dividend, divisor);
164
+ const check = EGPTPolynomial.add(EGPTPolynomial.multiply(divisor, quotient), remainder);
165
+ return EGPTPolynomial.equals(dividend, check);
166
+ });
167
+
168
+ // evaluateAt: 3 + 2x + x² at x=2 should equal 11
169
+ test.test('Polynomial evaluate at x=2: 3 + 2x + x² = 11', 'Arithmetic', () => {
170
+ const poly = [EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(1n)];
171
+ const result = EGPTPolynomial.evaluateAt(poly, EGPTReal.fromBigInt(2n));
172
+ return result.equals(EGPTReal.fromBigInt(11n));
173
+ });
174
+
175
+ // evaluateAt: 4 + 2x at x=1/2 should equal 5 (rational point)
176
+ test.test('Polynomial evaluate at x=1/2: 4 + 2x = 5', 'Arithmetic', () => {
177
+ const poly = [EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(2n)];
178
+ const result = EGPTPolynomial.evaluateAt(poly, EGPTReal.fromRational(1n, 2n));
179
+ return result.equals(EGPTReal.fromBigInt(5n));
180
+ });
181
+
182
+ // equals: identical polynomials
183
+ test.test('Polynomial equals comparison (identical)', 'Arithmetic', () => {
184
+ const poly1 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
185
+ const poly2 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
186
+ return EGPTPolynomial.equals(poly1, poly2);
187
+ });
188
+
189
+ // equals: different polynomials
190
+ test.test('Polynomial equals comparison (different)', 'Arithmetic', () => {
191
+ const poly1 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n)];
192
+ const poly2 = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(3n)];
193
+ return !EGPTPolynomial.equals(poly1, poly2);
194
+ });
195
+
196
+ // Rational coefficients
197
+ test.test('Polynomial with rational coefficients: addition', 'Arithmetic', () => {
198
+ const poly1 = [EGPTReal.fromRational(1n, 2n), EGPTReal.fromRational(3n, 4n)];
199
+ const poly2 = [EGPTReal.fromRational(1n, 4n), EGPTReal.fromRational(1n, 4n)];
200
+ const result = EGPTPolynomial.add(poly1, poly2);
201
+ const expected = [EGPTReal.fromRational(3n, 4n), EGPTReal.fromBigInt(1n)];
202
+ return EGPTPolynomial.equals(result, expected);
203
+ });
204
+
205
+ // trimZeros removes trailing zero coefficients
206
+ test.test('trimZeros removes trailing zeros', 'Arithmetic', () => {
207
+ const poly = [
208
+ EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n),
209
+ EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(0n)
210
+ ];
211
+ const result = EGPTPolynomial.trimZeros(poly);
212
+ const expected = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n)];
213
+ return EGPTPolynomial.equals(result, expected);
214
+ });
215
+
216
+ // degree: highest non-zero exponent
217
+ test.test('Degree calculation for polynomial', 'Arithmetic', () => {
218
+ const poly = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n)];
219
+ return EGPTPolynomial.degree(poly) === 2;
220
+ });
221
+
222
+ return { suite: test };
223
+ </cell>
224
+
225
+ <cell type="markdown">
226
+ ## Phase 2 — Forward transform at N=32
227
+
228
+ `EGPTPolynomial.forwardTransform(coeffs, N)` evaluates the polynomial at the N rational points `k/N` for `k = 0, 1, …, N−1`. These tests check specific expected values for simple polynomials: an impulse at position 0 must give constant samples; a constant polynomial `[c]` padded to N terms must produce all samples equal to `c`; linear and quadratic polynomials are checked at selected sample indices.
229
+ </cell>
230
+
231
+ <cell type="js" lane="math" id="poly-phase2" in="suite" out="suite">
232
+ const { math } = caps;
233
+ const { EGPTReal, EGPTPolynomial } = math;
234
+ const test = inputs.suite;
235
+
236
+ console.log('--- PHASE 2: Forward Transform Tests (N=32) ---');
237
+
238
+ test.test('N=32 Forward: Impulse at position 0', 'N=32 Forward', () => {
239
+ const coeffs = new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
240
+ coeffs[0] = EGPTReal.fromBigInt(1n);
241
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 32);
242
+ const expected = EGPTReal.fromBigInt(1n);
243
+ return samples.every(s => s.equals(expected));
244
+ });
245
+
246
+ test.test('N=32 Forward: Impulse at position 15', 'N=32 Forward', () => {
247
+ const coeffs = new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
248
+ coeffs[15] = EGPTReal.fromBigInt(1n);
249
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 32);
250
+ return samples.length === 32 && samples.every(s => s instanceof EGPTReal);
251
+ });
252
+
253
+ test.test('N=32 Forward: Constant polynomial [5]', 'N=32 Forward', () => {
254
+ const coeffs = new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
255
+ coeffs[0] = EGPTReal.fromBigInt(5n);
256
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 32);
257
+ const expected = EGPTReal.fromBigInt(5n);
258
+ return samples.every(s => s.equals(expected));
259
+ });
260
+
261
+ // Linear polynomial 1 + x evaluated at k/32:
262
+ // sample[0] = 1 + 0 = 1; sample[16] = 1 + 16/32 = 3/2
263
+ test.test('N=32 Forward: Linear polynomial [1,1]', 'N=32 Forward', () => {
264
+ const coeffs = new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
265
+ coeffs[0] = EGPTReal.fromBigInt(1n);
266
+ coeffs[1] = EGPTReal.fromBigInt(1n);
267
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 32);
268
+ return samples[0].equals(EGPTReal.fromBigInt(1n)) &&
269
+ samples[16].equals(EGPTReal.fromRational(3n, 2n));
270
+ });
271
+
272
+ // Quadratic 1 + x²: sample[0] = 1 + 0 = 1
273
+ test.test('N=32 Forward: Quadratic polynomial [1,0,1]', 'N=32 Forward', () => {
274
+ const coeffs = new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
275
+ coeffs[0] = EGPTReal.fromBigInt(1n);
276
+ coeffs[2] = EGPTReal.fromBigInt(1n);
277
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 32);
278
+ return samples[0].equals(EGPTReal.fromBigInt(1n)) && samples.length === 32;
279
+ });
280
+
281
+ // x^31: sample[0] = 0^31 = 0
282
+ test.test('N=32 Forward: High-degree monomial x^31', 'N=32 Forward', () => {
283
+ const coeffs = new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
284
+ coeffs[31] = EGPTReal.fromBigInt(1n);
285
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 32);
286
+ return samples[0].equals(EGPTReal.fromBigInt(0n)) && samples.length === 32;
287
+ });
288
+
289
+ return { suite: test };
290
+ </cell>
291
+
292
+ <cell type="markdown">
293
+ ## Phase 3 — Inverse (round-trip) transform at N=32
294
+
295
+ `inverseTransform(forwardTransform(c), N)` must recover `c` exactly — bit-for-bit in rational arithmetic. This is the core property the library must satisfy. The phase also includes **fractional-coefficient** polynomials (9 tests), verifying that the round-trip holds for polynomials with `1/2`, `1/3`, `−3/4`, large denominators, and sparse distributions.
296
+ </cell>
297
+
298
+ <cell type="js" lane="math" id="poly-phase3" in="suite" out="suite">
299
+ const { math } = caps;
300
+ const { EGPTReal, EGPTPolynomial } = math;
301
+ const test = inputs.suite;
302
+
303
+ console.log('--- PHASE 3: Inverse Transform / Round-trip Tests (N=32) ---');
304
+
305
+ function roundTrip32(original) {
306
+ const samples = EGPTPolynomial.forwardTransform(original, 32);
307
+ const recovered = EGPTPolynomial.inverseTransform(samples, 32);
308
+ return EGPTPolynomial.equals(original, recovered);
309
+ }
310
+
311
+ function makeCoeffs32() {
312
+ return new Array(32).fill(null).map(() => EGPTReal.fromBigInt(0n));
313
+ }
314
+
315
+ test.test('N=32 Round-trip: Impulse at position 0', 'N=32 Inverse', () => {
316
+ const orig = makeCoeffs32(); orig[0] = EGPTReal.fromBigInt(1n);
317
+ return roundTrip32(orig);
318
+ });
319
+
320
+ test.test('N=32 Round-trip: Impulse at position 15', 'N=32 Inverse', () => {
321
+ const orig = makeCoeffs32(); orig[15] = EGPTReal.fromBigInt(1n);
322
+ return roundTrip32(orig);
323
+ });
324
+
325
+ test.test('N=32 Round-trip: Constant polynomial [5]', 'N=32 Inverse', () => {
326
+ const orig = makeCoeffs32(); orig[0] = EGPTReal.fromBigInt(5n);
327
+ return roundTrip32(orig);
328
+ });
329
+
330
+ test.test('N=32 Round-trip: Linear polynomial [1,1]', 'N=32 Inverse', () => {
331
+ const orig = makeCoeffs32();
332
+ orig[0] = EGPTReal.fromBigInt(1n); orig[1] = EGPTReal.fromBigInt(1n);
333
+ return roundTrip32(orig);
334
+ });
335
+
336
+ test.test('N=32 Round-trip: Quadratic polynomial [1,0,1]', 'N=32 Inverse', () => {
337
+ const orig = makeCoeffs32();
338
+ orig[0] = EGPTReal.fromBigInt(1n); orig[2] = EGPTReal.fromBigInt(1n);
339
+ return roundTrip32(orig);
340
+ });
341
+
342
+ test.test('N=32 Round-trip: High-degree monomial x^31', 'N=32 Inverse', () => {
343
+ const orig = makeCoeffs32(); orig[31] = EGPTReal.fromBigInt(1n);
344
+ return roundTrip32(orig);
345
+ });
346
+
347
+ // -- Fractional coefficient tests --
348
+ test.test('N=32 Round-trip: Fractional constant [1/2]', 'N=32 Fractional', () => {
349
+ const orig = makeCoeffs32(); orig[0] = EGPTReal.fromRational(1n, 2n);
350
+ return roundTrip32(orig);
351
+ });
352
+
353
+ test.test('N=32 Round-trip: Fractional linear [1/2, 1/3]', 'N=32 Fractional', () => {
354
+ const orig = makeCoeffs32();
355
+ orig[0] = EGPTReal.fromRational(1n, 2n); orig[1] = EGPTReal.fromRational(1n, 3n);
356
+ return roundTrip32(orig);
357
+ });
358
+
359
+ test.test('N=32 Round-trip: Fractional quadratic [3/4, 1/2, 1/4]', 'N=32 Fractional', () => {
360
+ const orig = makeCoeffs32();
361
+ orig[0] = EGPTReal.fromRational(3n, 4n);
362
+ orig[1] = EGPTReal.fromRational(1n, 2n);
363
+ orig[2] = EGPTReal.fromRational(1n, 4n);
364
+ return roundTrip32(orig);
365
+ });
366
+
367
+ test.test('N=32 Round-trip: Mixed integer/fraction [2, 1/3, 0, 5/7]', 'N=32 Fractional', () => {
368
+ const orig = makeCoeffs32();
369
+ orig[0] = EGPTReal.fromBigInt(2n);
370
+ orig[1] = EGPTReal.fromRational(1n, 3n);
371
+ orig[3] = EGPTReal.fromRational(5n, 7n);
372
+ return roundTrip32(orig);
373
+ });
374
+
375
+ test.test('N=32 Round-trip: Negative fractions [-1/2, 3/4, -2/3]', 'N=32 Fractional', () => {
376
+ const orig = makeCoeffs32();
377
+ orig[0] = EGPTReal.fromRational(-1n, 2n);
378
+ orig[1] = EGPTReal.fromRational(3n, 4n);
379
+ orig[2] = EGPTReal.fromRational(-2n, 3n);
380
+ return roundTrip32(orig);
381
+ });
382
+
383
+ test.test('N=32 Round-trip: Dense fractions [1/2, 1/3, 1/4, 1/5, 1/6]', 'N=32 Fractional', () => {
384
+ const orig = makeCoeffs32();
385
+ orig[0] = EGPTReal.fromRational(1n, 2n); orig[1] = EGPTReal.fromRational(1n, 3n);
386
+ orig[2] = EGPTReal.fromRational(1n, 4n); orig[3] = EGPTReal.fromRational(1n, 5n);
387
+ orig[4] = EGPTReal.fromRational(1n, 6n);
388
+ return roundTrip32(orig);
389
+ });
390
+
391
+ test.test('N=32 Round-trip: Large denominators [1/100, 7/50]', 'N=32 Fractional', () => {
392
+ const orig = makeCoeffs32();
393
+ orig[0] = EGPTReal.fromRational(1n, 100n); orig[1] = EGPTReal.fromRational(7n, 50n);
394
+ return roundTrip32(orig);
395
+ });
396
+
397
+ test.test('N=32 Round-trip: High-degree fractional monomial [5/7] at x^31', 'N=32 Fractional', () => {
398
+ const orig = makeCoeffs32(); orig[31] = EGPTReal.fromRational(5n, 7n);
399
+ return roundTrip32(orig);
400
+ });
401
+
402
+ test.test('N=32 Round-trip: Complex sparse fractions', 'N=32 Fractional', () => {
403
+ const orig = makeCoeffs32();
404
+ orig[0] = EGPTReal.fromBigInt(2n);
405
+ orig[1] = EGPTReal.fromRational(-3n, 4n);
406
+ orig[3] = EGPTReal.fromRational(1n, 2n);
407
+ orig[7] = EGPTReal.fromRational(-5n, 3n);
408
+ orig[20] = EGPTReal.fromRational(7n, 11n);
409
+ return roundTrip32(orig);
410
+ });
411
+
412
+ return { suite: test };
413
+ </cell>
414
+
415
+ <cell type="markdown">
416
+ ## Phase 4 — Forward transform at N=64
417
+
418
+ Same battery as Phase 2 but at N=64. The extra size validates that the rational-point evaluation `k/64` grid produces correct values.
419
+ </cell>
420
+
421
+ <cell type="js" lane="math" id="poly-phase4" in="suite" out="suite">
422
+ const { math } = caps;
423
+ const { EGPTReal, EGPTPolynomial } = math;
424
+ const test = inputs.suite;
425
+
426
+ console.log('--- PHASE 4: Forward Transform Tests (N=64) ---');
427
+
428
+ function makeCoeffs64() {
429
+ return new Array(64).fill(null).map(() => EGPTReal.fromBigInt(0n));
430
+ }
431
+
432
+ test.test('N=64 Forward: Impulse at position 0', 'N=64 Forward', () => {
433
+ const coeffs = makeCoeffs64(); coeffs[0] = EGPTReal.fromBigInt(1n);
434
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 64);
435
+ return samples.every(s => s.equals(EGPTReal.fromBigInt(1n)));
436
+ });
437
+
438
+ test.test('N=64 Forward: Constant polynomial [7]', 'N=64 Forward', () => {
439
+ const coeffs = makeCoeffs64(); coeffs[0] = EGPTReal.fromBigInt(7n);
440
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 64);
441
+ return samples.every(s => s.equals(EGPTReal.fromBigInt(7n)));
442
+ });
443
+
444
+ // Linear 2 + 3x: sample[0] = 2 + 3(0) = 2
445
+ test.test('N=64 Forward: Linear polynomial [2,3]', 'N=64 Forward', () => {
446
+ const coeffs = makeCoeffs64();
447
+ coeffs[0] = EGPTReal.fromBigInt(2n); coeffs[1] = EGPTReal.fromBigInt(3n);
448
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 64);
449
+ return samples[0].equals(EGPTReal.fromBigInt(2n)) && samples.length === 64;
450
+ });
451
+
452
+ // Sparse: non-zero at positions 0, 10, 20, 30
453
+ test.test('N=64 Forward: Sparse polynomial with gaps', 'N=64 Forward', () => {
454
+ const coeffs = makeCoeffs64();
455
+ coeffs[0] = EGPTReal.fromBigInt(1n); coeffs[10] = EGPTReal.fromBigInt(1n);
456
+ coeffs[20] = EGPTReal.fromBigInt(1n); coeffs[30] = EGPTReal.fromBigInt(1n);
457
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 64);
458
+ return samples.length === 64 && samples.every(s => s instanceof EGPTReal);
459
+ });
460
+
461
+ // x^63: sample[0] = 0^63 = 0
462
+ test.test('N=64 Forward: High-degree monomial x^63', 'N=64 Forward', () => {
463
+ const coeffs = makeCoeffs64(); coeffs[63] = EGPTReal.fromBigInt(1n);
464
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 64);
465
+ return samples[0].equals(EGPTReal.fromBigInt(0n)) && samples.length === 64;
466
+ });
467
+
468
+ return { suite: test };
469
+ </cell>
470
+
471
+ <cell type="markdown">
472
+ ## Phase 5 — Inverse (round-trip) transform at N=64
473
+
474
+ Exact coefficient recovery after forward→inverse at N=64.
475
+ </cell>
476
+
477
+ <cell type="js" lane="math" id="poly-phase5" in="suite" out="suite">
478
+ const { math } = caps;
479
+ const { EGPTReal, EGPTPolynomial } = math;
480
+ const test = inputs.suite;
481
+
482
+ console.log('--- PHASE 5: Inverse Transform / Round-trip Tests (N=64) ---');
483
+
484
+ function makeCoeffs64() {
485
+ return new Array(64).fill(null).map(() => EGPTReal.fromBigInt(0n));
486
+ }
487
+
488
+ function roundTrip64(original) {
489
+ const samples = EGPTPolynomial.forwardTransform(original, 64);
490
+ const recovered = EGPTPolynomial.inverseTransform(samples, 64);
491
+ return EGPTPolynomial.equals(original, recovered);
492
+ }
493
+
494
+ test.test('N=64 Round-trip: Impulse at position 0', 'N=64 Inverse', () => {
495
+ const orig = makeCoeffs64(); orig[0] = EGPTReal.fromBigInt(1n);
496
+ return roundTrip64(orig);
497
+ });
498
+
499
+ test.test('N=64 Round-trip: Constant polynomial [7]', 'N=64 Inverse', () => {
500
+ const orig = makeCoeffs64(); orig[0] = EGPTReal.fromBigInt(7n);
501
+ return roundTrip64(orig);
502
+ });
503
+
504
+ test.test('N=64 Round-trip: Linear polynomial [2,3]', 'N=64 Inverse', () => {
505
+ const orig = makeCoeffs64();
506
+ orig[0] = EGPTReal.fromBigInt(2n); orig[1] = EGPTReal.fromBigInt(3n);
507
+ return roundTrip64(orig);
508
+ });
509
+
510
+ test.test('N=64 Round-trip: Sparse polynomial with gaps', 'N=64 Inverse', () => {
511
+ const orig = makeCoeffs64();
512
+ orig[0] = EGPTReal.fromBigInt(1n); orig[10] = EGPTReal.fromBigInt(1n);
513
+ orig[20] = EGPTReal.fromBigInt(1n); orig[30] = EGPTReal.fromBigInt(1n);
514
+ return roundTrip64(orig);
515
+ });
516
+
517
+ test.test('N=64 Round-trip: High-degree monomial x^63', 'N=64 Inverse', () => {
518
+ const orig = makeCoeffs64(); orig[63] = EGPTReal.fromBigInt(1n);
519
+ return roundTrip64(orig);
520
+ });
521
+
522
+ return { suite: test };
523
+ </cell>
524
+
525
+ <cell type="markdown">
526
+ ## Phase 6 — Forward transform at N=128
527
+
528
+ The largest transform size in the suite. N=128 requires 128 polynomial evaluations at rational points `k/128`.
529
+ </cell>
530
+
531
+ <cell type="js" lane="math" id="poly-phase6" in="suite" out="suite">
532
+ const { math } = caps;
533
+ const { EGPTReal, EGPTPolynomial } = math;
534
+ const test = inputs.suite;
535
+
536
+ console.log('--- PHASE 6: Forward Transform Tests (N=128) ---');
537
+
538
+ function makeCoeffs128() {
539
+ return new Array(128).fill(null).map(() => EGPTReal.fromBigInt(0n));
540
+ }
541
+
542
+ test.test('N=128 Forward: Impulse at position 0', 'N=128 Forward', () => {
543
+ const coeffs = makeCoeffs128(); coeffs[0] = EGPTReal.fromBigInt(1n);
544
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 128);
545
+ return samples.every(s => s.equals(EGPTReal.fromBigInt(1n)));
546
+ });
547
+
548
+ test.test('N=128 Forward: Constant polynomial [11]', 'N=128 Forward', () => {
549
+ const coeffs = makeCoeffs128(); coeffs[0] = EGPTReal.fromBigInt(11n);
550
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 128);
551
+ return samples.every(s => s.equals(EGPTReal.fromBigInt(11n)));
552
+ });
553
+
554
+ // Linear 1 + 2x: sample[0] = 1 + 2(0) = 1
555
+ test.test('N=128 Forward: Linear polynomial [1,2]', 'N=128 Forward', () => {
556
+ const coeffs = makeCoeffs128();
557
+ coeffs[0] = EGPTReal.fromBigInt(1n); coeffs[1] = EGPTReal.fromBigInt(2n);
558
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 128);
559
+ return samples[0].equals(EGPTReal.fromBigInt(1n)) && samples.length === 128;
560
+ });
561
+
562
+ // Sparse at positions 0, 16, 32, 64
563
+ test.test('N=128 Forward: Sparse polynomial', 'N=128 Forward', () => {
564
+ const coeffs = makeCoeffs128();
565
+ coeffs[0] = EGPTReal.fromBigInt(1n); coeffs[16] = EGPTReal.fromBigInt(1n);
566
+ coeffs[32] = EGPTReal.fromBigInt(1n); coeffs[64] = EGPTReal.fromBigInt(1n);
567
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 128);
568
+ return samples.length === 128 && samples.every(s => s instanceof EGPTReal);
569
+ });
570
+
571
+ // x^127: sample[0] = 0^127 = 0
572
+ test.test('N=128 Forward: High-degree monomial x^127', 'N=128 Forward', () => {
573
+ const coeffs = makeCoeffs128(); coeffs[127] = EGPTReal.fromBigInt(1n);
574
+ const samples = EGPTPolynomial.forwardTransform(coeffs, 128);
575
+ return samples[0].equals(EGPTReal.fromBigInt(0n)) && samples.length === 128;
576
+ });
577
+
578
+ return { suite: test };
579
+ </cell>
580
+
581
+ <cell type="markdown">
582
+ ## Phase 7 — Inverse (round-trip) transform at N=128
583
+
584
+ Exact coefficient recovery at N=128. The high-degree monomial `x^127` is the most demanding case.
585
+ </cell>
586
+
587
+ <cell type="js" lane="math" id="poly-phase7" in="suite" out="suite">
588
+ const { math } = caps;
589
+ const { EGPTReal, EGPTPolynomial } = math;
590
+ const test = inputs.suite;
591
+
592
+ console.log('--- PHASE 7: Inverse Transform / Round-trip Tests (N=128) ---');
593
+
594
+ function makeCoeffs128() {
595
+ return new Array(128).fill(null).map(() => EGPTReal.fromBigInt(0n));
596
+ }
597
+
598
+ function roundTrip128(original) {
599
+ const samples = EGPTPolynomial.forwardTransform(original, 128);
600
+ const recovered = EGPTPolynomial.inverseTransform(samples, 128);
601
+ return EGPTPolynomial.equals(original, recovered);
602
+ }
603
+
604
+ test.test('N=128 Round-trip: Impulse at position 0', 'N=128 Inverse', () => {
605
+ const orig = makeCoeffs128(); orig[0] = EGPTReal.fromBigInt(1n);
606
+ return roundTrip128(orig);
607
+ });
608
+
609
+ test.test('N=128 Round-trip: Constant polynomial [11]', 'N=128 Inverse', () => {
610
+ const orig = makeCoeffs128(); orig[0] = EGPTReal.fromBigInt(11n);
611
+ return roundTrip128(orig);
612
+ });
613
+
614
+ test.test('N=128 Round-trip: Linear polynomial [1,2]', 'N=128 Inverse', () => {
615
+ const orig = makeCoeffs128();
616
+ orig[0] = EGPTReal.fromBigInt(1n); orig[1] = EGPTReal.fromBigInt(2n);
617
+ return roundTrip128(orig);
618
+ });
619
+
620
+ test.test('N=128 Round-trip: Sparse polynomial', 'N=128 Inverse', () => {
621
+ const orig = makeCoeffs128();
622
+ orig[0] = EGPTReal.fromBigInt(1n); orig[16] = EGPTReal.fromBigInt(1n);
623
+ orig[32] = EGPTReal.fromBigInt(1n); orig[64] = EGPTReal.fromBigInt(1n);
624
+ return roundTrip128(orig);
625
+ });
626
+
627
+ test.test('N=128 Round-trip: High-degree monomial x^127', 'N=128 Inverse', () => {
628
+ const orig = makeCoeffs128(); orig[127] = EGPTReal.fromBigInt(1n);
629
+ return roundTrip128(orig);
630
+ });
631
+
632
+ return { suite: test };
633
+ </cell>
634
+
635
+ <cell type="markdown">
636
+ ## Phase 8 — Value representation (factor detection)
637
+
638
+ `EGPTPolynomial.evaluateValueRepresentation(k, p)` computes the rational value `k/p`. When `p` is an exact factor of `k` this quotient is an integer — detectable via `EGPTReal.isInteger()` and retrievable as a `BigInt` via `breakSymbolicToApproximateBigInt()`. When `p` does not divide `k`, the result is a proper fraction and `isInteger()` returns `false`.
639
+
640
+ This is the foundational divisibility test that underlies prime-factor detection in the EGPTMath bijection chain.
641
+ </cell>
642
+
643
+ <cell type="js" lane="math" id="poly-phase8" in="suite" out="suite">
644
+ const { math } = caps;
645
+ const { EGPTReal, EGPTPolynomial } = math;
646
+ const test = inputs.suite;
647
+
648
+ console.log('--- PHASE 8: Value Representation Tests (Factor Detection) ---');
649
+
650
+ // 35 / 5 = 7 (exact) → isInteger() true, breakSymbolicToApproximateBigInt() === 7n
651
+ test.test('Value representation: 35 / 5 (exact factor)', 'Value Representation', () => {
652
+ const entropy = EGPTPolynomial.evaluateValueRepresentation(
653
+ EGPTReal.fromBigInt(35n), EGPTReal.fromBigInt(5n)
654
+ );
655
+ return entropy.isInteger() && entropy.breakSymbolicToApproximateBigInt() === 7n;
656
+ });
657
+
658
+ // 35 / 6 — 6 does not divide 35 → isInteger() false
659
+ test.test('Value representation: 35 / 6 (non-factor)', 'Value Representation', () => {
660
+ const entropy = EGPTPolynomial.evaluateValueRepresentation(
661
+ EGPTReal.fromBigInt(35n), EGPTReal.fromBigInt(6n)
662
+ );
663
+ return !entropy.isInteger();
664
+ });
665
+
666
+ // 77 / 7 = 11 (exact)
667
+ test.test('Value representation: 77 / 7 (exact factor)', 'Value Representation', () => {
668
+ const entropy = EGPTPolynomial.evaluateValueRepresentation(
669
+ EGPTReal.fromBigInt(77n), EGPTReal.fromBigInt(7n)
670
+ );
671
+ return entropy.isInteger() && entropy.breakSymbolicToApproximateBigInt() === 11n;
672
+ });
673
+
674
+ // 77 / 8 — 8 does not divide 77
675
+ test.test('Value representation: 77 / 8 (non-factor)', 'Value Representation', () => {
676
+ const entropy = EGPTPolynomial.evaluateValueRepresentation(
677
+ EGPTReal.fromBigInt(77n), EGPTReal.fromBigInt(8n)
678
+ );
679
+ return !entropy.isInteger();
680
+ });
681
+
682
+ return { suite: test };
683
+ </cell>
684
+
685
+ <cell type="markdown">
686
+ ## Summary
687
+
688
+ All eight phases have run. The final cell prints the complete pass/fail accounting — the same summary the original test file emitted to the console.
689
+ </cell>
690
+
691
+ <cell type="js" lane="math" id="poly-summary" in="suite">
692
+ const test = inputs.suite;
693
+ const summary = test.getSummary();
694
+ console.log(summary);
695
+
696
+ const total = test.tests.length;
697
+ const passed = test.tests.filter(t => t.passed).length;
698
+ if (passed < total) {
699
+ throw new Error(`Suite incomplete: ${passed}/${total} passed. See summary above.`);
700
+ }
701
+ </cell>
702
+
703
+ </frqtl-notebook>