<div class="controls">
<label class="ctrl-label">Input qubit |ψ⟩:</label>
<div class="presets">
<button class="preset active" data-state="0">|0⟩</button>
<button class="preset" data-state="1">|1⟩</button>
<button class="preset" data-state="plus">|+⟩</button>
<button class="preset" data-state="minus">|−⟩</button>
</div>
<button id="run" type="button">Run circuit</button>
</div>
<div id="circuit-view" class="circuit-view" aria-live="polite"></div>
<div id="result" class="result-box" aria-live="polite"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: 14px; }
.controls { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .8rem; }
.ctrl-label { font-size: .88rem; font-weight: 600; color: #444; white-space: nowrap; }
.presets { display: flex; gap: .35rem; }
.preset { font: 600 13px ui-monospace, monospace; padding: .3rem .65rem;
border: 1.5px solid #8fa6be; background: #f0f4f8; color: #1d3557;
border-radius: 6px; cursor: pointer; transition: all .15s; }
.preset.active { background: #1d3557; color: #fff; border-color: #1d3557; }
#run { font: 600 14px system-ui; padding: .4rem .9rem; background: #2a7de1; color: #fff;
border: none; border-radius: 8px; cursor: pointer; margin-left: auto; }
#run:hover { background: #1a6dd1; }
.circuit-view { background: #f8fafc; border: 1px solid #d0dce8; border-radius: 10px;
padding: 1rem 1.2rem; font-family: ui-monospace, monospace; font-size: .82rem;
line-height: 2; margin-bottom: .8rem; min-height: 120px; }
.wire { display: flex; align-items: center; gap: .3rem; margin: .15rem 0; }
.wire-label { width: 56px; font-weight: 700; color: #1d3557; text-align: right; flex-shrink: 0; }
.wire-line { flex: 1; height: 2px; background: #a0b4c8; position: relative; }
.gate-box { display: inline-flex; align-items: center; justify-content: center;
width: 38px; height: 28px; border: 1.8px solid #1d3557; background: #e8f0fb;
border-radius: 5px; font: 700 12px ui-monospace; color: #1d3557;
position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }
.gate-ctrl { width: 10px; height: 10px; border-radius: 50%; background: #1d3557;
position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }
.gate-vert { position: absolute; left: 50%; top: -14px; bottom: -14px;
width: 2px; background: #1d3557; transform: translateX(-50%); z-index: 0; }
.state-chip { display: inline-block; font: 600 12px ui-monospace; padding: .15rem .45rem;
border-radius: 5px; background: #e8eef3; color: #1d3557; margin: 0 .2rem; }
.result-box { border-radius: 10px; padding: .75rem 1rem; font-size: .9rem; line-height: 1.55;
border: 1.5px solid transparent; display: none; }
.result-box.ok { background: #edfaf3; border-color: #4caf85; color: #0a4a26; display: block; }
.result-box.warn { background: #fff8e6; border-color: #e6a817; color: #6b4200; display: block; }
.result-box strong { display: block; font-size: .95rem; margin-bottom: .3rem; }
.arrow { color: #2a7de1; font-weight: 700; }
.bell-note { margin-top: .4rem; font-size: .82rem; opacity: .85; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// No-Cloning Theorem Demo
// Shows why the CNOT "copy" circuit works for |0⟩ and |1⟩ but produces
// an entangled Bell state (not two copies) when the input is a superposition.
//
// State representation: complex amplitudes [a00, a01, a10, a11]
// for the two-qubit basis |00⟩, |01⟩, |10⟩, |11⟩.
// Qubit 1 = original (control), Qubit 2 = ancilla (target), starts in |0⟩.
const STATES = {
'0': { label: '|0⟩', amp: [1,0,0,0] }, // |0⟩|0⟩ → CNOT → |00⟩
'1': { label: '|1⟩', amp: [0,0,1,0] }, // |1⟩|0⟩ → CNOT → |11⟩
'plus': { label: '|+⟩', amp: [1/Math.SQRT2, 0, 1/Math.SQRT2, 0] }, // superposition
'minus':{ label: '|−⟩', amp: [1/Math.SQRT2, 0, -1/Math.SQRT2, 0] }, // superposition
};
// CNOT gate: control=qubit1, target=qubit2
// Maps: |00⟩→|00⟩, |01⟩→|01⟩, |10⟩→|11⟩, |11⟩→|10⟩
function applyCNOT(amp) {
const [a00, a01, a10, a11] = amp;
return [a00, a01, a11, a10]; // swap a10 <-> a11
}
function fmtAmp(v) {
if (Math.abs(v) < 1e-9) return null;
const s = Math.abs(v - 1/Math.SQRT2) < 1e-9 ? '1/√2' :
Math.abs(v + 1/Math.SQRT2) < 1e-9 ? '-1/√2' :
Math.abs(v - 1) < 1e-9 ? '1' :
Math.abs(v + 1) < 1e-9 ? '-1' : v.toFixed(3);
return s;
}
function describeState(amp) {
const labels = ['|00⟩','|01⟩','|10⟩','|11⟩'];
const terms = amp.map((a, i) => {
const f = fmtAmp(a);
if (!f) return null;
const prefix = f.startsWith('-') ? f : (f === '1' ? '' : f);
return (prefix ? prefix + '·' : '') + labels[i];
}).filter(Boolean);
return terms.join(' + ').replace(/\+ -/g, '− ') || '0';
}
// Determine if the output is a product state or entangled
// Output [a00, a01, a10, a11] is separable iff a00*a11 == a01*a10
function isSeparable(amp) {
return Math.abs(amp[0]*amp[3] - amp[1]*amp[2]) < 1e-9;
}
// Build the circuit diagram
function renderCircuit(inputLabel, outputAmp, inputAmp) {
const cv = document.getElementById('circuit-view');
const outDesc = describeState(outputAmp);
cv.innerHTML = "\n " + fmt(`<div class="wire">
<span class="wire-label">ψ:</span>
<span class="state-chip">%inputLabel%</span>
<span class="arrow"> ──── </span>
<span style="position:relative;display:inline-block;width:60px;height:30px;">
<span class="gate-vert"></span>
<span class="gate-ctrl"></span>
</span>
<span class="arrow"> ──── </span>
<span class="state-chip">%inputLabel%</span>
</div>
<div class="wire">
<span class="wire-label">|0⟩:</span>
<span class="state-chip">|0⟩</span>
<span class="arrow"> ──── </span>
<span style="position:relative;display:inline-block;width:60px;height:30px;">
<span class="gate-box">⊕</span>
</span>
<span class="arrow"> ──── </span>
<span class="state-chip">?</span>
</div>
<div style="margin-top:.5rem;font-size:.8rem;color:#555;">
Output state: <strong style="color:#1d3557">%outDesc%</strong>
</div>`, { inputLabel: inputLabel, outDesc: outDesc });
}
let currentState = '0';
function run() {
const s = STATES[currentState];
const out = applyCNOT(s.amp);
const sep = isSeparable(out);
renderCircuit(s.label, out, s.amp);
const rb = document.getElementById('result');
const outDesc = describeState(out);
if (sep) {
// For |0⟩ and |1⟩ the output is a product state that "looks like a copy"
let cloneDesc = '';
if (currentState === '0') cloneDesc = `|0⟩ ⊗ |0⟩ — looks like two copies of |0⟩!`;
if (currentState === '1') cloneDesc = `|1⟩ ⊗ |1⟩ — looks like two copies of |1⟩!`;
rb.className = 'result-box ok';
rb.innerHTML = fmt(`<strong>Basis state: copy appears to work.</strong>
Output = %outDesc% = %cloneDesc%
<div class="bell-note">For basis states the CNOT produces the right result by coincidence. But this only works because the input was already a definite classical bit — no quantum superposition involved. Try |+⟩ or |−⟩ to see the theorem in action.</div>`, { outDesc: outDesc, cloneDesc: cloneDesc });
} else {
// Superposition → entangled Bell state
let expected = currentState === 'plus'
? '|+⟩ ⊗ |+⟩ = (|00⟩+|01⟩+|10⟩+|11⟩)/2'
: '|−⟩ ⊗ |−⟩ = (|00⟩−|01⟩−|10⟩+|11⟩)/2';
rb.className = 'result-box warn';
rb.innerHTML = fmt(`<strong>Superposition: cloning fails — output is entangled.</strong>
Got: %outDesc% (a Bell state)<br>
Expected for a true copy: %expected%<br>
<div class="bell-note">The CNOT spread the superposition across both qubits instead of duplicating it. The two qubits are now <em>entangled</em> — measuring one instantly determines the other. This is not two independent copies of the input; it is a completely different state. The no-cloning theorem says no unitary can do better.</div>`, { outDesc: outDesc, expected: expected });
}
}
document.querySelectorAll('.preset').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.preset').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentState = btn.dataset.state;
document.getElementById('result').className = 'result-box';
document.getElementById('result').innerHTML = '';
document.getElementById('circuit-view').innerHTML =
'<span style="color:#999;font-size:.85rem">Press Run circuit to see the output.</span>';
});
});
document.getElementById('run').addEventListener('click', run);
// Initial render placeholder
document.getElementById('circuit-view').innerHTML =
'<span style="color:#999;font-size:.85rem">Select an input state and press Run circuit.</span>';
<div class="controls">
<label class="ctrl-label">Input qubit |ψ⟩:</label>
<div class="presets">
<button class="preset active" data-state="0">|0⟩</button>
<button class="preset" data-state="1">|1⟩</button>
<button class="preset" data-state="plus">|+⟩</button>
<button class="preset" data-state="minus">|−⟩</button>
</div>
<button id="run" type="button">Run circuit</button>
</div>
<div id="circuit-view" class="circuit-view" aria-live="polite"></div>
<div id="result" class="result-box" aria-live="polite"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: 14px; }
.controls { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .8rem; }
.ctrl-label { font-size: .88rem; font-weight: 600; color: #444; white-space: nowrap; }
.presets { display: flex; gap: .35rem; }
.preset { font: 600 13px ui-monospace, monospace; padding: .3rem .65rem;
border: 1.5px solid #8fa6be; background: #f0f4f8; color: #1d3557;
border-radius: 6px; cursor: pointer; transition: all .15s; }
.preset.active { background: #1d3557; color: #fff; border-color: #1d3557; }
#run { font: 600 14px system-ui; padding: .4rem .9rem; background: #2a7de1; color: #fff;
border: none; border-radius: 8px; cursor: pointer; margin-left: auto; }
#run:hover { background: #1a6dd1; }
.circuit-view { background: #f8fafc; border: 1px solid #d0dce8; border-radius: 10px;
padding: 1rem 1.2rem; font-family: ui-monospace, monospace; font-size: .82rem;
line-height: 2; margin-bottom: .8rem; min-height: 120px; }
.wire { display: flex; align-items: center; gap: .3rem; margin: .15rem 0; }
.wire-label { width: 56px; font-weight: 700; color: #1d3557; text-align: right; flex-shrink: 0; }
.wire-line { flex: 1; height: 2px; background: #a0b4c8; position: relative; }
.gate-box { display: inline-flex; align-items: center; justify-content: center;
width: 38px; height: 28px; border: 1.8px solid #1d3557; background: #e8f0fb;
border-radius: 5px; font: 700 12px ui-monospace; color: #1d3557;
position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }
.gate-ctrl { width: 10px; height: 10px; border-radius: 50%; background: #1d3557;
position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }
.gate-vert { position: absolute; left: 50%; top: -14px; bottom: -14px;
width: 2px; background: #1d3557; transform: translateX(-50%); z-index: 0; }
.state-chip { display: inline-block; font: 600 12px ui-monospace; padding: .15rem .45rem;
border-radius: 5px; background: #e8eef3; color: #1d3557; margin: 0 .2rem; }
.result-box { border-radius: 10px; padding: .75rem 1rem; font-size: .9rem; line-height: 1.55;
border: 1.5px solid transparent; display: none; }
.result-box.ok { background: #edfaf3; border-color: #4caf85; color: #0a4a26; display: block; }
.result-box.warn { background: #fff8e6; border-color: #e6a817; color: #6b4200; display: block; }
.result-box strong { display: block; font-size: .95rem; margin-bottom: .3rem; }
.arrow { color: #2a7de1; font-weight: 700; }
.bell-note { margin-top: .4rem; font-size: .82rem; opacity: .85; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// No-Cloning Theorem Demo
// Shows why the CNOT "copy" circuit works for |0⟩ and |1⟩ but produces
// an entangled Bell state (not two copies) when the input is a superposition.
//
// State representation: complex amplitudes [a00, a01, a10, a11]
// for the two-qubit basis |00⟩, |01⟩, |10⟩, |11⟩.
// Qubit 1 = original (control), Qubit 2 = ancilla (target), starts in |0⟩.
const STATES = {
'0': { label: '|0⟩', amp: [1,0,0,0] }, // |0⟩|0⟩ → CNOT → |00⟩
'1': { label: '|1⟩', amp: [0,0,1,0] }, // |1⟩|0⟩ → CNOT → |11⟩
'plus': { label: '|+⟩', amp: [1/Math.SQRT2, 0, 1/Math.SQRT2, 0] }, // superposition
'minus':{ label: '|−⟩', amp: [1/Math.SQRT2, 0, -1/Math.SQRT2, 0] }, // superposition
};
// CNOT gate: control=qubit1, target=qubit2
// Maps: |00⟩→|00⟩, |01⟩→|01⟩, |10⟩→|11⟩, |11⟩→|10⟩
function applyCNOT(amp) {
const [a00, a01, a10, a11] = amp;
return [a00, a01, a11, a10]; // swap a10 <-> a11
}
function fmtAmp(v) {
if (Math.abs(v) < 1e-9) return null;
const s = Math.abs(v - 1/Math.SQRT2) < 1e-9 ? '1/√2' :
Math.abs(v + 1/Math.SQRT2) < 1e-9 ? '-1/√2' :
Math.abs(v - 1) < 1e-9 ? '1' :
Math.abs(v + 1) < 1e-9 ? '-1' : v.toFixed(3);
return s;
}
function describeState(amp) {
const labels = ['|00⟩','|01⟩','|10⟩','|11⟩'];
const terms = amp.map((a, i) => {
const f = fmtAmp(a);
if (!f) return null;
const prefix = f.startsWith('-') ? f : (f === '1' ? '' : f);
return (prefix ? prefix + '·' : '') + labels[i];
}).filter(Boolean);
return terms.join(' + ').replace(/\+ -/g, '− ') || '0';
}
// Determine if the output is a product state or entangled
// Output [a00, a01, a10, a11] is separable iff a00*a11 == a01*a10
function isSeparable(amp) {
return Math.abs(amp[0]*amp[3] - amp[1]*amp[2]) < 1e-9;
}
// Build the circuit diagram
function renderCircuit(inputLabel, outputAmp, inputAmp) {
const cv = document.getElementById('circuit-view');
const outDesc = describeState(outputAmp);
cv.innerHTML = "\n " + fmt(`<div class="wire">
<span class="wire-label">ψ:</span>
<span class="state-chip">%inputLabel%</span>
<span class="arrow"> ──── </span>
<span style="position:relative;display:inline-block;width:60px;height:30px;">
<span class="gate-vert"></span>
<span class="gate-ctrl"></span>
</span>
<span class="arrow"> ──── </span>
<span class="state-chip">%inputLabel%</span>
</div>
<div class="wire">
<span class="wire-label">|0⟩:</span>
<span class="state-chip">|0⟩</span>
<span class="arrow"> ──── </span>
<span style="position:relative;display:inline-block;width:60px;height:30px;">
<span class="gate-box">⊕</span>
</span>
<span class="arrow"> ──── </span>
<span class="state-chip">?</span>
</div>
<div style="margin-top:.5rem;font-size:.8rem;color:#555;">
Output state: <strong style="color:#1d3557">%outDesc%</strong>
</div>`, { inputLabel: inputLabel, outDesc: outDesc });
}
let currentState = '0';
function run() {
const s = STATES[currentState];
const out = applyCNOT(s.amp);
const sep = isSeparable(out);
renderCircuit(s.label, out, s.amp);
const rb = document.getElementById('result');
const outDesc = describeState(out);
if (sep) {
// For |0⟩ and |1⟩ the output is a product state that "looks like a copy"
let cloneDesc = '';
if (currentState === '0') cloneDesc = `|0⟩ ⊗ |0⟩ — looks like two copies of |0⟩!`;
if (currentState === '1') cloneDesc = `|1⟩ ⊗ |1⟩ — looks like two copies of |1⟩!`;
rb.className = 'result-box ok';
rb.innerHTML = fmt(`<strong>Basis state: copy appears to work.</strong>
Output = %outDesc% = %cloneDesc%
<div class="bell-note">For basis states the CNOT produces the right result by coincidence. But this only works because the input was already a definite classical bit — no quantum superposition involved. Try |+⟩ or |−⟩ to see the theorem in action.</div>`, { outDesc: outDesc, cloneDesc: cloneDesc });
} else {
// Superposition → entangled Bell state
let expected = currentState === 'plus'
? '|+⟩ ⊗ |+⟩ = (|00⟩+|01⟩+|10⟩+|11⟩)/2'
: '|−⟩ ⊗ |−⟩ = (|00⟩−|01⟩−|10⟩+|11⟩)/2';
rb.className = 'result-box warn';
rb.innerHTML = fmt(`<strong>Superposition: cloning fails — output is entangled.</strong>
Got: %outDesc% (a Bell state)<br>
Expected for a true copy: %expected%<br>
<div class="bell-note">The CNOT spread the superposition across both qubits instead of duplicating it. The two qubits are now <em>entangled</em> — measuring one instantly determines the other. This is not two independent copies of the input; it is a completely different state. The no-cloning theorem says no unitary can do better.</div>`, { outDesc: outDesc, expected: expected });
}
}
document.querySelectorAll('.preset').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.preset').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentState = btn.dataset.state;
document.getElementById('result').className = 'result-box';
document.getElementById('result').innerHTML = '';
document.getElementById('circuit-view').innerHTML =
'<span style="color:#999;font-size:.85rem">Press Run circuit to see the output.</span>';
});
});
document.getElementById('run').addEventListener('click', run);
// Initial render placeholder
document.getElementById('circuit-view').innerHTML =
'<span style="color:#999;font-size:.85rem">Select an input state and press Run circuit.</span>';
Comments
Loading comments...