.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/rmt/spacings/plot_riemann_zeta_keating_snaith_moments.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_rmt_spacings_plot_riemann_zeta_keating_snaith_moments.py: The Riemann Zeta Connection: Keating-Snaith Moments of the CUE Characteristic Polynomial ======================================================================================== For :math:`U` an :math:`n \times n` Haar-random unitary matrix (CUE) and its characteristic polynomial evaluated on the unit circle, :math:`Z_n(\theta) = \det(I - U e^{-i\theta})`, the Diaconis-Shahshahani / Keating-Snaith formula gives the exact moments (positive integer :math:`k`; by Haar-measure rotation invariance the value does not depend on :math:`\theta`): .. math:: E\left[|Z_n(\theta)|^{2k}\right] = \prod_{j=0}^{n-1} \frac{j!\,(j+2k)!}{(j+k)!^2}. At :math:`k=1` this product telescopes to the simple closed form :math:`E[|Z_n|^2] = n+1`. These moments are the random-matrix side of the Montgomery-Dyson-Keating-Snaith analogy: CUE eigenvalue statistics are conjectured to model the local statistics of Riemann zeta zeros on the critical line, and the moments of :math:`Z_n(\theta)` are the matrix-model analogue of the (still-conjectural) moments of :math:`\zeta(\tfrac{1}{2}+it)`. This example reproduces the exact Keating-Snaith moment formula for the CUE characteristic polynomial, :math:`E[|Z_n(\theta)|^{2k}]`, against direct Monte Carlo simulation of Haar-random unitary matrices. References: H. L. Montgomery, "The pair correlation of zeros of the zeta function", Proc. Sympos. Pure Math. 24 (1973) 181. J. P. Keating, N. C. Snaith, Commun. Math. Phys. 214 (2000) 57. .. GENERATED FROM PYTHON SOURCE LINES 33-103 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np import physicskit.rmt as rmt N_VALUES_K1 = np.arange(1, 13) N_VALUES_K2 = np.arange(1, 9) SEED = 2026 fig, axes = plt.subplots(1, 3, figsize=(16, 4.5)) # --- k=1: exact telescoping E[|Z_n|^2] = n + 1 --- ax = axes[0] exact_k1 = np.array([rmt.stats.keating_snaith_moment(int(n), 1) for n in N_VALUES_K1]) empirical_k1 = [] for n in N_VALUES_K1: ensemble = rmt.ensembles.CUE(n=int(n), seed=SEED) spectrum = ensemble.sample(n_samples=20_000) empirical_k1.append(rmt.stats.characteristic_polynomial_empirical_moment(spectrum.eigenvalues, k=1)) empirical_k1 = np.array(empirical_k1) ax.plot(N_VALUES_K1, exact_k1, "k-", lw=2, label=r"exact: $E[|Z_n|^2] = n+1$") ax.plot(N_VALUES_K1, empirical_k1, "o", color="steelblue", label="Monte Carlo (CUE)") ax.set_xlabel("n") ax.set_ylabel(r"$E[|Z_n(\theta)|^2]$") ax.set_title("k=1 moment") ax.legend(fontsize=8) # --- k=2: the general product formula --- ax = axes[1] exact_k2 = np.array([rmt.stats.keating_snaith_moment(int(n), 2) for n in N_VALUES_K2]) empirical_k2 = [] for n in N_VALUES_K2: ensemble = rmt.ensembles.CUE(n=int(n), seed=SEED + 1) spectrum = ensemble.sample(n_samples=150_000) empirical_k2.append(rmt.stats.characteristic_polynomial_empirical_moment(spectrum.eigenvalues, k=2)) empirical_k2 = np.array(empirical_k2) ax.plot(N_VALUES_K2, exact_k2, "k-", lw=2, label=r"exact: $\prod_j j!(j+4)!/(j+2)!^2$") ax.plot(N_VALUES_K2, empirical_k2, "o", color="indianred", label="Monte Carlo (CUE)") ax.set_yscale("log") ax.set_xlabel("n") ax.set_ylabel(r"$E[|Z_n(\theta)|^4]$") ax.set_title("k=2 moment (log scale)") ax.legend(fontsize=8) # --- Panel 3: the exact moment formula over the full (n, k) grid --- # Panels 1-2 are each a single fixed-k slice through the exact product # formula; this shows the whole 2-parameter landscape at once (exact # values, the same closed form already validated against Monte Carlo # in the two panels above -- no new sampling needed here). n_grid_ks = np.arange(1, 13) k_grid_ks = np.arange(1, 7) log_moment = np.array([[np.log10(rmt.stats.keating_snaith_moment(int(n), int(k))) for n in n_grid_ks] for k in k_grid_ks]) ax = axes[2] extent_ks = [n_grid_ks[0] - 0.5, n_grid_ks[-1] + 0.5, k_grid_ks[0] - 0.5, k_grid_ks[-1] + 0.5] im = ax.imshow(log_moment, aspect="auto", origin="lower", cmap="magma", extent=extent_ks) ax.set_xlabel("n") ax.set_ylabel("k") ax.set_title(r"Exact moment $\log_{10} E[|Z_n(\theta)|^{2k}]$" + "\nover the full (n, k) grid") fig.colorbar(im, ax=ax, label=r"$\log_{10}$ moment") fig.suptitle( "CUE characteristic polynomial moments: exact Keating-Snaith formula vs. Haar-unitary Monte Carlo", ) fig.tight_layout() plt.show() .. image-sg:: /api/gallery/rmt/spacings/images/sphx_glr_plot_riemann_zeta_keating_snaith_moments_001.png :alt: CUE characteristic polynomial moments: exact Keating-Snaith formula vs. Haar-unitary Monte Carlo, k=1 moment, k=2 moment (log scale), Exact moment $\log_{10} E[|Z_n(\theta)|^{2k}]$ over the full (n, k) grid :srcset: /api/gallery/rmt/spacings/images/sphx_glr_plot_riemann_zeta_keating_snaith_moments_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 104-108 Check ----- Keating-Snaith: E|Z|^2 = N + 1 and E|Z|^4 = (N+1)(N+2)^2(N+3)/12, matched by the Haar-unitary Monte Carlo (to a few percent: |Z|^2k is heavy-tailed). .. GENERATED FROM PYTHON SOURCE LINES 108-112 .. code-block:: Python np.testing.assert_allclose(exact_k1, N_VALUES_K1 + 1) np.testing.assert_allclose(exact_k2, (N_VALUES_K2 + 1) * (N_VALUES_K2 + 2) ** 2 * (N_VALUES_K2 + 3) / 12) assert np.max(np.abs(empirical_k1 / exact_k1 - 1)) < 0.08 assert np.max(np.abs(empirical_k2 / exact_k2 - 1)) < 0.08 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 35.217 seconds) .. _sphx_glr_download_api_gallery_rmt_spacings_plot_riemann_zeta_keating_snaith_moments.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_riemann_zeta_keating_snaith_moments.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_riemann_zeta_keating_snaith_moments.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_riemann_zeta_keating_snaith_moments.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_