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}