<div class="controls">
<label>
Initial error rate (ε₀):
<input type="range" id="errSlider" min="1" max="20" value="10" step="1">
<span id="errVal">10%</span>
</label>
<label>
Protocol:
<select id="protocol">
<option value="15">15-to-1 (ε → ε⁵ / 35)</option>
<option value="7">7-to-1 (ε → ε³ / 7)</option>
</select>
</label>
<label>
Rounds:
<input type="range" id="roundSlider" min="1" max="6" value="3" step="1">
<span id="roundVal">3</span>
</label>
<button id="runBtn" type="button">Run distillation</button>
</div>
<div id="chart" class="chart"></div>
<div id="summary" class="summary"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: 14px 2px; }
.controls { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .8rem; font-size: .88rem; }
.controls label { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.controls input[type=range] { width: 120px; accent-color: #1d3557; }
select { border: 1px solid #cdd9e3; border-radius: 6px; padding: 2px 6px; font-size: .85rem; background: #f4f7fa; }
button { font: 600 14px system-ui, sans-serif; padding: .4rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; align-self: flex-start; }
button:hover { background: #162a40; }
.chart { display: flex; flex-direction: column; gap: 6px; }
.row { display: flex; align-items: center; gap: 8px; font-size: .83rem; }
.row-label { width: 56px; text-align: right; color: #555; flex-shrink: 0; }
.bar-wrap { flex: 1; background: #e8eef3; border-radius: 4px; height: 22px; overflow: hidden; }
.bar { height: 100%; border-radius: 4px; display: flex; align-items: center; padding-left: 5px;
font-size: .75rem; font-weight: 700; color: #fff; white-space: nowrap; min-width: 4px;
transition: width .5s ease; }
.cost-label { width: 90px; text-align: right; font-size: .78rem; color: #555; flex-shrink: 0; }
.summary { margin-top: .8rem; font-size: .88rem; line-height: 1.55; background: #f4f7fa;
border-left: 3px solid #1d3557; padding: .5rem .7rem; border-radius: 0 6px 6px 0; }
.summary strong { color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Magic-state distillation simulator.
// 15-to-1 protocol: one output from 15 inputs, output error ~ eps^5 / 35
// 7-to-1 protocol: one output from 7 inputs, output error ~ eps^3 / 7
// (Both are established results from Bravyi & Kitaev 2005 and later refinements.)
// Overhead: total raw states consumed = ratio^rounds to make 1 final magic state.
// Round i produces 1 output from ratio^(rounds-i) input copies (recursive expansion).
// Total = sum_{i=1}^{rounds} ratio^i ... but simplest view: ratio^rounds raw per final output.
const errSlider = document.getElementById('errSlider');
const roundSlider= document.getElementById('roundSlider');
const errVal = document.getElementById('errVal');
const roundVal = document.getElementById('roundVal');
const protocolSel= document.getElementById('protocol');
const chart = document.getElementById('chart');
const summary = document.getElementById('summary');
errSlider.addEventListener('input', () => { errVal.textContent = errSlider.value + '%'; });
roundSlider.addEventListener('input', () => { roundVal.textContent = roundSlider.value; });
function distill(eps0, rounds, ratio, power, divisor) {
// Returns array of {round, eps, cost} where cost = raw states consumed to reach this level
const results = [];
let eps = eps0;
let cost = 1;
results.push({ round: 0, eps: eps0, cost: 1 });
for (let r = 1; r <= rounds; r++) {
eps = Math.pow(eps, power) / divisor;
if (eps < 0) eps = 0;
cost = cost * ratio; // each output of this round needed `ratio` inputs
results.push({ round: r, eps: Math.min(eps, 1), cost: cost });
}
return results;
}
function fmtEps(e) {
if (e <= 0) return '< 10⁻³⁰';
if (e >= 0.1) return (e * 100).toFixed(1) + '%';
const exp = Math.floor(Math.log10(e));
const mant = e / Math.pow(10, exp);
if (Math.abs(mant - 1) < 0.05) return '10' + superscript(exp);
return mant.toFixed(1) + '×10' + superscript(exp);
}
function superscript(n) {
const map = {'0':'⁰','1':'¹','2':'²','3':'³','4':'⁴','5':'⁵','6':'⁶','7':'⁷','8':'⁸','9':'⁹','-':'⁻'};
return String(n).split('').map(c => map[c] || c).join('');
}
function fmtCost(c) {
if (c < 1000) return fmt('%c% raw', { c: c });
if (c < 1e6) return fmt('%v%k raw', { v: (c/1000).toFixed(1) });
return fmt('%v%M raw', { v: (c/1e6).toFixed(2) });
}
// Color gradient: blue (low error) → orange → red (high error)
function errColor(eps) {
// eps in [0, 1]
const t = Math.min(1, Math.max(0, eps));
// lerp from #0a7d33 (green) to #e63946 (red)
const r = Math.round(10 + t * (230 - 10));
const g = Math.round(125 + t * (57 - 125));
const b = Math.round(51 + t * (70 - 51));
return `rgb(${r},${g},${b})`;
}
document.getElementById('runBtn').addEventListener('click', () => {
const eps0 = errSlider.value / 100;
const rounds = parseInt(roundSlider.value, 10);
const ratio = parseInt(protocolSel.value, 10);
const power = ratio === 15 ? 5 : 3;
const divisor= ratio === 15 ? 35 : 7;
const data = distill(eps0, rounds, ratio, power, divisor);
// Draw chart
chart.innerHTML = '';
// Header
const hdr = document.createElement('div');
hdr.className = 'row';
hdr.innerHTML =
'<div class="row-label" style="font-weight:700;color:#1d3557">Round</div><div class="bar-wrap" style="background:transparent;padding-left:0;font-weight:700;color:#1d3557;height:auto">Error rate</div><div class="cost-label" style="font-weight:700;color:#1d3557">Qubits used</div>';
chart.appendChild(hdr);
// Reference: log scale, map to bar width
// Worst eps = eps0, best = final. We map log scale.
const logWorst = Math.log10(Math.max(eps0, 1e-30));
const logBest = Math.min(Math.log10(Math.max(data[data.length-1].eps, 1e-30)), logWorst - 1);
const logRange = logWorst - logBest || 1;
data.forEach(d => {
const row = document.createElement('div');
row.className = 'row';
const logE = Math.log10(Math.max(d.eps, 1e-30));
const frac = Math.max(0.02, Math.min(1, (logWorst - logE) / logRange));
// Actually show how much better we've gotten — fraction of total improvement
const widthPct = d.round === 0 ? 100 : Math.max(4, 100 * (1 - frac + 0.04));
// For round 0 show full red bar, each successive round shorter (cleaner)
const barWidth = d.round === 0 ? 100 : Math.max(4, Math.round(100 * Math.pow(10, logE - logWorst) * (-1) + 100));
// simpler: just use 100 * (logWorst - logE) / logRange for "improvement" bar
const improvedFrac = d.round === 0 ? 0 : Math.min(1, (logWorst - logE) / logRange);
const errorFrac = 1 - improvedFrac; // how bad it still is
const barPct = Math.max(3, Math.round(errorFrac * 96) + 4);
const label = document.createElement('div');
label.className = 'row-label';
label.textContent = d.round === 0 ? 'Raw' : fmt('Round %round%', { round: d.round });
const wrap = document.createElement('div');
wrap.className = 'bar-wrap';
const bar = document.createElement('div');
bar.className = 'bar';
bar.style.width = '0%';
bar.style.background = errColor(d.eps);
bar.textContent = fmtEps(d.eps);
wrap.appendChild(bar);
const costLbl = document.createElement('div');
costLbl.className = 'cost-label';
costLbl.textContent = d.round === 0 ? '1 raw' : fmtCost(d.cost);
row.appendChild(label);
row.appendChild(wrap);
row.appendChild(costLbl);
chart.appendChild(row);
// Animate bar width after render
setTimeout(() => { bar.style.width = barPct + '%'; }, 50 + d.round * 80);
});
// Summary
const finalEps = data[data.length - 1].eps;
const totalCost = data[data.length - 1].cost;
const reduction = finalEps > 0 ? Math.round(Math.log10(eps0 / Math.max(finalEps, 1e-30))) : 30;
summary.innerHTML =
fmt('<strong>Result after %rounds% round%v%:</strong> error rate drops from <strong>%v2%%</strong> to <strong>%fmtEps%</strong> (( %reduction% orders of magnitude)), consuming <strong>%fmtCost%</strong> per clean magic state. %v3%', { rounds: rounds, v: rounds > 1 ? 's' : '', v2: (eps0 * 100).toFixed(0), fmtEps: fmtEps(finalEps), reduction: reduction, fmtCost: fmtCost(totalCost), v3: totalCost >= 1e6 ?
'At this scale, each logical T gate requires a dedicated distillation factory.' :
'Each T gate in a fault-tolerant circuit carries this hidden overhead.' });
console.log('Distillation results:', data.map(d =>
`Round ${d.round}: eps=${d.eps.toExponential(2)}, cost=${d.cost}`).join(' | '));
});
// Run on load with defaults
document.getElementById('runBtn').click();
<div class="controls">
<label>
Initial error rate (ε₀):
<input type="range" id="errSlider" min="1" max="20" value="10" step="1">
<span id="errVal">10%</span>
</label>
<label>
Protocol:
<select id="protocol">
<option value="15">15-to-1 (ε → ε⁵ / 35)</option>
<option value="7">7-to-1 (ε → ε³ / 7)</option>
</select>
</label>
<label>
Rounds:
<input type="range" id="roundSlider" min="1" max="6" value="3" step="1">
<span id="roundVal">3</span>
</label>
<button id="runBtn" type="button">Run distillation</button>
</div>
<div id="chart" class="chart"></div>
<div id="summary" class="summary"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: 14px 2px; }
.controls { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .8rem; font-size: .88rem; }
.controls label { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.controls input[type=range] { width: 120px; accent-color: #1d3557; }
select { border: 1px solid #cdd9e3; border-radius: 6px; padding: 2px 6px; font-size: .85rem; background: #f4f7fa; }
button { font: 600 14px system-ui, sans-serif; padding: .4rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; align-self: flex-start; }
button:hover { background: #162a40; }
.chart { display: flex; flex-direction: column; gap: 6px; }
.row { display: flex; align-items: center; gap: 8px; font-size: .83rem; }
.row-label { width: 56px; text-align: right; color: #555; flex-shrink: 0; }
.bar-wrap { flex: 1; background: #e8eef3; border-radius: 4px; height: 22px; overflow: hidden; }
.bar { height: 100%; border-radius: 4px; display: flex; align-items: center; padding-left: 5px;
font-size: .75rem; font-weight: 700; color: #fff; white-space: nowrap; min-width: 4px;
transition: width .5s ease; }
.cost-label { width: 90px; text-align: right; font-size: .78rem; color: #555; flex-shrink: 0; }
.summary { margin-top: .8rem; font-size: .88rem; line-height: 1.55; background: #f4f7fa;
border-left: 3px solid #1d3557; padding: .5rem .7rem; border-radius: 0 6px 6px 0; }
.summary strong { color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Magic-state distillation simulator.
// 15-to-1 protocol: one output from 15 inputs, output error ~ eps^5 / 35
// 7-to-1 protocol: one output from 7 inputs, output error ~ eps^3 / 7
// (Both are established results from Bravyi & Kitaev 2005 and later refinements.)
// Overhead: total raw states consumed = ratio^rounds to make 1 final magic state.
// Round i produces 1 output from ratio^(rounds-i) input copies (recursive expansion).
// Total = sum_{i=1}^{rounds} ratio^i ... but simplest view: ratio^rounds raw per final output.
const errSlider = document.getElementById('errSlider');
const roundSlider= document.getElementById('roundSlider');
const errVal = document.getElementById('errVal');
const roundVal = document.getElementById('roundVal');
const protocolSel= document.getElementById('protocol');
const chart = document.getElementById('chart');
const summary = document.getElementById('summary');
errSlider.addEventListener('input', () => { errVal.textContent = errSlider.value + '%'; });
roundSlider.addEventListener('input', () => { roundVal.textContent = roundSlider.value; });
function distill(eps0, rounds, ratio, power, divisor) {
// Returns array of {round, eps, cost} where cost = raw states consumed to reach this level
const results = [];
let eps = eps0;
let cost = 1;
results.push({ round: 0, eps: eps0, cost: 1 });
for (let r = 1; r <= rounds; r++) {
eps = Math.pow(eps, power) / divisor;
if (eps < 0) eps = 0;
cost = cost * ratio; // each output of this round needed `ratio` inputs
results.push({ round: r, eps: Math.min(eps, 1), cost: cost });
}
return results;
}
function fmtEps(e) {
if (e <= 0) return '< 10⁻³⁰';
if (e >= 0.1) return (e * 100).toFixed(1) + '%';
const exp = Math.floor(Math.log10(e));
const mant = e / Math.pow(10, exp);
if (Math.abs(mant - 1) < 0.05) return '10' + superscript(exp);
return mant.toFixed(1) + '×10' + superscript(exp);
}
function superscript(n) {
const map = {'0':'⁰','1':'¹','2':'²','3':'³','4':'⁴','5':'⁵','6':'⁶','7':'⁷','8':'⁸','9':'⁹','-':'⁻'};
return String(n).split('').map(c => map[c] || c).join('');
}
function fmtCost(c) {
if (c < 1000) return fmt('%c% raw', { c: c });
if (c < 1e6) return fmt('%v%k raw', { v: (c/1000).toFixed(1) });
return fmt('%v%M raw', { v: (c/1e6).toFixed(2) });
}
// Color gradient: blue (low error) → orange → red (high error)
function errColor(eps) {
// eps in [0, 1]
const t = Math.min(1, Math.max(0, eps));
// lerp from #0a7d33 (green) to #e63946 (red)
const r = Math.round(10 + t * (230 - 10));
const g = Math.round(125 + t * (57 - 125));
const b = Math.round(51 + t * (70 - 51));
return `rgb(${r},${g},${b})`;
}
document.getElementById('runBtn').addEventListener('click', () => {
const eps0 = errSlider.value / 100;
const rounds = parseInt(roundSlider.value, 10);
const ratio = parseInt(protocolSel.value, 10);
const power = ratio === 15 ? 5 : 3;
const divisor= ratio === 15 ? 35 : 7;
const data = distill(eps0, rounds, ratio, power, divisor);
// Draw chart
chart.innerHTML = '';
// Header
const hdr = document.createElement('div');
hdr.className = 'row';
hdr.innerHTML =
'<div class="row-label" style="font-weight:700;color:#1d3557">Round</div><div class="bar-wrap" style="background:transparent;padding-left:0;font-weight:700;color:#1d3557;height:auto">Error rate</div><div class="cost-label" style="font-weight:700;color:#1d3557">Qubits used</div>';
chart.appendChild(hdr);
// Reference: log scale, map to bar width
// Worst eps = eps0, best = final. We map log scale.
const logWorst = Math.log10(Math.max(eps0, 1e-30));
const logBest = Math.min(Math.log10(Math.max(data[data.length-1].eps, 1e-30)), logWorst - 1);
const logRange = logWorst - logBest || 1;
data.forEach(d => {
const row = document.createElement('div');
row.className = 'row';
const logE = Math.log10(Math.max(d.eps, 1e-30));
const frac = Math.max(0.02, Math.min(1, (logWorst - logE) / logRange));
// Actually show how much better we've gotten — fraction of total improvement
const widthPct = d.round === 0 ? 100 : Math.max(4, 100 * (1 - frac + 0.04));
// For round 0 show full red bar, each successive round shorter (cleaner)
const barWidth = d.round === 0 ? 100 : Math.max(4, Math.round(100 * Math.pow(10, logE - logWorst) * (-1) + 100));
// simpler: just use 100 * (logWorst - logE) / logRange for "improvement" bar
const improvedFrac = d.round === 0 ? 0 : Math.min(1, (logWorst - logE) / logRange);
const errorFrac = 1 - improvedFrac; // how bad it still is
const barPct = Math.max(3, Math.round(errorFrac * 96) + 4);
const label = document.createElement('div');
label.className = 'row-label';
label.textContent = d.round === 0 ? 'Raw' : fmt('Round %round%', { round: d.round });
const wrap = document.createElement('div');
wrap.className = 'bar-wrap';
const bar = document.createElement('div');
bar.className = 'bar';
bar.style.width = '0%';
bar.style.background = errColor(d.eps);
bar.textContent = fmtEps(d.eps);
wrap.appendChild(bar);
const costLbl = document.createElement('div');
costLbl.className = 'cost-label';
costLbl.textContent = d.round === 0 ? '1 raw' : fmtCost(d.cost);
row.appendChild(label);
row.appendChild(wrap);
row.appendChild(costLbl);
chart.appendChild(row);
// Animate bar width after render
setTimeout(() => { bar.style.width = barPct + '%'; }, 50 + d.round * 80);
});
// Summary
const finalEps = data[data.length - 1].eps;
const totalCost = data[data.length - 1].cost;
const reduction = finalEps > 0 ? Math.round(Math.log10(eps0 / Math.max(finalEps, 1e-30))) : 30;
summary.innerHTML =
fmt('<strong>Result after %rounds% round%v%:</strong> error rate drops from <strong>%v2%%</strong> to <strong>%fmtEps%</strong> (( %reduction% orders of magnitude)), consuming <strong>%fmtCost%</strong> per clean magic state. %v3%', { rounds: rounds, v: rounds > 1 ? 's' : '', v2: (eps0 * 100).toFixed(0), fmtEps: fmtEps(finalEps), reduction: reduction, fmtCost: fmtCost(totalCost), v3: totalCost >= 1e6 ?
'At this scale, each logical T gate requires a dedicated distillation factory.' :
'Each T gate in a fault-tolerant circuit carries this hidden overhead.' });
console.log('Distillation results:', data.map(d =>
`Round ${d.round}: eps=${d.eps.toExponential(2)}, cost=${d.cost}`).join(' | '));
});
// Run on load with defaults
document.getElementById('runBtn').click();
Notice the asymmetry: after just a few rounds the logical error rate plunges many orders of magnitude below the physical rate. But the qubit overhead — the total number of raw states consumed — grows exponentially with the number of rounds. A physical error rate of 1% might need three or four rounds, consuming thousands of raw magic states just to produce one usable T gate.
Comments
Loading comments...