Pick a secret bit-string (or use the random one). The oracle computes f(x)=s⋅xmod2. Try querying it classically — you will need one bit at a time. Then press Run quantum query to see the Hadamard trick recover all bits in one shot.
<!-- Main layout: secret selector, classical panel, quantum panel -->
<div class="bv-wrap">
<div class="secret-row">
<span class="label">Secret s =</span>
<div id="secret-bits" class="bit-row"></div>
<button id="btn-random" type="button" class="ghost sm">Random</button>
</div>
<hr class="divider"/>
<div class="panel">
<div class="panel-head">Classical: n queries</div>
<p class="panel-desc">Each query uses a basis vector to reveal one bit. Click to step through.</p>
<div id="classical-queries" class="query-log"></div>
<div class="panel-actions">
<button id="btn-classical-step" type="button">Query next bit</button>
<button id="btn-classical-reset" type="button" class="ghost sm">Reset</button>
</div>
<div class="result-row" id="classical-result"></div>
</div>
<hr class="divider"/>
<div class="panel">
<div class="panel-head">Quantum: 1 query</div>
<p class="panel-desc">Hadamard + phase kickback + Hadamard reveals all bits at once.</p>
<div id="quantum-visual" class="hadamard-vis"></div>
<div class="panel-actions">
<button id="btn-quantum" type="button">Run quantum query</button>
<button id="btn-quantum-reset" type="button" class="ghost sm">Reset</button>
</div>
<div class="result-row" id="quantum-result"></div>
</div>
</div>
/* Base layout styles */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: 14px 4px; }
.bv-wrap { max-width: 520px; margin: 0 auto; }
.secret-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .3rem; }
.label { font-size: .85rem; font-weight: 700; color: #444; white-space: nowrap; }
.bit-row { display: flex; gap: 4px; flex-wrap: wrap; }
/* Bit toggle button styles */
.bit { width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
font: 700 16px ui-monospace, monospace; border-radius: 6px; cursor: pointer; user-select: none;
border: 2px solid #adb1b8; background: #e4e7eb; transition: all .15s; }
.bit.on { background: #1d3557; border-color: #1d3557; color: #fff; }
.bit.off { background: #e4e7eb; color: #555; }
.divider { border: none; border-top: 1px solid #dde3ea; margin: .8rem 0; }
.panel { margin-bottom: .4rem; }
.panel-head { font-size: .9rem; font-weight: 700; color: #1d3557; margin-bottom: .2rem; }
.panel-desc { font-size: .82rem; color: #555; margin: 0 0 .4rem; line-height: 1.45; }
/* Query log styles */
.query-log { font: 13px/1.55 ui-monospace, monospace; min-height: 1.6em; color: #333;
background: #f4f6f8; border-radius: 6px; padding: .35rem .55rem; margin-bottom: .4rem; }
.q-row { display: flex; gap: .5rem; align-items: baseline; }
.q-x { color: #1d3557; }
.q-eq { color: #888; }
.q-val { color: #0a7d33; font-weight: 700; }
.panel-actions { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .3rem; }
.result-row { font-size: .9rem; font-weight: 600; min-height: 1.4em; }
.result-row.ok { color: #0a7d33; }
.result-row.progress { color: #555; }
/* Hadamard visualizer styles */
.hadamard-vis { font: 13px/1.6 ui-monospace, monospace; background: #f4f6f8;
border-radius: 6px; padding: .35rem .55rem; margin-bottom: .4rem; min-height: 2.5em; }
.h-step { color: #666; }
.h-step .hi { color: #1d3557; font-weight: 700; }
.h-step .hval { color: #0a7d33; font-weight: 700; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .85rem;
border: 1px solid #1d3557; background: #1d3557; color: #fff; border-radius: 7px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
button.sm { font-size: 12px; padding: .3rem .6rem; }
button:disabled { opacity: .45; cursor: default; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Bernstein-Vazirani demo: classical vs quantum query comparison
// Oracle: f(x) = s · x mod 2 (bitwise dot product mod 2)
// Classical approach: send basis vectors e_i to learn s[i] one at a time
// Quantum approach: Hadamard + oracle (phase kickback) + Hadamard = s in 1 query
const N = 5; // number of bits in the secret string
let secret = [1, 0, 1, 1, 0]; // default secret (user can toggle bits or randomize)
// Oracle function: dot product of secret and x, mod 2
function oracle(x) {
let dot = 0;
for (let i = 0; i < N; i++) dot ^= (secret[i] & x[i]);
return dot;
}
// Render the secret bit-string as clickable toggles
function renderSecret() {
const row = document.getElementById('secret-bits');
row.innerHTML = '';
for (let i = 0; i < N; i++) {
const d = document.createElement('div');
d.className = 'bit ' + (secret[i] ? 'on' : 'off');
d.textContent = secret[i];
d.dataset.idx = i;
d.addEventListener('click', () => {
secret[i] ^= 1;
resetAll();
renderSecret();
});
row.appendChild(d);
}
}
// Classical solver state: how many bits found so far
let classicalStep = 0;
let classicalFound = [];
function runClassicalStep() {
if (classicalStep >= N) return;
// Build the i-th basis vector (all zeros except position i)
const x = Array(N).fill(0);
x[classicalStep] = 1;
const bit = oracle(x);
classicalFound.push(bit);
const log = document.getElementById('classical-queries');
const row = document.createElement('div');
row.className = 'q-row';
row.innerHTML =
'<span class="q-x">f(' + x.join('') + ')</span>' +
'<span class="q-eq"> = </span>' +
'<span class="q-val">' + bit + '</span>' +
'<span class="q-eq"> → s[' + classicalStep + '] = ' + bit + '</span>';
log.appendChild(row);
classicalStep++;
updateClassicalResult();
}
function updateClassicalResult() {
const el = document.getElementById('classical-result');
if (classicalStep < N) {
el.textContent = fmt('Queried %classicalStep% of %N% bits — keep stepping.', { classicalStep: classicalStep, N: N });
el.className = 'result-row progress';
document.getElementById('btn-classical-step').disabled = false;
} else {
el.textContent = fmt('Done in %classicalFound% queries. Secret = %N%', { classicalFound: classicalFound.join(''), N: N });
el.className = 'result-row ok';
document.getElementById('btn-classical-step').disabled = true;
}
}
// Quantum algorithm: simulate the three-step Hadamard procedure
function runQuantum() {
const vis = document.getElementById('quantum-visual');
vis.innerHTML = '';
// Step 1: apply H to all input qubits (uniform superposition)
appendStep(vis, '<span class=’hi’>Step 1:</span> H⊗n applied — qubits enter uniform superposition over all 2^n inputs.');
// Step 2: oracle encodes s into phases via phase kickback
appendStep(vis, '<span class=’hi’>Step 2:</span> Oracle query — phase kickback encodes (−1)^(s·x) into every amplitude simultaneously.');
// Step 3: second Hadamard layer decodes phases back to s
appendStep(vis, '<span class=’hi’>Step 3:</span> H⊗n applied again — phases interfere constructively only at x = s.');
// Measurement collapses to |s> with probability 1
appendStep(vis, fmt('<span class=’hi’>Measure:</span> collapses to |<span class="hval">%secret%</span>⟩ with probability 1.', { secret: secret.join('') }));
const el = document.getElementById('quantum-result');
el.textContent = fmt('Secret revealed in 1 query: s = %secret%', { secret: secret.join('') });
el.className = 'result-row ok';
document.getElementById('btn-quantum').disabled = true;
}
function appendStep(container, html) {
const d = document.createElement('div');
d.className = 'h-step';
d.innerHTML = html;
container.appendChild(d);
}
// Reset helper functions
function resetClassical() {
classicalStep = 0;
classicalFound = [];
document.getElementById('classical-queries').innerHTML = '';
document.getElementById('classical-result').textContent = '';
document.getElementById('classical-result').className = 'result-row';
document.getElementById('btn-classical-step').disabled = false;
}
function resetQuantum() {
document.getElementById('quantum-visual').innerHTML = '';
document.getElementById('quantum-result').textContent = '';
document.getElementById('quantum-result').className = 'result-row';
document.getElementById('btn-quantum').disabled = false;
}
function resetAll() {
resetClassical();
resetQuantum();
}
// Wire up the random-secret button and all other controls
document.getElementById('btn-random').addEventListener('click', () => {
secret = Array.from({ length: N }, () => Math.random() < 0.5 ? 1 : 0);
resetAll();
renderSecret();
});
document.getElementById('btn-classical-step').addEventListener('click', runClassicalStep);
document.getElementById('btn-classical-reset').addEventListener('click', resetClassical);
document.getElementById('btn-quantum').addEventListener('click', runQuantum);
document.getElementById('btn-quantum-reset').addEventListener('click', resetQuantum);
renderSecret();
updateClassicalResult();
<!-- Main layout: secret selector, classical panel, quantum panel -->
<div class="bv-wrap">
<div class="secret-row">
<span class="label">Secret s =</span>
<div id="secret-bits" class="bit-row"></div>
<button id="btn-random" type="button" class="ghost sm">Random</button>
</div>
<hr class="divider"/>
<div class="panel">
<div class="panel-head">Classical: n queries</div>
<p class="panel-desc">Each query uses a basis vector to reveal one bit. Click to step through.</p>
<div id="classical-queries" class="query-log"></div>
<div class="panel-actions">
<button id="btn-classical-step" type="button">Query next bit</button>
<button id="btn-classical-reset" type="button" class="ghost sm">Reset</button>
</div>
<div class="result-row" id="classical-result"></div>
</div>
<hr class="divider"/>
<div class="panel">
<div class="panel-head">Quantum: 1 query</div>
<p class="panel-desc">Hadamard + phase kickback + Hadamard reveals all bits at once.</p>
<div id="quantum-visual" class="hadamard-vis"></div>
<div class="panel-actions">
<button id="btn-quantum" type="button">Run quantum query</button>
<button id="btn-quantum-reset" type="button" class="ghost sm">Reset</button>
</div>
<div class="result-row" id="quantum-result"></div>
</div>
</div>
/* Base layout styles */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: 14px 4px; }
.bv-wrap { max-width: 520px; margin: 0 auto; }
.secret-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .3rem; }
.label { font-size: .85rem; font-weight: 700; color: #444; white-space: nowrap; }
.bit-row { display: flex; gap: 4px; flex-wrap: wrap; }
/* Bit toggle button styles */
.bit { width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
font: 700 16px ui-monospace, monospace; border-radius: 6px; cursor: pointer; user-select: none;
border: 2px solid #adb1b8; background: #e4e7eb; transition: all .15s; }
.bit.on { background: #1d3557; border-color: #1d3557; color: #fff; }
.bit.off { background: #e4e7eb; color: #555; }
.divider { border: none; border-top: 1px solid #dde3ea; margin: .8rem 0; }
.panel { margin-bottom: .4rem; }
.panel-head { font-size: .9rem; font-weight: 700; color: #1d3557; margin-bottom: .2rem; }
.panel-desc { font-size: .82rem; color: #555; margin: 0 0 .4rem; line-height: 1.45; }
/* Query log styles */
.query-log { font: 13px/1.55 ui-monospace, monospace; min-height: 1.6em; color: #333;
background: #f4f6f8; border-radius: 6px; padding: .35rem .55rem; margin-bottom: .4rem; }
.q-row { display: flex; gap: .5rem; align-items: baseline; }
.q-x { color: #1d3557; }
.q-eq { color: #888; }
.q-val { color: #0a7d33; font-weight: 700; }
.panel-actions { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .3rem; }
.result-row { font-size: .9rem; font-weight: 600; min-height: 1.4em; }
.result-row.ok { color: #0a7d33; }
.result-row.progress { color: #555; }
/* Hadamard visualizer styles */
.hadamard-vis { font: 13px/1.6 ui-monospace, monospace; background: #f4f6f8;
border-radius: 6px; padding: .35rem .55rem; margin-bottom: .4rem; min-height: 2.5em; }
.h-step { color: #666; }
.h-step .hi { color: #1d3557; font-weight: 700; }
.h-step .hval { color: #0a7d33; font-weight: 700; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .85rem;
border: 1px solid #1d3557; background: #1d3557; color: #fff; border-radius: 7px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
button.sm { font-size: 12px; padding: .3rem .6rem; }
button:disabled { opacity: .45; cursor: default; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Bernstein-Vazirani demo: classical vs quantum query comparison
// Oracle: f(x) = s · x mod 2 (bitwise dot product mod 2)
// Classical approach: send basis vectors e_i to learn s[i] one at a time
// Quantum approach: Hadamard + oracle (phase kickback) + Hadamard = s in 1 query
const N = 5; // number of bits in the secret string
let secret = [1, 0, 1, 1, 0]; // default secret (user can toggle bits or randomize)
// Oracle function: dot product of secret and x, mod 2
function oracle(x) {
let dot = 0;
for (let i = 0; i < N; i++) dot ^= (secret[i] & x[i]);
return dot;
}
// Render the secret bit-string as clickable toggles
function renderSecret() {
const row = document.getElementById('secret-bits');
row.innerHTML = '';
for (let i = 0; i < N; i++) {
const d = document.createElement('div');
d.className = 'bit ' + (secret[i] ? 'on' : 'off');
d.textContent = secret[i];
d.dataset.idx = i;
d.addEventListener('click', () => {
secret[i] ^= 1;
resetAll();
renderSecret();
});
row.appendChild(d);
}
}
// Classical solver state: how many bits found so far
let classicalStep = 0;
let classicalFound = [];
function runClassicalStep() {
if (classicalStep >= N) return;
// Build the i-th basis vector (all zeros except position i)
const x = Array(N).fill(0);
x[classicalStep] = 1;
const bit = oracle(x);
classicalFound.push(bit);
const log = document.getElementById('classical-queries');
const row = document.createElement('div');
row.className = 'q-row';
row.innerHTML =
'<span class="q-x">f(' + x.join('') + ')</span>' +
'<span class="q-eq"> = </span>' +
'<span class="q-val">' + bit + '</span>' +
'<span class="q-eq"> → s[' + classicalStep + '] = ' + bit + '</span>';
log.appendChild(row);
classicalStep++;
updateClassicalResult();
}
function updateClassicalResult() {
const el = document.getElementById('classical-result');
if (classicalStep < N) {
el.textContent = fmt('Queried %classicalStep% of %N% bits — keep stepping.', { classicalStep: classicalStep, N: N });
el.className = 'result-row progress';
document.getElementById('btn-classical-step').disabled = false;
} else {
el.textContent = fmt('Done in %classicalFound% queries. Secret = %N%', { classicalFound: classicalFound.join(''), N: N });
el.className = 'result-row ok';
document.getElementById('btn-classical-step').disabled = true;
}
}
// Quantum algorithm: simulate the three-step Hadamard procedure
function runQuantum() {
const vis = document.getElementById('quantum-visual');
vis.innerHTML = '';
// Step 1: apply H to all input qubits (uniform superposition)
appendStep(vis, '<span class=’hi’>Step 1:</span> H⊗n applied — qubits enter uniform superposition over all 2^n inputs.');
// Step 2: oracle encodes s into phases via phase kickback
appendStep(vis, '<span class=’hi’>Step 2:</span> Oracle query — phase kickback encodes (−1)^(s·x) into every amplitude simultaneously.');
// Step 3: second Hadamard layer decodes phases back to s
appendStep(vis, '<span class=’hi’>Step 3:</span> H⊗n applied again — phases interfere constructively only at x = s.');
// Measurement collapses to |s> with probability 1
appendStep(vis, fmt('<span class=’hi’>Measure:</span> collapses to |<span class="hval">%secret%</span>⟩ with probability 1.', { secret: secret.join('') }));
const el = document.getElementById('quantum-result');
el.textContent = fmt('Secret revealed in 1 query: s = %secret%', { secret: secret.join('') });
el.className = 'result-row ok';
document.getElementById('btn-quantum').disabled = true;
}
function appendStep(container, html) {
const d = document.createElement('div');
d.className = 'h-step';
d.innerHTML = html;
container.appendChild(d);
}
// Reset helper functions
function resetClassical() {
classicalStep = 0;
classicalFound = [];
document.getElementById('classical-queries').innerHTML = '';
document.getElementById('classical-result').textContent = '';
document.getElementById('classical-result').className = 'result-row';
document.getElementById('btn-classical-step').disabled = false;
}
function resetQuantum() {
document.getElementById('quantum-visual').innerHTML = '';
document.getElementById('quantum-result').textContent = '';
document.getElementById('quantum-result').className = 'result-row';
document.getElementById('btn-quantum').disabled = false;
}
function resetAll() {
resetClassical();
resetQuantum();
}
// Wire up the random-secret button and all other controls
document.getElementById('btn-random').addEventListener('click', () => {
secret = Array.from({ length: N }, () => Math.random() < 0.5 ? 1 : 0);
resetAll();
renderSecret();
});
document.getElementById('btn-classical-step').addEventListener('click', runClassicalStep);
document.getElementById('btn-classical-reset').addEventListener('click', resetClassical);
document.getElementById('btn-quantum').addEventListener('click', runQuantum);
document.getElementById('btn-quantum-reset').addEventListener('click', resetQuantum);
renderSecret();
updateClassicalResult();
Notice the asymmetry. Each classical query learns exactly one bit of s — and you need all n. The quantum query puts x into uniform superposition over all 2n inputs simultaneously, applies the oracle coherently, and a final Hadamard layer reads out s all at once. The oracle is called once, no matter how large n is.
Comments
Loading comments...