sketch_thompson.nx
buildroot/runtime/sketch_thompson.nx
about
sketch_thompson.nx -- Thompson Sampling (Bernoulli-Beta bandit).
Thompson 1933 / Russo-Van Roy 2018 modern treatment. Bayesian
alternative to UCB1 (sketch_ucb1.nx): instead of a confidence-
bound upper-bonus, sample from each arm's posterior and pick the
argmax. Empirically tighter regret on stochastic Bernoulli arms;
matches UCB asymptotic bounds.
CORE OPERATION:
For arm i with s_i successes, f_i failures:
posterior ~ Beta(s_i + 1, f_i + 1) (uniform Beta(1,1) prior)
Per decision:
for each arm i: sample x_i ~ Beta(s_i+1, f_i+1)
pull arg max x_i
SAMPLING WITHOUT f64 (the technical chokepoint):
Beta(α, β) for integer α, β equals the distribution of the α-th
smallest of α + β − 1 uniforms in [0, 1]. (David-Nagaraja
"Order Statistics", standard textbook result.) Exact, no log
or special functions needed. Cost O(α + β) per sample.
HYBRID FOR LARGE (s + f):
- exact order statistic when s + f + 1 ≤ NX_THOMPSON_EXACT_MAX
- Normal approximation when larger (cost O(1) instead of O(n)).
Beta(α, β) ≈ N(μ, σ²) with μ = α/(α+β), σ² = μ(1−μ)/(α+β+1).
Normal sampled via Irwin-Hall sum of 12 uniforms (CLT).
Both paths produce Q14 fixed-point samples in [0, Q14] = [0, 1].
EXTENDS NISHI-SUBSTRATE BEYOND DATASKETCHES (DS is summarization-
only; bandits live elsewhere). Composes against sketch_ucb1 +
sketch_epsilon_greedy as the bandit-family triple.
LOSSLESS-LANGUAGE DISCIPLINE: nx_thompson_query returns
ApproxI64 with NX_ENV_REL_STDDEV = 1/sqrt(count_i + 1), matching
posterior shrinkage as samples accumulate.
dependencies 2 imports · 2 importers
imports: syscalls.nxsketch_types.nx
imported by: sketch_thompson_test.nxsketch_thompson_vs_ucb1_bench.nx
structs
| 51 | struct Thompson |
consts
| 41 | const NX_THOMPSON_ARMS_MIN: i64 = 2 |
| 42 | const NX_THOMPSON_ARMS_MAX: i64 = 256 |
| 43 | const NX_THOMPSON_Q14: i64 = 16384 |
| 44 | const NX_THOMPSON_EXACT_MAX: i64 = 64 // cutoff for order-stat sampler |
| 47 | const NX_THOMPSON_LCG_A: i64 = 1103515245 |
| 48 | const NX_THOMPSON_LCG_C: i64 = 12345 |
| 49 | const NX_THOMPSON_LCG_MOD: i64 = 0x7FFFFFFF |
functions
| 62 | func nx_thompson_alloc(n_arms: i64, seed: i64) -> *Thompson |
| 87 | func nx_thompson_rng_next(t: *Thompson) -> i64 called by 1: nx_thompson_uniform_q14 |
| 94 | func nx_thompson_uniform_q14(t: *Thompson) -> i64 |
| 101 | func nx_thompson_isqrt(x: i64) -> i64 |
| 123 | func nx_thompson_sort_scratch(t: *Thompson, n: i64) -> i64 called by 1: nx_thompson_sample_order_stat |
| 145 | func nx_thompson_sample_order_stat(t: *Thompson, alpha: i64, n_uniform: i64) -> i64 |
| 162 | func nx_thompson_clt_normal_q14(t: *Thompson) -> i64 |
| 176 | func nx_thompson_sample_q14(t: *Thompson, arm: i64) -> i64 |
| 205 | func nx_thompson_select(t: *Thompson) -> i64 |
| 227 | func nx_thompson_update(t: *Thompson, arm: i64, reward: i64) -> i64 |
| 244 | func nx_thompson_successes_for(t: *Thompson, arm: i64) -> i64 called by 1: main |
| 248 | func nx_thompson_failures_for(t: *Thompson, arm: i64) -> i64 called by 1: main |
| 253 | func nx_thompson_posterior_mean_ppm(t: *Thompson, arm: i64) -> i64 |
| 261 | func nx_thompson_best_arm(t: *Thompson) -> i64 |
| 278 | func nx_thompson_query(t: *Thompson, arm: i64) -> *ApproxI64 |
| 290 | func nx_thompson_memory_bytes(t: *Thompson) -> i64 called by 1: main |