eproc

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

commit 18a95aecce2a74ea6abd7b1a62adf07c927e4a9c
parent fd9e56f36fadee3edca61961dbb558d8ce52546a
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri,  3 Jul 2026 15:09:21 -0230

release: v0.4.0

Anytime-valid p-values and e-values on every test module, uniform
convex mixtures of e-processes (Numeric.Eproc.Mixture), and
time-uniform confidence sequences for bounded means
(Numeric.Eproc.ConfSeq). README, CHANGELOG, and cabal description
refreshed to match; the Mixture module example is now
self-contained, with outputs verified against a live GHCi session.

Diffstat:
MCHANGELOG | 15+++++++++++----
MREADME.md | 49++++++++++++++++++++++++++++++++++++++++++-------
Mlib/Numeric/Eproc/Mixture.hs | 21++++++++++++++-------
Mppad-eproc.cabal | 14++++++++------
4 files changed, 75 insertions(+), 24 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,5 +1,16 @@ # Changelog +- 0.4.0 (2026-07-03) + * Adds calibrated evidence accessors to every test module: + 'log_evalue', 'log_evalue_sup', and the anytime-valid 'p_value'. + * Adds Numeric.Eproc.Mixture: uniform convex mixtures of + e-processes, for testing a null against a union of qualitatively + different alternatives at a single Ville threshold. + * Adds Numeric.Eproc.ConfSeq: anytime-valid confidence sequences + for bounded means, via the hedged-capital construction of + Waudby-Smith & Ramdas (2024). + * Adds InvalidComponentCount and InvalidGridSize to ConfigError. + - 0.3.0 (2026-07-02) * Introduces a breaking API change: 'log_wealth' now returns the current log-wealth, whereas the supremum-thus-far statistic is @@ -9,10 +20,6 @@ * Adds a Numeric.Eproc.Bernoulli.TwoSided module for a two-sided Bernoulli rate test. -- 0.2.2 (2026-07-02) - * Adds a Numeric.Eproc.Bernoulli.TwoSided module for a two-sided - Bernoulli rate test. - - 0.2.1 (2026-07-02) * Two-sided bounded-mean tests now reject faster, or at least never later. diff --git a/README.md b/README.md @@ -4,9 +4,9 @@ ![](https://img.shields.io/badge/license-MIT-brightgreen) [![](https://img.shields.io/badge/haddock-eproc-lightblue)](https://docs.ppad.tech/eproc) -Anytime-valid sequential hypothesis testing for bounded random -variables, via the e-process / betting framework of -[Waudby-Smith & Ramdas (2024)][wsr24]. +Anytime-valid sequential hypothesis testing and confidence sequences +for bounded random variables, via the e-process / betting framework +of [Waudby-Smith & Ramdas (2024)][wsr24]. ## Usage @@ -42,6 +42,30 @@ A sample GHCi session: Reject ``` +Confidence sequences invert the same machinery into time-uniform +interval estimates: valid at every sample size simultaneously, so you +can watch the interval shrink and stop whenever it's tight enough: + +``` + > import qualified Numeric.Eproc.ConfSeq as CS + > + > -- estimate a mean in [0, 1] at 95% coverage, on a 100-point grid + > let Right cfg = CS.config 0.0 1.0 0.05 100 + > let s0 = CS.initial cfg + > + > -- the same drifting stream as above; the interval closes in on + > -- its empirical mean of 0.8 + > let xs = concat (replicate 30 [1, 1, 0, 1, 1, 0, 1, 1, 1, 1]) + > CS.interval cfg (foldl' (CS.update cfg) s0 xs) + Just (0.7227722772277227,0.8712871287128713) +``` + +Every test module also reports its evidence as an anytime-valid +p-value (`p_value`) and a normalized log e-value (`log_evalue`); the +`Mixture` module combines several e-processes into a single test with +power against a union of alternatives (see its haddocks for a worked +sign-plus-magnitude example). + ## Documentation Haddocks (API documentation, etc.) are hosted at @@ -73,13 +97,24 @@ Current benchmark figures on an M4 Silicon MacBook Air look like (use benchmarking Bernoulli.TwoSided.update (1000-sample fold)/newton time 14.83 μs (14.81 μs .. 14.84 μs) + + benchmarking Mixture.update (one step)/K=4 + time 31.38 ns (31.21 ns .. 31.55 ns) + + benchmarking ConfSeq.update (one step, g = 200)/plug-in + time 2.121 μs (2.118 μs .. 2.124 μs) + + benchmarking ConfSeq.update (1000-sample fold, g = 200)/plug-in + time 241.2 μs (239.7 μs .. 243.2 μs) ``` The `Paired` and `Bernoulli.TwoSided` modules are thin newtype wrappers over `Bounded`, and inline through with no measurable -overhead. See the criterion suite for the full breakdown across -`Fixed` / `Adaptive` / `Newton` bettors and per-step / fold -workloads. +overhead. `ConfSeq` updates cost O(live grid candidates) per +observation, so long streams get cheaper as candidates are rejected +(visible in the sub-linear fold figure above). See the criterion +suite for the full breakdown across `Fixed` / `Adaptive` / `Newton` +bettors and per-step / fold workloads. You should compile with the `llvm` flag for maximum performance. @@ -103,7 +138,7 @@ to get a REPL for the main library. ## References - Waudby-Smith & Ramdas (2024), "[Estimating means of bounded random - variables by betting][wsr24]." JRSS-Bounded. + variables by betting][wsr24]." JRSS-B. - Ramdas, Grunwald, Vovk, Shafer (2023), "[Game-theoretic statistics and safe anytime-valid inference][rgvs23]." Statistical Science. - Shafer (2021), "[Testing by betting][shafer21]." JRSS-A. diff --git a/lib/Numeric/Eproc/Mixture.hs b/lib/Numeric/Eproc/Mixture.hs @@ -62,17 +62,24 @@ -- -- >>> import qualified Numeric.Eproc.Bernoulli.TwoSided as Sign -- >>> import qualified Numeric.Eproc.Bounded as Magn --- >>> let Right sc = Sign.config 0.5 1.0e-3 Newton --- >>> let Right mc = Magn.config 0.0 (-1.0) 1.0 1.0e-3 Newton --- >>> let Right xc = config 2 1.0e-3 +-- >>> import qualified Numeric.Eproc.Mixture as Mix +-- >>> let Right sc = Sign.config 0.5 1.0e-3 Sign.Newton +-- >>> let Right mc = Magn.config 0.0 (-1.0) 1.0 1.0e-3 Magn.Newton +-- >>> let Right xc = Mix.config 2 1.0e-3 -- >>> :{ --- let step (!s, !m, !x) d = +-- let step (s, m, x) d = -- let s' = Sign.update sc s (d > 0) -- m' = Magn.update mc m d --- in (s', m', update xc x [Sign.log_evalue s', Magn.log_evalue m']) +-- in (s', m', Mix.update xc x +-- [Sign.log_evalue s', Magn.log_evalue m']) -- :} --- >>> let (_, _, x1) = foldl' step (Sign.initial sc, Magn.initial mc, initial xc) ds --- >>> decide xc x1 +-- >>> let ds = take 400 (cycle [0.6, 0.7, -0.2, 0.8]) +-- >>> let z0 = (Sign.initial sc, Magn.initial mc, Mix.initial xc) +-- >>> let (_, _, xf) = foldl' step z0 ds +-- >>> Mix.decide xc xf +-- Reject +-- >>> Mix.p_value xc xf +-- 9.482234479673792e-34 module Numeric.Eproc.Mixture ( -- * Mixture configuration and state diff --git a/ppad-eproc.cabal b/ppad-eproc.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: ppad-eproc -version: 0.3.0 +version: 0.4.0 synopsis: Anytime-valid sequential testing via e-processes. license: MIT license-file: LICENSE @@ -11,11 +11,13 @@ build-type: Simple tested-with: GHC == 9.10.3 extra-doc-files: CHANGELOG description: - Anytime-valid sequential hypothesis testing for bounded random - variables, via the e-process / betting framework of Waudby-Smith and - Ramdas (2024). Provides bounded-mean, paired two-sample, and one- and - two-sided Bernoulli rate tests with fixed, adaptive (aGRAPA), and - online Newton bettors. + Anytime-valid sequential hypothesis testing and estimation for + bounded random variables, via the e-process / betting framework of + Waudby-Smith and Ramdas (2024). Provides bounded-mean, paired + two-sample, and one- and two-sided Bernoulli rate tests with fixed, + adaptive (aGRAPA), and online Newton bettors; anytime-valid p-values + and e-values; uniform convex mixtures of e-processes; and + time-uniform confidence sequences for bounded means. flag llvm description: Use GHC's LLVM backend.