code wiki / (root) / sketch_ucb1.nx

sketch_ucb1.nx

buildroot/runtime/sketch_ucb1.nx

7290 B229 linesdepth 4pulls 4 transitivereach 2 importersview sourcekind sketch/demotopic sketch
docsdependenciesstructsconstsfunctions

about

sketch_ucb1.nx -- UCB1 multi-armed bandit (Auer-Cesa-Bianchi-Fischer 2002). Online-learning primitive. Given N "arms" (actions), select the best one over time while balancing EXPLORATION (try arms we haven't pulled) and EXPLOITATION (favor arms with high observed reward). UCB1 selection rule: score_i = mean_i + sqrt(2 * ln(N_total) / count_i) pull arg max score_i Where: mean_i = sum_reward_i / count_i (estimated value) sqrt(...) = exploration bonus (shrinks as count_i grows) Arms with count_i = 0 have score = +inf (must-pull first). PROVEN PROPERTIES (Auer 2002): regret bound: O(sqrt(K * N * ln(N))) where K = #arms, N = total pulls. Near-optimal for adversarial problems; optimal up to log factor for stochastic. USE CASES (extends NishiLang substrate beyond DataSketches scope): - A/B testing with multi-arm allocation (Bayesian alternative) - Recommendation with cold-start exploration - Hyperparameter tuning under budget constraints - Game AI move selection INTEGER-FIXED-POINT IMPLEMENTATION: - rewards scaled to PPM (0..1_000_000 = [0, 1.0]) - mean_i = sum_reward_ppm / count_i - ln(N) ≈ (bitlen(N) - 1) * 693147 / 1000 ppm (factor of ln(2)) - sqrt() via isqrt (Newton) - score_i in PPM LOSSLESS-LANGUAGE DISCIPLINE: nx_ucb_query returns ApproxI64 with NX_ENV_REL_STDDEV = 1/sqrt(count_i). Bandits are stochastic by nature; the envelope honestly declares estimation uncertainty.

dependencies 2 imports · 2 importers

syscalls.nx sketch_types.nx sketch_ucb1.nx sketch_thompson_vs_ucb1_bench.nx sketch_ucb1_test.nx

imports: syscalls.nxsketch_types.nx

imported by: sketch_thompson_vs_ucb1_bench.nxsketch_ucb1_test.nx

structs

48struct Ucb1 {

consts

43const NX_UCB_ARMS_MIN: i64 = 2
44const NX_UCB_ARMS_MAX: i64 = 10000
45const NX_UCB_LN2_PPM: i64 = 693147 // ln(2) * 1_000_000
46const NX_UCB_REWARD_MAX: i64 = 1000000 // 1.0 in PPM

functions

57func nx_ucb_alloc(n_arms: i64) -> *Ucb1 {
called by 2: mainmain
79func nx_ucb_isqrt(x: i64) -> i64 {
102func nx_ucb_bitlen(x: i64) -> i64 {
called by 1: nx_ucb_ln_ppm
114func nx_ucb_ln_ppm(n: i64) -> i64 {
called by 1: nx_ucb_score calls 1: nx_ucb_bitlen
133func nx_ucb_score(b: *Ucb1, arm: i64) -> i64 {
150func nx_ucb_select(b: *Ucb1) -> i64 {
called by 2: mainmain calls 1: nx_ucb_score
170func nx_ucb_update(b: *Ucb1, arm: i64, reward_ppm: i64) -> i64 {
called by 2: mainmain
183func nx_ucb_mean_ppm(b: *Ucb1, arm: i64) -> i64 {
189func nx_ucb_count(b: *Ucb1, arm: i64) -> i64 {
called by 1: main
194func nx_ucb_best_arm(b: *Ucb1) -> i64 {
called by 2: mainmain calls 1: nx_ucb_mean_ppm
213func nx_ucb_query(b: *Ucb1, arm: i64) -> *ApproxI64 {
227func nx_ucb_memory_bytes(b: *Ucb1) -> i64 {
called by 1: main