<p class="hint">Four anyons (A1–A4) encode two logical qubits. Their <b>world-lines</b> travel upward through time. When two anyons swap, their ribbons twist — forming a <b>braid</b> that implements a quantum gate. Local noise wiggles one ribbon but cannot change the global knot class.</p>
<div class="canvas-wrap">
<canvas id="canvas" width="420" height="320"></canvas>
<div id="gate-label" class="gate-label">Braid: Identity</div>
</div>
<div class="info-row">
<span id="step-info">Step 0 / 6</span>
<span id="state-info" class="state-ok">State |00⟩</span>
</div>
<div class="btns">
<button id="btn-step">Step ▶</button>
<button id="btn-run">Run CNOT</button>
<button id="btn-error">Inject Error</button>
<button id="btn-reset" class="ghost">Reset</button>
</div>
<div id="log" class="log"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .88rem; color: #444; margin: 0 0 .6rem; line-height: 1.45; }
.canvas-wrap { position: relative; display: inline-block; }
canvas { display: block; border: 1px solid #cdd9e3; border-radius: 8px; background: #f7fafc; max-width: 100%; }
.gate-label { position: absolute; top: 8px; right: 10px; font: 600 13px ui-monospace, monospace;
color: #1d3557; background: rgba(255,255,255,.85); padding: 2px 7px; border-radius: 5px; }
.info-row { display: flex; gap: 1.2rem; margin: .5rem 0 .3rem; font-size: .9rem; font-weight: 600; }
.state-ok { color: #0a7d33; }
.state-err { color: #c92f3c; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .4rem; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .85rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; transition: opacity .15s; }
button:hover { opacity: .85; }
button.ghost { background: #fff; color: #1d3557; }
.log { font: 13px ui-monospace, monospace; color: #555; min-height: 1.6em;
padding: .35rem .6rem; background: #f0f4f8; border-radius: 6px; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Topological Quantum Computing demo
// Anyons A1..A4 live on 4 tracks. A CNOT on (q0,q1) is implemented by 6 braid generators: σ1, σ2⁻¹, σ1, σ3, σ2⁻¹, σ3 (standard Ising/Fibonacci decomposition approximation used for educational visualization purposes).
// σi = swap anyon i with anyon i+1 (crossing: i goes OVER i+1).
// A "local error" only jiggles a single strand locally — it does NOT change the global braid word, so the logical state is unaffected.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
const TRACKS = 4;
const TRACK_X = [W*0.18, W*0.38, W*0.62, W*0.82]; // x-positions of the 4 anyon tracks
const Y_START = H - 30;
const Y_END = 40;
const COLORS = ['#e63946','#457b9d','#2a9d8f','#e9c46a'];
const LABELS = ['A1','A2','A3','A4'];
// CNOT braid sequence: each entry is [i, dir] where i is the left anyon index (0-based), dir = +1 (i over i+1, positive crossing) or -1 (i+1 over i, negative crossing).
const CNOT_BRAID = [
[0, +1], // σ1
[1, -1], // σ2⁻¹
[0, +1], // σ1
[2, +1], // σ3
[1, -1], // σ2⁻¹
[2, +1], // σ3
];
// Logical state labels for each step (educational approximation)
const STATE_LABELS = ['|00⟩', '|00⟩', '|00⟩', '|0+⟩', '|0+⟩', '|Φ⟩', '|CNOT⟩'];
const GATE_LABELS = [
'Braid: Identity',
'σ₁ applied',
'σ₂⁻¹ applied',
'σ₁ applied',
'σ₃ applied',
'σ₂⁻¹ applied',
'CNOT complete ✓',
];
let currentStep = 0;
let errorInjected = false;
let errorSegment = null; // {track, yFrac, wobble}
let animFrame = null;
function yForStep(step) {
// Map step index (0..6) to a y-coordinate between Y_START and Y_END
return Y_START - (step / CNOT_BRAID.length) * (Y_START - Y_END);
}
// For each step, compute track positions after each swap
function computeTrackPositions() {
// trackPos[step] = array of 4 track indices (which anyon is at which x-slot)
const positions = [[0,1,2,3]]; // initial: anyon i is at slot i
for (let s = 0; s < CNOT_BRAID.length; s++) {
const prev = positions[s].slice();
const [i] = CNOT_BRAID[s];
// Swap slot i and i+1
const next = prev.slice();
next[i] = prev[i+1];
next[i+1] = prev[i];
positions.push(next);
}
return positions;
}
const TRACK_POSITIONS = computeTrackPositions();
// Returns the x-coordinate of anyon 'anyon' at a given step
function xOfAnyon(anyon, step) {
const slotOf = TRACK_POSITIONS[step].indexOf(anyon);
return TRACK_X[slotOf];
}
function drawScene() {
ctx.clearRect(0, 0, W, H);
// Draw time arrow label
ctx.save();
ctx.font = '11px system-ui, sans-serif';
ctx.fillStyle = '#888';
ctx.fillText('time →', 5, 18);
ctx.restore();
// Draw step tick marks on the left
for (let s = 0; s <= CNOT_BRAID.length; s++) {
const y = yForStep(s);
ctx.save();
ctx.strokeStyle = '#d0d8e0';
ctx.lineWidth = 0.7;
ctx.setLineDash([2,4]);
ctx.beginPath(); ctx.moveTo(15, y); ctx.lineTo(W - 10, y); ctx.stroke();
ctx.setLineDash([]);
ctx.restore();
}
// Draw each anyon's world-line as a series of segments
for (let anyon = 0; anyon < TRACKS; anyon++) {
ctx.save();
ctx.strokeStyle = COLORS[anyon];
ctx.lineWidth = 2.4;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// Draw segments from step 0 up to currentStep (or all if completed)
const maxStep = currentStep;
for (let s = 0; s < maxStep; s++) {
const x0 = xOfAnyon(anyon, s);
const x1 = xOfAnyon(anyon, s + 1);
const y0 = yForStep(s);
const y1 = yForStep(s + 1);
// Check if this segment involves a crossing with another anyon
const [swapI, swapDir] = CNOT_BRAID[s];
const slotBefore = TRACK_POSITIONS[s].indexOf(anyon);
const isMoving = (slotBefore === swapI || slotBefore === swapI + 1);
if (isMoving && x0 !== x1) {
// Draw a crossing arc
// Determine if this anyon goes OVER or UNDER
const goesOver = (swapDir === +1 && slotBefore === swapI) ||
(swapDir === -1 && slotBefore === swapI + 1);
if (!goesOver) {
// Draw broken line (under crossing — draw first half, gap in middle, second half)
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x0 + (x1 - x0) * 0.35, y0 + (y1 - y0) * 0.35);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x0 + (x1 - x0) * 0.65, y0 + (y1 - y0) * 0.65);
ctx.lineTo(x1, y1);
ctx.stroke();
} else {
// Draw solid line (over crossing)
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.stroke();
}
} else {
// Straight segment (no crossing for this anyon this step)
// Possibly wobble if error was injected at this segment
let wobble = 0;
if (errorInjected && errorSegment &&
errorSegment.anyon === anyon && errorSegment.step === s) {
wobble = errorSegment.wobble;
}
ctx.beginPath();
ctx.moveTo(x0, y0);
if (wobble !== 0) {
const mx = (x0 + x1) / 2 + wobble;
const my = (y0 + y1) / 2;
ctx.quadraticCurveTo(mx, my, x1, y1);
} else {
ctx.lineTo(x1, y1);
}
ctx.stroke();
}
}
// Draw the future (unexecuted) portion as a dotted line from currentStep onward
if (currentStep < CNOT_BRAID.length) {
ctx.save();
ctx.strokeStyle = COLORS[anyon];
ctx.globalAlpha = 0.22;
ctx.lineWidth = 1.6;
ctx.setLineDash([3, 5]);
const xs = xOfAnyon(anyon, currentStep);
const ys = yForStep(currentStep);
ctx.beginPath();
ctx.moveTo(xs, ys);
ctx.lineTo(xs, Y_END); // approximate: future goes straight (simplification)
ctx.stroke();
ctx.restore();
}
// Draw anyon dot at current position
const xCur = xOfAnyon(anyon, Math.min(currentStep, CNOT_BRAID.length));
const yCur = yForStep(Math.min(currentStep, CNOT_BRAID.length));
ctx.beginPath();
ctx.arc(xCur, yCur, 6, 0, Math.PI * 2);
ctx.fillStyle = COLORS[anyon];
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 1.5;
ctx.stroke();
// Label
ctx.font = 'bold 11px system-ui, sans-serif';
ctx.fillStyle = COLORS[anyon];
ctx.textAlign = 'center';
ctx.fillText(LABELS[anyon], TRACK_X[anyon], Y_START + 18);
ctx.restore();
}
// Error indicator
if (errorInjected && errorSegment) {
ctx.save();
const es = errorSegment;
const ex = xOfAnyon(es.anyon, es.step) + (xOfAnyon(es.anyon, es.step+1) - xOfAnyon(es.anyon, es.step)) * 0.5 + es.wobble;
const ey = (yForStep(es.step) + yForStep(es.step+1)) / 2;
ctx.font = '12px system-ui';
ctx.fillStyle = '#c92f3c';
ctx.textAlign = 'center';
ctx.fillText('⚡ local noise', ex, ey - 10);
ctx.restore();
}
}
function updateUI() {
document.getElementById('step-info').textContent =
fmt('Step %currentStep% / %length%', { currentStep: currentStep, length: CNOT_BRAID.length });
const si = document.getElementById('state-info');
si.textContent = fmt('State: %v%', { v: STATE_LABELS[currentStep] });
si.className = 'state-ok';
document.getElementById('gate-label').textContent = GATE_LABELS[currentStep];
}
function log(msg) {
document.getElementById('log').textContent = msg;
}
document.getElementById('btn-step').addEventListener('click', () => {
if (currentStep < CNOT_BRAID.length) {
currentStep++;
errorInjected = false;
errorSegment = null;
const [i, dir] = CNOT_BRAID[currentStep - 1];
const dirStr = dir > 0 ? 'positive' : 'negative';
log(fmt('Applied σ%i%%v%%v2%: swap A%i%%v%↔A%i%%v3% (%dirStr% crossing)', { i: i, v: 1, v2: dir < 0 ? '⁻¹' : '', v3: 2, dirStr: dirStr }));
drawScene();
updateUI();
} else {
log('CNOT complete. Press Reset to start over.');
}
});
document.getElementById('btn-run').addEventListener('click', () => {
currentStep = 0;
errorInjected = false;
errorSegment = null;
let delay = 0;
for (let s = 0; s < CNOT_BRAID.length; s++) {
((step) => {
setTimeout(() => {
currentStep = step + 1;
errorInjected = false;
errorSegment = null;
drawScene();
updateUI();
const [i, dir] = CNOT_BRAID[step];
log(fmt('Step %step%%v%: σ%i%%v%%v2% — A%i%%v%↔A%i%%v3%', { step: step, v: 1, i: i, v2: dir < 0 ? '⁻¹' : '', v3: 2 }));
}, delay);
})(s);
delay += 500;
}
setTimeout(() => {
log('CNOT gate complete. Global braid encodes the gate — topology is intact.');
}, delay);
});
document.getElementById('btn-error').addEventListener('click', () => {
if (currentStep < 1) {
log('Advance at least one step before injecting an error.');
return;
}
// Inject a local wobble on a random strand at a past segment — does not change braid class
const targetStep = Math.floor(Math.random() * currentStep);
const targetAnyon = Math.floor(Math.random() * TRACKS);
const wobble = (Math.random() > 0.5 ? 1 : -1) * (12 + Math.random() * 10);
errorInjected = true;
errorSegment = { anyon: targetAnyon, step: targetStep, wobble };
drawScene();
updateUI();
const si = document.getElementById('state-info');
si.textContent = fmt('State: %v% (unchanged ✓)', { v: STATE_LABELS[currentStep] });
si.className = 'state-ok';
log(fmt('⚡ Local noise on A%targetAnyon%%v% at step %targetStep%. Braid class unchanged — logical state protected!', { targetAnyon: targetAnyon, v: 1, targetStep: targetStep }));
});
document.getElementById('btn-reset').addEventListener('click', () => {
currentStep = 0;
errorInjected = false;
errorSegment = null;
drawScene();
updateUI();
log('Reset. Ready to braid.');
});
// Initial render
drawScene();
updateUI();
log('Press Step or Run CNOT to begin braiding.');
<p class="hint">Four anyons (A1–A4) encode two logical qubits. Their <b>world-lines</b> travel upward through time. When two anyons swap, their ribbons twist — forming a <b>braid</b> that implements a quantum gate. Local noise wiggles one ribbon but cannot change the global knot class.</p>
<div class="canvas-wrap">
<canvas id="canvas" width="420" height="320"></canvas>
<div id="gate-label" class="gate-label">Braid: Identity</div>
</div>
<div class="info-row">
<span id="step-info">Step 0 / 6</span>
<span id="state-info" class="state-ok">State |00⟩</span>
</div>
<div class="btns">
<button id="btn-step">Step ▶</button>
<button id="btn-run">Run CNOT</button>
<button id="btn-error">Inject Error</button>
<button id="btn-reset" class="ghost">Reset</button>
</div>
<div id="log" class="log"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .88rem; color: #444; margin: 0 0 .6rem; line-height: 1.45; }
.canvas-wrap { position: relative; display: inline-block; }
canvas { display: block; border: 1px solid #cdd9e3; border-radius: 8px; background: #f7fafc; max-width: 100%; }
.gate-label { position: absolute; top: 8px; right: 10px; font: 600 13px ui-monospace, monospace;
color: #1d3557; background: rgba(255,255,255,.85); padding: 2px 7px; border-radius: 5px; }
.info-row { display: flex; gap: 1.2rem; margin: .5rem 0 .3rem; font-size: .9rem; font-weight: 600; }
.state-ok { color: #0a7d33; }
.state-err { color: #c92f3c; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .4rem; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .85rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; transition: opacity .15s; }
button:hover { opacity: .85; }
button.ghost { background: #fff; color: #1d3557; }
.log { font: 13px ui-monospace, monospace; color: #555; min-height: 1.6em;
padding: .35rem .6rem; background: #f0f4f8; border-radius: 6px; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Topological Quantum Computing demo
// Anyons A1..A4 live on 4 tracks. A CNOT on (q0,q1) is implemented by 6 braid generators: σ1, σ2⁻¹, σ1, σ3, σ2⁻¹, σ3 (standard Ising/Fibonacci decomposition approximation used for educational visualization purposes).
// σi = swap anyon i with anyon i+1 (crossing: i goes OVER i+1).
// A "local error" only jiggles a single strand locally — it does NOT change the global braid word, so the logical state is unaffected.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
const TRACKS = 4;
const TRACK_X = [W*0.18, W*0.38, W*0.62, W*0.82]; // x-positions of the 4 anyon tracks
const Y_START = H - 30;
const Y_END = 40;
const COLORS = ['#e63946','#457b9d','#2a9d8f','#e9c46a'];
const LABELS = ['A1','A2','A3','A4'];
// CNOT braid sequence: each entry is [i, dir] where i is the left anyon index (0-based), dir = +1 (i over i+1, positive crossing) or -1 (i+1 over i, negative crossing).
const CNOT_BRAID = [
[0, +1], // σ1
[1, -1], // σ2⁻¹
[0, +1], // σ1
[2, +1], // σ3
[1, -1], // σ2⁻¹
[2, +1], // σ3
];
// Logical state labels for each step (educational approximation)
const STATE_LABELS = ['|00⟩', '|00⟩', '|00⟩', '|0+⟩', '|0+⟩', '|Φ⟩', '|CNOT⟩'];
const GATE_LABELS = [
'Braid: Identity',
'σ₁ applied',
'σ₂⁻¹ applied',
'σ₁ applied',
'σ₃ applied',
'σ₂⁻¹ applied',
'CNOT complete ✓',
];
let currentStep = 0;
let errorInjected = false;
let errorSegment = null; // {track, yFrac, wobble}
let animFrame = null;
function yForStep(step) {
// Map step index (0..6) to a y-coordinate between Y_START and Y_END
return Y_START - (step / CNOT_BRAID.length) * (Y_START - Y_END);
}
// For each step, compute track positions after each swap
function computeTrackPositions() {
// trackPos[step] = array of 4 track indices (which anyon is at which x-slot)
const positions = [[0,1,2,3]]; // initial: anyon i is at slot i
for (let s = 0; s < CNOT_BRAID.length; s++) {
const prev = positions[s].slice();
const [i] = CNOT_BRAID[s];
// Swap slot i and i+1
const next = prev.slice();
next[i] = prev[i+1];
next[i+1] = prev[i];
positions.push(next);
}
return positions;
}
const TRACK_POSITIONS = computeTrackPositions();
// Returns the x-coordinate of anyon 'anyon' at a given step
function xOfAnyon(anyon, step) {
const slotOf = TRACK_POSITIONS[step].indexOf(anyon);
return TRACK_X[slotOf];
}
function drawScene() {
ctx.clearRect(0, 0, W, H);
// Draw time arrow label
ctx.save();
ctx.font = '11px system-ui, sans-serif';
ctx.fillStyle = '#888';
ctx.fillText('time →', 5, 18);
ctx.restore();
// Draw step tick marks on the left
for (let s = 0; s <= CNOT_BRAID.length; s++) {
const y = yForStep(s);
ctx.save();
ctx.strokeStyle = '#d0d8e0';
ctx.lineWidth = 0.7;
ctx.setLineDash([2,4]);
ctx.beginPath(); ctx.moveTo(15, y); ctx.lineTo(W - 10, y); ctx.stroke();
ctx.setLineDash([]);
ctx.restore();
}
// Draw each anyon's world-line as a series of segments
for (let anyon = 0; anyon < TRACKS; anyon++) {
ctx.save();
ctx.strokeStyle = COLORS[anyon];
ctx.lineWidth = 2.4;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// Draw segments from step 0 up to currentStep (or all if completed)
const maxStep = currentStep;
for (let s = 0; s < maxStep; s++) {
const x0 = xOfAnyon(anyon, s);
const x1 = xOfAnyon(anyon, s + 1);
const y0 = yForStep(s);
const y1 = yForStep(s + 1);
// Check if this segment involves a crossing with another anyon
const [swapI, swapDir] = CNOT_BRAID[s];
const slotBefore = TRACK_POSITIONS[s].indexOf(anyon);
const isMoving = (slotBefore === swapI || slotBefore === swapI + 1);
if (isMoving && x0 !== x1) {
// Draw a crossing arc
// Determine if this anyon goes OVER or UNDER
const goesOver = (swapDir === +1 && slotBefore === swapI) ||
(swapDir === -1 && slotBefore === swapI + 1);
if (!goesOver) {
// Draw broken line (under crossing — draw first half, gap in middle, second half)
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x0 + (x1 - x0) * 0.35, y0 + (y1 - y0) * 0.35);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x0 + (x1 - x0) * 0.65, y0 + (y1 - y0) * 0.65);
ctx.lineTo(x1, y1);
ctx.stroke();
} else {
// Draw solid line (over crossing)
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.stroke();
}
} else {
// Straight segment (no crossing for this anyon this step)
// Possibly wobble if error was injected at this segment
let wobble = 0;
if (errorInjected && errorSegment &&
errorSegment.anyon === anyon && errorSegment.step === s) {
wobble = errorSegment.wobble;
}
ctx.beginPath();
ctx.moveTo(x0, y0);
if (wobble !== 0) {
const mx = (x0 + x1) / 2 + wobble;
const my = (y0 + y1) / 2;
ctx.quadraticCurveTo(mx, my, x1, y1);
} else {
ctx.lineTo(x1, y1);
}
ctx.stroke();
}
}
// Draw the future (unexecuted) portion as a dotted line from currentStep onward
if (currentStep < CNOT_BRAID.length) {
ctx.save();
ctx.strokeStyle = COLORS[anyon];
ctx.globalAlpha = 0.22;
ctx.lineWidth = 1.6;
ctx.setLineDash([3, 5]);
const xs = xOfAnyon(anyon, currentStep);
const ys = yForStep(currentStep);
ctx.beginPath();
ctx.moveTo(xs, ys);
ctx.lineTo(xs, Y_END); // approximate: future goes straight (simplification)
ctx.stroke();
ctx.restore();
}
// Draw anyon dot at current position
const xCur = xOfAnyon(anyon, Math.min(currentStep, CNOT_BRAID.length));
const yCur = yForStep(Math.min(currentStep, CNOT_BRAID.length));
ctx.beginPath();
ctx.arc(xCur, yCur, 6, 0, Math.PI * 2);
ctx.fillStyle = COLORS[anyon];
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 1.5;
ctx.stroke();
// Label
ctx.font = 'bold 11px system-ui, sans-serif';
ctx.fillStyle = COLORS[anyon];
ctx.textAlign = 'center';
ctx.fillText(LABELS[anyon], TRACK_X[anyon], Y_START + 18);
ctx.restore();
}
// Error indicator
if (errorInjected && errorSegment) {
ctx.save();
const es = errorSegment;
const ex = xOfAnyon(es.anyon, es.step) + (xOfAnyon(es.anyon, es.step+1) - xOfAnyon(es.anyon, es.step)) * 0.5 + es.wobble;
const ey = (yForStep(es.step) + yForStep(es.step+1)) / 2;
ctx.font = '12px system-ui';
ctx.fillStyle = '#c92f3c';
ctx.textAlign = 'center';
ctx.fillText('⚡ local noise', ex, ey - 10);
ctx.restore();
}
}
function updateUI() {
document.getElementById('step-info').textContent =
fmt('Step %currentStep% / %length%', { currentStep: currentStep, length: CNOT_BRAID.length });
const si = document.getElementById('state-info');
si.textContent = fmt('State: %v%', { v: STATE_LABELS[currentStep] });
si.className = 'state-ok';
document.getElementById('gate-label').textContent = GATE_LABELS[currentStep];
}
function log(msg) {
document.getElementById('log').textContent = msg;
}
document.getElementById('btn-step').addEventListener('click', () => {
if (currentStep < CNOT_BRAID.length) {
currentStep++;
errorInjected = false;
errorSegment = null;
const [i, dir] = CNOT_BRAID[currentStep - 1];
const dirStr = dir > 0 ? 'positive' : 'negative';
log(fmt('Applied σ%i%%v%%v2%: swap A%i%%v%↔A%i%%v3% (%dirStr% crossing)', { i: i, v: 1, v2: dir < 0 ? '⁻¹' : '', v3: 2, dirStr: dirStr }));
drawScene();
updateUI();
} else {
log('CNOT complete. Press Reset to start over.');
}
});
document.getElementById('btn-run').addEventListener('click', () => {
currentStep = 0;
errorInjected = false;
errorSegment = null;
let delay = 0;
for (let s = 0; s < CNOT_BRAID.length; s++) {
((step) => {
setTimeout(() => {
currentStep = step + 1;
errorInjected = false;
errorSegment = null;
drawScene();
updateUI();
const [i, dir] = CNOT_BRAID[step];
log(fmt('Step %step%%v%: σ%i%%v%%v2% — A%i%%v%↔A%i%%v3%', { step: step, v: 1, i: i, v2: dir < 0 ? '⁻¹' : '', v3: 2 }));
}, delay);
})(s);
delay += 500;
}
setTimeout(() => {
log('CNOT gate complete. Global braid encodes the gate — topology is intact.');
}, delay);
});
document.getElementById('btn-error').addEventListener('click', () => {
if (currentStep < 1) {
log('Advance at least one step before injecting an error.');
return;
}
// Inject a local wobble on a random strand at a past segment — does not change braid class
const targetStep = Math.floor(Math.random() * currentStep);
const targetAnyon = Math.floor(Math.random() * TRACKS);
const wobble = (Math.random() > 0.5 ? 1 : -1) * (12 + Math.random() * 10);
errorInjected = true;
errorSegment = { anyon: targetAnyon, step: targetStep, wobble };
drawScene();
updateUI();
const si = document.getElementById('state-info');
si.textContent = fmt('State: %v% (unchanged ✓)', { v: STATE_LABELS[currentStep] });
si.className = 'state-ok';
log(fmt('⚡ Local noise on A%targetAnyon%%v% at step %targetStep%. Braid class unchanged — logical state protected!', { targetAnyon: targetAnyon, v: 1, targetStep: targetStep }));
});
document.getElementById('btn-reset').addEventListener('click', () => {
currentStep = 0;
errorInjected = false;
errorSegment = null;
drawScene();
updateUI();
log('Reset. Ready to braid.');
});
// Initial render
drawScene();
updateUI();
log('Press Step or Run CNOT to begin braiding.');
The key insight: checking whether two braids are equivalent is a hard topological problem. Nature cannot accidentally make that mistake, so topological qubits are intrinsically fault-tolerant — unlike conventional qubits, which need active correction after every gate.
Comments
Loading comments...