code wiki / _hdl_build / nx_refbench.nx
nx_refbench.nx source
↩ module page · 126 lines · 5073 B
1// nx_refbench.nx -- CLI/MCP surface for the reference-retention ruler.
2// All measurement lives in nx_refbench_lib.nx, which the GATE imports too, so the thing
3// that ships and the thing that is graded are the same code.
4//
5// VERBS
6// compare <ref.png> <gen.png> -> JSON {ref/gen dims, plane, structure, perceptual, retention}
7// selftest -> the anti-vacuity pair (identity must be 1000, mirror must not be)
8//
9// The full teeth live in nx_refbench_gate.nx; `selftest` is the fast in-tool smoke so an
10// agent calling this over MCP can confirm the instrument is sane before trusting a number.
11// expect_exit: 0 license_tier: ORIGINAL
12import "nx_refbench_lib.nx"
13import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
14
15func rb_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
16
17// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
18// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
19// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
20// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
21func rb_num(v: i64) -> i64 { nxi_out(v); return 0 }
22
23func rb_report(label: *u8, sp: i64, pp: i64) -> i64 {
24 rb_puts("{\"pair\":\"" as *u8); rb_puts(label)
25 rb_puts("\",\"structure_permil\":" as *u8); rb_num(sp)
26 rb_puts(",\"perceptual_permil\":" as *u8); rb_num(pp)
27 rb_puts(",\"retention_permil\":" as *u8); rb_num(rb_retention(sp, pp))
28 rb_puts(",\"headline\":\"MIN-of-channels\"}\n" as *u8)
29 return 0
30}
31
32// Fast in-tool smoke: the same two poles the gate proves at depth.
33func rb_selftest() -> i64 {
34 let side: i64 = 64
35 let a: *u8 = sys_mmap(side * side)
36 let b: *u8 = sys_mmap(side * side)
37 var y: i64 = 0
38 while y < side {
39 var x: i64 = 0
40 while x < side {
41 a[y * side + x] = (((x * 3 + y * 5) % 256) as u8)
42 // horizontally MIRRORED: identical histogram, different structure -- the case
43 // a naive mean/histogram comparator would wrongly call identical
44 b[y * side + x] = (((((side - 1 - x) * 3 + y * 5) % 256)) as u8)
45 x = x + 1
46 }
47 y = y + 1
48 }
49 let s1: *i64 = sys_mmap(8)
50 let p1: *i64 = sys_mmap(8)
51 rb_compare(a, side, side, a, side, side, s1, p1)
52 let t1s: i64 = s1[0]
53 let t1p: i64 = p1[0]
54 rb_puts("T1 identity " as *u8); rb_report("self-vs-self" as *u8, t1s, t1p)
55
56 let s2: *i64 = sys_mmap(8)
57 let p2: *i64 = sys_mmap(8)
58 rb_compare(a, side, side, b, side, side, s2, p2)
59 let t2s: i64 = s2[0]
60 let t2p: i64 = p2[0]
61 rb_puts("T2 mirrored " as *u8); rb_report("self-vs-mirror" as *u8, t2s, t2p)
62
63 var pass: i64 = 0
64 var fail: i64 = 0
65 if t1s >= 995 { pass = pass + 1 } else { fail = fail + 1 }
66 if t1p >= 995 { pass = pass + 1 } else { fail = fail + 1 }
67 if t2s < 900 { pass = pass + 1 } else { fail = fail + 1 }
68 rb_puts("SELFTEST pass=" as *u8); rb_num(pass)
69 rb_puts(" fail=" as *u8); rb_num(fail)
70 if fail == 0 { rb_puts(" verdict=GREEN\n" as *u8) } else { rb_puts(" verdict=RED\n" as *u8) }
71 return fail
72}
73
74func rb_streq(a: *u8, b: *u8) -> i64 {
75 var i: i64 = 0
76 while a[i] != (0 as u8) {
77 if a[i] != b[i] { return 0 }
78 i = i + 1
79 }
80 if b[i] != (0 as u8) { return 0 }
81 return 1
82}
83
84func main(argc: i64, argv: *i64) -> i64 {
85 if argc < 2 {
86 rb_puts("usage: nx_refbench selftest | nx_refbench compare <ref.png> <gen.png>\n" as *u8)
87 return 2
88 }
89 let verb: *u8 = argv[1] as *u8
90 if rb_streq(verb, "selftest" as *u8) == 1 { return rb_selftest() }
91 if rb_streq(verb, "compare" as *u8) == 1 {
92 if argc < 4 {
93 rb_puts("{\"error\":\"compare needs <ref.png> <gen.png>\"}\n" as *u8)
94 return 2
95 }
96 let pa: *u8 = argv[2] as *u8
97 let pb: *u8 = argv[3] as *u8
98 let wa: *i64 = sys_mmap(8)
99 let ha: *i64 = sys_mmap(8)
100 let wb: *i64 = sys_mmap(8)
101 let hb: *i64 = sys_mmap(8)
102 let ga: *u8 = rb_load_gray(pa, wa, ha)
103 if ga == (0 as *u8) {
104 rb_puts("{\"error\":\"cannot decode reference PNG\"}\n" as *u8)
105 return 3
106 }
107 let gb: *u8 = rb_load_gray(pb, wb, hb)
108 if gb == (0 as *u8) {
109 rb_puts("{\"error\":\"cannot decode generated PNG\"}\n" as *u8)
110 return 3
111 }
112 let sp: *i64 = sys_mmap(8)
113 let pp: *i64 = sys_mmap(8)
114 rb_compare(ga, wa[0], ha[0], gb, wb[0], hb[0], sp, pp)
115 rb_puts("{\"ref_w\":" as *u8); rb_num(wa[0])
116 rb_puts(",\"ref_h\":" as *u8); rb_num(ha[0])
117 rb_puts(",\"gen_w\":" as *u8); rb_num(wb[0])
118 rb_puts(",\"gen_h\":" as *u8); rb_num(hb[0])
119 rb_puts(",\"plane\":" as *u8); rb_num(RB_PLANE)
120 rb_puts("}\n" as *u8)
121 rb_report("ref-vs-gen" as *u8, sp[0], pp[0])
122 return 0
123 }
124 rb_puts("{\"error\":\"unknown verb\"}\n" as *u8)
125 return 2
126}