code wiki / (root) / nx_word_sketch_test.nx

nx_word_sketch_test.nx source

↩ module page · 149 lines · 5616 B

1// nx_word_sketch_test.nx -- exercise positional word sketch primitive. 2 3import "nx_syscalls.nx" 4import "nx_tier.nx" 5import "nx_ngram.nx" 6import "nx_collocation.nx" 7import "nx_word_sketch.nx" 8 9func main() -> nx_int { 10 // ===== Tiny corpus: "the cat sat on the mat the cat ran fast" ===== 11 // 12 // Interned IDs: the=1, cat=2, sat=3, on=4, mat=5, ran=6, fast=7. 13 // Length = 10 tokens. target=cat (id=2) appears 2 times. 14 15 let stream: *i64 = (sys_mmap(80)) as *i64 16 stream[0] = 1 // the 17 stream[1] = 2 // cat 18 stream[2] = 3 // sat 19 stream[3] = 4 // on 20 stream[4] = 1 // the 21 stream[5] = 5 // mat 22 stream[6] = 1 // the 23 stream[7] = 2 // cat 24 stream[8] = 6 // ran 25 stream[9] = 7 // fast 26 27 let cap: nx_int = 32 28 let keys: *i64 = (sys_mmap(cap * 8)) as *i64 29 let counts: *i64 = (sys_mmap(cap * 8)) as *i64 30 31 // ===== Sketch "cat" with window=1 ================================= 32 // 33 // Occurrences of cat at i=1 and i=7. 34 // window=1 neighbors: 35 // i=1 -> stream[0]=the(1), stream[2]=sat(3) 36 // i=7 -> stream[6]=the(1), stream[8]=ran(6) 37 // Expected counts: the=2, sat=1, ran=1. 38 39 let n_target_1: nx_int = nx_word_sketch_count(stream, 10, 2, 1, 40 keys, counts, cap) 41 if n_target_1 != 2 { return 1 } 42 43 // Walk the table; verify the expected collocates + counts 44 var n_the: nx_int = 0 45 var n_sat: nx_int = 0 46 var n_ran: nx_int = 0 47 var n_other: nx_int = 0 48 var i: nx_int = 0 49 while i < cap { 50 if keys[i] != NX_WS_EMPTY_KEY { 51 if keys[i] == 1 { n_the = counts[i] } 52 if keys[i] == 3 { n_sat = counts[i] } 53 if keys[i] == 6 { n_ran = counts[i] } 54 if keys[i] != 1 { 55 if keys[i] != 3 { 56 if keys[i] != 6 { 57 n_other = n_other + 1 58 } 59 } 60 } 61 } 62 i = i + 1 63 } 64 if n_the != 2 { return 2 } 65 if n_sat != 1 { return 3 } 66 if n_ran != 1 { return 4 } 67 if n_other != 0 { return 5 } 68 69 // ===== Sketch "cat" with window=2 ================================= 70 // 71 // window=2 neighbors: 72 // i=1 -> stream[0]=the(1) [skip -2 since i-2=-1 OOB], stream[2]=sat(3), stream[3]=on(4) 73 // (offset -2 is OOB; offsets -1, +1, +2 valid) 74 // i=7 -> stream[5]=mat(5), stream[6]=the(1), stream[8]=ran(6), stream[9]=fast(7) 75 // Expected: the=2, sat=1, on=1, mat=1, ran=1, fast=1 76 77 let n_target_2: nx_int = nx_word_sketch_count(stream, 10, 2, 2, 78 keys, counts, cap) 79 if n_target_2 != 2 { return 10 } 80 81 var t_the: nx_int = 0 82 var t_sat: nx_int = 0 83 var t_on: nx_int = 0 84 var t_mat: nx_int = 0 85 var t_ran: nx_int = 0 86 var t_fast: nx_int = 0 87 var distinct: nx_int = 0 88 var j: nx_int = 0 89 while j < cap { 90 if keys[j] != NX_WS_EMPTY_KEY { 91 distinct = distinct + 1 92 if keys[j] == 1 { t_the = counts[j] } 93 if keys[j] == 3 { t_sat = counts[j] } 94 if keys[j] == 4 { t_on = counts[j] } 95 if keys[j] == 5 { t_mat = counts[j] } 96 if keys[j] == 6 { t_ran = counts[j] } 97 if keys[j] == 7 { t_fast = counts[j] } 98 } 99 j = j + 1 100 } 101 if t_the != 2 { return 11 } 102 if t_sat != 1 { return 12 } 103 if t_on != 1 { return 13 } 104 if t_mat != 1 { return 14 } 105 if t_ran != 1 { return 15 } 106 if t_fast != 1 { return 16 } 107 if distinct != 6 { return 17 } 108 109 // ===== Sketch verdict bands ======================================= 110 if nx_ws_classify(0) != NX_WS_KIND_EMPTY { return 20 } 111 if nx_ws_classify(2) != NX_WS_KIND_SPARSE { return 21 } 112 if nx_ws_classify(10) != NX_WS_KIND_HEALTHY { return 22 } 113 if nx_ws_classify(500) != NX_WS_KIND_DENSE { return 23 } 114 115 // ===== Score a single collocate =================================== 116 // 117 // Assume corpus stats: n_target=2 (cat occurrences), n_the=3 (the 118 // total in corpus), n_cooccur=2, n_total=10. Score with log-Dice. 119 let dice: nx_int = nx_word_sketch_metric_q10(2, 3, 2, 10, 120 NX_WS_METRIC_LOG_DICE) 121 // log-Dice = 14 + log2(2*2 / (2+3)) = 14 + log2(4/5) ~ 14 - 0.32 ~ 13.68 122 // Q10 -> ~ 14008 123 // We sanity-check a wide band (>0 and < 20*1024 = 20480). 124 if dice <= 0 { return 30 } 125 if dice >= 20480 { return 31 } 126 127 // Score "weak" collocate: high target freq + low coccur -> small score 128 let dice_weak: nx_int = nx_word_sketch_metric_q10(100, 1000, 2, 100000, 129 NX_WS_METRIC_LOG_DICE) 130 // weak should be < strong 131 if dice_weak >= dice { return 32 } 132 133 // ===== Full-metric emit returns all 4 metrics + 4 bands ========== 134 let out: *i64 = (sys_mmap(NX_COL_OUT_FIELDS * 8)) as *i64 135 nx_word_sketch_score_one(2, 3, 2, 10, out) 136 // pmi_band must be valid 137 if nx_col_band_is_valid(out[NX_COL_OUT_PMI_BAND]) == 0 { return 40 } 138 if nx_col_band_is_valid(out[NX_COL_OUT_LL_BAND]) == 0 { return 41 } 139 if nx_col_band_is_valid(out[NX_COL_OUT_T_BAND]) == 0 { return 42 } 140 if nx_col_band_is_valid(out[NX_COL_OUT_DICE_BAND]) == 0 { return 43 } 141 142 // ===== Target absent from stream ================================== 143 let n_target_3: nx_int = nx_word_sketch_count(stream, 10, 99, 2, 144 keys, counts, cap) 145 if n_target_3 != 0 { return 50 } 146 if nx_ws_classify(n_target_3) != NX_WS_KIND_EMPTY { return 51 } 147 148 return 0 149}