code wiki / _hdl_build / nx_connect_fair_rank.nx

nx_connect_fair_rank.nx source

↩ module page · 105 lines · 6040 B

1// nx_connect_fair_rank.nx -- CONNECT capability: FAIRNESS-BY-CONSTRUCTION ranking (the CIQ roadmap's #1 2// vision build; incumbents score 0 here -- popularity-biased ranking -> paid boosts -> rich-get-richer). 3// This is a REAL, principled exposure-fair re-ranker: each round we recommend the top-S candidates, but 4// the FAIR policy discounts each candidate's relevance by the attention it has already received 5// (score = quality*SCALE/(exposure+1)), so exposure rotates to relevant-but-under-shown profiles instead 6// of concentrating on a fixed few. The MEASURED head-to-head proves the exceed, BY CONSTRUCTION: 7// - INCUMBENT (popularity): rank by pure quality every round -> the same top-S monopolize exposure. 8// - NISHI (fair): rank by exposure-discounted quality -> exposure spreads. 9// We measure exposure inequality via the integer Gini coefficient (permil) for BOTH, plus the relevance 10// delivered (sum of shown qualities). GATE (no-float, named thresholds): FAIR Gini must be < half the 11// popularity Gini (a real fairness exceed), AND FAIR must retain >= RELEVANCE_FLOOR_PCT of popularity's 12// relevance (we do not tank quality to get fairness). 100% sovereign, integer-exact. license_tier: ORIGINAL expect_exit: 0 13import "nx_syscalls.nx" 14 15const FR_M: i64 = 8 // candidate profiles 16const FR_K: i64 = 40 // recommendation rounds 17const FR_S: i64 = 3 // slots shown per round 18const FR_GINI_HALVE: i64 = 2 // FAIR Gini must be < POP Gini / FR_GINI_HALVE (fairness exceed margin) 19const FR_REL_FLOOR_PCT: i64 = 70 // FAIR relevance must be >= this % of POP relevance 20 21func rw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 22func rn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 } 23 24// integer Gini coefficient in permil: (Σi Σj |xi-xj|) * 1000 / (2 n Σx). 0=perfectly equal, 1000=maximally unequal. 25func gini_permil(x: *i64, n: i64) -> i64 { 26 var total: i64 = 0; var i: i64 = 0 27 while i < n { total = total + x[i]; i = i + 1 } 28 if total <= 0 { return 0 } 29 var sumabs: i64 = 0; i = 0 30 while i < n { var j: i64 = 0; while j < n { var d: i64 = x[i] - x[j]; if d < 0 { d = 0 - d } sumabs = sumabs + d; j = j + 1 } i = i + 1 } 31 return (sumabs * 1000) / (2 * n * total) 32} 33 34// run K rounds of "show top-S"; policy fair=1 uses exposure-discounted score, fair=0 pure quality. 35// fills expo[] (per-candidate exposure) and returns total relevance delivered. 36func simulate(q: *i64, expo: *i64, fair: i64) -> i64 { 37 var i: i64 = 0 38 while i < FR_M { expo[i] = 0; i = i + 1 } 39 var rel: i64 = 0 40 let picked: *i64 = sys_mmap(8 * FR_M) as *i64 41 var r: i64 = 0 42 while r < FR_K { 43 var p: i64 = 0 44 while p < FR_M { picked[p] = 0; p = p + 1 } 45 var s: i64 = 0 46 while s < FR_S { 47 var best: i64 = 0 - 1 48 var bestsc: i64 = 0 - 1 49 var c: i64 = 0 50 while c < FR_M { 51 if picked[c] == 0 { 52 var sc: i64 = q[c] * 1000 53 if fair == 1 { sc = (q[c] * 1000) / (expo[c] + 1) } 54 if sc > bestsc { bestsc = sc; best = c } 55 } 56 c = c + 1 57 } 58 picked[best] = 1 59 expo[best] = expo[best] + 1 60 rel = rel + q[best] 61 s = s + 1 62 } 63 r = r + 1 64 } 65 return rel 66} 67 68func main() -> i64 { 69 // candidate relevance/quality scores (fixed, descending = a realistic popularity spread). 70 let q: *i64 = sys_mmap(8 * FR_M) as *i64 71 q[0]=95; q[1]=88; q[2]=80; q[3]=72; q[4]=65; q[5]=55; q[6]=40; q[7]=30 72 73 let expop: *i64 = sys_mmap(8 * FR_M) as *i64 74 let expfair: *i64 = sys_mmap(8 * FR_M) as *i64 75 let rel_pop: i64 = simulate(q, expop, 0) 76 let rel_fair: i64 = simulate(q, expfair, 1) 77 let g_pop: i64 = gini_permil(expop, FR_M) 78 let g_fair: i64 = gini_permil(expfair, FR_M) 79 80 rw("=== nx_connect_fair_rank -- fairness-by-construction ranking (measured head-to-head) ===\n" as *u8) 81 rw("scenario: " as *u8); rn(FR_M); rw(" candidates, " as *u8); rn(FR_K); rw(" rounds, top-" as *u8); rn(FR_S); rw(" shown/round\n" as *u8) 82 rw("INCUMBENT (popularity rank): exposure=[" as *u8); var i: i64=0; while i<FR_M { if i>0 { rw("," as *u8) } rn(expop[i]); i=i+1 } rw("]\n" as *u8) 83 rw("NISHI (exposure-fair rank): exposure=[" as *u8); i=0; while i<FR_M { if i>0 { rw("," as *u8) } rn(expfair[i]); i=i+1 } rw("]\n" as *u8) 84 rw("exposure Gini (permil; lower=fairer): popularity=" as *u8); rn(g_pop); rw(" fair=" as *u8); rn(g_fair); rw("\n" as *u8) 85 rw("relevance delivered (sum shown quality): popularity=" as *u8); rn(rel_pop); rw(" fair=" as *u8); rn(rel_fair) 86 var rel_pct: i64 = 0; if rel_pop > 0 { rel_pct = (rel_fair * 100) / rel_pop } 87 rw(" (fair retains " as *u8); rn(rel_pct); rw("% of popularity relevance)\n" as *u8) 88 89 // MEASURED exceed gate 90 var fairness_exceed: i64 = 0 91 if g_fair * FR_GINI_HALVE < g_pop { fairness_exceed = 1 } // fair Gini < pop Gini / 2 92 var relevance_ok: i64 = 0 93 if rel_fair * 100 >= rel_pop * FR_REL_FLOOR_PCT { relevance_ok = 1 } 94 95 rw("--- gate --- fairness_exceed(fair_gini < pop_gini/" as *u8); rn(FR_GINI_HALVE); rw(")=" as *u8); if fairness_exceed==1 { rw("PASS" as *u8) } else { rw("FAIL" as *u8) } 96 rw(" relevance_retained(>=" as *u8); rn(FR_REL_FLOOR_PCT); rw("%)=" as *u8); if relevance_ok==1 { rw("PASS" as *u8) } else { rw("FAIL" as *u8) } 97 rw("\n" as *u8) 98 99 if fairness_exceed == 1 { if relevance_ok == 1 { 100 rw("FAIRRANKGATE verdict=GREEN (Nishi EXCEEDS popularity ranking on exposure-fairness at retained relevance, BY CONSTRUCTION)\n" as *u8) 101 sys_exit(0); return 0 102 } } 103 rw("FAIRRANKGATE verdict=RED\n" as *u8) 104 sys_exit(1); return 1 105}