diff --git a/brainsnn-r3f-app/README.md b/brainsnn-r3f-app/README.md index 2d58cd7..fe32f56 100644 --- a/brainsnn-r3f-app/README.md +++ b/brainsnn-r3f-app/README.md @@ -71,6 +71,35 @@ All optional. Copy [.env.example](.env.example) to `.env` and fill in only what | 33 | Multimodal RAG Router | [MultimodalRagPanel.jsx](src/components/MultimodalRagPanel.jsx) + [utils/multimodalRag.js](src/utils/multimodalRag.js) | | 34 | Vector-Graph Fusion | [VectorGraphFusionPanel.jsx](src/components/VectorGraphFusionPanel.jsx) | | 35 | Direct Content Insertion (JSON) | [DirectInsertPanel.jsx](src/components/DirectInsertPanel.jsx) | +| 101 | Quantum Coherence Lab | [QuantumCoherencePanel.jsx](src/components/QuantumCoherencePanel.jsx) + [utils/quantumCoherence.js](src/utils/quantumCoherence.js) | + +## Quantum Coherence Lab + +**Layer 101 — Quantum Coherence Lab.** A pure-JavaScript, in-browser simulation +of a single qubit running through `|0⟩ → H → RZ(θ) → H → M`. Slide the phase +θ to watch interference move probability between |0⟩ and |1⟩. Add noise to +damp the fringe. Toggle a mid-circuit observation to collapse superposition. +Stack X·X pairs (algebraically identity) to watch decoherence eat depth. + +**What this is.** A teaching sandbox for the *mechanism* behind the word +"alignment": phase coherence steers outcomes; noise and observation kill it. +A **Scientific / Metaphor** mode toggle reframes the same numbers in +plain English alongside the math. + +**What this is not.** This does **not** prove literal multiverse theory, +consciousness collapse, Planck foam, or spiritual portals. Those are framing +metaphors when the toggle is on, not physics claims. + +**Future backend.** The function surface (`runPhaseExperiment`, +`runDecoherenceExperiment`, etc.) is intentionally compatible with a +hardware-backed run — a future version can swap the local simulator for +IBM Quantum or OriginQ. **No vendor API keys are added to the frontend.** + +Run the unit tests directly with Node (no extra dev deps): + +```bash +npm run test:quantum +``` ## Keyboard shortcuts diff --git a/brainsnn-r3f-app/package.json b/brainsnn-r3f-app/package.json index 00c8c03..cf9355d 100644 --- a/brainsnn-r3f-app/package.json +++ b/brainsnn-r3f-app/package.json @@ -11,7 +11,8 @@ "build": "vite build", "preview": "vite preview", "start": "node server.js", - "start:dev": "npm run build && node server.js" + "start:dev": "npm run build && node server.js", + "test:quantum": "node --test src/utils/quantumCoherence.test.mjs" }, "dependencies": { "@ffmpeg/ffmpeg": "^0.12.15", diff --git a/brainsnn-r3f-app/src/App.jsx b/brainsnn-r3f-app/src/App.jsx index afb3b3f..3213437 100644 --- a/brainsnn-r3f-app/src/App.jsx +++ b/brainsnn-r3f-app/src/App.jsx @@ -81,6 +81,7 @@ import HotkeyMap from './components/HotkeyMap'; import ThemePanel from './components/ThemePanel'; import CommunityPackPanel from './components/CommunityPackPanel'; import MilestonePanel from './components/MilestonePanel'; +import QuantumCoherencePanel from './components/QuantumCoherencePanel'; import { registerServiceWorker } from './utils/pwa'; import { registerTheme } from './utils/theme'; import DreamModePanel from './components/DreamModePanel'; @@ -779,6 +780,28 @@ export default function App() { + + { + markActivity(); + setState((prev) => { + const regions = { ...prev.regions }; + for (const [region, delta] of Object.entries(deltas)) { + if (regions[region] === undefined) continue; + regions[region] = Math.max(0.04, Math.min(0.95, regions[region] + delta * 0.3)); + } + return { + ...prev, + regions, + tick: (prev.tick ?? 0) + 1, + scenario: `Quantum Coherence (${score}/100)`, + }; + }); + toastSuccess(`Quantum coherence ${score}/100 mapped to brain · ${result.kind}`); + }} + /> + + diff --git a/brainsnn-r3f-app/src/components/QuantumCoherencePanel.jsx b/brainsnn-r3f-app/src/components/QuantumCoherencePanel.jsx new file mode 100644 index 0000000..c40a22f --- /dev/null +++ b/brainsnn-r3f-app/src/components/QuantumCoherencePanel.jsx @@ -0,0 +1,390 @@ +import React, { useMemo, useState } from 'react'; +import { + runPhaseExperiment, + runObservationExperiment, + runDecoherenceExperiment, + coherenceScore, + mapQuantumToBrainState, +} from '../utils/quantumCoherence'; + +/** + * Layer 101 — Quantum Coherence Lab panel. + * + * Local, in-browser simulation of the simplest possible quantum circuit: + * |0⟩ → H → RZ(θ) → H → M + * + * Teaches superposition, phase, interference, observation, noise, and + * decoherence. The "Metaphor" toggle re-frames the same numbers in + * everyday language; nothing in this panel claims literal multiverse + * theory, consciousness collapse, Planck foam, or spiritual portals — + * those are framing aids, not physics claims. + */ + +const SHOTS_OPTIONS = [256, 1024, 4096]; + +const SHOTS_HINT = { + 256: 'Quick — noisy bars', + 1024: 'Default — balanced', + 4096: 'Slow — smooth bars', +}; + +function fmtPercent(p) { + return `${(p * 100).toFixed(1)}%`; +} + +function ProbabilityBars({ distribution, counts }) { + const [p0, p1] = distribution; + return ( +
+ {[ + { label: '|0⟩', p: p0, count: counts[0], color: '#5ad4ff' }, + { label: '|1⟩', p: p1, count: counts[1], color: '#a86fdf' }, + ].map((b) => ( +
+
+ {b.label} + + {fmtPercent(b.p)} · {b.count} shots + +
+
+
+
+
+ ))} +
+ ); +} + +function CircuitRow({ theta, observeMidway, depth }) { + const gates = [ + { label: 'H', desc: 'Hadamard — make superposition' }, + { label: `RZ(${theta.toFixed(2)})`, desc: 'Rotate the relative phase' }, + ]; + if (observeMidway) { + gates.push({ label: '👁 M', desc: 'Mid-circuit measurement' }); + } + if (depth > 0) { + gates.push({ label: `(X·X)×${depth}`, desc: 'Identity on paper, decoherence in practice' }); + } + gates.push({ label: 'H', desc: 'Hadamard — recombine for interference' }); + gates.push({ label: 'M', desc: 'Final measurement — read out 0 or 1' }); + + return ( +
+ |0⟩ + {gates.map((g, i) => ( + + + + {g.label} + + + ))} +
+ ); +} + +function buildExplanation({ result, score, mode, theta, observeMidway, depth, noise }) { + const [p0, p1] = result.distribution; + const dominant = p0 >= p1 ? '|0⟩' : '|1⟩'; + const dominantPct = fmtPercent(Math.max(p0, p1)); + const balanced = Math.abs(p0 - p1) < 0.1; + + if (mode === 'metaphor') { + if (observeMidway) { + return `Watching the qubit mid-flight collapsed it. Like checking a Schrödinger box too early — the second H spreads the now-classical bit back into ~50/50, score ${score}/100. Metaphor: peek at a held thought and you lose the held thought.`; + } + if (balanced) { + return `Phase tuned to a place where both outcomes interfere equally — ${dominantPct} either way. Metaphor: two stories with equal pull. Coherence ${score}/100.`; + } + if (noise > 0.5) { + return `Noise ate the interference. The qubit drifted toward ${dominant} (${dominantPct}) but without the clean fringe. Metaphor: signal in a loud room. Coherence ${score}/100.`; + } + if (depth > 0) { + return `Stacked ${depth} X·X pairs — algebraically a no-op, but each gate leaks. Metaphor: a long whispered chain stays the same on paper, drifts in real life. Coherence ${score}/100.`; + } + return `Phase steered the wave to ${dominant} (${dominantPct}). Metaphor: aligned attention picks one outcome out of two. Coherence ${score}/100.`; + } + + // Scientific mode + if (observeMidway) { + return `Mid-circuit measurement collapsed |+⟩ to a basis state, killing interference at the second H. Result is ~50/50 (${dominantPct} ${dominant}). Coherence ${score}/100. This is the "watched-path kills fringe" lesson.`; + } + if (depth > 0) { + return `${depth} X·X pairs. Ideal: identity (P(0)=1). With noise=${noise.toFixed(2)} and dephasing per gate, you got P(${dominant})=${dominantPct}. Coherence drops with depth × noise. Score ${score}/100.`; + } + if (balanced) { + return `θ=${theta.toFixed(2)} sits near π/2 — H·RZ(π/2)·H gives ~50/50. P(${dominant})=${dominantPct}. Interference fringe present at low noise. Score ${score}/100.`; + } + return `H → RZ(${theta.toFixed(2)}) → H → M. Phase rotation interferes at the second H, biasing the readout to ${dominant} (${dominantPct}). Noise=${noise.toFixed(2)}, coherence ${score}/100.`; +} + +export default function QuantumCoherencePanel({ onApplyToBrain } = {}) { + const [theta, setTheta] = useState(0); + const [shots, setShots] = useState(1024); + const [noise, setNoise] = useState(0); + const [depth, setDepth] = useState(0); // X-X pair count + const [observeMidway, setObserveMidway] = useState(false); + const [mode, setMode] = useState('scientific'); // 'scientific' | 'metaphor' + const [runToken, setRunToken] = useState(0); // bumps every Run click + + const result = useMemo(() => { + void runToken; + if (observeMidway) { + return runObservationExperiment({ shots, observeMidway: true, noise }); + } + if (depth > 0) { + return runDecoherenceExperiment({ xxPairs: depth, shots, noise }); + } + return runPhaseExperiment({ theta, shots, noise }); + // theta/shots/noise/depth/observe/runToken trigger re-runs + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [theta, shots, noise, depth, observeMidway, runToken]); + + const score = useMemo( + () => coherenceScore({ + noise, + depth: Math.max(1, depth + 1), + observedMidway: observeMidway, + }), + [noise, depth, observeMidway], + ); + + const explanation = useMemo( + () => buildExplanation({ result, score, mode, theta, observeMidway, depth, noise }), + [result, score, mode, theta, observeMidway, depth, noise], + ); + + const brainDeltas = useMemo(() => mapQuantumToBrainState(result), [result]); + + return ( +
+
Layer 101 · quantum coherence lab
+

Phase, interference, decoherence — in your browser

+

+ A single qubit running |0⟩ → H → RZ(θ) → H → M, simulated + locally in JavaScript. Slide θ to see interference move probability + between |0⟩ and |1⟩. Add noise. Toggle a mid-circuit observation. + Stack X·X pairs to watch identity-on-paper fall apart in practice. +

+

+ This teaches the mechanism behind the word "alignment" — phase + coherence steers outcomes; noise and observation kill it. It does + not prove multiverse theory, consciousness collapse, Planck foam, + or spiritual portals. Those are metaphors when the toggle is on. +

+ +
+ + + + {onApplyToBrain && ( + + )} +
+ + {/* Sliders */} +
+
+
+ Phase θ (0 → π) + {theta.toFixed(3)} +
+ setTheta(parseFloat(e.target.value))} + disabled={observeMidway || depth > 0} + style={{ width: '100%' }} + /> +
+ +
+
+ Noise (0 = ideal, 1 = thermal mush) + {noise.toFixed(2)} +
+ setNoise(parseFloat(e.target.value))} + style={{ width: '100%' }} + /> +
+ +
+
+ Depth — extra X·X pairs (algebraically zero work) + {depth} +
+ setDepth(parseInt(e.target.value, 10))} + style={{ width: '100%' }} + /> +
+ +
+ Shots: + {SHOTS_OPTIONS.map((s) => ( + + ))} + +
+
+ + {/* Circuit visualization */} + + + {/* Probability bars */} + + + {/* Coherence score */} +
= 70 ? '#5ee69a' : score >= 40 ? '#fdab43' : '#dd6974'}`, + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + }} + > + + Coherence score{' '} + {score}/100 + + + {score >= 70 ? 'phase intact' : score >= 40 ? 'fading' : 'decohered'} + +
+ + {/* Explanation */} +

+ {explanation} +

+ + {/* Brain deltas preview */} +
+ + Region deltas (preview) + +
+ {Object.entries(brainDeltas).map(([region, delta]) => ( +
+
{region}
+
0 ? '#5ee69a' : '#94a3b8' }}> + {delta >= 0 ? '+' : ''}{delta.toFixed(2)} +
+
+ ))} +
+
+
+ ); +} diff --git a/brainsnn-r3f-app/src/utils/layerCatalog.js b/brainsnn-r3f-app/src/utils/layerCatalog.js index 110bd86..a4b6154 100644 --- a/brainsnn-r3f-app/src/utils/layerCatalog.js +++ b/brainsnn-r3f-app/src/utils/layerCatalog.js @@ -107,6 +107,7 @@ export const LAYER_CATALOG = [ { id: 98, name: 'Theme + A11y', group: 'view', blurb: 'Dark/light, high-contrast, reduced-motion, font scale.' }, { id: 99, name: 'Federated Community Firewall', group: 'firewall', blurb: 'Weekly-rotated community rule pack.' }, { id: 100, name: 'Milestone Dashboard', group: 'view', blurb: '100 layers shipped — synthesis + personal stats.' }, + { id: 101, name: 'Quantum Coherence Lab', group: 'experimental', blurb: 'In-browser single-qubit phase / interference / decoherence sandbox.' }, ]; export const LAYER_GROUPS = { @@ -116,6 +117,7 @@ export const LAYER_GROUPS = { data: { label: 'Data & State', color: '#5ee69a' }, backend: { label: 'Backend & Agents', color: '#77dbe4' }, progression: { label: 'Progression', color: '#e57b40' }, + experimental: { label: 'Experimental Simulation', color: '#5ad4ff' }, }; export function searchLayers(query = '') { diff --git a/brainsnn-r3f-app/src/utils/quantumCoherence.js b/brainsnn-r3f-app/src/utils/quantumCoherence.js new file mode 100644 index 0000000..baa7ad1 --- /dev/null +++ b/brainsnn-r3f-app/src/utils/quantumCoherence.js @@ -0,0 +1,342 @@ +/** + * Layer 101 — Quantum Coherence Lab + * + * Browser-native, JavaScript-only simulation of a single qubit going through + * a tiny circuit: + * + * |0⟩ → H → RZ(θ) → H → M + * + * Goal: teach the physical mechanism behind "alignment" — superposition, + * phase, interference, observation, noise, decoherence, and final + * measurement — without claiming any of the metaphors are literal physics. + * + * No backend, no IBM/OriginQ keys. Future versions can swap runPhaseExperiment + * for a real-hardware call; the API surface is intentionally compatible. + * + * NOTHING in this file proves multiverse theory, consciousness collapse, + * Planck foam, or spiritual portals. The metaphor framing lives only in + * the panel UI, not in the math. + */ + +// ---------- complex helpers ------------------------------------------------- + +export function complex(re, im = 0) { + return { re, im }; +} + +export function addComplex(a, b) { + return { re: a.re + b.re, im: a.im + b.im }; +} + +export function mulComplex(a, b) { + return { + re: a.re * b.re - a.im * b.im, + im: a.re * b.im + a.im * b.re, + }; +} + +/** |z|^2 — squared magnitude. */ +export function abs2(z) { + return z.re * z.re + z.im * z.im; +} + +// ---------- single-qubit state --------------------------------------------- + +/** + * State is a 2-vector of complex amplitudes [α, β] for |0⟩ and |1⟩. + * normalizeState scales so |α|^2 + |β|^2 = 1 (or returns |0⟩ if zero). + */ +export function normalizeState(state) { + const total = abs2(state[0]) + abs2(state[1]); + if (!Number.isFinite(total) || total <= 1e-12) { + return [complex(1, 0), complex(0, 0)]; + } + const k = 1 / Math.sqrt(total); + return [ + complex(state[0].re * k, state[0].im * k), + complex(state[1].re * k, state[1].im * k), + ]; +} + +const SQRT1_2 = 1 / Math.SQRT2; + +/** Hadamard — creates / collapses superposition. */ +export function applyH(state) { + const a = state[0]; + const b = state[1]; + return [ + complex((a.re + b.re) * SQRT1_2, (a.im + b.im) * SQRT1_2), + complex((a.re - b.re) * SQRT1_2, (a.im - b.im) * SQRT1_2), + ]; +} + +/** Pauli-X — bit flip. */ +export function applyX(state) { + return [state[1], state[0]]; +} + +/** Pauli-Z — phase flip on |1⟩. */ +export function applyZ(state) { + return [state[0], complex(-state[1].re, -state[1].im)]; +} + +/** + * RZ(θ) — rotate phase. Standard form: diag(e^{-iθ/2}, e^{+iθ/2}). + * Global phase on |0⟩ is harmless for measurement; the *relative* phase + * between the two basis amplitudes is what matters for interference. + */ +export function applyRZ(state, theta) { + const half = theta / 2; + const c0 = complex(Math.cos(-half), Math.sin(-half)); + const c1 = complex(Math.cos(half), Math.sin(half)); + return [mulComplex(c0, state[0]), mulComplex(c1, state[1])]; +} + +// ---------- measurement ----------------------------------------------------- + +/** Returns [P(0), P(1)] for a normalized (or near-normalized) state. */ +export function measureDistribution(state) { + const norm = normalizeState(state); + const p0 = abs2(norm[0]); + const p1 = abs2(norm[1]); + const total = p0 + p1 || 1; + return [p0 / total, p1 / total]; +} + +/** + * Multinomial sample of `shots` measurements given a [P(0), P(1)] distribution. + * Deterministic-ish: uses Math.random; for tests, callers should compare + * proportions with tolerances rather than exact counts. + */ +export function sampleShots(distribution, shots) { + const total = Math.max(0, Math.floor(shots) || 0); + if (!total) return [0, 0]; + const p0 = Math.max(0, Math.min(1, distribution[0] ?? 0)); + let zeros = 0; + for (let i = 0; i < total; i += 1) { + if (Math.random() < p0) zeros += 1; + } + return [zeros, total - zeros]; +} + +// ---------- simple noise model --------------------------------------------- + +/** + * Dephasing damps the off-diagonal coherence. We model the state as a + * length-2 amplitude vector but keep an explicit `coherence` factor that + * shrinks toward zero as noise rises and circuit depth grows. We apply + * the factor by scaling the *imaginary* component of the relative phase + * (i.e. squeezing β toward its real projection) — an understandable + * approximation that reproduces the qualitative "lose interference" + * behavior without a full density matrix. + */ +function dephase(state, factor) { + const k = Math.max(0, Math.min(1, factor)); + if (k >= 0.999) return state; + return [ + state[0], + complex(state[1].re, state[1].im * k), + ]; +} + +/** Bit-flip channel: with probability p, swap |0⟩ ↔ |1⟩. */ +function bitFlip(state, p) { + if (p <= 0) return state; + if (Math.random() < p) return applyX(state); + return state; +} + +// ---------- experiments ----------------------------------------------------- + +/** + * H → RZ(θ) → H → M. + * + * Pure (noise = 0): + * θ = 0 → P(0) = 1 + * θ = π → P(1) = 1 + * θ = π/2 → P(0) = P(1) = 0.5 + * + * Higher noise damps the interference fringe, pushing both outcomes toward + * 0.5 regardless of θ. This is the "alignment" picture: phase coherence is + * the resource; noise is the enemy. + */ +export function runPhaseExperiment({ theta = 0, shots = 1024, noise = 0 } = {}) { + let state = [complex(1, 0), complex(0, 0)]; + state = applyH(state); + state = applyRZ(state, theta); + // Single-step dephasing between RZ and final H, parameterized by noise. + const dephaseFactor = Math.max(0, 1 - noise); + state = dephase(state, dephaseFactor); + state = applyH(state); + // Bit-flip readout error scales with noise. + state = bitFlip(state, noise * 0.25); + const distribution = measureDistribution(state); + const counts = sampleShots(distribution, shots); + return { + kind: 'phase', + theta, + shots, + noise, + distribution, + counts, + finalState: state, + }; +} + +/** + * H → (optional middle measurement) → H → M. + * + * Without the middle measurement: H ∘ H = I, so |0⟩ stays |0⟩ → P(0) ≈ 1. + * With the middle measurement: superposition collapses, the second H + * spreads it back out → P(0) ≈ P(1) ≈ 0.5. + * + * Demonstrates "observation kills interference" — the quantum-Zeno / + * which-path lesson, without invoking consciousness. + */ +export function runObservationExperiment({ + shots = 1024, + observeMidway = false, + noise = 0, +} = {}) { + let state = [complex(1, 0), complex(0, 0)]; + state = applyH(state); + + if (observeMidway) { + const [p0] = measureDistribution(state); + const collapsed = Math.random() < p0 + ? [complex(1, 0), complex(0, 0)] + : [complex(0, 0), complex(1, 0)]; + state = collapsed; + } else { + // Apply mild dephasing instead — a "soft watch" that costs coherence. + state = dephase(state, Math.max(0, 1 - noise)); + } + + state = applyH(state); + state = bitFlip(state, noise * 0.25); + + const distribution = measureDistribution(state); + const counts = sampleShots(distribution, shots); + return { + kind: 'observation', + observeMidway, + shots, + noise, + distribution, + counts, + finalState: state, + }; +} + +/** + * Stack `xxPairs` X-X pairs in a row. Algebraically X·X = I, so a perfect + * machine returns P(0) = 1 regardless of depth. With noise, each gate is + * a chance to misfire, so deeper circuits decohere — which is the point. + */ +export function runDecoherenceExperiment({ + xxPairs = 1, + shots = 1024, + noise = 0, +} = {}) { + const pairs = Math.max(0, Math.floor(xxPairs) || 0); + let state = [complex(1, 0), complex(0, 0)]; + // Each pair = X then X, with a per-gate noise channel between them. + for (let i = 0; i < pairs; i += 1) { + state = applyX(state); + state = bitFlip(state, noise * 0.5); + state = applyX(state); + state = bitFlip(state, noise * 0.5); + state = dephase(state, Math.max(0, 1 - noise * 0.4)); + } + const distribution = measureDistribution(state); + const counts = sampleShots(distribution, shots); + return { + kind: 'decoherence', + xxPairs: pairs, + shots, + noise, + distribution, + counts, + finalState: state, + }; +} + +// ---------- coherence score ------------------------------------------------- + +/** + * 0 – 100 score capturing how much "quantum-ness" survived the run. + * - More noise lowers the score. + * - Deeper circuits lower the score. + * - A midway measurement nukes the score (you broke the wavefunction). + * + * Pure determinism (no Math.random) so the UI is stable. + */ +export function coherenceScore({ + noise = 0, + depth = 1, + observedMidway = false, +} = {}) { + const n = Math.max(0, Math.min(1, Number(noise) || 0)); + const d = Math.max(1, Math.floor(Number(depth) || 1)); + const observationPenalty = observedMidway ? 0.5 : 0; + // Exponential decay in depth, linear-ish in noise. + const depthFactor = Math.exp(-0.18 * (d - 1)); + const noiseFactor = 1 - n * 0.85; + const raw = depthFactor * noiseFactor - observationPenalty; + const clamped = Math.max(0, Math.min(1, raw)); + return Math.round(clamped * 100); +} + +// ---------- brain mapping --------------------------------------------------- + +/** + * Convert a quantum experiment result into per-region brain deltas. + * Returns a simple { REGION: delta } object — caller decides how strongly + * to nudge state.regions (typical pattern is `delta * 0.3`). + * + * - PFC ↑ with coherenceScore (alignment / executive coherence) + * - AMY ↑ with noise (the system is rattled) + * - THL ↑ with signal routing (more shots = more relay traffic) + * - HPC ↑ when prior state survives (low depth + low noise = memory holds) + * - BG ↑ when one outcome dominates (decisive gating) + * - CBL ↑ when error / noise correction is high (cerebellum tunes timing) + * - CTX ↑ with experiment complexity (more gates = more cortical work) + * + * Deltas are bounded to [-1, 1]; consumers should scale further. + */ +export function mapQuantumToBrainState(result) { + if (!result || !result.distribution) { + return { CTX: 0, HPC: 0, THL: 0, AMY: 0, BG: 0, PFC: 0, CBL: 0 }; + } + const noise = Math.max(0, Math.min(1, Number(result.noise) || 0)); + const shots = Math.max(1, Number(result.shots) || 1); + const depth = Math.max(1, Number(result.xxPairs ?? 1)); + const observedMidway = !!result.observeMidway; + + const score = coherenceScore({ noise, depth, observedMidway }) / 100; + + const [p0, p1] = result.distribution; + const dominance = Math.abs((p0 ?? 0) - (p1 ?? 0)); // 0 = balanced, 1 = decisive + const survival = (p0 ?? 0); // "stayed in |0⟩" = prior state survived + + const routing = Math.min(1, Math.log10(shots) / 4); // 256→0.6 1024→0.75 4096→0.9 + const complexity = Math.min( + 1, + (result.kind === 'decoherence' ? depth / 10 : 0.35) + + (result.kind === 'observation' && observedMidway ? 0.15 : 0) + + (result.kind === 'phase' ? 0.4 : 0), + ); + const correction = noise * (1 - score); // we're working hard to fix things + + const clamp = (v) => Math.max(-1, Math.min(1, v)); + + return { + PFC: clamp(score * 0.6), + AMY: clamp(noise * 0.5), + THL: clamp(routing * 0.45), + HPC: clamp(survival * 0.5 * (1 - noise * 0.5)), + BG: clamp(dominance * 0.5), + CBL: clamp(correction * 0.6), + CTX: clamp(complexity * 0.5), + }; +} diff --git a/brainsnn-r3f-app/src/utils/quantumCoherence.test.mjs b/brainsnn-r3f-app/src/utils/quantumCoherence.test.mjs new file mode 100644 index 0000000..cf226a4 --- /dev/null +++ b/brainsnn-r3f-app/src/utils/quantumCoherence.test.mjs @@ -0,0 +1,171 @@ +/** + * Layer 101 — Quantum Coherence Lab tests. + * + * Run from brainsnn-r3f-app/ with: + * node --test src/utils/quantumCoherence.test.mjs + * + * Uses Node's built-in test runner (Node 18+). No extra dev deps. + */ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { + runPhaseExperiment, + runObservationExperiment, + runDecoherenceExperiment, + coherenceScore, + measureDistribution, + applyH, + applyX, + applyZ, + applyRZ, + complex, + abs2, + normalizeState, + mapQuantumToBrainState, +} from './quantumCoherence.js'; + +const SHOTS = 4096; + +test('phase experiment with theta=0 returns high P(0)', () => { + const res = runPhaseExperiment({ theta: 0, shots: SHOTS, noise: 0 }); + assert.equal(res.kind, 'phase'); + assert.ok( + res.distribution[0] > 0.95, + `expected P(0) > 0.95, got ${res.distribution[0]}`, + ); +}); + +test('phase experiment with theta=pi returns high P(1)', () => { + const res = runPhaseExperiment({ theta: Math.PI, shots: SHOTS, noise: 0 }); + assert.ok( + res.distribution[1] > 0.95, + `expected P(1) > 0.95, got ${res.distribution[1]}`, + ); +}); + +test('phase experiment at theta=pi/2 splits ~50/50', () => { + const res = runPhaseExperiment({ theta: Math.PI / 2, shots: SHOTS, noise: 0 }); + assert.ok( + Math.abs(res.distribution[0] - 0.5) < 0.05, + `expected P(0) ~ 0.5, got ${res.distribution[0]}`, + ); +}); + +test('observation experiment with observeMidway=false returns high P(0)', () => { + // H ∘ H = I, so |0⟩ stays |0⟩. + const res = runObservationExperiment({ shots: SHOTS, observeMidway: false, noise: 0 }); + assert.ok( + res.distribution[0] > 0.95, + `expected P(0) > 0.95 with no midway observation, got ${res.distribution[0]}`, + ); +}); + +test('observation experiment with observeMidway=true is more random', () => { + // Average over runs since the midway measurement is stochastic. + let p0Sum = 0; + const trials = 40; + for (let i = 0; i < trials; i += 1) { + const r = runObservationExperiment({ shots: 256, observeMidway: true, noise: 0 }); + p0Sum += r.distribution[0]; + } + const avgP0 = p0Sum / trials; + assert.ok( + avgP0 > 0.35 && avgP0 < 0.65, + `expected avg P(0) ~ 0.5 after midway measurement, got ${avgP0.toFixed(3)}`, + ); +}); + +test('increasing noise lowers coherenceScore', () => { + const low = coherenceScore({ noise: 0, depth: 1, observedMidway: false }); + const mid = coherenceScore({ noise: 0.5, depth: 1, observedMidway: false }); + const high = coherenceScore({ noise: 1, depth: 1, observedMidway: false }); + assert.ok(low > mid, `expected ${low} > ${mid}`); + assert.ok(mid > high, `expected ${mid} > ${high}`); +}); + +test('increasing depth lowers coherenceScore', () => { + const shallow = coherenceScore({ noise: 0.1, depth: 1, observedMidway: false }); + const deeper = coherenceScore({ noise: 0.1, depth: 5, observedMidway: false }); + const deepest = coherenceScore({ noise: 0.1, depth: 12, observedMidway: false }); + assert.ok(shallow > deeper, `expected ${shallow} > ${deeper}`); + assert.ok(deeper > deepest, `expected ${deeper} > ${deepest}`); +}); + +test('observing midway dings coherenceScore', () => { + const watched = coherenceScore({ noise: 0, depth: 1, observedMidway: true }); + const unwatched = coherenceScore({ noise: 0, depth: 1, observedMidway: false }); + assert.ok(unwatched > watched, `expected ${unwatched} > ${watched}`); +}); + +test('decoherence experiment ideal (noise=0) returns ~P(0)=1', () => { + const res = runDecoherenceExperiment({ xxPairs: 8, shots: SHOTS, noise: 0 }); + assert.ok( + res.distribution[0] > 0.99, + `X·X pairs are identity at noise=0; got P(0)=${res.distribution[0]}`, + ); +}); + +test('decoherence experiment with noise lowers P(0) vs ideal', () => { + const ideal = runDecoherenceExperiment({ xxPairs: 6, shots: SHOTS, noise: 0 }); + const noisy = runDecoherenceExperiment({ xxPairs: 6, shots: SHOTS, noise: 0.7 }); + assert.ok( + noisy.distribution[0] < ideal.distribution[0], + `expected noisy P(0) < ideal P(0); got ${noisy.distribution[0]} vs ${ideal.distribution[0]}`, + ); +}); + +test('Hadamard on |0> gives equal probabilities', () => { + const state = applyH([complex(1, 0), complex(0, 0)]); + const [p0, p1] = measureDistribution(state); + assert.ok(Math.abs(p0 - 0.5) < 1e-9); + assert.ok(Math.abs(p1 - 0.5) < 1e-9); +}); + +test('Pauli-X flips |0> to |1>', () => { + const state = applyX([complex(1, 0), complex(0, 0)]); + const [p0, p1] = measureDistribution(state); + assert.ok(p1 > 0.999); + assert.ok(p0 < 0.001); +}); + +test('Pauli-Z preserves probabilities (phase only)', () => { + const start = applyH([complex(1, 0), complex(0, 0)]); + const after = applyZ(start); + const before = measureDistribution(start); + const post = measureDistribution(after); + assert.ok(Math.abs(before[0] - post[0]) < 1e-9); +}); + +test('RZ(2π) acts as identity on probabilities', () => { + const start = applyH([complex(1, 0), complex(0, 0)]); + const after = applyRZ(start, Math.PI * 2); + assert.ok(Math.abs(abs2(start[0]) - abs2(after[0])) < 1e-9); + assert.ok(Math.abs(abs2(start[1]) - abs2(after[1])) < 1e-9); +}); + +test('normalizeState normalizes near-zero state to |0>', () => { + const norm = normalizeState([complex(0, 0), complex(0, 0)]); + assert.equal(norm[0].re, 1); + assert.equal(norm[1].re, 0); +}); + +test('mapQuantumToBrainState returns 7 region deltas in [-1, 1]', () => { + const res = runPhaseExperiment({ theta: 0, shots: 1024, noise: 0 }); + const deltas = mapQuantumToBrainState(res); + for (const region of ['CTX', 'HPC', 'THL', 'AMY', 'BG', 'PFC', 'CBL']) { + assert.ok(region in deltas, `missing region ${region}`); + assert.ok(deltas[region] >= -1 && deltas[region] <= 1, `${region} out of range: ${deltas[region]}`); + } +}); + +test('mapQuantumToBrainState: AMY rises with noise', () => { + const clean = mapQuantumToBrainState(runPhaseExperiment({ theta: 0, shots: 256, noise: 0 })); + const noisy = mapQuantumToBrainState(runPhaseExperiment({ theta: 0, shots: 256, noise: 0.9 })); + assert.ok(noisy.AMY > clean.AMY, `expected noisy AMY > clean AMY; got ${noisy.AMY} vs ${clean.AMY}`); +}); + +test('mapQuantumToBrainState: PFC rises with coherence (clean run > noisy run)', () => { + const clean = mapQuantumToBrainState(runPhaseExperiment({ theta: 0, shots: 256, noise: 0 })); + const noisy = mapQuantumToBrainState(runPhaseExperiment({ theta: 0, shots: 256, noise: 0.95 })); + assert.ok(clean.PFC > noisy.PFC, `expected clean PFC > noisy PFC; got ${clean.PFC} vs ${noisy.PFC}`); +});