nx_phash_test.nx source
↩ module page · 75 lines · 3354 B
1// nx_phash_test.nx -- KAT + benchmark for perceptual image hashing.
2// Native sovereign lane; exit 0 = pass, N = assertion N failed.
3// Prints the measured Hamming distances (the benchmark), then asserts the
4// research-documented properties: deterministic; INVARIANT to uniform
5// brightness (dHash's defining property); near-dup strictly closer than a
6// different image; reverse-image lookup returns the right image.
7
8import "fx.nx"
9import "nx_phash.nx"
10
11func nx_putc(c: i64) -> i64 { let b: *u8 = sys_mmap(1); b[0] = c; sys_write(1, b, 1); return 0 }
12func nx_puts(s: *u8) -> i64 { var i: i64 = 0; while (s[i] as i64) != 0 { nx_putc(s[i] as i64); i = i + 1 } return 0 }
13func nx_put_i64(n: i64) -> i64 {
14 if n == 0 { nx_putc(0x30); return 0 }
15 var v: i64 = n; let t: *u8 = sys_mmap(32); var k: i64 = 0
16 while v > 0 { t[k] = 0x30 + (v - (v/10)*10); v = v/10; k = k+1 }
17 while k > 0 { k = k-1; sys_write(1, (((t as i64)+k) as *u8), 1) }
18 return 0
19}
20
21func main() -> i64 {
22 let W: i64 = 16
23 let H: i64 = 16
24 let a: *u8 = sys_mmap(W * H)
25 let ab: *u8 = sys_mmap(W * H)
26 let b: *u8 = sys_mmap(W * H)
27 let an: *u8 = sys_mmap(W * H)
28 var y: i64 = 0
29 while y < H {
30 var x: i64 = 0
31 while x < W {
32 let va: i64 = (x * 37 + y * 17) & 0x3F // pattern A, 0..63
33 a[y * W + x] = va
34 ab[y * W + x] = va + 40 // +40 brightness (no saturation)
35 b[y * W + x] = (y * 37 + x * 17) & 0x3F // different structure (x/y swapped)
36 an[y * W + x] = va // near-dup base (block tweaked below)
37 x = x + 1
38 }
39 y = y + 1
40 }
41 var by: i64 = 2
42 while by < 5 { var bx: i64 = 2; while bx < 5 { an[by * W + bx] = 63; bx = bx + 1 } by = by + 1 }
43
44 let fa: i64 = nx_phash_dhash(a, W, H)
45 let fa2: i64 = nx_phash_dhash(a, W, H)
46 let fab: i64 = nx_phash_dhash(ab, W, H)
47 let fb: i64 = nx_phash_dhash(b, W, H)
48 let fan: i64 = nx_phash_dhash(an, W, H)
49
50 let h_self: i64 = nx_simhash_hamming(fa, fa2)
51 let h_bright: i64 = nx_simhash_hamming(fa, fab)
52 let h_near: i64 = nx_simhash_hamming(fa, fan)
53 let h_diff: i64 = nx_simhash_hamming(fa, fb)
54
55 nx_puts("== dHash benchmark (Hamming /64) ==\n")
56 nx_puts(" identical : "); nx_put_i64(h_self); nx_putc(0x0A)
57 nx_puts(" +brightness : "); nx_put_i64(h_bright); nx_putc(0x0A)
58 nx_puts(" near-dup (block) : "); nx_put_i64(h_near); nx_putc(0x0A)
59 nx_puts(" different image : "); nx_put_i64(h_diff); nx_putc(0x0A)
60
61 if h_self != 0 { return 1 } // deterministic
62 if h_bright != 0 { return 2 } // INVARIANT to uniform brightness (dHash property)
63 if h_near >= h_diff { return 3 } // near-dup strictly closer than a different image
64
65 // reverse-image: a brightness-shifted A, searched among {A, B}, finds A
66 let set: *i64 = sys_mmap(2 * 8) as *i64
67 set[0] = fa; set[1] = fb
68 let hb: *i64 = sys_mmap(8) as *i64
69 if nx_phash_nearest(fab, set, 2, 10, hb) != 0 { return 4 }
70 nx_puts(" reverse-image : +brightness A -> matched index 0 (A) at Hamming "); nx_put_i64(hb[0]); nx_putc(0x0A)
71 // B searched among {A,B} matches itself
72 if nx_phash_nearest(fb, set, 2, 10, hb) != 1 { return 5 }
73
74 return 0
75}