code wiki / _hdl_build / nx_qabench.nx

nx_qabench.nx source

↩ module page · 2146 lines · 95267 B

1// nx_qabench.nx -- the QA-benchmark LADDER (operator 2026-07-07: "use others like beerqa, climb the ladder to 2// the top"). Runs the sovereign researcher's mechanical retrieve+extract+multi-hop pipeline (shared engine = 3// nx_qabench_engine, extracted from nx_drbench) across a DIFFICULTY GRADIENT and prints ONE scoreboard: 4// RUNG 1-hop = SQuAD v1.1 (single context paragraph -> isolates EXTRACTION from retrieval; should score HIGH) 5// RUNG 2-hop = HotpotQA distractor (retrieve 2 of 10 paras + bridge reasoning -> the reasoning wall) 6// Same F1/EM metric (nx_qa_score_lib, integer permille), same extractor -> the F1 DROP as hops rise is the 7// honest, MEASURED "where mechanical ends and reasoning/LLM begins" signal. Each benchmark: T-parse + T-negctl 8// (rotated-gold F1 ~0 = metric not rigged). Formats dispatched by `fmt` (0=hotpot distractor, 1=squad single). 9// expect_exit: 0 license_tier: ORIGINAL 10import "nx_qabench_engine.nx" 11import "nx_qwen_extract.nx" // R5: opt-in pretrained-Qwen extraction (marker file knowledge/index/qwen_reader.on) 12const SEM_MAGIC_260000: i64 = 260000 13const SEM_MAGIC_32760: i64 = 32760 14const SEM_MAGIC_4096: i64 = 4096 15const SEM_MAGIC_536870912: i64 = 536870912 16const SEM_MAGIC_262144: i64 = 262144 17const SEM_MAGIC_4000: i64 = 4000 18const SEM_MAGIC_200000: i64 = 200000 19const SEM_MAGIC_2000: i64 = 2000 20const SEM_MAGIC_8000: i64 = 8000 21const SEM_MAGIC_1024: i64 = 1024 22const SEM_MAGIC_2000000000: i64 = 2000000000 23const SEM_MAGIC_16777216: i64 = 16777216 24const SEM_MAGIC_402653184: i64 = 402653184 25const SEM_MAGIC_10000: i64 = 10000 26const SEM_MAGIC_2026: i64 = 2026 27const SEM_MAGIC_2500: i64 = 2500 28const SEM_MAGIC_1000000: i64 = 1000000 29const SEM_MAGIC_2048: i64 = 2048 30const SEM_MAGIC_32768: i64 = 32768 31const SEM_MAGIC_1048576: i64 = 1048576 32const SEM_MAGIC_524288: i64 = 524288 33const SEM_MAGIC_8192: i64 = 8192 34const SEM_MAGIC_65536: i64 = 65536 35const SEM_MAGIC_8388608: i64 = 8388608 36const SEM_MAGIC_16384: i64 = 16384 37const SEM_MAGIC_3999: i64 = 3999 38 39// ---- SQuAD: split a single context string into sentences in sb/so/sl/sp (all para 0). returns nsent ---- 40// is src[start..start+ln) prose (real answerable text) vs web CHROME/wikitext/JSON? Real web pages (esp. 41// Wikipedia) carry nav menus, language lists, and infobox markup ({{...}}, [[...]], {"wt":...}) that pollute 42// retrieval -- the measured binding constraint for live web research. Prose = letter-dense, sane length, few 43// markup markers. General (not site-specific): keeps the article body, drops the scaffolding. 44func qa_is_prose(src: *u8, start: i64, ln: i64) -> i64 { 45 if ln < 25 { return 0 } 46 if ln > 600 { return 0 } // giant runs w/o '. ' = nav blob / language list 47 var letters: i64 = 0 48 var spaces: i64 = 0 49 var bad: i64 = 0 50 var i: i64 = 0 51 while i < ln { 52 let c: i64 = src[start+i] as i64 53 if c >= 65 { if c <= 90 { letters = letters + 1 } } 54 if c >= 97 { if c <= 122 { letters = letters + 1 } } 55 if c == 32 { spaces = spaces + 1 } 56 if c == 123 { bad = bad + 1 } // { 57 if c == 125 { bad = bad + 1 } // } 58 if c == 124 { bad = bad + 1 } // | 59 if c == 61 { bad = bad + 1 } // = 60 if c == 91 { bad = bad + 1 } // [ 61 if c == 93 { bad = bad + 1 } // ] 62 i = i + 1 63 } 64 if bad > 2 { return 0 } // wikitext/JSON markup 65 if (letters + spaces) * 100 < ln * 78 { return 0 } // < 78% letters+spaces = not prose 66 var wc: i64 = spaces + 1 67 if wc < 5 { return 0 } // need >= ~5 words to be a real sentence 68 return 1 69} 70 71// copy [start,start+ln) into dst, DROPPING content inside ( ) and [ ] (pronunciation IPA / citation / date 72// parentheticals that pollute real web prose and get whole sentences dropped by the letter-ratio filter). 73// flat ifs (no else-chain: deep else{if} miscompiles per nx_cc). returns cleaned length. 74func qa_clean_sentence(src: *u8, start: i64, ln: i64, dst: *u8) -> i64 { 75 var depth: i64 = 0 76 var o: i64 = 0 77 var k: i64 = 0 78 while k < ln { 79 let c: i64 = src[start+k] as i64 80 var open: i64 = 0 81 if c==40 { open=1 } // ( 82 if c==91 { open=1 } // [ 83 var close: i64 = 0 84 if c==41 { close=1 } // ) 85 if c==93 { close=1 } // ] 86 if open==1 { depth=depth+1 } 87 if close==1 { if depth>0 { depth=depth-1 } } 88 if open==0 { if close==0 { if depth==0 { if o<1000 { dst[o]=src[start+k]; o=o+1 } } } } 89 k=k+1 90 } 91 dst[o]=(0 as u8) 92 return o 93} 94 95// prose-filtered sentence splitter for the LIVE answer mode (higher cap; drops non-prose). Isolated from the 96// benchmark's qab_split_ctx (whose inputs are already clean JSON-extracted contexts). 97func qa_split_prose(g: *i64, src: *u8, slen: i64) -> i64 { 98 let sb: *u8 = g[15] as *u8 99 let so: *i64 = g[16] as *i64 100 let sl: *i64 = g[17] as *i64 101 let sp: *i64 = g[18] as *i64 102 var ns: i64 = 0 103 var bump: i64 = 0 104 var start: i64 = 0 105 var i: i64 = 0 106 while i < slen { 107 var boundary: i64 = 0 108 let c: i64 = src[i] as i64 109 if c==46 { boundary=1 } 110 if c==63 { boundary=1 } 111 if c==33 { boundary=1 } 112 if boundary==1 { 113 var nxsp: i64 = 1 114 if i+1 < slen { let d: i64 = src[i+1] as i64; if d!=32 { if d!=10 { nxsp=0 } } } 115 if nxsp==0 { boundary=0 } 116 } 117 if boundary==1 { 118 let ln: i64 = (i+1) - start 119 let cbuf: *u8 = g[130] as *u8 // clean parenthetical/IPA/citation junk first 120 let cln: i64 = qa_clean_sentence(src, start, ln, cbuf) 121 if qa_is_prose(cbuf, 0, cln) == 1 { if ns < 400 { if bump+cln < SEM_MAGIC_260000 { 122 var w: i64 = 0 123 while w < cln { sb[bump+w] = cbuf[w]; w = w + 1 } 124 sb[bump+cln] = (0 as u8) 125 so[ns]=bump; sl[ns]=cln; sp[ns]=0; ns=ns+1; bump=bump+cln+1 126 } } } 127 var sk: i64 = i+1 128 var go: i64 = 1 129 while go == 1 { if sk < slen { if src[sk]==(32 as u8) { sk=sk+1 } else { go=0 } } else { go=0 } } 130 start = sk 131 i = sk 132 } else { i = i + 1 } 133 } 134 return ns 135} 136 137func qab_split_ctx(g: *i64, src: *u8, slen: i64) -> i64 { 138 let sb: *u8 = g[15] as *u8 139 let so: *i64 = g[16] as *i64 140 let sl: *i64 = g[17] as *i64 141 let sp: *i64 = g[18] as *i64 142 var ns: i64 = 0 143 var bump: i64 = 0 144 var start: i64 = 0 145 var i: i64 = 0 146 while i < slen { 147 var boundary: i64 = 0 148 let c: i64 = src[i] as i64 149 if c==46 { boundary=1 } 150 if c==63 { boundary=1 } 151 if c==33 { boundary=1 } 152 if boundary==1 { 153 var nxsp: i64 = 1 154 if i+1 < slen { let d: i64 = src[i+1] as i64; if d!=32 { if d!=10 { nxsp=0 } } } 155 if nxsp==0 { boundary=0 } 156 } 157 if boundary==1 { 158 let ln: i64 = (i+1) - start 159 if ln > 2 { if ns < 80 { if bump+ln < SEM_MAGIC_260000 { 160 var w: i64 = 0 161 while w < ln { sb[bump+w] = src[start+w]; w = w + 1 } 162 sb[bump+ln] = (0 as u8) // terminate: qs_norm reads to null; sb is reused across rows 163 so[ns]=bump; sl[ns]=ln; sp[ns]=0; ns=ns+1; bump=bump+ln+1 164 } } } 165 var sk: i64 = i+1 166 var go: i64 = 1 167 while go == 1 { if sk < slen { if src[sk]==(32 as u8) { sk=sk+1 } else { go=0 } } else { go=0 } } 168 start = sk 169 i = sk 170 } else { i = i + 1 } 171 } 172 if start < slen { let ln2: i64 = slen - start 173 if ln2 > 2 { if ns < 80 { if bump+ln2 < SEM_MAGIC_260000 { 174 var w2: i64 = 0 175 while w2 < ln2 { sb[bump+w2] = src[start+w2]; w2 = w2 + 1 } 176 sb[bump+ln2] = (0 as u8) 177 so[ns]=bump; sl[ns]=ln2; sp[ns]=0; ns=ns+1 178 } } } 179 } 180 return ns 181} 182 183// match a JSON bracket: pos at '[' or '{' -> index of the matching close (string-aware). -1 if unbalanced. 184func db_match_bracket(g: *i64, pos: i64) -> i64 { 185 let open: i64 = db_b(g, pos) 186 var close: i64 = 93 187 if open == 123 { close = 125 } 188 var depth: i64 = 0 189 var i: i64 = pos 190 var instr: i64 = 0 191 while i < g[1] { 192 let c: i64 = db_b(g, i) 193 if instr == 1 { 194 if c == 92 { i = i + 1 } else { if c == 34 { instr = 0 } } 195 } else { 196 if c == 34 { instr = 1 } else { 197 if c == open { depth = depth + 1 } 198 if c == close { depth = depth - 1; if depth == 0 { return i } } 199 } 200 } 201 i = i + 1 202 } 203 return 0 - 1 204} 205 206// append sentences from src[0..slen) into sb/so/sl/sp with sp=para; st=[ns,bump] updated in place. 207func qab_split_append(g: *i64, src: *u8, slen: i64, para: i64, st: *i64) -> i64 { 208 let sb: *u8 = g[15] as *u8 209 let so: *i64 = g[16] as *i64 210 let sl: *i64 = g[17] as *i64 211 let sp: *i64 = g[18] as *i64 212 var ns: i64 = st[0] 213 var bump: i64 = st[1] 214 var start: i64 = 0 215 var i: i64 = 0 216 while i < slen { 217 var boundary: i64 = 0 218 let c: i64 = src[i] as i64 219 if c==46 { boundary=1 } 220 if c==63 { boundary=1 } 221 if c==33 { boundary=1 } 222 if boundary==1 { 223 var nxsp: i64 = 1 224 if i+1 < slen { let d: i64 = src[i+1] as i64; if d!=32 { if d!=10 { nxsp=0 } } } 225 if nxsp==0 { boundary=0 } 226 } 227 if boundary==1 { 228 let ln: i64 = (i+1) - start 229 if ln > 2 { if ns < 1000 { if bump+ln < SEM_MAGIC_260000 { 230 var w: i64 = 0 231 while w < ln { sb[bump+w] = src[start+w]; w = w + 1 } 232 sb[bump+ln] = (0 as u8) // terminate: qs_norm reads to null; sb is reused across rows 233 so[ns]=bump; sl[ns]=ln; sp[ns]=para; ns=ns+1; bump=bump+ln+1 234 } } } 235 var sk: i64 = i+1 236 var go: i64 = 1 237 while go == 1 { if sk < slen { if src[sk]==(32 as u8) { sk=sk+1 } else { go=0 } } else { go=0 } } 238 start = sk 239 i = sk 240 } else { i = i + 1 } 241 } 242 if start < slen { let ln2: i64 = slen - start 243 if ln2 > 2 { if ns < 1000 { if bump+ln2 < SEM_MAGIC_260000 { 244 var w2: i64 = 0 245 while w2 < ln2 { sb[bump+w2] = src[start+w2]; w2 = w2 + 1 } 246 sb[bump+ln2] = (0 as u8) 247 so[ns]=bump; sl[ns]=ln2; sp[ns]=para; ns=ns+1 248 } } } 249 } 250 st[0]=ns; st[1]=bump 251 return 0 252} 253 254// ==================== R3-LITE: SEMANTIC sentence selection (MODE2) ==================== 255// Distributional co-occurrence embedding built from the question's OWN paragraphs (the nx_distrib_embed 256// method, per-row, zero training, sovereign): vocab of content words -> windowed co-occurrence matrix -> 257// sentence/question vectors = sums of member-word rows -> integer cosine. Extraction UNCHANGED -> isolates 258// the SELECTION variable. 259// ★MEASURED 2026-07-08 (kept as the R3 baseline column, NOT a win): F1_SEM vs F1_lex = SQuAD 149 vs 158, 260// HotpotQA 130 vs 146, MuSiQue 24 vs 45 -- per-question co-occurrence is WORSE everywhere and degrades MOST 261// where paragraphs are many (distractor mass poisons the stats; the question vector drifts to hub sentences). 262// 3rd principled climb, 3rd measured negative => the semantic wall needs CORPUS-LEVEL embeddings (R3b-scale 263// 519-doc thread) or a trained bi-encoder (R1-adjacent), NOT per-row stats. This column is the plug-in point: 264// swap sem_build_cooc's source for a persisted corpus matrix and the delta shows here. 265// ctx slots: 60 C(vc*vc i64) 61 qvec 62 svec 63 voff 64 vlen 65 vcount 66 vbuf 67 vbump 266// 68 pred2(256B) 69 vidx(per-sentence vocab ids) 267const SEM_VMAX: i64 = 1024 268const SEM_W: i64 = 6 269 270func sem_isqrt(v: i64) -> i64 { 271 if v <= 0 { return 0 } 272 var x: i64 = v 273 var y: i64 = (x + 1) / 2 274 while y < x { x = y; let q: i64 = v / x; y = (x + q) / 2 } 275 return x 276} 277 278// find token (buf,off,len) in the vocab; -1 if absent 279func sem_vfind(g: *i64, buf: *u8, off: i64, len: i64) -> i64 { 280 let vbuf: *u8 = g[66] as *u8 281 let voff: *i64 = g[63] as *i64 282 let vlen: *i64 = g[64] as *i64 283 var i: i64 = 0 284 while i < g[65] { 285 if qs_tok_eq2(buf, off, len, vbuf, voff[i], vlen[i]) == 1 { return i } 286 i = i + 1 287 } 288 return 0-1 289} 290 291// find-or-append; returns idx or -1 (caps hit) 292func sem_vadd(g: *i64, buf: *u8, off: i64, len: i64) -> i64 { 293 let f: i64 = sem_vfind(g, buf, off, len) 294 if f >= 0 { return f } 295 if g[65] >= SEM_VMAX { return 0-1 } 296 if g[67] + len + 1 >= SEM_MAGIC_32760 { return 0-1 } 297 let vbuf: *u8 = g[66] as *u8 298 let voff: *i64 = g[63] as *i64 299 let vlen: *i64 = g[64] as *i64 300 let idx: i64 = g[65] 301 let bump: i64 = g[67] 302 var w: i64 = 0 303 while w < len { vbuf[bump+w] = buf[off+w]; w = w + 1 } 304 voff[idx] = bump; vlen[idx] = len 305 g[65] = idx + 1 306 g[67] = bump + len + 1 307 return idx 308} 309 310// vocab = question content words + all sentence content words (stop-filtered, len>=2) 311func sem_build_vocab(g: *i64) -> i64 { 312 g[65] = 0 313 g[67] = 0 314 let qnb: *u8 = g[28] as *u8 315 let qto: *i64 = g[29] as *i64 316 let qtl: *i64 = g[30] as *i64 317 let qk: *i64 = g[32] as *i64 318 var k: i64 = 0 319 while k < g[31] { 320 if qk[k] == 1 { if qtl[k] >= 2 { sem_vadd(g, qnb, qto[k], qtl[k]) } } 321 k = k + 1 322 } 323 let nb: *u8 = g[20] as *u8 324 let tko: *i64 = g[23] as *i64 325 let tkl: *i64 = g[24] as *i64 326 let tks: *i64 = g[25] as *i64 327 let tkc: *i64 = g[26] as *i64 328 var s: i64 = 0 329 while s < g[19] { 330 var j: i64 = 0 331 while j < tkc[s] { 332 let ti: i64 = tks[s] + j 333 if tkl[ti] >= 2 { if db_is_stop(nb, tko[ti], tkl[ti]) == 0 { sem_vadd(g, nb, tko[ti], tkl[ti]) } } 334 j = j + 1 335 } 336 s = s + 1 337 } 338 return g[65] 339} 340 341// windowed co-occurrence over each sentence's vocab-member tokens 342func sem_build_cooc(g: *i64) -> i64 { 343 let C: *i64 = g[60] as *i64 344 let vc: i64 = g[65] 345 var z: i64 = 0 346 let zn: i64 = vc * vc 347 while z < zn { C[z] = 0; z = z + 1 } 348 let nb: *u8 = g[20] as *u8 349 let tko: *i64 = g[23] as *i64 350 let tkl: *i64 = g[24] as *i64 351 let tks: *i64 = g[25] as *i64 352 let tkc: *i64 = g[26] as *i64 353 let vidx: *i64 = g[69] as *i64 354 var s: i64 = 0 355 while s < g[19] { 356 var n: i64 = tkc[s] 357 if n > 250 { n = 250 } 358 var j: i64 = 0 359 while j < n { 360 let ti: i64 = tks[s] + j 361 let v: i64 = sem_vfind(g, nb, tko[ti], tkl[ti]) 362 vidx[j] = v 363 j = j + 1 364 } 365 var a: i64 = 0 366 while a < n { 367 if vidx[a] >= 0 { 368 var b: i64 = a + 1 369 var bend: i64 = a + SEM_W 370 if bend > n-1 { bend = n-1 } 371 while b <= bend { 372 if vidx[b] >= 0 { 373 let ia: i64 = vidx[a]*vc + vidx[b] 374 let ib: i64 = vidx[b]*vc + vidx[a] 375 C[ia] = C[ia] + 1 376 C[ib] = C[ib] + 1 377 } 378 b = b + 1 379 } 380 } 381 a = a + 1 382 } 383 s = s + 1 384 } 385 return 0 386} 387 388// vec += C-row of vocab id t 389func sem_addrow(g: *i64, vec: *i64, t: i64) -> i64 { 390 let C: *i64 = g[60] as *i64 391 let vc: i64 = g[65] 392 let base: i64 = t * vc 393 var k: i64 = 0 394 while k < vc { vec[k] = vec[k] + C[base + k]; k = k + 1 } 395 return 0 396} 397 398// question vector = sum of rows of its content words present in vocab. returns #hits. 399func sem_qvec(g: *i64, vec: *i64) -> i64 { 400 let vc: i64 = g[65] 401 var k: i64 = 0 402 while k < vc { vec[k] = 0; k = k + 1 } 403 let qnb: *u8 = g[28] as *u8 404 let qto: *i64 = g[29] as *i64 405 let qtl: *i64 = g[30] as *i64 406 let qk: *i64 = g[32] as *i64 407 var hits: i64 = 0 408 var i: i64 = 0 409 while i < g[31] { 410 if qk[i] == 1 { 411 let v: i64 = sem_vfind(g, qnb, qto[i], qtl[i]) 412 if v >= 0 { sem_addrow(g, vec, v); hits = hits + 1 } 413 } 414 i = i + 1 415 } 416 return hits 417} 418 419func sem_svec(g: *i64, s: i64, vec: *i64) -> i64 { 420 let vc: i64 = g[65] 421 var k: i64 = 0 422 while k < vc { vec[k] = 0; k = k + 1 } 423 let nb: *u8 = g[20] as *u8 424 let tko: *i64 = g[23] as *i64 425 let tkl: *i64 = g[24] as *i64 426 let tks: *i64 = g[25] as *i64 427 let tkc: *i64 = g[26] as *i64 428 var hits: i64 = 0 429 var j: i64 = 0 430 while j < tkc[s] { 431 let ti: i64 = tks[s] + j 432 let v: i64 = sem_vfind(g, nb, tko[ti], tkl[ti]) 433 if v >= 0 { sem_addrow(g, vec, v); hits = hits + 1 } 434 j = j + 1 435 } 436 return hits 437} 438 439// integer cosine in permille 440func sem_cos(a: *i64, b: *i64, vc: i64) -> i64 { 441 var dot: i64 = 0 442 var na: i64 = 0 443 var nb2: i64 = 0 444 var k: i64 = 0 445 while k < vc { 446 dot = dot + a[k]*b[k] 447 na = na + a[k]*a[k] 448 nb2 = nb2 + b[k]*b[k] 449 k = k + 1 450 } 451 if dot <= 0 { return 0 } 452 let d1: i64 = sem_isqrt(na) 453 let d2: i64 = sem_isqrt(nb2) 454 return (dot/(d1+1))*1000/(d2+1) 455} 456 457// ---------- PPMI-soft path (loads knowledge/index/semppmi_v1.bin when present; else per-row fallback) ---------- 458// slots: 70 blob base, 71 nv, 72 nt, 73 vh, 74 ridx, 75 nrm2, 76 tctx, 77 tval, 78 loaded-flag 459func ppmi_load(g: *i64) -> i64 { 460 g[78] = 0 461 let fd: i64 = sys_openat_rd("knowledge/index/semppmi_v1.bin" as *u8) 462 if fd < 0 { return 0 } 463 // TWO-PHASE read (no fixed whole-file cap -- the exact "grew past a fixed buffer" debt class): read the 464 // 32B header first, size the blob from nv/nt, then read the rest. Sanity-capped at 512MB. 465 let hdrb: *u8 = sys_mmap(SEM_MAGIC_4096) 466 var hgot: i64 = 0 467 var hr: i64 = 1 468 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 } } } 469 if hgot < 32 { sys_close(fd); return 0 } 470 let hh: *i64 = (hdrb as i64 + 8) as *i64 471 let hnv: i64 = hh[0] 472 let hnt: i64 = hh[1] 473 let need0: i64 = 32 + (hnv*8) + ((hnv+1)*8) + (hnv*8) + (hnt*8) + (hnt*8) 474 if need0 <= 32 { sys_close(fd); return 0 } 475 if need0 > SEM_MAGIC_536870912 { sys_close(fd); return 0 } 476 let cap: i64 = need0 + SEM_MAGIC_4096 477 let blob: *u8 = sys_mmap(cap) 478 var i0: i64 = 0 479 while i0 < 32 { blob[i0] = hdrb[i0]; i0 = i0 + 1 } 480 var total: i64 = 32 481 var r: i64 = 1 482 while r > 0 { 483 let left: i64 = need0 - total 484 if left <= 0 { r = 0 } else { 485 var want: i64 = SEM_MAGIC_262144 486 if want > left { want = left } 487 r = sys_read(fd, (blob as i64 + total) as *u8, want) 488 if r > 0 { total = total + r } 489 } 490 } 491 sys_close(fd) 492 if total < 64 { return 0 } 493 if blob[0] != (78 as u8) { return 0 } 494 if blob[6] != (49 as u8) { return 0 } 495 let hi: *i64 = (blob as i64 + 8) as *i64 496 let nv: i64 = hi[0] 497 let nt: i64 = hi[1] 498 let need: i64 = 32 + (nv*8) + ((nv+1)*8) + (nv*8) + (nt*8) + (nt*8) 499 if total < need { return 0 } 500 g[70] = blob as i64 501 g[71] = nv 502 g[72] = nt 503 var off: i64 = 32 504 g[73] = (blob as i64) + off; off = off + nv*8 505 g[74] = (blob as i64) + off; off = off + (nv+1)*8 506 g[75] = (blob as i64) + off; off = off + nv*8 507 g[76] = (blob as i64) + off; off = off + nt*8 508 g[77] = (blob as i64) + off 509 g[78] = 1 510 return 1 511} 512 513// cosine between two PPMI rows (sorted sparse merge), permille 514func ppmi_cos(g: *i64, a: i64, b: i64) -> i64 { 515 let ridx: *i64 = g[74] as *i64 516 let nrm2: *i64 = g[75] as *i64 517 let tctx: *i64 = g[76] as *i64 518 let tval: *i64 = g[77] as *i64 519 var ia: i64 = ridx[a] 520 var ib: i64 = ridx[b] 521 let ea: i64 = ridx[a+1] 522 let eb: i64 = ridx[b+1] 523 var dot: i64 = 0 524 while ia < ea { 525 if ib >= eb { ia = ea } else { 526 if tctx[ia] == tctx[ib] { dot = dot + tval[ia]*tval[ib]; ia = ia + 1; ib = ib + 1 } 527 else { if tctx[ia] < tctx[ib] { ia = ia + 1 } else { ib = ib + 1 } } 528 } 529 } 530 if dot <= 0 { return 0 } 531 let d1: i64 = sem_isqrt(nrm2[a]) 532 let d2: i64 = sem_isqrt(nrm2[b]) 533 if d1 == 0 { return 0 } 534 if d2 == 0 { return 0 } 535 var cv: i64 = (dot*1000)/(d1*d2) 536 if cv > 1000 { cv = 1000 } 537 return cv 538} 539 540// resolve token (buf,off,len) -> PPMI vocab id or -1 541func ppmi_wid(g: *i64, buf: *u8, off: i64, len: i64) -> i64 { 542 let hv: i64 = db_semhash(buf, off, len) 543 return db_bsearch_i64(g[73] as *i64, g[71], hv) 544} 545 546// PPMI-SOFT sentence selection: score(s) = SUM over question content words q of MAX over sentence words w of 547// cos_ppmi(q,w) -- soft lexical alignment ("won" aligns to "defeated"). Identity pairs count 1000 (exact match 548// keeps its full weight). RETRIEVE-THEN-READ scope: when pa>=0, only sentences in paragraphs {pa,pb} are 549// scored (paragraph retrieval stays IDF-lexical -- semantics only refines WITHIN the retrieved scope; global 550// soft-matching inflated distractor hits on 20-para MuSiQue). Returns best sentence or -1. 551func ppmi_best_sentence(g: *i64, pa: i64, pb: i64) -> i64 { 552 let qnb: *u8 = g[28] as *u8 553 let qto: *i64 = g[29] as *i64 554 let qtl: *i64 = g[30] as *i64 555 let qk: *i64 = g[32] as *i64 556 let nb: *u8 = g[20] as *u8 557 let tko: *i64 = g[23] as *i64 558 let tkl: *i64 = g[24] as *i64 559 let tks: *i64 = g[25] as *i64 560 let tkc: *i64 = g[26] as *i64 561 // resolve question ids once 562 let qid: *i64 = g[61] as *i64 // reuse qvec buffer as id scratch 563 var nq: i64 = 0 564 var k: i64 = 0 565 while k < g[31] { 566 if qk[k] == 1 { if nq < 64 { 567 let wid: i64 = ppmi_wid(g, qnb, qto[k], qtl[k]) 568 if wid >= 0 { qid[nq] = wid; nq = nq + 1 } 569 } } 570 k = k + 1 571 } 572 if nq < 1 { return 0-1 } 573 let sid: *i64 = g[62] as *i64 // per-sentence word ids scratch 574 let spp: *i64 = g[18] as *i64 // sentence -> paragraph 575 var best: i64 = 0-1 576 var bs: i64 = 0 577 var s: i64 = 0 578 while s < g[19] { 579 var inscope: i64 = 1 580 if pa >= 0 { inscope = 0; if spp[s] == pa { inscope = 1 } if pb >= 0 { if spp[s] == pb { inscope = 1 } } } 581 if inscope == 1 { 582 var nsids: i64 = 0 583 var j: i64 = 0 584 while j < tkc[s] { 585 if nsids < 250 { 586 let ti: i64 = tks[s] + j 587 let wj: i64 = ppmi_wid(g, nb, tko[ti], tkl[ti]) 588 sid[nsids] = wj 589 nsids = nsids + 1 590 } 591 j = j + 1 592 } 593 var score: i64 = 0 594 var qi: i64 = 0 595 while qi < nq { 596 var mx: i64 = 0 597 var si: i64 = 0 598 while si < nsids { 599 if sid[si] >= 0 { 600 var cv: i64 = 0 601 if sid[si] == qid[qi] { cv = 1000 } else { cv = ppmi_cos(g, qid[qi], sid[si]) } 602 if cv > mx { mx = cv } 603 } 604 si = si + 1 605 } 606 score = score + mx 607 qi = qi + 1 608 } 609 if score > bs { bs = score; best = s } 610 } 611 s = s + 1 612 } 613 return best 614} 615 616// MODE2 core: best sentence by semantic similarity to the question. PPMI-soft when the corpus file is loaded 617// (g[78]==1), SCOPED to the top-2 retrieved paragraphs (retrieve-then-read); else the per-row co-occurrence 618// fallback (the recorded measured-negative baseline). -1 if degenerate. 619func sem_best_sentence(g: *i64, pa: i64, pb: i64) -> i64 { 620 if g[78] == 1 { return ppmi_best_sentence(g, pa, pb) } 621 return sem_best_sentence_perrow(g) 622} 623 624func sem_best_sentence_perrow(g: *i64) -> i64 { 625 let vcnt: i64 = sem_build_vocab(g) 626 if vcnt < 8 { return 0-1 } 627 sem_build_cooc(g) 628 let qvec: *i64 = g[61] as *i64 629 let svec: *i64 = g[62] as *i64 630 let qh: i64 = sem_qvec(g, qvec) 631 if qh < 1 { return 0-1 } 632 var best: i64 = 0-1 633 var bs: i64 = 0 634 var s: i64 = 0 635 while s < g[19] { 636 let sh: i64 = sem_svec(g, s, svec) 637 if sh >= 1 { 638 let c: i64 = sem_cos(qvec, svec, g[65]) 639 if c > bs { bs = c; best = s } 640 } 641 s = s + 1 642 } 643 return best 644} 645// ==================== end R3-LITE ==================== 646 647// ---- MuSiQue (2-4 hop) row loader. -1 EOF, 0 bad, 1 ok. JSON key order: paragraphs, question, 648// question_decomposition (nested q/a -> bracket-skip), answer, answer_aliases, answerable. 649// gt* slots = answer_aliases (fmt=3 max-F1). Skips unanswerable rows. ---- 650func qab_load_musique(g: *i64) -> i64 { 651 if db_find_key(g, "paragraphs" as *u8) < 0 { return 0-1 } 652 db_skip_ws(g) 653 if db_b(g, g[3]) != 91 { return 0 } 654 let arr_open: i64 = g[3] 655 let arr_end: i64 = db_match_bracket(g, arr_open) 656 if arr_end < 0 { return 0 } 657 let ptb: *u8 = g[11] as *u8 658 let pto: *i64 = g[12] as *i64 659 let ptl: *i64 = g[13] as *i64 660 let ctxb: *u8 = g[59] as *u8 661 let stbox: *i64 = g[100] as *i64 // preallocated (was sys_mmap per row -> leak over training) 662 stbox[0]=0; stbox[1]=0 // ns, sb bump 663 var np: i64 = 0 664 var tbump: i64 = 0 665 g[3] = arr_open + 1 666 var live: i64 = 1 667 while live == 1 { 668 if np >= 24 { live = 0 } else { 669 if db_find_key(g, "title" as *u8) < 0 { live = 0 } else { 670 if g[3] >= arr_end { live = 0 } else { 671 let tl: i64 = db_dec_str(g, (ptb as i64 + tbump) as *u8, SEM_MAGIC_4000 - tbump) 672 pto[np] = tbump; ptl[np] = tl; tbump = tbump + tl + 1 673 if db_find_key(g, "paragraph_text" as *u8) < 0 { live = 0 } else { 674 let cl: i64 = db_dec_str(g, ctxb, SEM_MAGIC_200000) 675 qab_split_append(g, ctxb, cl, np, stbox) 676 np = np + 1 677 } 678 } } } 679 } 680 g[14] = np 681 g[19] = stbox[0] 682 g[3] = arr_end + 1 683 // question 684 if db_find_key(g, "question" as *u8) < 0 { return 0 } 685 let ql: i64 = db_dec_str(g, g[4] as *u8, SEM_MAGIC_4000) 686 // skip question_decomposition (nested question/answer) 687 if db_find_key(g, "question_decomposition" as *u8) >= 0 { 688 db_skip_ws(g) 689 if db_b(g, g[3]) == 91 { let qd_end: i64 = db_match_bracket(g, g[3]); if qd_end >= 0 { g[3] = qd_end + 1 } } 690 } 691 // main answer 692 if db_find_key(g, "answer" as *u8) < 0 { return 0 } 693 let al: i64 = db_dec_str(g, g[5] as *u8, SEM_MAGIC_2000) 694 // answer_aliases -> gt* (refs) 695 var nref: i64 = 0 696 if db_find_key(g, "answer_aliases" as *u8) >= 0 { nref = db_parse_str_arr(g, g[7] as *u8, SEM_MAGIC_4000, g[8] as *i64, g[9] as *i64, 20) } 697 if nref < 0 { nref = 0 } 698 g[10] = nref 699 // answerable -> skip unanswerable 700 if db_find_key(g, "answerable" as *u8) >= 0 { db_skip_ws(g); if db_b(g, g[3]) == 102 { return 0 } } // 'f' = false 701 if ql <= 0 { return 0 } 702 if al <= 0 { return 0 } 703 if np < 2 { return 0 } 704 if g[19] <= 0 { return 0 } 705 return 1 706} 707 708// ---- SQuAD row loader. -1 EOF, 0 bad, 1 ok. gt* slots repurposed as ANSWER REFS (fmt=1). ---- 709func qab_load_squad(g: *i64) -> i64 { 710 if db_find_key(g, "context" as *u8) < 0 { return 0-1 } 711 let ctxb: *u8 = g[59] as *u8 712 let cl: i64 = db_dec_str(g, ctxb, SEM_MAGIC_200000) 713 db_find_key(g, "question" as *u8) 714 let ql: i64 = db_dec_str(g, g[4] as *u8, SEM_MAGIC_4000) 715 db_find_key(g, "answers" as *u8) 716 db_find_key(g, "text" as *u8) 717 let nref: i64 = db_parse_str_arr(g, g[7] as *u8, SEM_MAGIC_4000, g[8] as *i64, g[9] as *i64, 20) 718 g[10] = nref 719 // primary gold answer -> a (g[5]) 720 if nref > 0 { 721 let gtb: *u8 = g[7] as *u8 722 let gto: *i64 = g[8] as *i64 723 let gtl: *i64 = g[9] as *i64 724 let a: *u8 = g[5] as *u8 725 var w: i64 = 0 726 while w < gtl[0] { if w < 250 { a[w] = gtb[gto[0]+w] } w = w + 1 } 727 var e: i64 = gtl[0]; if e > 250 { e = 250 } 728 a[e] = (0 as u8) 729 } 730 // one paragraph, empty title, sentences = split(context) 731 g[14] = 1 732 let pto: *i64 = g[12] as *i64 733 let ptl: *i64 = g[13] as *i64 734 let ptb: *u8 = g[11] as *u8 735 pto[0]=0; ptl[0]=0; ptb[0]=(0 as u8) 736 let ns: i64 = qab_split_ctx(g, ctxb, cl) 737 g[19] = ns 738 if ql <= 0 { return 0 } 739 if nref < 1 { return 0 } 740 if ns <= 0 { return 0 } 741 return 1 742} 743 744// ---- HotpotQA distractor row loader (mirrors nx_drbench). -1 EOF, 0 bad, 1 ok. gt*=gold titles. ---- 745func qab_load_hotpot(g: *i64) -> i64 { 746 if db_find_key(g, "question" as *u8) < 0 { return 0-1 } 747 let ql: i64 = db_dec_str(g, g[4] as *u8, SEM_MAGIC_4000) 748 db_find_key(g, "answer" as *u8) 749 let al: i64 = db_dec_str(g, g[5] as *u8, SEM_MAGIC_2000) 750 db_find_key(g, "type" as *u8) 751 db_dec_str(g, g[6] as *u8, 60) 752 db_find_key(g, "supporting_facts" as *u8) 753 db_find_key(g, "title" as *u8) 754 let gtb: *u8 = g[7] as *u8 755 let gto: *i64 = g[8] as *i64 756 let gtl: *i64 = g[9] as *i64 757 let rawgt: i64 = db_parse_str_arr(g, gtb, SEM_MAGIC_4000, gto, gtl, 30) 758 g[10] = 0 759 var gi: i64 = 0 760 while gi < rawgt { 761 var dup: i64 = 0 762 var gj: i64 = 0 763 while gj < g[10] { 764 if gtl[gi] == gtl[gj] { 765 var eq: i64 = 1 766 var w: i64 = 0 767 while w < gtl[gi] { if gtb[gto[gi]+w] != gtb[gto[gj]+w] { eq = 0 } w = w + 1 } 768 if eq == 1 { dup = 1 } 769 } 770 gj = gj + 1 771 } 772 if dup == 0 { let nd: i64 = g[10]; gto[nd] = gto[gi]; gtl[nd] = gtl[gi]; g[10] = nd + 1 } 773 gi = gi + 1 774 } 775 db_find_key(g, "context" as *u8) 776 db_find_key(g, "title" as *u8) 777 let np0: i64 = db_parse_str_arr(g, g[11] as *u8, SEM_MAGIC_8000, g[12] as *i64, g[13] as *i64, 16) 778 g[14] = np0 779 db_find_key(g, "sentences" as *u8) 780 let npara2: i64 = db_parse_sentences(g) 781 if ql <= 0 { return 0 } 782 if al <= 0 { return 0 } 783 if g[14] < 2 { return 0 } 784 if npara2 != g[14] { return 0 } 785 if g[19] <= 0 { return 0 } 786 if g[10] < 1 { return 0 } 787 return 1 788} 789 790func qab_load_row(g: *i64, fmt: i64) -> i64 { 791 if fmt == 1 { return qab_load_squad(g) } 792 if fmt == 3 { return qab_load_musique(g) } 793 return qab_load_hotpot(g) 794} 795 796// F1 (permille): for SQuAD (fmt=1) take MAX over answer refs (SQuAD protocol); else single gold answer. 797func qab_f1(g: *i64, fmt: i64, pred: *u8) -> i64 { 798 var best: i64 = qs_f1(pred, g[5] as *u8) 799 if fmt >= 1 { 800 let gtb: *u8 = g[7] as *u8 801 let gto: *i64 = g[8] as *i64 802 let gtl: *i64 = g[9] as *i64 803 var r: i64 = 0 804 while r < g[10] { 805 let f: i64 = qs_f1(pred, (gtb as i64 + gto[r]) as *u8) 806 if f > best { best = f } 807 r = r + 1 808 } 809 } 810 return best 811} 812func qab_em(g: *i64, fmt: i64, pred: *u8) -> i64 { 813 var best: i64 = qs_em(pred, g[5] as *u8) 814 if fmt >= 1 { 815 let gtb: *u8 = g[7] as *u8 816 let gto: *i64 = g[8] as *i64 817 let gtl: *i64 = g[9] as *i64 818 var r: i64 = 0 819 while r < g[10] { 820 let e: i64 = qs_em(pred, (gtb as i64 + gto[r]) as *u8) 821 if e > best { best = e } 822 r = r + 1 823 } 824 } 825 return best 826} 827 828// ==================== MODE-R: SUPERVISED SPAN READER (SQuAD-baseline lineage) ==================== 829// The 6x-corpus datapoint proved SELECTION is no longer the binding stage -- EXTRACTION (which candidate span 830// to emit) is. This is the trained reader for that stage: a structured (averaged) perceptron over candidate 831// answer spans, exactly the Rajpurkar-2016 SQuAD-baseline recipe (candidate spans + lexical/type features + 832// a learned linear scorer, which got 51 F1 where sliding-window heuristics got 20). Sovereign/integer/no-float. 833// TRAIN on the qab_*_c* corpus rows (DISJOINT from the eval subsets) -> persist reader_v1.bin -> eval MODE-R. 834// Replaces db_extract's fixed pass-order (multiword>noncommon>any) with a learned ranking; the extractor's 835// candidate GENERATION is unchanged, so this isolates the scoring variable. Reports candidate-recall ceiling. 836// ctx: 79 loaded 80 w[NF] 81 featmat[300*NF] 82 meta[300] 84 predR 85 wsum[NF] 86 candtmp 87 avg-count 837// NF=14, featmat stride = NF*8 = 112. TWO principled scoring features were tried against the measured binding 838// stage (oracle 727 vs reader 251) and BOTH failed the linear perceptron: (a) positional proximity-to-anchor 839// (NF16) = NET-NEGATIVE (SQuAD 251->214); (b) corpus-PPMI semantic relatedness cand<->question (NF15) = INERT 840// (perceptron learned weight 0, F1 250~=251). => the gold-vs-distractor signal is NOT a linear function of 841// hand-features; the scoring gap needs LEARNED REPRESENTATIONS = the neural R1 no-float reader into this socket. 842const RD_NF: i64 = 14 843 844func rd_wants_entity(g: *i64) -> i64 { 845 let qnb: *u8 = g[28] as *u8 846 let qto: *i64 = g[29] as *i64 847 let qtl: *i64 = g[30] as *i64 848 var i: i64 = 0 849 while i < g[31] { 850 let o: i64 = qto[i]; let l: i64 = qtl[i] 851 if db_tok_is(qnb, o, l, "who" as *u8) == 1 { return 1 } 852 if db_tok_is(qnb, o, l, "whom" as *u8) == 1 { return 1 } 853 if db_tok_is(qnb, o, l, "whose" as *u8) == 1 { return 1 } 854 if db_tok_is(qnb, o, l, "which" as *u8) == 1 { return 1 } 855 i = i + 1 856 } 857 return 0 858} 859 860func rd_wants_place(g: *i64) -> i64 { 861 let qnb: *u8 = g[28] as *u8 862 let qto: *i64 = g[29] as *i64 863 let qtl: *i64 = g[30] as *i64 864 var i: i64 = 0 865 while i < g[31] { 866 let o: i64 = qto[i]; let l: i64 = qtl[i] 867 if db_tok_is(qnb, o, l, "where" as *u8) == 1 { return 1 } 868 if db_tok_is(qnb, o, l, "city" as *u8) == 1 { return 1 } 869 if db_tok_is(qnb, o, l, "country" as *u8) == 1 { return 1 } 870 if db_tok_is(qnb, o, l, "town" as *u8) == 1 { return 1 } 871 if db_tok_is(qnb, o, l, "state" as *u8) == 1 { return 1 } 872 if db_tok_is(qnb, o, l, "capital" as *u8) == 1 { return 1 } 873 if db_tok_is(qnb, o, l, "located" as *u8) == 1 { return 1 } 874 if db_tok_is(qnb, o, l, "venue" as *u8) == 1 { return 1 } 875 i = i + 1 876 } 877 return 0 878} 879 880// word count of candidate ci 881func rd_candwc(g: *i64, ci: i64) -> i64 { 882 let cnd: *u8 = g[48] as *u8 883 let cno: *i64 = g[49] as *i64 884 let cnl: *i64 = g[50] as *i64 885 let o: i64 = cno[ci]; let l: i64 = cnl[ci] 886 var wc: i64 = 1 887 var i: i64 = 0 888 while i < l { if cnd[o+i] == (32 as u8) { wc = wc + 1 } i = i + 1 } 889 return wc 890} 891 892// featurize candidate ci (db_candidates for its sentence must be current). best_s = the top sentence. 893func rd_feat(g: *i64, ci: i64, s: i64, best_s: i64, feat: *i64) -> i64 { 894 let cnt: *i64 = g[51] as *i64 895 let shit: *i64 = g[39] as *i64 896 let mw: i64 = db_cand_multiword(g, ci) 897 var isnum: i64 = 0 898 if cnt[ci] == 2 { isnum = 1 } 899 if cnt[ci] == 3 { isnum = 1 } 900 var isyr: i64 = 0 901 if cnt[ci] == 3 { isyr = 1 } 902 let ech: i64 = db_cand_is_echo(g, ci) 903 let com: i64 = db_cand_is_common(g, ci) 904 let wn: i64 = db_prefer_numeric(g) 905 let wy: i64 = db_wants_year(g) 906 let we: i64 = rd_wants_entity(g) 907 let wp: i64 = rd_wants_place(g) 908 let wc: i64 = rd_candwc(g, ci) 909 feat[0] = 10 910 var f1v: i64 = shit[s] 911 if f1v > 10 { f1v = 10 } 912 feat[1] = f1v 913 feat[2] = mw * 10 914 feat[3] = isnum * 10 915 feat[4] = isyr * 10 916 feat[5] = ech * 10 917 feat[6] = com * 10 918 var f7v: i64 = wc 919 if f7v > 6 { f7v = 6 } 920 feat[7] = f7v 921 var f8v: i64 = 0 922 if wn == 1 { if isnum == 1 { f8v = 10 } } 923 feat[8] = f8v 924 var f9v: i64 = 0 925 if we == 1 { if mw == 1 { f9v = 10 } } 926 feat[9] = f9v 927 var f10v: i64 = 0 928 if wp == 1 { if mw == 1 { f10v = 10 } } 929 feat[10] = f10v 930 var f11v: i64 = 0 931 if wy == 1 { if isyr == 1 { f11v = 10 } } 932 feat[11] = f11v 933 var f12v: i64 = 0 934 if s == best_s { f12v = 10 } 935 feat[12] = f12v 936 var f13v: i64 = 0 937 if ci == 0 { f13v = 5 } 938 feat[13] = f13v 939 return 0 940} 941 942func rd_score(g: *i64, feat: *i64) -> i64 { 943 let w: *i64 = g[80] as *i64 944 var acc: i64 = 0 945 var k: i64 = 0 946 while k < RD_NF { acc = acc + w[k]*feat[k]; k = k + 1 } 947 return acc 948} 949 950// reconstruct candidate ci string of sentence s into out (re-runs db_candidates for s). returns length. 951// out buffers are 2048B; a candidate can be up to ~2000B (db_candidates bump cap) so BOUND the copy at 250 952// (a real answer span is short; a longer candidate is never the gold and only needs a stable non-overflowing key). 953func rd_candstr(g: *i64, s: i64, ci: i64, out: *u8) -> i64 { 954 let so: *i64 = g[16] as *i64 955 let sl: *i64 = g[17] as *i64 956 db_candidates(g, so[s], sl[s]) 957 if ci >= g[52] { out[0] = (0 as u8); return 0 } 958 let cnd: *u8 = g[48] as *u8 959 let cno: *i64 = g[49] as *i64 960 let cnl: *i64 = g[50] as *i64 961 let o: i64 = cno[ci] 962 var l: i64 = cnl[ci] 963 if l > 250 { l = 250 } 964 var i: i64 = 0 965 while i < l { out[i] = cnd[o+i]; i = i + 1 } 966 out[l] = (0 as u8) 967 return l 968} 969 970// training-side F1 (word-F1 permille, same formula as qs_f1) using PREALLOCATED ctx buffers -- qs_f1 mmaps 7 971// buffers per call, which is fine for eval's few-thousand calls but OOMs at training's millions. Tokenize gold 972// ONCE per row (rd_setgold), then score each candidate with rd_f1 -- zero per-call allocation. 973// slots: 92 gold-norm 93 gold-toff 94 gold-tlen 95 cand-norm 96 cand-toff 97 cand-tlen 98 used 99 gold-ntok 974func rd_setgold(g: *i64, gold: *u8) -> i64 { 975 let gnb: *u8 = g[92] as *u8 976 let gto: *i64 = g[93] as *i64 977 let gtl: *i64 = g[94] as *i64 978 let gl: i64 = qs_norm(gold, gnb) 979 let ng: i64 = qs_tok(gnb, gl, gto, gtl, 256) 980 g[99] = ng 981 return ng 982} 983func rd_f1(g: *i64, cand: *u8) -> i64 { 984 let cnb: *u8 = g[95] as *u8 985 let cto: *i64 = g[96] as *i64 986 let ctl: *i64 = g[97] as *i64 987 let cl: i64 = qs_norm(cand, cnb) 988 let np: i64 = qs_tok(cnb, cl, cto, ctl, 256) 989 let ng: i64 = g[99] 990 if np == 0 { if ng == 0 { return 1000 } return 0 } 991 if ng == 0 { return 0 } 992 let used: *i64 = g[98] as *i64 993 let gnb: *u8 = g[92] as *u8 994 let gto: *i64 = g[93] as *i64 995 let gtl: *i64 = g[94] as *i64 996 let common: i64 = qs_common(cnb, cto, ctl, np, gnb, gto, gtl, ng, used) 997 if common == 0 { return 0 } 998 let prec: i64 = (common*1000)/np 999 let rec: i64 = (common*1000)/ng 1000 return (2*prec*rec)/(prec+rec) 1001} 1002 1003// enumerate all candidates across the top-2 retrieved paragraphs; fill featmat + meta. returns count. 1004func rd_enumerate(g: *i64, top1: i64, top2: i64, best_s: i64) -> i64 { 1005 let so: *i64 = g[16] as *i64 1006 let sl: *i64 = g[17] as *i64 1007 let sp: *i64 = g[18] as *i64 1008 let meta: *i64 = g[82] as *i64 1009 var nc: i64 = 0 1010 var s: i64 = 0 1011 while s < g[19] { 1012 var inscope: i64 = 1 1013 if top1 >= 0 { inscope = 0; if sp[s] == top1 { inscope = 1 } if top2 >= 0 { if sp[s] == top2 { inscope = 1 } } } 1014 if inscope == 1 { 1015 db_candidates(g, so[s], sl[s]) 1016 let ncand: i64 = g[52] 1017 var ci: i64 = 0 1018 while ci < ncand { 1019 if nc < 300 { 1020 let fp: *i64 = ((g[81] as i64) + nc*112) as *i64 1021 rd_feat(g, ci, s, best_s, fp) 1022 meta[nc] = s*SEM_MAGIC_1024 + ci 1023 nc = nc + 1 1024 } 1025 ci = ci + 1 1026 } 1027 } 1028 s = s + 1 1029 } 1030 return nc 1031} 1032 1033// ORACLE ceiling: max F1 over the enumerated candidate set vs gold. If this >> the reader's F1, SCORING has 1034// headroom; if ~= the reader's F1, candidate GENERATION (recall) is the wall. The measure-first probe that 1035// decides which stage to attack next (per the "measure the real path before optimizing" lesson). 1036func rd_oracle(g: *i64, top1: i64, top2: i64, best_s: i64, gold: *u8) -> i64 { 1037 let nc: i64 = rd_enumerate(g, top1, top2, best_s) 1038 if nc == 0 { return 0 } 1039 rd_setgold(g, gold) 1040 let meta: *i64 = g[82] as *i64 1041 let tmp: *u8 = g[86] as *u8 1042 var best: i64 = 0 1043 var i: i64 = 0 1044 while i < nc { 1045 let mv: i64 = meta[i] 1046 let s: i64 = mv / SEM_MAGIC_1024 1047 let ci: i64 = mv % SEM_MAGIC_1024 1048 rd_candstr(g, s, ci, tmp) 1049 let f: i64 = rd_f1(g, tmp) 1050 if f > best { best = f } 1051 i = i + 1 1052 } 1053 return best 1054} 1055 1056// inference: pick best-scored candidate into pred. 1 ok, 0 = no candidates (caller falls back). 1057func rd_pick(g: *i64, top1: i64, top2: i64, best_s: i64, pred: *u8) -> i64 { 1058 let nc: i64 = rd_enumerate(g, top1, top2, best_s) 1059 if nc == 0 { return 0 } 1060 var best: i64 = 0-1 1061 var bs: i64 = 0-SEM_MAGIC_2000000000 1062 var i: i64 = 0 1063 while i < nc { 1064 let sc: i64 = rd_score(g, ((g[81] as i64) + i*112) as *i64) 1065 if sc > bs { bs = sc; best = i } 1066 i = i + 1 1067 } 1068 if best < 0 { return 0 } 1069 let meta: *i64 = g[82] as *i64 1070 let mv: i64 = meta[best] 1071 let s: i64 = mv / SEM_MAGIC_1024 1072 let ci: i64 = mv % SEM_MAGIC_1024 1073 let n: i64 = rd_candstr(g, s, ci, pred) 1074 if n <= 0 { return 0 } 1075 return 1 1076} 1077 1078// one training row: label candidates by F1 vs gold; structured-perceptron update. returns 1 if gold recoverable. 1079func rd_train_row(g: *i64, gold: *u8, top1: i64, top2: i64, best_s: i64) -> i64 { 1080 let nc: i64 = rd_enumerate(g, top1, top2, best_s) 1081 if nc == 0 { return 0 } 1082 let meta: *i64 = g[82] as *i64 1083 let tmp: *u8 = g[86] as *u8 1084 rd_setgold(g, gold) // tokenize gold ONCE (rd_f1 reuses ctx buffers, no leak) 1085 var goldi: i64 = 0-1 1086 var goldf: i64 = 0 1087 var i: i64 = 0 1088 while i < nc { 1089 let mv: i64 = meta[i] 1090 let s: i64 = mv / SEM_MAGIC_1024 1091 let ci: i64 = mv % SEM_MAGIC_1024 1092 rd_candstr(g, s, ci, tmp) 1093 let f: i64 = rd_f1(g, tmp) 1094 if f > goldf { goldf = f; goldi = i } 1095 i = i + 1 1096 } 1097 if dbg == 1 { db_w(" [rr] labeled goldi="); db_n(goldi); db_w(" goldf="); db_n(goldf); db_w("\n" as *u8) } 1098 if goldf < 500 { return 0 } // gold not in candidate set -> unlearnable (recall miss) 1099 var predi: i64 = 0-1 1100 var bs: i64 = 0-SEM_MAGIC_2000000000 1101 i = 0 1102 while i < nc { 1103 let sc: i64 = rd_score(g, ((g[81] as i64) + i*112) as *i64) 1104 if sc > bs { bs = sc; predi = i } 1105 i = i + 1 1106 } 1107 if predi != goldi { 1108 let w: *i64 = g[80] as *i64 1109 let fg: *i64 = ((g[81] as i64) + goldi*112) as *i64 1110 let fp: *i64 = ((g[81] as i64) + predi*112) as *i64 1111 var k: i64 = 0 1112 while k < RD_NF { w[k] = w[k] + fg[k] - fp[k]; k = k + 1 } 1113 } 1114 return 1 1115} 1116 1117// walk one corpus file, train per row (averaged into wsum). returns [trained, recoverable] via g[88]/g[89] add. 1118func rd_train_file(g: *i64, path: *u8, fmt: i64) -> i64 { 1119 let total: i64 = db_read_raw(g, path, SEM_MAGIC_16777216) 1120 if total <= 0 { return 0 } 1121 g[2] = db_body_start(g, total) 1122 g[1] = total - g[2] 1123 g[3] = 0 1124 var trained: i64 = 0 1125 var live: i64 = 1 1126 while live == 1 { 1127 let rc: i64 = qab_load_row(g, fmt) 1128 if rc < 0 { live = 0 } else { 1129 if rc == 1 { 1130 db_norm_row(g) 1131 db_score_row(g) 1132 let top1: i64 = db_top_para(g, 0-1) 1133 let top2: i64 = db_top_para(g, top1) 1134 let s0: i64 = db_best_sentence(g) 1135 let yn: i64 = db_is_yesno(g) 1136 g[89] = g[89] + 1 // rows seen (non-degenerate) 1137 if yn == 0 { 1138 let did: i64 = rd_train_row(g, g[5] as *u8, top1, top2, s0) 1139 if did == 1 { 1140 trained = trained + 1 1141 g[88] = g[88] + 1 // recoverable-gold rows 1142 let w: *i64 = g[80] as *i64 1143 let ws: *i64 = g[85] as *i64 1144 var k: i64 = 0 1145 while k < RD_NF { ws[k] = ws[k] + w[k]; k = k + 1 } 1146 g[87] = g[87] + 1 1147 } 1148 } 1149 } 1150 } 1151 } 1152 return trained 1153} 1154 1155func rd_persist(g: *i64) -> i64 { 1156 let hdr: *u8 = sys_mmap(256) 1157 hdr[0]=78 as u8; hdr[1]=88 as u8; hdr[2]=82 as u8; hdr[3]=68 as u8; hdr[4]=82 as u8; hdr[5]=49 as u8; hdr[6]=0 as u8; hdr[7]=0 as u8 1158 let hi: *i64 = (hdr as i64 + 8) as *i64 1159 hi[0] = RD_NF 1160 let wb: *i64 = (hdr as i64 + 16) as *i64 1161 let w: *i64 = g[80] as *i64 1162 var k: i64 = 0 1163 while k < RD_NF { wb[k] = w[k]; k = k + 1 } 1164 let fd: i64 = sys_openat_wr("knowledge/index/reader_v1.bin" as *u8, 0x1a4) 1165 if fd < 0 { return 1 } 1166 var off: i64 = 0 1167 let tot: i64 = 16 + RD_NF*8 1168 while off < tot { let ww: i64 = sys_write(fd, (hdr as i64 + off) as *u8, tot - off); if ww <= 0 { off = tot } else { off = off + ww } } 1169 sys_close(fd) 1170 return 0 1171} 1172 1173// train the reader on the disjoint corpus chunks (E averaged-perceptron epochs), persist, load into g[80]. 1174func rd_train(g: *i64) -> i64 { 1175 let w: *i64 = g[80] as *i64 1176 let ws: *i64 = g[85] as *i64 1177 var k: i64 = 0 1178 while k < RD_NF { w[k] = 0; ws[k] = 0; k = k + 1 } 1179 g[87] = 0; g[88] = 0; g[89] = 0 1180 let E: i64 = 6 1181 var ep: i64 = 0 1182 while ep < E { 1183 rd_train_file(g, "knowledge/fetched/qab_squad_c0.raw" as *u8, 1) 1184 rd_train_file(g, "knowledge/fetched/qab_squad_c1.raw" as *u8, 1) 1185 rd_train_file(g, "knowledge/fetched/qab_squad_c2.raw" as *u8, 1) 1186 rd_train_file(g, "knowledge/fetched/qab_hotpot_c0.raw" as *u8, 0) 1187 rd_train_file(g, "knowledge/fetched/qab_hotpot_c1.raw" as *u8, 0) 1188 rd_train_file(g, "knowledge/fetched/qab_hotpot_c2.raw" as *u8, 0) 1189 rd_train_file(g, "knowledge/fetched/qab_musique_c0.raw" as *u8, 3) 1190 rd_train_file(g, "knowledge/fetched/qab_musique_c1.raw" as *u8, 3) 1191 ep = ep + 1 1192 } 1193 if g[87] > 0 { k = 0; while k < RD_NF { w[k] = ws[k] / g[87]; k = k + 1 } } 1194 var recall: i64 = 0 1195 if g[89] > 0 { recall = (g[88] * 1000) / g[89] } 1196 db_w(" reader trained: "); db_n(g[88]); db_w(" recoverable-gold rows / "); db_n(g[89]); db_w(" seen (candidate-recall="); db_n(recall); db_w("permille, over E="); db_n(E); db_w(" epochs)\n" as *u8) 1197 rd_persist(g) 1198 g[79] = 1 1199 return 0 1200} 1201 1202func rd_load(g: *i64) -> i64 { 1203 g[79] = 0 1204 let fd: i64 = sys_openat_rd("knowledge/index/reader_v1.bin" as *u8) 1205 if fd < 0 { return 0 } 1206 let buf: *u8 = sys_mmap(256) 1207 var got: i64 = 0 1208 var r: i64 = 1 1209 while r > 0 { if got >= 128 { r = 0 } else { r = sys_read(fd, (buf as i64 + got) as *u8, 128 - got); if r > 0 { got = got + r } } } 1210 sys_close(fd) 1211 if got < 16 { return 0 } 1212 if buf[0] != (78 as u8) { return 0 } 1213 if buf[5] != (49 as u8) { return 0 } 1214 let hi: *i64 = (buf as i64 + 8) as *i64 1215 if hi[0] != RD_NF { return 0 } 1216 let wb: *i64 = (buf as i64 + 16) as *i64 1217 let w: *i64 = g[80] as *i64 1218 var k: i64 = 0 1219 while k < RD_NF { w[k] = wb[k]; k = k + 1 } 1220 g[79] = 1 1221 return 1 1222} 1223 1224// DUMP_NF = 14 hand-features + 3 corpus-PPMI EMBEDDING features (semantic relatedness the hand-features lack). 1225// The rung-2 finding was that hand-features are the ceiling -> test whether embedding features break it. Kept 1226// in the DUMP only (not rd_feat), so the main perceptron reader stays at RD_NF=14/251 unchanged. 1227const DUMP_NF: i64 = 17 1228 1229// ---- TRAINED dense embeddings (embed_v1.bin from nx_embed_train): Q10 integer E[nv*DIM]; integer cosine = 1230// no-float inference. Loaded alongside semppmi (same vocab ids from ppmi vh). slots: 115 E 116 DIM 117 flag 1231func embed_load(g: *i64) -> i64 { 1232 g[117] = 0 1233 let fd: i64 = sys_openat_rd("knowledge/index/embed_v1.bin" as *u8) 1234 if fd < 0 { return 0 } 1235 let hb: *u8 = sys_mmap(64) 1236 var hg: i64 = 0 1237 var hr: i64 = 1 1238 while hr > 0 { if hg >= 24 { hr = 0 } else { hr = sys_read(fd, (hb as i64 + hg) as *u8, 24 - hg); if hr > 0 { hg = hg + hr } } } 1239 if hg < 24 { sys_close(fd); return 0 } 1240 if hb[0] != (78 as u8) { sys_close(fd); return 0 } // 'N' (NXEMB1) 1241 let hi: *i64 = (hb as i64 + 8) as *i64 1242 let nv: i64 = hi[0] 1243 let dim: i64 = hi[1] 1244 let need: i64 = nv * dim * 8 1245 if need <= 0 { sys_close(fd); return 0 } 1246 if need > SEM_MAGIC_402653184 { sys_close(fd); return 0 } // 384MB sanity 1247 let buf: *u8 = sys_mmap(need + SEM_MAGIC_4096) 1248 var got: i64 = 0 1249 var r: i64 = 1 1250 while r > 0 { let left: i64 = need - got; if left <= 0 { r = 0 } else { r = sys_read(fd, (buf as i64 + got) as *u8, left); if r > 0 { got = got + r } } } 1251 sys_close(fd) 1252 if got < need { return 0 } 1253 g[115] = buf as i64 1254 g[116] = dim 1255 g[117] = 1 1256 return 1 1257} 1258 1259// integer cosine (permille) of trained dense embedding rows a,b (Q10 ints; scale cancels in cosine). 1260func dense_cos_int(g: *i64, a: i64, b: i64) -> i64 { 1261 let E: *i64 = g[115] as *i64 1262 let dim: i64 = g[116] 1263 var dot: i64 = 0 1264 var na: i64 = 0 1265 var nb: i64 = 0 1266 var k: i64 = 0 1267 let ba: i64 = a * dim 1268 let bb: i64 = b * dim 1269 while k < dim { 1270 let ea: i64 = E[ba+k] 1271 let eb: i64 = E[bb+k] 1272 dot = dot + ea*eb 1273 na = na + ea*ea 1274 nb = nb + eb*eb 1275 k = k + 1 1276 } 1277 if dot <= 0 { return 0 } 1278 let d1: i64 = sem_isqrt(na) 1279 let d2: i64 = sem_isqrt(nb) 1280 if d1 == 0 { return 0 } 1281 if d2 == 0 { return 0 } 1282 var cv: i64 = (dot*1000)/(d1*d2) 1283 if cv > 1000 { cv = 1000 } 1284 return cv 1285} 1286 1287// resolve the question's content-word PPMI ids into g[108] (count g[109]) once per row. 1288func rd_setqppmi(g: *i64) -> i64 { 1289 g[109] = 0 1290 if g[78] != 1 { return 0 } 1291 let qnb: *u8 = g[28] as *u8 1292 let qto: *i64 = g[29] as *i64 1293 let qtl: *i64 = g[30] as *i64 1294 let qk: *i64 = g[32] as *i64 1295 let qid: *i64 = g[108] as *i64 1296 var n: i64 = 0 1297 var k: i64 = 0 1298 while k < g[31] { 1299 if qk[k] == 1 { if n < 64 { let wid: i64 = ppmi_wid(g, qnb, qto[k], qtl[k]); if wid >= 0 { qid[n] = wid; n = n + 1 } } } 1300 k = k + 1 1301 } 1302 g[109] = n 1303 return n 1304} 1305 1306// 3 corpus-PPMI embedding features for a candidate STRING vs the question: out[0]=max token-alignment, 1307// out[1]=mean token-alignment, out[2]=#candidate tokens strongly related to a q-word. All ~0..10. 1308func rd_emb_feats(g: *i64, candstr: *u8, out: *i64) -> i64 { 1309 out[0] = 0; out[1] = 0; out[2] = 0 1310 if g[78] != 1 { return 0 } 1311 if g[109] == 0 { return 0 } 1312 let nrm: *u8 = g[111] as *u8 1313 let cto: *i64 = g[112] as *i64 1314 let ctl: *i64 = g[113] as *i64 1315 let nl: i64 = qs_norm(candstr, nrm) 1316 let nt: i64 = qs_tok(nrm, nl, cto, ctl, 16) 1317 let qid: *i64 = g[108] as *i64 1318 var best: i64 = 0 1319 var sum: i64 = 0 1320 var ntok: i64 = 0 1321 var cnt: i64 = 0 1322 var t: i64 = 0 1323 while t < nt { 1324 let cid: i64 = ppmi_wid(g, nrm, cto[t], ctl[t]) 1325 if cid >= 0 { 1326 var tb: i64 = 0 1327 var q: i64 = 0 1328 while q < g[109] { 1329 var c: i64 = 0 1330 if g[117] == 1 { c = dense_cos_int(g, cid, qid[q]) } else { c = ppmi_cos(g, cid, qid[q]) } 1331 if c > tb { tb = c } 1332 q = q + 1 1333 } 1334 if tb > best { best = tb } 1335 sum = sum + tb; ntok = ntok + 1 1336 if tb > 300 { cnt = cnt + 1 } 1337 } 1338 t = t + 1 1339 } 1340 out[0] = best / 100 1341 if ntok > 0 { out[1] = (sum / ntok) / 100 } 1342 out[2] = cnt 1343 if out[2] > 10 { out[2] = 10 } 1344 return 0 1345} 1346 1347// ---- FULL-VECTOR embedding features (the R1 crux): instead of collapsing to a scalar cosine, feed the MLP 1348// the element-wise product of the L2-normalized question and candidate embedding vectors (DIM values) so 1349// it learns a per-dimension weighted metric. slots: 118 q_emb_unit 119 cand_unit scratch ---- 1350func rd_setqemb(g: *i64) -> i64 { 1351 let dim: i64 = g[116] 1352 let qu: *i64 = g[118] as *i64 1353 var d: i64 = 0 1354 while d < dim { qu[d] = 0; d = d + 1 } 1355 if g[117] != 1 { return 0 } 1356 if g[109] == 0 { return 0 } 1357 let qid: *i64 = g[108] as *i64 1358 let E: *i64 = g[115] as *i64 1359 var n: i64 = 0 1360 while n < g[109] { 1361 let id: i64 = qid[n] 1362 d = 0 1363 while d < dim { qu[d] = qu[d] + E[id*dim+d]; d = d + 1 } 1364 n = n + 1 1365 } 1366 var nrm: i64 = 0 1367 d = 0 1368 while d < dim { nrm = nrm + qu[d]*qu[d]; d = d + 1 } 1369 let rt: i64 = sem_isqrt(nrm) 1370 if rt == 0 { return 0 } 1371 d = 0 1372 while d < dim { qu[d] = qu[d]*SEM_MAGIC_1024/rt; d = d + 1 } // Q10 unit vector 1373 return 1 1374} 1375 1376// element-wise product of q_emb_unit and cand_emb_unit, each component scaled to ~0..10. out must hold DIM. 1377func rd_emb_vec(g: *i64, candstr: *u8, out: *i64) -> i64 { 1378 let dim: i64 = g[116] 1379 var d: i64 = 0 1380 while d < dim { out[d] = 5; d = d + 1 } // neutral default 1381 if g[117] != 1 { return 0 } 1382 if g[109] == 0 { return 0 } 1383 let nrm2: *u8 = g[111] as *u8 1384 let cto: *i64 = g[112] as *i64 1385 let ctl: *i64 = g[113] as *i64 1386 let cu: *i64 = g[119] as *i64 1387 d = 0 1388 while d < dim { cu[d] = 0; d = d + 1 } 1389 let nl: i64 = qs_norm(candstr, nrm2) 1390 let nt: i64 = qs_tok(nrm2, nl, cto, ctl, 16) 1391 let E: *i64 = g[115] as *i64 1392 var nseen: i64 = 0 1393 var t: i64 = 0 1394 while t < nt { 1395 let cid: i64 = ppmi_wid(g, nrm2, cto[t], ctl[t]) 1396 if cid >= 0 { d = 0; while d < dim { cu[d] = cu[d] + E[cid*dim+d]; d = d + 1 } nseen = nseen + 1 } 1397 t = t + 1 1398 } 1399 if nseen == 0 { return 0 } 1400 var cn: i64 = 0 1401 d = 0 1402 while d < dim { cn = cn + cu[d]*cu[d]; d = d + 1 } 1403 let crt: i64 = sem_isqrt(cn) 1404 if crt == 0 { return 0 } 1405 d = 0 1406 while d < dim { cu[d] = cu[d]*SEM_MAGIC_1024/crt; d = d + 1 } 1407 let qu: *i64 = g[118] as *i64 1408 d = 0 1409 while d < dim { 1410 let p: i64 = qu[d]*cu[d]/SEM_MAGIC_1024 // Q10 product, ~+-SEM_MAGIC_1024 1411 var f: i64 = p/20 + 5 // scale to ~0..10 (matches hand-feature range) 1412 if f < 0 { f = 0 } 1413 if f > 10 { f = 10 } 1414 out[d] = f 1415 d = d + 1 1416 } 1417 return 1 1418} 1419 1420// ---- TEXT DUMP (R3 neural reader): export per-row RAW (question, context, gold-answer) strings so the 1421// offline neural trainer (nx_reader_squad_gate on nx_nofloat_autograd) does its own tokenization + gold 1422// span matching. File: knowledge/index/reader_rows.bin = [magic "NXRR1"] then per row: 1423// [qlen i64][q bytes][clen i64][ctx bytes = prose sentences space-joined][alen i64][gold bytes]. 1424// Selected by g[131]=1 (dumptext mode 'dt'); the feats path is untouched when the flag is 0. ---- 1425func rd_dump_text_row(g: *i64, gold: *u8, fd: i64) -> i64 { 1426 let q: *u8 = g[4] as *u8 1427 let qlen: i64 = qa_slen(q) 1428 let alen: i64 = qa_slen(gold) 1429 if qlen < 4 { return 0 } 1430 if alen < 1 { return 0 } 1431 if g[19] <= 0 { return 0 } 1432 let sb: *u8 = g[15] as *u8 1433 let so: *i64 = g[16] as *i64 1434 var clen: i64 = 0 1435 var s: i64 = 0 1436 while s < g[19] { let sl: i64 = qa_slen((sb as i64 + so[s]) as *u8); clen = clen + sl + 1; s = s + 1 } 1437 if clen < 8 { return 0 } 1438 let hb: *i64 = g[86] as *i64 1439 hb[0] = qlen 1440 sys_write(fd, g[86] as *u8, 8) 1441 sys_write(fd, q, qlen) 1442 hb[0] = clen 1443 sys_write(fd, g[86] as *u8, 8) 1444 s = 0 1445 while s < g[19] { 1446 let sp0: *u8 = (sb as i64 + so[s]) as *u8 1447 let sl: i64 = qa_slen(sp0) 1448 sys_write(fd, sp0, sl) 1449 let sc: *u8 = g[86] as *u8 1450 sc[0] = 32 as u8 1451 sys_write(fd, sc, 1) 1452 s = s + 1 1453 } 1454 hb[0] = alen 1455 sys_write(fd, g[86] as *u8, 8) 1456 sys_write(fd, gold, alen) 1457 return 1 1458} 1459 1460func rd_dump_texts(g: *i64) -> i64 { 1461 let fd: i64 = sys_openat_wr("knowledge/index/reader_rows.bin" as *u8, 0x1a4) 1462 if fd < 0 { db_w("dumptext: cannot open reader_rows.bin\n" as *u8); return 1 } 1463 let mgb: *u8 = g[86] as *u8 1464 mgb[0]=78 as u8; mgb[1]=88 as u8; mgb[2]=82 as u8; mgb[3]=82 as u8; mgb[4]=49 as u8; mgb[5]=0 as u8; mgb[6]=0 as u8; mgb[7]=0 as u8 1465 sys_write(fd, g[86] as *u8, 8) 1466 g[88] = 0 1467 g[131] = 1 1468 rd_dump_file(g, "knowledge/fetched/qab_squad_c0.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1469 rd_dump_file(g, "knowledge/fetched/qab_squad_c1.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1470 g[131] = 0 1471 sys_close(fd) 1472 db_w("dumptext: wrote "); db_n(g[88]); db_w(" SQuAD rows (raw q/ctx/gold text) -> knowledge/index/reader_rows.bin\n" as *u8) 1473 return 0 1474} 1475 1476// XL text dump ('dx'): ALL banked SQuAD chunks -> reader_rows_xl.bin. SEPARATE FILE by design: the in-flight 1477// f32 run's checkpoint is keyed to reader_rows.bin's vocab (nw) -- overwriting it mid-arc would invalidate the 1478// checkpoint on the next watchdog relaunch. The XL set is the R3f data-scale lever, staged in advance. 1479func rd_dump_texts_xl(g: *i64) -> i64 { 1480 let fd: i64 = sys_openat_wr("knowledge/index/reader_rows_xl.bin" as *u8, 0x1a4) 1481 if fd < 0 { db_w("dumptext-xl: cannot open reader_rows_xl.bin\n" as *u8); return 1 } 1482 let mgb: *u8 = g[86] as *u8 1483 mgb[0]=78 as u8; mgb[1]=88 as u8; mgb[2]=82 as u8; mgb[3]=82 as u8; mgb[4]=49 as u8; mgb[5]=0 as u8; mgb[6]=0 as u8; mgb[7]=0 as u8 1484 sys_write(fd, g[86] as *u8, 8) 1485 g[88] = 0 1486 g[131] = 1 1487 rd_dump_file(g, "knowledge/fetched/qab_squad_c0.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1488 rd_dump_file(g, "knowledge/fetched/qab_squad_c1.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1489 rd_dump_file(g, "knowledge/fetched/qab_squad_c2.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1490 rd_dump_file(g, "knowledge/fetched/qab_squad_c3.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1491 rd_dump_file(g, "knowledge/fetched/qab_squad_c4.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1492 rd_dump_file(g, "knowledge/fetched/qab_squad_c5.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1493 rd_dump_file(g, "knowledge/fetched/qab_squad_c6.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1494 rd_dump_file(g, "knowledge/fetched/qab_squad_c7.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1495 rd_dump_file(g, "knowledge/fetched/qab_squad_c8.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1496 rd_dump_file(g, "knowledge/fetched/qab_squad_big.raw" as *u8, 1, fd, SEM_MAGIC_10000) 1497 g[131] = 0 1498 sys_close(fd) 1499 db_w("dumptext-xl: wrote "); db_n(g[88]); db_w(" SQuAD rows -> knowledge/index/reader_rows_xl.bin\n" as *u8) 1500 return 0 1501} 1502 1503// ---- feature DUMP: export per-row candidate features + gold index for OFFLINE MLP training (nx_reader_mlp_train 1504// trains the neural reader on nx_autograd; nx_qabench stays integer/no-float). File: knowledge/index/ 1505// reader_feats.bin = [magic "NXRF1", DUMP_NF] then per row: [nc, goldi, feat[nc*DUMP_NF]] (14 hand + 3 emb). ---- 1506func rd_dump_row(g: *i64, gold: *u8, top1: i64, top2: i64, best_s: i64, fd: i64) -> i64 { 1507 if g[131] == 1 { return rd_dump_text_row(g, gold, fd) } 1508 let nc: i64 = rd_enumerate(g, top1, top2, best_s) 1509 if nc < 2 { return 0 } 1510 if nc > 64 { return 0 } 1511 rd_setgold(g, gold) 1512 let meta: *i64 = g[82] as *i64 1513 let tmp: *u8 = g[86] as *u8 1514 var goldi: i64 = 0-1 1515 var goldf: i64 = 0 1516 var i: i64 = 0 1517 while i < nc { 1518 let mv: i64 = meta[i] 1519 let s: i64 = mv / SEM_MAGIC_1024 1520 let ci: i64 = mv % SEM_MAGIC_1024 1521 rd_candstr(g, s, ci, tmp) 1522 let f: i64 = rd_f1(g, tmp) 1523 if f > goldf { goldf = f; goldi = i } 1524 i = i + 1 1525 } 1526 if goldf < 500 { return 0 } // gold not recoverable -> skip 1527 rd_setqppmi(g) // question PPMI ids 1528 let vecmode: i64 = g[117] // 1 = dense embeddings loaded -> FULL-VECTOR features 1529 if vecmode == 1 { rd_setqemb(g) } // q_emb_unit once per row 1530 let hb: *i64 = g[86] as *i64 1531 hb[0] = nc; hb[1] = goldi 1532 sys_write(fd, g[86] as *u8, 16) 1533 let emb: *i64 = g[114] as *i64 // 3-scalar buffer (sparse mode) 1534 let vbuf: *i64 = g[121] as *i64 // DIM-vector buffer (vector mode) 1535 var wc: i64 = 0 1536 while wc < nc { 1537 sys_write(fd, (g[81] as i64 + wc*RD_NF*8) as *u8, RD_NF * 8) // 14 hand-features for candidate wc 1538 let mv: i64 = meta[wc] 1539 let s: i64 = mv / SEM_MAGIC_1024 1540 let ci: i64 = mv % SEM_MAGIC_1024 1541 rd_candstr(g, s, ci, g[110] as *u8) 1542 if vecmode == 1 { rd_emb_vec(g, g[110] as *u8, vbuf); sys_write(fd, g[121] as *u8, g[116] * 8) } // DIM vector feats 1543 else { rd_emb_feats(g, g[110] as *u8, emb); sys_write(fd, g[114] as *u8, 24) } // 3 scalar feats 1544 wc = wc + 1 1545 } 1546 return 1 1547} 1548 1549func rd_dump_file(g: *i64, path: *u8, fmt: i64, fd: i64, cap: i64) -> i64 { 1550 let total: i64 = db_read_raw(g, path, SEM_MAGIC_16777216) 1551 if total <= 0 { return 0 } 1552 g[2] = db_body_start(g, total) 1553 g[1] = total - g[2] 1554 g[3] = 0 1555 let start88: i64 = g[88] // debt eaten SEM_MAGIC_2026-07-10: cap is now PER-FILE. It was compared 1556 var live: i64 = 1 // against the GLOBAL row counter, so a multi-file dump silently 1557 while live == 1 { // truncated at `cap` TOTAL rows (the XL dump lost half its data). 1558 if g[88] - start88 >= cap { live = 0 } else { 1559 let rc: i64 = qab_load_row(g, fmt) 1560 if rc < 0 { live = 0 } else { 1561 if rc == 1 { 1562 db_norm_row(g) 1563 db_score_row(g) 1564 let top1: i64 = db_top_para(g, 0-1) 1565 let top2: i64 = db_top_para(g, top1) 1566 let s0: i64 = db_best_sentence(g) 1567 let yn: i64 = db_is_yesno(g) 1568 if yn == 0 { if rd_dump_row(g, g[5] as *u8, top1, top2, s0, fd) == 1 { g[88] = g[88] + 1 } } 1569 } 1570 } 1571 } 1572 } 1573 return g[88] 1574} 1575 1576func rd_dump_feats(g: *i64) -> i64 { 1577 let fd: i64 = sys_openat_wr("knowledge/index/reader_feats.bin" as *u8, 0x1a4) 1578 if fd < 0 { db_w("dumpfeats: cannot open reader_feats.bin\n" as *u8); return 1 } 1579 let mgb: *u8 = g[86] as *u8 1580 mgb[0]=78 as u8; mgb[1]=88 as u8; mgb[2]=82 as u8; mgb[3]=70 as u8; mgb[4]=49 as u8; mgb[5]=0 as u8; mgb[6]=0 as u8; mgb[7]=0 as u8 1581 let mg: *i64 = g[86] as *i64 1582 var nf: i64 = DUMP_NF // sparse: 14 hand + 3 scalar embed 1583 if g[117] == 1 { nf = RD_NF + g[116] } // vector mode: 14 hand + DIM full-vector product 1584 mg[1] = nf 1585 db_w("dumpfeats: feature count nf="); db_n(nf); db_w("\n" as *u8) 1586 sys_write(fd, g[86] as *u8, 16) 1587 g[88] = 0 1588 let CAP: i64 = SEM_MAGIC_2500 1589 rd_dump_file(g, "knowledge/fetched/qab_squad_c0.raw" as *u8, 1, fd, CAP) 1590 rd_dump_file(g, "knowledge/fetched/qab_squad_c1.raw" as *u8, 1, fd, CAP) 1591 rd_dump_file(g, "knowledge/fetched/qab_hotpot_c0.raw" as *u8, 0, fd, CAP) 1592 rd_dump_file(g, "knowledge/fetched/qab_hotpot_c1.raw" as *u8, 0, fd, CAP) 1593 sys_close(fd) 1594 db_w("dumpfeats: wrote "); db_n(g[88]); db_w(" rows (DUMP_NF="); db_n(DUMP_NF); db_w(", incl 3 PPMI-embed) -> knowledge/index/reader_feats.bin\n" as *u8) 1595 return 0 1596} 1597// ==================== end MODE-R ==================== 1598 1599// run one benchmark end-to-end; write [rows, f1_single, f1_multi, em] into res[base..base+3]. returns rows. 1600func qab_run(g: *i64, path: *u8, fmt: i64, label: *u8, res: *i64, base: i64) -> i64 { 1601 let total: i64 = db_read_raw(g, path, SEM_MAGIC_16777216) 1602 if total == 0-2 { db_w(" "); db_w(label); db_w(": [file EXCEEDS 16MB raw buffer -- raise m0, skipped]\n" as *u8); res[base]=0; return 0 } 1603 if total <= 0 { db_w(" "); db_w(label); db_w(": [absent -- fetch first, skipped]\n" as *u8); res[base]=0; return 0 } 1604 g[2] = db_body_start(g, total) 1605 g[1] = total - g[2] 1606 let p0a: *u8 = g[54] as *u8 1607 let gaa: *u8 = g[56] as *u8 1608 1609 var rows: i64 = 0 1610 var sum_f0: i64 = 0; var sum_f1: i64 = 0; var sum_f2: i64 = 0; var sum_fR: i64 = 0; var sum_orc: i64 = 0; var em0: i64 = 0 1611 g[3] = 0 1612 var live: i64 = 1 1613 let DBGL: i64 = 0 1614 var QLIMIT: i64 = 0 // optional row cap (knowledge/index/qab_limit.txt) -> bounded on-box runs 1615 let lfd: i64 = sys_openat_rd("knowledge/index/qab_limit.txt" as *u8) 1616 if lfd >= 0 { 1617 let lb: *u8 = sys_mmap(32) 1618 let lrn: i64 = sys_read(lfd, lb, 31) 1619 sys_close(lfd) 1620 var lci: i64 = 0 1621 while lci < lrn { if lb[lci]>=(48 as u8) { if lb[lci]<=(57 as u8) { QLIMIT = QLIMIT*10 + (lb[lci] as i64 - 48) } } lci=lci+1 } 1622 } 1623 while live == 1 { 1624 let rc: i64 = qab_load_row(g, fmt) 1625 if DBGL == 1 { if fmt == 3 { db_w("MQ load rows="); db_n(rows); db_w(" rc="); db_n(rc); db_w(" np="); db_n(g[14]); db_w(" ns="); db_n(g[19]); db_w(" nqt="); db_n(g[31]); db_w("\n" as *u8) } } 1626 if rc < 0 { live = 0 } else { 1627 if rc == 1 { 1628 db_norm_row(g) 1629 if DBGL == 1 { if fmt == 3 { db_w(" MQ normed\n" as *u8) } } 1630 db_score_row(g) 1631 if DBGL == 1 { if fmt == 3 { db_w(" MQ scored\n" as *u8) } } 1632 let top1: i64 = db_top_para(g, 0-1) 1633 let top2: i64 = db_top_para(g, top1) 1634 let s0: i64 = db_best_sentence(g) 1635 let yn: i64 = db_is_yesno(g) 1636 let wantnum0: i64 = db_prefer_numeric(g) 1637 let pd0: *u8 = (p0a as i64 + rows*256) as *u8 1638 var qw0: i64 = 0 1639 if g[132] == 1 { if qwx_ready() == 1 { if s0 >= 0 { qw0 = qwx_extract(g, s0, pd0) } } } // R5: Qwen reads context centered on best sentence s0 (mode0/SQuAD = 251 rung) 1640 if qw0 == 0 { 1641 if yn == 1 { db_setpred(pd0, "yes" as *u8, 3) } else { 1642 var got0: i64 = 0 1643 if wantnum0 == 1 { got0 = db_sweep_numeric(g, top1, top2, pd0) } 1644 if got0 == 0 { if s0 >= 0 { db_extract(g, s0, pd0) } else { db_setpred(pd0, "none" as *u8, 4) } } 1645 } 1646 } 1647 // multi-hop (mode1) 1648 var x2: i64 = 0-1 1649 if s0 >= 0 { if top1 >= 0 { 1650 db_bridge_from(g, s0, top1) 1651 let psc: *i64 = g[42] as *i64 1652 let xsc: *i64 = g[43] as *i64 1653 var pp: i64 = 0 1654 while pp < g[14] { 1655 if pp == top1 { xsc[pp] = 0-1000 } else { 1656 let bt: i64 = db_bridge_title_hits(g, pp) 1657 let bb: i64 = db_bridge_body_hits(g, pp) 1658 xsc[pp] = psc[pp] + 3*bt + 2*bb 1659 } 1660 pp = pp + 1 1661 } 1662 var bx2: i64 = 0-1 1663 var bxs: i64 = 0-SEM_MAGIC_1000000 1664 pp = 0 1665 while pp < g[14] { if xsc[pp] > bxs { bxs = xsc[pp]; bx2 = pp } pp = pp + 1 } 1666 x2 = bx2 1667 } } 1668 let pd1: *u8 = (g[55] as i64 + rows*256) as *u8 1669 if yn == 1 { db_setpred(pd1, "yes" as *u8, 3) } else { 1670 var got1: i64 = 0 1671 if wantnum0 == 1 { got1 = db_sweep_numeric(g, top1, x2, pd1) } 1672 if got1 == 0 { 1673 var s2: i64 = 0-1 1674 if x2 >= 0 { s2 = db_best_sentence_in(g, x2) } 1675 var sfin: i64 = s2 1676 if sfin < 0 { sfin = s0 } 1677 let shit: *i64 = g[39] as *i64 1678 if s0 >= 0 { if s2 >= 0 { if shit[s0] > shit[s2] + 1 { sfin = s0 } } } 1679 if sfin >= 0 { db_extract(g, sfin, pd1) } else { db_setpred(pd1, "none" as *u8, 4) } 1680 } 1681 } 1682 // ---- mode 2: SEMANTIC sentence selection (R3-lite; same extraction, different selection) ---- 1683 let pd2: *u8 = g[68] as *u8 1684 if yn == 1 { db_setpred(pd2, "yes" as *u8, 3) } else { 1685 var got2: i64 = 0 1686 if wantnum0 == 1 { got2 = db_sweep_numeric(g, top1, top2, pd2) } 1687 if got2 == 0 { 1688 let ss: i64 = sem_best_sentence(g, top1, top2) 1689 var sf2: i64 = ss 1690 if sf2 < 0 { sf2 = s0 } 1691 if sf2 >= 0 { db_extract(g, sf2, pd2) } else { db_setpred(pd2, "none" as *u8, 4) } 1692 } 1693 } 1694 // ---- mode R: TRAINED span reader (learned candidate ranking; same candidate GENERATION) ---- 1695 let pdR: *u8 = g[84] as *u8 1696 if g[79] == 1 { 1697 if yn == 1 { db_setpred(pdR, "yes" as *u8, 3) } else { 1698 var gotR: i64 = 0 1699 if wantnum0 == 1 { gotR = db_sweep_numeric(g, top1, top2, pdR) } 1700 if gotR == 0 { 1701 let okR: i64 = rd_pick(g, top1, top2, s0, pdR) 1702 if okR == 0 { if s0 >= 0 { db_extract(g, s0, pdR) } else { db_setpred(pdR, "none" as *u8, 4) } } 1703 } 1704 } 1705 if yn == 0 { sum_orc = sum_orc + rd_oracle(g, top1, top2, s0, g[5] as *u8) } 1706 } 1707 1708 // gold copy (for neg-control) 1709 let gd: *u8 = (gaa as i64 + rows*256) as *u8 1710 db_setpred(gd, g[5] as *u8, 250) 1711 sum_f0 = sum_f0 + qab_f1(g, fmt, pd0) 1712 sum_f1 = sum_f1 + qab_f1(g, fmt, pd1) 1713 sum_f2 = sum_f2 + qab_f1(g, fmt, pd2) 1714 if g[79] == 1 { sum_fR = sum_fR + qab_f1(g, fmt, pdR) } 1715 em0 = em0 + qab_em(g, fmt, pd0) 1716 let DBG: i64 = 0 1717 if DBG == 1 { if fmt == 1 { if rows < 14 { 1718 db_w(" [SQ] f0="); db_n(qab_f1(g,fmt,pd0)); db_w(" | Q="); db_w(g[4] as *u8); db_w(" | P="); db_w(pd0); db_w(" | G="); db_w(g[5] as *u8); db_w("\n" as *u8) 1719 } } } 1720 rows = rows + 1 1721 if QLIMIT > 0 { if rows >= QLIMIT { live = 0 } } 1722 } 1723 } 1724 } 1725 1726 // neg-control: mode0 preds vs ROTATED golds -> must be ~0 1727 var neg: i64 = 0 1728 var r: i64 = 0 1729 while r < rows { 1730 let pd: *u8 = (p0a as i64 + r*256) as *u8 1731 var r2: i64 = r + 1 1732 if r2 >= rows { r2 = 0 } 1733 neg = neg + qs_f1(pd, (gaa as i64 + r2*256) as *u8) 1734 r = r + 1 1735 } 1736 var af0: i64 = 0; var af1: i64 = 0; var af2: i64 = 0; var afR: i64 = 0; var afO: i64 = 0; var naneg: i64 = 0 1737 if rows > 0 { af0 = sum_f0/rows; af1 = sum_f1/rows; af2 = sum_f2/rows; afR = sum_fR/rows; afO = sum_orc/rows; naneg = neg/rows } 1738 db_w(" "); db_w(label) 1739 db_w(" rows="); db_n(rows) 1740 db_w(" F1_lex="); db_n(af0) 1741 db_w(" F1_hop="); db_n(af1) 1742 db_w(" F1_SEM="); db_n(af2) 1743 db_w(" F1_rdr="); db_n(afR) 1744 db_w(" ORACLE="); db_n(afO) 1745 db_w(" EM="); db_n(em0); db_w("/"); db_n(rows) 1746 db_w(" negctl="); db_n(naneg); db_w("\n" as *u8) 1747 res[base]=rows; res[base+1]=af0; res[base+2]=af1; res[base+3]=af2; res[base+4]=em0; res[base+5]=afR; res[base+6]=afO 1748 return rows 1749} 1750 1751func main(argc: i64, argv: *i64) -> i64 { 1752 if argc < 4 { db_w("=== nx_qabench -- QA benchmark LADDER: SQuAD 1-hop (extraction floor) vs HotpotQA 2-hop (reasoning wall) ===\n" as *u8) } 1753 if argc >= 4 { db_w("=== nx_qabench ANSWER (retrieve-then-read; trained span reader) ===\n" as *u8) } 1754 let g: *i64 = sys_mmap(SEM_MAGIC_2048) as *i64 // 256 slots (was 128; multi-source research uses 125-127) 1755 let m0: *u8 = sys_mmap(SEM_MAGIC_16777216); g[0] = m0 as i64 // 16MB raw-file buffer: paginated sets grow past the old 1.5MB (HotpotQA-300 = 1.9MB) 1756 let m4: *u8 = sys_mmap(SEM_MAGIC_4096); g[4] = m4 as i64 1757 let m5: *u8 = sys_mmap(SEM_MAGIC_2048); g[5] = m5 as i64 1758 let m6: *u8 = sys_mmap(64); g[6] = m6 as i64 1759 let m7: *u8 = sys_mmap(SEM_MAGIC_4096); g[7] = m7 as i64 1760 let m8: *u8 = sys_mmap(256); g[8] = m8 as i64 1761 let m9: *u8 = sys_mmap(256); g[9] = m9 as i64 1762 let m11: *u8 = sys_mmap(SEM_MAGIC_32768); g[11] = m11 as i64 // title arena (MuSiQue: 20 paras vs HotpotQA 10) 1763 let m12: *u8 = sys_mmap(SEM_MAGIC_4096); g[12] = m12 as i64 // pto: 512 paragraph slots 1764 let m13: *u8 = sys_mmap(SEM_MAGIC_4096); g[13] = m13 as i64 // ptl 1765 let m15: *u8 = sys_mmap(SEM_MAGIC_1048576); g[15] = m15 as i64 // sentence arena (20 long paras) 1766 let m16: *u8 = sys_mmap(SEM_MAGIC_32768); g[16] = m16 as i64 // so: SEM_MAGIC_4096 sentence slots 1767 let m17: *u8 = sys_mmap(SEM_MAGIC_32768); g[17] = m17 as i64 // sl 1768 let m18: *u8 = sys_mmap(SEM_MAGIC_32768); g[18] = m18 as i64 // sp 1769 let m20: *u8 = sys_mmap(SEM_MAGIC_1048576); g[20] = m20 as i64 // normalized sentence arena 1770 let m21: *u8 = sys_mmap(SEM_MAGIC_32768); g[21] = m21 as i64 // no 1771 let m22: *u8 = sys_mmap(SEM_MAGIC_32768); g[22] = m22 as i64 // nl 1772 let m23: *u8 = sys_mmap(SEM_MAGIC_524288); g[23] = m23 as i64 // tko: 64k token slots 1773 let m24: *u8 = sys_mmap(SEM_MAGIC_524288); g[24] = m24 as i64 // tkl 1774 let m25: *u8 = sys_mmap(SEM_MAGIC_32768); g[25] = m25 as i64 // tks: per-sentence token start 1775 let m26: *u8 = sys_mmap(SEM_MAGIC_32768); g[26] = m26 as i64 // tkc 1776 let m28: *u8 = sys_mmap(SEM_MAGIC_4096); g[28] = m28 as i64 1777 let m29: *u8 = sys_mmap(SEM_MAGIC_2048); g[29] = m29 as i64 1778 let m30: *u8 = sys_mmap(SEM_MAGIC_2048); g[30] = m30 as i64 1779 let m32: *u8 = sys_mmap(SEM_MAGIC_2048); g[32] = m32 as i64 1780 let m33: *u8 = sys_mmap(SEM_MAGIC_32768); g[33] = m33 as i64 // title normalized arena 1781 let m34: *u8 = sys_mmap(SEM_MAGIC_32768); g[34] = m34 as i64 // tto 1782 let m35: *u8 = sys_mmap(SEM_MAGIC_32768); g[35] = m35 as i64 // ttl 1783 let m36: *u8 = sys_mmap(SEM_MAGIC_4096); g[36] = m36 as i64 // tts: 512 paragraph slots 1784 let m37: *u8 = sys_mmap(SEM_MAGIC_4096); g[37] = m37 as i64 // ttc 1785 let m39: *u8 = sys_mmap(SEM_MAGIC_32768); g[39] = m39 as i64 // shit: per-sentence 1786 let m40: *u8 = sys_mmap(SEM_MAGIC_4096); g[40] = m40 as i64 // thit: per-paragraph 1787 let m41: *u8 = sys_mmap(SEM_MAGIC_4096); g[41] = m41 as i64 // bhit 1788 let m42: *u8 = sys_mmap(SEM_MAGIC_4096); g[42] = m42 as i64 // psc 1789 let m43: *u8 = sys_mmap(SEM_MAGIC_4096); g[43] = m43 as i64 // xsc 1790 let m44: *u8 = sys_mmap(SEM_MAGIC_1024); g[44] = m44 as i64 1791 let m45: *u8 = sys_mmap(128); g[45] = m45 as i64 1792 let m46: *u8 = sys_mmap(128); g[46] = m46 as i64 1793 let m48: *u8 = sys_mmap(SEM_MAGIC_2048); g[48] = m48 as i64 1794 let m49: *u8 = sys_mmap(256); g[49] = m49 as i64 1795 let m50: *u8 = sys_mmap(256); g[50] = m50 as i64 1796 let m51: *u8 = sys_mmap(256); g[51] = m51 as i64 1797 let m53: *u8 = sys_mmap(SEM_MAGIC_8192); g[53] = m53 as i64 1798 let m54: *u8 = sys_mmap(SEM_MAGIC_262144); g[54] = m54 as i64 // pred/gold arenas: 256B/row -> SEM_MAGIC_1024-row capacity (grown for paginated eval sets) 1799 let m55: *u8 = sys_mmap(SEM_MAGIC_262144); g[55] = m55 as i64 1800 let m56: *u8 = sys_mmap(SEM_MAGIC_262144); g[56] = m56 as i64 1801 let m57: *u8 = sys_mmap(SEM_MAGIC_65536); g[57] = m57 as i64 // H presence matrix p*128+k (20 paras) 1802 let m58: *u8 = sys_mmap(SEM_MAGIC_8192); g[58] = m58 as i64 // df per content qterm 1803 let m59: *u8 = sys_mmap(SEM_MAGIC_262144); g[59] = m59 as i64 // SQuAD single-context temp 1804 let m60: *u8 = sys_mmap(SEM_MAGIC_8388608); g[60] = m60 as i64 // sem C matrix vc*vc i64 (vc<=SEM_MAGIC_1024) 1805 let m61: *u8 = sys_mmap(SEM_MAGIC_8192); g[61] = m61 as i64 // sem qvec 1806 let m62: *u8 = sys_mmap(SEM_MAGIC_8192); g[62] = m62 as i64 // sem svec 1807 let m63: *u8 = sys_mmap(SEM_MAGIC_8192); g[63] = m63 as i64 // sem voff 1808 let m64: *u8 = sys_mmap(SEM_MAGIC_8192); g[64] = m64 as i64 // sem vlen 1809 g[65] = 0 // sem vcount 1810 let m66: *u8 = sys_mmap(SEM_MAGIC_32768); g[66] = m66 as i64 // sem vbuf 1811 g[67] = 0 // sem vbump 1812 let m68: *u8 = sys_mmap(256); g[68] = m68 as i64 // pred2 (MODE2, reused per row) 1813 let m69: *u8 = sys_mmap(SEM_MAGIC_2048); g[69] = m69 as i64 // sem per-sentence vidx 1814 // reader (MODE-R) slots 1815 let m80: *u8 = sys_mmap(256); g[80] = m80 as i64 // reader weights w[14] 1816 let m81: *u8 = sys_mmap(SEM_MAGIC_65536); g[81] = m81 as i64 // cand feature matrix 300*14 i64 1817 let m82: *u8 = sys_mmap(SEM_MAGIC_4096); g[82] = m82 as i64 // cand meta 300 1818 let m84: *u8 = sys_mmap(SEM_MAGIC_2048); g[84] = m84 as i64 // reader prediction (candidates can be long) 1819 let m85: *u8 = sys_mmap(256); g[85] = m85 as i64 // averaged-perceptron weight sum 1820 let m86: *u8 = sys_mmap(SEM_MAGIC_2048); g[86] = m86 as i64 // candidate-string tmp (bounded copy 250) 1821 // reader training-F1 scratch (avoids qs_f1's 7-mmap-per-call OOM over millions of training scores) 1822 let m92: *u8 = sys_mmap(SEM_MAGIC_2048); g[92] = m92 as i64 // gold normalized 1823 let m93: *u8 = sys_mmap(SEM_MAGIC_2048); g[93] = m93 as i64 // gold token offsets 1824 let m94: *u8 = sys_mmap(SEM_MAGIC_2048); g[94] = m94 as i64 // gold token lengths 1825 let m95: *u8 = sys_mmap(SEM_MAGIC_2048); g[95] = m95 as i64 // cand normalized 1826 let m96: *u8 = sys_mmap(SEM_MAGIC_2048); g[96] = m96 as i64 // cand token offsets 1827 let m97: *u8 = sys_mmap(SEM_MAGIC_2048); g[97] = m97 as i64 // cand token lengths 1828 let m98: *u8 = sys_mmap(SEM_MAGIC_2048); g[98] = m98 as i64 // used array (qs_common) 1829 let m100: *u8 = sys_mmap(64); g[100] = m100 as i64 // MuSiQue loader stbox (hoisted from per-row mmap) 1830 let m108: *u8 = sys_mmap(SEM_MAGIC_2048); g[108] = m108 as i64 // dump: question PPMI ids (embed feats) 1831 let m110: *u8 = sys_mmap(SEM_MAGIC_2048); g[110] = m110 as i64 // dump: candidate string 1832 let m111: *u8 = sys_mmap(SEM_MAGIC_2048); g[111] = m111 as i64 // dump: candidate normalized 1833 let m112: *u8 = sys_mmap(SEM_MAGIC_2048); g[112] = m112 as i64 // dump: candidate token offsets 1834 let m113: *u8 = sys_mmap(SEM_MAGIC_2048); g[113] = m113 as i64 // dump: candidate token lengths 1835 let m114: *u8 = sys_mmap(64); g[114] = m114 as i64 // dump: 3-i64 embedding feature buffer 1836 let m118: *u8 = sys_mmap(SEM_MAGIC_1024); g[118] = m118 as i64 // full-vec: q_emb_unit (DIM i64) 1837 let m119: *u8 = sys_mmap(SEM_MAGIC_1024); g[119] = m119 as i64 // full-vec: cand_unit scratch 1838 let m121: *u8 = sys_mmap(SEM_MAGIC_1024); g[121] = m121 as i64 // full-vec: DIM-vector feature buffer 1839 let m126: *u8 = sys_mmap(256); g[126] = m126 as i64 // research: best answer buffer 1840 let m127: *u8 = sys_mmap(SEM_MAGIC_16384); g[127] = m127 as i64 // research: per-source answers (64 x 256 fixed-width) 1841 let m128: *u8 = sys_mmap(512); g[128] = m128 as i64 // research: per-source confidence (i64) 1842 let m129: *u8 = sys_mmap(512); g[129] = m129 as i64 // research: per-source argv index (i64) 1843 let m130: *u8 = sys_mmap(SEM_MAGIC_4096); g[130] = m130 as i64 // live prose: sentence-clean scratch 1844 g[79] = 0 1845 1846 // ---- DUMPFEATS MODE: nx_qabench dumpfeats -> export candidate features for offline neural-reader training ---- 1847 // dumpfeats: sparse-PPMI embed features are the current BEST (measured: sparse 279 > dense@24 262 -- the 1848 // 24-dim factorization is a lossy compression, weaker than the full sparse signal AS A SCALAR feature). 1849 // embed_load()/dense_cos_int() are committed infra for the next rung (bigger embeddings / full-vector 1850 // features); 'de' selects dense to re-measure. Default 'd' = sparse. 1851 if argc >= 2 { let a1: *u8 = argv[1] as *u8; if a1[0] == (100 as u8) { 1852 if a1[1] == (116 as u8) { return rd_dump_texts(g) } // 'dt' = raw text rows for the neural reader (no ppmi needed) 1853 if a1[1] == (120 as u8) { return rd_dump_texts_xl(g) } // 'dx' = XL rows (all chunks) -> reader_rows_xl.bin 1854 ppmi_load(g) 1855 if a1[1] == (101 as u8) { let el: i64 = embed_load(g); if el == 1 { db_w("dumpfeats: TRAINED dense embeddings (embed_v1.bin)\n" as *u8) } } // 'de' = dense 1856 return rd_dump_feats(g) 1857 } } 1858 1859 // R5 opt-in: if the marker file exists, route the researcher's EXTRACTION through the pretrained sovereign 1860 // Qwen (qwx_extract) instead of the mechanical db_extract. Boots the model once (fail-fast, before serving). 1861 g[132] = 0 1862 let qw_on: i64 = sys_openat_rd("knowledge/index/qwen_reader.on" as *u8) 1863 if qw_on >= 0 { 1864 sys_close(qw_on) 1865 db_w("QWEN-READER = marker present -> booting pretrained Qwen for extraction (nx_qwen_extract)...\n" as *u8) 1866 let qrc: i64 = qwx_load() 1867 if qrc == 0 { g[132] = 1; db_w("QWEN-READER = LIVE (qwx_extract routes qa_read_source extraction)\n" as *u8) } 1868 else { db_w("QWEN-READER = load FAILED -> mechanical db_extract fallback\n" as *u8) } 1869 } 1870 1871 // ---- LIVE ANSWER MODE: nx_qabench answer "<question>" <context-file> ---- 1872 // Turns the benchmark pipeline into a callable reading-comprehension capability on ARBITRARY input 1873 // (retrieve-then-read with the trained span reader). Same organ, no benchmark files needed. 1874 if argc >= 4 { 1875 ppmi_load(g) // silent (loads semppmi_v1.bin if present) 1876 rd_load(g) // silent (loads reader_v1.bin if present; else db_extract fallback) 1877 let a1: *u8 = argv[1] as *u8 1878 if a1[0] == (114 as u8) { return qa_research(g, argv[2] as *u8, argv, 3, argc) } // 'r' = research "<q>" ctx1 ctx2... 1879 return qa_answer(g, argv[2] as *u8, argv[3] as *u8) // else answer "<q>" ctx 1880 } 1881 1882 let res: *i64 = sys_mmap(256) as *i64 1883 let pl: i64 = ppmi_load(g) 1884 if pl == 1 { db_w("\nSEM path = CORPUS sparse-PPMI soft-alignment (semppmi_v1.bin loaded: vocab="); db_n(g[71]); db_w(" triples="); db_n(g[72]); db_w(")\n" as *u8) } 1885 else { db_w("\nSEM path = per-row co-occurrence FALLBACK (semppmi_v1.bin absent; run nx_semppmi_build)\n" as *u8) } 1886 // reader: load persisted weights, else train on disjoint corpus chunks 1887 let rl: i64 = rd_load(g) 1888 if rl == 0 { db_w("READER = no reader_v1.bin -> training span-scorer on DISJOINT corpus rows (SQuAD-baseline recipe)...\n" as *u8); rd_train(g) } 1889 if g[79] == 1 { 1890 let w: *i64 = g[80] as *i64 1891 db_w("READER = trained span-scorer LIVE. w=[") 1892 var wi: i64 = 0 1893 while wi < RD_NF { db_n(w[wi]); if wi < RD_NF-1 { db_w(" " as *u8) } wi = wi + 1 } 1894 db_w("]\n" as *u8) 1895 } else { db_w("READER = unavailable (corpus absent); MODE-R column will read 0\n" as *u8) } 1896 db_w("\n-- per-benchmark (same extractor+metric; F1 permille; lex=IDF-lexical hop=bridge SEM=distributional MODE2) --\n" as *u8) 1897 qab_run(g, "knowledge/fetched/qab_squad_big.raw" as *u8, 1, "SQuAD-v1.1 [1-hop, single-ctx]" as *u8, res, 0) 1898 qab_run(g, "knowledge/fetched/qab_hotpot_big.raw" as *u8, 0, "HotpotQA [2-hop, distractor]" as *u8, res, 8) 1899 qab_run(g, "knowledge/fetched/qab_musique_big.raw" as *u8, 3, "MuSiQue [2-4-hop, 20 paras]" as *u8, res, 16) 1900 1901 db_w("\n=== LADDER (mechanical researcher vs published SOTA; harder = more hops/distractors) ===\n" as *u8) 1902 db_w(" RUNG F1_lex F1_hop F1_SEM F1_rdr published-SOTA F1 gap(best)\n" as *u8) 1903 db_w(" SQuAD 1-hop "); db_n(res[1]); db_w(" "); db_n(res[2]); db_w(" "); db_n(res[3]); db_w(" "); db_n(res[5]); db_w(" ~900 (BiDAF+ 2016..) "); db_n(900 - qab_max4(res[1],res[2],res[3],res[5])); db_w("\n" as *u8) 1904 db_w(" HotpotQA 2-hop "); db_n(res[9]); db_w(" "); db_n(res[10]); db_w(" "); db_n(res[11]); db_w(" "); db_n(res[13]); db_w(" ~700-820 (strong) "); db_n(760 - qab_max4(res[9],res[10],res[11],res[13])); db_w("\n" as *u8) 1905 db_w(" MuSiQue 2-4-hop "); db_n(res[17]); db_w(" "); db_n(res[18]); db_w(" "); db_n(res[19]); db_w(" "); db_n(res[21]); db_w(" ~490-690 (SOTA/RoHT) "); db_n(590 - qab_max4(res[17],res[18],res[19],res[21])); db_w("\n" as *u8) 1906 1907 // best-mode per rung + which mode won (honest: name the winner, never hide a losing column) 1908 let bS: i64 = qab_max4(res[1],res[2],res[3],res[5]) 1909 let bH: i64 = qab_max4(res[9],res[10],res[11],res[13]) 1910 let bM: i64 = qab_max4(res[17],res[18],res[19],res[21]) 1911 db_w(" BEST-MODE ladder: SQuAD "); db_n(bS); db_w(" / HotpotQA "); db_n(bH); db_w(" / MuSiQue "); db_n(bM); db_w(" (rdr=trained span reader)\n" as *u8) 1912 // ORACLE ceiling (best candidate in the set) vs reader -> names the binding stage: gap(oracle-rdr) big = SCORING 1913 // headroom; oracle ~= reader = candidate GENERATION is the wall. 1914 db_w(" ORACLE ceiling: SQuAD "); db_n(res[6]); db_w(" / HotpotQA "); db_n(res[14]); db_w(" / MuSiQue "); db_n(res[22]); db_w(" (best candidate available; rdr-to-oracle gap = scoring headroom)\n" as *u8) 1915 db_w(" -> binding stage: SQuAD "); qab_bind(res[5], res[6]); db_w(" / HotpotQA "); qab_bind(res[13], res[14]); db_w(" / MuSiQue "); qab_bind(res[21], res[22]); db_w("\n" as *u8) 1916 1917 var pass: i64 = 0 1918 if res[0] > 0 { pass = pass + 1 } 1919 if res[8] > 0 { pass = pass + 1 } 1920 if res[16] > 0 { pass = pass + 1 } 1921 // difficulty gradient must hold on the BEST mode: SQuAD >= HotpotQA >= MuSiQue -> the hops ARE the gap 1922 if bS >= bH { if bH >= bM { pass = pass + 1 } } 1923 db_w("\nTEETH (squad+hotpot+musique ran + best-mode difficulty-gradient holds) = "); db_n(pass); db_w("/4\n" as *u8) 1924 if pass == 4 { 1925 db_w("GREEN -- 4-mode ladder measured (lex/hop/SEM/trained-reader). Best-mode F1 falls monotonically as\n" as *u8) 1926 db_w("HOPS + DISTRACTORS rise. The trained span reader (SQuAD-baseline recipe) attacks the EXTRACTION stage\n" as *u8) 1927 db_w("the 6x-corpus datapoint proved is now binding. Honest: no rung at SOTA; next lever = R1 no-float reader.\n" as *u8) 1928 return 0 1929 } 1930 db_w("RED -- a rung did not run (fetch its subset) or the best-mode difficulty gradient did not hold\n" as *u8) 1931 return 1 1932} 1933 1934func qab_max4(a: i64, b: i64, c: i64, d: i64) -> i64 { 1935 var m: i64 = a 1936 if b > m { m = b } 1937 if c > m { m = c } 1938 if d > m { m = d } 1939 return m 1940} 1941 1942// name the binding stage from (reader F1, oracle F1): a wide gap = the right candidate exists but the reader 1943// mis-scores it (SCORING); a narrow gap = the reader is near-optimal and the answer isn't a candidate (GENERATION). 1944func qab_bind(rdr: i64, orc: i64) -> i64 { 1945 let gap: i64 = orc - rdr 1946 if gap > 150 { db_w("SCORING(gap "); db_n(gap); db_w(")" as *u8) } else { db_w("GENERATION(gap "); db_n(gap); db_w(")" as *u8) } 1947 return 0 1948} 1949 1950// read a whole file into buf (null-terminated); returns byte length, -1 on open failure. 1951func qa_read_file(path: *u8, buf: *u8, cap: i64) -> i64 { 1952 let fd: i64 = sys_openat_rd(path) 1953 if fd < 0 { return 0-1 } 1954 var total: i64 = 0 1955 var r: i64 = 1 1956 while r > 0 { 1957 let left: i64 = cap - 1 - total 1958 if left <= 0 { r = 0 } else { 1959 r = sys_read(fd, (buf as i64 + total) as *u8, left) 1960 if r > 0 { total = total + r } 1961 } 1962 } 1963 sys_close(fd) 1964 buf[total] = (0 as u8) 1965 return total 1966} 1967 1968// LIVE answer: run the retrieve-then-read pipeline on an arbitrary (question, context) and print the answer + 1969// its source sentence (citation). Reuses the exact benchmark machinery; reader if loaded, else db_extract. 1970// core: read ONE source vs the question already in g[4]; extract the answer into pred; stash the best-sentence 1971// index in g[125]; return CONFIDENCE = best-sentence question-hit score (2*sentence-hits + title-hits), which is 1972// comparable across sources. Returns -1 on read/parse failure. Shared by single-source answer + multi-source. 1973func qa_read_source(g: *i64, ctxpath: *u8, pred: *u8) -> i64 { 1974 let ctxb: *u8 = g[59] as *u8 1975 let cl: i64 = qa_read_file(ctxpath, ctxb, SEM_MAGIC_200000) 1976 if cl <= 0 { return 0-1 } 1977 g[14] = 1 1978 let pto: *i64 = g[12] as *i64 1979 let ptl: *i64 = g[13] as *i64 1980 let ptb: *u8 = g[11] as *u8 1981 pto[0]=0; ptl[0]=0; ptb[0]=(0 as u8) 1982 let ns: i64 = qa_split_prose(g, ctxb, cl) // prose-filtered: drops web chrome/wikitext/JSON 1983 g[19] = ns 1984 if ns <= 0 { return 0-1 } 1985 db_norm_row(g) 1986 db_score_row(g) 1987 let top1: i64 = db_top_para(g, 0-1) 1988 let top2: i64 = db_top_para(g, top1) 1989 let s0: i64 = db_best_sentence(g) 1990 g[125] = s0 1991 var conf: i64 = 0 1992 if s0 >= 0 { 1993 let shit: *i64 = g[39] as *i64 1994 let thit: *i64 = g[40] as *i64 1995 let sp: *i64 = g[18] as *i64 1996 conf = 2*shit[s0] + thit[sp[s0]] 1997 } 1998 let yn: i64 = db_is_yesno(g) 1999 let wantnum: i64 = db_prefer_numeric(g) 2000 var qwdone: i64 = 0 2001 if g[132] == 1 { if qwx_ready() == 1 { if s0 >= 0 { qwdone = qwx_extract(g, s0, pred) } } } // R5: Qwen reads context centered on best sentence s0 2002 if qwdone == 0 { 2003 if yn == 1 { db_setpred(pred, "yes" as *u8, 3) } else { 2004 var got: i64 = 0 2005 if wantnum == 1 { got = db_sweep_numeric(g, top1, top2, pred) } 2006 if got == 0 { if db_wants_location(g) == 1 { got = db_sweep_location(g, top1, top2, pred) } } // where -> place answer 2007 if got == 0 { if s0 >= 0 { db_extract(g, s0, pred) } else { db_setpred(pred, "(no answer found)" as *u8, 17) } } 2008 } 2009 } 2010 // ACCURATE CITATION: a sweep may extract from a different sentence than the top-match s0, so cite the 2011 // sentence that actually CONTAINS the answer (fall back to s0 if not found). 2012 if yn == 0 { 2013 let so2: *i64 = g[16] as *i64 2014 let sb2: *u8 = g[15] as *u8 2015 var cs: i64 = 0 2016 var found: i64 = 0 2017 while cs < g[19] { 2018 if found == 0 { 2019 if qa_contains_ci((sb2 as i64 + so2[cs]) as *u8, pred) == 1 { g[125] = cs; found = 1 } 2020 } 2021 cs = cs + 1 2022 } 2023 } 2024 return conf 2025} 2026 2027func qa_streq(a: *u8, b: *u8) -> i64 { 2028 var i: i64 = 0 2029 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 2030 if b[i] != (0 as u8) { return 0 } 2031 return 1 2032} 2033 2034func qa_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c } 2035func qa_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i } 2036 2037// case-insensitive: is `needle` a substring of `hay`? 2038func qa_contains_ci(hay: *u8, needle: *u8) -> i64 { 2039 let hl: i64 = qa_slen(hay) 2040 let nl: i64 = qa_slen(needle) 2041 if nl == 0 { return 0 } 2042 if nl > hl { return 0 } 2043 var i: i64 = 0 2044 while i + nl <= hl { 2045 var j: i64 = 0 2046 var m: i64 = 1 2047 while j < nl { if m == 1 { if qa_lc(hay[i+j] as i64) != qa_lc(needle[j] as i64) { m = 0 } } j = j + 1 } 2048 if m == 1 { return 1 } 2049 i = i + 1 2050 } 2051 return 0 2052} 2053 2054// two answers CORROBORATE if one is contained in the other (case-insensitive): "Einstein" ~ "Albert Einstein". 2055func qa_answer_agree(a: *u8, b: *u8) -> i64 { 2056 if qa_contains_ci(a, b) == 1 { return 1 } 2057 if qa_contains_ci(b, a) == 1 { return 1 } 2058 return 0 2059} 2060// (a definitional hit-density sentence selector was tried to fix the Eiffel "New York Times" miss -- it was 2061// INERT (the concise lead still did not win; deeper debug = single-example whack-a-mole) so it was removed. 2062// The Eiffel-class selection miss needs a trained neural reader, not a mechanical density heuristic.) 2063 2064func qa_answer(g: *i64, question: *u8, ctxpath: *u8) -> i64 { 2065 let q: *u8 = g[4] as *u8 2066 var i: i64 = 0 2067 while question[i] != (0 as u8) { if i < SEM_MAGIC_3999 { q[i] = question[i] } i = i + 1 } 2068 var qn: i64 = i 2069 if qn > SEM_MAGIC_3999 { qn = SEM_MAGIC_3999 } 2070 q[qn] = (0 as u8) 2071 let pred: *u8 = g[84] as *u8 2072 let conf: i64 = qa_read_source(g, ctxpath, pred) 2073 if conf < 0 { db_w("ERROR: cannot read/parse context file: "); db_w(ctxpath); db_w("\n" as *u8); return 1 } 2074 db_w("Q: "); db_w(q); db_w("\n" as *u8) 2075 db_w("A: "); db_w(pred); db_w("\n" as *u8) 2076 let s0: i64 = g[125] 2077 if s0 >= 0 { 2078 let sb: *u8 = g[15] as *u8 2079 let so: *i64 = g[16] as *i64 2080 db_w(" source: "); db_w((sb as i64 + so[s0]) as *u8); db_w("\n" as *u8) 2081 } 2082 return 0 2083} 2084 2085// DEEP RESEARCH: read the question across MULTIPLE fetched sources, pick the highest-confidence answer, and 2086// report the cross-source picture + AGREEMENT (how many sources produced the same answer = corroboration). This 2087// is the researcher's synthesis stage -- multi-source, the actual "deep research" loop. 2088func qa_research(g: *i64, question: *u8, argv: *i64, cstart: i64, argc: i64) -> i64 { 2089 let q: *u8 = g[4] as *u8 2090 var i: i64 = 0 2091 while question[i] != (0 as u8) { if i < SEM_MAGIC_3999 { q[i] = question[i] } i = i + 1 } 2092 var qn: i64 = i 2093 if qn > SEM_MAGIC_3999 { qn = SEM_MAGIC_3999 } 2094 q[qn] = (0 as u8) 2095 db_w("=== DEEP RESEARCH (multi-source) ===\nQ: "); db_w(q); db_w("\n" as *u8) 2096 let pred: *u8 = g[84] as *u8 2097 let bestpred: *u8 = g[126] as *u8 2098 let ansb: *u8 = g[127] as *u8 // per-source answers, 256-byte fixed-width records 2099 let confs: *i64 = g[128] as *i64 // per-source confidence 2100 let sidx: *i64 = g[129] as *i64 // per-source argv index (for citation) 2101 var nsrc: i64 = 0 2102 var si: i64 = cstart 2103 while si < argc { 2104 if nsrc < 64 { 2105 let ctxpath: *u8 = argv[si] as *u8 2106 let conf: i64 = qa_read_source(g, ctxpath, pred) 2107 if conf >= 0 { 2108 db_w(" [src "); db_n(si-cstart); db_w("] conf="); db_n(conf); db_w(" A: "); db_w(pred); db_w(" <- "); db_w(ctxpath); db_w("\n" as *u8) 2109 qa_strcpy((ansb as i64 + nsrc*256) as *u8, pred) 2110 confs[nsrc] = conf 2111 sidx[nsrc] = si 2112 nsrc = nsrc + 1 2113 } else { 2114 db_w(" [src "); db_n(si-cstart); db_w("] (unreadable / no prose) <- "); db_w(ctxpath); db_w("\n" as *u8) 2115 } 2116 } 2117 si = si + 1 2118 } 2119 if nsrc == 0 { db_w("NO ANSWER: no readable source\n" as *u8); return 1 } 2120 // CORROBORATION-FIRST aggregation: the answer the MOST sources support wins (tie-break by confidence). 2121 // This is the deep-research principle -- agreement across independent sources beats a lone high score. 2122 var best: i64 = 0-1 2123 var bestagree: i64 = 0-1 2124 var bestconf: i64 = 0-1 2125 var a: i64 = 0 2126 while a < nsrc { 2127 let ca: *u8 = (ansb as i64 + a*256) as *u8 2128 var agree: i64 = 0 2129 var b: i64 = 0 2130 while b < nsrc { if qa_answer_agree(ca, (ansb as i64 + b*256) as *u8) == 1 { agree = agree + 1 } b = b + 1 } 2131 var take: i64 = 0 2132 if agree > bestagree { take = 1 } else { if agree == bestagree { if confs[a] > bestconf { take = 1 } } } 2133 if take == 1 { bestagree = agree; bestconf = confs[a]; best = a } 2134 a = a + 1 2135 } 2136 qa_strcpy(bestpred, (ansb as i64 + best*256) as *u8) 2137 db_w("\n=== ANSWER: "); db_w(bestpred); db_w("\n "); db_n(bestagree); db_w("/"); db_n(nsrc); db_w(" sources corroborate (confidence "); db_n(bestconf); db_w(")\n source: "); db_w(argv[sidx[best]] as *u8); db_w("\n" as *u8) 2138 return 0 2139} 2140 2141func qa_strcpy(dst: *u8, src: *u8) -> i64 { 2142 var i: i64 = 0 2143 while src[i] != (0 as u8) { if i < 250 { dst[i] = src[i] } i = i + 1 } 2144 var n: i64 = i; if n > 250 { n = 250 } dst[n] = (0 as u8) 2145 return 0 2146}