code wiki / (root) / nx_sketch_linear_counter.nx

nx_sketch_linear_counter.nx

buildroot/runtime/nx_sketch_linear_counter.nx

7684 B229 linesdepth 3pulls 4 transitivereach 0 importersview sourcekind sketch/demotopic sketch
docsdependenciesstructsconstsfunctions

about

sketch_linear_counter.nx -- Linear Counting (Whang-Vander Zanden 1990). Pre-HLL cardinality primitive. Simpler than HLL; sometimes more accurate at small cardinalities (n < m/10). Used by Google's BigQuery as the small-cardinality fallback. ALGORITHM: bitmap of m bits, all zero initially. add(x): set bit at index = hash(x) % m estimate(n) = -m * ln(zeros / m) where zeros = count of unset bits at query time. Derivation: if items are hashed uniformly to m buckets and we observe `zeros` empty buckets, then by occupancy theory the true count n satisfies E[zeros] = m * (1 - 1/m)^n ≈ m * e^(-n/m) inverting: n ≈ -m * ln(zeros / m). CAPABILITIES (vs HLL): - LC: accurate at n < m (uses bitmap directly) - HLL: accurate at n >> m (uses harmonic mean of register maxima) Together: BigQuery + others run LC for n < threshold, HLL for n >=. INTEGER-FIXED-POINT IMPLEMENTATION: ln(zeros/m) approximated via tabulated values keyed on (zeros*100)/m (percentage of empty bits, in [0, 100]). Table values are -ln(p/100) * 1_000_000 in PPM (negative of -log so positive). MEMORY: m bits = m/8 bytes. For m=8192: 1 KB. LOSSLESS-LANGUAGE DISCIPLINE: nx_lc_query returns ApproxI64 with NX_ENV_REL_STDDEV. Standard error per Whang 1990: sqrt(e^t - t - 1) / t where t = n/m (load). Tabulated by load class.

dependencies 3 imports · 0 importers

nx_syscalls.nx nx_murmur3.nx nx_sketch_types.nx nx_sketch_linear_counter.nx

imports: nx_syscalls.nxnx_murmur3.nxnx_sketch_types.nx

imported by: nobody (leaf or entry point)

structs

48struct LinearCounter

consts

45const NX_LC_MIN_BITS: i64 = 64
46const NX_LC_MAX_BITS: i64 = 16777216 // 2 MB cap

functions

57func nx_lc_is_pow2(n: i64) -> i64
called by 1: nx_lc_alloc
63func nx_lc_alloc(m_bits: i64, seed: i64) -> *LinearCounter
called by 1: nx_lc_merge calls 2: nx_lc_is_pow2sys_mmap
83func nx_lc_set_bit(lc: *LinearCounter, bit_idx: i64) -> i64
called by 1: nx_lc_add
90func nx_lc_get_bit(lc: *LinearCounter, bit_idx: i64) -> i64
98func nx_lc_add(lc: *LinearCounter, key: *u8, len: i64) -> i64
110func nx_lc_popcount_byte(b: i64) -> i64
called by 1: nx_lc_zeros
120func nx_lc_zeros(lc: *LinearCounter) -> i64
called by 1: nx_lc_estimate calls 1: nx_lc_popcount_byte
148func nx_lc_neg_ln_ppm(zeros_x_100: i64, m: i64) -> i64
called by 1: nx_lc_estimate
173func nx_lc_estimate(lc: *LinearCounter) -> i64
187func nx_lc_stddev_rel_ppb(load_pct: i64) -> i64
called by 1: nx_lc_query
199func nx_lc_query(lc: *LinearCounter) -> *ApproxI64
214func nx_lc_merge(a: *LinearCounter, b: *LinearCounter) -> *LinearCounter
calls 1: nx_lc_alloc
227func nx_lc_memory_bytes(lc: *LinearCounter) -> i64