nx_bench_metrics_test.nx source
↩ module page · 106 lines · 4024 B
1// nx_bench_metrics_test.nx -- KAT for the retrieval-quality kernels.
2//
3// Native sovereign lane: nx_compile_x86_native.elf -> as -> ld -> run.
4// Exit 0 = all pass; exit N = assertion N failed.
5//
6// Goldens (Q16.16, FX_ONE = 65536):
7// DCG[3,2,3,0,1,2]@6 = 6.8610 * 65536 ~= 449640
8// IDCG (sorted desc) = 7.1410 * 65536 ~= 467989
9// nDCG = 0.96081 * 65536 ~= 62968
10// precision@4 (2 rel) = 0.5 -> 32768 (exact)
11// recall@4 (2 of 3) = 0.6667 -> 43690 (exact, truncated)
12// RR (first rel @ 2) = 0.5 -> 32768 (exact)
13// AP [a,b,c,d] rel{a,c}= (1 + 2/3)/2 = 0.8333 -> 54613 (exact, trunc)
14// primary@4 [1,0,1,1] = 0.75 -> 49152 (exact)
15// canonical_rate[1,1,2,3]= 0.75 -> 49152 (exact)
16
17import "fx.nx"
18import "nx_bench_metrics.nx"
19
20func within(a: i64, b: i64, tol: i64) -> i64 {
21 var d: i64 = a - b
22 if d < 0 { d = 0 - d }
23 if d <= tol { return 1 }
24 return 0
25}
26
27func main() -> i64 {
28 // ---- graded gains [3,2,3,0,1,2] in Q16.16 ----
29 let g_raw: *u8 = sys_mmap(6 * 8)
30 let g: *i64 = g_raw as *i64
31 g[0] = fx_from_int(3)
32 g[1] = fx_from_int(2)
33 g[2] = fx_from_int(3)
34 g[3] = 0
35 g[4] = fx_from_int(1)
36 g[5] = fx_from_int(2)
37
38 let dcg: i64 = nx_bench_dcg(g, 6, 6)
39 if within(dcg, 449640, 200) != 1 { return 1 }
40
41 let ndcg: i64 = nx_bench_ndcg(g, 6, 6)
42 if within(ndcg, 62968, 150) != 1 { return 2 }
43
44 // already-ideal order normalizes to 1.0
45 let g2_raw: *u8 = sys_mmap(3 * 8)
46 let g2: *i64 = g2_raw as *i64
47 g2[0] = fx_from_int(3); g2[1] = fx_from_int(2); g2[2] = fx_from_int(1)
48 if within(nx_bench_ndcg(g2, 3, 3), FX_ONE, 4) != 1 { return 3 }
49
50 // no relevant gain -> nDCG 0
51 let g3_raw: *u8 = sys_mmap(3 * 8)
52 let g3: *i64 = g3_raw as *i64
53 g3[0] = 0; g3[1] = 0; g3[2] = 0
54 if nx_bench_ndcg(g3, 3, 3) != 0 { return 4 }
55
56 // ---- id lists: retrieved [10,20,30,40], relevant {10,30,50} ----
57 let retr_raw: *u8 = sys_mmap(4 * 8)
58 let retr: *i64 = retr_raw as *i64
59 retr[0] = 10; retr[1] = 20; retr[2] = 30; retr[3] = 40
60 let rel_raw: *u8 = sys_mmap(3 * 8)
61 let rel: *i64 = rel_raw as *i64
62 rel[0] = 10; rel[1] = 30; rel[2] = 50
63
64 // precision@4 = 2/4 = 0.5
65 if nx_bench_precision_at_k(retr, 4, rel, 3, 4) != FX_HALF { return 5 }
66 // recall@4 = 2/3 -> (2<<16)/3 = 43690
67 if nx_bench_recall_at_k(retr, 4, rel, 3, 4) != 43690 { return 6 }
68 // RR: first relevant is 10 at rank 1 -> 1.0
69 if nx_bench_reciprocal_rank(retr, 4, rel, 3) != FX_ONE { return 7 }
70
71 // RR with first relevant at rank 2: retrieved [20,10,30], rel {10}
72 let retr2_raw: *u8 = sys_mmap(3 * 8)
73 let retr2: *i64 = retr2_raw as *i64
74 retr2[0] = 20; retr2[1] = 10; retr2[2] = 30
75 let rel2_raw: *u8 = sys_mmap(1 * 8)
76 let rel2: *i64 = rel2_raw as *i64
77 rel2[0] = 10
78 if nx_bench_reciprocal_rank(retr2, 3, rel2, 1) != FX_HALF { return 8 }
79
80 // AP: retrieved [10,20,30,40], rel {10,30} -> (1/1 + 2/3)/2
81 // = (65536 + 43690)/2 = 54613
82 let relac_raw: *u8 = sys_mmap(2 * 8)
83 let relac: *i64 = relac_raw as *i64
84 relac[0] = 10; relac[1] = 30
85 if within(nx_bench_average_precision(retr, 4, relac, 2), 54613, 1) != 1 { return 9 }
86
87 // ---- primary-source precision: [1,0,1,1]@4 = 0.75 ----
88 let prim_raw: *u8 = sys_mmap(4 * 8)
89 let prim: *i64 = prim_raw as *i64
90 prim[0] = 1; prim[1] = 0; prim[2] = 1; prim[3] = 1
91 if nx_bench_primary_precision_at_k(prim, 4, 4) != 49152 { return 10 }
92 // top-2 [1,0] = 0.5
93 if nx_bench_primary_precision_at_k(prim, 4, 2) != FX_HALF { return 11 }
94
95 // ---- canonical rate: [1,1,2,3] = 3 distinct / 4 = 0.75 ----
96 let can_raw: *u8 = sys_mmap(4 * 8)
97 let can: *i64 = can_raw as *i64
98 can[0] = 1; can[1] = 1; can[2] = 2; can[3] = 3
99 if nx_bench_canonical_rate(can, 4) != 49152 { return 12 }
100
101 // ---- altitude = (ndcg + primary)/2 ----
102 if nx_bench_altitude(FX_ONE, FX_ONE) != FX_ONE { return 13 }
103 if nx_bench_altitude(FX_ONE, 0) != FX_HALF { return 14 }
104
105 return 0
106}