code wiki / _hdl_build / nx_ppmi_probe.nx
nx_ppmi_probe.nx source
↩ module page · 156 lines · 6250 B
1// nx_ppmi_probe.nx -- HONEST VERDICT on the SHIPPED knowledge/index/semppmi_v1.bin.
2// Loads the persisted 41MB PPMI model (built by nx_semppmi_build) and prints the real
3// probe cosines: cos(won,defeated) vs cos(won,purple), cos(city,stadium) vs cos(city,january).
4// This is the evidence gate for wiring the dense/semantic reranker over the REAL model:
5// both order -> GREEN (count-model carries the signal; dense reranker is wire-ready)
6// not both -> AMBER (count-model weak at this pair; trained thread may be required)
7// Reuses the PROVEN loader/cos format from nx_qabench.nx (ppmi_load/ppmi_cos), sem_isqrt
8// re-defined locally (it lives in the app layer, not the engine).
9// expect_exit: 0 license_tier: ORIGINAL
10import "nx_qabench_engine.nx"
11const K_MAGIC_4096: i64 = 4096
12const K_MAGIC_536870912: i64 = 536870912
13const K_MAGIC_262144: i64 = 262144
14
15// integer sqrt (Newton), copy of the app-layer helper
16func pb_isqrt(v: i64) -> i64 {
17 if v <= 0 { return 0 }
18 var x: i64 = v
19 var y: i64 = (x + 1) / 2
20 while y < x { x = y; let q: i64 = v / x; y = (x + q) / 2 }
21 return x
22}
23
24// g-slots: 70 blob,71 nv,72 nt,73 vh,74 ridx,75 nrm2,76 tctx,77 tval,78 loaded
25func pb_load(g: *i64) -> i64 {
26 g[78] = 0
27 let fd: i64 = sys_openat_rd("knowledge/index/semppmi_v1.bin" as *u8)
28 if fd < 0 { return 0 }
29 let hdrb: *u8 = sys_mmap(K_MAGIC_4096)
30 var hgot: i64 = 0
31 var hr: i64 = 1
32 while hr > 0 { if hgot >= 32 { hr = 0 } else { hr = sys_read(fd, (hdrb as i64 + hgot) as *u8, 32 - hgot); if hr > 0 { hgot = hgot + hr } } }
33 if hgot < 32 { sys_close(fd); return 0 }
34 let hh: *i64 = (hdrb as i64 + 8) as *i64
35 let hnv: i64 = hh[0]
36 let hnt: i64 = hh[1]
37 let need0: i64 = 32 + (hnv*8) + ((hnv+1)*8) + (hnv*8) + (hnt*8) + (hnt*8)
38 if need0 <= 32 { sys_close(fd); return 0 }
39 if need0 > K_MAGIC_536870912 { sys_close(fd); return 0 }
40 let cap: i64 = need0 + K_MAGIC_4096
41 let blob: *u8 = sys_mmap(cap)
42 var i0: i64 = 0
43 while i0 < 32 { blob[i0] = hdrb[i0]; i0 = i0 + 1 }
44 var total: i64 = 32
45 var r: i64 = 1
46 while r > 0 {
47 let left: i64 = need0 - total
48 if left <= 0 { r = 0 } else {
49 var want: i64 = K_MAGIC_262144
50 if want > left { want = left }
51 r = sys_read(fd, (blob as i64 + total) as *u8, want)
52 if r > 0 { total = total + r }
53 }
54 }
55 sys_close(fd)
56 if total < 64 { return 0 }
57 if blob[0] != (78 as u8) { return 0 }
58 if blob[6] != (49 as u8) { return 0 }
59 let hi: *i64 = (blob as i64 + 8) as *i64
60 let nv: i64 = hi[0]
61 let nt: i64 = hi[1]
62 let need: i64 = 32 + (nv*8) + ((nv+1)*8) + (nv*8) + (nt*8) + (nt*8)
63 if total < need { return 0 }
64 g[70] = blob as i64
65 g[71] = nv
66 g[72] = nt
67 var off: i64 = 32
68 g[73] = (blob as i64) + off; off = off + nv*8
69 g[74] = (blob as i64) + off; off = off + (nv+1)*8
70 g[75] = (blob as i64) + off; off = off + nv*8
71 g[76] = (blob as i64) + off; off = off + nt*8
72 g[77] = (blob as i64) + off
73 g[78] = 1
74 return 1
75}
76
77// cosine between two PPMI rows (sorted sparse merge), permille
78func pb_cos(g: *i64, a: i64, b: i64) -> i64 {
79 let ridx: *i64 = g[74] as *i64
80 let nrm2: *i64 = g[75] as *i64
81 let tctx: *i64 = g[76] as *i64
82 let tval: *i64 = g[77] as *i64
83 var ia: i64 = ridx[a]
84 var ib: i64 = ridx[b]
85 let ea: i64 = ridx[a+1]
86 let eb: i64 = ridx[b+1]
87 var dot: i64 = 0
88 while ia < ea {
89 if ib >= eb { ia = ea } else {
90 if tctx[ia] == tctx[ib] { dot = dot + tval[ia]*tval[ib]; ia = ia + 1; ib = ib + 1 }
91 else { if tctx[ia] < tctx[ib] { ia = ia + 1 } else { ib = ib + 1 } }
92 }
93 }
94 if dot <= 0 { return 0 }
95 let d1: i64 = pb_isqrt(nrm2[a])
96 let d2: i64 = pb_isqrt(nrm2[b])
97 if d1 == 0 { return 0 }
98 if d2 == 0 { return 0 }
99 var cv: i64 = (dot*1000)/(d1*d2)
100 if cv > 1000 { cv = 1000 }
101 return cv
102}
103
104// resolve a null-terminated word literal -> PPMI vocab id or -1
105func pb_wid(g: *i64, s: *u8) -> i64 {
106 var n: i64 = 0
107 while s[n] != (0 as u8) { n = n + 1 }
108 let hv: i64 = db_semhash(s, 0, n)
109 return db_bsearch_i64(g[73] as *i64, g[71], hv)
110}
111
112// -1 if either id missing from vocab
113func pb_safecos(g: *i64, a: i64, b: i64) -> i64 {
114 if a < 0 { return 0-1 }
115 if b < 0 { return 0-1 }
116 return pb_cos(g, a, b)
117}
118
119func main() -> i64 {
120 let g: *i64 = sys_mmap(128*8) as *i64
121 let ok: i64 = pb_load(g)
122 if ok == 0 { db_w("RED -- semppmi_v1.bin load failed\n" as *u8); return 1 }
123 db_w("MODEL loaded: vocab="); db_n(g[71]); db_w(" triples="); db_n(g[72]); db_w("\n" as *u8)
124
125 let won: i64 = pb_wid(g, "won" as *u8)
126 let def: i64 = pb_wid(g, "defeated" as *u8)
127 let pur: i64 = pb_wid(g, "purple" as *u8)
128 let cty: i64 = pb_wid(g, "city" as *u8)
129 let sta: i64 = pb_wid(g, "stadium" as *u8)
130 let jan: i64 = pb_wid(g, "january" as *u8)
131 db_w("ids: won="); db_n(won); db_w(" defeated="); db_n(def); db_w(" purple="); db_n(pur)
132 db_w(" city="); db_n(cty); db_w(" stadium="); db_n(sta); db_w(" january="); db_n(jan); db_w("\n" as *u8)
133
134 let p1: i64 = pb_safecos(g, won, def)
135 let p2: i64 = pb_safecos(g, won, pur)
136 let p3: i64 = pb_safecos(g, cty, sta)
137 let p4: i64 = pb_safecos(g, cty, jan)
138 db_w("PROBE1 cos(won,defeated)="); db_n(p1); db_w(" cos(won,purple)="); db_n(p2); db_w("\n" as *u8)
139 db_w("PROBE2 cos(city,stadium)="); db_n(p3); db_w(" cos(city,january)="); db_n(p4); db_w("\n" as *u8)
140
141 // identity sanity (a row vs itself should be 1000)
142 let idn: i64 = pb_safecos(g, won, won)
143 db_w("NEG identity cos(won,won)="); db_n(idn); db_w("\n" as *u8)
144
145 var ord1: i64 = 0
146 if p1 > p2 { ord1 = 1 }
147 var ord2: i64 = 0
148 if p3 > p4 { ord2 = 1 }
149 db_w("VERDICT ord1(defeated>purple)="); db_n(ord1); db_w(" ord2(stadium>january)="); db_n(ord2); db_w("\n" as *u8)
150 if ord1 == 1 { if ord2 == 1 {
151 db_w("GREEN -- PROBES ORDER: the real PPMI model carries semantic signal; dense reranker is WIRE-READY over the shipped model.\n" as *u8)
152 return 0
153 } }
154 db_w("AMBER -- probes do not both order; count-model signal weak at these pairs (trained thread may be required for the dense axis).\n" as *u8)
155 return 0
156}