food_chain/experiments/ab/supplement.mjs
2026-09-29 23:45:12 +09:00

8 lines
3.7 KiB
JavaScript

import fs from 'node:fs/promises';import vm from 'node:vm';import {performance} from 'node:perf_hooks';
const html=await fs.readFile(new URL('../../index.html',import.meta.url),'utf8'),scripts=[...html.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g)].map(m=>m[1]),kc={};vm.runInNewContext(scripts[0],kc);const element={width:256,height:192,clientWidth:256,clientHeight:192,style:{},hidden:false,value:'',textContent:'',disabled:false,addEventListener(){},classList:{toggle(){}},setAttribute(){},removeAttribute(){},showModal(){},close(){},getBoundingClientRect(){return{left:0,top:0,width:256,height:192}}};const app={MANDEL_WEBGPU_KERNELS:kc.MANDEL_WEBGPU_KERNELS,document:{querySelector:()=>element,getElementById:()=>element,documentElement:{classList:{toggle(){}}},body:{classList:{toggle(){}},appendChild(){}}},navigator:{hardwareConcurrency:8,deviceMemory:8},location:{search:'',hash:''},history:{replaceState(){}},performance,URLSearchParams,URL:{createObjectURL:()=>'',revokeObjectURL(){}},TextEncoder,Blob:class{},console,addEventListener(){},requestAnimationFrame:()=>1,cancelAnimationFrame(){},setTimeout,clearTimeout,setInterval,clearInterval,innerWidth:256,innerHeight:192,devicePixelRatio:1,localStorage:{getItem(){return null},setItem(){},removeItem(){}}};const cut=scripts[1].indexOf('// ── boot / teardown');vm.runInNewContext(scripts[1].slice(0,cut)+`\nglobalThis.x={certifiedInteriorTiles};})();`,app);const C=app.x;
function fromDec(s,bits=256){s=String(s);let neg=s[0]=='-';if(neg)s=s.slice(1);const [m,e0='0']=s.toLowerCase().split('e'),e=+e0||0,[i='0',f='']=m.split('.');let d=(i+f).replace(/^0+(?=\d)/,'')||'0',p=f.length-e;if(p<0){d+='0'.repeat(-p);p=0}let den=10n**BigInt(p),v=(BigInt(d)*(1n<<BigInt(bits))+den/2n)/den;return neg?-v:v}
function gate(v,w,h){const re=v.re,im=v.im,span=v.span,unit=1n<<BigInt(v.bits),bw=BigInt(w),bh=BigInt(h),xLo=2n*re-span,xHi=2n*re+span,xDen=2n*unit,yLo=2n*bw*im-span*bh,yHi=2n*bw*im+span*bh,yDen=2n*bw*unit,axis=(lo,hi,den,lp,lq,hp,hq)=>hi*BigInt(lq)>=BigInt(lp)*den&&lo*BigInt(hq)<=BigInt(hp)*den;return axis(xLo,xHi,xDen,-3,4,3,8)&&axis(yLo,yHi,yDen,-2,3,2,3)||axis(xLo,xHi,xDen,-5,4,-3,4)&&axis(yLo,yHi,yDen,-1,4,1,4)}
let seed=0x9e3779b9;const rnd=()=>{seed=(Math.imul(seed,1664525)+1013904223)>>>0;return seed/2**32};let gateFalse=0,falseNeg=0,totalProof=0;for(let i=0;i<240;i++){const span=10**(-4+rnd()*4.7),v={bits:256,re:fromDec(-2+rnd()*3),im:fromDec(-1.2+rnd()*2.4),span:fromDec(span)},g=gate(v,256,192),p=C.certifiedInteriorTiles(v,256,192,32,null).pixels;if(!g)gateFalse++;if(!g&&p){falseNeg++;totalProof+=p}}
// FAST semantic coverage with random seeded/proven/unknown metadata. 0 means untouched hole; any invocation writes nonzero unless a nonzero seed/proof is intentionally retained.
let fastFalse=0,fastCases=0;for(let c=0;c<200;c++){const w=1+Math.floor(rnd()*700),h=1+Math.floor(rnd()*500),mirror=rnd()<.5,computeH=mirror?Math.ceil(h/2):h,meta=new Uint32Array(w*h);for(let i=0;i<meta.length;i++){const q=rnd();meta[i]=q<.1?(3<<28):q<.2?(1<<28)|5:q<.3?123:0}const tileW=1+Math.floor(rnd()*Math.min(w,200)),rows=1+Math.floor(rnd()*Math.min(computeH,80));for(let y=0;y<computeH;y+=rows)for(let x=0;x<w;x+=tileW){const tw=Math.min(tileW,w-x),th=Math.min(rows,computeH-y);for(let yy=0;yy<th;yy++)for(let xx=0;xx<tw;xx++){const i=(y+yy)*w+x+xx,cls=meta[i]>>>28;if(cls===3)continue;if(cls!==0)continue;meta[i]=(1<<28)|1}}if(mirror)for(let y=0;y<Math.floor(h/2);y++)for(let x=0;x<w;x++)meta[(h-1-y)*w+x]=meta[y*w+x]||1;let holes=0;for(const m of meta)if(m===0)holes++;if(holes)fastFalse++;fastCases++}
console.log(JSON.stringify({interiorGateRandom:{cases:240,gateFalse,falseNeg,totalProofInFalseNeg:totalProof},fastCoverageSemantic:{cases:fastCases,casesWithHoles:fastFalse}},null,2));