Thompson sampling balances exploring and exploiting by acting on a random draw from each arm's posterior. With a Beta(1, 1) prior per arm:
theta[a] ~ Beta(1 + successes[a], 1 + failures[a]) for every arm, in arm order.rng.random() < true_rates[arm], and update that arm's counts.Implement:
thompson(true_rates, n_rounds, rng): return (pulls, total_reward), where pulls[a] counts how often arm a was chosenregret(true_rates, pulls): the expected regret, n_rounds × best_rate − Σ pulls[a] × rate[a]epsilon_greedy(true_rates, n_rounds, rng, eps=0.1): for comparison. Each round, if rng.random() < eps pick rng.integers(len(arms)); otherwise pick the arm with the best observed mean (unpulled arms count as 0, ties: lowest index). Then draw the reward with rng.random() as above. Return (pulls, total_reward).