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}