code wiki / (root) / nx_bloom_capacity.nx

nx_bloom_capacity.nx source

↩ module page · 84 lines · 3356 B

1// nx_bloom_capacity.nx -- FPR-profile constructor on top of nx_bloom. 2// 3// At the call site you usually know "how many items" and "what FPR is 4// acceptable", not (m, k). This wraps nx_bloom.bloom_new to derive 5// (m, k) from (n_items, fpr_profile). 6// 7// genealogy_id: bloom_1970 8// lineage_id: construction_helper 9 10// nx_safety_envelope: 11// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 12// sil_target: SIL1 13// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 14// verdict: NOT_YET_EVALUATED 15 16import "nx_syscalls.nx" 17import "nx_tier.nx" 18import "nx_bloom.nx" 19const NX_MAGIC_1024: i64 = 1024 20 21// ===== capacity profiles ============================================= 22// Pre-computed (bits-per-item Q10, k) for the standard FPR breakpoints. 23 24const NX_BLOOM_FPR_10PCT_BITS_Q10: nx_int = 4905 25const NX_BLOOM_FPR_10PCT_K: nx_int = 3 26const NX_BLOOM_FPR_5PCT_BITS_Q10: nx_int = 6390 27const NX_BLOOM_FPR_5PCT_K: nx_int = 4 28const NX_BLOOM_FPR_1PCT_BITS_Q10: nx_int = 9817 29const NX_BLOOM_FPR_1PCT_K: nx_int = 7 30const NX_BLOOM_FPR_P1PCT_BITS_Q10: nx_int = 14722 31const NX_BLOOM_FPR_P1PCT_K: nx_int = 10 32const NX_BLOOM_FPR_P01PCT_BITS_Q10: nx_int = 19628 33const NX_BLOOM_FPR_P01PCT_K: nx_int = 13 34 35const NX_BLOOM_PROFILE_10PCT: nx_int = 0 36const NX_BLOOM_PROFILE_5PCT: nx_int = 1 37const NX_BLOOM_PROFILE_1PCT: nx_int = 2 38const NX_BLOOM_PROFILE_P1PCT: nx_int = 3 39const NX_BLOOM_PROFILE_P01PCT: nx_int = 4 40 41// ===== bit-arithmetic helpers ======================================== 42 43func nx_bloom_next_pow2(n: nx_int) -> nx_int { 44 var p: nx_int = 8 45 while p < n { p = p * 2 } 46 return p 47} 48 49func nx_bloom_profile_bits_q10(profile: nx_int) -> nx_int { 50 if profile == NX_BLOOM_PROFILE_10PCT { return NX_BLOOM_FPR_10PCT_BITS_Q10 } 51 if profile == NX_BLOOM_PROFILE_5PCT { return NX_BLOOM_FPR_5PCT_BITS_Q10 } 52 if profile == NX_BLOOM_PROFILE_P1PCT { return NX_BLOOM_FPR_P1PCT_BITS_Q10 } 53 if profile == NX_BLOOM_PROFILE_P01PCT { return NX_BLOOM_FPR_P01PCT_BITS_Q10 } 54 return NX_BLOOM_FPR_1PCT_BITS_Q10 55} 56 57func nx_bloom_profile_k(profile: nx_int) -> nx_int { 58 if profile == NX_BLOOM_PROFILE_10PCT { return NX_BLOOM_FPR_10PCT_K } 59 if profile == NX_BLOOM_PROFILE_5PCT { return NX_BLOOM_FPR_5PCT_K } 60 if profile == NX_BLOOM_PROFILE_P1PCT { return NX_BLOOM_FPR_P1PCT_K } 61 if profile == NX_BLOOM_PROFILE_P01PCT { return NX_BLOOM_FPR_P01PCT_K } 62 return NX_BLOOM_FPR_1PCT_K 63} 64 65func nx_bloom_target_bits(n_items: nx_int, profile: nx_int) -> nx_int { 66 let bits_per_q10: nx_int = nx_bloom_profile_bits_q10(profile) 67 return (n_items * bits_per_q10) / NX_MAGIC_1024 68} 69 70func nx_bloom_byte_cost(n_items: nx_int, profile: nx_int) -> nx_int { 71 let target_bits: nx_int = nx_bloom_target_bits(n_items, profile) 72 let cap_bits: nx_int = nx_bloom_next_pow2(target_bits) 73 return cap_bits / 8 74} 75 76// ===== construction =================================================== 77 78func nx_bloom_new_for_capacity(n_items: nx_int, profile: nx_int) -> *Bloom { 79 if n_items < 1 { return 0 as *Bloom } 80 let target_bits: nx_int = nx_bloom_target_bits(n_items, profile) 81 let cap_bits: nx_int = nx_bloom_next_pow2(target_bits) 82 let k: nx_int = nx_bloom_profile_k(profile) 83 return bloom_new(cap_bits, k) 84}