code wiki / _hdl_build / nx_editjudge.nx

nx_editjudge.nx source

↩ module page · 122 lines · 5475 B

1// nx_editjudge.nx -- CLI/MCP surface for the edit-compliance judge. 2// Measurement lives in nx_editjudge_lib.nx, which the gate imports too. 3// 4// VERBS 5// judge <ref.png> <gen.png> <from_hue_deg> <to_hue_deg> 6// -> JSON {masked, shifted, drifted, stayed, compliance_permil}. compliance = shifted/masked. 7// A HIGH "stayed" is the retention-converged failure (nothing changed); a HIGH "drifted" 8// is "changed to the wrong thing". They are reported separately on purpose. 9// selftest 10// expect_exit: 0 license_tier: ORIGINAL 11import "nx_editjudge_lib.nx" 12 13func jw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 14func jn(v: i64) -> i64 { 15 let b: *u8 = sys_mmap(28) 16 var m: i64 = v 17 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 18 let t: *u8 = sys_mmap(28) 19 var k: i64 = 0 20 if m == 0 { t[0] = (48 as u8); k = 1 } 21 while m > 0 { t[k] = ((48 + (m % 10)) as u8); m = m / 10; k = k + 1 } 22 var i: i64 = 0 23 while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 24 sys_write(1, b, k) 25 return 0 26} 27 28func j_streq(a: *u8, b: *u8) -> i64 { 29 var i: i64 = 0 30 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 31 if b[i] != (0 as u8) { return 0 } 32 return 1 33} 34func j_atoi(s: *u8) -> i64 { 35 var v: i64 = 0 36 var i: i64 = 0 37 while s[i] != (0 as u8) { let c: i64 = (s[i] as i64) & 255; if c >= 48 { if c <= 57 { v = v*10 + (c-48) } } i = i + 1 } 38 return v 39} 40 41// synthetic solid-colour RGB field for selftest 42func j_fill(buf: *u8, npix: i64, r: i64, g: i64, b: i64) -> i64 { 43 var i: i64 = 0 44 while i < npix { buf[i*3] = (r as u8); buf[i*3+1] = (g as u8); buf[i*3+2] = (b as u8); i = i + 1 } 45 return 0 46} 47 48func j_selftest() -> i64 { 49 let n: i64 = 100 50 let refy: *u8 = sys_mmap(n*3) 51 let geng: *u8 = sys_mmap(n*3) 52 let geny: *u8 = sys_mmap(n*3) 53 j_fill(refy, n, 235, 205, 40) // yellow (hue ~ 51) 54 j_fill(geng, n, 40, 200, 70) // green (hue ~ 130) 55 j_fill(geny, n, 235, 205, 40) // still yellow -- the retention-converged failure 56 let mk: *i64 = sys_mmap(8) 57 let sh: *i64 = sys_mmap(8) 58 let dr: *i64 = sys_mmap(8) 59 let st: *i64 = sys_mmap(8) 60 61 let c1: i64 = ej_compliance(refy, geng, n, 50, 130, mk, sh, dr, st) 62 jw("T1 yellow->green compliance=" as *u8); jn(c1); jw(" (want ~1000)\n" as *u8) 63 let c2: i64 = ej_compliance(refy, geny, n, 50, 130, mk, sh, dr, st) 64 jw("T2 yellow->yellow compliance=" as *u8); jn(c2); jw(" stayed=" as *u8); jn(st[0]); jw(" (want ~0 -- this is the failure the loop hid)\n" as *u8) 65 66 var pass: i64 = 0 67 if c1 >= 900 { pass = pass + 1 } 68 if c2 <= 100 { pass = pass + 1 } 69 jw("SELFTEST pass=" as *u8); jn(pass); jw("/2" as *u8) 70 if pass == 2 { jw(" verdict=GREEN\n" as *u8); return 0 } 71 jw(" verdict=RED\n" as *u8) 72 return 1 73} 74 75func main(argc: i64, argv: *i64) -> i64 { 76 if argc < 2 { 77 jw("usage: nx_editjudge judge <ref.png> <gen.png> <from_hue> <to_hue>\n" as *u8) 78 jw(" nx_editjudge selftest\n" as *u8) 79 return 2 80 } 81 let verb: *u8 = argv[1] as *u8 82 if j_streq(verb, "selftest" as *u8) == 1 { return j_selftest() } 83 if j_streq(verb, "judge" as *u8) == 1 { 84 if argc < 6 { jw("{\"error\":\"judge needs <ref.png> <gen.png> <from_hue> <to_hue> [x0 y0 x1 y1]\"}\n" as *u8); return 2 } 85 let fw: *i64 = sys_mmap(8) 86 let fh: *i64 = sys_mmap(8) 87 let gw: *i64 = sys_mmap(8) 88 let gh: *i64 = sys_mmap(8) 89 let ref: *u8 = ej_load_rgb(argv[2] as *u8, fw, fh) 90 if ref == (0 as *u8) { jw("{\"error\":\"cannot decode reference PNG\"}\n" as *u8); return 3 } 91 let gen: *u8 = ej_load_rgb(argv[3] as *u8, gw, gh) 92 if gen == (0 as *u8) { jw("{\"error\":\"cannot decode generated PNG\"}\n" as *u8); return 3 } 93 if fw[0] != gw[0] { jw("{\"error\":\"dimension mismatch -- ref and gen must be the same size\"}\n" as *u8); return 4 } 94 if fh[0] != gh[0] { jw("{\"error\":\"dimension mismatch -- ref and gen must be the same size\"}\n" as *u8); return 4 } 95 let from: i64 = j_atoi(argv[4] as *u8) 96 let to: i64 = j_atoi(argv[5] as *u8) 97 var x0: i64 = 0 98 var y0: i64 = 0 99 var x1: i64 = 1000 100 var y1: i64 = 1000 101 if argc >= 10 { x0 = j_atoi(argv[6] as *u8); y0 = j_atoi(argv[7] as *u8); x1 = j_atoi(argv[8] as *u8); y1 = j_atoi(argv[9] as *u8) } 102 var satmin: i64 = EJ_SAT_MIN 103 if argc >= 11 { satmin = j_atoi(argv[10] as *u8) } 104 let mk: *i64 = sys_mmap(8) 105 let sh: *i64 = sys_mmap(8) 106 let dr: *i64 = sys_mmap(8) 107 let st: *i64 = sys_mmap(8) 108 let c: i64 = ej_compliance_spec(ref, gen, fw[0], fh[0], from, to, x0, y0, x1, y1, satmin, mk, sh, dr, st) 109 jw("{\"from_hue\":" as *u8); jn(from) 110 jw(",\"to_hue\":" as *u8); jn(to) 111 jw(",\"masked_px\":" as *u8); jn(mk[0]) 112 jw(",\"shifted\":" as *u8); jn(sh[0]) 113 jw(",\"drifted\":" as *u8); jn(dr[0]) 114 jw(",\"stayed\":" as *u8); jn(st[0]) 115 jw(",\"compliance_permil\":" as *u8); jn(c) 116 jw(",\"footprint_permil\":" as *u8); jn(ej_footprint(ref, gen, fw[0]*fh[0])) 117 jw(",\"headline\":\"shifted/masked -- high stayed = nothing changed, high drifted = wrong change; footprint = fraction of the WHOLE frame that moved (mask-free collateral check, DEC026)\"}\n" as *u8) 118 return 0 119 } 120 jw("{\"error\":\"unknown verb\"}\n" as *u8) 121 return 2 122}