code wiki / (root) / sketch_hll_packed_test.nx

sketch_hll_packed_test.nx source

↩ module page · 92 lines · 3076 B

1// sketch_hll_packed_test.nx -- end-to-end test for HLL_6 packed 2// registers. Memory + accuracy parity vs HLL_8. 3 4import "syscalls.nx" 5import "sketch_hll.nx" 6import "sketch_hll_packed.nx" 7import "sketch_types.nx" 8 9func write_i64_le(buf: *u8, value: i64) -> i64 { 10 var i: i64 = 0 11 var v: i64 = value 12 while i < 8 { 13 buf[i] = v & 0xFF 14 v = v >> 8 15 i = i + 1 16 } 17 return 0 18} 19 20func main() -> i64 { 21 // lg_k=10 -> 1024 registers. HLL_8 = 1024 bytes; HLL_6 = 769. 22 let h6: *Hll6 = nx_hll6_alloc(10, 0) 23 if h6 == (0 as *Hll6) { return __syscall(93, 5, 0, 0, 0, 0, 0) } 24 25 // ---- memory stomp ---- 26 // HLL_8 register-array size is m bytes; HLL_6 should be 27 // m*6/8 rounded up + 1 guard byte. For m=1024: 768+1 = 769. 28 let mem6: i64 = nx_hll6_memory_bytes(h6) 29 if mem6 != 769 { return __syscall(93, 6, 0, 0, 0, 0, 0) } 30 // Confirm < 25% reduction baseline: 769 < 1024 * 0.80 31 let baseline: i64 = 1024 32 let reduced_threshold: i64 = (baseline * 80) / 100 33 if mem6 >= reduced_threshold { 34 // Should be 75% of HLL_8 size; if we didn't make 80% threshold, 35 // the packing is wrong. 36 return __syscall(93, 7, 0, 0, 0, 0, 0) 37 } 38 39 // ---- accuracy parity ---- 40 // Stream same N=5000 keys through HLL_6 and verify estimate 41 // within +-15% of N (same tolerance as HLL_8). 42 let N: i64 = 5000 43 let key: *u8 = sys_mmap(8) 44 var i: i64 = 0 45 while i < N { 46 write_i64_le(key, i) 47 nx_hll6_add(h6, key, 8) 48 i = i + 1 49 } 50 let est: i64 = nx_hll6_estimate(h6) 51 let lo: i64 = (N * 85) / 100 52 let hi: i64 = (N * 115) / 100 53 if est < lo { return __syscall(93, 10, 0, 0, 0, 0, 0) } 54 if est > hi { return __syscall(93, 11, 0, 0, 0, 0, 0) } 55 56 // ---- bit-packing round-trip ---- 57 // Set rho=53 at index 100; read it back. 58 let h6b: *Hll6 = nx_hll6_alloc(10, 0) 59 nx_hll6_set(h6b.regs, 100, 53) 60 let got: i64 = nx_hll6_get(h6b.regs, 100) 61 if got != 53 { return __syscall(93, 20, 0, 0, 0, 0, 0) } 62 // Set rho=42 at index 101 (adjacent register); index 100 unchanged. 63 nx_hll6_set(h6b.regs, 101, 42) 64 if nx_hll6_get(h6b.regs, 100) != 53 { 65 return __syscall(93, 21, 0, 0, 0, 0, 0) 66 } 67 if nx_hll6_get(h6b.regs, 101) != 42 { 68 return __syscall(93, 22, 0, 0, 0, 0, 0) 69 } 70 // Clear by overwriting with 0. 71 nx_hll6_set(h6b.regs, 100, 0) 72 if nx_hll6_get(h6b.regs, 100) != 0 { 73 return __syscall(93, 23, 0, 0, 0, 0, 0) 74 } 75 if nx_hll6_get(h6b.regs, 101) != 42 { 76 return __syscall(93, 24, 0, 0, 0, 0, 0) 77 } 78 79 // ---- typed envelope ---- 80 let q: *ApproxI64 = nx_hll6_query(h6) 81 if q.envelope_kind != NX_ENV_REL_STDDEV { 82 return __syscall(93, 30, 0, 0, 0, 0, 0) 83 } 84 if q.maturity != NX_MATURITY_REFERENCE_IMPL { 85 return __syscall(93, 31, 0, 0, 0, 0, 0) 86 } 87 if q.adv_safety != NX_ADV_HONEST { 88 return __syscall(93, 32, 0, 0, 0, 0, 0) 89 } 90 91 return 0 92}