Repository navigation
niveau 5 expert
Session 6 — Frontières de la recherche autour de ζ(s) Méthode : théorie avancée → formule → exploration numérique → code Python
| Animation | Ce qu'elle montre |
|---|---|
| ▶ Distribution des zéros |
|
| ▶ Mur de latence | Goulot |
Ce niveau franchit la frontière entre apprentissage et recherche.
Quatre thèmes de recherche active, tous connectés à
-
TNP et formule explicite — comment les zéros de
$\zeta$ gouvernent les premiers - Matrices aléatoires et GUE — pourquoi les zéros se comportent comme des valeurs propres
-
Fonctions
$L$ généralisées — la famille dont$\zeta$ est le membre le plus simple - Cryptographie et PRNG — applications concrètes de la distribution des premiers
Forme plus précise via le logarithme intégral
Si HR est vraie : l'erreur descend à
La connexion exacte entre
où
Interprétation :
Les zéros "sculpte" la distribution des premiers par interférence de ces ondes.
Pour
-
$\pi(100) = 25$ (25 premiers$\leq 100$ ) $\text{Li}(100) \approx 29{,}08$ - Erreur
$= |25 - 29{,}08| = 4{,}08$
Le premier terme de correction vient de
module
from mpmath import mp, mpf, mpc, log, sqrt, exp, pi, zeta, re, im, fabs, power
from sympy import primerange, factorint
import numpy as np
import matplotlib.pyplot as plt
mp.dps = 20
# ψ(x) exact — fonction de Tchebyshev
def psi_exact(x):
"""ψ(x) = Σ_{p^k ≤ x} log(p)"""
s = mpf(0)
for p in primerange(2, int(x)+1):
pk = p
while pk <= x:
s += log(p)
pk *= p
return float(s)
# ψ(x) approché par formule explicite (N premiers zéros)
zeros_t = [14.134725141734693, 21.022039638771555, 25.010857580145688,
30.424876125859513, 32.935061587739189, 37.586178158825671,
40.918719012147495, 43.327073280914999, 48.005150881167159,
49.773832477672302]
def psi_explicite(x, zeros_t):
"""Approximation de ψ(x) via la formule explicite de Riemann."""
x = mpf(x)
S = x # terme principal
for t in zeros_t:
rho = mpc(0.5, t)
S -= re(power(x, rho) / rho)
rho_conj = mpc(0.5, -t)
S -= re(power(x, rho_conj) / rho_conj)
S -= log(2*pi) # correction constante approx.
return float(S)
# Comparaison
print("Reconstruction de ψ(x) par formule explicite :\n")
print(f"{'x':>8} | {'ψ exact':>12} | {'ψ explicite':>12} | {'Erreur %':>10}")
print("-" * 50)
for x in [10, 20, 50, 100, 200]:
p_ex = psi_exact(x)
p_app = psi_explicite(x, zeros_t)
err = abs(p_ex - p_app) / p_ex * 100 if p_ex > 0 else 0
print(f"{x:>8} | {p_ex:>12.4f} | {p_app:>12.4f} | {err:>9.2f}%")
# Graphique
x_vals = np.linspace(2, 150, 600)
psi_ex_vals = [psi_exact(x) for x in x_vals]
psi_app_vals = [psi_explicite(x, zeros_t) for x in x_vals]
psi_lisse = [float(x) for x in x_vals] # terme principal seul
fig, axes = plt.subplots(2, 1, figsize=(12, 9))
ax1 = axes[0]
ax1.plot(x_vals, psi_ex_vals, 'k-', linewidth=1.5, label='ψ(x) exact')
ax1.plot(x_vals, psi_app_vals, 'r--', linewidth=1.5, label=f'ψ(x) formule explicite ({len(zeros_t)} zéros)')
ax1.plot(x_vals, psi_lisse, 'b:', linewidth=1.5, alpha=0.7, label='ψ(x) ≈ x (terme principal)')
for p in primerange(2, 151):
ax1.axvline(p, color='gray', linewidth=0.3, alpha=0.4)
ax1.set_xlabel('x')
ax1.set_ylabel('ψ(x)')
ax1.set_title('Formule explicite de Riemann — reconstruction de ψ(x)\nChaque zéro de ζ ajoute une oscillation')
ax1.legend(fontsize=9)
ax1.grid(True, alpha=0.3)
ax2 = axes[1]
erreur = [a - e for a, e in zip(psi_app_vals, psi_ex_vals)]
ax2.plot(x_vals, erreur, 'purple', linewidth=1.2)
ax2.axhline(0, color='k', linewidth=0.8)
ax2.set_xlabel('x')
ax2.set_ylabel('ψ_explicite(x) − ψ_exact(x)')
ax2.set_title('Erreur de troncature — due aux zéros non inclus dans la somme')
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("niveau5_formule_explicite.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau5_formule_explicite.png")On normalise les zéros
L'espacement normalisé entre zéros consécutifs est :
Montgomery a conjecturé que la corrélation de paires des zéros de
Connexion avec la physique : les niveaux d'énergie de systèmes quantiques chaotiques (boule de billard quantique, noyaux atomiques lourds) suivent la même statistique GUE.
Les zéros de
Pour GUE, la distribution des espacements
Caractéristique : répulsion de niveaux — la probabilité que deux zéros soient très proches
tend vers
À partir des premiers zéros
Espacement moyen pour
Espacement normalisé :
from mpmath import mp, mpf, pi, log
import numpy as np
from scipy.stats import gaussian_kde
import matplotlib.pyplot as plt
mp.dps = 15
# Zéros de ζ — table de Odlyzko (premiers 1000 zéros approx. via mpmath)
from mpmath import zetazero
mp.dps = 15
print("Calcul des 200 premiers zéros de ζ...")
N_zeros = 200
zeros = [float(zetazero(n).imag) for n in range(1, N_zeros+1)]
print(f" t_1 = {zeros[0]:.6f}")
print(f" t_{N_zeros} = {zeros[-1]:.6f}")
# Normalisation par la densité locale
def densite_locale(t):
return float(log(t / (2*pi)) / (2*pi))
zeros_norm = [t * densite_locale(t) for t in zeros]
espacements = [zeros_norm[n+1] - zeros_norm[n] for n in range(len(zeros_norm)-1)]
# Distribution de Wigner-Dyson (GUE)
s = np.linspace(0, 4, 500)
wigner = (32/np.pi**2) * s**2 * np.exp(-4*s**2/np.pi)
# Distribution de Poisson (processus indépendant — ce que ce N'EST PAS)
poisson = np.exp(-s)
fig, axes = plt.subplots(1, 2, figsize=(13, 6))
# Histogramme des espacements vs loi de Wigner
ax1 = axes[0]
ax1.hist(espacements, bins=40, density=True, alpha=0.6, color='steelblue',
label=f'Espacements des {N_zeros} premiers zéros de ζ')
ax1.plot(s, wigner, 'r-', linewidth=2.5, label='Loi de Wigner-Dyson (GUE)')
ax1.plot(s, poisson, 'g--', linewidth=2, label='Loi de Poisson (indépendant)')
ax1.set_xlabel('Espacement normalisé δ')
ax1.set_ylabel('Densité de probabilité')
ax1.set_title('Distribution des espacements entre zéros de ζ\nvs loi GUE — conjecture de Montgomery')
ax1.legend(fontsize=9)
ax1.grid(True, alpha=0.3)
ax1.set_xlim(0, 4)
# Statistiques des espacements
ax2 = axes[1]
ax2.plot(range(1, len(espacements)+1), espacements, 'b.', markersize=3, alpha=0.5)
ax2.axhline(np.mean(espacements), color='r', linewidth=2,
label=f'Moyenne = {np.mean(espacements):.4f} (théorique ≈ 1)')
ax2.axhline(1.0, color='g', linewidth=1.5, linestyle='--', label='Valeur théorique = 1')
ax2.set_xlabel('Indice n')
ax2.set_ylabel('Espacement normalisé δₙ')
ax2.set_title('Espacements consécutifs entre les zéros normalisés\n(répulsion de niveaux visible)')
ax2.legend(fontsize=9)
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("niveau5_gue_montgomery.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau5_gue_montgomery.png")
# Statistiques de base
print(f"\nStatistiques des {len(espacements)} espacements normalisés :")
print(f" Moyenne : {np.mean(espacements):.6f} (théorique : 1.000)")
print(f" Variance : {np.var(espacements):.6f}")
print(f" Min/Max : {min(espacements):.6f} / {max(espacements):.6f}")
print(f" Nb δ < 0.1 : {sum(1 for d in espacements if d < 0.1)} (répulsion de niveaux)")Un caractère de Dirichlet modulo
-
$\chi(n+q) = \chi(n)$ (périodicité) -
$\chi(mn) = \chi(m)\chi(n)$ (multiplicativité) -
$\chi(n) = 0$ si$\gcd(n,q) > 1$
Le caractère trivial
Propriétés :
-
$L(s,\chi)$ est holomorphe sur$\mathbb{C}$ si$\chi \neq \chi_0$ -
$L(s,\chi_0)$ a un pôle simple en$s=1$ (comme$\zeta$ ) - Équation fonctionnelle similaire à celle de
$\zeta$
Pour
La preuve utilise que
Densité : parmi les premiers
Tous les zéros non triviaux de
$L(s,\chi)$ ont partie réelle$\tfrac{1}{2}$ .
C'est l'analogue de HR pour toutes les fonctions
from mpmath import mp, mpc, zeta, re, im, fabs, log, pi, exp
import numpy as np
import matplotlib.pyplot as plt
mp.dps = 15
# Caractère de Dirichlet χ mod 4 (le seul non trivial mod 4)
# χ(1)=1, χ(3)=-1, χ(0)=χ(2)=0
def chi4(n):
n = n % 4
if n == 1: return 1
if n == 3: return -1
return 0
def L_dirichlet(s, chi, N=5000):
"""Calcul de L(s,χ) = Σ χ(n)/nˢ par troncature."""
s = mpc(s)
total = mpc(0)
for n in range(1, N+1):
c = chi(n)
if c != 0:
total += mpc(c) / mpc(n)**s
return total
# Comparaison ζ(s) et L(s, χ₄)
print("Valeurs de ζ(s) et L(s, χ₄) = Σ(-1)ⁿ/(2n+1)ˢ pour s réel :\n")
print(f"{'s':>6} | {'ζ(s)':>14} | {'L(s,χ₄)':>14} | Note")
print("-" * 58)
for s_val, note in [(1, 'pôle pour ζ'), (2, 'π²/6'), (3, ''), (4, 'π⁴/90')]:
z = zeta(s_val) if s_val > 1 else float('inf')
l = float(re(L_dirichlet(s_val, chi4)))
print(f"{s_val:>6} | {float(z) if z != float('inf') else 'pôle':>14} | {l:>14.8f} | {note}")
# L(1, χ₄) = π/4 (formule de Leibniz)
print(f"\nL(1, χ₄) = 1 - 1/3 + 1/5 - 1/7 + ... = π/4 ≈ {float(pi)/4:.8f}")
L1_num = float(re(L_dirichlet(1, chi4)))
print(f"L(1, χ₄) numérique = {L1_num:.8f}")
# Module |L(1/2 + it, χ₄)| sur la droite critique
t_vals = np.linspace(1, 50, 500)
L_crit = [float(fabs(L_dirichlet(mpc(0.5, t), chi4, N=2000))) for t in t_vals]
Z_crit = [float(fabs(zeta(mpc(0.5, t)))) for t in t_vals]
fig, ax = plt.subplots(figsize=(11, 5))
ax.plot(t_vals, Z_crit, 'b-', linewidth=1.5, alpha=0.8, label='|ζ(1/2+it)|')
ax.plot(t_vals, L_crit, 'r-', linewidth=1.5, alpha=0.8, label='|L(1/2+it, χ₄)|')
ax.axhline(0, color='k', linewidth=0.5)
ax.set_xlabel('t')
ax.set_ylabel('Module')
ax.set_title('|ζ(1/2+it)| et |L(1/2+it, χ₄)| sur la droite critique\n'
'Les zéros des fonctions L généralisées obéissent à GRH (conjecturée)')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("niveau5_fonctions_L.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau5_fonctions_L.png")La sécurité de RSA repose sur la difficulté de factoriser
HR quantifie précisément cette irrégularité :
- HR vraie → erreur
$O(\sqrt{x}\log x)$ dans le TNP → distribution "presque régulière" - HR fausse → erreur bien plus grande → distribution bien plus irrégulière
Des algorithmes de génération de premiers (Miller-Rabin probabiliste, AKS déterministe) utilisent des résultats conditionnels à GRH.
Une idée expérimentale : utiliser les zéros de
Principe : les parties fractionnaires
Ce PRNG est étudié dans la littérature comme test de l'hypothèse de normalité (Weyl, 1916) appliquée aux zéros.
Alan Turing a proposé en 1953 une méthode pour certifier qu'aucun zéro
n'a été manqué dans un intervalle
Critère de Backlund :
Si le nombre de changements de signe de
Mathlib4 (bibliothèque Lean 4) contient :
- La définition formelle de
$\zeta(s)$ - La preuve du TNP
- Des lemmes sur
$\Gamma(s)$
Exemple de structure d'une preuve Lean 4 autour de ζ :
-- Définition de ζ pour Re(s) > 1
noncomputable def riemannZeta : ℂ → ℂ := Complex.riemannZeta
-- Le TNP en Lean 4 (disponible dans Mathlib)
theorem prime_number_theorem :
Tendsto (fun x => π x / (x / Real.log x)) atTop (𝓝 1) := by
exact PrimeNumberTheorem.tendsto_pi_div_x_div_log_xL'objectif à long terme du projet : formaliser des résultats partiels autour de HR en utilisant Lean 4 + Mathlib4.
from mpmath import mp, zetazero, frac, log, pi
import numpy as np
from scipy.stats import kstest, uniform
import matplotlib.pyplot as plt
mp.dps = 20
# Génération de la suite pseudo-aléatoire via les zéros de ζ
print("Calcul des 500 premiers zéros de ζ pour le PRNG...")
N = 500
zeros_im = [float(zetazero(n).imag) for n in range(1, N+1)]
# Parties fractionnaires de t_n * log(2) — test de Weyl
seq_log2 = [float(frac(t * log(2))) for t in zeros_im]
# Parties fractionnaires de t_n / (2π) — espacement normalisé
seq_2pi = [float(frac(t / (2*pi))) for t in zeros_im]
# Test de Kolmogorov-Smirnov contre la loi uniforme [0,1]
ks_log2, p_log2 = kstest(seq_log2, 'uniform')
ks_2pi, p_2pi = kstest(seq_2pi, 'uniform')
print(f"\nTest KS d'uniformité sur {N} valeurs :")
print(f" {{t_n·log2}} : statistique KS = {ks_log2:.4f}, p-valeur = {p_log2:.4f}")
print(f" {{t_n/2π}} : statistique KS = {ks_2pi:.4f}, p-valeur = {p_2pi:.4f}")
print(f" (p > 0.05 = pas de raison de rejeter l'uniformité)")
fig, axes = plt.subplots(2, 2, figsize=(13, 10))
# Histogramme {t_n · log 2}
ax1 = axes[0][0]
ax1.hist(seq_log2, bins=25, density=True, alpha=0.7, color='steelblue')
ax1.axhline(1, color='r', linewidth=2, linestyle='--', label='Uniforme [0,1]')
ax1.set_title(f'Distribution de {{t_n·log 2}}\nKS={ks_log2:.4f}, p={p_log2:.3f}')
ax1.set_xlabel('Partie fractionnaire')
ax1.legend()
ax1.grid(True, alpha=0.3)
# Diagramme de dispersion (t_n, t_{n+1}) pour détecter corrélations
ax2 = axes[0][1]
ax2.scatter(seq_log2[:-1], seq_log2[1:], s=3, alpha=0.4, color='steelblue')
ax2.set_title('Diagramme de retard : (uₙ, uₙ₊₁)\n(absence de structure = bonne aléatoire)')
ax2.set_xlabel('uₙ')
ax2.set_ylabel('uₙ₊₁')
ax2.grid(True, alpha=0.3)
# Autocorrélation
ax3 = axes[1][0]
corr = np.correlate(seq_log2 - np.mean(seq_log2),
seq_log2 - np.mean(seq_log2), mode='full')
corr = corr[len(corr)//2:] / corr[len(corr)//2]
ax3.plot(range(50), corr[:50], 'b-o', markersize=4)
ax3.axhline(0, color='k', linewidth=0.8)
ax3.axhline(1.96/np.sqrt(N), color='r', linestyle='--', alpha=0.7, label='±1.96/√N (intervalle 95%)')
ax3.axhline(-1.96/np.sqrt(N), color='r', linestyle='--', alpha=0.7)
ax3.set_title('Autocorrélation de {t_n·log 2}\n(doit rester dans les bandes rouges)')
ax3.set_xlabel('Décalage k')
ax3.set_ylabel('Autocorrélation')
ax3.legend(fontsize=8)
ax3.grid(True, alpha=0.3)
# Évolution de la p-valeur KS en fonction de N
ax4 = axes[1][1]
ns = range(50, N, 10)
p_vals = [kstest(seq_log2[:n], 'uniform')[1] for n in ns]
ax4.plot(ns, p_vals, 'g-', linewidth=1.5)
ax4.axhline(0.05, color='r', linestyle='--', label='Seuil p=0.05')
ax4.set_xlabel('Nombre de zéros utilisés (N)')
ax4.set_ylabel('p-valeur KS')
ax4.set_title('Robustesse du test KS selon N\n(p > 0.05 = uniformité non rejetée)')
ax4.legend()
ax4.grid(True, alpha=0.3)
ax4.set_ylim(0, 1)
plt.tight_layout()
plt.savefig("niveau5_prng_zeta.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau5_prng_zeta.png")Calculez la contribution du seul premier zéro
Avec les 1000 premiers zéros (via zetazero), recalculez la distribution des espacements normalisés.
Comparez la moyenne et la variance obtenues aux prédictions théoriques GUE :
Calculez
Comparez à la valeur exacte
Implémentez le critère de Backlund pour vérifier qu'aucun zéro n'a été manqué
dans l'intervalle
graph TD
A["ζ(s) — prolongement sur C\\{1}"] --> B["Formule explicite\nψ(x) = x − Σ xᵨ/ρ − ..."]
B --> C["TNP : π(x) ~ x/log x"]
B --> D["HR → erreur O(√x log x)"]
A --> E["Zéros non triviaux\nρ = 1/2 + itₙ"]
E --> F["Espacements normalisés\nδₙ = t̃ₙ₊₁ − t̃ₙ"]
F --> G["Conjecture de Montgomery\nstatistiques = GUE"]
G --> H["Connexion physique\nniveaux d'énergie quantiques"]
A --> I["Fonctions L de Dirichlet\nL(s,χ) = Σ χ(n)/nˢ"]
I --> J["GRH : tous les zéros\nsur Re(s) = 1/2"]
I --> K["Th. Dirichlet\npremiers en progression arithm."]
A --> L["Cryptographie RSA\ndifficulté de factorisation"]
E --> M["PRNG ζ\n{tₙ·log 2} ~ Uniforme"]
A --> N["Lean 4 / Mathlib\npreuves formelles de HR ?"]
| Concept | Formule / Résultat | Importance |
|---|---|---|
| Formule explicite | Lien direct zéros ↔ premiers | |
| TNP conditionnel à HR | Meilleure borne connue sous HR | |
| Conjecture Montgomery | Espacements ~ GUE | Connexion théorie des nombres / physique |
| Loi de Wigner-Dyson | Répulsion de niveaux des zéros | |
| Fonctions |
Généralisation de |
|
| GRH | HR pour toutes les fonctions |
|
| PRNG ζ | Aléatoire des zéros (conjectural) |
| Thème | Description | Références |
|---|---|---|
| Conjecture de Birch-Swinnerton-Dyer | Analogue de HR pour les courbes elliptiques | arXiv:math.NT |
| Programme de Langlands | Unification des fonctions |
LMFDB, arXiv |
| Hypothèse de Lindelöf | Plus faible que HR | |
| Moments de |
Connexion avec GUE | |
| Zéros de |
AKS, Miller-Rabin sous GRH | Théorie algorithmique |
Dernière mise à jour : 22 mai 2026 — 585 lignes