<p class="hint">The <b>butterfly network</b>: source S has packets <b>a=1</b> and <b>b=0</b>. Both receivers R1 and R2 need both packets. The middle edge M→N is the bottleneck — it carries only one value per round. Toggle between Routing and Coding to see the difference.</p>
<div class="mode-row">
<button id="btnRoute" class="mode-btn active" type="button">Routing</button>
<button id="btnCode" class="mode-btn" type="button">Coding (XOR)</button>
</div>
<div class="net-wrap">
<svg id="net" viewBox="0 0 340 300" width="340" height="300" aria-label="Butterfly network diagram"></svg>
</div>
<div class="step-row">
<button id="btnStep" type="button">▶ Step</button>
<button id="btnReset" type="button" class="ghost">Reset</button>
<span id="stepLabel" class="step-label">Round 1 of 2</span>
</div>
<div id="status" class="status"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .88rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.mode-row { display: flex; gap: .5rem; margin-bottom: .7rem; }
.mode-btn { font: 600 13px system-ui; padding: .35rem .8rem; border: 1.5px solid #1d3557;
background: #fff; color: #1d3557; border-radius: 7px; cursor: pointer; transition: background .15s; }
.mode-btn.active { background: #1d3557; color: #fff; }
.net-wrap { display: flex; justify-content: center; margin: .3rem 0 .5rem; }
svg text { font-family: system-ui, ui-monospace, monospace; }
.step-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .4rem; }
button { font: 600 13px system-ui; padding: .38rem .85rem; border: 1.5px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 7px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.step-label { font-size: .85rem; color: #555; }
.status { font-size: .95rem; font-weight: 600; min-height: 1.4em; padding: .15rem 0; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c02a2a; }
.status.info { color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Butterfly network simulation.
// Nodes: S (source), M (top middle), N (bottom middle), R1, R2
// Edges round 1: S→M (a), S→N (b) [routing & coding same]
// round 2 routing: M→R1 (a), N→R2 (b), bottleneck M→N carries either a or b
// round 2 coding: M→R1 (a), N→R2 (b), bottleneck M→N carries a XOR b
// After round 2:
// routing: R1 gets (a, ?), R2 gets (?, b) — one receiver misses a packet
// coding: R1 gets a + (a XOR b) → decodes b; R2 gets b + (a XOR b) → decodes a
const A = 1, B = 0; // packet values
const XOR = (x, y) => x ^ y;
// Layout: SVG positions for each node
const POS = {
S: { x: 170, y: 30 },
M: { x: 90, y: 130 },
N: { x: 250, y: 130 },
R1: { x: 90, y: 250 },
R2: { x: 250, y: 250 }
};
const EDGES = [
{ id:'sM', from:'S', to:'M' },
{ id:'sN', from:'S', to:'N' },
{ id:'mN', from:'M', to:'N' }, // bottleneck
{ id:'mR1', from:'M', to:'R1' },
{ id:'nR2', from:'N', to:'R2' }
];
// State
let mode = 'route'; // 'route' | 'code'
let round = 0; // 0 = initial, 1 = after round 1, 2 = after round 2
// What each node holds per round
function getState(m, r) {
// returns { node: [packets...], edgeLabels: { edgeId: label } }
const nodes = { S: ['a','b'], M: [], N: [], R1: [], R2: [] };
const edges = {};
if (r >= 1) {
// Round 1: S sends a to M, S sends b to N
edges['sM'] = 'a';
edges['sN'] = 'b';
nodes['M'] = ['a'];
nodes['N'] = ['b'];
}
if (r >= 2) {
if (m === 'route') {
// Routing: bottleneck forwards 'a' (arbitrary choice — R2 loses a)
edges['mN'] = 'a';
edges['mR1'] = 'a';
edges['nR2'] = 'b';
nodes['R1'] = ['a']; // receives a from M; has a but not b
nodes['R2'] = ['b']; // receives b from N; has b but not a
} else {
// Coding: bottleneck sends a XOR b = 1 XOR 0 = 1
const coded = XOR(A, B);
const label = 'a⊕b';
edges['mN'] = label;
edges['mR1'] = 'a';
edges['nR2'] = 'b';
// R1 has 'a' from M; receives a⊕b from N; recovers b = (a⊕b)⊕a
nodes['R1'] = ['a', 'b'];
// R2 has 'b' from N; receives a⊕b; recovers a = (a⊕b)⊕b
nodes['R2'] = ['a', 'b'];
nodes['N'] = ['b', label]; // N now also holds the coded value for forwarding
}
}
return { nodes, edges };
}
const svg = document.getElementById('net');
function arrow(x1,y1,x2,y2,col){
const dx=x2-x1, dy=y2-y1, len=Math.sqrt(dx*dx+dy*dy);
const ux=dx/len, uy=dy/len;
const r=22; // node radius
const sx=x1+ux*r, sy=y1+uy*r, ex=x2-ux*r, ey=y2-uy*r;
const el=document.createElementNS('http://www.w3.org/2000/svg','line');
el.setAttribute('x1',sx); el.setAttribute('y1',sy);
el.setAttribute('x2',ex); el.setAttribute('y2',ey);
el.setAttribute('stroke',col||'#1d3557');
el.setAttribute('stroke-width','1.8');
el.setAttribute('marker-end','url(#arrowhead)');
return el;
}
function renderNet() {
const state = getState(mode, round);
svg.innerHTML = '';
// Defs: arrowhead
const defs = document.createElementNS('http://www.w3.org/2000/svg','defs');
defs.innerHTML = `<marker id="arrowhead" markerWidth="8" markerHeight="6"
refX="6" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#1d3557"/>
</marker>
<marker id="arrowhead-active" markerWidth="8" markerHeight="6"
refX="6" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#e63946"/>
</marker>`;
svg.appendChild(defs);
// Draw edges
EDGES.forEach(e => {
const from = POS[e.from], to = POS[e.to];
const isBottleneck = (e.id === 'mN');
const isActive = (state.edges[e.id] !== undefined);
const col = isBottleneck ? '#e63946' : (isActive ? '#1d3557' : '#bcc0c6');
const markerEnd = isBottleneck ? 'url(#arrowhead-active)' : 'url(#arrowhead)';
const dx=to.x-from.x, dy=to.y-from.y, len=Math.sqrt(dx*dx+dy*dy);
const ux=dx/len, uy=dy/len;
const r=22;
const sx=from.x+ux*r, sy=from.y+uy*r, ex=to.x-ux*r, ey=to.y-uy*r;
const line = document.createElementNS('http://www.w3.org/2000/svg','line');
line.setAttribute('x1',sx); line.setAttribute('y1',sy);
line.setAttribute('x2',ex); line.setAttribute('y2',ey);
line.setAttribute('stroke',col);
line.setAttribute('stroke-width', isBottleneck ? '2.2' : '1.8');
line.setAttribute('marker-end', isBottleneck
? (isActive ? 'url(#arrowhead-active)' : 'url(#arrowhead)')
: 'url(#arrowhead)');
if (!isActive && !isBottleneck) line.setAttribute('stroke-dasharray','4 3');
svg.appendChild(line);
// Edge label
if (state.edges[e.id] !== undefined) {
const mx=(sx+ex)/2, my=(sy+ey)/2;
const lbl = document.createElementNS('http://www.w3.org/2000/svg','text');
lbl.setAttribute('x', mx + (isBottleneck?8:-14));
lbl.setAttribute('y', my - 4);
lbl.setAttribute('font-size','12');
lbl.setAttribute('fill', isBottleneck ? '#e63946' : '#1d3557');
lbl.setAttribute('font-weight','700');
lbl.textContent = state.edges[e.id];
svg.appendChild(lbl);
}
});
// Draw nodes
const NODE_LABELS = { S:'S', M:'M', N:'N', R1:'R1', R2:'R2' };
Object.entries(POS).forEach(([id, pos]) => {
const isReceiver = (id==='R1'||id==='R2');
const packets = state.nodes[id];
const full = isReceiver && packets.length === 2;
const partial = isReceiver && packets.length === 1;
const missing = isReceiver && round === 2 && packets.length < 2;
const bgCol = id==='S' ? '#2b6cb0' :
(full ? '#0a7d33' :
(missing ? '#c02a2a' : '#1d3557'));
const circle = document.createElementNS('http://www.w3.org/2000/svg','circle');
circle.setAttribute('cx',pos.x); circle.setAttribute('cy',pos.y); circle.setAttribute('r',22);
circle.setAttribute('fill',bgCol); circle.setAttribute('stroke','none');
svg.appendChild(circle);
const lbl = document.createElementNS('http://www.w3.org/2000/svg','text');
lbl.setAttribute('x',pos.x); lbl.setAttribute('y',pos.y-6);
lbl.setAttribute('text-anchor','middle'); lbl.setAttribute('dominant-baseline','middle');
lbl.setAttribute('font-size','13'); lbl.setAttribute('font-weight','700');
lbl.setAttribute('fill','#fff');
lbl.textContent = NODE_LABELS[id];
svg.appendChild(lbl);
// Show packet contents below node name
if (packets.length > 0) {
const sub = document.createElementNS('http://www.w3.org/2000/svg','text');
sub.setAttribute('x',pos.x); sub.setAttribute('y',pos.y+9);
sub.setAttribute('text-anchor','middle');
sub.setAttribute('font-size','11'); sub.setAttribute('fill','#e8f4ff');
sub.textContent = '{' + packets.join(',') + '}';
svg.appendChild(sub);
}
});
// Bottleneck label
const bLabel = document.createElementNS('http://www.w3.org/2000/svg','text');
bLabel.setAttribute('x','170'); bLabel.setAttribute('y','118');
bLabel.setAttribute('text-anchor','middle');
bLabel.setAttribute('font-size','11'); bLabel.setAttribute('fill','#e63946');
bLabel.textContent = 'bottleneck';
svg.appendChild(bLabel);
// Status
const statusEl = document.getElementById('status');
const stepLbl = document.getElementById('stepLabel');
if (round === 0) {
statusEl.textContent = 'S holds packets a=1 and b=0. Press Step to send.';
statusEl.className = 'status info';
stepLbl.textContent = 'Round 1 of 2';
} else if (round === 1) {
statusEl.textContent = 'Round 1 done: M received a, N received b. Press Step for round 2.';
statusEl.className = 'status info';
stepLbl.textContent = 'Round 2 of 2';
} else {
if (mode === 'route') {
statusEl.textContent = '✗ Routing: R1 gets only {a}, R2 gets only {b}. Bottleneck forced a choice — one packet lost per receiver.';
statusEl.className = 'status bad';
} else {
statusEl.textContent = '✓ Coding: R1 computes (a⊕b)⊕a=b; R2 computes (a⊕b)⊕b=a. Both receivers recover all packets!';
statusEl.className = 'status ok';
}
stepLbl.textContent = 'Done';
}
}
function step() {
if (round < 2) { round++; renderNet(); }
}
function reset() {
round = 0; renderNet();
}
document.getElementById('btnStep').addEventListener('click', step);
document.getElementById('btnReset').addEventListener('click', reset);
document.getElementById('btnRoute').addEventListener('click', () => {
mode = 'route';
document.getElementById('btnRoute').classList.add('active');
document.getElementById('btnCode').classList.remove('active');
round = 0; renderNet();
});
document.getElementById('btnCode').addEventListener('click', () => {
mode = 'code';
document.getElementById('btnCode').classList.add('active');
document.getElementById('btnRoute').classList.remove('active');
round = 0; renderNet();
});
renderNet();
// Verification for node: assert XOR logic
console.assert(XOR(1,0) === 1, 'XOR(1,0) should be 1');
console.assert(XOR(1,0) ^ 1 === 0, 'R1 decode: (a XOR b) XOR a = b = 0');
console.assert(XOR(1,0) ^ 0 === 1, 'R2 decode: (a XOR b) XOR b = a = 1');
console.log(fmt('Network coding demo: all assertions passed. a=1, b=0, a⊕b=%XOR%, R1 recovers b=%v%, R2 recovers a=%v2%', { XOR: XOR(1,0), v: XOR(1,0)^1, v2: XOR(1,0)^0 }));
<p class="hint">The <b>butterfly network</b>: source S has packets <b>a=1</b> and <b>b=0</b>. Both receivers R1 and R2 need both packets. The middle edge M→N is the bottleneck — it carries only one value per round. Toggle between Routing and Coding to see the difference.</p>
<div class="mode-row">
<button id="btnRoute" class="mode-btn active" type="button">Routing</button>
<button id="btnCode" class="mode-btn" type="button">Coding (XOR)</button>
</div>
<div class="net-wrap">
<svg id="net" viewBox="0 0 340 300" width="340" height="300" aria-label="Butterfly network diagram"></svg>
</div>
<div class="step-row">
<button id="btnStep" type="button">▶ Step</button>
<button id="btnReset" type="button" class="ghost">Reset</button>
<span id="stepLabel" class="step-label">Round 1 of 2</span>
</div>
<div id="status" class="status"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .88rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.mode-row { display: flex; gap: .5rem; margin-bottom: .7rem; }
.mode-btn { font: 600 13px system-ui; padding: .35rem .8rem; border: 1.5px solid #1d3557;
background: #fff; color: #1d3557; border-radius: 7px; cursor: pointer; transition: background .15s; }
.mode-btn.active { background: #1d3557; color: #fff; }
.net-wrap { display: flex; justify-content: center; margin: .3rem 0 .5rem; }
svg text { font-family: system-ui, ui-monospace, monospace; }
.step-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .4rem; }
button { font: 600 13px system-ui; padding: .38rem .85rem; border: 1.5px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 7px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.step-label { font-size: .85rem; color: #555; }
.status { font-size: .95rem; font-weight: 600; min-height: 1.4em; padding: .15rem 0; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c02a2a; }
.status.info { color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Butterfly network simulation.
// Nodes: S (source), M (top middle), N (bottom middle), R1, R2
// Edges round 1: S→M (a), S→N (b) [routing & coding same]
// round 2 routing: M→R1 (a), N→R2 (b), bottleneck M→N carries either a or b
// round 2 coding: M→R1 (a), N→R2 (b), bottleneck M→N carries a XOR b
// After round 2:
// routing: R1 gets (a, ?), R2 gets (?, b) — one receiver misses a packet
// coding: R1 gets a + (a XOR b) → decodes b; R2 gets b + (a XOR b) → decodes a
const A = 1, B = 0; // packet values
const XOR = (x, y) => x ^ y;
// Layout: SVG positions for each node
const POS = {
S: { x: 170, y: 30 },
M: { x: 90, y: 130 },
N: { x: 250, y: 130 },
R1: { x: 90, y: 250 },
R2: { x: 250, y: 250 }
};
const EDGES = [
{ id:'sM', from:'S', to:'M' },
{ id:'sN', from:'S', to:'N' },
{ id:'mN', from:'M', to:'N' }, // bottleneck
{ id:'mR1', from:'M', to:'R1' },
{ id:'nR2', from:'N', to:'R2' }
];
// State
let mode = 'route'; // 'route' | 'code'
let round = 0; // 0 = initial, 1 = after round 1, 2 = after round 2
// What each node holds per round
function getState(m, r) {
// returns { node: [packets...], edgeLabels: { edgeId: label } }
const nodes = { S: ['a','b'], M: [], N: [], R1: [], R2: [] };
const edges = {};
if (r >= 1) {
// Round 1: S sends a to M, S sends b to N
edges['sM'] = 'a';
edges['sN'] = 'b';
nodes['M'] = ['a'];
nodes['N'] = ['b'];
}
if (r >= 2) {
if (m === 'route') {
// Routing: bottleneck forwards 'a' (arbitrary choice — R2 loses a)
edges['mN'] = 'a';
edges['mR1'] = 'a';
edges['nR2'] = 'b';
nodes['R1'] = ['a']; // receives a from M; has a but not b
nodes['R2'] = ['b']; // receives b from N; has b but not a
} else {
// Coding: bottleneck sends a XOR b = 1 XOR 0 = 1
const coded = XOR(A, B);
const label = 'a⊕b';
edges['mN'] = label;
edges['mR1'] = 'a';
edges['nR2'] = 'b';
// R1 has 'a' from M; receives a⊕b from N; recovers b = (a⊕b)⊕a
nodes['R1'] = ['a', 'b'];
// R2 has 'b' from N; receives a⊕b; recovers a = (a⊕b)⊕b
nodes['R2'] = ['a', 'b'];
nodes['N'] = ['b', label]; // N now also holds the coded value for forwarding
}
}
return { nodes, edges };
}
const svg = document.getElementById('net');
function arrow(x1,y1,x2,y2,col){
const dx=x2-x1, dy=y2-y1, len=Math.sqrt(dx*dx+dy*dy);
const ux=dx/len, uy=dy/len;
const r=22; // node radius
const sx=x1+ux*r, sy=y1+uy*r, ex=x2-ux*r, ey=y2-uy*r;
const el=document.createElementNS('http://www.w3.org/2000/svg','line');
el.setAttribute('x1',sx); el.setAttribute('y1',sy);
el.setAttribute('x2',ex); el.setAttribute('y2',ey);
el.setAttribute('stroke',col||'#1d3557');
el.setAttribute('stroke-width','1.8');
el.setAttribute('marker-end','url(#arrowhead)');
return el;
}
function renderNet() {
const state = getState(mode, round);
svg.innerHTML = '';
// Defs: arrowhead
const defs = document.createElementNS('http://www.w3.org/2000/svg','defs');
defs.innerHTML = `<marker id="arrowhead" markerWidth="8" markerHeight="6"
refX="6" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#1d3557"/>
</marker>
<marker id="arrowhead-active" markerWidth="8" markerHeight="6"
refX="6" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#e63946"/>
</marker>`;
svg.appendChild(defs);
// Draw edges
EDGES.forEach(e => {
const from = POS[e.from], to = POS[e.to];
const isBottleneck = (e.id === 'mN');
const isActive = (state.edges[e.id] !== undefined);
const col = isBottleneck ? '#e63946' : (isActive ? '#1d3557' : '#bcc0c6');
const markerEnd = isBottleneck ? 'url(#arrowhead-active)' : 'url(#arrowhead)';
const dx=to.x-from.x, dy=to.y-from.y, len=Math.sqrt(dx*dx+dy*dy);
const ux=dx/len, uy=dy/len;
const r=22;
const sx=from.x+ux*r, sy=from.y+uy*r, ex=to.x-ux*r, ey=to.y-uy*r;
const line = document.createElementNS('http://www.w3.org/2000/svg','line');
line.setAttribute('x1',sx); line.setAttribute('y1',sy);
line.setAttribute('x2',ex); line.setAttribute('y2',ey);
line.setAttribute('stroke',col);
line.setAttribute('stroke-width', isBottleneck ? '2.2' : '1.8');
line.setAttribute('marker-end', isBottleneck
? (isActive ? 'url(#arrowhead-active)' : 'url(#arrowhead)')
: 'url(#arrowhead)');
if (!isActive && !isBottleneck) line.setAttribute('stroke-dasharray','4 3');
svg.appendChild(line);
// Edge label
if (state.edges[e.id] !== undefined) {
const mx=(sx+ex)/2, my=(sy+ey)/2;
const lbl = document.createElementNS('http://www.w3.org/2000/svg','text');
lbl.setAttribute('x', mx + (isBottleneck?8:-14));
lbl.setAttribute('y', my - 4);
lbl.setAttribute('font-size','12');
lbl.setAttribute('fill', isBottleneck ? '#e63946' : '#1d3557');
lbl.setAttribute('font-weight','700');
lbl.textContent = state.edges[e.id];
svg.appendChild(lbl);
}
});
// Draw nodes
const NODE_LABELS = { S:'S', M:'M', N:'N', R1:'R1', R2:'R2' };
Object.entries(POS).forEach(([id, pos]) => {
const isReceiver = (id==='R1'||id==='R2');
const packets = state.nodes[id];
const full = isReceiver && packets.length === 2;
const partial = isReceiver && packets.length === 1;
const missing = isReceiver && round === 2 && packets.length < 2;
const bgCol = id==='S' ? '#2b6cb0' :
(full ? '#0a7d33' :
(missing ? '#c02a2a' : '#1d3557'));
const circle = document.createElementNS('http://www.w3.org/2000/svg','circle');
circle.setAttribute('cx',pos.x); circle.setAttribute('cy',pos.y); circle.setAttribute('r',22);
circle.setAttribute('fill',bgCol); circle.setAttribute('stroke','none');
svg.appendChild(circle);
const lbl = document.createElementNS('http://www.w3.org/2000/svg','text');
lbl.setAttribute('x',pos.x); lbl.setAttribute('y',pos.y-6);
lbl.setAttribute('text-anchor','middle'); lbl.setAttribute('dominant-baseline','middle');
lbl.setAttribute('font-size','13'); lbl.setAttribute('font-weight','700');
lbl.setAttribute('fill','#fff');
lbl.textContent = NODE_LABELS[id];
svg.appendChild(lbl);
// Show packet contents below node name
if (packets.length > 0) {
const sub = document.createElementNS('http://www.w3.org/2000/svg','text');
sub.setAttribute('x',pos.x); sub.setAttribute('y',pos.y+9);
sub.setAttribute('text-anchor','middle');
sub.setAttribute('font-size','11'); sub.setAttribute('fill','#e8f4ff');
sub.textContent = '{' + packets.join(',') + '}';
svg.appendChild(sub);
}
});
// Bottleneck label
const bLabel = document.createElementNS('http://www.w3.org/2000/svg','text');
bLabel.setAttribute('x','170'); bLabel.setAttribute('y','118');
bLabel.setAttribute('text-anchor','middle');
bLabel.setAttribute('font-size','11'); bLabel.setAttribute('fill','#e63946');
bLabel.textContent = 'bottleneck';
svg.appendChild(bLabel);
// Status
const statusEl = document.getElementById('status');
const stepLbl = document.getElementById('stepLabel');
if (round === 0) {
statusEl.textContent = 'S holds packets a=1 and b=0. Press Step to send.';
statusEl.className = 'status info';
stepLbl.textContent = 'Round 1 of 2';
} else if (round === 1) {
statusEl.textContent = 'Round 1 done: M received a, N received b. Press Step for round 2.';
statusEl.className = 'status info';
stepLbl.textContent = 'Round 2 of 2';
} else {
if (mode === 'route') {
statusEl.textContent = '✗ Routing: R1 gets only {a}, R2 gets only {b}. Bottleneck forced a choice — one packet lost per receiver.';
statusEl.className = 'status bad';
} else {
statusEl.textContent = '✓ Coding: R1 computes (a⊕b)⊕a=b; R2 computes (a⊕b)⊕b=a. Both receivers recover all packets!';
statusEl.className = 'status ok';
}
stepLbl.textContent = 'Done';
}
}
function step() {
if (round < 2) { round++; renderNet(); }
}
function reset() {
round = 0; renderNet();
}
document.getElementById('btnStep').addEventListener('click', step);
document.getElementById('btnReset').addEventListener('click', reset);
document.getElementById('btnRoute').addEventListener('click', () => {
mode = 'route';
document.getElementById('btnRoute').classList.add('active');
document.getElementById('btnCode').classList.remove('active');
round = 0; renderNet();
});
document.getElementById('btnCode').addEventListener('click', () => {
mode = 'code';
document.getElementById('btnCode').classList.add('active');
document.getElementById('btnRoute').classList.remove('active');
round = 0; renderNet();
});
renderNet();
// Verification for node: assert XOR logic
console.assert(XOR(1,0) === 1, 'XOR(1,0) should be 1');
console.assert(XOR(1,0) ^ 1 === 0, 'R1 decode: (a XOR b) XOR a = b = 0');
console.assert(XOR(1,0) ^ 0 === 1, 'R2 decode: (a XOR b) XOR b = a = 1');
console.log(fmt('Network coding demo: all assertions passed. a=1, b=0, a⊕b=%XOR%, R1 recovers b=%v%, R2 recovers a=%v2%', { XOR: XOR(1,0), v: XOR(1,0)^1, v2: XOR(1,0)^0 }));
Comments
Loading comments...