nx_sketch_varopt.nx
buildroot/runtime/nx_sketch_varopt.nx
about
sketch_varopt.nx -- Weighted reservoir sampling (Efraimidis-Spirakis 2006 / Cohen 2011).
Given a stream of (item, weight) arrivals, maintain a reservoir
of size k such that the inclusion probability is proportional
to weight. Heavy items more likely to be retained than light.
COMPLETES THE SAMPLING FAMILY:
- Reservoir (Vitter 1985): uniform sampling, equal weights.
- VarOpt (here): weighted sampling.
ALGORITHM (A-ExpJ variant of A-Res):
For each (item, w): generate key = u^(1/w) where u ~ Uniform(0,1).
Keep top-k items by key (descending). Higher w concentrates the
key near 1; lower w near 0. Inclusion probability is provably
proportional to w under reasonable conditions.
INTEGER-FIXED-POINT APPROXIMATION (because C anchor lacks f64,
but we want the sibling to be Wheeler-comparable against C):
- u_31 = LCG draw in (0, 2^31)
- approx_log2_u = bitlen(u_31) - 31 // in [-30, 0]
- approx_log_key = (approx_log2_u * 1_000_000) / w
- key = approx_log_key
Higher weight pulls key closer to 0; lower weight pulls more
negative. Sort descending by key; top-k by key are retained.
PROPERTIES UNDER THE APPROXIMATION:
- Heavy items (w >> 1) get keys near 0 (large in descending sort).
- Light items (w = 1) get keys uniformly distributed in
[-30_000_000, 0], breaking ties uniformly.
- Quality degrades for very large weight variance. v2 will swap
in a finer-grained log approximation.
LOSSLESS-LANGUAGE DISCIPLINE: per-item retain probability declared
in the typed envelope as conf_ppb proportional to weight_total /
weight_sum_sampled.
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_sketch_types.nx
imported by: nobody (leaf or entry point)
structs
| 53 | struct VoptEntry |
| 59 | struct VarOpt |
consts
| 46 | const NX_VOPT_K_MIN: i64 = 4 |
| 47 | const NX_VOPT_K_MAX: i64 = 100000 |
| 49 | const NX_VOPT_LCG_A: i64 = 1103515245 |
| 50 | const NX_VOPT_LCG_C: i64 = 12345 |
| 51 | const NX_VOPT_LCG_MOD: i64 = 0x7FFFFFFF |
functions
| 70 | func nx_varopt_alloc(k: i64, seed: i64) -> *VarOpt calls 1: sys_mmap |
| 85 | func nx_varopt_rng_next(v: *VarOpt) -> i64 called by 1: nx_varopt_key |
| 95 | func nx_varopt_bitlen(x: i64) -> i64 |
| 111 | func nx_varopt_key(v: *VarOpt, weight: i64) -> i64 |
| 122 | func nx_varopt_entry_at(v: *VarOpt, i: i64) -> *VoptEntry |
| 132 | func nx_varopt_add(v: *VarOpt, item: i64, weight: i64) -> i64 |
| 199 | func nx_varopt_n_items(v: *VarOpt) -> i64 |
| 203 | func nx_varopt_total_seen(v: *VarOpt) -> i64 |
| 207 | func nx_varopt_total_weight(v: *VarOpt) -> i64 |
| 215 | func nx_varopt_weighted_mean(v: *VarOpt) -> i64 |
| 234 | func nx_varopt_query_mean(v: *VarOpt) -> *ApproxI64 |
| 243 | func nx_varopt_memory_bytes(v: *VarOpt) -> i64 |