code wiki / _hdl_build / nx_dr_densejudge.nx

nx_dr_densejudge.nx source

↩ module page · 201 lines · 6878 B

1// nx_dr_densejudge.nx -- TRAINED DENSE representation for the judge (DR-13). 2// Three measured rejections (§10 vocabulary, §12 term weighting, §14 learned fusion) localised 3// the ceiling to the FEATURES themselves: sparse PPMI co-occurrence carries only ~65% pairwise 4// signal on insight-vs-distractor, so no amount of reweighting or fusing fixes it. The 5// remaining move is a DIFFERENT REPRESENTATION. 6// 7// This uses the ecosystem's TRAINED dense embeddings (knowledge/index/embed_v1.bin, Q10, 8// nv x DIM), produced by nx_embed_train factorising the PPMI matrix (Levy & Goldberg 2014: 9// factorising PPMI == word2vec/SGNS). On the known-hard pair the trained dense vectors ordered 10// far more confidently than raw counts (607 vs 559, where sparse counts gave 86 vs 25), which 11// is exactly the kind of representational change the diagnosis calls for. 12// 13// Vocabulary: embed_v1.bin rows are indexed by the SAME ids as semppmi_v1.bin (the trainer read 14// that vocab), so word resolution still goes through nx_ppmi_lib -- BOTH models are loaded. 15// on-disk: 24B header [magic "NXEMB1", i64 nv, i64 DIM] then nv*DIM Q10 i64 (block-padded tail 16// is ignored -- we read exactly nv*DIM). 17// Every func <=6 params (NAS nx_cc >6-arg skew, seq239). No hardware writes (Rule 26). 18// 19// module: nishi-core.research.dr_densejudge 20// depends: nx_ppmi_lib.nx 21// genealogy_id: levy_goldberg_2014_sgns + colbert_late_interaction 22import "nx_ppmi_lib.nx" 23const K_MAGIC_536870912: i64 = 536870912 24const K_MAGIC_4096: i64 = 4096 25const K_MAGIC_262144: i64 = 262144 26 27// embed slots (disjoint from the PPMI slots 70..78): 80 base, 81 nv, 82 dim, 83 loaded 28func dj_load_embed(g: *i64, path: *u8) -> i64 { 29 g[83] = 0 30 let fd: i64 = sys_openat_rd(path) 31 if fd < 0 { return 0 } 32 let hb: *u8 = sys_mmap(64) 33 var got: i64 = 0 34 var r: i64 = 1 35 while r > 0 { if got >= 24 { r = 0 } else { r = sys_read(fd, (hb as i64 + got) as *u8, 24 - got); if r > 0 { got = got + r } } } 36 if got < 24 { sys_close(fd); return 0 } 37 if hb[0] != (78 as u8) { sys_close(fd); return 0 } 38 if hb[5] != (49 as u8) { sys_close(fd); return 0 } 39 let hi: *i64 = (hb as i64 + 8) as *i64 40 let nv: i64 = hi[0] 41 let dim: i64 = hi[1] 42 if nv < 1 { sys_close(fd); return 0 } 43 if dim < 1 { sys_close(fd); return 0 } 44 let need: i64 = nv * dim * 8 45 if need > K_MAGIC_536870912 { sys_close(fd); return 0 } 46 let blob: *u8 = sys_mmap(need + K_MAGIC_4096) 47 var total: i64 = 0 48 r = 1 49 while r > 0 { 50 let left: i64 = need - total 51 if left <= 0 { r = 0 } else { 52 var want: i64 = K_MAGIC_262144 53 if want > left { want = left } 54 r = sys_read(fd, (blob as i64 + total) as *u8, want) 55 if r > 0 { total = total + r } 56 } 57 } 58 sys_close(fd) 59 if total < need { return 0 } 60 g[80] = blob as i64 61 g[81] = nv 62 g[82] = dim 63 g[83] = 1 64 return 1 65} 66 67// dense cosine between two vocab rows, permille. Negative similarity is clamped to 0 (for 68// coverage purposes "anti-related" and "unrelated" are both simply not evidence). 69func dj_cos(g: *i64, a: i64, b: i64) -> i64 { 70 if a < 0 { return 0 } 71 if b < 0 { return 0 } 72 if g[83] != 1 { return 0 } 73 let nv: i64 = g[81] 74 if a >= nv { return 0 } 75 if b >= nv { return 0 } 76 if a == b { return 1000 } 77 let dim: i64 = g[82] 78 let e: *i64 = g[80] as *i64 79 let ba: i64 = a * dim 80 let bb: i64 = b * dim 81 var dot: i64 = 0 82 var na: i64 = 0 83 var nb: i64 = 0 84 var d: i64 = 0 85 while d < dim { 86 let x: i64 = e[ba + d] 87 let y: i64 = e[bb + d] 88 dot = dot + x * y 89 na = na + x * x 90 nb = nb + y * y 91 d = d + 1 92 } 93 if dot <= 0 { return 0 } 94 let la: i64 = ppl_isqrt(na) 95 let lb: i64 = ppl_isqrt(nb) 96 if la == 0 { return 0 } 97 if lb == 0 { return 0 } 98 var cv: i64 = (dot * 1000) / (la * lb) 99 if cv > 1000 { cv = 1000 } 100 return cv 101} 102 103// Build the mean vector over the WHOLE vocabulary into slot 84. Trained embeddings acquire a 104// dominant common direction that inflates every cosine (the recorded symptom on embed_v1: 105// "cosines compressed by a common component"). Removing it is the standard fix -- Mu & 106// Viswanath 2018, "All-but-the-Top". Measured, not assumed: dj_cos_centered is compared against 107// dj_cos on the same benchmark. 108func dj_build_mean(g: *i64) -> i64 { 109 if g[83] != 1 { return 0 } 110 let nv: i64 = g[81] 111 let dim: i64 = g[82] 112 let e: *i64 = g[80] as *i64 113 let m: *i64 = sys_mmap(dim * 8) as *i64 114 var d: i64 = 0 115 while d < dim { m[d] = 0; d = d + 1 } 116 var i: i64 = 0 117 while i < nv { 118 let b: i64 = i * dim 119 d = 0 120 while d < dim { m[d] = m[d] + e[b + d]; d = d + 1 } 121 i = i + 1 122 } 123 d = 0 124 while d < dim { m[d] = m[d] / nv; d = d + 1 } 125 g[84] = m as i64 126 return 1 127} 128 129// dense cosine with the common component removed (requires dj_build_mean first) 130func dj_cos_centered(g: *i64, a: i64, b: i64) -> i64 { 131 if a < 0 { return 0 } 132 if b < 0 { return 0 } 133 if g[83] != 1 { return 0 } 134 if a == b { return 1000 } 135 let nv: i64 = g[81] 136 if a >= nv { return 0 } 137 if b >= nv { return 0 } 138 let dim: i64 = g[82] 139 let e: *i64 = g[80] as *i64 140 let m: *i64 = g[84] as *i64 141 let ba: i64 = a * dim 142 let bb: i64 = b * dim 143 var dot: i64 = 0 144 var na: i64 = 0 145 var nb: i64 = 0 146 var d: i64 = 0 147 while d < dim { 148 let x: i64 = e[ba + d] - m[d] 149 let y: i64 = e[bb + d] - m[d] 150 dot = dot + x * y 151 na = na + x * x 152 nb = nb + y * y 153 d = d + 1 154 } 155 if dot <= 0 { return 0 } 156 let la: i64 = ppl_isqrt(na) 157 let lb: i64 = ppl_isqrt(nb) 158 if la == 0 { return 0 } 159 if lb == 0 { return 0 } 160 var cv: i64 = (dot * 1000) / (la * lb) 161 if cv > 1000 { cv = 1000 } 162 return cv 163} 164 165// late-interaction coverage under the COMMON-COMPONENT-REMOVED dense representation 166func dj_maxsim_centered(g: *i64, a: *i64, na: i64, b: *i64, nb: i64) -> i64 { 167 if na < 1 { return 0 } 168 var total: i64 = 0 169 var i: i64 = 0 170 while i < na { 171 var best: i64 = 0 172 var j: i64 = 0 173 while j < nb { 174 let c: i64 = dj_cos_centered(g, a[i], b[j]) 175 if c > best { best = c } 176 j = j + 1 177 } 178 total = total + best 179 i = i + 1 180 } 181 return total / na 182} 183 184// Late-interaction coverage of `a` by `b` under the DENSE representation, permille. 185func dj_maxsim(g: *i64, a: *i64, na: i64, b: *i64, nb: i64) -> i64 { 186 if na < 1 { return 0 } 187 var total: i64 = 0 188 var i: i64 = 0 189 while i < na { 190 var best: i64 = 0 191 var j: i64 = 0 192 while j < nb { 193 let c: i64 = dj_cos(g, a[i], b[j]) 194 if c > best { best = c } 195 j = j + 1 196 } 197 total = total + best 198 i = i + 1 199 } 200 return total / na 201}