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}