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:
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://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.