@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.
- package/README.md +224 -0
- package/dist/egpt-math-sdk.browser.js +5 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +985 -0
- package/dist/notebooks/arithmetic-basics.html +166 -0
- package/dist/notebooks/complex-twiddle.html +148 -0
- package/dist/notebooks/double-slit-rosetta-qft.html +154 -0
- package/dist/notebooks/egpt-fft-test.html +202 -0
- package/dist/notebooks/egpt-matrix-test.html +241 -0
- package/dist/notebooks/egpt-polynomial-test.html +703 -0
- package/dist/notebooks/egpt-prime-composite-test.html +561 -0
- package/dist/notebooks/egpt-test-suite.html +1387 -0
- package/dist/notebooks/egpt-topology-test.html +410 -0
- package/dist/notebooks/factorization-basics.html +131 -0
- package/dist/notebooks/fft.html +155 -0
- package/dist/notebooks/frqtl-qft-benchmark.html +207 -0
- package/dist/notebooks/gallery-atomic-model.html +51 -0
- package/dist/notebooks/gallery-big-bang.html +62 -0
- package/dist/notebooks/gallery-blackbody.html +52 -0
- package/dist/notebooks/gallery-circuit-sat.html +104 -0
- package/dist/notebooks/gallery-collision-matrix-3d.html +51 -0
- package/dist/notebooks/gallery-double-slit.html +53 -0
- package/dist/notebooks/gallery-gun-chamber.html +62 -0
- package/dist/notebooks/gallery-particle-walk-3d.html +53 -0
- package/dist/notebooks/gallery-wave-interference.html +52 -0
- package/dist/notebooks/getting-started-hello-frqtl.html +53 -0
- package/dist/notebooks/iso-canonical-chain.html +203 -0
- package/dist/notebooks/iso-entropy-log.html +127 -0
- package/dist/notebooks/iso-fft-polynomial.html +136 -0
- package/dist/notebooks/iso-matrix-four-views.html +131 -0
- package/dist/notebooks/iso-number-theory-four-views.html +99 -0
- package/dist/notebooks/iso-pi-log-fraction-loop.html +140 -0
- package/dist/notebooks/matrix.html +202 -0
- package/dist/notebooks/notebooks.json +240 -0
- package/dist/notebooks/polynomials.html +201 -0
- package/dist/notebooks/prime-composite.html +268 -0
- package/dist/notebooks/rational-core.html +179 -0
- package/dist/notebooks/reference-egpt-fft-test.html +187 -0
- package/dist/notebooks/reference-order-finder-test.html +196 -0
- package/dist/notebooks/reference-prime-atom-polynomial-test.html +542 -0
- package/dist/notebooks/reference-solve-polynomial-system-test.html +471 -0
- package/dist/notebooks/scaled-vectors.html +112 -0
- package/dist/notebooks/stats.html +206 -0
- package/dist/notebooks/transcendentals.html +195 -0
- package/dist/notebooks/view-vendored-d3.html +78 -0
- package/dist/vendor/d3-array/src/array.js +4 -0
- package/dist/vendor/d3-array/src/ascending.js +3 -0
- package/dist/vendor/d3-array/src/bin.js +125 -0
- package/dist/vendor/d3-array/src/bisect.js +9 -0
- package/dist/vendor/d3-array/src/bisector.js +56 -0
- package/dist/vendor/d3-array/src/blur.js +115 -0
- package/dist/vendor/d3-array/src/constant.js +3 -0
- package/dist/vendor/d3-array/src/count.js +18 -0
- package/dist/vendor/d3-array/src/cross.js +33 -0
- package/dist/vendor/d3-array/src/cumsum.js +6 -0
- package/dist/vendor/d3-array/src/descending.js +7 -0
- package/dist/vendor/d3-array/src/deviation.js +6 -0
- package/dist/vendor/d3-array/src/difference.js +11 -0
- package/dist/vendor/d3-array/src/disjoint.js +15 -0
- package/dist/vendor/d3-array/src/every.js +10 -0
- package/dist/vendor/d3-array/src/extent.js +29 -0
- package/dist/vendor/d3-array/src/filter.js +11 -0
- package/dist/vendor/d3-array/src/fsum.js +69 -0
- package/dist/vendor/d3-array/src/greatest.js +29 -0
- package/dist/vendor/d3-array/src/greatestIndex.js +19 -0
- package/dist/vendor/d3-array/src/group.js +65 -0
- package/dist/vendor/d3-array/src/groupSort.js +10 -0
- package/dist/vendor/d3-array/src/identity.js +3 -0
- package/dist/vendor/d3-array/src/index.js +57 -0
- package/dist/vendor/d3-array/src/intersection.js +19 -0
- package/dist/vendor/d3-array/src/least.js +29 -0
- package/dist/vendor/d3-array/src/leastIndex.js +19 -0
- package/dist/vendor/d3-array/src/map.js +5 -0
- package/dist/vendor/d3-array/src/max.js +20 -0
- package/dist/vendor/d3-array/src/maxIndex.js +22 -0
- package/dist/vendor/d3-array/src/mean.js +19 -0
- package/dist/vendor/d3-array/src/median.js +9 -0
- package/dist/vendor/d3-array/src/merge.js +9 -0
- package/dist/vendor/d3-array/src/min.js +20 -0
- package/dist/vendor/d3-array/src/minIndex.js +22 -0
- package/dist/vendor/d3-array/src/mode.js +28 -0
- package/dist/vendor/d3-array/src/nice.js +18 -0
- package/dist/vendor/d3-array/src/number.js +20 -0
- package/dist/vendor/d3-array/src/pairs.js +15 -0
- package/dist/vendor/d3-array/src/permute.js +3 -0
- package/dist/vendor/d3-array/src/quantile.js +47 -0
- package/dist/vendor/d3-array/src/quickselect.js +53 -0
- package/dist/vendor/d3-array/src/range.js +13 -0
- package/dist/vendor/d3-array/src/rank.js +24 -0
- package/dist/vendor/d3-array/src/reduce.js +14 -0
- package/dist/vendor/d3-array/src/reverse.js +4 -0
- package/dist/vendor/d3-array/src/scan.js +6 -0
- package/dist/vendor/d3-array/src/shuffle.js +13 -0
- package/dist/vendor/d3-array/src/some.js +10 -0
- package/dist/vendor/d3-array/src/sort.js +39 -0
- package/dist/vendor/d3-array/src/subset.js +5 -0
- package/dist/vendor/d3-array/src/sum.js +18 -0
- package/dist/vendor/d3-array/src/superset.js +19 -0
- package/dist/vendor/d3-array/src/threshold/freedmanDiaconis.js +7 -0
- package/dist/vendor/d3-array/src/threshold/scott.js +7 -0
- package/dist/vendor/d3-array/src/threshold/sturges.js +5 -0
- package/dist/vendor/d3-array/src/ticks.js +55 -0
- package/dist/vendor/d3-array/src/transpose.js +15 -0
- package/dist/vendor/d3-array/src/union.js +11 -0
- package/dist/vendor/d3-array/src/variance.js +25 -0
- package/dist/vendor/d3-array/src/zip.js +5 -0
- package/dist/vendor/internmap/src/index.js +61 -0
- package/dist/vendor/manifest.json +11 -0
- package/dist/wasm/egpt_math_sdk_wasm.d.ts +214 -0
- package/dist/wasm/egpt_math_sdk_wasm.js +1120 -0
- package/dist/wasm/egpt_math_sdk_wasm_bg.wasm +0 -0
- package/dist/wasm/egpt_math_sdk_wasm_bg.wasm.d.ts +66 -0
- package/dist/wasm/manifest.json +5 -0
- package/package.json +53 -0
|
@@ -0,0 +1,1387 @@
|
|
|
1
|
+
<frqtl-notebook version="1" title="EGPT Test Suite — Vector/Scalar Paradigm Validation">
|
|
2
|
+
|
|
3
|
+
<cell type="markdown">
|
|
4
|
+
# EGPT Test Suite — Vector/Scalar Paradigm Validation
|
|
5
|
+
|
|
6
|
+
This notebook validates the EGPTReal + EGPTMath architecture: the separation of
|
|
7
|
+
**data containers** (`EGPTReal`) from **algebra engines** (`EGPTMath`, `EGPTranscendental`,
|
|
8
|
+
`EGPTComplex`). It also tests statistical functions (`EGPTStat`, `EGPTStatData`) and
|
|
9
|
+
the phase-based `TwiddleTable` required for exact FFT operations.
|
|
10
|
+
|
|
11
|
+
The core insight behind this architecture:
|
|
12
|
+
|
|
13
|
+
- `EGPTReal` is a **pure vector data container** — it holds a value in PPF (Prime-Power
|
|
14
|
+
Factorization) encoding and provides scalar mutation methods (`scalarAdd`, `scalarMultiply`,
|
|
15
|
+
etc.) that operate on the rational representation.
|
|
16
|
+
- `EGPTMath` is a **pure static algebra engine** — it takes two `EGPTReal` vectors and
|
|
17
|
+
applies operations in Shannon/log space (multiply = add exponent vectors; divide =
|
|
18
|
+
subtract exponent vectors).
|
|
19
|
+
- The **RET Iron Law**: `H(p × q) = H(p) + H(q)`. Multiplying two numbers in normal space
|
|
20
|
+
is the same as adding their entropy vectors in log space. This identity is the central
|
|
21
|
+
invariant verified throughout the suite.
|
|
22
|
+
|
|
23
|
+
Negative numbers, fractional exponents, complex numbers, and irrational (scaled-vector)
|
|
24
|
+
representations are all tested to demonstrate the breadth of the PPF encoding.
|
|
25
|
+
</cell>
|
|
26
|
+
|
|
27
|
+
<cell type="markdown">
|
|
28
|
+
## Setup — Test Harness
|
|
29
|
+
|
|
30
|
+
The `TestFramework` class mirrors the original test runner: each `.test()` call runs a
|
|
31
|
+
function, records pass/fail, and logs the result. Phase cells share this harness via the
|
|
32
|
+
`suite` binding. A final summary cell prints totals and the list of any failures.
|
|
33
|
+
</cell>
|
|
34
|
+
|
|
35
|
+
<cell type="js" lane="math" id="setup" out="suite">
|
|
36
|
+
const { math } = caps;
|
|
37
|
+
const { EGPTReal, EGPTMath, ComplexEGPTReal, EGPTranscendental, EGPTComplex,
|
|
38
|
+
TwiddleTable, EGPTStat, EGPTStatData } = math;
|
|
39
|
+
|
|
40
|
+
class TestFramework {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.tests = [];
|
|
43
|
+
this.categories = {};
|
|
44
|
+
}
|
|
45
|
+
test(description, category, fn) {
|
|
46
|
+
const result = { description, category, passed: false, error: null };
|
|
47
|
+
try {
|
|
48
|
+
result.passed = fn();
|
|
49
|
+
if (result.passed === undefined) result.passed = true;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
result.passed = false;
|
|
52
|
+
result.error = e.message;
|
|
53
|
+
}
|
|
54
|
+
this.tests.push(result);
|
|
55
|
+
if (!this.categories[category]) this.categories[category] = [];
|
|
56
|
+
this.categories[category].push(result);
|
|
57
|
+
const status = result.passed ? "PASS" : "FAIL";
|
|
58
|
+
const errMsg = result.error ? ` (${result.error})` : "";
|
|
59
|
+
console.log(`[${status}] ${description}${errMsg}`);
|
|
60
|
+
}
|
|
61
|
+
printSummary() {
|
|
62
|
+
const total = this.tests.length;
|
|
63
|
+
const passed = this.tests.filter(t => t.passed).length;
|
|
64
|
+
const failed = total - passed;
|
|
65
|
+
console.log("=".repeat(60));
|
|
66
|
+
console.log("TEST SUMMARY");
|
|
67
|
+
console.log("=".repeat(60));
|
|
68
|
+
for (const [cat, catTests] of Object.entries(this.categories)) {
|
|
69
|
+
const p = catTests.filter(t => t.passed).length;
|
|
70
|
+
console.log(` ${cat}: ${p}/${catTests.length} passed`);
|
|
71
|
+
}
|
|
72
|
+
console.log("-".repeat(60));
|
|
73
|
+
console.log(`TOTAL: ${passed}/${total} tests passed`);
|
|
74
|
+
console.log(`SUCCESS RATE: ${((passed / total) * 100).toFixed(1)}%`);
|
|
75
|
+
if (failed > 0) {
|
|
76
|
+
console.log("\nFAILED TESTS:");
|
|
77
|
+
this.tests.filter(t => !t.passed).forEach(t => {
|
|
78
|
+
console.log(` [${t.category}] ${t.description}`);
|
|
79
|
+
if (t.error) console.log(` Error: ${t.error}`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return { total, passed, failed };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const tf = new TestFramework();
|
|
87
|
+
return { suite: { tf, EGPTReal, EGPTMath, ComplexEGPTReal, EGPTranscendental,
|
|
88
|
+
EGPTComplex, TwiddleTable, EGPTStat, EGPTStatData } };
|
|
89
|
+
</cell>
|
|
90
|
+
|
|
91
|
+
<cell type="markdown">
|
|
92
|
+
## Phase 1 — EGPTReal: Vector Data Container
|
|
93
|
+
|
|
94
|
+
`EGPTReal` stores numbers in PPF encoding. These tests verify that integers and rationals
|
|
95
|
+
can be created, cloned, compared for equality, and inspected for integrality — all without
|
|
96
|
+
any algebra engine.
|
|
97
|
+
|
|
98
|
+
`fromBigInt(n)` → PPF of `n`. `fromRational(p, q)` → PPF of `p/q` in lowest terms.
|
|
99
|
+
`_getPPFRationalParts()` extracts the canonical `{numerator, denominator}` BigInt pair.
|
|
100
|
+
</cell>
|
|
101
|
+
|
|
102
|
+
<cell type="js" lane="math" id="phase1" in="suite" out="suite">
|
|
103
|
+
const { tf, EGPTReal } = inputs.suite;
|
|
104
|
+
|
|
105
|
+
console.log("PHASE 1: EGPTReal (Vector Data Container)");
|
|
106
|
+
|
|
107
|
+
tf.test("EGPTReal.fromBigInt creates vector from scalar", "Vector Creation", () => {
|
|
108
|
+
const v = EGPTReal.fromBigInt(42n);
|
|
109
|
+
return v.breakSymbolicToApproximateBigInt() === 42n;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
tf.test("EGPTReal.fromRational creates vector from rational", "Vector Creation", () => {
|
|
113
|
+
const v = EGPTReal.fromRational(3n, 4n);
|
|
114
|
+
const r = v._getPPFRationalParts();
|
|
115
|
+
return r.numerator === 3n && r.denominator === 4n;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
tf.test("Vector clone creates independent copy", "Vector Creation", () => {
|
|
119
|
+
const original = EGPTReal.fromBigInt(10n);
|
|
120
|
+
const clone = original.clone();
|
|
121
|
+
clone.scalarAdd(5n);
|
|
122
|
+
return original.breakSymbolicToApproximateBigInt() === 10n
|
|
123
|
+
&& clone.breakSymbolicToApproximateBigInt() === 15n;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
tf.test("Vector equality works correctly", "Vector Identity", () => {
|
|
127
|
+
const v1 = EGPTReal.fromRational(6n, 8n);
|
|
128
|
+
const v2 = EGPTReal.fromRational(3n, 4n);
|
|
129
|
+
return v1.equals(v2);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
tf.test("Vector isInteger detection works", "Vector Identity", () => {
|
|
133
|
+
const intV = EGPTReal.fromBigInt(42n);
|
|
134
|
+
const fracV = EGPTReal.fromRational(3n, 4n);
|
|
135
|
+
return intV.isInteger() && !fracV.isInteger();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return { suite: inputs.suite };
|
|
139
|
+
</cell>
|
|
140
|
+
|
|
141
|
+
<cell type="markdown">
|
|
142
|
+
## Phase 1.5 — Negative Number Encoding
|
|
143
|
+
|
|
144
|
+
Negative numbers require a special PPF encoding: the absolute value is encoded normally,
|
|
145
|
+
then the exponent `N` is sign-transformed so the representation stays within the PPF
|
|
146
|
+
lattice. The encoding convention: for negative integer with `|x|` having PPF exponent `N`,
|
|
147
|
+
store `N_neg = -N - 2`. This test phase verifies the round-trip from BigInt → PPF → BigInt
|
|
148
|
+
for negative values, including sign normalization for rationals.
|
|
149
|
+
</cell>
|
|
150
|
+
|
|
151
|
+
<cell type="js" lane="math" id="phase15" in="suite" out="suite">
|
|
152
|
+
const { tf, EGPTReal } = inputs.suite;
|
|
153
|
+
|
|
154
|
+
console.log("PHASE 1.5: Negative Number Encoding");
|
|
155
|
+
|
|
156
|
+
tf.test("Negative integer encoding: fromBigInt(-13n)", "Negative Numbers", () => {
|
|
157
|
+
return EGPTReal.fromBigInt(-13n).breakSymbolicToApproximateBigInt() === -13n;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
tf.test("Negative rational: fromRational(-13n, 1n)", "Negative Numbers", () => {
|
|
161
|
+
return EGPTReal.fromRational(-13n, 1n).breakSymbolicToApproximateBigInt() === -13n;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
tf.test("Negative rational: fromRational(-3n, 4n)", "Negative Numbers", () => {
|
|
165
|
+
const r = EGPTReal.fromRational(-3n, 4n)._getPPFRationalParts();
|
|
166
|
+
return r.numerator === -3n && r.denominator === 4n;
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
tf.test("Negative denominator normalization: fromRational(3n, -4n) = -3/4", "Negative Numbers", () => {
|
|
170
|
+
const r = EGPTReal.fromRational(3n, -4n)._getPPFRationalParts();
|
|
171
|
+
return r.numerator === -3n && r.denominator === 4n;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
tf.test("Double negative normalization: fromRational(-3n, -4n) = 3/4", "Negative Numbers", () => {
|
|
175
|
+
const r = EGPTReal.fromRational(-3n, -4n)._getPPFRationalParts();
|
|
176
|
+
return r.numerator === 3n && r.denominator === 4n;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
tf.test("Negative number round-trip: -77n", "Negative Numbers", () => {
|
|
180
|
+
return EGPTReal.fromBigInt(-77n).breakSymbolicToApproximateBigInt() === -77n;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
tf.test("PPF encoding for -13: N transformation stores N_neg = -5", "Negative Numbers", () => {
|
|
184
|
+
const ppf = EGPTReal.fromBigInt(-13n).toPPF();
|
|
185
|
+
return ppf.numerator.N === -5n && ppf.numerator.offset === 5n;
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
tf.test("PPF decoding for negative: fromPPF({N:-5,offset:5}) = -13n", "Negative Numbers", () => {
|
|
189
|
+
const v = EGPTReal.fromPPF({ numerator: { N: -5n, offset: 5n }, denominator: { N: 0n, offset: 0n } });
|
|
190
|
+
return v.breakSymbolicToApproximateBigInt() === -13n;
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
tf.test("Negative number equality: fromBigInt(-42n) === fromRational(-42n, 1n)", "Negative Numbers", () => {
|
|
194
|
+
return EGPTReal.fromBigInt(-42n).equals(EGPTReal.fromRational(-42n, 1n));
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
tf.test("Mixed sign equality: -6/8 equals -3/4", "Negative Numbers", () => {
|
|
198
|
+
return EGPTReal.fromRational(-6n, 8n).equals(EGPTReal.fromRational(-3n, 4n));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
tf.test("Negative toMathString: -42 and -3/4", "Negative Numbers", () => {
|
|
202
|
+
return EGPTReal.fromBigInt(-42n).toMathString() === "-42"
|
|
203
|
+
&& EGPTReal.fromRational(-3n, 4n).toMathString() === "-3/4";
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
tf.test("Negative zero normalization: -0n becomes 0n", "Negative Numbers", () => {
|
|
207
|
+
return EGPTReal.fromBigInt(-0n).breakSymbolicToApproximateBigInt() === 0n;
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
tf.test("Trace verification: -13 PPF encode then decode", "Negative Numbers", () => {
|
|
211
|
+
const v = EGPTReal.fromRational(-13n, 1n);
|
|
212
|
+
const ppf = v.toPPF();
|
|
213
|
+
const stored = ppf.numerator.N === -5n && ppf.numerator.offset === 5n;
|
|
214
|
+
const decoded = v.breakSymbolicToApproximateBigInt() === -13n;
|
|
215
|
+
return stored && decoded;
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return { suite: inputs.suite };
|
|
219
|
+
</cell>
|
|
220
|
+
|
|
221
|
+
<cell type="markdown">
|
|
222
|
+
## Phase 2 — Scalar Operations (Mutable Chaining)
|
|
223
|
+
|
|
224
|
+
`EGPTReal` supports **in-place** scalar mutations via BigInt arguments. These operate
|
|
225
|
+
directly on the underlying rational representation. Each method returns `this` to enable
|
|
226
|
+
fluent chaining. Note that scalar operations require `BigInt` — passing a `Number` throws.
|
|
227
|
+
</cell>
|
|
228
|
+
|
|
229
|
+
<cell type="js" lane="math" id="phase2" in="suite" out="suite">
|
|
230
|
+
const { tf, EGPTReal } = inputs.suite;
|
|
231
|
+
|
|
232
|
+
console.log("PHASE 2: Scalar Operations (Mutable Chaining)");
|
|
233
|
+
|
|
234
|
+
tf.test("scalarAdd modifies in-place and returns this", "Scalar Operations", () => {
|
|
235
|
+
const v = EGPTReal.fromBigInt(10n);
|
|
236
|
+
const r = v.scalarAdd(5n);
|
|
237
|
+
return r === v && v.breakSymbolicToApproximateBigInt() === 15n;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
tf.test("scalarSubtract: 10 - 3 = 7", "Scalar Operations", () => {
|
|
241
|
+
const v = EGPTReal.fromBigInt(10n); v.scalarSubtract(3n);
|
|
242
|
+
return v.breakSymbolicToApproximateBigInt() === 7n;
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
tf.test("scalarMultiply: 6 * 3 = 18", "Scalar Operations", () => {
|
|
246
|
+
const v = EGPTReal.fromBigInt(6n); v.scalarMultiply(3n);
|
|
247
|
+
return v.breakSymbolicToApproximateBigInt() === 18n;
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
tf.test("scalarDivide: 20 / 4 = 5", "Scalar Operations", () => {
|
|
251
|
+
const v = EGPTReal.fromBigInt(20n); v.scalarDivide(4n);
|
|
252
|
+
return v.breakSymbolicToApproximateBigInt() === 5n;
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
tf.test("Fluent chaining: (10+5)*2/5 = 6", "Scalar Operations", () => {
|
|
256
|
+
const v = EGPTReal.fromBigInt(10n);
|
|
257
|
+
v.scalarAdd(5n).scalarMultiply(2n).scalarDivide(5n);
|
|
258
|
+
return v.breakSymbolicToApproximateBigInt() === 6n;
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
tf.test("Scalar operations require BigInt (Number throws)", "Scalar Operations", () => {
|
|
262
|
+
const v = EGPTReal.fromBigInt(10n);
|
|
263
|
+
try { v.scalarAdd(5); return false; }
|
|
264
|
+
catch (e) { return e.message.includes("BigInt"); }
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
return { suite: inputs.suite };
|
|
268
|
+
</cell>
|
|
269
|
+
|
|
270
|
+
<cell type="markdown">
|
|
271
|
+
## Phase 2.5 — Scalar Operations with Negative Numbers
|
|
272
|
+
|
|
273
|
+
Scalar operations must handle sign changes correctly — adding a positive to a negative,
|
|
274
|
+
crossing zero, multiplying two negatives, and dividing by a negative. These tests probe
|
|
275
|
+
the boundary where the PPF sign-encoding has to flip during mutation.
|
|
276
|
+
</cell>
|
|
277
|
+
|
|
278
|
+
<cell type="js" lane="math" id="phase25" in="suite" out="suite">
|
|
279
|
+
const { tf, EGPTReal } = inputs.suite;
|
|
280
|
+
|
|
281
|
+
console.log("PHASE 2.5: Scalar Operations with Negative Numbers");
|
|
282
|
+
|
|
283
|
+
tf.test("-10 + 5 = -5", "Negative Scalar Ops", () => {
|
|
284
|
+
const v = EGPTReal.fromBigInt(-10n); v.scalarAdd(5n);
|
|
285
|
+
return v.breakSymbolicToApproximateBigInt() === -5n;
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
tf.test("-3 + 8 = 5 (negative becomes positive)", "Negative Scalar Ops", () => {
|
|
289
|
+
const v = EGPTReal.fromBigInt(-3n); v.scalarAdd(8n);
|
|
290
|
+
return v.breakSymbolicToApproximateBigInt() === 5n;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
tf.test("-10 - 5 = -15", "Negative Scalar Ops", () => {
|
|
294
|
+
const v = EGPTReal.fromBigInt(-10n); v.scalarSubtract(5n);
|
|
295
|
+
return v.breakSymbolicToApproximateBigInt() === -15n;
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
tf.test("3 - 8 = -5 (positive becomes negative)", "Negative Scalar Ops", () => {
|
|
299
|
+
const v = EGPTReal.fromBigInt(3n); v.scalarSubtract(8n);
|
|
300
|
+
return v.breakSymbolicToApproximateBigInt() === -5n;
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
tf.test("-6 * 3 = -18", "Negative Scalar Ops", () => {
|
|
304
|
+
const v = EGPTReal.fromBigInt(-6n); v.scalarMultiply(3n);
|
|
305
|
+
return v.breakSymbolicToApproximateBigInt() === -18n;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
tf.test("-6 * -3 = 18 (negative × negative = positive)", "Negative Scalar Ops", () => {
|
|
309
|
+
const v = EGPTReal.fromBigInt(-6n); v.scalarMultiply(-3n);
|
|
310
|
+
return v.breakSymbolicToApproximateBigInt() === 18n;
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
tf.test("-20 / 4 = -5", "Negative Scalar Ops", () => {
|
|
314
|
+
const v = EGPTReal.fromBigInt(-20n); v.scalarDivide(4n);
|
|
315
|
+
return v.breakSymbolicToApproximateBigInt() === -5n;
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
tf.test("20 / -4 = -5", "Negative Scalar Ops", () => {
|
|
319
|
+
const v = EGPTReal.fromBigInt(20n); v.scalarDivide(-4n);
|
|
320
|
+
return v.breakSymbolicToApproximateBigInt() === -5n;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
tf.test("Negative fluent chain: (-10+5)*2/(-5) = 2", "Negative Scalar Ops", () => {
|
|
324
|
+
const v = EGPTReal.fromBigInt(-10n);
|
|
325
|
+
v.scalarAdd(5n).scalarMultiply(2n).scalarDivide(-5n);
|
|
326
|
+
return v.breakSymbolicToApproximateBigInt() === 2n;
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
tf.test("-3/4 + 1 = 1/4", "Negative Scalar Ops", () => {
|
|
330
|
+
const v = EGPTReal.fromRational(-3n, 4n); v.scalarAdd(1n);
|
|
331
|
+
const r = v._getPPFRationalParts();
|
|
332
|
+
return r.numerator === 1n && r.denominator === 4n;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
tf.test("Crossing zero: -1 + 2 = 1", "Negative Scalar Ops", () => {
|
|
336
|
+
const v = EGPTReal.fromBigInt(-1n); v.scalarAdd(2n);
|
|
337
|
+
return v.breakSymbolicToApproximateBigInt() === 1n;
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
tf.test("-7 / 3 creates fraction -7/3", "Negative Scalar Ops", () => {
|
|
341
|
+
const v = EGPTReal.fromBigInt(-7n); v.scalarDivide(3n);
|
|
342
|
+
const r = v._getPPFRationalParts();
|
|
343
|
+
return r.numerator === -7n && r.denominator === 3n;
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
return { suite: inputs.suite };
|
|
347
|
+
</cell>
|
|
348
|
+
|
|
349
|
+
<cell type="markdown">
|
|
350
|
+
## Phase 3 — EGPTMath: Vector Algebra Engine
|
|
351
|
+
|
|
352
|
+
`EGPTMath` is a **static-only** class (instantiation throws). Its operations work in
|
|
353
|
+
Shannon/log space where multiplication of values becomes addition of their PPF exponent
|
|
354
|
+
vectors (RET Iron Law). The `add` / `subtract` methods perform normal-space rational
|
|
355
|
+
arithmetic.
|
|
356
|
+
|
|
357
|
+
| Method | Shannon interpretation | Normal-space result |
|
|
358
|
+
|---|---|---|
|
|
359
|
+
| `multiply(a, b)` | add exponent vectors `H(a) + H(b)` | `a × b` |
|
|
360
|
+
| `divide(a, b)` | subtract exponent vectors `H(a) − H(b)` | `a / b` |
|
|
361
|
+
| `pow(a, p, q)` | scale exponent vector by `p/q` | `a^(p/q)` |
|
|
362
|
+
| `sqrt(a)` | scale exponent vector by `1/2` | `√a` |
|
|
363
|
+
| `add(a, b)` | normal-space rational add | `a + b` |
|
|
364
|
+
| `subtract(a, b)` | normal-space rational subtract | `a − b` |
|
|
365
|
+
</cell>
|
|
366
|
+
|
|
367
|
+
<cell type="js" lane="math" id="phase3" in="suite" out="suite">
|
|
368
|
+
const { tf, EGPTReal, EGPTMath } = inputs.suite;
|
|
369
|
+
|
|
370
|
+
console.log("PHASE 3: EGPTMath (Vector Algebra Engine)");
|
|
371
|
+
|
|
372
|
+
tf.test("EGPTMath cannot be instantiated (static class)", "Architecture", () => {
|
|
373
|
+
try { new EGPTMath(); return false; }
|
|
374
|
+
catch (e) { return e.message.includes("static class"); }
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
tf.test("multiply() RET Iron Law: 2 × 3 = 6", "Vector Algebra", () => {
|
|
378
|
+
return EGPTMath.multiply(EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n))
|
|
379
|
+
.breakSymbolicToApproximateBigInt() === 6n;
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
tf.test("divide() Shannon subtraction: 6 ÷ 2 = 3", "Vector Algebra", () => {
|
|
383
|
+
return EGPTMath.divide(EGPTReal.fromBigInt(6n), EGPTReal.fromBigInt(2n))
|
|
384
|
+
.breakSymbolicToApproximateBigInt() === 3n;
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
tf.test("pow() Shannon scaling: 2^3 = 8", "Vector Algebra", () => {
|
|
388
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(2n), 3n, 1n)
|
|
389
|
+
.breakSymbolicToApproximateBigInt() === 8n;
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
tf.test("sqrt(): √16 = 4", "Vector Algebra", () => {
|
|
393
|
+
return EGPTMath.sqrt(EGPTReal.fromBigInt(16n))
|
|
394
|
+
.breakSymbolicToApproximateBigInt() === 4n;
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
tf.test("add(): 1/3 + 1/6 = 1/2", "Vector Algebra", () => {
|
|
398
|
+
const sum = EGPTMath.add(EGPTReal.fromRational(1n, 3n), EGPTReal.fromRational(1n, 6n));
|
|
399
|
+
const r = sum._getPPFRationalParts();
|
|
400
|
+
return r.numerator === 1n && r.denominator === 2n;
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
tf.test("subtract(): 2/3 - 1/6 = 1/2", "Vector Algebra", () => {
|
|
404
|
+
const diff = EGPTMath.subtract(EGPTReal.fromRational(2n, 3n), EGPTReal.fromRational(1n, 6n));
|
|
405
|
+
const r = diff._getPPFRationalParts();
|
|
406
|
+
return r.numerator === 1n && r.denominator === 2n;
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
return { suite: inputs.suite };
|
|
410
|
+
</cell>
|
|
411
|
+
|
|
412
|
+
<cell type="markdown">
|
|
413
|
+
## Phase 4 — Pedagogical Dual Naming
|
|
414
|
+
|
|
415
|
+
`EGPTMath` exposes **alias methods** that surface the Shannon-space perspective alongside
|
|
416
|
+
the normal-space names. `addInLogSpace` is identical to `multiply` — both add entropy
|
|
417
|
+
vectors. `subtractInLogSpace` is identical to `divide`. `addVectors` is identical to
|
|
418
|
+
`add`. These aliases exist so that code can declare its intent: "I am working in log space"
|
|
419
|
+
vs "I am working in normal space."
|
|
420
|
+
</cell>
|
|
421
|
+
|
|
422
|
+
<cell type="js" lane="math" id="phase4" in="suite" out="suite">
|
|
423
|
+
const { tf, EGPTReal, EGPTMath } = inputs.suite;
|
|
424
|
+
|
|
425
|
+
console.log("PHASE 4: Pedagogical Dual Naming");
|
|
426
|
+
|
|
427
|
+
tf.test("addInLogSpace alias equals multiply result", "Dual Naming", () => {
|
|
428
|
+
const H5 = EGPTReal.fromBigInt(5n), H7 = EGPTReal.fromBigInt(7n);
|
|
429
|
+
return EGPTMath.multiply(H5, H7).equals(EGPTMath.addInLogSpace(H5, H7));
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
tf.test("subtractInLogSpace alias equals divide result", "Dual Naming", () => {
|
|
433
|
+
const H35 = EGPTReal.fromBigInt(35n), H5 = EGPTReal.fromBigInt(5n);
|
|
434
|
+
return EGPTMath.divide(H35, H5).equals(EGPTMath.subtractInLogSpace(H35, H5));
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
tf.test("addVectors alias equals add result", "Dual Naming", () => {
|
|
438
|
+
const v1 = EGPTReal.fromRational(1n, 4n), v2 = EGPTReal.fromRational(1n, 4n);
|
|
439
|
+
return EGPTMath.add(v1, v2).equals(EGPTMath.addVectors(v1, v2));
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
return { suite: inputs.suite };
|
|
443
|
+
</cell>
|
|
444
|
+
|
|
445
|
+
<cell type="markdown">
|
|
446
|
+
## Phase 5 — RET Iron Law Validation
|
|
447
|
+
|
|
448
|
+
The **Rational Entropy Theorem (RET) Iron Law**: `H(p × q) = H(p) + H(q)`. In code this
|
|
449
|
+
means `EGPTMath.multiply(H_p, H_q)` must equal `EGPTReal.fromBigInt(p * q)` for any
|
|
450
|
+
integers `p`, `q`. This is the foundational correctness invariant — if it fails, the
|
|
451
|
+
PPF encoding is broken.
|
|
452
|
+
|
|
453
|
+
`conditionalEntropyVector(k, p)` = `H(k) - H(p)` = `H(k/p)`. When `p` exactly divides
|
|
454
|
+
`k`, the result is an integer; otherwise it is a fraction. This gives a factorization test
|
|
455
|
+
that runs in polynomial time (no search).
|
|
456
|
+
</cell>
|
|
457
|
+
|
|
458
|
+
<cell type="js" lane="math" id="phase5" in="suite" out="suite">
|
|
459
|
+
const { tf, EGPTReal, EGPTMath } = inputs.suite;
|
|
460
|
+
|
|
461
|
+
console.log("PHASE 5: RET Iron Law Validation");
|
|
462
|
+
|
|
463
|
+
tf.test("RET Iron Law: H(6) = H(2) + H(3) via multiply", "RET Iron Law", () => {
|
|
464
|
+
return EGPTReal.fromBigInt(6n).equals(
|
|
465
|
+
EGPTMath.multiply(EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n))
|
|
466
|
+
);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
tf.test("RET Iron Law: large numbers (77 = 7 × 11)", "RET Iron Law", () => {
|
|
470
|
+
return EGPTReal.fromBigInt(77n).equals(
|
|
471
|
+
EGPTMath.multiply(EGPTReal.fromBigInt(7n), EGPTReal.fromBigInt(11n))
|
|
472
|
+
);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
tf.test("RET Iron Law: inverse — multiply then divide recovers original", "RET Iron Law", () => {
|
|
476
|
+
const H13 = EGPTReal.fromBigInt(13n), H17 = EGPTReal.fromBigInt(17n);
|
|
477
|
+
const product = EGPTMath.multiply(H13, H17);
|
|
478
|
+
return H17.equals(EGPTMath.divide(product, H13));
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
tf.test("conditionalEntropyVector: exact factor yields integer", "RET Iron Law", () => {
|
|
482
|
+
const H35 = EGPTReal.fromBigInt(35n);
|
|
483
|
+
const exact = EGPTMath.conditionalEntropyVector(H35, EGPTReal.fromBigInt(5n));
|
|
484
|
+
const nonFactor = EGPTMath.conditionalEntropyVector(H35, EGPTReal.fromBigInt(6n));
|
|
485
|
+
return exact.isInteger() && !nonFactor.isInteger();
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
return { suite: inputs.suite };
|
|
489
|
+
</cell>
|
|
490
|
+
|
|
491
|
+
<cell type="markdown">
|
|
492
|
+
## Phase 6 — Statistical Functions (EGPTStat)
|
|
493
|
+
|
|
494
|
+
`EGPTStat` provides exact rational statistics over arrays of `EGPTReal` values. Unlike
|
|
495
|
+
floating-point statistics, these operations are **exact** — the mean and variance are
|
|
496
|
+
exact rational `EGPTReal` values. The variance uses `absoluteDifference` (always
|
|
497
|
+
positive) so deviation terms stay in valid PPF encoding.
|
|
498
|
+
</cell>
|
|
499
|
+
|
|
500
|
+
<cell type="js" lane="math" id="phase6" in="suite" out="suite">
|
|
501
|
+
const { tf, EGPTReal, EGPTStat } = inputs.suite;
|
|
502
|
+
|
|
503
|
+
console.log("PHASE 6: Statistical Functions (EGPTStat)");
|
|
504
|
+
|
|
505
|
+
tf.test("mean() of [2, 4, 6] = 4", "Statistics", () => {
|
|
506
|
+
const vs = [EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(6n)];
|
|
507
|
+
return EGPTStat.mean(vs).breakSymbolicToApproximateBigInt() === 4n;
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
tf.test("variance() of [1,3,5]: variance = 8/3, negative_deviations = 1", "Statistics", () => {
|
|
511
|
+
const vs = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(5n)];
|
|
512
|
+
const result = EGPTStat.variance(vs);
|
|
513
|
+
const r = result.variance._getPPFRationalParts();
|
|
514
|
+
return r.numerator === 8n && r.denominator === 3n
|
|
515
|
+
&& result.metadata.negative_deviations === 1
|
|
516
|
+
&& result.metadata.has_negative_deviations === true;
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
tf.test("variance() handles negative deviations without error", "Statistics", () => {
|
|
520
|
+
const vs = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(5n)];
|
|
521
|
+
try {
|
|
522
|
+
const result = EGPTStat.variance(vs);
|
|
523
|
+
return result.variance.breakSymbolicToApproximateBigInt() >= 0n
|
|
524
|
+
&& result.metadata.negative_deviations === 1
|
|
525
|
+
&& result.metadata.has_negative_deviations === true;
|
|
526
|
+
} catch (e) { return false; }
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
return { suite: inputs.suite };
|
|
530
|
+
</cell>
|
|
531
|
+
|
|
532
|
+
<cell type="markdown">
|
|
533
|
+
## Phase 6.5 — Fractional Exponentiation and Roots
|
|
534
|
+
|
|
535
|
+
`EGPTMath.pow(x, p, q)` scales the exponent vector of `x` by `p/q`. When the result is
|
|
536
|
+
reducible to an integer (i.e. `x^(p/q)` is a perfect power), `equals()` returns `true`
|
|
537
|
+
when compared to the integer. Irrational cases produce **scaled vectors** — held in exact
|
|
538
|
+
PPF form as `(p/q) * H(base)` — which are further reducible by subsequent operations.
|
|
539
|
+
</cell>
|
|
540
|
+
|
|
541
|
+
<cell type="js" lane="math" id="phase65" in="suite" out="suite">
|
|
542
|
+
const { tf, EGPTReal, EGPTMath } = inputs.suite;
|
|
543
|
+
|
|
544
|
+
console.log("PHASE 6.5: Fractional Exponentiation and Roots");
|
|
545
|
+
|
|
546
|
+
tf.test("8^(1/3) = 2 (cube root)", "Fractional Powers", () => {
|
|
547
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(8n), 1n, 3n)
|
|
548
|
+
.equals(EGPTReal.fromBigInt(2n));
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
tf.test("16^(1/4) = 2 (fourth root)", "Fractional Powers", () => {
|
|
552
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(16n), 1n, 4n)
|
|
553
|
+
.equals(EGPTReal.fromBigInt(2n));
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
tf.test("9^(1/2) = 3 (square root)", "Fractional Powers", () => {
|
|
557
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(9n), 1n, 2n)
|
|
558
|
+
.equals(EGPTReal.fromBigInt(3n));
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
tf.test("27^(2/3) = 9", "Fractional Powers", () => {
|
|
562
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(27n), 2n, 3n)
|
|
563
|
+
.equals(EGPTReal.fromBigInt(9n));
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
tf.test("32^(3/5) = 8", "Fractional Powers", () => {
|
|
567
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(32n), 3n, 5n)
|
|
568
|
+
.equals(EGPTReal.fromBigInt(8n));
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
tf.test("sqrt() consistent with pow(x, 1/2): √25", "Root Consistency", () => {
|
|
572
|
+
const H25 = EGPTReal.fromBigInt(25n);
|
|
573
|
+
return EGPTMath.sqrt(H25).equals(EGPTMath.pow(H25, 1n, 2n));
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
tf.test("Power identity: (x^a)^b = x^(a*b): (8^(1/3))^3 = 8", "Fractional Identities", () => {
|
|
577
|
+
const H8 = EGPTReal.fromBigInt(8n);
|
|
578
|
+
const inner = EGPTMath.pow(H8, 1n, 3n); // ∛8 = H(2)
|
|
579
|
+
const method1 = EGPTMath.pow(inner, 3n, 1n); // H(2)^3 = H(8)
|
|
580
|
+
const method2 = EGPTMath.pow(H8, 1n, 1n);
|
|
581
|
+
return method1.equals(method2) && method1.equals(EGPTReal.fromBigInt(8n));
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
tf.test("64^(1/6) = 2", "Fractional Precision", () => {
|
|
585
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(64n), 1n, 6n)
|
|
586
|
+
.equals(EGPTReal.fromBigInt(2n));
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
tf.test("Nested: √(∛27) = 27^(1/6)", "Nested Fractionals", () => {
|
|
590
|
+
const H27 = EGPTReal.fromBigInt(27n);
|
|
591
|
+
const cubeRoot = EGPTMath.pow(H27, 1n, 3n);
|
|
592
|
+
return EGPTMath.sqrt(cubeRoot).equals(EGPTMath.pow(H27, 1n, 6n));
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
tf.test("Rational base: (9/4)^(1/2) = 3/2", "Rational Fractional", () => {
|
|
596
|
+
const base = EGPTReal.fromRational(9n, 4n);
|
|
597
|
+
return EGPTMath.pow(base, 1n, 2n).equals(EGPTReal.fromRational(3n, 2n));
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
tf.test("Shannon scaling via sqrt: √4 * √9 = 6 (RET law on roots)", "Shannon Fractional", () => {
|
|
601
|
+
const product = EGPTMath.multiply(
|
|
602
|
+
EGPTMath.sqrt(EGPTReal.fromBigInt(4n)),
|
|
603
|
+
EGPTMath.sqrt(EGPTReal.fromBigInt(9n))
|
|
604
|
+
);
|
|
605
|
+
return product.equals(EGPTReal.fromBigInt(6n));
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
tf.test("Complex fractional chain: ((16^(1/4))^(1/2))^2 = 2", "Complex Fractional Chain", () => {
|
|
609
|
+
const step1 = EGPTMath.pow(EGPTReal.fromBigInt(16n), 1n, 4n); // 2
|
|
610
|
+
const step2 = EGPTMath.sqrt(step1); // √2
|
|
611
|
+
const final = EGPTMath.pow(step2, 2n, 1n); // (√2)^2 = 2
|
|
612
|
+
return final.equals(EGPTReal.fromBigInt(2n));
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
return { suite: inputs.suite };
|
|
616
|
+
</cell>
|
|
617
|
+
|
|
618
|
+
<cell type="markdown">
|
|
619
|
+
## Phase 6.6 — exp2 and log2 (EGPTranscendental)
|
|
620
|
+
|
|
621
|
+
`EGPTranscendental.exp2(x)` computes `2^x` and `EGPTranscendental.log2(x)` computes
|
|
622
|
+
`log₂(x)` — both exactly, over `EGPTReal` values. These are **transcendental** operations
|
|
623
|
+
but implemented via exact PPF rational arithmetic. The key identity checked is
|
|
624
|
+
`exp2(log2(x)) = x` and `log2(exp2(n)) = n` for integer inputs.
|
|
625
|
+
|
|
626
|
+
Note: `EGPTranscendental` is a separate class from `EGPTMath` (accessed as
|
|
627
|
+
`math.EGPTranscendental` from the SDK surface).
|
|
628
|
+
</cell>
|
|
629
|
+
|
|
630
|
+
<cell type="js" lane="math" id="phase66" in="suite" out="suite">
|
|
631
|
+
const { tf, EGPTReal, EGPTMath, EGPTranscendental } = inputs.suite;
|
|
632
|
+
|
|
633
|
+
console.log("PHASE 6.6: exp2 and log2 (EGPTranscendental)");
|
|
634
|
+
|
|
635
|
+
tf.test("exp2(3) = 8", "Exponential Functions", () => {
|
|
636
|
+
return EGPTranscendental.exp2(EGPTReal.fromBigInt(3n))
|
|
637
|
+
.equals(EGPTReal.fromBigInt(8n));
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
tf.test("exp2(5) = 32", "Exponential Functions", () => {
|
|
641
|
+
return EGPTranscendental.exp2(EGPTReal.fromBigInt(5n))
|
|
642
|
+
.equals(EGPTReal.fromBigInt(32n));
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
tf.test("exp2(0) = 1", "Exponential Functions", () => {
|
|
646
|
+
return EGPTranscendental.exp2(EGPTReal.fromBigInt(0n))
|
|
647
|
+
.equals(EGPTReal.fromBigInt(1n));
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
tf.test("exp2(10) = 1024", "Exponential Functions", () => {
|
|
651
|
+
return EGPTranscendental.exp2(EGPTReal.fromBigInt(10n))
|
|
652
|
+
.equals(EGPTReal.fromBigInt(1024n));
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
tf.test("exp2(1/2) = √2: squaring recovers 2", "Exponential Functions", () => {
|
|
656
|
+
const sqrt2 = EGPTranscendental.exp2(EGPTReal.fromRational(1n, 2n));
|
|
657
|
+
return EGPTMath.pow(sqrt2, 2n, 1n).equals(EGPTReal.fromBigInt(2n));
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
tf.test("exp2(3/2) = 2^1 * 2^(1/2)", "Exponential Functions", () => {
|
|
661
|
+
const result = EGPTranscendental.exp2(EGPTReal.fromRational(3n, 2n));
|
|
662
|
+
const alt = EGPTMath.multiply(
|
|
663
|
+
EGPTranscendental.exp2(EGPTReal.fromBigInt(1n)),
|
|
664
|
+
EGPTranscendental.exp2(EGPTReal.fromRational(1n, 2n))
|
|
665
|
+
);
|
|
666
|
+
return result.equals(alt);
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
tf.test("log2(8) = 3", "Logarithmic Functions", () => {
|
|
670
|
+
return EGPTranscendental.log2(EGPTReal.fromBigInt(8n))
|
|
671
|
+
.equals(EGPTReal.fromBigInt(3n));
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
tf.test("log2(16) = 4", "Logarithmic Functions", () => {
|
|
675
|
+
return EGPTranscendental.log2(EGPTReal.fromBigInt(16n))
|
|
676
|
+
.equals(EGPTReal.fromBigInt(4n));
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
tf.test("log2(1024) = 10", "Logarithmic Functions", () => {
|
|
680
|
+
return EGPTranscendental.log2(EGPTReal.fromBigInt(1024n))
|
|
681
|
+
.equals(EGPTReal.fromBigInt(10n));
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
tf.test("log2(2) = 1", "Logarithmic Functions", () => {
|
|
685
|
+
return EGPTranscendental.log2(EGPTReal.fromBigInt(2n))
|
|
686
|
+
.equals(EGPTReal.fromBigInt(1n));
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
tf.test("log2(1) = 0", "Logarithmic Functions", () => {
|
|
690
|
+
return EGPTranscendental.log2(EGPTReal.fromBigInt(1n))
|
|
691
|
+
.equals(EGPTReal.fromBigInt(0n));
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
tf.test("Inverse: exp2(log2(x)) = x for powers of 2", "Exponential-Logarithmic Identity", () => {
|
|
695
|
+
for (const v of [1n, 2n, 4n, 8n, 16n, 32n, 64n, 1024n]) {
|
|
696
|
+
const H = EGPTReal.fromBigInt(v);
|
|
697
|
+
if (!EGPTranscendental.exp2(EGPTranscendental.log2(H)).equals(H)) return false;
|
|
698
|
+
}
|
|
699
|
+
return true;
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
tf.test("Inverse: log2(exp2(n)) = n for small integers", "Exponential-Logarithmic Identity", () => {
|
|
703
|
+
for (const n of [0n, 1n, 2n, 3n, 4n, 5n, 10n]) {
|
|
704
|
+
const H = EGPTReal.fromBigInt(n);
|
|
705
|
+
if (!EGPTranscendental.log2(EGPTranscendental.exp2(H)).equals(H)) return false;
|
|
706
|
+
}
|
|
707
|
+
return true;
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
tf.test("RET preserved: exp2(2) * exp2(3) = exp2(5) = 32", "Shannon Exponential RET", () => {
|
|
711
|
+
const H4 = EGPTranscendental.exp2(EGPTReal.fromBigInt(2n));
|
|
712
|
+
const H8 = EGPTranscendental.exp2(EGPTReal.fromBigInt(3n));
|
|
713
|
+
return EGPTMath.multiply(H4, H8).equals(EGPTReal.fromBigInt(32n));
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
tf.test("Compound: exp2(exp2(2)) = exp2(4) = 16", "Compound Exponentials", () => {
|
|
717
|
+
const inner = EGPTranscendental.exp2(EGPTReal.fromBigInt(2n)); // 4
|
|
718
|
+
return EGPTranscendental.exp2(inner).equals(EGPTReal.fromBigInt(16n));
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
return { suite: inputs.suite };
|
|
722
|
+
</cell>
|
|
723
|
+
|
|
724
|
+
<cell type="markdown">
|
|
725
|
+
## Phase 6.7 — Scaled Vectors: Irrational Number Support
|
|
726
|
+
|
|
727
|
+
When `EGPTMath.pow(x, p, q)` cannot reduce the result to a rational (e.g. `√2`, `2^(3/4)`),
|
|
728
|
+
it produces a **scaled vector**: an `EGPTReal` holding `(p/q) * H(base)`. These are exact
|
|
729
|
+
representations of irrationals that can participate in further algebra.
|
|
730
|
+
|
|
731
|
+
`fromScaledVector(base, p, q)` creates such a vector explicitly. `getScalarParts()` extracts
|
|
732
|
+
the `{numerator, denominator}` of the scalar multiplier. `getBaseRationalParts()` extracts
|
|
733
|
+
the underlying base vector's rational form.
|
|
734
|
+
|
|
735
|
+
Reducible cases (where the root is itself rational) automatically normalize to the integer
|
|
736
|
+
form on `equals()`.
|
|
737
|
+
</cell>
|
|
738
|
+
|
|
739
|
+
<cell type="js" lane="math" id="phase67" in="suite" out="suite">
|
|
740
|
+
const { tf, EGPTReal, EGPTMath } = inputs.suite;
|
|
741
|
+
|
|
742
|
+
console.log("PHASE 6.7: Scaled Vectors");
|
|
743
|
+
|
|
744
|
+
tf.test("fromScaledVector: H(√2) has scalar 1/2 and base 2", "Scaled Vectors", () => {
|
|
745
|
+
const H2 = EGPTReal.fromBigInt(2n);
|
|
746
|
+
const Hsqrt2 = EGPTReal.fromScaledVector(H2, 1n, 2n);
|
|
747
|
+
const s = Hsqrt2.getScalarParts();
|
|
748
|
+
const b = Hsqrt2.getBaseRationalParts();
|
|
749
|
+
return s.numerator === 1n && s.denominator === 2n
|
|
750
|
+
&& b.numerator === 2n && b.denominator === 1n;
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
tf.test("Reversibility: H(√2) + H(√2) = H(2) in normal space", "Scaled Vectors", () => {
|
|
754
|
+
const H2 = EGPTReal.fromBigInt(2n);
|
|
755
|
+
const Hsqrt2 = EGPTReal.fromScaledVector(H2, 1n, 2n);
|
|
756
|
+
return EGPTMath.add(Hsqrt2, Hsqrt2).equals(H2);
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
tf.test("pow(8, 1/3) reduces to H(2) — canonical form", "Scaled Vectors", () => {
|
|
760
|
+
return EGPTMath.pow(EGPTReal.fromBigInt(8n), 1n, 3n)
|
|
761
|
+
.equals(EGPTReal.fromBigInt(2n));
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
tf.test("sqrt(4) reduces to H(2) — canonical form", "Scaled Vectors", () => {
|
|
765
|
+
return EGPTMath.sqrt(EGPTReal.fromBigInt(4n))
|
|
766
|
+
.equals(EGPTReal.fromBigInt(2n));
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
tf.test("toMathString for scaled vector shows scaling operation", "Scaled Vectors", () => {
|
|
770
|
+
const H2 = EGPTReal.fromBigInt(2n);
|
|
771
|
+
const s = EGPTReal.fromScaledVector(H2, 3n, 4n).toMathString();
|
|
772
|
+
return s.includes("3/4") && s.includes("H(2)");
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
tf.test("Scaled vector clone preserves scalar multiplier", "Scaled Vectors", () => {
|
|
776
|
+
const H5 = EGPTReal.fromBigInt(5n);
|
|
777
|
+
const scaled = EGPTReal.fromScaledVector(H5, 7n, 11n);
|
|
778
|
+
const cloned = scaled.clone();
|
|
779
|
+
const os = scaled.getScalarParts(), cs = cloned.getScalarParts();
|
|
780
|
+
return os.numerator === cs.numerator && os.denominator === cs.denominator
|
|
781
|
+
&& scaled.equals(cloned);
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
tf.test("toPPF for scaled vector includes scalar info", "Scaled Vectors", () => {
|
|
785
|
+
const H3 = EGPTReal.fromBigInt(3n);
|
|
786
|
+
const ppf = EGPTReal.fromScaledVector(H3, 5n, 7n).toPPF();
|
|
787
|
+
return ppf.scalar && ppf.scalar.numerator === 5n && ppf.scalar.denominator === 7n;
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
tf.test("Scaled vector equality across equivalent representations", "Scaled Vectors", () => {
|
|
791
|
+
const H6 = EGPTReal.fromBigInt(6n);
|
|
792
|
+
const s1 = EGPTReal.fromScaledVector(H6, 2n, 3n);
|
|
793
|
+
const s2 = EGPTReal.fromScaledVector(H6, 4n, 6n);
|
|
794
|
+
return s1.equals(s2);
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
tf.test("H(2^(3/4)) has scalar 3/4 and base 2", "Scaled Vectors", () => {
|
|
798
|
+
const result = EGPTMath.pow(EGPTReal.fromBigInt(2n), 3n, 4n);
|
|
799
|
+
const s = result.getScalarParts(), b = result.getBaseRationalParts();
|
|
800
|
+
return s.numerator === 3n && s.denominator === 4n
|
|
801
|
+
&& b.numerator === 2n && b.denominator === 1n;
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
tf.test("demonstrateIrrationalRoots: sqrt_2 scalar=1/2, two_to_3/2 scalar=3/2, cuberoot_8=H(2)", "Scaled Vectors", () => {
|
|
805
|
+
const ex = EGPTMath.demonstrateIrrationalRoots();
|
|
806
|
+
const ss = ex.sqrt_2.getScalarParts();
|
|
807
|
+
const ts = ex.two_to_three_halves.getScalarParts();
|
|
808
|
+
const irrPass = ss.numerator === 1n && ss.denominator === 2n
|
|
809
|
+
&& ts.numerator === 3n && ts.denominator === 2n;
|
|
810
|
+
const redPass = ex.cuberoot_8.equals(EGPTReal.fromBigInt(2n));
|
|
811
|
+
return irrPass && redPass;
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
return { suite: inputs.suite };
|
|
815
|
+
</cell>
|
|
816
|
+
|
|
817
|
+
<cell type="markdown">
|
|
818
|
+
## Phase 6.8 — Scaled Vector Algebra
|
|
819
|
+
|
|
820
|
+
Operations between scaled vectors follow specific rules. When both operands have the
|
|
821
|
+
**same scalar multiplier** (e.g. both are `(1/2)*H(something)`), multiply/divide works by
|
|
822
|
+
operating on the bases and combining the scalars. When scalars differ and are non-trivial,
|
|
823
|
+
the operation is undefined and throws — this enforces discipline (you cannot silently mix
|
|
824
|
+
`√2 * ∛3` without acknowledging the incompatible root spaces).
|
|
825
|
+
</cell>
|
|
826
|
+
|
|
827
|
+
<cell type="js" lane="math" id="phase68" in="suite" out="suite">
|
|
828
|
+
const { tf, EGPTReal, EGPTMath } = inputs.suite;
|
|
829
|
+
|
|
830
|
+
console.log("PHASE 6.8: Scaled Vector Algebra");
|
|
831
|
+
|
|
832
|
+
tf.test("H(√2) * H(√3) = H(√6) — identical scalars", "Scaled Vector Algebra", () => {
|
|
833
|
+
const Hsqrt2 = EGPTMath.sqrt(EGPTReal.fromBigInt(2n));
|
|
834
|
+
const Hsqrt3 = EGPTMath.sqrt(EGPTReal.fromBigInt(3n));
|
|
835
|
+
return EGPTMath.multiply(Hsqrt2, Hsqrt3)
|
|
836
|
+
.equals(EGPTMath.sqrt(EGPTReal.fromBigInt(6n)));
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
tf.test("H(2) * H(√3) = H(√12) — one scalar, one integer", "Scaled Vector Algebra", () => {
|
|
840
|
+
const H2 = EGPTReal.fromBigInt(2n);
|
|
841
|
+
const Hsqrt3 = EGPTMath.sqrt(EGPTReal.fromBigInt(3n));
|
|
842
|
+
const product = EGPTMath.multiply(H2, Hsqrt3);
|
|
843
|
+
return product.equals(EGPTMath.sqrt(EGPTReal.fromBigInt(12n)));
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
tf.test("H(√2) * H(√2) = H(2) — self-multiply eliminates root", "Scaled Vector Algebra", () => {
|
|
847
|
+
const H2 = EGPTReal.fromBigInt(2n);
|
|
848
|
+
const Hsqrt2 = EGPTMath.sqrt(H2);
|
|
849
|
+
return EGPTMath.multiply(Hsqrt2, Hsqrt2).equals(H2);
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
tf.test("(1/2)*H(2) * (-1/2)*H(2) = H(1) — opposite scalars cancel", "Scaled Vector Algebra", () => {
|
|
853
|
+
const H2 = EGPTReal.fromBigInt(2n);
|
|
854
|
+
const pos = EGPTReal.fromScaledVector(H2, 1n, 2n);
|
|
855
|
+
const neg = EGPTReal.fromScaledVector(H2, -1n, 2n);
|
|
856
|
+
return EGPTMath.multiply(pos, neg).equals(EGPTReal.fromBigInt(1n));
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
tf.test("√(1/2) * 2 = √2", "Scaled Vector Algebra", () => {
|
|
860
|
+
const Hsqrt_half = EGPTMath.sqrt(EGPTReal.fromRational(1n, 2n));
|
|
861
|
+
const product = EGPTMath.multiply(Hsqrt_half, EGPTReal.fromBigInt(2n));
|
|
862
|
+
return product.equals(EGPTMath.sqrt(EGPTReal.fromBigInt(2n)));
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
tf.test("H(√6) / H(√2) = H(√3) — identical scalars divide", "Scaled Vector Algebra", () => {
|
|
866
|
+
const Hsqrt2 = EGPTMath.sqrt(EGPTReal.fromBigInt(2n));
|
|
867
|
+
const Hsqrt3 = EGPTMath.sqrt(EGPTReal.fromBigInt(3n));
|
|
868
|
+
const Hsqrt6 = EGPTMath.sqrt(EGPTReal.fromBigInt(6n));
|
|
869
|
+
return EGPTMath.divide(Hsqrt6, Hsqrt2).equals(Hsqrt3);
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
tf.test("H(√2) * H(∛3) throws (incompatible scalars)", "Scaled Vector Algebra", () => {
|
|
873
|
+
const Hsqrt2 = EGPTMath.sqrt(EGPTReal.fromBigInt(2n));
|
|
874
|
+
const Hcbrt3 = EGPTMath.pow(EGPTReal.fromBigInt(3n), 1n, 3n);
|
|
875
|
+
try { EGPTMath.multiply(Hsqrt2, Hcbrt3); return false; }
|
|
876
|
+
catch (e) { return e.message.includes("not supported"); }
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
tf.test("H(√6) / H(∛2) throws (incompatible scalars)", "Scaled Vector Algebra", () => {
|
|
880
|
+
const Hsqrt6 = EGPTMath.sqrt(EGPTReal.fromBigInt(6n));
|
|
881
|
+
const Hcbrt2 = EGPTMath.pow(EGPTReal.fromBigInt(2n), 1n, 3n);
|
|
882
|
+
try { EGPTMath.divide(Hsqrt6, Hcbrt2); return false; }
|
|
883
|
+
catch (e) { return e.message.includes("not supported"); }
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
return { suite: inputs.suite };
|
|
887
|
+
</cell>
|
|
888
|
+
|
|
889
|
+
<cell type="markdown">
|
|
890
|
+
## Phase 6.9 — EGPTStat Statistical Functions (Extended)
|
|
891
|
+
|
|
892
|
+
Extended statistical tests covering `mean()` with negative numbers and fractions,
|
|
893
|
+
`variance()` with signed values, `absoluteDifference()`, and
|
|
894
|
+
`comprehensiveStatisticalAnalysis()` which returns a full `EGPTStatData` object including
|
|
895
|
+
variance, standard deviation, min/max, and negative count.
|
|
896
|
+
</cell>
|
|
897
|
+
|
|
898
|
+
<cell type="js" lane="math" id="phase69" in="suite" out="suite">
|
|
899
|
+
const { tf, EGPTReal, EGPTMath, EGPTStat, EGPTStatData } = inputs.suite;
|
|
900
|
+
|
|
901
|
+
console.log("PHASE 6.9: EGPTStat Statistical Functions (Extended)");
|
|
902
|
+
|
|
903
|
+
tf.test("mean() with positive numbers [2,4,6] = 4", "Statistical Functions", () => {
|
|
904
|
+
const vs = [EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(6n)];
|
|
905
|
+
return EGPTStat.mean(vs).equals(EGPTReal.fromBigInt(4n));
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
tf.test("mean() with negative numbers [-2,0,4] = 2/3", "Statistical Functions", () => {
|
|
909
|
+
const vs = [EGPTReal.fromBigInt(-2n), EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(4n)];
|
|
910
|
+
return EGPTStat.mean(vs).equals(EGPTReal.fromRational(2n, 3n));
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
tf.test("mean() with fractions [1/2, 3/4, 1] = 3/4", "Statistical Functions", () => {
|
|
914
|
+
const vs = [EGPTReal.fromRational(1n,2n), EGPTReal.fromRational(3n,4n), EGPTReal.fromRational(1n,1n)];
|
|
915
|
+
return EGPTStat.mean(vs).equals(EGPTReal.fromRational(3n, 4n));
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
tf.test("mean() with scaled vectors returns EGPTReal", "Statistical Functions", () => {
|
|
919
|
+
const H2 = EGPTReal.fromBigInt(2n), H8 = EGPTReal.fromBigInt(8n);
|
|
920
|
+
const vs = [EGPTMath.sqrt(H2), EGPTReal.fromBigInt(2n), EGPTMath.sqrt(H8)];
|
|
921
|
+
const mean = EGPTStat.mean(vs);
|
|
922
|
+
return mean instanceof EGPTReal;
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
tf.test("variance() of [1,3,5]: variance=8/3, negative_deviations=1, total=3", "Statistical Functions", () => {
|
|
926
|
+
const vs = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(5n)];
|
|
927
|
+
const r = EGPTStat.variance(vs);
|
|
928
|
+
return r.variance.equals(EGPTReal.fromRational(8n, 3n))
|
|
929
|
+
&& r.metadata.total_vectors === 3
|
|
930
|
+
&& r.metadata.negative_deviations === 1;
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
tf.test("variance() of [-1,0,1] = 2/3", "Statistical Functions", () => {
|
|
934
|
+
const vs = [EGPTReal.fromBigInt(-1n), EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(1n)];
|
|
935
|
+
const r = EGPTStat.variance(vs);
|
|
936
|
+
return r.variance.equals(EGPTReal.fromRational(2n, 3n))
|
|
937
|
+
&& r.metadata.total_vectors === 3;
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
tf.test("absoluteDifference(5, 2) = 3", "Statistical Functions", () => {
|
|
941
|
+
return EGPTStat.absoluteDifference(EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(2n))
|
|
942
|
+
.equals(EGPTReal.fromBigInt(3n));
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
tf.test("absoluteDifference(2, 5) = 3 (commutative)", "Statistical Functions", () => {
|
|
946
|
+
return EGPTStat.absoluteDifference(EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(5n))
|
|
947
|
+
.equals(EGPTReal.fromBigInt(3n));
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
tf.test("absoluteDifference(7/4, 3/4) = 1", "Statistical Functions", () => {
|
|
951
|
+
return EGPTStat.absoluteDifference(EGPTReal.fromRational(7n,4n), EGPTReal.fromRational(3n,4n))
|
|
952
|
+
.equals(EGPTReal.fromBigInt(1n));
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
tf.test("comprehensiveStatisticalAnalysis([1..5]): EGPTStatData, count=5, mean=3", "Statistical Functions", () => {
|
|
956
|
+
const vs = [1n,2n,3n,4n,5n].map(n => EGPTReal.fromBigInt(n));
|
|
957
|
+
const a = EGPTStat.comprehensiveStatisticalAnalysis(vs);
|
|
958
|
+
return a instanceof EGPTStatData && a.total_count === 5
|
|
959
|
+
&& a.mean.equals(EGPTReal.fromBigInt(3n));
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
return { suite: inputs.suite };
|
|
963
|
+
</cell>
|
|
964
|
+
|
|
965
|
+
<cell type="markdown">
|
|
966
|
+
## Phase 6.10 — EGPTStatData Metadata Handling
|
|
967
|
+
|
|
968
|
+
`EGPTStatData` is the rich result object returned by `comprehensiveStatisticalAnalysis()`.
|
|
969
|
+
Beyond the scalar statistics, it tracks metadata: `total_count`, `negative_count`,
|
|
970
|
+
`min_value`, `max_value`, `variance`, `std_deviation`. The `getNormalizedDeltas()` method
|
|
971
|
+
returns per-element delta objects with magnitude classification — useful for outlier
|
|
972
|
+
detection.
|
|
973
|
+
</cell>
|
|
974
|
+
|
|
975
|
+
<cell type="js" lane="math" id="phase610" in="suite" out="suite">
|
|
976
|
+
const { tf, EGPTReal, EGPTMath, EGPTStat, EGPTStatData } = inputs.suite;
|
|
977
|
+
|
|
978
|
+
console.log("PHASE 6.10: EGPTStatData Metadata Handling");
|
|
979
|
+
|
|
980
|
+
tf.test("fromArray([1,3,5]): count=3, mean=3, min=1, max=5", "Statistical Metadata", () => {
|
|
981
|
+
const vs = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(5n)];
|
|
982
|
+
const sd = EGPTStatData.fromArray(vs);
|
|
983
|
+
return sd.total_count === 3
|
|
984
|
+
&& sd.mean.equals(EGPTReal.fromBigInt(3n))
|
|
985
|
+
&& sd.min_value.equals(EGPTReal.fromBigInt(1n))
|
|
986
|
+
&& sd.max_value.equals(EGPTReal.fromBigInt(5n));
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
tf.test("fromArray([-2,0,3]): count=3, negative_count=1, min=-2, max=3", "Statistical Metadata", () => {
|
|
990
|
+
const vs = [EGPTReal.fromBigInt(-2n), EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(3n)];
|
|
991
|
+
const sd = EGPTStatData.fromArray(vs);
|
|
992
|
+
return sd.total_count === 3 && sd.negative_count === 1
|
|
993
|
+
&& sd.min_value.equals(EGPTReal.fromBigInt(-2n))
|
|
994
|
+
&& sd.max_value.equals(EGPTReal.fromBigInt(3n));
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
tf.test("fromArray with scaled vectors: count=3, is EGPTStatData", "Statistical Metadata", () => {
|
|
998
|
+
const H2 = EGPTReal.fromBigInt(2n), H4 = EGPTReal.fromBigInt(4n);
|
|
999
|
+
const vs = [EGPTMath.sqrt(H2), EGPTMath.sqrt(H4), EGPTReal.fromBigInt(3n)];
|
|
1000
|
+
const sd = EGPTStatData.fromArray(vs);
|
|
1001
|
+
return sd.total_count === 3 && sd instanceof EGPTStatData;
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
tf.test("getNormalizedDeltas() returns 3 entries with required fields", "Statistical Metadata", () => {
|
|
1005
|
+
const vs = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(5n)];
|
|
1006
|
+
const deltas = EGPTStatData.fromArray(vs).getNormalizedDeltas();
|
|
1007
|
+
return deltas.length === 3
|
|
1008
|
+
&& 'index' in deltas[0] && 'raw_delta' in deltas[0]
|
|
1009
|
+
&& 'normalized_delta' in deltas[0] && 'magnitude_class' in deltas[0];
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
tf.test("Outlier gets different magnitude_class than baseline values", "Statistical Metadata", () => {
|
|
1013
|
+
const vs = [EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(100n)];
|
|
1014
|
+
const classes = EGPTStatData.fromArray(vs).getNormalizedDeltas().map(d => d.magnitude_class);
|
|
1015
|
+
return [...new Set(classes)].length > 1;
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
tf.test("comprehensiveStatisticalAnalysis([5,10,15,20]): count=4, mean=50/4, has variance & std_dev", "Statistical Integration", () => {
|
|
1019
|
+
const vs = [5n, 10n, 15n, 20n].map(n => EGPTReal.fromBigInt(n));
|
|
1020
|
+
const a = EGPTStat.comprehensiveStatisticalAnalysis(vs);
|
|
1021
|
+
return a instanceof EGPTStatData && a.total_count === 4
|
|
1022
|
+
&& a.mean.equals(EGPTReal.fromRational(50n, 4n))
|
|
1023
|
+
&& 'variance' in a && 'std_deviation' in a;
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
tf.test("comprehensiveStatisticalAnalysis with fractional roots: count=4", "Statistical Integration", () => {
|
|
1027
|
+
const H8 = EGPTReal.fromBigInt(8n), H16 = EGPTReal.fromBigInt(16n);
|
|
1028
|
+
const vs = [
|
|
1029
|
+
EGPTMath.pow(H8, 1n, 3n), // ∛8 → H(2)
|
|
1030
|
+
EGPTMath.pow(H16, 1n, 4n), // ⁴√16 → H(2)
|
|
1031
|
+
EGPTReal.fromBigInt(2n),
|
|
1032
|
+
EGPTReal.fromBigInt(3n)
|
|
1033
|
+
];
|
|
1034
|
+
const a = EGPTStat.comprehensiveStatisticalAnalysis(vs);
|
|
1035
|
+
return a instanceof EGPTStatData && a.total_count === 4;
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
return { suite: inputs.suite };
|
|
1039
|
+
</cell>
|
|
1040
|
+
|
|
1041
|
+
<cell type="markdown">
|
|
1042
|
+
## Phase 6.11 — Complex Number Syntactic Sugar
|
|
1043
|
+
|
|
1044
|
+
`EGPTReal.negate(x)` returns a new vector with the sign flipped. `ComplexEGPTReal` wraps
|
|
1045
|
+
two `EGPTReal` values (real + imaginary) and provides conjugate, scaling, magnitude-squared,
|
|
1046
|
+
and real/imaginary detection. The `conjugate()` method — which flips the sign of the
|
|
1047
|
+
imaginary part — is essential for IFFT twiddle-factor arithmetic.
|
|
1048
|
+
</cell>
|
|
1049
|
+
|
|
1050
|
+
<cell type="js" lane="math" id="phase611" in="suite" out="suite">
|
|
1051
|
+
const { tf, EGPTReal, EGPTMath, ComplexEGPTReal } = inputs.suite;
|
|
1052
|
+
|
|
1053
|
+
console.log("PHASE 6.11: Complex Number Syntactic Sugar");
|
|
1054
|
+
|
|
1055
|
+
const H_ZERO = EGPTReal.fromBigInt(0n);
|
|
1056
|
+
|
|
1057
|
+
tf.test("EGPTReal.negate(5) = -5", "Complex Sugar", () => {
|
|
1058
|
+
return EGPTReal.negate(EGPTReal.fromBigInt(5n))
|
|
1059
|
+
.breakSymbolicToApproximateBigInt() === -5n;
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
tf.test("EGPTReal.negate(√2) is negative", "Complex Sugar", () => {
|
|
1063
|
+
const neg = EGPTReal.negate(EGPTMath.sqrt(EGPTReal.fromBigInt(2n)));
|
|
1064
|
+
return EGPTMath.compare(neg, H_ZERO) < 0;
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
tf.test("EGPTReal.negate double negation: negate(negate(5)) = 5", "Complex Sugar", () => {
|
|
1068
|
+
const H5 = EGPTReal.fromBigInt(5n);
|
|
1069
|
+
return EGPTReal.negate(EGPTReal.negate(H5)).breakSymbolicToApproximateBigInt() === 5n;
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
tf.test("ComplexEGPTReal.negate(): -(3+4i) = -3-4i", "Complex Sugar", () => {
|
|
1073
|
+
const z = new ComplexEGPTReal(EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(4n));
|
|
1074
|
+
const neg = z.negate();
|
|
1075
|
+
return neg.real.breakSymbolicToApproximateBigInt() === -3n
|
|
1076
|
+
&& neg.imag.breakSymbolicToApproximateBigInt() === -4n;
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
tf.test("ComplexEGPTReal.conjugate(): conj(3+4i) = 3-4i", "Complex Sugar", () => {
|
|
1080
|
+
const z = new ComplexEGPTReal(EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(4n));
|
|
1081
|
+
const c = z.conjugate();
|
|
1082
|
+
return c.real.breakSymbolicToApproximateBigInt() === 3n
|
|
1083
|
+
&& c.imag.breakSymbolicToApproximateBigInt() === -4n;
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
tf.test("ComplexEGPTReal.conjugate() on scaled vectors: real positive, imag negative", "Complex Sugar", () => {
|
|
1087
|
+
const Hsqrt2 = EGPTMath.sqrt(EGPTReal.fromBigInt(2n));
|
|
1088
|
+
const z = new ComplexEGPTReal(Hsqrt2, Hsqrt2);
|
|
1089
|
+
const c = z.conjugate();
|
|
1090
|
+
return EGPTMath.compare(c.real, H_ZERO) > 0
|
|
1091
|
+
&& EGPTMath.compare(c.imag, H_ZERO) < 0;
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
tf.test("ComplexEGPTReal.conjugate() with rational: (1/2, 1/2)* = (1/2, -1/2)", "Complex Sugar", () => {
|
|
1095
|
+
const H_half = EGPTReal.fromRational(1n, 2n);
|
|
1096
|
+
const z = new ComplexEGPTReal(H_half, H_half);
|
|
1097
|
+
const c = z.conjugate();
|
|
1098
|
+
return c.real.equals(EGPTReal.fromRational(1n, 2n))
|
|
1099
|
+
&& c.imag.equals(EGPTReal.fromRational(-1n, 2n));
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
tf.test("ComplexEGPTReal.conjugate() double: conj(conj(z)) = z", "Complex Sugar", () => {
|
|
1103
|
+
const z = new ComplexEGPTReal(EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(-4n));
|
|
1104
|
+
return z.conjugate().conjugate().equals(z);
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
tf.test("IFFT pattern: (-2-2i) × conj(0+1i) = (-2+2i)", "Complex Sugar", () => {
|
|
1108
|
+
const value = new ComplexEGPTReal(EGPTReal.fromBigInt(-2n), EGPTReal.fromBigInt(-2n));
|
|
1109
|
+
const twiddle = new ComplexEGPTReal(EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(1n));
|
|
1110
|
+
const product = value.multiply(twiddle.conjugate());
|
|
1111
|
+
const expected = new ComplexEGPTReal(EGPTReal.fromBigInt(-2n), EGPTReal.fromBigInt(2n));
|
|
1112
|
+
return product.equals(expected);
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
tf.test("ComplexEGPTReal.scaleBy(5): (2+3i)*5 = (10+15i)", "Complex Sugar", () => {
|
|
1116
|
+
const z = new ComplexEGPTReal(EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n));
|
|
1117
|
+
const s = z.scaleBy(5n);
|
|
1118
|
+
return s.real.breakSymbolicToApproximateBigInt() === 10n
|
|
1119
|
+
&& s.imag.breakSymbolicToApproximateBigInt() === 15n;
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
tf.test("ComplexEGPTReal.scaleByRational(1/2): (6+8i)/2 = (3+4i)", "Complex Sugar", () => {
|
|
1123
|
+
const z = new ComplexEGPTReal(EGPTReal.fromBigInt(6n), EGPTReal.fromBigInt(8n));
|
|
1124
|
+
const s = z.scaleByRational(1n, 2n);
|
|
1125
|
+
return s.real.breakSymbolicToApproximateBigInt() === 3n
|
|
1126
|
+
&& s.imag.breakSymbolicToApproximateBigInt() === 4n;
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
tf.test("getMagnitudeSquared(): |3+4i|² = 25", "Complex Sugar", () => {
|
|
1130
|
+
const z = new ComplexEGPTReal(EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(4n));
|
|
1131
|
+
return z.getMagnitudeSquared().breakSymbolicToApproximateBigInt() === 25n;
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
tf.test("isReal() and isImaginary() detection", "Complex Sugar", () => {
|
|
1135
|
+
const zReal = new ComplexEGPTReal(EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(0n));
|
|
1136
|
+
const zImag = new ComplexEGPTReal(EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(5n));
|
|
1137
|
+
const zBoth = new ComplexEGPTReal(EGPTReal.fromBigInt(5n), EGPTReal.fromBigInt(1n));
|
|
1138
|
+
return zReal.isReal() && !zBoth.isReal()
|
|
1139
|
+
&& zImag.isImaginary() && !zBoth.isImaginary();
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
return { suite: inputs.suite };
|
|
1143
|
+
</cell>
|
|
1144
|
+
|
|
1145
|
+
<cell type="markdown">
|
|
1146
|
+
## Phase 7 — Complex Numbers and Riemann Zeta Function
|
|
1147
|
+
|
|
1148
|
+
`EGPTComplex` provides static methods for complex arithmetic (`complexAdd`, `complexMultiply`,
|
|
1149
|
+
`complexPower`) and the Riemann Zeta function approximation (`riemannZeta`). These operate
|
|
1150
|
+
over `ComplexEGPTReal` values.
|
|
1151
|
+
|
|
1152
|
+
`complexPower(n, s)` computes `n^s` for complex exponent `s`. When `s` is purely imaginary
|
|
1153
|
+
(`s = 0 + 2i`), the result lies on the unit circle — `|n^(it)|² ≈ 1`. The Riemann Zeta
|
|
1154
|
+
`ζ(2) = π²/6 ≈ 1.645` is verified with 100-term partial sum.
|
|
1155
|
+
</cell>
|
|
1156
|
+
|
|
1157
|
+
<cell type="js" lane="math" id="phase7" in="suite" out="suite">
|
|
1158
|
+
const { tf, EGPTReal, EGPTMath, ComplexEGPTReal, EGPTComplex } = inputs.suite;
|
|
1159
|
+
|
|
1160
|
+
console.log("PHASE 7: Complex Numbers and Riemann Zeta Function");
|
|
1161
|
+
|
|
1162
|
+
tf.test("ComplexEGPTReal creation and equality", "Complex Numbers", () => {
|
|
1163
|
+
const H2 = EGPTReal.fromBigInt(2n), H3 = EGPTReal.fromBigInt(3n);
|
|
1164
|
+
const z1 = new ComplexEGPTReal(H2, H3);
|
|
1165
|
+
const z2 = new ComplexEGPTReal(H2.clone(), H3.clone());
|
|
1166
|
+
const z3 = new ComplexEGPTReal(H3, H2);
|
|
1167
|
+
return z1.equals(z2) && !z1.equals(z3);
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
tf.test("EGPTComplex.complexAdd: (1+2i)+(3+4i) = (4+6i)", "Complex Algebra", () => {
|
|
1171
|
+
const z1 = new ComplexEGPTReal(EGPTReal.fromBigInt(1n), EGPTReal.fromBigInt(2n));
|
|
1172
|
+
const z2 = new ComplexEGPTReal(EGPTReal.fromBigInt(3n), EGPTReal.fromBigInt(4n));
|
|
1173
|
+
const result = EGPTComplex.complexAdd(z1, z2);
|
|
1174
|
+
const expected = new ComplexEGPTReal(EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(6n));
|
|
1175
|
+
return result.equals(expected);
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
tf.test("EGPTComplex.complexMultiply: (2+3i)*(4+5i) = -7+22i", "Complex Algebra", () => {
|
|
1179
|
+
const z1 = new ComplexEGPTReal(EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(3n));
|
|
1180
|
+
const z2 = new ComplexEGPTReal(EGPTReal.fromBigInt(4n), EGPTReal.fromBigInt(5n));
|
|
1181
|
+
const result = EGPTComplex.complexMultiply(z1, z2);
|
|
1182
|
+
const expected = new ComplexEGPTReal(EGPTReal.fromBigInt(-7n), EGPTReal.fromBigInt(22n));
|
|
1183
|
+
return result.equals(expected);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
tf.test("EGPTComplex.complexPower: 3^(0+2i) lies on unit circle (|result|²≈1)", "Complex Algebra", () => {
|
|
1187
|
+
const H3 = EGPTReal.fromBigInt(3n);
|
|
1188
|
+
const s = new ComplexEGPTReal(EGPTReal.fromBigInt(0n), EGPTReal.fromBigInt(2n));
|
|
1189
|
+
const result = EGPTComplex.complexPower(H3, s);
|
|
1190
|
+
const magSq = EGPTMath.add(
|
|
1191
|
+
EGPTMath.pow(result.real, 2n),
|
|
1192
|
+
EGPTMath.pow(result.imag, 2n)
|
|
1193
|
+
);
|
|
1194
|
+
const diff = EGPTMath.subtract(magSq, EGPTReal.fromBigInt(1n));
|
|
1195
|
+
return Math.abs(diff.breakSymbolicToApproximateJSNumber()) < 1e-9;
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
tf.test("EGPTComplex.riemannZeta(2) ≈ π²/6 ≈ 1.645 (100 terms)", "Riemann Zeta Function", () => {
|
|
1199
|
+
const s = new ComplexEGPTReal(EGPTReal.fromBigInt(2n), EGPTReal.fromBigInt(0n));
|
|
1200
|
+
const result = EGPTComplex.riemannZeta(s, 100);
|
|
1201
|
+
const val = result.real.breakSymbolicToApproximateJSNumber();
|
|
1202
|
+
return Math.abs(val - (Math.PI ** 2) / 6) < 0.01;
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
return { suite: inputs.suite };
|
|
1206
|
+
</cell>
|
|
1207
|
+
|
|
1208
|
+
<cell type="markdown">
|
|
1209
|
+
## Phase 9 — TwiddleTable: Phase-Based FFT Operations
|
|
1210
|
+
|
|
1211
|
+
`TwiddleTable(k)` pre-computes the k-th roots of unity `ω_j = e^(2πi·j/k)` as exact
|
|
1212
|
+
`ComplexEGPTReal` values. All FFT phase operations (`multiplyByPhase`, `powerByPhase`,
|
|
1213
|
+
`conjugateByPhase`) work as **integer index arithmetic modulo k** — no floating-point trig,
|
|
1214
|
+
no rounding, O(1) per operation.
|
|
1215
|
+
|
|
1216
|
+
This tests four FFT correctness requirements:
|
|
1217
|
+
1. `ω^k = ω₀` (periodicity) for k = 4, 8, 16, 4096
|
|
1218
|
+
2. Phase additivity: `ω^a × ω^b = ω^((a+b) mod k)`
|
|
1219
|
+
3. Special values: `ω₀=(1,0)`, `ω_{k/2}=(-1,0)`, `ω_{k/4}=(0,1)`
|
|
1220
|
+
4. Conjugate symmetry: `ω_j* = ω_{k-j}`
|
|
1221
|
+
</cell>
|
|
1222
|
+
|
|
1223
|
+
<cell type="js" lane="math" id="phase9" in="suite" out="suite">
|
|
1224
|
+
const { tf, EGPTReal, ComplexEGPTReal, TwiddleTable } = inputs.suite;
|
|
1225
|
+
|
|
1226
|
+
console.log("PHASE 9: TwiddleTable (Phase-Based FFT Operations)");
|
|
1227
|
+
|
|
1228
|
+
// A. Generation
|
|
1229
|
+
tf.test("TwiddleTable k=4: 4 twiddles", "Twiddle Generation", () => {
|
|
1230
|
+
const t = new TwiddleTable(4);
|
|
1231
|
+
return t.k === 4 && t.twiddles.size === 4;
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
tf.test("TwiddleTable k=8: 8 twiddles", "Twiddle Generation", () => {
|
|
1235
|
+
const t = new TwiddleTable(8);
|
|
1236
|
+
return t.k === 8 && t.twiddles.size === 8;
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
tf.test("TwiddleTable k=16: 16 twiddles", "Twiddle Generation", () => {
|
|
1240
|
+
const t = new TwiddleTable(16);
|
|
1241
|
+
return t.k === 16 && t.twiddles.size === 16;
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
tf.test("TwiddleTable k=4096: 4096 twiddles in under 5s", "Twiddle Generation", () => {
|
|
1245
|
+
const t = new TwiddleTable(4096);
|
|
1246
|
+
return t.k === 4096 && t.twiddles.size === 4096;
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
tf.test("Twiddle coordinates are EGPTReal instances", "Twiddle Generation", () => {
|
|
1250
|
+
const t = new TwiddleTable(8);
|
|
1251
|
+
const w1 = t.getTwiddle(1);
|
|
1252
|
+
return w1.real instanceof EGPTReal && w1.imag instanceof EGPTReal;
|
|
1253
|
+
});
|
|
1254
|
+
|
|
1255
|
+
// B. Phase operations
|
|
1256
|
+
tf.test("multiplyByPhase: ω₁ × ω₂ = ω₃ (k=8)", "Phase Operations", () => {
|
|
1257
|
+
return new TwiddleTable(8).multiplyByPhase(1, 2).index === 3;
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
tf.test("multiplyByPhase: ω₂ × ω₃ = ω₅ (k=8)", "Phase Operations", () => {
|
|
1261
|
+
return new TwiddleTable(8).multiplyByPhase(2, 3).index === 5;
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
tf.test("multiplyByPhase wraparound: ω₇ × ω₂ = ω₁ (k=8)", "Phase Operations", () => {
|
|
1265
|
+
return new TwiddleTable(8).multiplyByPhase(7, 2).index === 1;
|
|
1266
|
+
});
|
|
1267
|
+
|
|
1268
|
+
tf.test("powerByPhase: ω₁^2 = ω₂ (k=8)", "Phase Operations", () => {
|
|
1269
|
+
return new TwiddleTable(8).powerByPhase(1, 2).index === 2;
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
tf.test("powerByPhase: ω₂^3 = ω₆ (k=8)", "Phase Operations", () => {
|
|
1273
|
+
return new TwiddleTable(8).powerByPhase(2, 3).index === 6;
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
tf.test("conjugateByPhase: ω₁* = ω₇ (k=8)", "Phase Operations", () => {
|
|
1277
|
+
return new TwiddleTable(8).conjugateByPhase(1).index === 7;
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
tf.test("conjugateByPhase: ω₃* = ω₅ (k=8)", "Phase Operations", () => {
|
|
1281
|
+
return new TwiddleTable(8).conjugateByPhase(3).index === 5;
|
|
1282
|
+
});
|
|
1283
|
+
|
|
1284
|
+
// C. FFT Requirements
|
|
1285
|
+
tf.test("FFT Req 1: ω^k = ω₀ for all j (k=4)", "FFT Requirements", () => {
|
|
1286
|
+
const t = new TwiddleTable(4);
|
|
1287
|
+
for (let j = 0; j < 4; j++) if (t.powerByPhase(j, 4).index !== 0) return false;
|
|
1288
|
+
return true;
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
tf.test("FFT Req 1: ω^k = ω₀ for all j (k=8)", "FFT Requirements", () => {
|
|
1292
|
+
const t = new TwiddleTable(8);
|
|
1293
|
+
for (let j = 0; j < 8; j++) if (t.powerByPhase(j, 8).index !== 0) return false;
|
|
1294
|
+
return true;
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
tf.test("FFT Req 1: ω^k = ω₀ for all j (k=16)", "FFT Requirements", () => {
|
|
1298
|
+
const t = new TwiddleTable(16);
|
|
1299
|
+
for (let j = 0; j < 16; j++) if (t.powerByPhase(j, 16).index !== 0) return false;
|
|
1300
|
+
return true;
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
tf.test("FFT Req 1: ω^k = ω₀ sampled at k=4096", "FFT Requirements", () => {
|
|
1304
|
+
const t = new TwiddleTable(4096);
|
|
1305
|
+
for (const j of [0, 1, 2, 100, 1000, 2048, 4095]) {
|
|
1306
|
+
if (t.powerByPhase(j, 4096).index !== 0) return false;
|
|
1307
|
+
}
|
|
1308
|
+
return true;
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
tf.test("FFT Req 2: Phase additivity ω^a × ω^b = ω^((a+b) mod k) (k=16)", "FFT Requirements", () => {
|
|
1312
|
+
const t = new TwiddleTable(16);
|
|
1313
|
+
for (const {a, b, ex} of [{a:1,b:1,ex:2},{a:3,b:4,ex:7},{a:8,b:8,ex:0},{a:15,b:1,ex:0}]) {
|
|
1314
|
+
if (t.multiplyByPhase(a, b).index !== ex) return false;
|
|
1315
|
+
}
|
|
1316
|
+
return true;
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
tf.test("FFT Req 3: Special values ω₀=(1,0), ω₄=(-1,0), ω₂=(0,1) (k=8)", "FFT Requirements", () => {
|
|
1320
|
+
const t = new TwiddleTable(8);
|
|
1321
|
+
const one = EGPTReal.fromBigInt(1n), zero = EGPTReal.fromBigInt(0n), neg1 = EGPTReal.fromBigInt(-1n);
|
|
1322
|
+
const w0 = t.getTwiddle(0), w4 = t.getTwiddle(4), w2 = t.getTwiddle(2);
|
|
1323
|
+
return w0.real.equals(one) && w0.imag.equals(zero)
|
|
1324
|
+
&& w4.real.equals(neg1) && w4.imag.equals(zero)
|
|
1325
|
+
&& w2.real.equals(zero) && w2.imag.equals(one);
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
tf.test("FFT Req 4: Conjugate symmetry ω_j* = ω_{k-j} (k=16)", "FFT Requirements", () => {
|
|
1329
|
+
const t = new TwiddleTable(16);
|
|
1330
|
+
for (const j of [1, 2, 3, 5]) {
|
|
1331
|
+
if (t.conjugateByPhase(j).index !== (16 - j) % 16) return false;
|
|
1332
|
+
}
|
|
1333
|
+
return true;
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
// D. Integration
|
|
1337
|
+
tf.test("getPhaseIndex finds correct index", "Phase Integration", () => {
|
|
1338
|
+
const t = new TwiddleTable(8);
|
|
1339
|
+
return t.getPhaseIndex(t.getTwiddle(3)) === 3;
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
tf.test("Phase operations at k=4096: mult(1000,2000)=3000, pow(100,10)=1000, conj(1000)=3096", "Phase Integration", () => {
|
|
1343
|
+
const t = new TwiddleTable(4096);
|
|
1344
|
+
return t.multiplyByPhase(1000, 2000).index === 3000
|
|
1345
|
+
&& t.powerByPhase(100, 10).index === 1000
|
|
1346
|
+
&& t.conjugateByPhase(1000).index === 3096;
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
tf.test("k=4096 memory: first/mid/last twiddles are ComplexEGPTReal", "Performance", () => {
|
|
1350
|
+
const t = new TwiddleTable(4096);
|
|
1351
|
+
return t.getTwiddle(0) instanceof ComplexEGPTReal
|
|
1352
|
+
&& t.getTwiddle(2048) instanceof ComplexEGPTReal
|
|
1353
|
+
&& t.getTwiddle(4095) instanceof ComplexEGPTReal;
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
tf.test("k=4096 O(1) operations: 3000 phase ops complete quickly", "Performance", () => {
|
|
1357
|
+
const t = new TwiddleTable(4096);
|
|
1358
|
+
const start = Date.now();
|
|
1359
|
+
for (let i = 0; i < 1000; i++) {
|
|
1360
|
+
t.multiplyByPhase(i % 4096, (i * 2) % 4096);
|
|
1361
|
+
t.powerByPhase(i % 4096, 10);
|
|
1362
|
+
t.conjugateByPhase(i % 4096);
|
|
1363
|
+
}
|
|
1364
|
+
return (Date.now() - start) < 500;
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
return { suite: inputs.suite };
|
|
1368
|
+
</cell>
|
|
1369
|
+
|
|
1370
|
+
<cell type="markdown">
|
|
1371
|
+
## Final Summary
|
|
1372
|
+
|
|
1373
|
+
This cell prints the complete test summary across all phases. Each category line shows
|
|
1374
|
+
`passed/total`; the bottom line gives the overall count and success rate; any failed tests
|
|
1375
|
+
are listed with their error messages.
|
|
1376
|
+
</cell>
|
|
1377
|
+
|
|
1378
|
+
<cell type="js" lane="math" id="summary" in="suite">
|
|
1379
|
+
const { tf } = inputs.suite;
|
|
1380
|
+
const { total, passed, failed } = tf.printSummary();
|
|
1381
|
+
if (failed > 0) {
|
|
1382
|
+
throw new Error(`Suite failed: ${failed}/${total} tests did not pass`);
|
|
1383
|
+
}
|
|
1384
|
+
console.log("All tests passed.");
|
|
1385
|
+
</cell>
|
|
1386
|
+
|
|
1387
|
+
</frqtl-notebook>
|