Here is a tiny universe of programs, each with its own halting time. Press Run a step to let every still-running program execute one more instruction. Whenever a program halts, it contributes its weight to our running estimate of Ω, and the bar creeps up.
<p class="hint">Each row is a tiny random program with a <b>length</b> (so it carries
weight 2<sup>-length</sup>) and a hidden <b>halting time</b>. Press <b>Run a step</b> to let every
still-running program execute one more instruction. When one halts, it adds its weight to
our estimate of Ω — the bar only ever <b>rises</b>, and you can never tell which
running programs will ever stop.</p>
<div class="meter">
<div class="bar"><div id="fill" class="fill"></div></div>
<div class="readout">Ω ≥ <span id="omega">0.000000</span>
<span class="muted">(step <span id="step">0</span>)</span></div>
</div>
<div id="progs" class="progs"></div>
<div class="btns">
<button id="run" type="button">Run a step</button>
<button id="run10" type="button">Run 10 steps</button>
<button id="reset" type="button" class="ghost">Reset</button>
</div>
<div class="status" id="status">Some programs never halt — the estimate stays a lower bound forever.</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; }
.meter { margin: .4rem 0 .8rem; }
.bar { height: 22px; background: #e8eef3; border: 1px solid #cdd9e3; border-radius: 6px; overflow: hidden; }
.fill { height: 100%; width: 0%; background: linear-gradient(90deg,#1d3557,#3a6ea5); transition: width .25s; }
.readout { font: 600 1rem ui-monospace, monospace; margin-top: .4rem; color: #1d3557; }
.muted { color: #788; font-weight: 400; }
.progs { display: grid; gap: 5px; margin: .4rem 0; }
.prog { display: grid; grid-template-columns: 70px 1fr 96px; align-items: center; gap: 8px;
font: 600 13px ui-monospace, monospace; }
.tag { color: #1d3557; }
.track { height: 14px; background: #c9ccd1; border: 1px solid #adb1b8; border-radius: 7px; position: relative; overflow: hidden; }
.tip { position: absolute; top: 0; bottom: 0; width: 6px; background: #1d3557; transition: left .2s; }
.prog.halted .track { background: #d6f0df; border-color: #9ad3ad; }
.prog.halted .tip { background: #0a7d33; }
.prog.running .track { background: #fff3d6; border-color: #e6c878; }
.st { font: 600 12px system-ui, sans-serif; text-align: right; }
.prog.halted .st { color: #0a7d33; }
.prog.running .st { color: #a06a00; }
.status { font-size: .92rem; font-weight: 600; margin: .5rem 0; min-height: 1.3em; color: #555; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .3rem; }
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; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Approximating Chaitin's Omega FROM BELOW. Omega = sum over halting programs p of
// 2^(-length(p)). We can only ever discover halting programs (never prove non-halting),
// so our estimate only rises and is always a lower bound. Programs that never halt
// contribute nothing we can ever account for — that's why Omega is uncomputable.
//
// Each program here has a fixed length L (weight 2^-L) and a halting time H (steps to
// halt) or H = Infinity (never halts). At each step every running program advances by 1.
const PROGRAMS = [
{ name: 'p1', len: 2, halt: 1 }, // weight .25
{ name: 'p2', len: 3, halt: 4 }, // weight .125
{ name: 'p3', len: 3, halt: Infinity }, // never halts
{ name: 'p4', len: 4, halt: 7 }, // weight .0625
{ name: 'p5', len: 4, halt: 2 }, // weight .0625
{ name: 'p6', len: 5, halt: Infinity }, // never halts
{ name: 'p7', len: 5, halt: 12 }, // weight .03125
{ name: 'p8', len: 6, halt: 9 }, // weight .015625
];
const MAXSTEP = 20; // we can only watch finitely long; non-halting stays "running"
const weight = (p) => Math.pow(2, -p.len);
let step = 0;
function omegaEstimate() {
// sum of weights of programs KNOWN to have halted by now (halt <= step)
let s = 0;
for (const p of PROGRAMS) if (p.halt <= step) s += weight(p);
return s;
}
function render() {
document.getElementById('step').textContent = step;
const est = omegaEstimate();
document.getElementById('omega').textContent = est.toFixed(6);
document.getElementById('fill').style.width = (est * 100).toFixed(2) + '%';
const box = document.getElementById('progs'); box.innerHTML = '';
let running = 0;
for (const p of PROGRAMS) {
const halted = p.halt <= step;
if (!halted) running++;
const row = document.createElement('div');
row.className = 'prog ' + (halted ? 'halted' : 'running');
const frac = halted ? 1 : Math.min(step / MAXSTEP, 0.96);
row.innerHTML =
'<span class="tag">' + p.name + ' (2<sup>-' + p.len + '</sup>)</span>' +
'<span class="track"><span class="tip" style="left:' + (frac * 100) + '%"></span></span>' +
'<span class="st">' + (halted ? fmt('halted +%weight%', { weight: weight(p).toFixed(4) }) : 'running…') + '</span>';
box.appendChild(row);
}
const s = document.getElementById('status');
if (running === 0) s.textContent = 'All observable programs halted. But in general you can NEVER be sure none are left.';
else s.textContent = fmt('%running% program(s) still running — will they halt? Omega never tells you.', { running: running });
}
function stepOnce() { if (step < MAXSTEP) step++; render(); }
document.getElementById('run').addEventListener('click', stepOnce);
document.getElementById('run10').addEventListener('click', () => { for (let i = 0; i < 10; i++) stepOnce(); });
document.getElementById('reset').addEventListener('click', () => { step = 0; render(); });
render();
<p class="hint">Each row is a tiny random program with a <b>length</b> (so it carries
weight 2<sup>-length</sup>) and a hidden <b>halting time</b>. Press <b>Run a step</b> to let every
still-running program execute one more instruction. When one halts, it adds its weight to
our estimate of Ω — the bar only ever <b>rises</b>, and you can never tell which
running programs will ever stop.</p>
<div class="meter">
<div class="bar"><div id="fill" class="fill"></div></div>
<div class="readout">Ω ≥ <span id="omega">0.000000</span>
<span class="muted">(step <span id="step">0</span>)</span></div>
</div>
<div id="progs" class="progs"></div>
<div class="btns">
<button id="run" type="button">Run a step</button>
<button id="run10" type="button">Run 10 steps</button>
<button id="reset" type="button" class="ghost">Reset</button>
</div>
<div class="status" id="status">Some programs never halt — the estimate stays a lower bound forever.</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; }
.meter { margin: .4rem 0 .8rem; }
.bar { height: 22px; background: #e8eef3; border: 1px solid #cdd9e3; border-radius: 6px; overflow: hidden; }
.fill { height: 100%; width: 0%; background: linear-gradient(90deg,#1d3557,#3a6ea5); transition: width .25s; }
.readout { font: 600 1rem ui-monospace, monospace; margin-top: .4rem; color: #1d3557; }
.muted { color: #788; font-weight: 400; }
.progs { display: grid; gap: 5px; margin: .4rem 0; }
.prog { display: grid; grid-template-columns: 70px 1fr 96px; align-items: center; gap: 8px;
font: 600 13px ui-monospace, monospace; }
.tag { color: #1d3557; }
.track { height: 14px; background: #c9ccd1; border: 1px solid #adb1b8; border-radius: 7px; position: relative; overflow: hidden; }
.tip { position: absolute; top: 0; bottom: 0; width: 6px; background: #1d3557; transition: left .2s; }
.prog.halted .track { background: #d6f0df; border-color: #9ad3ad; }
.prog.halted .tip { background: #0a7d33; }
.prog.running .track { background: #fff3d6; border-color: #e6c878; }
.st { font: 600 12px system-ui, sans-serif; text-align: right; }
.prog.halted .st { color: #0a7d33; }
.prog.running .st { color: #a06a00; }
.status { font-size: .92rem; font-weight: 600; margin: .5rem 0; min-height: 1.3em; color: #555; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .3rem; }
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; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Approximating Chaitin's Omega FROM BELOW. Omega = sum over halting programs p of
// 2^(-length(p)). We can only ever discover halting programs (never prove non-halting),
// so our estimate only rises and is always a lower bound. Programs that never halt
// contribute nothing we can ever account for — that's why Omega is uncomputable.
//
// Each program here has a fixed length L (weight 2^-L) and a halting time H (steps to
// halt) or H = Infinity (never halts). At each step every running program advances by 1.
const PROGRAMS = [
{ name: 'p1', len: 2, halt: 1 }, // weight .25
{ name: 'p2', len: 3, halt: 4 }, // weight .125
{ name: 'p3', len: 3, halt: Infinity }, // never halts
{ name: 'p4', len: 4, halt: 7 }, // weight .0625
{ name: 'p5', len: 4, halt: 2 }, // weight .0625
{ name: 'p6', len: 5, halt: Infinity }, // never halts
{ name: 'p7', len: 5, halt: 12 }, // weight .03125
{ name: 'p8', len: 6, halt: 9 }, // weight .015625
];
const MAXSTEP = 20; // we can only watch finitely long; non-halting stays "running"
const weight = (p) => Math.pow(2, -p.len);
let step = 0;
function omegaEstimate() {
// sum of weights of programs KNOWN to have halted by now (halt <= step)
let s = 0;
for (const p of PROGRAMS) if (p.halt <= step) s += weight(p);
return s;
}
function render() {
document.getElementById('step').textContent = step;
const est = omegaEstimate();
document.getElementById('omega').textContent = est.toFixed(6);
document.getElementById('fill').style.width = (est * 100).toFixed(2) + '%';
const box = document.getElementById('progs'); box.innerHTML = '';
let running = 0;
for (const p of PROGRAMS) {
const halted = p.halt <= step;
if (!halted) running++;
const row = document.createElement('div');
row.className = 'prog ' + (halted ? 'halted' : 'running');
const frac = halted ? 1 : Math.min(step / MAXSTEP, 0.96);
row.innerHTML =
'<span class="tag">' + p.name + ' (2<sup>-' + p.len + '</sup>)</span>' +
'<span class="track"><span class="tip" style="left:' + (frac * 100) + '%"></span></span>' +
'<span class="st">' + (halted ? fmt('halted +%weight%', { weight: weight(p).toFixed(4) }) : 'running…') + '</span>';
box.appendChild(row);
}
const s = document.getElementById('status');
if (running === 0) s.textContent = 'All observable programs halted. But in general you can NEVER be sure none are left.';
else s.textContent = fmt('%running% program(s) still running — will they halt? Omega never tells you.', { running: running });
}
function stepOnce() { if (step < MAXSTEP) step++; render(); }
document.getElementById('run').addEventListener('click', stepOnce);
document.getElementById('run10').addEventListener('click', () => { for (let i = 0; i < 10; i++) stepOnce(); });
document.getElementById('reset').addEventListener('click', () => { step = 0; render(); });
render();
Watch what happens. The estimate only ever rises — each newly halting program adds a little, none can ever subtract. That is what "approximating Ω from below" means. But notice the cruelty: at any moment, programs are still running, and you have no way to tell whether one of them will halt on the next step or never halt at all. The number you see is always a lower bound, never the true value — and you can never know how close you are. To learn more about that wall, see the halting problem and the busy beaver.
Comments
Loading comments...