Below is a hidden function on 4-bit inputs (16 possible inputs). It is secretly either constant or balanced — you don't know which. Probe it classically: each click reveals one more output. To be sure it's constant you may have to check 2n⁄2 + 1 = 9 inputs in the worst case.
<p class="hint">A hidden function on 4-bit inputs is secretly <b>constant</b> (same answer everywhere) or <b>balanced</b> (0 for half, 1 for the other half). Probe it <b>classically</b> — one input per click — or run the <b>quantum</b> algorithm, which decides in a single query. New function makes a fresh secret box.</p>
<div id="grid" class="grid"></div>
<div class="counts">
<span>Classical queries: <b id="cq">0</b> / 9 worst case</span>
<span>Quantum queries: <b id="qq">0</b></span>
</div>
<div class="status" id="status">Probe the box to decide: constant or balanced?</div>
<div class="btns">
<button id="classic" type="button">Classical query</button>
<button id="quantum" type="button">Quantum query</button>
<button id="reset" type="button" class="ghost">New function</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.grid { display: grid; grid-template-columns: repeat(8, 38px); gap: 5px; margin: .5rem 0; }
.bit { width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
font: 700 15px ui-monospace, monospace; border-radius: 7px; background: #e8eef3;
color: #1d3557; border: 1px solid #cdd9e3; }
.bit.q0 { background: #d4edda; border-color: #9ccaa9; color: #0a7d33; }
.bit.q1 { background: #f8d7da; border-color: #e0a3a9; color: #c92f3c; }
.bit small { font-size: 9px; font-weight: 600; opacity: .65; display: block; line-height: 1; }
.counts { display: flex; gap: 1.2rem; flex-wrap: wrap; font-size: .9rem; color: #444; margin: .3rem 0 .2rem; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.status.q { color: #5a2a9d; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button#quantum { background: #5a2a9d; border-color: #5a2a9d; }
button.ghost { background: #fff; color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Deutsch-Jozsa: a hidden function f on n-bit inputs is promised to be either
// CONSTANT (same output for all 2^n inputs) or BALANCED (0 for exactly half,
// 1 for the other half). Deciding which classically needs, in the worst case,
// 2^(n-1)+1 queries to be CERTAIN. A quantum computer needs exactly ONE query.
const N = 4; // 4-bit inputs -> 16 cases
const SIZE = 1 << N; // 16
const WORST = SIZE / 2 + 1; // 9 classical queries, worst case (certainty)
let truth = []; // the hidden outputs f(0..15)
let kind = ''; // 'constant' | 'balanced'
let revealed = [];
let cq = 0, qq = 0, order = [];
function makeFunction(){
// 50/50 pick constant or balanced
if (Math.random() < 0.5){
kind = 'constant';
const v = Math.random() < 0.5 ? 0 : 1;
truth = Array(SIZE).fill(v);
} else {
kind = 'balanced';
// exactly half 1s, half 0s, shuffled
truth = Array(SIZE).fill(0).map((_,i)=> i < SIZE/2 ? 1 : 0);
for (let i = truth.length-1; i>0; i--){ const j = (Math.random()*(i+1))|0; [truth[i],truth[j]]=[truth[j],truth[i]]; }
}
revealed = Array(SIZE).fill(null);
// a worst-case-ish probe order: classical learner can't do better than this on adversarial inputs
order = Array.from({length:SIZE}, (_,i)=>i);
cq = 0; qq = 0;
}
function render(){
const g = document.getElementById('grid'); g.innerHTML = '';
for (let i=0;i<SIZE;i++){
const d = document.createElement('div');
const r = revealed[i];
d.className = 'bit' + (r===0?' q0':r===1?' q1':'');
const lbl = i.toString(2).padStart(N,'0');
d.innerHTML = '<span>'+(r===null?'?':r)+'</span><small>'+lbl+'</small>';
g.appendChild(d);
}
document.getElementById('cq').textContent = cq;
document.getElementById('qq').textContent = qq;
}
function setStatus(t,cls){ const s=document.getElementById('status'); s.textContent=t; s.className='status '+cls; }
// CLASSICAL: reveal one more output. Decide as soon as logic forces it.
function classicalProbe(){
// find next unrevealed in order
const idx = order.find(i => revealed[i] === null);
if (idx === undefined){ return; }
revealed[idx] = truth[idx]; cq++;
const seen = revealed.filter(v => v !== null);
const ones = seen.filter(v=>v===1).length, zeros = seen.length - ones;
render();
// Two distinct values seen => must be BALANCED (constant ruled out).
if (ones > 0 && zeros > 0){
setStatus(fmt('Two different outputs after %cq% queries -> BALANCED. (It was %kind%.)', { cq: cq, kind: kind }), kind==='balanced'?'ok':'bad');
return;
}
// Saw more than half identical with no disagreement => must be CONSTANT.
if (seen.length >= WORST){
setStatus(fmt('All %cq% agree, past the halfway mark -> CONSTANT. (It was %kind%.)', { cq: cq, kind: kind }), kind==='constant'?'ok':'bad');
return;
}
setStatus(fmt('So far all the same. Not yet certain — keep probing (%cq%/%WORST%).', { cq: cq, WORST: WORST }),'');
}
// QUANTUM: one query, always correct. We compute the Deutsch-Jozsa outcome
// exactly: measuring |0..0> with probability |(1/2^n) * sum_x (-1)^f(x)|^2.
// = 1 iff f is constant, 0 iff f is balanced.
function quantumProbe(){
qq = 1;
let amp = 0;
for (let x=0;x<SIZE;x++) amp += (truth[x] ? -1 : 1);
amp /= SIZE; // amplitude of the all-zeros outcome
const pAllZero = amp*amp; // probability of measuring 0000
const verdict = pAllZero > 0.5 ? 'constant' : 'balanced';
// reveal everything just to show the box (the algorithm did NOT need to)
for (let i=0;i<SIZE;i++) revealed[i] = truth[i];
render();
setStatus(fmt('Quantum query #1 -> measured %v% => %toUpperCase%. One query, always right. (It was %kind%.)', { v: verdict==='constant'?'all-zeros':'non-zero', toUpperCase: verdict.toUpperCase(), kind: kind }), 'q');
}
document.getElementById('classic').addEventListener('click', classicalProbe);
document.getElementById('quantum').addEventListener('click', quantumProbe);
document.getElementById('reset').addEventListener('click', ()=>{ makeFunction(); render(); setStatus('New hidden box. Probe to decide: constant or balanced?',''); });
makeFunction(); render();
<p class="hint">A hidden function on 4-bit inputs is secretly <b>constant</b> (same answer everywhere) or <b>balanced</b> (0 for half, 1 for the other half). Probe it <b>classically</b> — one input per click — or run the <b>quantum</b> algorithm, which decides in a single query. New function makes a fresh secret box.</p>
<div id="grid" class="grid"></div>
<div class="counts">
<span>Classical queries: <b id="cq">0</b> / 9 worst case</span>
<span>Quantum queries: <b id="qq">0</b></span>
</div>
<div class="status" id="status">Probe the box to decide: constant or balanced?</div>
<div class="btns">
<button id="classic" type="button">Classical query</button>
<button id="quantum" type="button">Quantum query</button>
<button id="reset" type="button" class="ghost">New function</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.grid { display: grid; grid-template-columns: repeat(8, 38px); gap: 5px; margin: .5rem 0; }
.bit { width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
font: 700 15px ui-monospace, monospace; border-radius: 7px; background: #e8eef3;
color: #1d3557; border: 1px solid #cdd9e3; }
.bit.q0 { background: #d4edda; border-color: #9ccaa9; color: #0a7d33; }
.bit.q1 { background: #f8d7da; border-color: #e0a3a9; color: #c92f3c; }
.bit small { font-size: 9px; font-weight: 600; opacity: .65; display: block; line-height: 1; }
.counts { display: flex; gap: 1.2rem; flex-wrap: wrap; font-size: .9rem; color: #444; margin: .3rem 0 .2rem; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.status.q { color: #5a2a9d; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button#quantum { background: #5a2a9d; border-color: #5a2a9d; }
button.ghost { background: #fff; color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Deutsch-Jozsa: a hidden function f on n-bit inputs is promised to be either
// CONSTANT (same output for all 2^n inputs) or BALANCED (0 for exactly half,
// 1 for the other half). Deciding which classically needs, in the worst case,
// 2^(n-1)+1 queries to be CERTAIN. A quantum computer needs exactly ONE query.
const N = 4; // 4-bit inputs -> 16 cases
const SIZE = 1 << N; // 16
const WORST = SIZE / 2 + 1; // 9 classical queries, worst case (certainty)
let truth = []; // the hidden outputs f(0..15)
let kind = ''; // 'constant' | 'balanced'
let revealed = [];
let cq = 0, qq = 0, order = [];
function makeFunction(){
// 50/50 pick constant or balanced
if (Math.random() < 0.5){
kind = 'constant';
const v = Math.random() < 0.5 ? 0 : 1;
truth = Array(SIZE).fill(v);
} else {
kind = 'balanced';
// exactly half 1s, half 0s, shuffled
truth = Array(SIZE).fill(0).map((_,i)=> i < SIZE/2 ? 1 : 0);
for (let i = truth.length-1; i>0; i--){ const j = (Math.random()*(i+1))|0; [truth[i],truth[j]]=[truth[j],truth[i]]; }
}
revealed = Array(SIZE).fill(null);
// a worst-case-ish probe order: classical learner can't do better than this on adversarial inputs
order = Array.from({length:SIZE}, (_,i)=>i);
cq = 0; qq = 0;
}
function render(){
const g = document.getElementById('grid'); g.innerHTML = '';
for (let i=0;i<SIZE;i++){
const d = document.createElement('div');
const r = revealed[i];
d.className = 'bit' + (r===0?' q0':r===1?' q1':'');
const lbl = i.toString(2).padStart(N,'0');
d.innerHTML = '<span>'+(r===null?'?':r)+'</span><small>'+lbl+'</small>';
g.appendChild(d);
}
document.getElementById('cq').textContent = cq;
document.getElementById('qq').textContent = qq;
}
function setStatus(t,cls){ const s=document.getElementById('status'); s.textContent=t; s.className='status '+cls; }
// CLASSICAL: reveal one more output. Decide as soon as logic forces it.
function classicalProbe(){
// find next unrevealed in order
const idx = order.find(i => revealed[i] === null);
if (idx === undefined){ return; }
revealed[idx] = truth[idx]; cq++;
const seen = revealed.filter(v => v !== null);
const ones = seen.filter(v=>v===1).length, zeros = seen.length - ones;
render();
// Two distinct values seen => must be BALANCED (constant ruled out).
if (ones > 0 && zeros > 0){
setStatus(fmt('Two different outputs after %cq% queries -> BALANCED. (It was %kind%.)', { cq: cq, kind: kind }), kind==='balanced'?'ok':'bad');
return;
}
// Saw more than half identical with no disagreement => must be CONSTANT.
if (seen.length >= WORST){
setStatus(fmt('All %cq% agree, past the halfway mark -> CONSTANT. (It was %kind%.)', { cq: cq, kind: kind }), kind==='constant'?'ok':'bad');
return;
}
setStatus(fmt('So far all the same. Not yet certain — keep probing (%cq%/%WORST%).', { cq: cq, WORST: WORST }),'');
}
// QUANTUM: one query, always correct. We compute the Deutsch-Jozsa outcome
// exactly: measuring |0..0> with probability |(1/2^n) * sum_x (-1)^f(x)|^2.
// = 1 iff f is constant, 0 iff f is balanced.
function quantumProbe(){
qq = 1;
let amp = 0;
for (let x=0;x<SIZE;x++) amp += (truth[x] ? -1 : 1);
amp /= SIZE; // amplitude of the all-zeros outcome
const pAllZero = amp*amp; // probability of measuring 0000
const verdict = pAllZero > 0.5 ? 'constant' : 'balanced';
// reveal everything just to show the box (the algorithm did NOT need to)
for (let i=0;i<SIZE;i++) revealed[i] = truth[i];
render();
setStatus(fmt('Quantum query #1 -> measured %v% => %toUpperCase%. One query, always right. (It was %kind%.)', { v: verdict==='constant'?'all-zeros':'non-zero', toUpperCase: verdict.toUpperCase(), kind: kind }), 'q');
}
document.getElementById('classic').addEventListener('click', classicalProbe);
document.getElementById('quantum').addEventListener('click', quantumProbe);
document.getElementById('reset').addEventListener('click', ()=>{ makeFunction(); render(); setStatus('New hidden box. Probe to decide: constant or balanced?',''); });
makeFunction(); render();
Now press Quantum query. The Deutsch–Jozsa algorithm prepares all inputs in superposition, runs the box once, and lets the answers interfere: a measurement of all-zeros means constant, anything else means balanced — guaranteed, after a single call. The classical counter can climb to nine; the quantum one never leaves one.
Comments
Loading comments...