@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,471 @@
1
+ <frqtl-notebook version="1" title="Solving Polynomial Systems — fractional roots, GCD, and shared-factor detection">
2
+
3
+ <cell type="markdown">
4
+ # Solving Polynomial Systems in EGPT Canonical Space
5
+
6
+ This notebook ports `SolvePolynomialSystemTest.js` — the canonical test suite for
7
+ `SolvePolynomialSystem.js`.
8
+
9
+ The library operates entirely in **rational (PPF) arithmetic** via `EGPTReal` and
10
+ `EGPTPolynomial`. No floating-point, no approximate GCD — every root, every remainder,
11
+ every shared factor is detected to the last bit.
12
+
13
+ Four stages are covered:
14
+
15
+ | Stage | What is tested |
16
+ |-------|---------------|
17
+ | 1 | Single polynomial with fractional coefficients — root evaluation and exact division |
18
+ | 2 | System of two polynomials — GCD finds the shared root |
19
+ | 3 | Minimal-polynomial elimination — express √2 and √3 by integer-coefficient polynomials |
20
+ | 4 | `EGPTPolynomial.gcd` / `shareCommonFactor` — the polynomial-chain API |
21
+
22
+ Plus a set of **edge cases** covering zero polynomials, roots at zero, repeated roots,
23
+ large rational denominators, negative-rational canonicalization, and algebraic laws.
24
+
25
+ *(All arithmetic goes through `caps.math`. No URL imports.)*
26
+ </cell>
27
+
28
+ <cell type="markdown">
29
+ ## Setup — helpers and test harness
30
+
31
+ `EGPTReal.fromBigInt` / `EGPTReal.fromRational` are the two constructors used throughout.
32
+ The SDK also exports standalone `polyGCD` and `monicNormalize` (the Euclidean GCD walk and
33
+ monic normalization) — these replace the local helpers from the source file.
34
+
35
+ The `suite` binding is consumed by every phase cell.
36
+ </cell>
37
+
38
+ <cell type="js" lane="math" id="setup" out="suite">
39
+ const { math } = caps;
40
+ const { EGPTReal, EGPTPolynomial, polyGCD, monicNormalize } = math;
41
+
42
+ const ZERO = EGPTReal.fromBigInt(0n);
43
+ const ONE = EGPTReal.fromBigInt(1n);
44
+
45
+ // Convenience constructors
46
+ const frac = (n, d) => EGPTReal.fromRational(BigInt(n), BigInt(d));
47
+ const intN = (n) => EGPTReal.fromBigInt(BigInt(n));
48
+ const isZero = (en) => en.equals(ZERO);
49
+
50
+ // Minimal test harness
51
+ let passed = 0;
52
+ let failed = 0;
53
+ const failures = [];
54
+
55
+ function test(name, fn) {
56
+ try {
57
+ fn();
58
+ passed++;
59
+ console.log(' ok — ' + name);
60
+ } catch (err) {
61
+ failed++;
62
+ failures.push({ name, err });
63
+ console.log(' FAIL — ' + name);
64
+ console.log(' ' + err.message);
65
+ }
66
+ }
67
+
68
+ function assert(cond, msg) {
69
+ if (!cond) throw new Error(msg || 'assertion failed');
70
+ }
71
+
72
+ function assertEqPoly(actual, expected, msg) {
73
+ if (!EGPTPolynomial.equals(actual, expected)) {
74
+ const show = (p) => '[' + p.map(c => c.breakSymbolicToString()).join(', ') + ']';
75
+ throw new Error((msg || 'polynomial mismatch') + '\n actual = ' + show(actual) + '\n expected = ' + show(expected));
76
+ }
77
+ }
78
+
79
+ function assertZero(en, msg) {
80
+ if (!isZero(en)) throw new Error((msg || 'expected zero') + ': got ' + en.breakSymbolicToString());
81
+ }
82
+
83
+ // `polyGCD` and `monicNormalize` come from the SDK — no local re-implementation needed.
84
+ // They are identical to the local helpers in the source file.
85
+
86
+ return { suite: { test, assert, assertEqPoly, assertZero, frac, intN, ZERO, ONE, isZero, polyGCD, monicNormalize, getResults: () => ({ passed, failed, failures }) } };
87
+ </cell>
88
+
89
+ <cell type="markdown">
90
+ ## Stage 1 — Single polynomial with fractional coefficients
91
+
92
+ Consider `f(x) = x² − (7/6)x + 1/3`. In coefficient-vector form (constant term first):
93
+
94
+ ```
95
+ f = [1/3, −7/6, 1]
96
+ ```
97
+
98
+ Its roots are `x = 1/2` and `x = 2/3` — both rational, discoverable by exact evaluation and exact polynomial division with zero remainder.
99
+ </cell>
100
+
101
+ <cell type="js" lane="math" id="stage1" in="suite" out="s1">
102
+ const { math } = caps;
103
+ const { EGPTPolynomial } = math;
104
+ const { test, assert, assertEqPoly, assertZero, frac, intN, ZERO, ONE, isZero } = inputs.suite;
105
+
106
+ console.log('\n[Stage 1] single polynomial, fractional coefficients');
107
+
108
+ // f(x) = x² − (7/6)x + 1/3 (coefficients stored constant-term first)
109
+ const f = [ frac(1, 3), frac(-7, 6), ONE ];
110
+
111
+ test('f(1/2) is exactly zero', () => {
112
+ assertZero(EGPTPolynomial.evaluateAt(f, frac(1, 2)), 'f(1/2)');
113
+ });
114
+
115
+ test('f(2/3) is exactly zero', () => {
116
+ assertZero(EGPTPolynomial.evaluateAt(f, frac(2, 3)), 'f(2/3)');
117
+ });
118
+
119
+ test('f / (x − 1/2) has zero remainder and leaves the other root', () => {
120
+ const { quotient, remainder } = EGPTPolynomial.divide(f, [frac(-1, 2), ONE]);
121
+ assert(remainder.every(isZero), 'non-zero remainder');
122
+ assertZero(EGPTPolynomial.evaluateAt(quotient, frac(2, 3)), 'quotient(2/3)');
123
+ });
124
+
125
+ test('f / (x − 1/2) quotient is exactly x − 2/3', () => {
126
+ const { quotient } = EGPTPolynomial.divide(f, [frac(-1, 2), ONE]);
127
+ assertEqPoly(quotient, [frac(-2, 3), ONE], 'quotient should be x − 2/3');
128
+ });
129
+
130
+ test('f(1) equals the sum of coefficients (= 1/3 − 7/6 + 1 = 1/6)', () => {
131
+ const v = EGPTPolynomial.evaluateAt(f, ONE);
132
+ assert(v.equals(frac(1, 6)), 'got ' + v.breakSymbolicToString() + ', expected 1/6');
133
+ });
134
+
135
+ test('f(0) equals the constant term 1/3', () => {
136
+ const v = EGPTPolynomial.evaluateAt(f, ZERO);
137
+ assert(v.equals(frac(1, 3)), 'got ' + v.breakSymbolicToString() + ', expected 1/3');
138
+ });
139
+
140
+ return { s1: inputs.suite.getResults() };
141
+ </cell>
142
+
143
+ <cell type="markdown">
144
+ ## Stage 2 — System of polynomials: polynomial GCD finds the shared root
145
+
146
+ Two polynomials sharing exactly one root:
147
+
148
+ ```
149
+ f1(x) = x² − (7/6)x + 1/3 roots: 1/2, 2/3
150
+ f2(x) = x² − (5/6)x + 1/6 roots: 1/2, 1/3
151
+ ```
152
+
153
+ The Euclidean algorithm on polynomial remainder sequences (`polyGCD`) isolates the common
154
+ factor `(x − 1/2)` in exact rational arithmetic — no numeric threshold, no tolerance.
155
+
156
+ Additional GCD identities are checked: `gcd(f, f) = f`, coprime polynomials, divisor-of
157
+ relationships, and a three-polynomial chained GCD.
158
+ </cell>
159
+
160
+ <cell type="js" lane="math" id="stage2" in="suite" out="s2">
161
+ const { math } = caps;
162
+ const { EGPTPolynomial } = math;
163
+ const { test, assert, assertEqPoly, assertZero, frac, intN, ONE, isZero, polyGCD, monicNormalize } = inputs.suite;
164
+
165
+ console.log('\n[Stage 2] system of polynomials via polynomial GCD');
166
+
167
+ const f1 = [ frac(1, 3), frac(-7, 6), ONE ]; // roots 1/2, 2/3
168
+ const f2 = [ frac(1, 6), frac(-5, 6), ONE ]; // roots 1/2, 1/3
169
+
170
+ test('gcd(f1, f2) is monic x − 1/2', () => {
171
+ const g = monicNormalize(polyGCD(f1, f2));
172
+ assertEqPoly(g, [frac(-1, 2), ONE], 'gcd should be x − 1/2');
173
+ });
174
+
175
+ test('gcd vanishes at the shared root 1/2', () => {
176
+ const g = monicNormalize(polyGCD(f1, f2));
177
+ assertZero(EGPTPolynomial.evaluateAt(g, frac(1, 2)));
178
+ });
179
+
180
+ test('gcd(f, f) = f (monic)', () => {
181
+ const g = monicNormalize(polyGCD(f1, f1));
182
+ assertEqPoly(g, f1, 'gcd(f1, f1) should equal f1');
183
+ });
184
+
185
+ test('coprime polynomials have constant gcd (degree 0, nonzero)', () => {
186
+ // (x − 1) and (x − 2) share no root
187
+ const a = [intN(-1), ONE];
188
+ const b = [intN(-2), ONE];
189
+ const g = polyGCD(a, b);
190
+ assert(EGPTPolynomial.degree(g) === 0, 'coprime gcd should be degree 0, got ' + EGPTPolynomial.degree(g));
191
+ assert(!isZero(g[0]), 'coprime gcd constant must be nonzero');
192
+ const gm = monicNormalize(g);
193
+ assertEqPoly(gm, [ONE], 'monic coprime gcd should be [1]');
194
+ });
195
+
196
+ test('when f2 divides f1, gcd(f1, f2) = f2 (monic)', () => {
197
+ // f1 = (x−1)(x−2) = x² − 3x + 2, f2 = (x−1)
198
+ const a = [intN(2), intN(-3), ONE];
199
+ const b = [intN(-1), ONE];
200
+ const g = monicNormalize(polyGCD(a, b));
201
+ assertEqPoly(g, b, 'gcd should equal the divisor factor');
202
+ });
203
+
204
+ test('two shared roots produce a degree-2 gcd', () => {
205
+ // f1 = (x−1)(x−2)(x−3), f2 = (x−1)(x−2)(x−4)
206
+ // Shared: (x−1)(x−2) = x² − 3x + 2
207
+ const p1 = [intN(-6), intN(11), intN(-6), ONE];
208
+ const p2 = [intN(-8), intN(14), intN(-7), ONE];
209
+ const g = monicNormalize(polyGCD(p1, p2));
210
+ assertEqPoly(g, [intN(2), intN(-3), ONE], 'gcd should be x² − 3x + 2');
211
+ });
212
+
213
+ test('three-polynomial system: chained gcd finds the common root', () => {
214
+ // All share (x − 1): (x−1)(x−2), (x−1)(x−3), (x−1)(x−5)
215
+ const a = [intN(2), intN(-3), ONE];
216
+ const b = [intN(3), intN(-4), ONE];
217
+ const c = [intN(5), intN(-6), ONE];
218
+ const g = monicNormalize(polyGCD(polyGCD(a, b), c));
219
+ assertEqPoly(g, [intN(-1), ONE], 'chained gcd should be x − 1');
220
+ });
221
+
222
+ return { s2: inputs.suite.getResults() };
223
+ </cell>
224
+
225
+ <cell type="markdown">
226
+ ## Stage 3 — Minimal-polynomial elimination for irrationals
227
+
228
+ To work with `x² − √k · x − 1 = 0` (which has irrational coefficients), we eliminate `√k`
229
+ by conjugation. Multiplying `(x² − 1 − √k · x)(x² − 1 + √k · x)` gives:
230
+
231
+ ```
232
+ p(x) = (x² − 1)² − k · x²
233
+ ```
234
+
235
+ This is a degree-4 polynomial in `x` with **integer coefficients only** — the irrationality
236
+ is gone. For `k = 2`: `x⁴ − 4x² + 1`. For `k = 3`: `x⁴ − 5x² + 1`.
237
+
238
+ All arithmetic uses `EGPTPolynomial.multiply` and `EGPTPolynomial.subtract` on integer `EGPTReal` coefficients.
239
+ </cell>
240
+
241
+ <cell type="js" lane="math" id="stage3" in="suite" out="s3">
242
+ const { math } = caps;
243
+ const { EGPTPolynomial } = math;
244
+ const { test, assertEqPoly, intN, ZERO, ONE } = inputs.suite;
245
+
246
+ console.log('\n[Stage 3] minimal-polynomial elimination of irrationals');
247
+
248
+ function eliminateSquareRoot(kBigInt) {
249
+ // For g(x) = x² − √k · x − 1 with α² = k, the elimination yields
250
+ // p(x) = (x² − 1)² − k·x²
251
+ // which is a polynomial with integer coefficients in x alone.
252
+ const u = [intN(-1), ZERO, ONE]; // x² − 1
253
+ const u2 = EGPTPolynomial.multiply(u, u); // (x² − 1)²
254
+ const kxSq = [ZERO, ZERO, EGPTReal.fromBigInt(kBigInt)];
255
+ return EGPTPolynomial.subtract(u2, kxSq);
256
+ }
257
+
258
+ // EGPTReal must be in scope for eliminateSquareRoot
259
+ const { EGPTReal } = math;
260
+
261
+ test('√2 elimination yields x⁴ − 4x² + 1', () => {
262
+ const p = eliminateSquareRoot(2n);
263
+ assertEqPoly(p, [ONE, ZERO, intN(-4), ZERO, ONE], 'minimal poly for √2 case');
264
+ });
265
+
266
+ test('√3 elimination yields x⁴ − 5x² + 1', () => {
267
+ const p = eliminateSquareRoot(3n);
268
+ assertEqPoly(p, [ONE, ZERO, intN(-5), ZERO, ONE], 'minimal poly for √3 case');
269
+ });
270
+
271
+ test('minimal polynomial has no fractional coefficients (structural)', () => {
272
+ const p = eliminateSquareRoot(2n);
273
+ // Every coefficient must equal its integer rebuild — confirms no hidden fractions.
274
+ const rebuilt = [intN(1), intN(0), intN(-4), intN(0), intN(1)];
275
+ assertEqPoly(p, rebuilt, 'integer rebuild must match');
276
+ });
277
+
278
+ return { s3: inputs.suite.getResults() };
279
+ </cell>
280
+
281
+ <cell type="markdown">
282
+ ## Edge cases — structural integrity of canonical-space operations
283
+
284
+ These tests cover the boundary conditions flagged during design:
285
+
286
+ - Subtraction `a − a` collapses to the zero polynomial
287
+ - `evaluateAt(p, 0)` returns the constant term
288
+ - A polynomial with a root at zero (`x`) evaluates to zero at zero and to `c` at `c`
289
+ - Repeated roots: `(x − 2)²` vanishes at 2 and divides cleanly by `(x − 2)`
290
+ - Large rational denominators (denominator = 10¹⁸) — no floating-point loss
291
+ - Negative-rational canonicalization: `fromRational(-1, 2)` equals `fromRational(1, -2)`
292
+ - Distributive law: `a·(b + c) = a·b + a·c`
293
+ - Multiply by the zero polynomial collapses to `[0]`
294
+ - Addition commutes: `a + b = b + a`
295
+ - Degree is consistent after arithmetic
296
+ </cell>
297
+
298
+ <cell type="js" lane="math" id="edge-cases" in="suite" out="ec">
299
+ const { math } = caps;
300
+ const { EGPTReal, EGPTPolynomial } = math;
301
+ const { test, assert, assertEqPoly, assertZero, frac, intN, ZERO, ONE, isZero } = inputs.suite;
302
+
303
+ console.log('\n[Edge cases] structural integrity of canonical-space ops');
304
+
305
+ test('a − a collapses to the zero polynomial', () => {
306
+ const a = [frac(1, 3), frac(-7, 6), ONE];
307
+ const r = EGPTPolynomial.subtract(a, a);
308
+ assert(r.every(isZero), 'subtract should be all-zero, got ' + r.map(x => x.breakSymbolicToString()));
309
+ });
310
+
311
+ test('evaluate at 0 returns the constant term (even for higher-degree poly)', () => {
312
+ const p = [intN(7), intN(-3), intN(5), intN(-9)]; // 7 − 3x + 5x² − 9x³
313
+ const v = EGPTPolynomial.evaluateAt(p, ZERO);
314
+ assert(v.equals(intN(7)), 'got ' + v.breakSymbolicToString() + ', expected 7');
315
+ });
316
+
317
+ test('root at zero: x vanishes at 0 and equals c at c', () => {
318
+ const x = [ZERO, ONE]; // polynomial = x
319
+ assertZero(EGPTPolynomial.evaluateAt(x, ZERO));
320
+ const c = EGPTPolynomial.evaluateAt(x, frac(5, 7));
321
+ assert(c.equals(frac(5, 7)), 'got ' + c.breakSymbolicToString() + ', expected 5/7');
322
+ });
323
+
324
+ test('repeated root: (x − 2)² vanishes at 2 and divides cleanly by (x − 2)', () => {
325
+ // (x − 2)² = x² − 4x + 4
326
+ const p = [intN(4), intN(-4), ONE];
327
+ assertZero(EGPTPolynomial.evaluateAt(p, intN(2)), '(x−2)² at x=2');
328
+ const { quotient, remainder } = EGPTPolynomial.divide(p, [intN(-2), ONE]);
329
+ assert(remainder.every(isZero), 'remainder should be zero');
330
+ assertEqPoly(quotient, [intN(-2), ONE], 'quotient should be (x − 2)');
331
+ });
332
+
333
+ test('large rational denominator: x − 1/10^18 vanishes at 1/10^18', () => {
334
+ const tiny = EGPTReal.fromRational(1n, 10n ** 18n);
335
+ const p = [EGPTReal.fromRational(-1n, 10n ** 18n), ONE];
336
+ assertZero(EGPTPolynomial.evaluateAt(p, tiny), 'large-denom root');
337
+ // At 2 * tiny the value should be exactly tiny — not floating-point zero.
338
+ const two_tiny = EGPTReal.fromRational(2n, 10n ** 18n);
339
+ const v = EGPTPolynomial.evaluateAt(p, two_tiny);
340
+ assert(v.equals(tiny), 'got ' + v.breakSymbolicToString() + ', expected ' + tiny.breakSymbolicToString());
341
+ });
342
+
343
+ test('negative rational canonicalization: -1/2 equals 1/-2', () => {
344
+ const a = EGPTReal.fromRational(-1n, 2n);
345
+ const b = EGPTReal.fromRational(1n, -2n);
346
+ assert(a.equals(b), 'fromRational(-1,2) should equal fromRational(1,-2): ' + a.breakSymbolicToString() + ' vs ' + b.breakSymbolicToString());
347
+ });
348
+
349
+ test('distributivity: a·(b + c) = a·b + a·c', () => {
350
+ const a = [ONE, ONE]; // x + 1
351
+ const b = [intN(2), ONE]; // x + 2
352
+ const c = [intN(3), ONE]; // x + 3
353
+ const lhs = EGPTPolynomial.multiply(a, EGPTPolynomial.add(b, c));
354
+ const rhs = EGPTPolynomial.add(
355
+ EGPTPolynomial.multiply(a, b),
356
+ EGPTPolynomial.multiply(a, c)
357
+ );
358
+ assertEqPoly(lhs, rhs, 'distributive law broken');
359
+ });
360
+
361
+ test('multiply by zero polynomial collapses to [0]', () => {
362
+ const a = [frac(1, 3), frac(-7, 6), ONE];
363
+ const z = [ZERO];
364
+ const r = EGPTPolynomial.multiply(a, z);
365
+ assert(r.every(isZero), 'zero-poly multiply should be all zero');
366
+ });
367
+
368
+ test('add commutes: a + b = b + a', () => {
369
+ const a = [frac(1, 3), frac(-7, 6), ONE];
370
+ const b = [frac(1, 6), frac(-5, 6), ONE];
371
+ assertEqPoly(EGPTPolynomial.add(a, b), EGPTPolynomial.add(b, a));
372
+ });
373
+
374
+ test('degree is consistent after arithmetic', () => {
375
+ const a = [intN(1), intN(2), intN(3)]; // degree 2
376
+ const b = [intN(4), intN(5)]; // degree 1
377
+ const prod = EGPTPolynomial.multiply(a, b);
378
+ assert(EGPTPolynomial.degree(prod) === 3, 'expected degree 3, got ' + EGPTPolynomial.degree(prod));
379
+ const diff = EGPTPolynomial.subtract(a, a);
380
+ assert(EGPTPolynomial.degree(diff) === 0, 'expected degree 0 (zero poly), got ' + EGPTPolynomial.degree(diff));
381
+ });
382
+
383
+ return { ec: inputs.suite.getResults() };
384
+ </cell>
385
+
386
+ <cell type="markdown">
387
+ ## Stage 4 — Polynomial-chain shared-factor detection
388
+
389
+ `EGPTPolynomial.gcd` and `EGPTPolynomial.shareCommonFactor` expose the GCD walk as a
390
+ first-class class method rather than a standalone function. This stage verifies the API
391
+ directly.
392
+
393
+ Note: the Vandermonde / Toeplitz / Sylvester matrix-form demonstrations that appeared in an
394
+ earlier architecture have been retired. The polynomial-chain primitives (`gcd`,
395
+ `shareCommonFactor`, `multiply`, `evaluateAt`) now cover every operation those matrix forms
396
+ once demonstrated.
397
+ </cell>
398
+
399
+ <cell type="js" lane="math" id="stage4" in="suite" out="s4">
400
+ const { math } = caps;
401
+ const { EGPTPolynomial } = math;
402
+ const { test, assert, assertEqPoly, frac, intN, ONE, monicNormalize } = inputs.suite;
403
+
404
+ console.log('\n[Stage 4] polynomial-chain shared-factor detection');
405
+
406
+ test('gcd of coprime (x−1, x−2) has degree 0 — no shared factor', () => {
407
+ const a = [intN(-1), ONE]; // x − 1
408
+ const b = [intN(-2), ONE]; // x − 2
409
+ const g = EGPTPolynomial.gcd(a, b);
410
+ assert(EGPTPolynomial.degree(g) === 0, 'coprime gcd must be degree 0, got ' + EGPTPolynomial.degree(g));
411
+ assert(!EGPTPolynomial.shareCommonFactor(a, b),
412
+ 'shareCommonFactor should be false for coprime polynomials');
413
+ });
414
+
415
+ test('gcd of (x−1) and (x−1)(x−2) is (x − 1)', () => {
416
+ const a = [intN(-1), ONE]; // x − 1
417
+ const b = [intN(2), intN(-3), ONE]; // (x−1)(x−2)
418
+ assert(EGPTPolynomial.shareCommonFactor(a, b),
419
+ 'shareCommonFactor should be true when there is a common factor');
420
+ const g = monicNormalize(EGPTPolynomial.gcd(a, b));
421
+ assertEqPoly(g, [intN(-1), ONE], 'common factor should be (x − 1)');
422
+ });
423
+
424
+ test('gcd of the stage-2 system (f1, f2) is (x − 1/2)', () => {
425
+ const f1 = [ frac(1, 3), frac(-7, 6), ONE ];
426
+ const f2 = [ frac(1, 6), frac(-5, 6), ONE ];
427
+ assert(EGPTPolynomial.shareCommonFactor(f1, f2),
428
+ 'f1 and f2 share the root x = 1/2');
429
+ const g = monicNormalize(EGPTPolynomial.gcd(f1, f2));
430
+ assertEqPoly(g, [frac(-1, 2), ONE], 'gcd should be x − 1/2');
431
+ });
432
+
433
+ test('two quadratics with one shared root: gcd has positive degree', () => {
434
+ // f1 = (x−1)(x−2), f2 = (x−1)(x−3) → one shared root
435
+ const f1 = [intN(2), intN(-3), ONE];
436
+ const f2 = [intN(3), intN(-4), ONE];
437
+ assert(EGPTPolynomial.shareCommonFactor(f1, f2), 'shared-root predicate');
438
+ // Self: gcd(f, f) = f (positive degree)
439
+ assert(EGPTPolynomial.shareCommonFactor(f1, f1),
440
+ 'self-gcd: f shares a factor with itself');
441
+ });
442
+
443
+ return { s4: inputs.suite.getResults() };
444
+ </cell>
445
+
446
+ <cell type="markdown">
447
+ ## Summary
448
+
449
+ Final tally across all stages and edge cases.
450
+ </cell>
451
+
452
+ <cell type="js" lane="math" id="summary" in="s4">
453
+ const snap = inputs.s4;
454
+ const { passed, failed, failures } = snap;
455
+ const total = passed + failed;
456
+
457
+ console.log('');
458
+ console.log('='.repeat(60));
459
+ console.log('Results: ' + passed + ' passed, ' + failed + ' failed (total: ' + total + ')');
460
+ if (failures.length > 0) {
461
+ console.log('\nFailures:');
462
+ for (const { name, err } of failures) {
463
+ console.log(' - ' + name + ': ' + err.message);
464
+ }
465
+ }
466
+ console.log('='.repeat(60));
467
+
468
+ if (failed > 0) throw new Error('[SolvePolynomialSystemTest] ' + failed + ' test(s) failed');
469
+ </cell>
470
+
471
+ </frqtl-notebook>
@@ -0,0 +1,112 @@
1
+ <frqtl-notebook version="1" title="Scaled Vectors — Exact Rational Arithmetic with EGPTReal">
2
+
3
+ <cell type="markdown">
4
+ # Scaled Vectors — Exact Rational Arithmetic with EGPTReal
5
+
6
+ **What is EGPTReal?**
7
+
8
+ In IEEE-754 floating-point, `Math.sqrt(0.5)` returns a 64-bit approximation. The exact result — `1/√2` — cannot be represented: floating-point rounds, accumulates error across operations, and ultimately loses the identity that `(√½)² = ½` to rounding.
9
+
10
+ `EGPTReal` works differently. A value lives in *compressed information space*: its prime-power factorization is stored symbolically. Multiplication is vector addition in log-space; square roots halve the exponents. The identity `(√½)² = ½` holds **exactly** — not approximately — because no floating-point boundary is ever crossed inside the computation.
11
+
12
+ This notebook demonstrates the three arithmetic operations from `sdk/egpt-math-sdk/src/examples/scaled-vectors.js`, one concept at a time, framed so a first-time reader can see what each step does and why it stays exact.
13
+
14
+ Every cell reaches its math through the single injected `math` builtin — no imports, no URLs.
15
+ </cell>
16
+
17
+ <cell type="js" lane="math" id="backend">
18
+ // Report the active math backend. The label is DERIVED — never hardcoded.
19
+ const { math, display } = caps;
20
+ const backend = math.activeMathBackend;
21
+ display(`Active math backend (derived from SDK registry): ${backend}`);
22
+ </cell>
23
+
24
+ <cell type="markdown">
25
+ ## 1. Constructing a rational and computing its square root
26
+
27
+ `EGPTReal.fromRational(numerator, denominator)` lifts a BigInt fraction into compressed information space. The number ½ becomes a symbolic object whose prime factorization carries the exact value `2⁻¹`.
28
+
29
+ `EGPTMath.sqrt(x)` halves all exponents in that factorization. For `√(½) = √(2⁻¹) = 2⁻¹/²`, the exponent on prime 2 moves from `−1` to `−½`. The result is a new `EGPTReal` representing the exact algebraic value `1/√2` — no decimal approximation involved.
30
+
31
+ `toMathString()` renders the internal representation as a human-readable expression.
32
+ </cell>
33
+
34
+ <cell type="js" lane="math" id="sqrt-half" out="sqrtHalf">
35
+ // Lift ½ into EGPTReal and compute its exact square root.
36
+ const { EGPTReal, EGPTMath } = caps.math;
37
+ const { display } = caps; // display is on caps, not caps.math
38
+
39
+ // EGPTReal.fromRational(1n, 2n) constructs the exact rational 1/2
40
+ // as a symbolic prime-power vector: {prime: 2, exponent: -1}.
41
+ const half = EGPTReal.fromRational(1n, 2n);
42
+
43
+ // EGPTMath.sqrt halves every exponent: 2^(-1) → 2^(-1/2).
44
+ // Result is the exact algebraic value √(1/2) = 1/√2.
45
+ const sqrtHalf = EGPTMath.sqrt(half);
46
+
47
+ display(`half = ${half.toMathString()}`);
48
+ display(`√half = ${sqrtHalf.toMathString()}`);
49
+
50
+ return { sqrtHalf };
51
+ </cell>
52
+
53
+ <cell type="markdown">
54
+ ## 2. Squaring back — verifying the identity (√½)² = ½
55
+
56
+ `EGPTMath.multiply(a, b)` adds the exponent vectors of `a` and `b`. Multiplying `√(½)` by itself adds `2^(−½)` to `2^(−½)`, yielding `2^(−1)` — which is exactly ½. No rounding, no approximation.
57
+
58
+ This is the key correctness check: an exact symbolic system must close the round-trip `x = sqrt(y)` → `x * x == y`.
59
+ </cell>
60
+
61
+ <cell type="js" lane="math" id="square-back" in="sqrtHalf" out="squaredBack">
62
+ // Multiply sqrtHalf by itself. In log-space this adds the exponents:
63
+ // (-1/2) + (-1/2) = -1 → the result is 2^(-1) = 1/2.
64
+ // The identity (√½)² = ½ holds exactly — no floating-point rounding.
65
+ const { EGPTMath } = caps.math;
66
+ const { display } = caps; // display is on caps, not caps.math
67
+ const sqrtHalf = inputs.sqrtHalf;
68
+
69
+ const squaredBack = EGPTMath.multiply(sqrtHalf, sqrtHalf);
70
+ display(`(√½)² = ${squaredBack.toMathString()}`);
71
+
72
+ return { squaredBack };
73
+ </cell>
74
+
75
+ <cell type="markdown">
76
+ ## 3. Scaling by an integer — exact scalar multiplication
77
+
78
+ `EGPTReal.fromBigInt(2n)` constructs the integer 2 as a prime-power vector `{prime: 2, exponent: 1}`. Multiplying `√(½)` by `2` adds that `+1` exponent to the `−½` exponent on prime 2, yielding `2^(+½) = √2`.
79
+
80
+ The result `√½ × 2 = 2/√2 = √2` is exact. This demonstrates that scaling an irrational by an integer stays in the same symbolic space — no boundary crossing, no precision loss.
81
+ </cell>
82
+
83
+ <cell type="js" lane="math" id="scaled-by-two" in="sqrtHalf">
84
+ // Scale √½ by the integer 2.
85
+ // In log-space: exponent of 2 moves from -1/2 to -1/2 + 1 = +1/2.
86
+ // Result: 2^(1/2) = √2.
87
+ const { EGPTReal, EGPTMath } = caps.math;
88
+ const { display } = caps; // display is on caps, not caps.math
89
+ const sqrtHalf = inputs.sqrtHalf;
90
+
91
+ const two = EGPTReal.fromBigInt(2n);
92
+ const scaledByTwo = EGPTMath.multiply(sqrtHalf, two);
93
+
94
+ display(`2 × √½ = ${scaledByTwo.toMathString()}`);
95
+ display('(Exact algebraic value: √2)');
96
+ </cell>
97
+
98
+ <cell type="markdown">
99
+ ## Summary
100
+
101
+ The three values computed here match the `scaled-vectors` example exactly:
102
+
103
+ | Expression | Exact value | What EGPTMath does |
104
+ |---|---|---|
105
+ | `√(½)` | `2^(−½)` | halves the exponent on prime 2 |
106
+ | `(√½)²` | `2^(−1) = ½` | adds exponents: −½ + −½ = −1 |
107
+ | `2 × √½` | `2^(+½) = √2` | adds exponents: +1 + −½ = +½ |
108
+
109
+ Every step stays inside the prime-power symbolic representation. Floating-point arithmetic is never involved. The rounding errors that would accumulate in IEEE-754 simply do not exist here.
110
+ </cell>
111
+
112
+ </frqtl-notebook>