eproc

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 54282d253042a7ec1891ef4fe72496f4908ffa52
parent 18a95aecce2a74ea6abd7b1a62adf07c927e4a9c
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat,  4 Jul 2026 16:27:06 -0230

fix: uncap the ConfSeq plug-in bet

Numeric.Eproc.ConfSeq pre-capped the shared predictable plug-in bet
at the truncation level c = 1/2 before applying the candidate-
specific truncations c/m and c/(1 - m). Since both exceed c on the
interior grid, those truncations could never bind: a conservative
deviation from the WSR (2024) eq. (26) bet that Theorem 3 and the
module documentation describe, slowing rejection of extreme
candidates early in the stream.

Drop the pre-cap. The raw eq. (26) bet is now truncated only per-
candidate, restoring the paper's construction and its early power;
every capital factor retains the 1 - c floor via the truncations
themselves, so coverage is unaffected. The update haddock, which
carried the same pre-cap in its bet formula, and the module-header
example output are corrected to match.

Validated with and without -f+llvm.

Diffstat:
Mlib/Numeric/Eproc/ConfSeq.hs | 14+++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/Numeric/Eproc/ConfSeq.hs b/lib/Numeric/Eproc/ConfSeq.hs @@ -69,7 +69,7 @@ -- >>> let Right cfg = config 0.0 1.0 0.05 100 -- >>> let xs = concat (replicate 50 [1, 1, 0, 1, 1, 0, 1, 1, 1, 1]) -- >>> interval cfg (foldl' (update cfg) (initial cfg) xs) --- Just (0.7326732673267327,0.8514851485148515) +-- Just (0.7326732673267327,0.8613861386138614) module Numeric.Eproc.ConfSeq ( -- * Confidence-sequence configuration and state @@ -218,14 +218,15 @@ initial Config{..} = State { -- plug-in bet from the statistics accumulated through the -- /previous/ step (Waudby-Smith & Ramdas (2024), eq. (26)): -- --- @lambda_t = min c (sqrt (2 log(2 \/ alpha) --- \/ (sigma^2_{t-1} * t * log(1 + t))))@ +-- @lambda_t = sqrt (2 log(2 \/ alpha) +-- \/ (sigma^2_{t-1} * t * log(1 + t)))@ -- --- with @c = 1\/2@. The bet is computed once and shared across all +-- The bet is computed once and shared across all -- live candidates -- its independence from @m@ is what keeps the -- survivor set an interval. Each live candidate @m@ then updates -- its pair of log-capitals with the truncated bets --- @min lambda_t (c \/ m)@ and @min lambda_t (c \/ (1 - m))@, and +-- @min lambda_t (c \/ m)@ and @min lambda_t (c \/ (1 - m))@, +-- with @c = 1\/2@, and -- is dropped iff @max(log K^+, log K^-)@ has reached -- @log(2 \/ alpha)@. Finally @y@ is folded into the shared -- statistics, preserving predictability of the next bet. @@ -245,8 +246,7 @@ update Config{..} State{..} !x = !gp1 = fromIntegral (cfg_grid + 1) -- sigma^2_{t-1} = (1/4 + sum_{i<=t-1} (y_i - mu_i)^2) / t !sig2 = (0.25 + st_sum_dev2) / td - !lam = min trunc_c - (sqrt (cfg_bet_num / (sig2 * td * log1p td))) + !lam = sqrt (cfg_bet_num / (sig2 * td * log1p td)) -- built eagerly, as in 'initial': the tail is forced before -- consing, so the new live list is in normal form on -- construction.