|
# Double Slit → Rosetta → QFT
One environment, three engines, **individually runnable**. This dogfood proves the unified-notebook capability end-to-end:
- **imperative cells** — nothing runs on load; you click Run per cell.
- **typed object-bag handoff** — a cell declares what it consumes (`in`) and produces (`out`); the kernel wires named outputs to named inputs and marks consumers *stale* (never auto-runs them).
- **a live physics canvas alongside math** — the double-slit simulation mounts only when you Run its canvas cell, and at most one canvas runs at a time.
The loose through-line: an interference pattern *is* information; we encode it (Rosetta), and we factor a number whose period extraction is the "quantum" step of Shor's algorithm (QFT) — all classical, all here.
|
## 1. The double slit
The canvas below DECLARES the canonical double-slit experiment (`setup="./setups/double-slit.js#setupDoubleSlit"` + `stage="480x480"` + `seed="42"`); the shim synthesizes the builder boilerplate (import → ensureEngine → FrqtlApp → setup → mount) and runs it in the realm. It does **not** start on notebook load — click **Run** to mount and start it. The canvas also declares `produceAfter="600"`: before committing the `hist` binding (§2) the shim warms the realm 600 deterministic ticks so particles cross the stage and accumulate at the detector — so the histogram (and the §3 chart) shows **real** fringe data rather than an empty tick-0 snapshot. The runner stays **realm-internal** (it is never a kernel binding); realm-produced data reaches downstream cells via the realm→kernel binding seam (§2). Switch to another notebook and back, Run again — the pane disposes the prior runner first, so there is never a duplicate RAF loop.
The canvas also declares `liveChart="detectorHistogram"`: a **same-cell** live accumulation chart renders **inside this canvas's own realm**, beneath the sim, and **fills as the sim runs** (the original-gallery model). It subscribes to the realm's **local** tick stream (`handle.on('tick')`), polls the same `detectorHistogram` projector, and redraws ~10×/s — so you watch the fringes build live. This is **orthogonal** to `produces=`: the live chart draws continuously and commits **nothing**, while `produces="hist"` derives the histogram **once** and commits the `hist` kernel binding the §3 chart consumes. Because the live chart lives in the realm, its data **never** crosses the renderer↔realm boundary.
|
/* setupDoubleSlit — THIN ADAPTER over the canonical setup factory
* (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
* a divergent fork of lib/frqtl/objects/setup/setupDoubleSlit.js that had
* already drifted onto a stale `universe.init(...)` positional-argument call the
* engine now FAIL-LOUDs on. The canonical factory is imported by BARE SPECIFIER
* (a relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js);
* this cell only bridges the notebook builder's `(frqtl, universe, options)` call
* shape to the factory's `(universe, options)` shape — ZERO physics here. This
* is the SAME canonical factory the gallery-double-slit notebook drives —
* one experiment identity.)
*/
import { setupDoubleSlit as _setupDoubleSlit } from '@frqtl/setups/double-slit';
export function setupDoubleSlit(frqtl, universe, options) {
return _setupDoubleSlit(universe, options);
}
|
|
## 2. Pull the interference histogram (the realm→kernel binding seam)
The canvas above DECLARES its setup (`setup="./setups/double-slit.js#setupDoubleSlit"`) **and** what it produces (`produces="hist"`); the shim synthesizes the builder and runs it **realm-internal** — the runner is **never** a kernel binding (WS-NOTEBOOK-SHIM-MANAGED-BUILDER C9).
After the runner mounts, the realm DERIVES a **serializable** detector histogram from the live runner via the one frozen-handle projector (`detectorHistogram(runner)`, default `produceVia`) and commits it as the `hist` binding through the single binding-commit authority `kernel.commitViewOutputs` (WS-NOTEBOOK-REALM-KERNEL-BINDING). The committed value is a plain `{ binKey: count }` object — a live runner can never cross the seam (it FAILS LOUD at the serializability gate). The `hist`-consuming cells below now resolve once you Run the canvas; before it has produced, they still FAIL LOUD ("`hist` not yet produced") — by design, never a silent empty result.
|
## 3. Chart the fringes
The chart cell consumes `hist` and renders the interference fringes as a bar chart (Chart.js). It FAILs LOUD naming the producing cell if `hist` is not yet produced — it never silently draws an empty chart, and never auto-runs the upstream cell. (`hist` arrives via the realm→kernel binding seam — see §2.)
|
|
## 4. Encoding the pattern (Rosetta)
Now we cross lanes — `frqtl` → `math`. This cell consumes `hist` (produced in the frqtl lane) and builds a Rosetta `Codec` over the histogram counts: a typed pipeline `HostFloats → EGPTReal → HostFloats` with an explicit `claim`. Running it captures per-stage `snapshots` (the object-bag-per-stage trace) — the same provenance discipline the notebook kernel generalizes. This is the `hist → chain` cross-lane handoff.
|
// Cross-lane handoff: hist (frqtl) → a Rosetta Codec (math).
const { math, display } = caps;
// `hist` arrives via the realm→kernel binding seam as a SERIALIZABLE plain
// { binKey: count } object (a live runner / Map can never cross the seam). Read its
// counts from the plain object's values (NOT Map.values()).
const hist = inputs.hist;
const counts = (hist && typeof hist === 'object')
? Object.keys(hist).map((k) => Number(hist[k]))
: [];
// Pad to a non-empty array so the chain always has something to encode.
const payload = counts.length ? counts : [0];
const codecRuntime = math.codec; // { registry, Codec, buildCodecDsl, EncodingClasses }
const dsl = codecRuntime.buildCodecDsl(
codecRuntime.registry, codecRuntime.Codec, codecRuntime.EncodingClasses
).dsl;
// A minimal typed round-trip chain over the histogram values.
dsl.input('HostFloats', { payload, format: 'fp64' });
dsl.push('HostFloatsToEGPTReal');
dsl.push('EGPTRealToHostFloats');
// Codec.run THROWS MissingClaimError unless a claim was declared first
// (architect ground-truth correction #4).
dsl.claim('round-trip-exact', { reference: 'round-trip-exact', tolerance: 'exact' });
const built = dsl.build();
const codec = built.codec;
const chain = codec.run(built.headEncoding); // RunResult { snapshots, output, trace }
display(`Rosetta chain ran: ${chain.snapshots.length} snapshots ` +
`(input → EGPTReal → host floats); claim="${chain.claimMeta && chain.claimMeta.name}".`);
return { chain };
|
// Display the per-stage snapshots (the object-bag-per-stage trace) + the
// round-trip verdict. Ties the Rosetta paradigm to the notebook paradigm:
// named typed handoff, captured at every stage.
const { display } = caps;
const chain = inputs.chain;
const kinds = chain.snapshots.map(s => (s && s.constructor && s.constructor.kind) || '?');
display(`stages: ${kinds.join(' → ')}`);
const head = chain.snapshots[0];
const tail = chain.output;
const roundTrips = (head && typeof head.equals === 'function')
? head.equals(tail) : false;
display(`round-trip (head.equals(output)): ${roundTrips ? 'OK (exact)' : 'differs'}`);
|
## 5. The QFT benchmark
This `math`-lane cell drives the **same** `FraqtlSession` the QFT showcase notebook drives (`math.FraqtlSession.auto()` → `session.run(N)`) — reuse, not fork. It factors the 39-bit semiprime `549755813701 = 712321 × 771781` (the period-extraction "quantum" step of Shor's algorithm, run classically here). N and the 594-core-year comparison come from the single baseline authority `math.benchmarks.qftBaseline` — no inlined figures. This cell is deliberately **not** wired to the others: not every cell must chain.
|
const { math, display } = caps;
const b = math.benchmarks && math.benchmarks.qftBaseline;
if (!b) {
throw new Error('math.benchmarks.qftBaseline absent — figures live in ONE authority (FAIL-LOUD).');
}
const N = b.benchmarkRun.N; // the SAME semiprime, from the authority
const session = math.FraqtlSession.auto();
const t0 = performance.now();
const result = session.run(N);
const elapsedMs = (typeof result.elapsed_ms === 'number') ? result.elapsed_ms : (performance.now() - t0);
const expected = b.benchmarkRun.factors;
const got = (result.factors || []).slice().sort((x, y) => x - y);
const want = expected.slice().sort((x, y) => x - y);
const ok = got.length === want.length && got.every((v, i) => v === want[i]);
display(ok
? `FACTORS VERIFIED on ${math.activeMathBackend}: ${N} = ${result.factors.join(' x ')} ` +
`in ${elapsedMs.toFixed(0)} ms — vs the published ${b.studyCompute.coreYears} core-years of supercomputer compute.`
: `MISMATCH: got [${result.factors}], expected [${expected}].`);
const qft = { N, factors: result.factors, ok, elapsedMs, backend: math.activeMathBackend };
return { qft };
|
## What this validates
Interference → encoding → factoring, in one notebook, on one execution surface, every cell individually runnable, the physics canvas never auto-triggered. This is the capability bar for the CODE + GALLERY merge: the same native `` format and the same on-demand kernel carry markdown, math, live physics, and charts side by side.
|