Feat/binned autocorrelation - #298
Conversation
# Conflicts: # pyerrors/obs.py
There was a problem hiding this comment.
🟡 Changes recommended
The normalized-block windowing path currently skips the smallest candidate window W=b, which contradicts the documented window set and can bias window selection for short-correlated histories.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds an optional autocorrelation “lag binning” (rho_bin) mode to Obs.gamma_method() to make automatic window selection more robust for gapped / mixed-measurement histories (e.g., sawtooth autocorrelation shapes), while keeping the underlying truncated autocorrelation sum unchanged at equivalent physical windows.
Changes:
- Add
rho_bin(global + per-ensemble dict configuration) and store binned autocorrelation sums/errors (e_rho_bins,e_drho_bins) alongside the existing raw outputs. - Update windowing + exponential-tail logic to operate in physical lag units while allowing window selection on a coarse-grained (binned) representation.
- Add extensive regression and behavior tests for
rho_bin, and document the feature in the package docs.
File summaries
| File | Description |
|---|---|
pyerrors/obs.py |
Implements rho_bin parsing/storage, binned autocorrelation computation/error propagation, and plotting updates. |
tests/obs_test.py |
Adds regression + behavioral tests covering default equivalence, sawtooth handling, tail logic, error propagation, and validation. |
pyerrors/__init__.py |
Documents the motivation, math, and API/plotting behavior for rho_bin. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…l fix for early exiting the gamma method
There was a problem hiding this comment.
🟡 Changes recommended
Uncomputed uncertainties are exposed as zeros, and large valid bins can cause excessive memory allocation.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Review effort level: Balanced
| kernel = np.sum(self.e_rho[e_name][m[:, None] + lags] | ||
| + self.e_rho[e_name][np.abs(m[:, None] - lags)] | ||
| - 2 * self.e_rho[e_name][m[:, None]] * self.e_rho[e_name][lags], axis=1) |
| self.e_rho_bins[e_name] = binned_lags.reshape(n_bins, bin_size).sum(axis=1) | ||
| self.e_drho_bins[e_name] = np.zeros(n_bins) |
|
Well, the copilot comments were really useful and I have (basically) implemented the suggested changes. One could also set the entries of the standard |
This pull request touches some of the inner workings of the gamma method (when the feature is selected), therefore I have tried to explain the suggested changes in some detail. I have thought about this for some time and now I am happy that a nasty feature of working with gapped measurements and combining different data sets can be resolved:
When observables measured on different subsets of configurations are combined, the resulting autocorrelation function can have a pronounced short-distance structure that breaks the existing automatic windowing procedure.
One example is the product of a precise observable measured on every configuration and a noisier, autocorrelated observable measured only on every fourth configuration. The autocorrelation function of the derived observable then has a sawtooth shape: the slow mode is visible at every fourth lag, while the lags in between are close to zero.
The standard automatic windowing procedure can interpret one of these early zeros as the end of the autocorrelation and stop much too early.
In the example below, the ordinary analysis selects
W=1and gives an error of approximately0.038. An analysis with four-lag autocorrelation bins selectsW=92and gives0.14, consistent with analyzing the sparse observable separately which gives the same uncertainty and a window of 22 in units of 4 configurations.Example used for the plots
Without autocorrelation binning
With
rho_bin=4The correlated observable alone with the usual gapped analysis
Approach
The new
rho_binargument coarse-grains the autocorrelation analysis without binning the Monte Carlo history itself.For a bin size (b), consecutive positive autocorrelation lags are summed:
The integrated autocorrelation time at the corresponding physical window (W=kb) is then
This is only a regrouping of the original sum. At a common physical window, the estimator is unchanged.
For automatic window selection, the block envelope is normalized by its first block,
and the usual window criterion is evaluated in block units with an effective history length$N/b$ .
For a pure exponential,$\rho(t)=q^t$ ,
The normalized blocks therefore describe the same decay on a coarser grid. This keeps the selected physical window invariant up to the finite bin resolution. It also turns a regularly spaced sawtooth into a smooth representation of its envelope.
If the first block is not larger than its uncertainty, it cannot be used safely for normalization. In that case the code falls back to the direct window criterion (which should be fine because autocorrelation is small anyways).
Compatibility
The default is
rho_bin=1. In this case:For ordinary smooth histories, increasing
rho_binleaves the estimator unchanged at common physical windows. So any change is just due to discrete bin sizes.The raw autocorrelation remains available in
e_rho. The block sums and their uncertainties are stored separately ine_rho_binsande_drho_bins.Error of an autocorrelation block
The uncertainty of a block sum is not obtained by adding the individual autocorrelation errors in quadrature since autocorrelation estimates at neighboring lags are correlated.
Starting from the covariance approximation used by the existing
_compute_drho, the kernels for all lags in a block are summed before squaring:This keeps all cross-covariance terms between the constituent lags. For
rho_bin=1, the original implementation is used unchanged.Physical window and exponential tails
Quantities that depend on the truncation point continue to use the physical window$W=kb$ . This includes:
The exponential-tail analysis uses the significance of the block sum,
to choose its attachment point. The next block is converted to the equivalent first-lag amplitude of a discrete exponential before applying the existing tail prescription:
This reduces exactly to the previous expression when
rho_bin=1.As before, the uncertainty of$\tau_{\exp}$ itself and covariances between the truncated sum and the tail are not included.
Additional details
plot_rho()displays the raw normalized autocorrelation forrho_bin=1and the summed blocks for larger bin sizes.e_windowsizeremain in the original lag units.rho_bin_globalandrho_bin_dictprovide the same global and per-ensemble configuration mechanism as the other parameters we had before already.Tests
The added tests cover:
rho_bin=1pathsI'm happy for feedback. Merging this is not super urgent, but it could help in some real-world analyses.