<p class="hint">The same function — <b>XOR of four bits</b> (output 1 when an odd number of inputs are 1) — built two ways from AND, OR and NOT gates. Flip the switches; both circuits agree. Then toggle the layout and watch <b>depth</b> trade against <b>width</b>.</p>
<div class="inputs" id="inputs"></div>
<div class="layout-btns">
<button id="balanced" type="button">Balanced (shallow)</button>
<button id="chained" type="button" class="ghost">Chained (deep)</button>
</div>
<div id="diagram" class="diagram"></div>
<div class="readout">
<div class="metric"><span class="k">Output</span><span class="v" id="out">0</span></div>
<div class="metric"><span class="k">Gates (size)</span><span class="v" id="size">0</span></div>
<div class="metric"><span class="k">Depth</span><span class="v" id="depth">0</span></div>
</div>
<div class="status" id="status"></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; }
.inputs { display: flex; gap: .6rem; flex-wrap: wrap; margin: .3rem 0 .6rem; }
.bit { display: flex; flex-direction: column; align-items: center; gap: .25rem; }
.bit button { width: 44px; height: 44px; font: 700 18px ui-monospace, monospace;
border-radius: 8px; border: 1px solid #adb1b8; background: #e8eef3;
color: #1d3557; cursor: pointer; }
.bit button.on { background: #1d3557; color: #fff; border-color: #1d3557; }
.bit .lbl { font: 600 12px system-ui; color: #555; }
.layout-btns { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .6rem; }
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.ghost { background: #fff; color: #1d3557; }
.diagram { display: flex; flex-direction: column; gap: 10px; margin: .4rem 0;
padding: .6rem; background: #f5f7fa; border-radius: 10px; min-height: 90px; }
.layer { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.gate { padding: .35rem .55rem; border-radius: 8px; font: 700 13px ui-monospace, monospace;
border: 1px solid #cdd9e3; background: #fff; min-width: 60px; text-align: center; }
.gate.hot { background: #d5f0dd; border-color: #5bbd7a; }
.gate small { display: block; font: 500 10px system-ui; color: #777; }
.readout { display: flex; gap: 1.4rem; flex-wrap: wrap; margin: .6rem 0; }
.metric { display: flex; flex-direction: column; }
.metric .k { font: 600 11px system-ui; color: #777; text-transform: uppercase; letter-spacing: .04em; }
.metric .v { font: 800 22px ui-monospace, monospace; color: #1d3557; }
.status { font-size: .95rem; font-weight: 600; min-height: 1.3em; color: #0a7d33; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Circuit complexity: the same Boolean function, two circuits.
// XOR of 4 bits = parity. Built only from AND / OR / NOT.
// xor2(a,b) = (a OR b) AND NOT(a AND b)
// Each xor2 costs 4 gates (OR, AND, NOT, AND) and has depth 3.
// Balanced: xor2(xor2(a,b), xor2(c,d)) -> 3 xor2 blocks, two run in parallel
// Chained: xor2(xor2(xor2(a,b),c),d) -> 3 xor2 blocks strung in a line
const AND=(x,y)=>x&y, OR=(x,y)=>x|y, NOT=x=>x^1;
function xor2(a,b){ const or=OR(a,b), and=AND(a,b), nand=NOT(and); return AND(or,nand); }
const bits=[0,0,0,0];
let mode='balanced';
// Build a layered description of the chosen circuit for both display and metrics.
function build(){
const [a,b,c,d]=bits;
if(mode==='balanced'){
const p=xor2(a,b), q=xor2(c,d), out=xor2(p,q);
// 3 xor2 blocks; the two leaf blocks share layers -> depth 3+3 = 6, width up to 2 blocks wide.
return {
out,
layers:[
[g('OR',OR(a,b)),g('OR',OR(c,d))],
[g('AND',AND(a,b)),g('AND',AND(c,d))],
[g('NOT',NOT(AND(a,b))),g('NOT',NOT(AND(c,d)))],
[g('AND a⊕b',p),g('AND c⊕d',q)],
[g('OR',OR(p,q))],
[g('AND',AND(p,q))],
[g('NOT',NOT(AND(p,q)))],
[g('AND out',out)]
]
};
} else {
const p=xor2(a,b), q=xor2(p,c), out=xor2(q,d);
return {
out,
layers:[
[g('OR',OR(a,b))],[g('AND',AND(a,b))],[g('NOT',NOT(AND(a,b)))],[g('AND a⊕b',p)],
[g('OR',OR(p,c))],[g('AND',AND(p,c))],[g('NOT',NOT(AND(p,c)))],[g('AND ⊕c',q)],
[g('OR',OR(q,d))],[g('AND',AND(q,d))],[g('NOT',NOT(AND(q,d)))],[g('AND out',out)]
]
};
}
}
function g(label,val){ return {label,val}; }
function refInputs(){
const wrap=document.getElementById('inputs'); wrap.innerHTML='';
['a','b','c','d'].forEach((name,i)=>{
const div=document.createElement('div'); div.className='bit';
const btn=document.createElement('button'); btn.textContent=bits[i];
if(bits[i]) btn.classList.add('on');
btn.addEventListener('click',()=>{ bits[i]^=1; render(); });
const lbl=document.createElement('span'); lbl.className='lbl'; lbl.textContent=name;
div.appendChild(btn); div.appendChild(lbl); wrap.appendChild(div);
});
}
function render(){
refInputs();
const c=build();
const dia=document.getElementById('diagram'); dia.innerHTML='';
c.layers.forEach(layer=>{
const row=document.createElement('div'); row.className='layer';
layer.forEach(gt=>{
const el=document.createElement('div'); el.className='gate'+(gt.val?' hot':'');
el.innerHTML=gt.label+'<small>'+gt.val+'</small>';
row.appendChild(el);
});
dia.appendChild(row);
});
const size=c.layers.reduce((s,l)=>s+l.length,0);
const depth=c.layers.length;
document.getElementById('out').textContent=c.out;
document.getElementById('size').textContent=size;
document.getElementById('depth').textContent=depth;
const expected=bits.reduce((x,y)=>x^y,0);
const ok=(c.out===expected);
const s=document.getElementById('status');
s.textContent=ok ? (fmt('✓ Both layouts compute the same XOR = %expected% (%v%)', { expected: expected, v: mode==='balanced'?'shallow & wide':'deep & narrow' })) : '✗ mismatch';
s.style.color=ok?'#0a7d33':'#c92f3c';
}
document.getElementById('balanced').addEventListener('click',()=>{ mode='balanced'; render(); });
document.getElementById('chained').addEventListener('click',()=>{ mode='chained'; render(); });
render();
<p class="hint">The same function — <b>XOR of four bits</b> (output 1 when an odd number of inputs are 1) — built two ways from AND, OR and NOT gates. Flip the switches; both circuits agree. Then toggle the layout and watch <b>depth</b> trade against <b>width</b>.</p>
<div class="inputs" id="inputs"></div>
<div class="layout-btns">
<button id="balanced" type="button">Balanced (shallow)</button>
<button id="chained" type="button" class="ghost">Chained (deep)</button>
</div>
<div id="diagram" class="diagram"></div>
<div class="readout">
<div class="metric"><span class="k">Output</span><span class="v" id="out">0</span></div>
<div class="metric"><span class="k">Gates (size)</span><span class="v" id="size">0</span></div>
<div class="metric"><span class="k">Depth</span><span class="v" id="depth">0</span></div>
</div>
<div class="status" id="status"></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; }
.inputs { display: flex; gap: .6rem; flex-wrap: wrap; margin: .3rem 0 .6rem; }
.bit { display: flex; flex-direction: column; align-items: center; gap: .25rem; }
.bit button { width: 44px; height: 44px; font: 700 18px ui-monospace, monospace;
border-radius: 8px; border: 1px solid #adb1b8; background: #e8eef3;
color: #1d3557; cursor: pointer; }
.bit button.on { background: #1d3557; color: #fff; border-color: #1d3557; }
.bit .lbl { font: 600 12px system-ui; color: #555; }
.layout-btns { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .6rem; }
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.ghost { background: #fff; color: #1d3557; }
.diagram { display: flex; flex-direction: column; gap: 10px; margin: .4rem 0;
padding: .6rem; background: #f5f7fa; border-radius: 10px; min-height: 90px; }
.layer { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.gate { padding: .35rem .55rem; border-radius: 8px; font: 700 13px ui-monospace, monospace;
border: 1px solid #cdd9e3; background: #fff; min-width: 60px; text-align: center; }
.gate.hot { background: #d5f0dd; border-color: #5bbd7a; }
.gate small { display: block; font: 500 10px system-ui; color: #777; }
.readout { display: flex; gap: 1.4rem; flex-wrap: wrap; margin: .6rem 0; }
.metric { display: flex; flex-direction: column; }
.metric .k { font: 600 11px system-ui; color: #777; text-transform: uppercase; letter-spacing: .04em; }
.metric .v { font: 800 22px ui-monospace, monospace; color: #1d3557; }
.status { font-size: .95rem; font-weight: 600; min-height: 1.3em; color: #0a7d33; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Circuit complexity: the same Boolean function, two circuits.
// XOR of 4 bits = parity. Built only from AND / OR / NOT.
// xor2(a,b) = (a OR b) AND NOT(a AND b)
// Each xor2 costs 4 gates (OR, AND, NOT, AND) and has depth 3.
// Balanced: xor2(xor2(a,b), xor2(c,d)) -> 3 xor2 blocks, two run in parallel
// Chained: xor2(xor2(xor2(a,b),c),d) -> 3 xor2 blocks strung in a line
const AND=(x,y)=>x&y, OR=(x,y)=>x|y, NOT=x=>x^1;
function xor2(a,b){ const or=OR(a,b), and=AND(a,b), nand=NOT(and); return AND(or,nand); }
const bits=[0,0,0,0];
let mode='balanced';
// Build a layered description of the chosen circuit for both display and metrics.
function build(){
const [a,b,c,d]=bits;
if(mode==='balanced'){
const p=xor2(a,b), q=xor2(c,d), out=xor2(p,q);
// 3 xor2 blocks; the two leaf blocks share layers -> depth 3+3 = 6, width up to 2 blocks wide.
return {
out,
layers:[
[g('OR',OR(a,b)),g('OR',OR(c,d))],
[g('AND',AND(a,b)),g('AND',AND(c,d))],
[g('NOT',NOT(AND(a,b))),g('NOT',NOT(AND(c,d)))],
[g('AND a⊕b',p),g('AND c⊕d',q)],
[g('OR',OR(p,q))],
[g('AND',AND(p,q))],
[g('NOT',NOT(AND(p,q)))],
[g('AND out',out)]
]
};
} else {
const p=xor2(a,b), q=xor2(p,c), out=xor2(q,d);
return {
out,
layers:[
[g('OR',OR(a,b))],[g('AND',AND(a,b))],[g('NOT',NOT(AND(a,b)))],[g('AND a⊕b',p)],
[g('OR',OR(p,c))],[g('AND',AND(p,c))],[g('NOT',NOT(AND(p,c)))],[g('AND ⊕c',q)],
[g('OR',OR(q,d))],[g('AND',AND(q,d))],[g('NOT',NOT(AND(q,d)))],[g('AND out',out)]
]
};
}
}
function g(label,val){ return {label,val}; }
function refInputs(){
const wrap=document.getElementById('inputs'); wrap.innerHTML='';
['a','b','c','d'].forEach((name,i)=>{
const div=document.createElement('div'); div.className='bit';
const btn=document.createElement('button'); btn.textContent=bits[i];
if(bits[i]) btn.classList.add('on');
btn.addEventListener('click',()=>{ bits[i]^=1; render(); });
const lbl=document.createElement('span'); lbl.className='lbl'; lbl.textContent=name;
div.appendChild(btn); div.appendChild(lbl); wrap.appendChild(div);
});
}
function render(){
refInputs();
const c=build();
const dia=document.getElementById('diagram'); dia.innerHTML='';
c.layers.forEach(layer=>{
const row=document.createElement('div'); row.className='layer';
layer.forEach(gt=>{
const el=document.createElement('div'); el.className='gate'+(gt.val?' hot':'');
el.innerHTML=gt.label+'<small>'+gt.val+'</small>';
row.appendChild(el);
});
dia.appendChild(row);
});
const size=c.layers.reduce((s,l)=>s+l.length,0);
const depth=c.layers.length;
document.getElementById('out').textContent=c.out;
document.getElementById('size').textContent=size;
document.getElementById('depth').textContent=depth;
const expected=bits.reduce((x,y)=>x^y,0);
const ok=(c.out===expected);
const s=document.getElementById('status');
s.textContent=ok ? (fmt('✓ Both layouts compute the same XOR = %expected% (%v%)', { expected: expected, v: mode==='balanced'?'shallow & wide':'deep & narrow' })) : '✗ mismatch';
s.style.color=ok?'#0a7d33':'#c92f3c';
}
document.getElementById('balanced').addEventListener('click',()=>{ mode='balanced'; render(); });
document.getElementById('chained').addEventListener('click',()=>{ mode='chained'; render(); });
render();
Comments
Loading comments...