code wiki / _hdl_build / nx_visual_diff_gate.nx

nx_visual_diff_gate.nx source

↩ module page · 90 lines · 4165 B

1// nx_visual_diff_gate.nx -- PROOF (re-runnable, known-answer fixtures) that the visual-parity instrument 2// measures truthfully BEFORE we point it at Chrome-vs-Nishi: identical images MUST score 1000 permille, 3// a half-different image MUST score exactly 500, the worst-cell report must point AT the differing half, 4// content extent must find the exact last content row, and a PNG round-trip must survive. If the ruler 5// lies, every benchmark on top of it lies -- so the ruler gets its own gate. license_tier: ORIGINAL 6// expect_exit: 0 7import "nx_visual_diff.nx" 8import "nx_png_write.nx" 9 10func vg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 11func vg_n(v: i64) -> i64 { let t: *u8=sys_mmap(24); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(24); var j: i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 12 13// build an in-memory VdImg (RGB, nc=3) filled with (r,g,b) 14func vg_img(w: i64, h: i64, r: i64, g: i64, b: i64) -> *VdImg { 15 let im: *VdImg = sys_mmap(VD_IMG_BYTES as nx_size) as *VdImg 16 im.px = sys_mmap((w*h*3) as nx_size) 17 im.w = w 18 im.h = h 19 im.nc = 3 20 var i: i64 = 0 21 while i < w*h { 22 im.px[i*3] = r as u8 23 im.px[i*3+1] = g as u8 24 im.px[i*3+2] = b as u8 25 i = i + 1 26 } 27 return im 28} 29 30func main() -> i64 { 31 vg_w("=== nx_visual_diff_gate -- prove the parity ruler measures truthfully ===\n" as *u8) 32 var fails: i64 = 0 33 let out: *i64 = sys_mmap(256) as *i64 34 35 // T1: identical images -> exactly 1000 permille 36 let a: *VdImg = vg_img(64, 64, 10, 12, 14) 37 let b: *VdImg = vg_img(64, 64, 10, 12, 14) 38 let p1: i64 = vd_grid_parity(a, 0, b, 0, 64, 64, 8, 8, 12, out) 39 vg_w(" T1 identical -> " as *u8); vg_n(p1) 40 if p1 == 1000 { vg_w(" PASS\n" as *u8) } else { fails=fails+1; vg_w(" FAIL (want 1000)\n" as *u8) } 41 42 // T2 CAN-FAIL: right half bright -> exactly 500 permille; worst cell must be IN the right half (cx>=4) 43 let c: *VdImg = vg_img(64, 64, 10, 12, 14) 44 var y: i64 = 0 45 while y < 64 { 46 var x: i64 = 32 47 while x < 64 { 48 let o: i64 = (y*64+x)*3 49 c.px[o] = 220 as u8 50 c.px[o+1] = 220 as u8 51 c.px[o+2] = 220 as u8 52 x = x + 1 53 } 54 y = y + 1 55 } 56 let p2: i64 = vd_grid_parity(a, 0, c, 0, 64, 64, 8, 8, 12, out) 57 vg_w(" T2 half-different -> " as *u8); vg_n(p2); vg_w(" worst-cell cx=" as *u8); vg_n(out[2]) 58 var t2: i64 = 0 59 if p2 == 500 { if out[2] >= 4 { t2 = 1 } } 60 if t2 == 1 { vg_w(" PASS (500 + worst cell points at the differing half)\n" as *u8) } else { fails=fails+1; vg_w(" FAIL\n" as *u8) } 61 62 // T3: content extent -- bright band at rows y=40..41 on dark bg -> extent = 42 63 let d: *VdImg = vg_img(64, 64, 10, 10, 10) 64 y = 40 65 while y < 42 { 66 var x2: i64 = 0 67 while x2 < 64 { let o2: i64 = (y*64+x2)*3; d.px[o2]=200 as u8; d.px[o2+1]=200 as u8; d.px[o2+2]=200 as u8; x2=x2+1 } 68 y = y + 1 69 } 70 let e3: i64 = vd_content_extent(d, 12) 71 vg_w(" T3 extent (band at 40..41) -> " as *u8); vg_n(e3) 72 if e3 == 42 { vg_w(" PASS\n" as *u8) } else { fails=fails+1; vg_w(" FAIL (want 42)\n" as *u8) } 73 74 // T4: PNG round-trip -- write a fixture, vd_load it, verify dims + a pixel 75 nx_png_write_rgb("knowledge/status/vd_gate_fixture.png\x00" as *u8, d.px, 64, 64) 76 let ld: *VdImg = vd_load("knowledge/status/vd_gate_fixture.png\x00" as *u8) 77 var t4: i64 = 0 78 if (ld as i64) != 0 { 79 if ld.w == 64 { if ld.h == 64 { 80 let po: i64 = (40*64+10) * ld.nc 81 if (ld.px[po] as i64) > 150 { t4 = 1 } 82 } } 83 } 84 vg_w(" T4 PNG round-trip (write->vd_load->pixel) -> " as *u8) 85 if t4 == 1 { vg_w("PASS\n" as *u8) } else { fails=fails+1; vg_w("FAIL\n" as *u8) } 86 87 if fails == 0 { vg_w("NX-VISUAL-DIFF GREEN -- the ruler is truthful (known-answer fixtures)\n" as *u8); sys_exit(0); return 0 } 88 vg_w("NX-VISUAL-DIFF RED fails=" as *u8); vg_n(fails); vg_w("\n" as *u8) 89 sys_exit(1); return 1 90}