@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,155 @@
1
+ <frqtl-notebook version="1" title="EGPT FFT — Polynomial Forward/Inverse Transform in Canonical Space">
2
+
3
+ <cell type="markdown">
4
+ # EGPT FFT — Polynomial Forward/Inverse Transform in Canonical Space
5
+
6
+ The `EGPTFFT` class is the pedagogical entry point to EGPT's transform discipline.
7
+ Where a classical FFT works in floating-point complex arithmetic (`e^{2πik/N}` twiddles, `sin`/`cos` calls), the EGPT formulation stays entirely in **rational canonical space**:
8
+
9
+ - **Forward transform** — Horner-evaluate the coefficient polynomial `P(x)` at the `N` equally-spaced rational nodes `x_k = k/N` for `k = 0, 1, …, N−1`.
10
+ - **Inverse transform** — recover the original coefficients from those N sample values via Newton divided differences.
11
+
12
+ Both operations are **O(N²)** in exact `EGPTReal` arithmetic. No `Math.sin`, no `Math.cos`, no floating-point rounding. The round-trip `inverse(forward(c)) ≡ c` is a structural fact proved in the theorem file `F_FFTPolynomialIsomorphism.js`, not a numerical approximation.
13
+
14
+ Every cell below computes through the injected `math` builtin. No URL imports.
15
+ </cell>
16
+
17
+ <cell type="js" lane="math" id="backend">
18
+ // Show the active math backend (truth-in-labeling: derived, never asserted).
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. Build the input — three integer coefficients
26
+
27
+ We start with the polynomial `P(x) = 1 + 2x + 3x²` represented as an array of
28
+ `EGPTReal` values. `EGPTReal.fromBigInt(n)` constructs the exact canonical
29
+ representation of the integer `n` (no floating-point, no approximation).
30
+ </cell>
31
+
32
+ <cell type="js" lane="math" id="build-coeffs" out="coeffs">
33
+ const { math, display } = caps;
34
+ const { EGPTReal } = math;
35
+
36
+ // P(x) = 1 + 2x + 3x²
37
+ const coeffs = [
38
+ EGPTReal.fromBigInt(1n),
39
+ EGPTReal.fromBigInt(2n),
40
+ EGPTReal.fromBigInt(3n)
41
+ ];
42
+
43
+ display('Coefficients (toMathString): ' + coeffs.map(c => c.toMathString()).join(', '));
44
+ return { coeffs };
45
+ </cell>
46
+
47
+ <cell type="markdown">
48
+ ## 2. Forward transform — evaluate at rational nodes 0/3, 1/3, 2/3
49
+
50
+ `EGPTFFT.forward(coeffs, N)` evaluates `P(x)` at each of the `N` nodes `k/N`
51
+ using Horner's method in canonical space:
52
+
53
+ ```
54
+ P(0/3) = 1 + 2·(0) + 3·(0)² = 1
55
+ P(1/3) = 1 + 2·(1/3) + 3·(1/3)² = 1 + 2/3 + 1/3 = 2
56
+ P(2/3) = 1 + 2·(2/3) + 3·(2/3)² = 1 + 4/3 + 4/3 = 11/3
57
+ ```
58
+
59
+ These are exact rational results — no approximation.
60
+ </cell>
61
+
62
+ <cell type="js" lane="math" id="forward" in="coeffs" out="forward">
63
+ const { math, display } = caps;
64
+ const { EGPTFFT } = math;
65
+ const { coeffs } = inputs;
66
+
67
+ const forward = EGPTFFT.forward(coeffs, 3);
68
+
69
+ display('Forward transform values at k/3 (toMathString):');
70
+ forward.forEach((v, k) => {
71
+ display(` P(${k}/3) = ${v.toMathString()}`);
72
+ });
73
+
74
+ return { forward };
75
+ </cell>
76
+
77
+ <cell type="markdown">
78
+ ## 3. Inverse transform — recover the original coefficients
79
+
80
+ `EGPTFFT.inverse(values, N)` runs Newton divided differences on the N sample values
81
+ and reconstructs the polynomial coefficient vector. The result must be
82
+ bit-identical to the original `[1, 2, 3]` — not approximately equal, **exactly equal**
83
+ in `EGPTReal` canonical arithmetic.
84
+ </cell>
85
+
86
+ <cell type="js" lane="math" id="inverse" in="forward" out="inverse">
87
+ const { math, display } = caps;
88
+ const { EGPTFFT } = math;
89
+ const { forward } = inputs;
90
+
91
+ const inverse = EGPTFFT.inverse(forward, 3);
92
+
93
+ display('Recovered coefficients (toMathString):');
94
+ inverse.forEach((c, i) => {
95
+ display(` c[${i}] = ${c.toMathString()}`);
96
+ });
97
+
98
+ return { inverse };
99
+ </cell>
100
+
101
+ <cell type="markdown">
102
+ ## 4. Round-trip verification
103
+
104
+ The original polynomial was `[1, 2, 3]`. After `forward` then `inverse` we expect
105
+ to get exactly `["1", "2", "3"]` from `toMathString()`. Any deviation would be a
106
+ violation of the polynomial bijection theorem `F2: inverse ∘ forward ≡ identity`.
107
+ </cell>
108
+
109
+ <cell type="js" lane="math" id="verify" in="inverse">
110
+ const { math, display } = caps;
111
+ const { inverse } = inputs;
112
+
113
+ const expected = ['1', '2', '3'];
114
+ const got = inverse.map(c => c.toMathString());
115
+
116
+ const ok = got.length === expected.length &&
117
+ got.every((v, i) => v === expected[i]);
118
+
119
+ const el = document.createElement('div');
120
+ el.style.cssText =
121
+ 'font:600 0.95rem/1.5 system-ui,sans-serif;padding:10px 14px;border-radius:6px;margin:4px 0;' +
122
+ (ok
123
+ ? 'background:#0f2417;border:1px solid #1f5a36;color:#7ee2a8;'
124
+ : 'background:#2a0c0c;border:1px solid #5a1f1f;color:#ff8a8a;');
125
+ el.textContent = ok
126
+ ? `ROUND-TRIP VERIFIED: inverse(forward([1,2,3])) = [${got.join(', ')}] — bit-exact.`
127
+ : `MISMATCH: expected [${expected.join(', ')}], got [${got.join(', ')}]`;
128
+
129
+ display(el);
130
+
131
+ if (!ok) {
132
+ throw new Error('FFT forward/inverse roundtrip failed');
133
+ }
134
+ </cell>
135
+
136
+ <cell type="markdown">
137
+ ## 5. What makes this different from a classical FFT?
138
+
139
+ | | Classical FFT | EGPT FFT |
140
+ |---|---|---|
141
+ | Twiddle factors | `e^{2πik/N}` — transcendental, computed via `sin`/`cos` | `k/N` — exact rational nodes, no transcendentals |
142
+ | Arithmetic domain | Complex floating-point (`float64`) | Canonical `EGPTReal` (exact BigInt rationals) |
143
+ | Round-trip error | Floating-point accumulation (`~1e-15`) | Zero — `inverse(forward(c))` is exactly `c` |
144
+ | Complexity | `O(N log N)` via Cooley-Tukey twiddle caching | `O(N²)` Horner + Newton DD in rational space |
145
+ | Purpose | Signal processing via approximation | Polynomial bijection — transform as exact algebraic operation |
146
+
147
+ The EGPT FFT is not competing with Cooley-Tukey on wall-clock speed for large N.
148
+ Its role is to make the polynomial ↔ transform bijection visible and provable:
149
+ evaluating `P` at `N` nodes and recovering `P` from those values is a bijection —
150
+ `inverse ∘ forward = identity` — with no approximation involved.
151
+ This is the foundation for the CNF ↔ polynomial isomorphism (BIPP theorem)
152
+ and the matrix ↔ ℕ chain (Translation1–7).
153
+ </cell>
154
+
155
+ </frqtl-notebook>
@@ -0,0 +1,207 @@
1
+ <frqtl-notebook version="1" title="A Quantum Computer That Runs in Your Browser — FRQTL QFT Benchmark">
2
+
3
+ <cell type="markdown">
4
+ # A Quantum Computer That Runs in Your Browser
5
+
6
+ **White Paper:** *Logarithmic Root Finding — A Deterministic, EGPT-Native, efficiently and classically computable QFT.* E. Abadir, Electronic Graph Paper Theory (EGPT) Research Group.
7
+
8
+ Shor's factoring algorithm has three stages: classical setup, **the Quantum Fourier Transform** (the one step believed to need quantum hardware), and classical post-processing. This notebook computes that QFT step **deterministically, classically, in this browser tab** — and benchmarks it head-to-head against a published large-scale supercomputer Shor simulation.
9
+
10
+ Every cell below reaches its math through one injected capability — `math` — and imports nothing. `math` is the live FRQTL math SDK the IDE resolved; the backend that actually executes is reported by the SDK itself, never asserted.
11
+ </cell>
12
+
13
+ <cell type="js" lane="math" id="backend">
14
+ // The ONLY way a cell gets compute: ask the injected builtin BY NAME.
15
+ // activeMathBackend is a DERIVED field — it reports whatever
16
+ // MathBackendRegistry.active() is (wasm-math under audience='public').
17
+ const { math, display } = caps;
18
+ const backend = math.activeMathBackend;
19
+ display(`Live math backend (derived from the SDK): ${backend}`);
20
+ </cell>
21
+
22
+ <cell type="markdown">
23
+ ## 1. Reframing the QFT in information space
24
+
25
+ Classical statevector simulation of the QFT scales as `O(2^n)` memory and `O(n·2^n)` operations — the exponential wall a supercomputer hit at 39 bits. EGPT sidesteps statevector simulation entirely: a number `k` is bijective to its information vector `H(k) = log2(k)`, and the RET Iron Law gives `H(p×q) = H(p) + H(q)`. Period extraction becomes a deterministic operation in lossless information space, not a search over a `2^n` Hilbert space.
26
+ </cell>
27
+
28
+ <cell type="markdown">
29
+ ## 2. The Logarithmic Root Finding algorithm
30
+
31
+ Two quantum steps are replaced by deterministic EGPT analogues:
32
+
33
+ - **Superposition → logarithmic decomposition.** Recursively apply `log2` to `H(k)` for `n = ceil(log2 k)` steps, distilling `L_final = H(H(...H(k)...))`.
34
+ - **QFT → deterministic period extraction.** The order is read directly as `r ~ floor(H(k) / L_final)`, then probed in a small even neighborhood.
35
+ - **Factor extraction (classical Shor tail).** Compute `y = a^(r/2) mod k`; recover factors via `gcd(y±1, k)` (Pollard p-1 packaged in refinement).
36
+
37
+ Complexity: `O((log k)^3)` — polynomial in the bit length, where statevector simulation is exponential.
38
+ </cell>
39
+
40
+ <cell type="markdown">
41
+ ## 3. The benchmark baseline — a published supercomputer result
42
+
43
+ We benchmark against the largest published statevector simulation of Shor's algorithm. All figures below are read from the SDK's single baseline authority (`math.benchmarks.qftBaseline`) — this notebook inlines no numbers.
44
+ </cell>
45
+
46
+ <cell type="js" lane="math" id="baseline">
47
+ // Render the published baseline FROM THE SINGLE AUTHORITY.
48
+ // Reads math.benchmarks.qftBaseline by name; FAIL-LOUD if absent. No literal.
49
+ const { math, display } = caps;
50
+ const b = math.benchmarks && math.benchmarks.qftBaseline;
51
+ if (!b) {
52
+ throw new Error(
53
+ '[notebook] math.benchmarks.qftBaseline is absent — the benchmark must ' +
54
+ 'not narrate against a missing baseline. The figures live in ONE authority ' +
55
+ '(qft-benchmark-baseline.js), surfaced on the SDK as math.benchmarks.qftBaseline. ' +
56
+ '(FAIL-LOUD — never an inlined literal, never a silent blank.)'
57
+ );
58
+ }
59
+ const c = b.citation;
60
+ const lines = [
61
+ `Published result: ${c.authors}`,
62
+ ` "${c.title}." ${c.venue}, ${c.year}. DOI: ${c.doi}`,
63
+ `Hardware: ${b.hardware.system}`,
64
+ ` ${b.hardware.gpus}, ${b.hardware.memory}`,
65
+ `What was computed: ${b.whatWasComputed}`,
66
+ `Total study compute: ${b.studyCompute.gpuYears} GPU-years ` +
67
+ `(${b.studyCompute.coreYears} core-years)`,
68
+ `Benchmark run: N=${b.benchmarkRun.N} = ${b.benchmarkRun.factors.join(' x ')} ` +
69
+ `(${b.benchmarkRun.bits}-bit) — ~${b.benchmarkRun.shorGpuSeconds}s per run on the supercomputer`
70
+ ];
71
+ display(lines.join('\n'));
72
+ </cell>
73
+
74
+ <cell type="markdown">
75
+ ## 4. Run it here — the same computation, in your browser
76
+
77
+ The next cell drives the **same** `FraqtlSession` the catalog benchmark entry drives (`math.FraqtlSession.auto()` → `session.run(N)`), on the same math backend, through the same seam. The factors it returns are bit-identical to the entry's. We time the live run with `performance.now()` (the human-facing wall-clock — never part of any byte-stable comparison).
78
+ </cell>
79
+
80
+ <cell type="js" lane="math" id="run" out="run">
81
+ // THE DOGFOOD: drive the SAME computation as the catalog entry.
82
+ // math.FraqtlSession.auto() is the exact object the entry's run(sdk) uses.
83
+ const { math, display } = caps;
84
+ const b = math.benchmarks.qftBaseline;
85
+ // N comes from the baseline authority's benchmarkRun — the SAME semiprime the
86
+ // supercomputer factored. No inlined literal (value lives in the authority).
87
+ const N = b.benchmarkRun.N;
88
+ const session = math.FraqtlSession.auto();
89
+
90
+ const t0 = performance.now();
91
+ const result = session.run(N); // identical path to the entry
92
+ const elapsedMs = (typeof result.elapsed_ms === 'number')
93
+ ? result.elapsed_ms
94
+ : (performance.now() - t0);
95
+
96
+ const run = {
97
+ N,
98
+ factors: result.factors,
99
+ successful: result.successful,
100
+ post_reason: result.post_reason,
101
+ elapsedMs,
102
+ backend: math.activeMathBackend // DERIVED
103
+ };
104
+ display(run);
105
+ return { run };
106
+ </cell>
107
+
108
+ <cell type="js" lane="math" id="verify" in="run">
109
+ // The AC assertion: factors match the baseline authority's factors,
110
+ // bit-identical to the catalog entry. Renders PASS/FAIL plainly.
111
+ const { math, display } = caps;
112
+ const run = inputs.run;
113
+ const b = math.benchmarks.qftBaseline;
114
+ const expected = b.benchmarkRun.factors; // from the single authority
115
+ const got = (run.factors || []).slice().sort((x, y) => x - y);
116
+ const want = expected.slice().sort((x, y) => x - y);
117
+ const ok = got.length === want.length && got.every((v, i) => v === want[i]);
118
+
119
+ const el = document.createElement('div');
120
+ el.style.cssText =
121
+ 'font:600 0.95rem/1.5 system-ui,sans-serif;padding:10px 14px;border-radius:6px;margin:4px 0;' +
122
+ (ok
123
+ ? 'background:#0f2417;border:1px solid #1f5a36;color:#7ee2a8;'
124
+ : 'background:#2a0c0c;border:1px solid #5a1f1f;color:#ff8a8a;');
125
+ el.textContent = ok
126
+ ? `FACTORS VERIFIED on ${run.backend}: ${run.N} = ${run.factors.join(' x ')} ` +
127
+ `— bit-identical to the catalog benchmark entry and to the supercomputer's result.`
128
+ : `MISMATCH: got [${run.factors}], expected [${expected}] on ${run.backend}.`;
129
+ display(el);
130
+ </cell>
131
+
132
+ <cell type="js" lane="math" id="comparison" in="run">
133
+ // THE COMPARISON BAR + LIVE WALL-CLOCK. Baseline figures read from
134
+ // math.benchmarks.qftBaseline ONLY. Wall-clock is the TIMING channel
135
+ // (human-facing, excluded from comparison). DOM built directly.
136
+ const { math, display } = caps;
137
+ const run = inputs.run;
138
+ const b = math.benchmarks.qftBaseline;
139
+ const coreYears = b.studyCompute.coreYears;
140
+ const gpuYears = b.studyCompute.gpuYears;
141
+ const shorSecs = b.benchmarkRun.shorGpuSeconds; // supercomputer s/run
142
+ const bits = b.benchmarkRun.bits;
143
+ const browserMs = run.elapsedMs; // live wall-clock (TIMING)
144
+ const browserSecs = browserMs / 1000;
145
+
146
+ const speedup = shorSecs / Math.max(browserSecs, 1e-9);
147
+
148
+ const wrap = document.createElement('div');
149
+ wrap.style.cssText = 'font:0.85rem/1.4 system-ui,sans-serif;color:#ddd;margin:6px 0;max-width:680px;';
150
+
151
+ const head = document.createElement('div');
152
+ head.style.cssText = 'font-weight:600;color:#fff;margin-bottom:8px;font-size:0.95rem;';
153
+ head.textContent = `${bits}-bit QFT period extraction — wall-clock, this run vs. the supercomputer`;
154
+ wrap.appendChild(head);
155
+
156
+ function bar(label, valueText, fillPct, color) {
157
+ const row = document.createElement('div');
158
+ row.style.cssText = 'margin:6px 0;';
159
+ const lab = document.createElement('div');
160
+ lab.style.cssText = 'display:flex;justify-content:space-between;margin-bottom:2px;';
161
+ const l = document.createElement('span'); l.textContent = label;
162
+ const v = document.createElement('span'); v.style.color = '#aaa'; v.textContent = valueText;
163
+ lab.appendChild(l); lab.appendChild(v); row.appendChild(lab);
164
+ const track = document.createElement('div');
165
+ track.style.cssText = 'background:#1a1a1a;border-radius:4px;height:18px;overflow:hidden;';
166
+ const fill = document.createElement('div');
167
+ fill.style.cssText =
168
+ `background:${color};height:100%;width:${Math.max(fillPct, 0.6)}%;border-radius:4px;transition:width .3s;`;
169
+ track.appendChild(fill); row.appendChild(track);
170
+ return row;
171
+ }
172
+
173
+ const maxLog = Math.log10(Math.max(shorSecs, browserSecs, 1) + 1);
174
+ const shorPct = (Math.log10(shorSecs + 1) / maxLog) * 100;
175
+ const browserPct = (Math.log10(browserSecs + 1) / maxLog) * 100;
176
+
177
+ wrap.appendChild(bar(
178
+ `Supercomputer (${b.hardware.gpus})`,
179
+ `~${shorSecs}s/run`, shorPct, '#c0584f'
180
+ ));
181
+ wrap.appendChild(bar(
182
+ `This browser tab (${run.backend})`,
183
+ `~${browserSecs < 1 ? browserMs.toFixed(0) + 'ms' : browserSecs.toFixed(2) + 's'}`,
184
+ browserPct, '#4f9fc0'
185
+ ));
186
+
187
+ const foot = document.createElement('div');
188
+ foot.style.cssText = 'margin-top:10px;color:#bbb;font-size:0.8rem;line-height:1.5;';
189
+ foot.innerHTML =
190
+ `Per-run wall-clock speedup on this hardware: <b style="color:#7ee2a8;">~${Math.round(speedup).toLocaleString()}x</b>. ` +
191
+ `The published study consumed <b>${gpuYears} GPU-years (${coreYears} core-years)</b> of compute; ` +
192
+ `this run finished in <b>${browserSecs < 1 ? browserMs.toFixed(0) + ' ms' : browserSecs.toFixed(2) + ' s'}</b> ` +
193
+ `on one browser tab. <span style="color:#888;">(Live wall-clock — the TIMING channel, human-facing, excluded from any byte-stable comparison.)</span>`;
194
+ wrap.appendChild(foot);
195
+
196
+ display(wrap);
197
+ </cell>
198
+
199
+ <cell type="markdown">
200
+ ## If the QFT is classically efficient, "quantum advantage" evaporates
201
+
202
+ The factorization above ran the QFT period-extraction step — the one part of Shor's algorithm believed to require a quantum computer — deterministically, in polynomial time, in this browser tab. The classical setup and post-processing stages are common to both paths. With the QFT step neutralized, the relevant factoring frontier is classical (GNFS and friends), which remains informationally near-optimal. Internet security does not rest on the unavailability of qubit hardware.
203
+
204
+ *Same computation, two surfaces:* this notebook and the catalog benchmark entry drive the identical `FraqtlSession` through the identical shim seam — the factors are bit-identical. Reference: Willsch et al., *Mathematics* 2023, 11, 4222 (see the baseline cell for the full citation, surfaced from the SDK).
205
+ </cell>
206
+
207
+ </frqtl-notebook>
@@ -0,0 +1,51 @@
1
+ <frqtl-notebook version="1" title="Atomic Model — stable orbits without quantum numbers">
2
+
3
+ <cell type="markdown">
4
+ # Atomic Model
5
+
6
+ **Stable orbits emerge — no electron shells, no quantum numbers.**
7
+
8
+ Particles collide and merge into stable bound structures that persist for thousands of ticks. There are no electron shells, no principal quantum numbers, no Bohr radius — only leaf Frames making local greedy choices and the single-occupancy collision rule.
9
+
10
+ **Why this is impossible (classically):** Stable atomic orbits require quantized energy levels — continuous mechanics predicts spiral decay (the classical electron should radiate and crash into the nucleus). Here the bound structures stay stable because the discrete 1-pixel-per-tick rule and emergent momentum conservation forbid the spiral.
11
+
12
+ The experiment setup is **real, editable user code**: the module cell `./setups/atomic-model.js` is a thin adapter over the CANONICAL setup factory (`lib/frqtl/objects/setup/setupAtomicModel.js`, the SAME construction the standalone Gallery exhibit and any experiment page drive) — it builds the proton/atom frame hierarchy and the orbiting electron from `Frame`/`Charge`/`Rectangle`. The **canvas cell** below DECLARES that module (`setup="./setups/atomic-model.js#setupAtomicModel"`) plus its config; the shim synthesizes and runs the builder boilerplate. Nothing runs on load — click **Run** on the canvas (or **Run All**).
13
+
14
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
15
+
16
+ **Edit the physics:** open the `./setups/atomic-model.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `Object.assign({ canvasRect: universe.universe_rect }, options)` call to `Object.assign({ canvasRect: universe.universe_rect, quarksPerProton: 12, includeElectron: false }, options)` — then re-Run. The emergent bound structure changes because you edited the construction, not a label.
17
+ </cell>
18
+
19
+ <cell type="module" name="./setups/atomic-model.js">
20
+ /* setupAtomicModel — THIN ADAPTER over the canonical setup factory
21
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
22
+ * a divergent fork of lib/frqtl/objects/setup/setupAtomicModel.js that had
23
+ * already drifted onto a stale `universe.init(...)` positional-argument call the
24
+ * engine now FAIL-LOUDs on, and was missing the canonical `noObserverFrame: true`
25
+ * init option. The canonical factory is imported by BARE SPECIFIER (a relative
26
+ * path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js); this
27
+ * cell only bridges the notebook builder's `(frqtl, universe, options)` call
28
+ * shape to the factory's `(universe, options)` shape — ZERO physics here. The
29
+ * canonical factory reads `options.canvasRect`, not `universe.universe_rect`
30
+ * directly, so this adapter supplies it explicitly (matching the factory's own
31
+ * documented two-cell example).
32
+ */
33
+ import { setupAtomicModel as _setupAtomicModel } from '@frqtl/setups/atomic-model';
34
+
35
+ export function setupAtomicModel(frqtl, universe, options) {
36
+ options = options || {};
37
+ return _setupAtomicModel(universe, Object.assign({ canvasRect: universe.universe_rect }, options));
38
+ }
39
+ </cell>
40
+
41
+ <cell type="canvas" id="c-atom-canvas" setup="./setups/atomic-model.js#setupAtomicModel" stage="480x480" seed="42"></cell>
42
+
43
+ <cell type="markdown">
44
+ ## What you are seeing
45
+
46
+ A dense central structure (the "nucleus") forms as particles merge, with lighter quanta settling into persistent surrounding orbits rather than collapsing inward. The stability is emergent — no force law holds the orbit together.
47
+
48
+ The simulation runs live in your browser on the compiled FRQTL (WASM) engine. The same canonical sugar objects (`Frame`, `Charge`, `Rectangle`) and `ExperimentRunner` drive the standalone Gallery exhibit and this notebook cell — the difference is only that here the *assembly* is editable user code in the `./setups/atomic-model.js` tab, not an opaque system fetch.
49
+ </cell>
50
+
51
+ </frqtl-notebook>
@@ -0,0 +1,62 @@
1
+ <frqtl-notebook version="1" title="Big Bang — structure from nothing, no gravity law">
2
+
3
+ <cell type="markdown">
4
+ # Big Bang
5
+
6
+ **Large-scale structure — filaments, voids, bound clumps — from a uniform particle field, with no gravity law anywhere.**
7
+
8
+ A single radial point source fires quanta with zero initial velocity. Every outward movement is emergent: `emergentPhysics = true` means the engine uses top-down frame generation (Phase B `buildFramesFromSprites`) and Brownian motion, not directed launch vectors. Filaments and voids are a consequence of single-occupancy + the recursive compress nudge, nothing else.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ The experiment assembly — a single radial `PointSource` at canvas center — as editable user code:
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/big-bang.js">
18
+ /* setupBigBang — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
20
+ * a divergent fork of lib/frqtl/objects/setup/setupBigBang.js that had already
21
+ * drifted onto a stale `universe.init(...)` positional-argument call the engine
22
+ * now FAIL-LOUDs on. The canonical factory is imported by BARE SPECIFIER (a
23
+ * relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js);
24
+ * this cell only bridges the notebook builder's `(frqtl, universe, options)` call
25
+ * shape to the factory's `(universe, options)` shape — ZERO physics here.)
26
+ */
27
+ import { setupBigBang as _setupBigBang } from '@frqtl/setups/big-bang';
28
+
29
+ export function setupBigBang(frqtl, universe, options) {
30
+ return _setupBigBang(universe, options);
31
+ }
32
+ </cell>
33
+
34
+ <cell type="markdown">
35
+ Declare a canvas that runs it. `setup="<module>#<export>"` + `stage`/`seed`; the shim synthesizes and runs the builder boilerplate in the realm. Click **Run** (or **Run All**):
36
+ </cell>
37
+
38
+ <cell type="canvas" id="c-bb-canvas" setup="./setups/big-bang.js#setupBigBang" stage="480x480" seed="42"></cell>
39
+
40
+ <cell type="markdown">
41
+ ## What you are seeing
42
+
43
+ An initially smooth particle field develops texture: dense filaments thread between emptier voids, and bound clumps condense — the cosmic-web morphology — with no force equation driving the collapse. No Newtonian gravity, no `G`, no cosmological constant.
44
+
45
+ **`lightSourceDiameter` is the primary knob.** It sets the outer radius of the emission ring. Because `minRadius: 2` fills inward, the total emitter count scales as `(radius / 2) × 72` (at the default 5° increment). Larger diameter → more initial quanta → larger emergent explosion:
46
+
47
+ | `lightSourceDiameter` | Active quanta (~50 frames) | Field |
48
+ |---|---|---|
49
+ | 16 | ~21,000 | Tight compact cluster, few emergent Frame circles |
50
+ | **64** (default) | ~79,000 | Well-developed explosion, prominent Frame hierarchy |
51
+ | 128 | ~157,000 | Very large expansion; stack overflow observed at init (2k+ emitters) |
52
+
53
+ The full sweep with screenshots is in [`docs/physics/big-bang-lightSourceDiameter.md`](../../docs/physics/big-bang-lightSourceDiameter.md).
54
+
55
+ **`dispersionAngleIncrement`** (default 5°) sets the angular resolution of the ring: 5° = 72 rays, 10° = 36 rays. Larger values produce discrete spokes in the initial field.
56
+
57
+ **`emergentPhysics = true` is the mode switch.** Setting it `false` disables top-down frame generation — the expansion collapses because there are no directed launch vectors to carry particles outward.
58
+
59
+ **Edit the physics:** open the `./setups/big-bang.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `_setupBigBang(universe, options)` call to `_setupBigBang(universe, Object.assign({ lightSourceDiameter: 32 }, options))` (also try `dispersionAngleIncrement` or `maxTicks`) — then re-Run. The emergent structure changes because you edited the construction. (The physics body itself lives in the canonical `lib/frqtl/objects/setup/setupBigBang.js` — this cell is a thin, engine-agnostic adapter over it.) The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
60
+ </cell>
61
+
62
+ </frqtl-notebook>
@@ -0,0 +1,52 @@
1
+ <frqtl-notebook version="1" title="Blackbody — the Planck curve from collisions">
2
+
3
+ <cell type="markdown">
4
+ # Blackbody Radiation
5
+
6
+ **The Planck curve emerges from collisions — no energy quanta assumed.**
7
+
8
+ Particles bounce in a walled cavity. The frequency histogram converges to the Planck distribution. No discrete energy quanta, no Planck's constant inserted — the quantization is a consequence of the discrete pixel/tick lattice. Classically this is supposed to produce the Rayleigh-Jeans divergence (infinite energy at high frequencies); the discrete lattice cuts it off and yields the Planck curve instead.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ Bounce-walled oven cavity with thermostat — editable user code:
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/blackbody.js">
18
+ /* setupBlackbody — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
20
+ * a divergent fork of lib/frqtl/objects/setup/setupBlackbody.js that had
21
+ * already drifted onto a stale `universe.init(...)` positional-argument call the
22
+ * engine now FAIL-LOUDs on. The canonical factory is imported by BARE SPECIFIER
23
+ * (a relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js);
24
+ * this cell only bridges the notebook builder's `(frqtl, universe, options)` call
25
+ * shape to the factory's `(universe, options)` shape — ZERO physics here.)
26
+ */
27
+ import { setupBlackbody as _setupBlackbody } from '@frqtl/setups/blackbody';
28
+
29
+ export function setupBlackbody(frqtl, universe, options) {
30
+ return _setupBlackbody(universe, options);
31
+ }
32
+ </cell>
33
+
34
+ <cell type="markdown">
35
+ Declare a canvas that runs it. `setup="<module>#<export>"` + `stage`/`seed`; the shim synthesizes and runs the builder boilerplate in the realm. Click **Run** (or **Run All**):
36
+ </cell>
37
+
38
+ <cell type="canvas" id="c-bb-canvas" setup="./setups/blackbody.js#setupBlackbody" stage="480x480" seed="42"></cell>
39
+
40
+ <cell type="markdown">
41
+ ## What you are seeing
42
+
43
+ Particles bounce within the cavity, exchanging momentum on every collision. Energy redistributes across the population until the frequency distribution stabilizes — the emergent shape matches the Planck curve, not the diverging Rayleigh-Jeans prediction.
44
+
45
+ **`temperature` is the driving knob.** It sets the thermostat's target `activeQuanta` count. The thermostat emits `floor((temperature - activeQuanta) / 4)` new leaf Frames per emitter per tick until the target is met, then silences all emitters that tick — a discrete proportional controller over quanta count. Raising `temperature` 300 → 4000 densifies the cavity from sparse scattered leaf dots to a near-saturated mass, increases compound-frame (non-leaf, merged) formation dramatically, and widens the escaped-radiation stream through the slit in both volume and angular spread. The captured sweep is in [`docs/physics/blackbody-temperature.md`](../../docs/physics/blackbody-temperature.md).
46
+
47
+ Note: `temperature` is NOT energy or kinetic temperature in the continuous-mechanics sense — it is the integer target for `universe.activeQuanta`. The per-Frame oscillation wavelength (`wavelength = floor((capacity / mass) × WAVELENGTH_CONSTANT)`, Core Axiom §6) is unchanged by `temperature` directly; it is determined by the mass of each Frame, which grows as frames merge via collisions. Higher temperature → more collisions → larger compound frames → shorter oscillation wavelengths — the FRAQTL analog of Wien's displacement.
48
+
49
+ **Edit the physics:** open the `./setups/blackbody.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `_setupBlackbody(universe, options)` call to `_setupBlackbody(universe, Object.assign({ temperature: 3000 }, options))` (also try `boxFraction` or `slitHeight`) — then re-Run. The emergent frequency spectrum changes because you edited the construction, not a label. (The physics body itself lives in the canonical `lib/frqtl/objects/setup/setupBlackbody.js` — this cell is a thin, engine-agnostic adapter over it, so every other notebook and experiment page drives the SAME construction.) The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
50
+ </cell>
51
+
52
+ </frqtl-notebook>
@@ -0,0 +1,104 @@
1
+ <frqtl-notebook version="1" title="Circuit SAT — the circuit finds its own satisfying assignment">
2
+
3
+ <cell type="markdown">
4
+ # Circuit SAT
5
+
6
+ **A half-adder circuit evaluates itself — particle density, not a search algorithm, selects the truth-table row.**
7
+
8
+ Leaf Frames flow through wire channels. Density-activated gates (XOR → SUM, AND → CARRY) open and close as quanta accumulate in their control regions. The circuit settles on the correct half-adder output for whatever `(inputA, inputB)` pair you set — with no DPLL, no backtracking, no enumeration of assignments.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ Wire/battery/resistor primitives — the reusable building blocks:
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/circuit-basic.js">
18
+ /* createWire / createBattery / createResistor / setupCircuitBasic — THIN
19
+ * ADAPTERS over the canonical primitives
20
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
21
+ * a divergent fork of lib/frqtl/objects/setup/setupCircuitBasic.js that had
22
+ * already drifted onto a stale `universe.init(...)` positional-argument call
23
+ * the engine now FAIL-LOUDs on. The canonical primitives are imported by BARE
24
+ * SPECIFIER (a relative path here would 404 — see
25
+ * lib/shim/notebook/frqtl-setups-importmap.js); these wrappers only bridge this
26
+ * notebook's `(frqtl, universe, ...)` calling convention (matching every other
27
+ * setup module here) to the canonical `(universe, ...)` shape — ZERO physics.
28
+ *
29
+ * NOTE: `setupCircuitSAT` below is now a standalone adapter over the FULLY
30
+ * self-contained canonical `setupCircuitSAT` factory (which builds its own
31
+ * wires/batteries internally via its own canonical `setupCircuitBasic` import) —
32
+ * it no longer imports from this cell. This cell is kept as the "reusable
33
+ * building blocks" reference the notebook's own narrative describes.
34
+ */
35
+ import {
36
+ createWire as _createWire,
37
+ createBattery as _createBattery,
38
+ createResistor as _createResistor,
39
+ setupCircuitBasic as _setupCircuitBasic
40
+ } from '@frqtl/setups/circuit-basic';
41
+
42
+ export function createWire(frqtl, universe, x1, y1, x2, y2, width, wallThickness, color) {
43
+ return _createWire(universe, x1, y1, x2, y2, width, wallThickness, color);
44
+ }
45
+
46
+ export function createBattery(frqtl, universe, sourceX, sourceY, sinkX, sinkY, amperage, terminalSize, fundamentalDim, voltage, channelWidth, wallThickness) {
47
+ return _createBattery(universe, sourceX, sourceY, sinkX, sinkY, amperage, terminalSize, fundamentalDim, voltage, channelWidth, wallThickness);
48
+ }
49
+
50
+ export function createResistor(frqtl, universe, x, y, length, channelWidth, outerWidth, horizontal, wallThickness, color) {
51
+ return _createResistor(universe, x, y, length, channelWidth, outerWidth, horizontal, wallThickness, color);
52
+ }
53
+
54
+ export function setupCircuitBasic(frqtl, universe, options) {
55
+ return _setupCircuitBasic(universe, options);
56
+ }
57
+ </cell>
58
+
59
+ <cell type="markdown">
60
+ The half-adder wiring — the canonical experiment factory (assembled from the same wire/battery primitives shown above, wired together inside `lib/frqtl/objects/setup/setupCircuitSAT.js`):
61
+ </cell>
62
+
63
+ <cell type="module" name="./setups/circuit-sat.js">
64
+ /* setupCircuitSAT — THIN ADAPTER over the canonical setup factory
65
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
66
+ * a divergent fork of lib/frqtl/objects/setup/setupCircuitSAT.js that had
67
+ * already drifted onto a stale `universe.init(...)` positional-argument call
68
+ * the engine now FAIL-LOUDs on. The canonical factory is imported by BARE
69
+ * SPECIFIER (a relative path here would 404 — see
70
+ * lib/shim/notebook/frqtl-setups-importmap.js); this cell only bridges the
71
+ * notebook builder's `(frqtl, universe, options)` call shape to the factory's
72
+ * `(universe, options)` shape — ZERO physics here. The canonical factory is
73
+ * FULLY self-contained: it builds its own wires/batteries by importing the
74
+ * canonical setupCircuitBasic.js internally, so this adapter no longer needs
75
+ * `createWire`/`createBattery` from the sibling circuit-basic.js cell.)
76
+ */
77
+ import { setupCircuitSAT as _setupCircuitSAT } from '@frqtl/setups/circuit-sat';
78
+
79
+ export function setupCircuitSAT(frqtl, universe, options) {
80
+ return _setupCircuitSAT(universe, options);
81
+ }
82
+ </cell>
83
+
84
+ <cell type="markdown">
85
+ Declare a canvas that runs it. `setup="<module>#<export>"` + `stage`/`seed`; the shim synthesizes and runs the builder boilerplate in the realm. Click **Run** (or **Run All**):
86
+ </cell>
87
+
88
+ <cell type="canvas" id="c-csat-canvas" setup="./setups/circuit-sat.js#setupCircuitSAT" stage="480x480" seed="42"></cell>
89
+
90
+ <cell type="markdown">
91
+ ## What you are seeing
92
+
93
+ Particles emit from the four batteries (two per gate section) and flow left-to-right along wire channels. Each gate samples the density in two upstream control regions over a `windowTicks`-tick sliding average. When the average crosses `gateThreshold` (default 3) the gate body switches from `WALL` (blocking) to `NONE` (transparent); when it falls below `max(1, gateThreshold − 1)` it closes again (hysteresis). The `CircuitProbe` markers at 75 % of the canvas read the stabilized output without absorbing quanta — no search ever runs.
94
+
95
+ **The driving parameter is the boolean `(inputA, inputB)` pair.** There is no continuous numeric sweep here — the four input combinations each produce a distinct rendered layout: dark channels when a battery is OFF, a dense particle cloud upstream of a closed gate, clear flow past an open gate. All four are verified correct at tick 1500 (see [`docs/physics/circuit-sat-overview.md`](../../docs/physics/circuit-sat-overview.md)).
96
+
97
+ When `(A=1, B=1)` the XOR gate closes while the AND gate opens — quanta back-fill and spill visibly above the wire array as the circuit holds the `SUM=0, CARRY=1` result. This is the tell-tale of the `(1,1)` row: the XOR collision creates visible backpressure.
98
+
99
+ **Gates converge after ~200–400 ticks** (one `windowTicks` window plus wire transit time). If you switch inputs mid-run via `setInputA` / `setInputB`, let it run another 400 ticks before reading the probe.
100
+
101
+ **Edit the physics:** open the `./setups/circuit-sat.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `_setupCircuitSAT(universe, options)` call to `_setupCircuitSAT(universe, Object.assign({ inputA: false, gateThreshold: 5 }, options))` (also try `emissionRate` or `wireWidth`) — then re-Run. The gate behavior changes because you edited the construction. (The physics body itself lives in the canonical `lib/frqtl/objects/setup/setupCircuitSAT.js` — this cell and `./setups/circuit-basic.js` are thin, engine-agnostic adapters over the canonical factories.) The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
102
+ </cell>
103
+
104
+ </frqtl-notebook>