code wiki / _hdl_build / nx_qabench_engine.nx

nx_qabench_engine.nx source

↩ module page · 1278 lines · 47933 B

1// nx_drbench.nx -- R2: the FIRST public-benchmark run of the Nishi researcher (census axis [BEN]: "MEASURED 2// scores on public benchmarks -- NEVER run"). Dataset = HotpotQA distractor validation rows 0..99 (banked by 3// nx_drbench_fetch -> knowledge/fetched/drb_hotpot_p0.raw, sovereign TLS). Protocol = the published distractor 4// eval: each question ships 10 paragraphs (2 gold + 8 distractors); systems retrieve + extract an answer; 5// scored by SQuAD word-F1/EM (nx_qa_score_lib, integer permille) + gold-paragraph recall at 2. 6// TWO MODES measured side by side: 7// mode0 SINGLE-HOP lexical baseline: question-term overlap retrieval -> span heuristic extraction. 8// mode1 MULTI-HOP (the DeepResearcher loop shape, mechanical): hop-1 best para/sentence -> harvest BRIDGE 9// entities (cap-runs + hop-1 title terms not in the question) -> expanded second retrieval -> extract. 10// The LOW numbers ARE the honest baseline (no LLM synth yet -- that is census rung R1). Teeth: 11// T1 parse integrity (100 rows, 10 paras, nonempty q/a) T2 gold titles parsed + resolvable to paragraphs 12// T3 NEG-CONTROL: predictions scored against the WRONG (rotated) golds must collapse to ~0 (metric not rigged) 13// T4 non-degenerate retrieval floor (recall at 2 must beat the ~200 permille random floor) 14// T5 report mode0 vs mode1 delta (measurement, not a forced win -- honest either way) 15// NOTE: all state lives in ONE ctx table g: *i64 passed to every fn (the proven rctx pattern) -- statics hit 16// the known multi-static subscript-read compiler bug (filed; PHASE-A/B bisect proof in the session log). 17// ctx slots: 0 raw 1 blen 2 boff 3 cur 4 q 5 a 6 ty 7 gtb 8 gto 9 gtl 10 ngt 11 ptb 12 pto 13 ptl 14 np 18// 15 sb 16 so 17 sl 18 sp 19 ns 20 nb 21 no 22 nl 23 tko 24 tkl 25 tks 26 tkc 27 ntk 28 qnb 29 qto 30 qtl 19// 31 nqt 32 qk 33 tnb 34 tto 35 ttl 36 tts 37 ttc 38 nttk 39 shit 40 thit 41 bhit 42 psc 43 xsc 20// 44 btb 45 bto 46 btl 47 nbt 48 cnd 49 cno 50 cnl 51 cnt 52 ncn 53 scr 54 p0 55 p1 56 ga 21// expect_exit: 0 license_tier: ORIGINAL 22import "nx_qa_score_lib.nx" 23import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 24const K_MAGIC_262144: i64 = 262144 25const K_MAGIC_260000: i64 = 260000 26const K_MAGIC_5381: i64 = 5381 27const K_MAGIC_77245: i64 = 77245 28const K_MAGIC_1073741789: i64 = 1073741789 29const K_MAGIC_1073741783: i64 = 1073741783 30const K_MAGIC_15000: i64 = 15000 31const K_MAGIC_2000: i64 = 2000 32const K_MAGIC_2048: i64 = 2048 33const K_MAGIC_4096: i64 = 4096 34const K_MAGIC_1000000: i64 = 1000000 35 36// ---------- print helpers ---------- 37func db_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 38// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 39// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 40// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 41// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 42func db_n(v: i64) -> i64 { nxi_out(v); return 0 } 43 44// ---------- file ---------- 45// BOUNDED read (debt eaten 2026-07-07: the old unbounded loop overflowed g[0] when a grown dataset exceeded the 46// buffer -> SIGSEGV; sizing the buffer was a workaround, THIS is the fix). Reads at most cap bytes; if the file 47// has MORE, returns -2 (caller reports "grow the buffer") instead of corrupting memory. Closes fd on all paths. 48func db_read_raw(g: *i64, path: *u8, cap: i64) -> i64 { 49 let raw: *u8 = g[0] as *u8 50 let fd: i64 = sys_openat_rd(path) 51 if fd < 0 { return 0-1 } 52 var total: i64 = 0 53 var r: i64 = 1 54 while r > 0 { 55 var want: i64 = K_MAGIC_262144 56 let left: i64 = cap - total 57 if left <= 0 { 58 // buffer exactly full: probe 1 byte to distinguish exact-fit from oversize 59 var pb: [8]u8 60 let pr: i64 = sys_read(fd, pb, 1) 61 sys_close(fd) 62 if pr > 0 { return 0-2 } 63 return total 64 } 65 if want > left { want = left } 66 r = sys_read(fd, (raw as i64 + total) as *u8, want) 67 if r > 0 { total = total + r } 68 } 69 sys_close(fd) 70 return total 71} 72 73// find body start (after CRLFCRLF) 74func db_body_start(g: *i64, total: i64) -> i64 { 75 let raw: *u8 = g[0] as *u8 76 var i: i64 = 0 77 while i < total-3 { 78 if raw[i]==(13 as u8) { if raw[i+1]==(10 as u8) { if raw[i+2]==(13 as u8) { if raw[i+3]==(10 as u8) { return i+4 } } } } 79 i = i + 1 80 } 81 return 0 82} 83 84func db_b(g: *i64, i: i64) -> i64 { 85 let raw: *u8 = g[0] as *u8 86 return raw[g[2] + i] as i64 87} 88 89// ---------- json scan ---------- 90// does body[pos..] match: QUOTE key QUOTE COLON ? return pos after colon, else -1 91func db_match_key(g: *i64, pos: i64, key: *u8) -> i64 { 92 if db_b(g,pos) != 34 { return 0-1 } 93 var k: i64 = 0 94 var p: i64 = pos + 1 95 while key[k] != (0 as u8) { 96 if p >= g[1] { return 0-1 } 97 if db_b(g,p) != (key[k] as i64) { return 0-1 } 98 p = p + 1; k = k + 1 99 } 100 if db_b(g,p) != 34 { return 0-1 } 101 p = p + 1 102 if db_b(g,p) != 58 { return 0-1 } 103 return p + 1 104} 105 106// scan forward from cur for "key": ; leaves cur after colon. returns 0 ok, -1 not found 107func db_find_key(g: *i64, key: *u8) -> i64 { 108 var i: i64 = g[3] 109 while i < g[1] { 110 if db_b(g,i) == 34 { 111 let m: i64 = db_match_key(g, i, key) 112 if m >= 0 { g[3] = m; return 0 } 113 } 114 i = i + 1 115 } 116 return 0-1 117} 118 119func db_skip_ws(g: *i64) -> i64 { 120 while g[3] < g[1] { 121 var c: i64 = db_b(g, g[3]) 122 var sp: i64 = 0 123 if c==32 { sp=1 } 124 if c==10 { sp=1 } 125 if c==13 { sp=1 } 126 if c==9 { sp=1 } 127 if sp==0 { return 0 } 128 g[3] = g[3] + 1 129 } 130 return 0 131} 132 133// decode a JSON string. cur must be AT the opening quote (after ws). writes out (cap), returns len; cur -> after closing quote. 134func db_dec_str(g: *i64, out: *u8, cap: i64) -> i64 { 135 db_skip_ws(g) 136 if db_b(g, g[3]) != 34 { return 0-1 } 137 g[3] = g[3] + 1 138 var j: i64 = 0 139 while g[3] < g[1] { 140 var c: i64 = db_b(g, g[3]) 141 if c == 34 { g[3] = g[3] + 1; out[j] = (0 as u8); return j } 142 if c == 92 { 143 g[3] = g[3] + 1 144 var e: i64 = db_b(g, g[3]) 145 var oc: i64 = e 146 if e == 110 { oc = 10 } 147 if e == 116 { oc = 9 } 148 if e == 114 { oc = 13 } 149 if e == 98 { oc = 32 } 150 if e == 102 { oc = 32 } 151 if e == 117 { oc = 32; g[3] = g[3] + 4 } 152 if j < cap-2 { out[j] = (oc as u8); j = j + 1 } 153 g[3] = g[3] + 1 154 } else { 155 if j < cap-2 { out[j] = (c as u8); j = j + 1 } 156 g[3] = g[3] + 1 157 } 158 } 159 out[j] = (0 as u8) 160 return j 161} 162 163// parse ["s","s",...] into arena+offs. cur at/before '['. returns count. 164func db_parse_str_arr(g: *i64, arena: *u8, acap: i64, offs: *i64, lens: *i64, maxn: i64) -> i64 { 165 db_skip_ws(g) 166 if db_b(g, g[3]) != 91 { return 0-1 } 167 g[3] = g[3] + 1 168 var n: i64 = 0 169 var bump: i64 = 0 170 while g[3] < g[1] { 171 db_skip_ws(g) 172 var c: i64 = db_b(g, g[3]) 173 if c == 93 { g[3] = g[3] + 1; return n } 174 if c == 44 { g[3] = g[3] + 1 } 175 db_skip_ws(g) 176 if db_b(g, g[3]) == 34 { 177 let dst: *u8 = (arena as i64 + bump) as *u8 178 let ln: i64 = db_dec_str(g, dst, acap - bump) 179 if ln < 0 { return 0-1 } 180 if n < maxn { offs[n] = bump; lens[n] = ln; n = n + 1; bump = bump + ln + 1 } 181 } else { return 0-1 } 182 } 183 return 0-1 184} 185 186// parse [[..],[..]] sentences. fills sb/so/sl/sp + ns (g[19]). returns npara. 187func db_parse_sentences(g: *i64) -> i64 { 188 let sb: *u8 = g[15] as *u8 189 let so: *i64 = g[16] as *i64 190 let sl: *i64 = g[17] as *i64 191 let sp: *i64 = g[18] as *i64 192 db_skip_ws(g) 193 if db_b(g, g[3]) != 91 { return 0-1 } 194 g[3] = g[3] + 1 195 var para: i64 = 0 196 var bump: i64 = 0 197 g[19] = 0 198 while g[3] < g[1] { 199 db_skip_ws(g) 200 var c: i64 = db_b(g, g[3]) 201 if c == 93 { g[3] = g[3] + 1; return para } 202 if c == 44 { g[3] = g[3] + 1; db_skip_ws(g); c = db_b(g, g[3]) } 203 if c == 91 { 204 g[3] = g[3] + 1 205 var live: i64 = 1 206 while live == 1 { 207 db_skip_ws(g) 208 var d: i64 = db_b(g, g[3]) 209 if d == 93 { g[3] = g[3] + 1; live = 0 } 210 if live == 1 { 211 if d == 44 { g[3] = g[3] + 1; db_skip_ws(g) } 212 if db_b(g, g[3]) == 34 { 213 let dst: *u8 = (sb as i64 + bump) as *u8 214 let ln: i64 = db_dec_str(g, dst, K_MAGIC_262144 - bump - 8) 215 if ln < 0 { return 0-1 } 216 if g[19] < 1000 { if bump + ln < K_MAGIC_260000 { 217 let ns0: i64 = g[19] 218 so[ns0] = bump; sl[ns0] = ln; sp[ns0] = para 219 g[19] = ns0 + 1; bump = bump + ln + 1 220 } } 221 } 222 } 223 } 224 para = para + 1 225 } 226 } 227 return 0-1 228} 229 230// ---------- shared semantic-hash (ONE source of truth: nx_semppmi_build writes ids with this, nx_qabench 231// resolves query words with it -- any drift silently zeroes all similarities) ---------- 232func db_semhash(buf: *u8, off: i64, len: i64) -> i64 { 233 var h1: i64 = K_MAGIC_5381 234 var h2: i64 = K_MAGIC_77245 235 var i: i64 = 0 236 while i < len { 237 let c: i64 = buf[off+i] as i64 238 h1 = (h1*33 + c) % K_MAGIC_1073741789 239 h2 = (h2*131 + c) % K_MAGIC_1073741783 240 i = i + 1 241 } 242 return h1 * K_MAGIC_1073741783 + h2 243} 244 245// binary search sorted i64 array; idx or -1 246func db_bsearch_i64(a: *i64, n: i64, v: i64) -> i64 { 247 var lo: i64 = 0 248 var hi: i64 = n - 1 249 while lo <= hi { 250 let mid: i64 = (lo + hi) / 2 251 if a[mid] == v { return mid } 252 if a[mid] < v { lo = mid + 1 } else { hi = mid - 1 } 253 } 254 return 0-1 255} 256 257// ---------- token utilities ---------- 258func db_tok_is(buf: *u8, off: i64, len: i64, lit: *u8) -> i64 { 259 var ll: i64 = 0 260 while lit[ll] != (0 as u8) { ll = ll + 1 } 261 if ll != len { return 0 } 262 var k: i64 = 0 263 while k < len { if buf[off+k] != lit[k] { return 0 } k = k + 1 } 264 return 1 265} 266 267func db_is_stop(buf: *u8, off: i64, len: i64) -> i64 { 268 if db_tok_is(buf,off,len,"is" as *u8)==1 { return 1 } 269 if db_tok_is(buf,off,len,"are" as *u8)==1 { return 1 } 270 if db_tok_is(buf,off,len,"was" as *u8)==1 { return 1 } 271 if db_tok_is(buf,off,len,"were" as *u8)==1 { return 1 } 272 if db_tok_is(buf,off,len,"be" as *u8)==1 { return 1 } 273 if db_tok_is(buf,off,len,"been" as *u8)==1 { return 1 } 274 if db_tok_is(buf,off,len,"do" as *u8)==1 { return 1 } 275 if db_tok_is(buf,off,len,"does" as *u8)==1 { return 1 } 276 if db_tok_is(buf,off,len,"did" as *u8)==1 { return 1 } 277 if db_tok_is(buf,off,len,"what" as *u8)==1 { return 1 } 278 if db_tok_is(buf,off,len,"which" as *u8)==1 { return 1 } 279 if db_tok_is(buf,off,len,"who" as *u8)==1 { return 1 } 280 if db_tok_is(buf,off,len,"whom" as *u8)==1 { return 1 } 281 if db_tok_is(buf,off,len,"whose" as *u8)==1 { return 1 } 282 if db_tok_is(buf,off,len,"when" as *u8)==1 { return 1 } 283 if db_tok_is(buf,off,len,"where" as *u8)==1 { return 1 } 284 if db_tok_is(buf,off,len,"why" as *u8)==1 { return 1 } 285 if db_tok_is(buf,off,len,"how" as *u8)==1 { return 1 } 286 if db_tok_is(buf,off,len,"of" as *u8)==1 { return 1 } 287 if db_tok_is(buf,off,len,"in" as *u8)==1 { return 1 } 288 if db_tok_is(buf,off,len,"on" as *u8)==1 { return 1 } 289 if db_tok_is(buf,off,len,"at" as *u8)==1 { return 1 } 290 if db_tok_is(buf,off,len,"by" as *u8)==1 { return 1 } 291 if db_tok_is(buf,off,len,"for" as *u8)==1 { return 1 } 292 if db_tok_is(buf,off,len,"with" as *u8)==1 { return 1 } 293 if db_tok_is(buf,off,len,"to" as *u8)==1 { return 1 } 294 if db_tok_is(buf,off,len,"from" as *u8)==1 { return 1 } 295 if db_tok_is(buf,off,len,"and" as *u8)==1 { return 1 } 296 if db_tok_is(buf,off,len,"or" as *u8)==1 { return 1 } 297 if db_tok_is(buf,off,len,"as" as *u8)==1 { return 1 } 298 if db_tok_is(buf,off,len,"that" as *u8)==1 { return 1 } 299 if db_tok_is(buf,off,len,"this" as *u8)==1 { return 1 } 300 if db_tok_is(buf,off,len,"it" as *u8)==1 { return 1 } 301 if db_tok_is(buf,off,len,"its" as *u8)==1 { return 1 } 302 if db_tok_is(buf,off,len,"he" as *u8)==1 { return 1 } 303 if db_tok_is(buf,off,len,"she" as *u8)==1 { return 1 } 304 if db_tok_is(buf,off,len,"they" as *u8)==1 { return 1 } 305 if db_tok_is(buf,off,len,"his" as *u8)==1 { return 1 } 306 if db_tok_is(buf,off,len,"her" as *u8)==1 { return 1 } 307 if db_tok_is(buf,off,len,"their" as *u8)==1 { return 1 } 308 if db_tok_is(buf,off,len,"both" as *u8)==1 { return 1 } 309 if db_tok_is(buf,off,len,"same" as *u8)==1 { return 1 } 310 if db_tok_is(buf,off,len,"other" as *u8)==1 { return 1 } 311 if db_tok_is(buf,off,len,"more" as *u8)==1 { return 1 } 312 if db_tok_is(buf,off,len,"most" as *u8)==1 { return 1 } 313 if db_tok_is(buf,off,len,"has" as *u8)==1 { return 1 } 314 if db_tok_is(buf,off,len,"have" as *u8)==1 { return 1 } 315 if db_tok_is(buf,off,len,"had" as *u8)==1 { return 1 } 316 if db_tok_is(buf,off,len,"also" as *u8)==1 { return 1 } 317 if db_tok_is(buf,off,len,"name" as *u8)==1 { return 1 } 318 if db_tok_is(buf,off,len,"named" as *u8)==1 { return 1 } 319 if db_tok_is(buf,off,len,"known" as *u8)==1 { return 1 } 320 if db_tok_is(buf,off,len,"first" as *u8)==1 { return 1 } 321 if db_tok_is(buf,off,len,"born" as *u8)==0 { return 0 } 322 return 1 323} 324 325// is token (buf,off,len) present in question tokens? contentonly 1 = content terms only 326func db_in_question(g: *i64, buf: *u8, off: i64, len: i64, contentonly: i64) -> i64 { 327 let qnb: *u8 = g[28] as *u8 328 let qto: *i64 = g[29] as *i64 329 let qtl: *i64 = g[30] as *i64 330 let qk: *i64 = g[32] as *i64 331 var k: i64 = 0 332 while k < g[31] { 333 var use: i64 = 1 334 if contentonly == 1 { if qk[k] == 0 { use = 0 } } 335 if use == 1 { 336 if qs_tok_eq2(buf, off, len, qnb, qto[k], qtl[k]) == 1 { return 1 } 337 } 338 k = k + 1 339 } 340 return 0 341} 342 343// ---------- per-row normalize + tokenize ---------- 344func db_norm_row(g: *i64) -> i64 { 345 let q: *u8 = g[4] as *u8 346 let qnb: *u8 = g[28] as *u8 347 let qto: *i64 = g[29] as *i64 348 let qtl: *i64 = g[30] as *i64 349 let qk: *i64 = g[32] as *i64 350 let sb: *u8 = g[15] as *u8 351 let so: *i64 = g[16] as *i64 352 let nb: *u8 = g[20] as *u8 353 let no2: *i64 = g[21] as *i64 354 let nl2: *i64 = g[22] as *i64 355 let tko: *i64 = g[23] as *i64 356 let tkl: *i64 = g[24] as *i64 357 let tks: *i64 = g[25] as *i64 358 let tkc: *i64 = g[26] as *i64 359 let ptb: *u8 = g[11] as *u8 360 let pto: *i64 = g[12] as *i64 361 let tnb: *u8 = g[33] as *u8 362 let tto: *i64 = g[34] as *i64 363 let ttl: *i64 = g[35] as *i64 364 let tts: *i64 = g[36] as *i64 365 let ttc: *i64 = g[37] as *i64 366 367 // question 368 let ql: i64 = qs_norm(q, qnb) 369 let nq: i64 = qs_tok(qnb, ql, qto, qtl, 120) 370 g[31] = nq 371 var k: i64 = 0 372 while k < nq { 373 var keep: i64 = 1 374 if db_is_stop(qnb, qto[k], qtl[k]) == 1 { keep = 0 } 375 qk[k] = keep 376 k = k + 1 377 } 378 // sentences 379 g[27] = 0 380 var bump: i64 = 0 381 var s: i64 = 0 382 while s < g[19] { 383 let src: *u8 = (sb as i64 + so[s]) as *u8 384 let dst: *u8 = (nb as i64 + bump) as *u8 385 let nl0: i64 = qs_norm(src, dst) 386 no2[s] = bump; nl2[s] = nl0 387 let t0: i64 = g[27] 388 let cnt: i64 = qs_tok(dst, nl0, (tko as i64 + t0*8) as *i64, (tkl as i64 + t0*8) as *i64, K_MAGIC_15000 - t0) 389 var j: i64 = 0 390 while j < cnt { tko[t0+j] = tko[t0+j] + bump; j = j + 1 } 391 tks[s] = t0; tkc[s] = cnt 392 g[27] = t0 + cnt 393 bump = bump + nl0 + 2 394 s = s + 1 395 } 396 // titles 397 g[38] = 0 398 var tb: i64 = 0 399 var p: i64 = 0 400 while p < g[14] { 401 let tsrc: *u8 = (ptb as i64 + pto[p]) as *u8 402 let tdst: *u8 = (tnb as i64 + tb) as *u8 403 let tl0: i64 = qs_norm(tsrc, tdst) 404 let s0: i64 = g[38] 405 let c2: i64 = qs_tok(tdst, tl0, (tto as i64 + s0*8) as *i64, (ttl as i64 + s0*8) as *i64, 1000 - s0) 406 var j2: i64 = 0 407 while j2 < c2 { tto[s0+j2] = tto[s0+j2] + tb; j2 = j2 + 1 } 408 tts[p] = s0; ttc[p] = c2 409 g[38] = s0 + c2 410 tb = tb + tl0 + 2 411 p = p + 1 412 } 413 return 0 414} 415 416// ---------- scoring ---------- 417func db_sent_hits(g: *i64, s: i64) -> i64 { 418 let nb: *u8 = g[20] as *u8 419 let tko: *i64 = g[23] as *i64 420 let tkl: *i64 = g[24] as *i64 421 let tks: *i64 = g[25] as *i64 422 let tkc: *i64 = g[26] as *i64 423 let qnb: *u8 = g[28] as *u8 424 let qto: *i64 = g[29] as *i64 425 let qtl: *i64 = g[30] as *i64 426 let qk: *i64 = g[32] as *i64 427 var hits: i64 = 0 428 var k: i64 = 0 429 while k < g[31] { 430 if qk[k] == 1 { 431 var found: i64 = 0 432 var j: i64 = 0 433 while j < tkc[s] { 434 if found == 0 { 435 let ti: i64 = tks[s] + j 436 if qs_tok_eq2(nb, tko[ti], tkl[ti], qnb, qto[k], qtl[k]) == 1 { found = 1 } 437 } 438 j = j + 1 439 } 440 hits = hits + found 441 } 442 k = k + 1 443 } 444 return hits 445} 446 447func db_title_hits(g: *i64, p: i64) -> i64 { 448 let tnb: *u8 = g[33] as *u8 449 let tto: *i64 = g[34] as *i64 450 let ttl: *i64 = g[35] as *i64 451 let tts: *i64 = g[36] as *i64 452 let ttc: *i64 = g[37] as *i64 453 let qnb: *u8 = g[28] as *u8 454 let qto: *i64 = g[29] as *i64 455 let qtl: *i64 = g[30] as *i64 456 let qk: *i64 = g[32] as *i64 457 var hits: i64 = 0 458 var k: i64 = 0 459 while k < g[31] { 460 if qk[k] == 1 { 461 var found: i64 = 0 462 var j: i64 = 0 463 while j < ttc[p] { 464 if found == 0 { 465 let ti: i64 = tts[p] + j 466 if qs_tok_eq2(tnb, tto[ti], ttl[ti], qnb, qto[k], qtl[k]) == 1 { found = 1 } 467 } 468 j = j + 1 469 } 470 hits = hits + found 471 } 472 k = k + 1 473 } 474 return hits 475} 476 477func db_body_hits(g: *i64, p: i64) -> i64 { 478 let nb: *u8 = g[20] as *u8 479 let tko: *i64 = g[23] as *i64 480 let tkl: *i64 = g[24] as *i64 481 let tks: *i64 = g[25] as *i64 482 let tkc: *i64 = g[26] as *i64 483 let sp: *i64 = g[18] as *i64 484 let qnb: *u8 = g[28] as *u8 485 let qto: *i64 = g[29] as *i64 486 let qtl: *i64 = g[30] as *i64 487 let qk: *i64 = g[32] as *i64 488 var hits: i64 = 0 489 var k: i64 = 0 490 while k < g[31] { 491 if qk[k] == 1 { 492 var found: i64 = 0 493 var s: i64 = 0 494 while s < g[19] { 495 if found == 0 { if sp[s] == p { 496 var j: i64 = 0 497 while j < tkc[s] { 498 if found == 0 { 499 let ti: i64 = tks[s] + j 500 if qs_tok_eq2(nb, tko[ti], tkl[ti], qnb, qto[k], qtl[k]) == 1 { found = 1 } 501 } 502 j = j + 1 503 } 504 } } 505 s = s + 1 506 } 507 hits = hits + found 508 } 509 k = k + 1 510 } 511 return hits 512} 513 514// single content-qterm k present in para p body? (0/1) 515func db_term_in_body(g: *i64, p: i64, k: i64) -> i64 { 516 let nb: *u8 = g[20] as *u8 517 let tko: *i64 = g[23] as *i64 518 let tkl: *i64 = g[24] as *i64 519 let tks: *i64 = g[25] as *i64 520 let tkc: *i64 = g[26] as *i64 521 let sp: *i64 = g[18] as *i64 522 let qnb: *u8 = g[28] as *u8 523 let qto: *i64 = g[29] as *i64 524 let qtl: *i64 = g[30] as *i64 525 var s: i64 = 0 526 while s < g[19] { 527 if sp[s] == p { 528 var j: i64 = 0 529 while j < tkc[s] { 530 let ti: i64 = tks[s] + j 531 if qs_tok_eq2(nb, tko[ti], tkl[ti], qnb, qto[k], qtl[k]) == 1 { return 1 } 532 j = j + 1 533 } 534 } 535 s = s + 1 536 } 537 return 0 538} 539 540func db_term_in_title(g: *i64, p: i64, k: i64) -> i64 { 541 let tnb: *u8 = g[33] as *u8 542 let tto: *i64 = g[34] as *i64 543 let ttl: *i64 = g[35] as *i64 544 let tts: *i64 = g[36] as *i64 545 let ttc: *i64 = g[37] as *i64 546 let qnb: *u8 = g[28] as *u8 547 let qto: *i64 = g[29] as *i64 548 let qtl: *i64 = g[30] as *i64 549 var j: i64 = 0 550 while j < ttc[p] { 551 let ti: i64 = tts[p] + j 552 if qs_tok_eq2(tnb, tto[ti], ttl[ti], qnb, qto[k], qtl[k]) == 1 { return 1 } 553 j = j + 1 554 } 555 return 0 556} 557 558// IDF-weighted paragraph retrieval (BM25-style discrimination: a term in FEWER paras weighs more). 559// H[p*128+k] = body(bit0)|title(bit1); df[k]=#paras with term; score += (np-df+1) per present term, title 2x. 560func db_score_row(g: *i64) -> i64 { 561 let shit: *i64 = g[39] as *i64 562 let thit: *i64 = g[40] as *i64 563 let psc: *i64 = g[42] as *i64 564 let qk: *i64 = g[32] as *i64 565 let H: *u8 = g[57] as *u8 566 let df: *i64 = g[58] as *i64 567 var s: i64 = 0 568 while s < g[19] { let h: i64 = db_sent_hits(g, s); shit[s] = h; s = s + 1 } 569 // build presence matrix + df over content qterms 570 var k: i64 = 0 571 while k < g[31] { 572 df[k] = 0 573 if qk[k] == 1 { 574 var p: i64 = 0 575 while p < g[14] { 576 let b: i64 = db_term_in_body(g, p, k) 577 let t: i64 = db_term_in_title(g, p, k) 578 var h: i64 = 0 579 if b == 1 { h = h + 1 } 580 if t == 1 { h = h + 2 } 581 H[p*128+k] = h as u8 582 if h != 0 { df[k] = df[k] + 1 } 583 p = p + 1 584 } 585 } 586 k = k + 1 587 } 588 // per-para IDF-weighted score 589 var p2: i64 = 0 590 while p2 < g[14] { 591 var sc: i64 = 0 592 var th: i64 = 0 593 var k2: i64 = 0 594 while k2 < g[31] { 595 if qk[k2] == 1 { 596 let h2: i64 = H[p2*128+k2] as i64 597 if h2 != 0 { 598 let w: i64 = g[14] - df[k2] + 1 // rarer term -> higher weight 599 sc = sc + w 600 if h2 >= 2 { sc = sc + 2*w; th = th + 1 } // title match: extra weight + count 601 } 602 } 603 k2 = k2 + 1 604 } 605 thit[p2] = th 606 psc[p2] = sc 607 p2 = p2 + 1 608 } 609 return 0 610} 611 612func db_bridge_title_hits(g: *i64, p: i64) -> i64 { 613 let tnb: *u8 = g[33] as *u8 614 let tto: *i64 = g[34] as *i64 615 let ttl: *i64 = g[35] as *i64 616 let tts: *i64 = g[36] as *i64 617 let ttc: *i64 = g[37] as *i64 618 let btb: *u8 = g[44] as *u8 619 let bto: *i64 = g[45] as *i64 620 let btl: *i64 = g[46] as *i64 621 var hits: i64 = 0 622 var k: i64 = 0 623 while k < g[47] { 624 var found: i64 = 0 625 var j: i64 = 0 626 while j < ttc[p] { 627 if found == 0 { 628 let ti: i64 = tts[p] + j 629 if qs_tok_eq2(tnb, tto[ti], ttl[ti], btb, bto[k], btl[k]) == 1 { found = 1 } 630 } 631 j = j + 1 632 } 633 hits = hits + found 634 k = k + 1 635 } 636 return hits 637} 638 639func db_bridge_body_hits(g: *i64, p: i64) -> i64 { 640 let nb: *u8 = g[20] as *u8 641 let tko: *i64 = g[23] as *i64 642 let tkl: *i64 = g[24] as *i64 643 let tks: *i64 = g[25] as *i64 644 let tkc: *i64 = g[26] as *i64 645 let sp: *i64 = g[18] as *i64 646 let btb: *u8 = g[44] as *u8 647 let bto: *i64 = g[45] as *i64 648 let btl: *i64 = g[46] as *i64 649 var hits: i64 = 0 650 var k: i64 = 0 651 while k < g[47] { 652 var found: i64 = 0 653 var s: i64 = 0 654 while s < g[19] { 655 if found == 0 { if sp[s] == p { 656 var j: i64 = 0 657 while j < tkc[s] { 658 if found == 0 { 659 let ti: i64 = tks[s] + j 660 if qs_tok_eq2(nb, tko[ti], tkl[ti], btb, bto[k], btl[k]) == 1 { found = 1 } 661 } 662 j = j + 1 663 } 664 } } 665 s = s + 1 666 } 667 hits = hits + found 668 k = k + 1 669 } 670 return hits 671} 672 673// ---------- candidates + extraction ---------- 674// harvest candidates from RAW sentence bytes: capitalized runs + numerics. fills cnd arrays (ncn=g[52]). 675func db_candidates(g: *i64, soff: i64, slen: i64) -> i64 { 676 let sb: *u8 = g[15] as *u8 677 let cnd: *u8 = g[48] as *u8 678 let cno: *i64 = g[49] as *i64 679 let cnl: *i64 = g[50] as *i64 680 let cnt: *i64 = g[51] as *i64 681 g[52] = 0 682 var bump: i64 = 0 683 var i: i64 = 0 684 while i < slen { 685 var c: i64 = sb[soff+i] as i64 686 var alnum: i64 = 0 687 if c>=48 { if c<=57 { alnum=1 } } 688 if c>=65 { if c<=90 { alnum=1 } } 689 if c>=97 { if c<=122 { alnum=1 } } 690 if alnum == 1 { 691 var wend: i64 = i 692 var isnum: i64 = 1 693 var iscap: i64 = 0 694 if c>=65 { if c<=90 { iscap=1 } } 695 while wend < slen { 696 var d: i64 = sb[soff+wend] as i64 697 var a2: i64 = 0 698 if d>=48 { if d<=57 { a2=1 } } 699 if d>=65 { if d<=90 { a2=1; isnum=0 } } 700 if d>=97 { if d<=122 { a2=1; isnum=0 } } 701 if d==44 { if wend+1<slen { var e2: i64 = sb[soff+wend+1] as i64; if e2>=48 { if e2<=57 { a2=1 } } } } // comma between digits: "3,677" stays one number 702 if a2 == 0 { wend = slen + wend + 1 } else { wend = wend + 1 } 703 } 704 if wend > slen { wend = wend - slen - 1 } 705 let wlen: i64 = wend - i 706 if isnum == 1 { 707 if g[52] < 15 { if bump + wlen < K_MAGIC_2000 { 708 var w: i64 = 0 709 while w < wlen { cnd[bump+w] = sb[soff+i+w]; w = w + 1 } 710 cnd[bump+wlen] = (0 as u8) 711 let n0: i64 = g[52] 712 cno[n0] = bump; cnl[n0] = wlen 713 var cty: i64 = 2 714 if wlen == 4 { cty = 3 } 715 cnt[n0] = cty 716 g[52] = n0 + 1; bump = bump + wlen + 1 717 } } 718 i = wend 719 } else { 720 if iscap == 1 { 721 var rend: i64 = wend 722 var words: i64 = 1 723 var go: i64 = 1 724 while go == 1 { 725 if rend < slen { if sb[soff+rend]==(32 as u8) { 726 var nx: i64 = rend + 1 727 if nx < slen { 728 var e: i64 = sb[soff+nx] as i64 729 var ecap: i64 = 0 730 if e>=65 { if e<=90 { ecap=1 } } 731 if e>=48 { if e<=57 { ecap=1 } } 732 if ecap == 1 { if words < 6 { 733 var we2: i64 = nx 734 while we2 < slen { 735 var f: i64 = sb[soff+we2] as i64 736 var a3: i64 = 0 737 if f>=48 { if f<=57 { a3=1 } } 738 if f>=65 { if f<=90 { a3=1 } } 739 if f>=97 { if f<=122 { a3=1 } } 740 if a3 == 0 { we2 = slen + we2 + 1 } else { we2 = we2 + 1 } 741 } 742 if we2 > slen { we2 = we2 - slen - 1 } 743 rend = we2; words = words + 1 744 } else { go = 0 } } else { go = 0 } 745 } else { go = 0 } 746 } else { go = 0 } } else { go = 0 } 747 } 748 let rlen: i64 = rend - i 749 if g[52] < 15 { if bump + rlen < K_MAGIC_2000 { 750 var w2: i64 = 0 751 while w2 < rlen { cnd[bump+w2] = sb[soff+i+w2]; w2 = w2 + 1 } 752 cnd[bump+rlen] = (0 as u8) 753 let n1: i64 = g[52] 754 cno[n1] = bump; cnl[n1] = rlen 755 cnt[n1] = 1 756 g[52] = n1 + 1; bump = bump + rlen + 1 757 } } 758 i = rend 759 } else { 760 i = wend 761 } 762 } 763 } else { 764 i = i + 1 765 } 766 } 767 return g[52] 768} 769 770// candidate echo-check: 1 = candidate fully contained in the question (drop it) 771func db_cand_is_echo(g: *i64, ci: i64) -> i64 { 772 let cnd: *u8 = g[48] as *u8 773 let cno: *i64 = g[49] as *i64 774 let scr: *u8 = g[53] as *u8 775 let src: *u8 = (cnd as i64 + cno[ci]) as *u8 776 let nl0: i64 = qs_norm(src, scr) 777 let toks: *i64 = (scr as i64 + K_MAGIC_2048) as *i64 778 let tlens: *i64 = (scr as i64 + K_MAGIC_4096) as *i64 779 let n: i64 = qs_tok(scr, nl0, toks, tlens, 32) 780 if n == 0 { return 1 } 781 var k: i64 = 0 782 while k < n { 783 if db_in_question(g, scr, toks[k], tlens[k], 0) == 0 { return 0 } 784 k = k + 1 785 } 786 return 1 787} 788 789func db_prefer_numeric(g: *i64) -> i64 { 790 let qnb: *u8 = g[28] as *u8 791 let qto: *i64 = g[29] as *i64 792 let qtl: *i64 = g[30] as *i64 793 var k: i64 = 0 794 while k < g[31] { 795 if db_tok_is(qnb, qto[k], qtl[k], "when" as *u8)==1 { return 1 } 796 if db_tok_is(qnb, qto[k], qtl[k], "year" as *u8)==1 { return 1 } 797 if db_tok_is(qnb, qto[k], qtl[k], "many" as *u8)==1 { return 1 } 798 k = k + 1 799 } 800 return 0 801} 802 803// question wants a YEAR specifically (prefer 4-digit) 804func db_wants_year(g: *i64) -> i64 { 805 let qnb: *u8 = g[28] as *u8 806 let qto: *i64 = g[29] as *i64 807 let qtl: *i64 = g[30] as *i64 808 var k: i64 = 0 809 while k < g[31] { 810 if db_tok_is(qnb, qto[k], qtl[k], "when" as *u8)==1 { return 1 } 811 if db_tok_is(qnb, qto[k], qtl[k], "year" as *u8)==1 { return 1 } 812 k = k + 1 813 } 814 return 0 815} 816 817// candidate ci is a COMMON capitalized word (nationality/pronoun/determiner/number-word) = a likely distractor, not the answer 818func db_cand_is_common(g: *i64, ci: i64) -> i64 { 819 let cnd: *u8 = g[48] as *u8 820 let cno: *i64 = g[49] as *i64 821 let scr: *u8 = g[53] as *u8 822 let src: *u8 = (cnd as i64 + cno[ci]) as *u8 823 let nl0: i64 = qs_norm(src, scr) 824 let toks: *i64 = (scr as i64 + K_MAGIC_2048) as *i64 825 let tlens: *i64 = (scr as i64 + K_MAGIC_4096) as *i64 826 let n: i64 = qs_tok(scr, nl0, toks, tlens, 8) 827 if n != 1 { return 0 } // multi-word runs are proper nouns, not common 828 let o: i64 = toks[0] 829 let l: i64 = tlens[0] 830 if db_tok_is(scr,o,l,"american" as *u8)==1 { return 1 } 831 if db_tok_is(scr,o,l,"british" as *u8)==1 { return 1 } 832 if db_tok_is(scr,o,l,"english" as *u8)==1 { return 1 } 833 if db_tok_is(scr,o,l,"french" as *u8)==1 { return 1 } 834 if db_tok_is(scr,o,l,"german" as *u8)==1 { return 1 } 835 if db_tok_is(scr,o,l,"italian" as *u8)==1 { return 1 } 836 if db_tok_is(scr,o,l,"european" as *u8)==1 { return 1 } 837 if db_tok_is(scr,o,l,"she" as *u8)==1 { return 1 } 838 if db_tok_is(scr,o,l,"he" as *u8)==1 { return 1 } 839 if db_tok_is(scr,o,l,"they" as *u8)==1 { return 1 } 840 if db_tok_is(scr,o,l,"it" as *u8)==1 { return 1 } 841 if db_tok_is(scr,o,l,"the" as *u8)==1 { return 1 } 842 if db_tok_is(scr,o,l,"this" as *u8)==1 { return 1 } 843 if db_tok_is(scr,o,l,"one" as *u8)==1 { return 1 } 844 if db_tok_is(scr,o,l,"two" as *u8)==1 { return 1 } 845 if db_tok_is(scr,o,l,"three" as *u8)==1 { return 1 } 846 return 0 847} 848 849// candidate ci is a MULTI-WORD run (contains a space) = strong proper-noun signal 850func db_cand_multiword(g: *i64, ci: i64) -> i64 { 851 let cnd: *u8 = g[48] as *u8 852 let cno: *i64 = g[49] as *i64 853 let cnl: *i64 = g[50] as *i64 854 var w: i64 = 0 855 while w < cnl[ci] { if cnd[cno[ci]+w]==(32 as u8) { return 1 } w = w + 1 } 856 return 0 857} 858 859// sweep the two retrieved paragraphs for a NUMERIC answer (numeric questions). fills pred, returns 1 if found. 860func db_sweep_numeric(g: *i64, pa: i64, pb: i64, pred: *u8) -> i64 { 861 let so: *i64 = g[16] as *i64 862 let sl: *i64 = g[17] as *i64 863 let sp: *i64 = g[18] as *i64 864 let cnd: *u8 = g[48] as *u8 865 let cno: *i64 = g[49] as *i64 866 let cnl: *i64 = g[50] as *i64 867 let cnt: *i64 = g[51] as *i64 868 let wy: i64 = db_wants_year(g) 869 // (a subject-mention "shit>0" year pass was tried and REGRESSED -- too loose: any sentence naming the 870 // subject qualifies, e.g. "...Earl of Lovelace in 1838" for a birth-year Q. Correct fix = bind the year to 871 // the event cue ("born"), which is dependency-parse-hard; left as a residual plateau item, not patched.) 872 // pass 1: 4-digit (year) when the question wants a year 873 if wy == 1 { 874 var s: i64 = 0 875 while s < g[19] { 876 if sp[s]==pa { if sp[s]<0 { } } // (keep structure explicit) 877 var inpar: i64 = 0 878 if sp[s]==pa { inpar = 1 } 879 if sp[s]==pb { inpar = 1 } 880 if inpar == 1 { 881 db_candidates(g, so[s], sl[s]) 882 var c: i64 = 0 883 while c < g[52] { 884 if cnt[c]==3 { if db_cand_is_echo(g,c)==0 { 885 db_setpred(pred, (cnd as i64 + cno[c]) as *u8, cnl[c]); return 1 886 } } 887 c = c + 1 888 } 889 } 890 s = s + 1 891 } 892 } 893 // pass 2: any number 894 var s2: i64 = 0 895 while s2 < g[19] { 896 var inpar2: i64 = 0 897 if sp[s2]==pa { inpar2 = 1 } 898 if sp[s2]==pb { inpar2 = 1 } 899 if inpar2 == 1 { 900 db_candidates(g, so[s2], sl[s2]) 901 var c2: i64 = 0 902 while c2 < g[52] { 903 if cnt[c2]>=2 { if db_cand_is_echo(g,c2)==0 { 904 db_setpred(pred, (cnd as i64 + cno[c2]) as *u8, cnl[c2]); return 1 905 } } 906 c2 = c2 + 1 907 } 908 } 909 s2 = s2 + 1 910 } 911 return 0 912} 913 914// question is a LOCATION question ("where ...") 915func db_wants_location(g: *i64) -> i64 { 916 let qnb: *u8 = g[28] as *u8 917 let qto: *i64 = g[29] as *i64 918 let qtl: *i64 = g[30] as *i64 919 if g[31] < 1 { return 0 } 920 if db_tok_is(qnb, qto[0], qtl[0], "where" as *u8)==1 { return 1 } 921 return 0 922} 923 924// sentence s carries a LOCATIVE cue (so its proper nouns are likely the place answer, even if it is not the 925// top question-word-match sentence -- the "where" answer usually lives in a follow-up sentence via a pronoun). 926func db_sentence_has_locative(g: *i64, s: i64) -> i64 { 927 let nb: *u8 = g[20] as *u8 928 let tko: *i64 = g[23] as *i64 929 let tkl: *i64 = g[24] as *i64 930 let tks: *i64 = g[25] as *i64 931 let tkc: *i64 = g[26] as *i64 932 var j: i64 = 0 933 while j < tkc[s] { 934 let ti: i64 = tks[s] + j 935 if db_tok_is(nb,tko[ti],tkl[ti],"located" as *u8)==1 { return 1 } 936 if db_tok_is(nb,tko[ti],tkl[ti],"coast" as *u8)==1 { return 1 } 937 if db_tok_is(nb,tko[ti],tkl[ti],"situated" as *u8)==1 { return 1 } 938 if db_tok_is(nb,tko[ti],tkl[ti],"city" as *u8)==1 { return 1 } 939 if db_tok_is(nb,tko[ti],tkl[ti],"country" as *u8)==1 { return 1 } 940 if db_tok_is(nb,tko[ti],tkl[ti],"state" as *u8)==1 { return 1 } 941 if db_tok_is(nb,tko[ti],tkl[ti],"region" as *u8)==1 { return 1 } 942 if db_tok_is(nb,tko[ti],tkl[ti],"capital" as *u8)==1 { return 1 } 943 j = j + 1 944 } 945 return 0 946} 947 948// sentence s is a COMPARISON ("taller than X", "surpassed X") -- its proper noun is a compared entity, NOT the 949// subject's location. These fool a naive location sweep (e.g. "taller than the Washington Monument"). 950func db_sentence_has_comparison(g: *i64, s: i64) -> i64 { 951 let nb: *u8 = g[20] as *u8 952 let tko: *i64 = g[23] as *i64 953 let tkl: *i64 = g[24] as *i64 954 let tks: *i64 = g[25] as *i64 955 let tkc: *i64 = g[26] as *i64 956 var j: i64 = 0 957 while j < tkc[s] { 958 let ti: i64 = tks[s] + j 959 if db_tok_is(nb,tko[ti],tkl[ti],"than" as *u8)==1 { return 1 } 960 if db_tok_is(nb,tko[ti],tkl[ti],"taller" as *u8)==1 { return 1 } 961 if db_tok_is(nb,tko[ti],tkl[ti],"shorter" as *u8)==1 { return 1 } 962 if db_tok_is(nb,tko[ti],tkl[ti],"larger" as *u8)==1 { return 1 } 963 if db_tok_is(nb,tko[ti],tkl[ti],"smaller" as *u8)==1 { return 1 } 964 if db_tok_is(nb,tko[ti],tkl[ti],"surpassed" as *u8)==1 { return 1 } 965 if db_tok_is(nb,tko[ti],tkl[ti],"compared" as *u8)==1 { return 1 } 966 j = j + 1 967 } 968 return 0 969} 970 971// pick the first proper-noun candidate (multiword preferred, else single non-common) in sentence s; non-echo. 972func db_pick_proper_in(g: *i64, s: i64, pred: *u8) -> i64 { 973 let so: *i64 = g[16] as *i64 974 let sl: *i64 = g[17] as *i64 975 let cnd: *u8 = g[48] as *u8 976 let cno: *i64 = g[49] as *i64 977 let cnl: *i64 = g[50] as *i64 978 let cnt: *i64 = g[51] as *i64 979 db_candidates(g, so[s], sl[s]) 980 var c: i64 = 0 981 while c < g[52] { if cnt[c]==1 { if db_cand_multiword(g,c)==1 { if db_cand_is_echo(g,c)==0 { db_setpred(pred,(cnd as i64 + cno[c]) as *u8, cnl[c]); return 1 } } } c = c + 1 } 982 c = 0 983 while c < g[52] { if cnt[c]==1 { if db_cand_is_common(g,c)==0 { if db_cand_is_echo(g,c)==0 { db_setpred(pred,(cnd as i64 + cno[c]) as *u8, cnl[c]); return 1 } } } c = c + 1 } 984 return 0 985} 986 987// sweep the retrieved paragraphs for a LOCATION answer. Distractor-hardened: SKIP comparison clauses (their 988// proper noun is a COMPARED entity, not the subject's place -- "taller than the Washington Monument"). Prefer a 989// locative-cued sentence that mentions the subject (pass 1), else a locative-cued follow-up with a pronoun 990// subject (pass 2). Mirrors db_sweep_numeric. 991func db_sweep_location(g: *i64, pa: i64, pb: i64, pred: *u8) -> i64 { 992 let sp: *i64 = g[18] as *i64 993 let shit: *i64 = g[39] as *i64 994 // pass 1: locative cue + mentions the subject + NOT a comparison 995 var s: i64 = 0 996 while s < g[19] { 997 var inpar: i64 = 0 998 if sp[s]==pa { inpar = 1 } 999 if sp[s]==pb { inpar = 1 } 1000 if inpar == 1 { if db_sentence_has_locative(g, s) == 1 { if shit[s] > 0 { if db_sentence_has_comparison(g, s) == 0 { 1001 if db_pick_proper_in(g, s, pred) == 1 { return 1 } 1002 } } } } 1003 s = s + 1 1004 } 1005 // pass 2: locative cue + NOT a comparison (the "It is located in ..." pronoun-subject follow-up) 1006 var s2: i64 = 0 1007 while s2 < g[19] { 1008 var inpar2: i64 = 0 1009 if sp[s2]==pa { inpar2 = 1 } 1010 if sp[s2]==pb { inpar2 = 1 } 1011 if inpar2 == 1 { if db_sentence_has_locative(g, s2) == 1 { if db_sentence_has_comparison(g, s2) == 0 { 1012 if db_pick_proper_in(g, s2, pred) == 1 { return 1 } 1013 } } } 1014 s2 = s2 + 1 1015 } 1016 return 0 1017} 1018 1019func db_is_yesno(g: *i64) -> i64 { 1020 let qnb: *u8 = g[28] as *u8 1021 let qto: *i64 = g[29] as *i64 1022 let qtl: *i64 = g[30] as *i64 1023 if g[31] < 1 { return 0 } 1024 if db_tok_is(qnb, qto[0], qtl[0], "is" as *u8)==1 { return 1 } 1025 if db_tok_is(qnb, qto[0], qtl[0], "are" as *u8)==1 { return 1 } 1026 if db_tok_is(qnb, qto[0], qtl[0], "was" as *u8)==1 { return 1 } 1027 if db_tok_is(qnb, qto[0], qtl[0], "were" as *u8)==1 { return 1 } 1028 if db_tok_is(qnb, qto[0], qtl[0], "do" as *u8)==1 { return 1 } 1029 if db_tok_is(qnb, qto[0], qtl[0], "does" as *u8)==1 { return 1 } 1030 if db_tok_is(qnb, qto[0], qtl[0], "did" as *u8)==1 { return 1 } 1031 return 0 1032} 1033 1034func db_setpred(dst: *u8, src: *u8, len: i64) -> i64 { 1035 var i: i64 = 0 1036 while i < len { if i < 250 { dst[i] = src[i] } i = i + 1 } 1037 var e: i64 = len 1038 if e > 250 { e = 250 } 1039 dst[e] = (0 as u8) 1040 return 0 1041} 1042 1043// extract answer from sentence s into pred (256B slot). fallback = leading non-question content tokens. 1044func db_extract(g: *i64, s: i64, pred: *u8) -> i64 { 1045 let so: *i64 = g[16] as *i64 1046 let sl: *i64 = g[17] as *i64 1047 let nb: *u8 = g[20] as *u8 1048 let tko: *i64 = g[23] as *i64 1049 let tkl: *i64 = g[24] as *i64 1050 let tks: *i64 = g[25] as *i64 1051 let tkc: *i64 = g[26] as *i64 1052 let cnd: *u8 = g[48] as *u8 1053 let cno: *i64 = g[49] as *i64 1054 let cnl: *i64 = g[50] as *i64 1055 let cnt: *i64 = g[51] as *i64 1056 db_candidates(g, so[s], sl[s]) 1057 let wantnum: i64 = db_prefer_numeric(g) 1058 var pick: i64 = 0-1 1059 if wantnum == 1 { 1060 var c: i64 = 0 1061 while c < g[52] { if pick < 0 { if cnt[c]==3 { if db_cand_is_echo(g,c)==0 { pick = c } } } c = c + 1 } 1062 c = 0 1063 while c < g[52] { if pick < 0 { if cnt[c]==2 { if db_cand_is_echo(g,c)==0 { pick = c } } } c = c + 1 } 1064 } 1065 // pass 1: MULTI-WORD proper-noun run (non-echo) -- beats single common distractors ("American"/"Two") 1066 var c2: i64 = 0 1067 while c2 < g[52] { if pick < 0 { if cnt[c2]==1 { if db_cand_multiword(g,c2)==1 { if db_cand_is_echo(g,c2)==0 { pick = c2 } } } } c2 = c2 + 1 } 1068 // pass 2: single capitalized, non-echo, NOT a common word 1069 c2 = 0 1070 while c2 < g[52] { if pick < 0 { if cnt[c2]==1 { if db_cand_is_common(g,c2)==0 { if db_cand_is_echo(g,c2)==0 { pick = c2 } } } } c2 = c2 + 1 } 1071 // pass 3: any capitalized non-echo (common words as last resort) 1072 c2 = 0 1073 while c2 < g[52] { if pick < 0 { if cnt[c2]==1 { if db_cand_is_echo(g,c2)==0 { pick = c2 } } } c2 = c2 + 1 } 1074 // pass 4: any non-echo candidate 1075 c2 = 0 1076 while c2 < g[52] { if pick < 0 { if db_cand_is_echo(g,c2)==0 { pick = c2 } } c2 = c2 + 1 } 1077 if pick >= 0 { 1078 let src: *u8 = (cnd as i64 + cno[pick]) as *u8 1079 db_setpred(pred, src, cnl[pick]) 1080 return 1 1081 } 1082 var out: i64 = 0 1083 var used: i64 = 0 1084 var j: i64 = 0 1085 while j < tkc[s] { 1086 if used < 8 { 1087 let ti: i64 = tks[s] + j 1088 if db_in_question(g, nb, tko[ti], tkl[ti], 0) == 0 { 1089 var w: i64 = 0 1090 while w < tkl[ti] { if out < 240 { pred[out] = nb[tko[ti]+w]; out = out + 1 } w = w + 1 } 1091 if out < 240 { pred[out] = (32 as u8); out = out + 1 } 1092 used = used + 1 1093 } 1094 } 1095 j = j + 1 1096 } 1097 if out > 0 { out = out - 1 } 1098 pred[out] = (0 as u8) 1099 return 0 1100} 1101 1102// build bridge terms from hop-1 sentence + hop-1 para title: normalized tokens NOT in the question. max 8. (nbt=g[47]) 1103func db_bridge_from(g: *i64, s: i64, p: i64) -> i64 { 1104 let so: *i64 = g[16] as *i64 1105 let sl: *i64 = g[17] as *i64 1106 let tnb: *u8 = g[33] as *u8 1107 let tto: *i64 = g[34] as *i64 1108 let ttl: *i64 = g[35] as *i64 1109 let tts: *i64 = g[36] as *i64 1110 let ttc: *i64 = g[37] as *i64 1111 let btb: *u8 = g[44] as *u8 1112 let bto: *i64 = g[45] as *i64 1113 let btl: *i64 = g[46] as *i64 1114 let cnd: *u8 = g[48] as *u8 1115 let cno: *i64 = g[49] as *i64 1116 let cnt: *i64 = g[51] as *i64 1117 let scr: *u8 = g[53] as *u8 1118 g[47] = 0 1119 var bump: i64 = 0 1120 db_candidates(g, so[s], sl[s]) 1121 var c: i64 = 0 1122 while c < g[52] { 1123 if cnt[c] == 1 { 1124 let src: *u8 = (cnd as i64 + cno[c]) as *u8 1125 let nl0: i64 = qs_norm(src, scr) 1126 let toks: *i64 = (scr as i64 + K_MAGIC_2048) as *i64 1127 let tlens: *i64 = (scr as i64 + K_MAGIC_4096) as *i64 1128 let n: i64 = qs_tok(scr, nl0, toks, tlens, 16) 1129 var k: i64 = 0 1130 while k < n { 1131 if g[47] < 8 { 1132 if db_in_question(g, scr, toks[k], tlens[k], 0) == 0 { 1133 var dup: i64 = 0 1134 var b: i64 = 0 1135 while b < g[47] { if qs_tok_eq2(scr, toks[k], tlens[k], btb, bto[b], btl[b])==1 { dup = 1 } b = b + 1 } 1136 if dup == 0 { 1137 var w: i64 = 0 1138 while w < tlens[k] { btb[bump+w] = scr[toks[k]+w]; w = w + 1 } 1139 let nb0: i64 = g[47] 1140 bto[nb0] = bump; btl[nb0] = tlens[k] 1141 g[47] = nb0 + 1; bump = bump + tlens[k] + 1 1142 } 1143 } 1144 } 1145 k = k + 1 1146 } 1147 } 1148 c = c + 1 1149 } 1150 var j: i64 = 0 1151 while j < ttc[p] { 1152 if g[47] < 8 { 1153 let ti: i64 = tts[p] + j 1154 if db_in_question(g, tnb, tto[ti], ttl[ti], 0) == 0 { 1155 var dup2: i64 = 0 1156 var b2: i64 = 0 1157 while b2 < g[47] { if qs_tok_eq2(tnb, tto[ti], ttl[ti], btb, bto[b2], btl[b2])==1 { dup2 = 1 } b2 = b2 + 1 } 1158 if dup2 == 0 { 1159 var w2: i64 = 0 1160 while w2 < ttl[ti] { btb[bump+w2] = tnb[tto[ti]+w2]; w2 = w2 + 1 } 1161 let nb1: i64 = g[47] 1162 bto[nb1] = bump; btl[nb1] = ttl[ti] 1163 g[47] = nb1 + 1; bump = bump + ttl[ti] + 1 1164 } 1165 } 1166 } 1167 j = j + 1 1168 } 1169 return g[47] 1170} 1171 1172// best sentence index overall (by hits*2 + para title hits, tiebreak earlier); -1 if none 1173func db_best_sentence(g: *i64) -> i64 { 1174 let shit: *i64 = g[39] as *i64 1175 let thit: *i64 = g[40] as *i64 1176 let sp: *i64 = g[18] as *i64 1177 var best: i64 = 0-1 1178 var bs: i64 = 0-1 1179 var s: i64 = 0 1180 while s < g[19] { 1181 let sc: i64 = 2*shit[s] + thit[sp[s]] 1182 if sc > bs { bs = sc; best = s } 1183 s = s + 1 1184 } 1185 return best 1186} 1187 1188// best sentence within para p, scoring question-hits*2 + bridge-hits 1189func db_best_sentence_in(g: *i64, p: i64) -> i64 { 1190 let nb: *u8 = g[20] as *u8 1191 let tko: *i64 = g[23] as *i64 1192 let tkl: *i64 = g[24] as *i64 1193 let tks: *i64 = g[25] as *i64 1194 let tkc: *i64 = g[26] as *i64 1195 let sp: *i64 = g[18] as *i64 1196 let shit: *i64 = g[39] as *i64 1197 let btb: *u8 = g[44] as *u8 1198 let bto: *i64 = g[45] as *i64 1199 let btl: *i64 = g[46] as *i64 1200 var best: i64 = 0-1 1201 var bs: i64 = 0-1 1202 var s: i64 = 0 1203 while s < g[19] { 1204 if sp[s] == p { 1205 var bh: i64 = 0 1206 var k: i64 = 0 1207 while k < g[47] { 1208 var found: i64 = 0 1209 var j: i64 = 0 1210 while j < tkc[s] { 1211 if found == 0 { 1212 let ti: i64 = tks[s] + j 1213 if qs_tok_eq2(nb, tko[ti], tkl[ti], btb, bto[k], btl[k]) == 1 { found = 1 } 1214 } 1215 j = j + 1 1216 } 1217 bh = bh + found 1218 k = k + 1 1219 } 1220 let sc: i64 = 2*shit[s] + bh 1221 if sc > bs { bs = sc; best = s } 1222 } 1223 s = s + 1 1224 } 1225 return best 1226} 1227 1228// gold recall at 2: how many gold titles are in {pa,pb}, permille of ngt 1229func db_recall2(g: *i64, pa: i64, pb: i64) -> i64 { 1230 let gtb: *u8 = g[7] as *u8 1231 let gto: *i64 = g[8] as *i64 1232 let gtl: *i64 = g[9] as *i64 1233 let ptb: *u8 = g[11] as *u8 1234 let pto: *i64 = g[12] as *i64 1235 let ptl: *i64 = g[13] as *i64 1236 if g[10] == 0 { return 0 } 1237 var hit: i64 = 0 1238 var gsel: i64 = 0 1239 while gsel < g[10] { 1240 let gt: *u8 = (gtb as i64 + gto[gsel]) as *u8 1241 var m: i64 = 0 1242 var p: i64 = pa 1243 var round: i64 = 0 1244 while round < 2 { 1245 if p >= 0 { 1246 let pt: *u8 = (ptb as i64 + pto[p]) as *u8 1247 if gtl[gsel] == ptl[p] { 1248 var eq: i64 = 1 1249 var w: i64 = 0 1250 while w < gtl[gsel] { if gt[w] != pt[w] { eq = 0 } w = w + 1 } 1251 if eq == 1 { m = 1 } 1252 } 1253 } 1254 p = pb 1255 round = round + 1 1256 } 1257 hit = hit + m 1258 gsel = gsel + 1 1259 } 1260 return (1000*hit)/g[10] 1261} 1262 1263// top para by psc excluding skip; -1 if none 1264func db_top_para(g: *i64, skip: i64) -> i64 { 1265 let psc: *i64 = g[42] as *i64 1266 var best: i64 = 0-1 1267 var bs: i64 = 0-K_MAGIC_1000000 1268 var p: i64 = 0 1269 while p < g[14] { 1270 if p != skip { 1271 if psc[p] > bs { bs = psc[p]; best = p } 1272 } 1273 p = p + 1 1274 } 1275 return best 1276} 1277 1278// (engine only -- main lives in nx_qabench.nx; shared benchmark engine extracted from nx_drbench)