Normalized 4th-order coupling metrics and losses for generative model evaluation.
Project description
couplnorm
Normalized 4th-order coupling metrics and losses for generative model evaluation.
couplnorm implements the normalized off-diagonal coupling diagnostic C, a
4th-order spectral statistic that measures joint coupling between Fourier modes
— structure that second-order metrics (power spectrum, two-point function) miss
by construction.
Marginal Gaussianity does not imply joint independence. C measures the gap.
All three distributions above have (near-)identical per-mode marginals; a power
spectrum cannot tell them apart. C rises from ~0.04 to ~0.82 as joint 4th-order
coupling is switched on. (Reproduce with notebooks/01_basic_usage.ipynb.)
Given field samples, couplnorm computes the covariance of the per-mode spectral
energies E_k = |φ̃_k|² and reduces it to a single scale-free number:
C = ‖Σ − diag(Σ)‖_F / ‖Σ‖_F
C = 0 means the spectral energies are pairwise uncorrelated (a Gaussian /
free-field signature); C → 1 means off-diagonal coupling dominates.
Install
pip install -e .[dev] # from a checkout
Requires Python ≥ 3.10 and PyTorch ≥ 2.0.
Quickstart
import torch
from couplnorm import coupling_from_samples, CouplingMetric, CouplingLoss
# One-shot number from a batch of (B, N) real fields
phi = torch.randn(10_000, 32)
print(coupling_from_samples(phi).item()) # ~0.03 (independent modes)
# As a streaming nn.Module metric
metric = CouplingMetric(mode="running", momentum=0.02, n_modes=32 // 2 + 1)
for chunk in loader: # doctest: +SKIP
metric(chunk)
print(metric.compute().item())
# As a training loss that matches a reference distribution's coupling
loss_fn = CouplingLoss.from_data(reference_data, target_type="matrix") # doctest: +SKIP
loss = loss_fn(generated_batch) # doctest: +SKIP
Three forms
| Object | Use |
|---|---|
coupling_from_samples |
one-line functional helper — just want the number |
CouplingMetric |
nn.Module metric; batch or streaming (running EMA) mode |
CouplingLoss |
differentiable loss: match a covariance, match a scalar C, or minimize C (DeCov-style) |
The FFT convention (important)
For a real field of length N, the DFT is conjugate-symmetric
(φ̃_k = φ̃*_{N−k}), so |φ̃_k|² = |φ̃_{N−k}|² exactly. Feeding the full FFT into
C creates N − 2 off-diagonal entries that equal diagonal entries before any
physics enters, inflating C by an analytical floor of
C_floor = sqrt((N − 2) / (2N − 2)) ≈ 0.7
couplnorm defaults to real_fft=True (uses torch.fft.rfft, keeping only the
N//2 + 1 unique modes), which reflects only genuine coupling. Set
real_fft=False only for intrinsically complex fields. A regression test pins
the analytical floor so this convention can't silently break.
What's in the box
src/couplnorm/
coupling.py # the metric, loss, and helpers (the contribution)
samplers.py # Phi4Sampler: 1D phi^4 Metropolis-Hastings reference sampler
models/ # FourierModel, FullGaussian, PCAModel, MAF baselines
plotting.py # matplotlib helpers for the notebooks
notebooks/
01_basic_usage.ipynb # compare C across distributions
02_reproduce_paper.ipynb # phi^4 free vs interacting theory
03_coupling_as_loss.ipynb # train a generator to match coupling
Baselines share one interface: construct, .fit(data) where applicable, then
.sample(n) returning (n, N) real position-space fields. The FourierModel
assumes marginal mode independence, so it collapses C to ≈ 0 regardless of the
target — the concrete demonstration of why C is worth measuring.
Case study
The φ⁴ lattice study that motivates C is:
A. Bhat, R. Ide, Z. Zhao. When Independent Gaussian Models Break Down: Characterizing Regime-Dependent Modeling Failures in φ⁴ Theory. arXiv:2605.01145.
That paper's reported C values (C(N=32) ≈ 0.06 up to C(N=128) ≈ 0.2, strong
coupling saturating near 0.17–0.18) are computed on the unique rfft modes —
the real_fft=True default here. The full FFT would inflate every value to the
~0.7 conjugate-symmetry floor (see above), so the published magnitudes are only
consistent with the unique-mode convention.
Citation
See CITATION.cff.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file couplnorm-0.1.0.tar.gz.
File metadata
- Download URL: couplnorm-0.1.0.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67d6da3bf359e6c43c2a46a021cb46188cbdea4ec5596fc8e4fbe2c31504daba
|
|
| MD5 |
aff146efbc74043f6814db1f5c6fc50f
|
|
| BLAKE2b-256 |
18cf751822305e6faa36f33fe37772ca37a7deabd158f34ce5fd46a64ada59e2
|
File details
Details for the file couplnorm-0.1.0-py3-none-any.whl.
File metadata
- Download URL: couplnorm-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2341a5dde9cd7275c4d3498ee46876616acc980b9571631e68e87dcc862ab0b0
|
|
| MD5 |
3506293513568c94134f2571edde57bc
|
|
| BLAKE2b-256 |
b3cf5b6916e2c1b54b52f6fddca9c1cb06beb1c160cafe157e88fbb84b32c087
|