mixle.experimental.e_process module¶
P9 (experimental) – anytime-valid receipts via e-processes.
Conformal/coverage receipts are fixed-sample, but much of mixle streams: streaming EM, drift monitoring, training curves, the evolution loop’s champion/challenger gate. A fixed-sample test that you peek at every step spends its error budget silently – after enough peeks a level-alpha test rejects a true null with probability far above alpha.
E-processes fix this. An e-value is a non-negative statistic with expectation <= 1 under the
null; an e-process (E_t) is a sequence of them that forms a non-negative supermartingale
under the null with E_0 = 1. Ville’s inequality then gives, for the whole trajectory at once,
P_null( sup_t E_t >= 1/alpha ) <= alpha.
So the rule “reject the first time E_t >= 1/alpha” controls the type-I error at alpha
no matter when you look or when you stop – continuous monitoring and optional stopping are
free, with no alpha-spending bookkeeping.
Why this is native to mixle: a likelihood ratio q(x)/p(x) between two densities is exactly an
e-value when p is the null (E_null[q(X)/p(X)] = integral q = 1), so a running product of
mixle density ratios IS an e-process. This module provides:
EProcess– a running-product e-process constructed from typed predictable null and alternative conditional densities plus explicit normalization evidence, with theE_t >= 1/alphastopping rule and the anytime-valid guarantee;normal_mixture_eprocess()/MeanShiftDetector– the closed-form Robbins normal-mixture e-process for detecting a mean shift of unknown size, and a drift detector built on it.
This is exploratory mixle.experimental code (see the P9 card): its graduation receipt is the
empirically-verified anytime type-I control in e_process_test.py.
- class TestMartingaleValidity(null_hypothesis, alternative_hypothesis, assumptions, normalization_evidence, construction='predictable-conditional-likelihood-ratio/v1')[source]
Bases:
objectEvidence that a predictable likelihood ratio defines a test martingale.
- class PredictableLikelihoodRatio(log_alternative, log_null, validity)[source]
Bases:
objectConditional densities evaluated from history available before the next observation.
- class EProcessReceipt(e_value, peak_e_value, log_e_value, peak_log_e_value, n, alpha, threshold, rejected, validity, numerical_status, guarantee="anytime-valid: P_null(ever reject) <= alpha by Ville's inequality")[source]
Bases:
objectAnytime decision plus construction assumptions and numerical status.
- class EProcess(martingale)[source]
Bases:
objectA running product from a declared predictable conditional likelihood ratio.
Construction requires a typed validity receipt. The process itself evaluates both conditional densities from the pre-observation history, preventing arbitrary log-ratio streams from being mislabeled as anytime-valid evidence.
- Parameters:
martingale (PredictableLikelihoodRatio)
- update(observation)[source]
Evaluate and multiply the next predictable conditional likelihood ratio.
- rejects(alpha=0.05)[source]
Whether the CURRENT e-value clears the
1/alphathreshold (an anytime-valid reject).
- ever_rejected(alpha=0.05)[source]
Whether the e-process has crossed
1/alphaat any point so far (peeking-safe).
- normal_mixture_log_e(sum_centered, t, *, sigma, tau)[source]
Log of the Robbins two-sided normal-mixture e-value for a Gaussian mean shift.
Tests
H0: mean == mu0for a stream ofN(mean, sigma^2)observations, mixing the alternative mean over aN(mu0, tau^2)prior (so an unknown-size shift is covered without choosing it in advance).sum_centered = sum_i (x_i - mu0)over thetobservations.Closed form (a non-negative martingale under H0 with value 1 at t=0):
E_t = sqrt( s2 / (s2 + t*T2) ) * exp( T2 * S^2 / (2*s2*(s2 + t*T2)) )
with
s2 = sigma^2,T2 = tau^2,S = sum_centered.
- normal_mixture_log_eprocess(stream, *, mu0, sigma, tau)[source]
Return stable running log e-values for the Robbins normal-mixture process.
- normal_mixture_eprocess(stream, *, mu0, sigma, tau)[source]
Return the running e-values of the Robbins normal-mixture e-process over
stream.result[i]isE_{i+1}after seeingstream[:i+1]. Element 0 corresponds to one observation; the process starts atE_0 = 1implicitly.
- class DriftReport(detected, detection_time, alpha, peak_e_value, final_e_value, peak_log_e_value=0.0, final_log_e_value=0.0, numerical_status='finite', assumptions=('independent Gaussian observations under the null', 'known positive observation sigma', 'normal mean-shift mixture with fixed positive tau'), guarantee='anytime-valid: false-alarm probability <= alpha under the null (Ville)')[source]
Bases:
objectOutcome of a drift scan: whether/when the e-process crossed
1/alpha.
- class MeanShiftDetector(*, mu0, sigma, tau=1.0, alpha=0.05)[source]
Bases:
objectAn anytime-valid detector for a shift in a Gaussian stream’s mean, built on the e-process.
The null is
mean == mu0with knownsigma;tausets the scale of shifts the mixture is most sensitive to. Because it is an e-process, you may test after every observation and stop whenever it fires; the false-alarm probability over the whole run is still at mostalpha.