Monte Carlo estimation of the true entropy rate of a quantized filtered Gaussian process#
Purpose. This document specifies, in enough detail for independent implementation and testing (Python + numpy/scipy is the intended target), a Monte Carlo method for estimating the exact entropy rate R of the integer process produced by the pipeline below — the quantity that the closed-form formula in the companion app (timeseries-compressibility) only approximates. The estimator is consistent (converges to the true R as particle count, window length, and sample count grow), all of its systematic errors push in a known direction (upward), and it admits a two-sided sandwich so convergence can be certified rather than assumed.
No code from the app needs to be reused; everything required is specified here. Reference values measured with the app are given in §7 for cross-checking.
Implementation status. A reference implementation exists at
scripts/true_rate.py (--selftest runs §6's
cheap tests; the UI shows the ready-to-run command for its current
parameters). It validates on none (matches the closed form),
first-difference, moving-average, and windowed-sinc kernels up to ~21
taps. For longer windowed-sinc kernels the innovation std falls to a few
hundredths of a step and the plain sequential filter hits the §5.3
genealogical collapse — the script detects this and aborts rather than
reporting garbage. Extending to that regime needs lookahead/twisted
proposals (Guarniero, Johansen & Lee, "The iterated auxiliary particle
filter", JASA 2017) or exact-HMC rejuvenation for truncated Gaussians
(Pakman & Paninski 2014); single-site Gibbs rejuvenation is not a viable
substitute here because the near-deterministic dynamics make its
conditionals microscopically narrow. Early healthy-regime results: the
closed-form R overestimates the MC truth by ≈ 0.07–0.10 bits/sample at
σ = 5 for MA(8) and the 21-tap bandpass — consistent with §1.3's error
analysis.
1. The system under study#
1.1 Generating model#
-
is a known FIR kernel (designs in §1.2).
-
i.i.d. when dither is on; otherwise. Dither is non-subtractive: the stored integers include it and the decoder never learns .
-
Quantization step = 1 (σ is measured in steps). Rounding ties are a measure-zero event, so the tie convention does not affect any law.
-
is a stationary Gaussian process with autocovariance
and spectral density , , cycles/sample.
The object of interest is the entropy rate of the integer process :
This is the true lossless compression limit for , the number the app's LPC + ANS bars try to approach from above.
1.2 Kernel designs (must match to compare numbers)#
All comparisons in §7 use the bandpass kernel below; implement at least
none and bandpass.
-
none: (then is i.i.d. and everything has closed form — the primary validation case). -
Hamming-windowed sinc lowpass, cutoff cycles/sample, odd length , midpoint :
then normalized to unit DC gain: .
-
bandpass(f_1, f_2)= lowpass() − lowpass(), same length, no further normalization. -
The default ephys case: bandpass 300–6000 Hz at 30 kHz sample rate (, ), 101 taps. Checkable constant: , so the filtered std is at .
1.3 The approximate formula being tested (for comparison only)#
The app's closed-form estimate, to be reimplemented for the comparison plots:
with (no dither) or (dither), the integral by midpoint rule (8192 points suffices), and the exact entropy of on the unit lattice: , .
Known inexactness (details in the analysis that motivated this work):
- It is not a bound in either direction.
- In the i.i.d. case (
none) the truth is exactly , while the formula returns — an overestimate (a double-count of the quantization variance): +0.0024 bits at σ = 5, +0.171 at σ = 0.5, +0.576 at σ = 0.1 (where the truth is ≈ 0). - In the stopband-dominated regime (default bandpass, σ = 5) it lands remarkably close to achievable rates, plausibly partly by cancellation of errors; the MC estimator exists to resolve this.
2. Why Monte Carlo can be exact here#
Three facts combine:
-
The law of is fully known, so conditional probabilities can be computed, not estimated from frequencies. For a window , the event probability (no dither) is a Gaussian rectangle probability:
— an -dimensional box integral of with the banded covariance from . (With dither the box edges are shifted by the , which are handled by sampling; §4.4.)
-
Predictive decomposition. , and by Shannon–McMillan–Breiman, almost surely along a single simulated realization. Equivalently, averaging the conditional surprisal over independent draws estimates , and monotonically.
-
Monotone error structure. Every systematic error is upward:
- finite window: for every (conditioning reduces entropy);
- inner estimation: an unbiased gives by Jensen, with bias , vanishing as the particle count grows.
So the estimate converges to R from above, and the only downward fluctuation is CLT noise, which gets an error bar.
For a two-sided certificate, use the hidden-Markov sandwich (Cover & Thomas, Elements of Information Theory, §4.5): is a function of the Markov state (plus ), so
with the lower bound increasing in and the gap . In simulation the true state at is known (we generated it), so the lower bound is estimable by the same machinery (§4.5).
3. The estimator in one paragraph#
Simulate one long realization from the pipeline. Run a sequential Monte Carlo over the latent Gaussian path constrained to the observed boxes: each particle is a sampled path consistent with so far; at each step the exact one-step predictive probability of the observed box, given the particle's path, is a Gaussian -difference (because is Gaussian with linear-prediction mean and fixed innovation variance); the mean of those -differences across particles is an unbiased estimate of ; the particle is extended by sampling from the corresponding truncated Gaussian (this "optimal one-step proposal" is exactly Genz's separation-of-variables construction for box probabilities, run sequentially with resampling). Average over after a burn-in; repeat over independent replicates for error bars. That average estimates R.
4. Algorithm specification#
4.1 Precomputation#
-
Build the kernel (§1.2) and the autocovariance (zero beyond lag ).
-
Run Levinson–Durbin on up to order (suggest , capped at ~1024). Store, for each order — or just for the terminal order — the prediction coefficients and innovation variance . After these are effectively converged ( the Szegő value for without any noise floor; e.g. for the default bandpass at σ = 5, , i.e. innovation std ≈ 0.044). Guard against underflow of for extreme stopbands (floor at ~1e-30 and warn).
For use the order- coefficients; past that, the terminal ones (steady state).
4.2 Per-step recursion (undithered)#
State: particle paths , (only the last values are needed), all with equal weight after resampling.
For , with observed integer :
- Prediction per particle: , innovation std , where .
- Standardized box edges: , .
- Incremental weight (log-space; see §5.1).
- Predictive estimate . Record . If (all particles incompatible), the run has degenerated — restart the replicate with larger N; do not clamp.
- Resample particles with probabilities (systematic resampling; adaptive — only when — is fine, but then must use the standard normalized-weight form with carried weights ).
- Extend each surviving particle: , — the truncated-Gaussian draw (§5.2).
4.3 Assembling the estimate#
- , with burn-in (the early steps estimate for small , which is above R).
- Run independent replicates (fresh , fresh particles). Report mean ± SE across replicates. Within-run block averaging is acceptable but replicates are simpler and honest about autocorrelation.
- Bias control (essential): repeat at , , particles. The estimate must decrease and plateau (Jensen bias shrinks like ). Treat the plateau as the answer; optionally Richardson-extrapolate in . A per-step delta correction is a useful diagnostic but is not exact under resampling — the particle-doubling plateau is authoritative.
4.4 Dither#
With dither, the box for is shifted by the (unknown to the decoder) : . Extend each particle with its own drawn before step 2, and use the shifted edges. Everything else is unchanged; remains unbiased (the dither prior is part of the proposal). Optionally, integrate analytically in the weight — the integral of a -difference over a unit shift is a difference of terms — and then sample jointly; lower variance, more code. Start with the sampled version.
Note: when generating the observed for a dithered run, the generator also draws ; those true dither values are not given to the estimator (non-subtractive dither).
4.5 Sandwich lower bound (optional but recommended)#
Estimate : for each of many independent windows, (a) simulate truth and keep the exact latent inputs up to time ; (b) condition the Gaussian law of on that known state — its conditional mean is the deterministic tail response and its conditional covariance is that of the truncated kernel (only the taps applied to inputs after ); (c) run the same SOV/SMC over the constrained steps and record the last step's . Average over windows. Plot lower and upper curves against ; the closing gap certifies memory-length convergence independently of any modeling argument.
5. Numerical hazards (all known, all manageable)#
5.1 Φ-differences in the tails#
When both edges are far in one tail, underflows
in the naive form. Compute in log space:
use scipy.special.log_ndtr; for switch to the upper
tail, , and combine as
log_ndtr(hi) + log1p(-exp(log_ndtr(lo) - log_ndtr(hi))). These
low-probability steps are precisely the ones that dominate the surprisal,
so they must not be clamped to zero.
5.2 Truncated-normal sampling#
The inverse-CDF trick in §4.2(6) loses precision when the interval sits
beyond ~6σ. Use scipy.stats.truncnorm (which handles tails), or Robert's
exponential-rejection sampler for one-sided extreme tails. A particle
sitting exactly on an edge after sampling is harmless.
5.3 Weight degeneracy and path collapse#
The innovation std can be much smaller than the box width (deep stopbands, no dither). Then most particles get and the rest : weights are Bernoulli-like with success probability per step. This is workable — the truncated draw in step 6 spans the box, i.e. many innovation-σ's, so resampled duplicates re-diversify quickly — but it costs particles. If ESS collapses persistently:
- raise N (first resort; the estimator is embarrassingly parallel across particles and replicates);
- use a lookahead / auxiliary proposal (weight by the next few observations before resampling);
- as a fallback formulation, run the SMC in x-space (particles over the i.i.d. inputs, observation constraining ). Beware: after causal reindexing, windowed- sinc kernels have tiny leading taps, which makes the naive one-step x-space proposal much worse than the y-space one specified here. x-space only becomes attractive with block/lookahead proposals.
- dithered runs are easier (the dither smooths the likelihood); debug there first.
5.4 Sanity invariants to assert in code#
- always; running finite.
- Undithered,
nonekernel, any σ: the SMC reduces to i.i.d. draws and must equal -difference of the marginal for every particle identically (zero variance across particles). - Generated statistics: sample std of for .
6. Test plan#
Ordered from cheap-and-exact to expensive-and-comparative.
- i.i.d. exactness (primary).
nonekernel. True in closed form. Require agreement within 3 SE at σ ∈ {0.5, 1, 5}, and that the reimplemented reproduces its known overestimates (§7 table). - Marginal check. (no conditioning) equals the marginal quantized entropy for any kernel: compare a short-window run against the 1-D formula with (undithered).
- Brute force, small windows. For MA(1)-like kernels
(, σ ≤ 2), compute for exactly:
enumerate integer tuples within ±8σ_y and evaluate box probabilities
with
scipy.stats.multivariate_normal.cdf(Genz), then . The SMC at the same (fresh independent windows, fixed ) must match within error bars. - Monotonicity. non-increasing in (within noise); estimate decreasing and plateauing in particle count N; sandwich gap (if implemented) shrinking in .
- Dead zone.
none, σ = 0.1: (truth ~1e-5), vs . With dither, σ → 0: truth → 0 as well (uniform ±½ dither alone never flips the integer), vs . - Achievability cross-check. For the default bandpass, σ = 5: must be ≤ the achievable rates in §7 (LPC residual entropy ≈ 1.947) plus noise, and plausibly close to . This is the headline number this whole exercise exists to pin down.
- Sweep deliverable. σ ∈ {0.5, 1, 2, 5, 10, 20, 50, 100} × {dither on, off} for the default bandpass: plot with error bars against , plus the i.i.d. sweep where truth is closed-form. Deliver the numbers as CSV alongside the plot.
Suggested starting parameters: N = 4096 particles, T = 4000 steps, burn-in B = 1000, J = 16 replicates, for the 101-tap kernel. Rough cost: O(N·k_max) per step ⇒ ~10⁹–10¹⁰ flops per replicate — seconds to a minute in vectorized numpy (vectorize across particles; the prediction is a matrix–vector product against the shared coefficient vector).
7. Reference values (default bandpass = 300–6000 Hz @ 30 kHz, 101 taps)#
Closed-form / app-measured values for validating reimplementations. "Exact" rows are analytic; others were measured with the app's codecs on a 100k-sample block (seed-dependent in the third decimal).
| Quantity | Value | Status |
|---|---|---|
| at s = 0.1 / 0.3 / 1 / 5 / 50 | 0.00001 / 0.55042 / 2.10483 / 4.37142 / 7.69098 | exact |
True R, none, σ = 5 / 0.5 / 0.1 |
4.37142 / 1.24174 / ≈1e-5 | exact () |
, none, σ = 0.1 / 1 / 5 / 100 |
0.57611 / 2.15829 / 4.37382 / 8.69096 | exact given §1.3 |
| , bandpass, σ = 0.5 / 5 / 20 / 100 | 0.8620 / 1.9397 / 2.7282 / 3.7166 | exact given §1.3 |
| , bandpass + dither, σ = 5 | 2.2111 | exact given §1.3 |
| , default bandpass | 0.60216 | exact given §1.2 |
| Order-0 entropy of LPC(32) / LPC(128) residual, bandpass σ = 5 | 1.965 / 1.947 | measured (achievable ⇒ upper bounds on R) |
| LPC(32)+ANS achieved, bandpass σ = 5 | 2.002–2.011 | measured |
| Pure high-res rate (no floor), bandpass σ = 5 | −2.4604 | exact; demonstrates why the floor exists |
8. References#
- A. Genz, "Numerical computation of multivariate normal probabilities," J. Comput. Graph. Statist., 1992 — the separation-of-variables construction that §4.2 runs sequentially.
- A. Genz, F. Bretz, Computation of Multivariate Normal and t Probabilities, Springer, 2009.
- Z. I. Botev, "The normal law under linear restrictions: simulation and estimation via minimax tilting," JRSS-B, 2017 — variance reduction if §5.3 becomes limiting.
- T. M. Cover, J. A. Thomas, Elements of Information Theory, 2nd ed.: §4.5 (HMM entropy-rate sandwich), §16.8 / AEP (Shannon–McMillan–Breiman).
- Companion theory note in the sibling repository
entropy-quantized-linear-gaussian(entropy_quantized_linear_gaussian.md): the block-entropy version of the same box-probability machinery, including the inner-bias caveat this spec's §4.3 addresses.