expected_information_gain returns 4.67x its own ln k ceiling #56

Closed
opened 2026-09-09 14:50:43 +00:00 by logaritmisk · 0 comments
Owner

src/acquisition.rs:166. The crate documents this bound as the sharpest test it has:

never_exceeds_the_entropy_of_the_outcome — the information gain from observing one of k outcomes cannot exceed ln k.

and records that an early prototype returned 4.77 nats, violating ln 2, and that the bound is what caught it. The bound is violated again now, by a different route.

Measured

Reproduced independently of the audit that found it:

mu    = (9.577887112129012, -14.114932828525696)
sigma = (0.00013250752658513438, 91.58669014092116)
beta  = 0.0003072355590130962, p_draw = 0

gain = 3.237828   ceiling ln 2 = 0.693147   ratio = 4.671

For contrast, ordinary parameters are fine:

mu=(25,25) sigma=(25/3,25/3) beta=25/6  ->  gain = 0.293899   ratio = 0.424

A 60 000-sample random sweep over mu ∈ ±100, sigma ∈ [1e-4, 1e2], beta ∈ [1e-4, 1e1] produced 1 073 violations. A three-team sweep produced 96 of 6 000.

Cause

Not in this function's own arithmetic. gain += probability * divergence is weighted by outcome_distribution, which in this regime returns probabilities of 3.97 and 2.62 (see #55). The exact P(a first) is 0.602063873417914, confirmed by mpmath quadrature at 40 dps.

So #55 is the root and fixing it fixes this. Filed separately for two reasons: expected_information_gain is a free public function reachable with no History and no fixture at all, and this bound is the crate's own designated tripwire — it should be a regression test that fails today, not merely a consequence someone infers from the other issue.

Suggested test

The existing never_exceeds_the_entropy_of_the_outcome passes, so it is not sampling this regime. Extend it to sweep the sigma ratio — the violations begin around a performance-sigma ratio of 1e4, which is where #55's grid stops resolving. A property test over random (mu, sigma, beta) asserting gain <= ln(k) + eps would have caught both this and the original prototype bug.

Also here

kl_divergence (src/acquisition.rs:50) returns negative values — 762 082 of 3 000 000 near-identical pairs, worst -5.551115123125783e-17, which is exactly one ULP of the - 1.0 term. It propagates: 1 041 of the 60 000 EIG samples came back negative. The magnitude is negligible but the sign is a hard mathematical violation, and the existing kl_divergence_is_non_negative_and_grows_with_separation only probes mean separation at fixed sigma — the variance-ratio term is the uncovered case. 0.5*(u - ln1p(u)) + gap^2/(2*var_p) with u = var_q/var_p - 1 makes non-negativity structural rather than incidental. Filed here rather than separately because it is the same function pair and the same fix session.

Found by a floating-point audit, 2026-09-09.

`src/acquisition.rs:166`. The crate documents this bound as the sharpest test it has: > `never_exceeds_the_entropy_of_the_outcome` — the information gain from observing one of `k` outcomes cannot exceed `ln k`. and records that an early prototype returned 4.77 nats, violating `ln 2`, and that the bound is what caught it. **The bound is violated again now**, by a different route. ## Measured Reproduced independently of the audit that found it: ``` mu = (9.577887112129012, -14.114932828525696) sigma = (0.00013250752658513438, 91.58669014092116) beta = 0.0003072355590130962, p_draw = 0 gain = 3.237828 ceiling ln 2 = 0.693147 ratio = 4.671 ``` For contrast, ordinary parameters are fine: ``` mu=(25,25) sigma=(25/3,25/3) beta=25/6 -> gain = 0.293899 ratio = 0.424 ``` A 60 000-sample random sweep over `mu ∈ ±100`, `sigma ∈ [1e-4, 1e2]`, `beta ∈ [1e-4, 1e1]` produced **1 073 violations**. A three-team sweep produced 96 of 6 000. ## Cause Not in this function's own arithmetic. `gain += probability * divergence` is weighted by `outcome_distribution`, which in this regime returns probabilities of **3.97 and 2.62** (see #55). The exact `P(a first)` is 0.602063873417914, confirmed by mpmath quadrature at 40 dps. So #55 is the root and fixing it fixes this. Filed separately for two reasons: `expected_information_gain` is a **free public function** reachable with no `History` and no fixture at all, and this bound is the crate's own designated tripwire — it should be a regression test that fails today, not merely a consequence someone infers from the other issue. ## Suggested test The existing `never_exceeds_the_entropy_of_the_outcome` passes, so it is not sampling this regime. Extend it to sweep the sigma ratio — the violations begin around a performance-sigma ratio of 1e4, which is where #55's grid stops resolving. A property test over random `(mu, sigma, beta)` asserting `gain <= ln(k) + eps` would have caught both this and the original prototype bug. ## Also here `kl_divergence` (`src/acquisition.rs:50`) returns **negative** values — 762 082 of 3 000 000 near-identical pairs, worst `-5.551115123125783e-17`, which is exactly one ULP of the `- 1.0` term. It propagates: 1 041 of the 60 000 EIG samples came back negative. The magnitude is negligible but the sign is a hard mathematical violation, and the existing `kl_divergence_is_non_negative_and_grows_with_separation` only probes mean separation at fixed sigma — the variance-ratio term is the uncovered case. `0.5*(u - ln1p(u)) + gap^2/(2*var_p)` with `u = var_q/var_p - 1` makes non-negativity structural rather than incidental. Filed here rather than separately because it is the same function pair and the same fix session. Found by a floating-point audit, 2026-09-09.
logaritmisk added the bugnumerics labels 2026-09-09 14:53:44 +00:00
Sign in to join this conversation.