nx_colordesc_gate.nx source
↩ module page · 205 lines · 9889 B
1// nx_colordesc_gate.nx -- referee for the chroma color-layout descriptor (nx_colordesc).
2// PROVES the color axis grayscale throws away. Corpus = 4 color classes (red/green/blue/yellow),
3// 4 instances each varying additive brightness + per-channel noise.
4// row1 RETRIEVAL: precision@3 by COLOR class (each image has 3 same-color peers).
5// row2 BEYOND-GRAYSCALE (headline exceed): a luma-MATCHED red field and green field have identical
6// grayscale (dHash Hamming == 0 -> the gray engine cannot tell them apart) yet a LARGE colordesc
7// L1 -> color sees what dHash/visdesc structurally cannot.
8// row3 BRIGHTNESS INVARIANCE: +uniform brightness leaves chroma unchanged (L1 ~ 0, by construction).
9// row4 DETERMINISM: same image twice -> identical descriptor (L1 == 0).
10// row5 SEPARATION: cross-color avg L1 >> same-color avg L1 (no collapse).
11// GREEN iff 5/5. Durable verdict -> knowledge/status/colordesc_gate.log. license_tier: ORIGINAL
12import "nx_colordesc.nx"
13import "nx_phash.nx"
14
15func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16func g_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); 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}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
17func g_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
18func g_wn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); 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}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
19
20func g_clamp255(v: i64) -> i64 { if v<0 { return 0 } if v>255 { return 255 } return v }
21
22// flat color fill (no noise) -- for the clean luma-matched headline pair.
23func g_fill_rgb(buf: *u8, w: i64, h: i64, r: i64, g: i64, b: i64) -> i64 {
24 var i: i64 = 0
25 let n: i64 = w*h
26 while i < n { buf[i*3]=g_clamp255(r) as u8; buf[i*3+1]=g_clamp255(g) as u8; buf[i*3+2]=g_clamp255(b) as u8; i=i+1 }
27 return 0
28}
29// color field with additive brightness + deterministic per-channel noise (instances differ).
30func g_synth_rgb(buf: *u8, w: i64, h: i64, r: i64, g: i64, b: i64, dbright: i64, phase: i64) -> i64 {
31 var y: i64 = 0
32 while y < h {
33 var x: i64 = 0
34 while x < w {
35 let idx: i64 = (y*w+x)*3
36 buf[idx] = g_clamp255(r + dbright + ((x*7 + y*13 + phase*5) & 7)) as u8
37 buf[idx+1] = g_clamp255(g + dbright + ((x*5 + y*11 + phase*3) & 7)) as u8
38 buf[idx+2] = g_clamp255(b + dbright + ((x*3 + y*17 + phase*7) & 7)) as u8
39 x = x + 1
40 }
41 y = y + 1
42 }
43 return 0
44}
45// interleaved RGB -> row-major luma (Rec.601 integer), so we can dHash the grayscale view.
46func g_rgb_to_gray(rgb: *u8, gray: *u8, w: i64, h: i64) -> i64 {
47 var i: i64 = 0
48 let n: i64 = w*h
49 while i < n {
50 let r: i64 = rgb[i*3] as i64
51 let g: i64 = rgb[i*3+1] as i64
52 let b: i64 = rgb[i*3+2] as i64
53 gray[i] = g_clamp255((77*r + 150*g + 29*b) / 256) as u8
54 i = i + 1
55 }
56 return 0
57}
58
59func main() -> i64 {
60 g_puts("=== COLORDESC GATE (color-layout: distinguishes hue grayscale collapses) ===\n" as *u8)
61 let W: i64 = 32
62 let H: i64 = 32
63 let NPX: i64 = W*H
64 let NINST: i64 = 4
65 let NIMG: i64 = 16
66
67 // 4 color classes
68 let CR: *i64 = sys_mmap(8*4) as *i64
69 let CG: *i64 = sys_mmap(8*4) as *i64
70 let CB: *i64 = sys_mmap(8*4) as *i64
71 CR[0]=210; CG[0]=30; CB[0]=30 // red
72 CR[1]=30; CG[1]=170; CB[1]=40 // green
73 CR[2]=40; CG[2]=40; CB[2]=210 // blue
74 CR[3]=200; CG[3]=190; CB[3]=40 // yellow
75
76 let descs: *i64 = sys_mmap(8*NIMG) as *i64
77 var k: i64 = 0
78 while k < NIMG {
79 let cls: i64 = k / NINST
80 let inst: i64 = k % NINST
81 let buf: *u8 = sys_mmap(NPX*3)
82 g_synth_rgb(buf, W, H, CR[cls], CG[cls], CB[cls], inst*10, inst)
83 let d: *i64 = sys_mmap(8*32) as *i64
84 nx_colordesc_extract(buf, W, H, d)
85 descs[k] = d as i64
86 k = k + 1
87 }
88
89 var pass: i64 = 0
90 let rows: i64 = 5
91
92 // ---- row1: retrieval precision@3 by color ----
93 let taken: *i64 = sys_mmap(8*NIMG) as *i64
94 let TOPK: i64 = 3
95 var pk_num: i64 = 0
96 var nn_same: i64 = 0
97 k = 0
98 while k < NIMG {
99 let dk: *i64 = descs[k] as *i64
100 var t: i64 = 0
101 while t < NIMG { taken[t] = 0; t = t + 1 }
102 taken[k] = 1
103 var rank: i64 = 0
104 while rank < TOPK {
105 var best: i64 = 0-1
106 var bestd: i64 = 0
107 var j: i64 = 0
108 while j < NIMG {
109 if taken[j] == 0 {
110 let dj: *i64 = descs[j] as *i64
111 let l1: i64 = nx_colordesc_l1(dk, dj)
112 if best < 0 { best = j; bestd = l1 } else { if l1 < bestd { best = j; bestd = l1 } }
113 }
114 j = j + 1
115 }
116 if best >= 0 {
117 taken[best] = 1
118 if (best/NINST) == (k/NINST) { pk_num = pk_num + 1 }
119 if rank == 0 { if (best/NINST) == (k/NINST) { nn_same = nn_same + 1 } }
120 }
121 rank = rank + 1
122 }
123 k = k + 1
124 }
125 var pk_permil: i64 = 0
126 if NIMG*TOPK > 0 { pk_permil = pk_num * 1000 / (NIMG*TOPK) }
127 g_puts(" row1 retrieval P@3=" as *u8); g_num(pk_permil); g_puts("permil (1-NN same-color=" as *u8); g_num(nn_same); g_puts("/" as *u8); g_num(NIMG); g_puts(") -> " as *u8)
128 if pk_permil >= 750 { pass=pass+1; g_puts("PASS (color retrieval)\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
129
130 // ---- row2: luma-matched red vs green -- gray collapses (dHash ham 0), color separates ----
131 let rgbR: *u8 = sys_mmap(NPX*3)
132 g_fill_rgb(rgbR, W, H, 204, 0, 0) // luma ~61
133 let rgbG: *u8 = sys_mmap(NPX*3)
134 g_fill_rgb(rgbG, W, H, 0, 105, 0) // luma ~61
135 let gR: *u8 = sys_mmap(NPX)
136 let gG: *u8 = sys_mmap(NPX)
137 g_rgb_to_gray(rgbR, gR, W, H)
138 g_rgb_to_gray(rgbG, gG, W, H)
139 let lumaR: i64 = gR[0] as i64
140 let lumaG: i64 = gG[0] as i64
141 let dhR: i64 = nx_phash_dhash(gR, W, H)
142 let dhG: i64 = nx_phash_dhash(gG, W, H)
143 let gray_ham: i64 = nx_simhash_hamming(dhR, dhG)
144 let cdR: *i64 = sys_mmap(8*32) as *i64
145 let cdG: *i64 = sys_mmap(8*32) as *i64
146 nx_colordesc_extract(rgbR, W, H, cdR)
147 nx_colordesc_extract(rgbG, W, H, cdG)
148 let color_l1: i64 = nx_colordesc_l1(cdR, cdG)
149 g_puts(" row2 red(luma=" as *u8); g_num(lumaR); g_puts(") vs green(luma=" as *u8); g_num(lumaG); g_puts("): grayscale dHash ham=" as *u8); g_num(gray_ham)
150 g_puts(" (identical), colordesc L1=" as *u8); g_num(color_l1); g_puts(" (distinct) -> " as *u8)
151 if gray_ham <= 2 { if color_l1 > 200 { pass=pass+1; g_puts("PASS (color sees what gray cannot)\n" as *u8) } else { g_puts("FAIL\n" as *u8) } } else { g_puts("FAIL\n" as *u8) }
152
153 // ---- row3: brightness invariance (uniform +40 to all channels) ----
154 let rgbRB: *u8 = sys_mmap(NPX*3)
155 g_fill_rgb(rgbRB, W, H, 244, 40, 40) // red + 40 on every channel
156 let cdRB: *i64 = sys_mmap(8*32) as *i64
157 nx_colordesc_extract(rgbRB, W, H, cdRB)
158 let bri_l1: i64 = nx_colordesc_l1(cdR, cdRB)
159 g_puts(" row3 brightness invariance -> L1(red, red+40)=" as *u8); g_num(bri_l1); g_puts(" (small) -> " as *u8)
160 if bri_l1 < 40 { pass=pass+1; g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
161
162 // ---- row4: determinism ----
163 let cdR2: *i64 = sys_mmap(8*32) as *i64
164 nx_colordesc_extract(rgbR, W, H, cdR2)
165 let det_l1: i64 = nx_colordesc_l1(cdR, cdR2)
166 g_puts(" row4 determinism -> L1(extract,extract)=" as *u8); g_num(det_l1); g_puts(" (==0) -> " as *u8)
167 if det_l1 == 0 { pass=pass+1; g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
168
169 // ---- row5: separation (cross-color L1 >> same-color L1) ----
170 var ssum: i64 = 0
171 var scnt: i64 = 0
172 var xsum: i64 = 0
173 var xcnt: i64 = 0
174 var a: i64 = 0
175 while a < NIMG {
176 var b: i64 = a+1
177 while b < NIMG {
178 let da: *i64 = descs[a] as *i64
179 let db: *i64 = descs[b] as *i64
180 let l1: i64 = nx_colordesc_l1(da, db)
181 if (a/NINST) == (b/NINST) { ssum = ssum + l1; scnt = scnt + 1 } else { xsum = xsum + l1; xcnt = xcnt + 1 }
182 b = b + 1
183 }
184 a = a + 1
185 }
186 var savg: i64 = 0
187 if scnt > 0 { savg = ssum / scnt }
188 var xavg: i64 = 0
189 if xcnt > 0 { xavg = xsum / xcnt }
190 g_puts(" row5 separation -> same-color avg L1=" as *u8); g_num(savg); g_puts(" cross-color avg L1=" as *u8); g_num(xavg); g_puts(" (~" as *u8)
191 if savg>0 { g_num(xavg/savg) } else { g_num(0) }
192 g_puts("x) -> " as *u8)
193 if xavg > 2*savg { pass=pass+1; g_puts("PASS (clear color separation)\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
194
195 g_puts("----\nCOLORDESC-GATE rows=" as *u8); g_num(rows); g_puts(" pass=" as *u8); g_num(pass); g_puts("\n" as *u8)
196 let lg: i64 = sys_openat_append("knowledge/status/colordesc_gate.log" as *u8, 0x1a4)
197 if lg>=0 {
198 g_w(lg,"COLORDESC-GATE rows=" as *u8); g_wn(lg,rows); g_w(lg," pass=" as *u8); g_wn(lg,pass)
199 g_w(lg," p_at_3=" as *u8); g_wn(lg,pk_permil); g_w(lg," gray_ham=" as *u8); g_wn(lg,gray_ham); g_w(lg," color_l1=" as *u8); g_wn(lg,color_l1); g_w(lg," sameL1=" as *u8); g_wn(lg,savg); g_w(lg," crossL1=" as *u8); g_wn(lg,xavg)
200 if pass==rows { g_w(lg," verdict=GREEN\n" as *u8) } else { g_w(lg," verdict=RED\n" as *u8) }
201 sys_close(lg)
202 }
203 if pass==rows { g_puts("COLORDESC-GATE GREEN\n" as *u8); sys_exit(0); return 0 }
204 g_puts("COLORDESC-GATE RED\n" as *u8); sys_exit(1); return 1
205}