sketch_reservoir.nx
buildroot/runtime/sketch_reservoir.nx
about
sketch_reservoir.nx -- Vitter reservoir sampling + quantile.
Vitter 1985 "Random Sampling with a Reservoir." Algorithm R:
maintain a cap-element reservoir. For the i-th input value
(1-indexed):
- if i <= cap: items[i-1] = value
- else: draw j uniformly from [1, i]; if j <= cap,
items[j-1] = value (else discard)
At end of stream, items[] holds a UNIFORMLY RANDOM sample of
the input. Per-quantile estimation: sort items, look up the
floor(p * n_items)-th value. Hoeffding bound on quantile from
k samples: error ~ sqrt(ln(1/delta) / (2k)) ~ 1/sqrt(k) at fixed
delta. We declare 1/sqrt(cap) as the rank_error envelope.
OPENS TWO ROADMAP AXES SIMULTANEOUSLY:
- Sampling family (Vitter / VarOpt -- DataSketches ships both;
this is the first axis primitive)
- Quantile family (rank_error envelope; T-Digest / KLL ship
this same family with tighter bounds; reservoir is the
SIMPLEST sample-based quantile)
LCG-based PRNG for deterministic reproducibility. Per the
lossless-language discipline (doc 20): randomized sketches MUST
declare their RNG state in the typed envelope so two runs with
the same seed produce bit-identical output.
dependencies 2 imports · 3 importers
imports: syscalls.nxsketch_types.nx
imported by: sketch_kll_vs_reservoir_bench.nxsketch_reservoir_test.nxsketch_varopt_vs_reservoir_biased_bench.nx
structs
| 39 | struct Reservoir { |
consts
| 31 | const NX_RES_CAP_MIN: i64 = 4 |
| 32 | const NX_RES_CAP_MAX: i64 = 1000000 |
| 35 | const NX_RES_LCG_A: i64 = 1103515245 |
| 36 | const NX_RES_LCG_C: i64 = 12345 |
| 37 | const NX_RES_LCG_MOD: i64 = 0x7FFFFFFF |
functions
| 47 | func nx_reservoir_alloc(cap: i64, seed: i64) -> *Reservoir { |
| 62 | func nx_reservoir_rng_next(r: *Reservoir) -> i64 {
called by 1: nx_reservoir_rng_below |
| 69 | func nx_reservoir_rng_below(r: *Reservoir, n: i64) -> i64 { |
| 74 | func nx_reservoir_add(r: *Reservoir, value: i64) -> i64 { |
| 91 | func nx_reservoir_sort(r: *Reservoir) -> i64 { |
| 121 | func nx_reservoir_quantile(r: *Reservoir, p_milli: i64) -> i64 { |
| 132 | func nx_reservoir_rank(r: *Reservoir, value: i64) -> i64 { |
| 159 | func nx_reservoir_rank_error_ppb(cap: i64) -> i64 {
called by 1: nx_reservoir_query_quantile |
| 169 | func nx_reservoir_query_quantile(r: *Reservoir, p_milli: i64) -> *ApproxI64 { |
| 180 | func nx_reservoir_memory_bytes(r: *Reservoir) -> i64 {
called by 1: main |