mixle.task.bandit module¶
Multi-armed bandits: pick-an-arm / observe-a-reward loops with posterior policies.
Where this sits in mixle: mixle.doe’s Bayesian-optimization acquisitions (UCB and
Thompson draws over a surrogate posterior) are the continuous-design cousins; this module is the
small DISCRETE-arm loop for serving-time decisions – which teacher to query, which prompt
variant, which data source, which model tier answers when calibrated confidence
(mixle.task.router.Router) is unavailable or costs drift and the choice must be LEARNED
from observed outcomes instead.
Policies (shared surface: select() -> arm, update(arm, reward),
batch_update(arms, rewards), pulls, means):
ThompsonBernoulli– Beta-Bernoulli conjugate Thompson sampling; rewards in [0, 1] (clicks, agreement flags, pass/fail, or any fractional credit).ThompsonGaussian– Normal-Inverse-Gamma conjugate Thompson sampling; unbounded real rewards with unknown variance (latencies, margins, log-likelihood gains).UCB1– the deterministic optimism baseline (Auer et al.); no randomness at all, useful when reproducible selection matters more than Bayesian credit assignment.EstimatorBandit– Thompson sampling with ARBITRARY mixle reward models via the online bootstrap (Poisson(1) replicate weights, Eckles & Kaptein): any estimator/accumulator pair – Gamma service times, categorical outcomes scored by a utility, mixtures for multi-modal rewards – becomes an arm with NO conjugate math, riding the same accumulator machinery the rest of mixle estimates with.
Every policy owns a seeded numpy.random.RandomState and is deterministic given it. Conjugate
and UCB1 updates commute, so batch_update (delayed/batched feedback, the streaming pattern
used across mixle) is exactly the sequential replay of its pairs.
- class EstimatorBandit(estimators, *, n_boot=32, mean_fn=None, mc_draws=64, seed=None)[source]
Bases:
_BanditBaseThompson sampling for ARBITRARY mixle reward models, via the online bootstrap.
Each arm keeps
n_bootaccumulator replicates of its estimator;updateadds the reward to every replicate with an independent Poisson(1) weight (Eckles & Kaptein’s online bootstrap), so the replicate ensemble approximates the sampling distribution of the fitted reward model with no conjugate structure required.selectplays each arm once, then draws one non-empty replicate per arm, fits it (estimator.estimate), scores it withmean_fn(default: Monte-Carlo mean ofestimate.sampler(...).sample(mc_draws)), and plays the argmax – posterior-sample-then-maximize, exactly Thompson’s rule with a bootstrap posterior.estimatorsis one mixle ParameterEstimator per arm (Gamma for waiting times, Gaussian for margins, a mixture for multi-modal rewards – anything with the accumulator contract).
- class ThompsonBernoulli(n_arms, *, alpha=1.0, beta=1.0, seed=None)[source]
Bases:
_BanditBaseBeta-Bernoulli Thompson sampling. Rewards live in [0, 1]; fractional rewards contribute fractional pseudo-counts (the standard Bernoulli-moment update).
- class ThompsonGaussian(n_arms, *, mu0=0.0, kappa0=1.0e-2, alpha0=0.5, beta0=0.5, seed=None)[source]
Bases:
_BanditBaseNormal-Inverse-Gamma Thompson sampling: unknown mean AND variance per arm, so early optimism comes from honest posterior width rather than a tuned exploration constant.
- class UCB1(n_arms, *, c=1.0, seed=None)[source]
Bases:
_BanditBaseThe deterministic optimism baseline: play each arm once, then
argmax mean_k + c * sqrt(2 ln t / n_k). Ties break to the lowest index; with no randomness anywhere, two UCB1 runs on the same reward sequence are identical.