code wiki / _hdl_build / nx_vec_fuse.nx

nx_vec_fuse.nx source

↩ module page · 44 lines · 2312 B

1// nx_vec_fuse.nx -- R-VEC-5 of the onsite-search S-class ladder: SOVEREIGN hybrid-search rank fusion (LIBRARY). 2// THE felt S-class jump: lexical BM25 nails exact terms, vector cosine (R-VEC-0/1) nails paraphrase -- fusing 3// their two ranked lists gets the best of both. "Data fusion in information retrieval combines results from 4// multiple search systems or retrieval models" (cited srch_ir.raw). 5// 6// Reciprocal Rank Fusion (Cormack/Clarke/Buettcher 2009): score(d) = SUM_lists 1/(k + rank_i(d)), k=60 canonical; 7// sort docs by descending score. The defining behavior: a doc ranked MODERATELY in BOTH lists outranks a doc 8// ranked #1 in only ONE -- agreement across retrievers beats a single strong signal. 9// 10// NO-FLOAT (operator doctrine): the reciprocal is computed in fixed point, weight = SCALE/(k+rank), SCALE=1e6. 11// Determinism: strict-greater selection sort keeps ascending doc-id order on ties. 12// 13// exports: vr_rrf_w, vr_fuse_add, vr_fuse_rank. license_tier: ORIGINAL 14import "nx_syscalls.nx" 15 16const VF_K: i64 = 60 // canonical RRF rank constant (Cormack et al. 2009) 17const VF_SCALE: i64 = 1000000 // fixed-point scale for the reciprocal (no-float) 18 19// reciprocal-rank weight for a 1-based rank: SCALE/(k+rank) 20func vr_rrf_w(rank: i64) -> i64 { return VF_SCALE / (VF_K + rank) } 21 22// accumulate one ranked list into score[] (indexed by doc id). list[r] = doc id at rank r+1 (0-based r). 23func vr_fuse_add(score: *i64, list: *i64, n: i64) -> i64 { 24 var r: i64 = 0 25 while r < n { let id: i64 = list[r]; score[id] = score[id] + vr_rrf_w(r + 1); r = r + 1 } 26 return 0 27} 28 29// rank doc ids [0,maxdoc) with score>0 by descending score into out_ids; returns count. selection sort (small N, 30// or top-K shortlist in production). strict > => stable ascending-id tie order => deterministic. 31func vr_fuse_rank(score: *i64, maxdoc: i64, out_ids: *i64) -> i64 { 32 var m: i64 = 0 33 var i: i64 = 0 34 while i < maxdoc { if score[i] > 0 { out_ids[m] = i; m = m + 1 } i = i + 1 } 35 var a: i64 = 0 36 while a < m { 37 var best: i64 = a 38 var b: i64 = a + 1 39 while b < m { if score[out_ids[b]] > score[out_ids[best]] { best = b } b = b + 1 } 40 let tmp: i64 = out_ids[a]; out_ids[a] = out_ids[best]; out_ids[best] = tmp 41 a = a + 1 42 } 43 return m 44}