"""
Preface (Relational Riemann Hypothesis)
---------------------------------------
This operationalizes the RH-UCF hypothesis within the UCF/GUTT framework as a
diagnostic—not a proof—of RH. We build a finite, prime-indexed coupling operator C_s and
evaluate two debiased symmetry tests designed to avoid “baked-in” reflection effects:
• D̃(s): functional-equation–whitened reflection mismatch (RSC diagnostic)
• S_J(s): J-self-adjointness misfit (RBC diagnostic)
Numerical signatures that would support the Relational RH picture:
(i) For a range of t, both D̃ and S_J attain minima near σ = 1/2.
(ii) The eigenvalue cloud of C_s appears “most real-like” on σ = 1/2.
(iii) These patterns persist across interaction kernels and sharpen as |P| increases
(finite-size scaling), with π-normalization mitigating large-prime bias.
Signals that would count against it:
• Stable, reproducible minima away from σ = 1/2 that survive kernel swaps and scaling,
or degradation of the effect as |P| grows.
Mathematical north star (operator path):
These computations scaffold an operator-theoretic statement that, in the |P| → ∞ limit,
the coupling obeys J C_s = C_s* J only on σ = 1/2, with a spectrum compatible with a
Hilbert–Pólya–style mechanism. Nothing here proves RH; the goal is to stress-test the
Relational RH heuristics with falsifiable numerics.
UCF/GUTT — Relational Operator Diagnostics for a “Relational RH” Experiment
===========================================================================
We implement the UCF/GUTT view of prime interactions as a finite coupling operator C_s
on a prime-indexed Hilbert space, then probe two debiased symmetry diagnostics and inspect
eigenvalue snapshots:
• D̃(s): functional-factor–whitened reflection mismatch across s ↔ (1 − s)
(Relational Symmetry Condition, RSC, in operator form)
• S_J(s): J-self-adjointness misfit (Relational Balance Condition, RBC;
“closest to self-adjoint” on the critical line)
• Eig(C_s): eigenvalue clouds along verticals and on the critical line
(spectrum expected to look most real-like at σ = 1/2)
Key modeling choices (consistent with UCF/GUTT):
- Tensor T_{p,q}(s): normalized prime-interaction tensor (π-normalization)
- Coupling operator: (C_s)_{a,b} = Σ_g f(T_{a,g}(s) · conj(T_{g,b}(s)))
- Interaction f(Δ): oscillatory/decaying kernel f(Δ) = exp(i β Re Δ) · exp(−α |Δ|)
- Functional whitening: divide C_s by the classical functional factor C_func(s) to
suppress symmetry inherited from ζ’s functional equation
- J metric: J = diag(p^{σ − 1/2}) encodes the σ ↔ 1/2 flip as a metric change;
JC_s ≈ C_s*J on the critical line indicates near self-adjointness
Caveats:
- Finite (|P|) truncation ⇒ empirical diagnostics, not proofs.
- Build cost grows ~ O(|P|^3); caching is used on the grid.
- Swap π(x) approximation for sharper normalization if desired.
Author: Michael Fillippini
Date: 2025
"""
import numpy as np
import mpmath as mp
import math
import pandas as pd
import matplotlib.pyplot as plt
# High-precision for |zeta| and functional factor
mp.mp.dps = 50
# ---------- primes -----------------------------------------------------------
def primes_upto(n):
"""
Sieve of Eratosthenes.
UCF/GUTT note:
The prime set P defines the index set of the finite-dimensional
Hilbert space ℓ^2(P) on which we realize the coupling operator C_s.
Increasing n (and slicing more primes) is the finite-size scaling knob
for your “infinite symmetry” limit |P| → ∞.
"""
sieve = [True]*(n+1)
sieve[0:2] = [False, False]
for p in range(2, int(n**0.5)+1):
if sieve[p]:
start = p*p
sieve[start:n+1:p] = [False]*len(range(start, n+1, p))
return [i for i, is_prime in enumerate(sieve) if is_prime]
# Choose a moderate size for tractability; increase for scaling studies
P = primes_upto(400)[:35] # 35 primes (<= 149)
def pi_approx(x):
"""
Crude π(x) ≈ x / log x.
UCF/GUTT note:
π-normalization is your density correction inside T_{p,q}(s). A sharper
approximation (e.g., Dusart bounds or Riemann R) can be substituted
with no change to the interface.
"""
if x < 3:
return 1.0
return x / math.log(x)
# ---------- T and f ----------------------------------------------------------
def Tpq(s, p, q, use_density_norm=True):
"""
Relational tensor element T_{p,q}(s).
Definition (UCF/GUTT, π-normalized):
T_{p,q}(s) = [log p · log q] / (p+q)^s · 1/(π(p) π(q)) [optional]
Rationale:
- log factors encode ‘prime strength’ (Euler product echo).
- (p+q)^s couples s into the pair (p,q); we use principal branch powering.
- π-normalization dampens large-prime dominance (density correction).
Returns: complex
"""
logp = math.log(p); logq = math.log(q)
val = (logp * logq) / ((p + q) ** s)
if use_density_norm:
val = val / (pi_approx(p) * pi_approx(q))
return complex(val)
def f_interact_phase(delta, alpha=0.6, beta=math.pi):
"""
Oscillatory-decaying interaction kernel f(Δ) = exp(i β Re Δ) · exp(-α|Δ|).
UCF/GUTT note:
- Using Δ := T_{a,g}(s) · conj(T_{g,b}(s)) respects ‘two-leg’ coupling via g.
- β = π (“zeta-wave”) sets the oscillation scale; α > 0 damps long-range.
- Real/imag structure comes from Δ; we keep phase via Re Δ for stability.
"""
return np.exp(1j * beta * float(np.real(delta))) * np.exp(-alpha * float(np.abs(delta)))
# ---------- cache for C(s) ---------------------------------------------------
_C_cache = {}
def build_C(s, primes, alpha=0.6, beta=math.pi, density_norm=True):
"""
Assemble the coupling operator C_s on ℓ^2(P):
(C_s)_{a,b} = Σ_{g∈P} f( T_{a,g}(s) · conj(T_{g,b}(s)) )
Interpretation (UCF/GUTT):
- C_s is the prime–prime ‘coupling tensor’ collapsed to an operator.
- Summation over g implements the relational ‘mediator’ channel.
- Different f (Gaussian, log, oscillatory) probe different relational laws.
Caching:
C_s depends only on s, P, and kernel parameters; we memoize by a key.
Returns: np.ndarray (complex) of shape (|P|, |P|)
"""
key = (float(np.real(s)), float(np.imag(s)), len(primes), alpha, beta, density_norm)
if key in _C_cache:
return _C_cache[key]
T = {(p,q): Tpq(s, p, q, use_density_norm=density_norm) for p in primes for q in primes}
n = len(primes)
C = np.zeros((n, n), dtype=np.complex128)
for i, a in enumerate(primes):
for j, b in enumerate(primes):
acc = 0+0j
for g in primes:
# Δ is the g-channeled interaction between a and b
delta = T[(a,g)] * np.conj(T[(g,b)])
acc += f_interact_phase(delta, alpha=alpha, beta=beta)
C[i, j] = acc
_C_cache[key] = C
return C
# ---------- functional factor (whitening) ------------------------------------
def functional_factor(s):
"""
Classical functional factor:
C_func(s) = 2^s · π^{s-1} · sin(π s / 2) · Γ(1 - s)
Purpose:
We ‘whiten’ (divide out) C_s and C_{1-s} by C_func to suppress the trivial
s↔(1-s) magnitude symmetry inherited from ζ’s functional equation.
This makes D_tilde a *debiased* RSC diagnostic.
Returns: complex
"""
s_mp = mp.mpc(s.real, s.imag)
val = (mp.power(2, s_mp) *
mp.power(mp.pi, s_mp - 1) *
mp.sin(mp.pi * s_mp / 2) *
mp.gamma(1 - s_mp))
return complex(val)
# ---------- diagnostics: RSC (debiased) & RBC (J-self-adjointness) -----------
def D_tilde_from_cached(s, primes, alpha=0.6, beta=math.pi, density_norm=True):
"""
Debiased Relational Symmetry Condition (RSC) diagnostic:
D_tilde(s) = || (C(s)/C_func(s)) - conj(C(1-s)/C_func(1-s)) ||_F
Interpretation:
- If RSC holds *after* functional whitening, D_tilde(s) should be minimal
near Re(s)=1/2; a valley there supports the relational symmetry claim.
"""
Cs = build_C(s, primes, alpha=alpha, beta=beta, density_norm=density_norm)
s1 = 1 - s
C1s = build_C(s1, primes, alpha=alpha, beta=beta, density_norm=density_norm)
Fs = functional_factor(s) or (1e-30+0j)
F1s = functional_factor(s1) or (1e-30+0j)
A = (1/Fs) * Cs - np.conj((1/F1s) * C1s)
return float(np.linalg.norm(A, 'fro'))
def S_J_from_cached(s, primes, alpha=0.6, beta=math.pi, density_norm=True):
"""
J-self-adjointness misfit (Relational Balance Condition, RBC):
S_J(s) = || J C_s - C_s^* J ||_F / ||C_s||_F ,
where J = diag(p^{σ - 1/2}) and s = σ + it.
Interpretation:
- On σ = 1/2, J = I and this reduces to ||C_s - C_s^*|| / ||C_s||,
i.e., ‘how close is C_s to self-adjoint?’
- Off the line, J twists the metric so the σ↔1/2 reflection is encoded;
a minimum of S_J at σ=1/2 across t supports RBC.
"""
Cs = build_C(s, primes, alpha=alpha, beta=beta, density_norm=density_norm)
sigma = s.real
ex = sigma - 0.5
J_diag = np.array([p**ex for p in primes], dtype=np.float64)
J = np.diag(J_diag)
num = np.linalg.norm(J @ Cs - Cs.conj().T @ J)
den = np.linalg.norm(Cs)
return float(num/den) if den > 0 else 0.0
# ---------- grids (reduced to keep runtime reasonable) -----------------------
sigmas = np.array([0.35, 0.40, 0.45, 0.50, 0.60, 0.65]) # focus around 1/2
tvals = np.array([10.0, 15.0, 20.0, 25.0, 30.0]) # early heights
# Kernel / normalization controls (UCF/GUTT knobs)
alpha = 0.6 # decay strength (relational range)
beta = math.pi # β = π (“zeta-wave”)
density_norm = True # π-normalization in T_{p,q}
# ---------- compute heatmap data ---------------------------------------------
print("Computing metrics over the (σ, t) grid... This may take a moment.")
Dtilde_grid = np.zeros((len(tvals), len(sigmas)))
SJ_grid = np.zeros_like(Dtilde_grid)
Zabs_grid = np.zeros_like(Dtilde_grid) # classical |ζ(s)| for reference only
for i, t in enumerate(tvals):
print(f" Processing t = {t:.1f}")
for j, sigma in enumerate(sigmas):
s = complex(float(sigma), float(t))
Dtilde_grid[i, j] = D_tilde_from_cached(s, P, alpha=alpha, beta=beta, density_norm=density_norm)
SJ_grid[i, j] = S_J_from_cached(s, P, alpha=alpha, beta=beta, density_norm=density_norm)
Zabs_grid[i, j] = float(abs(mp.zeta(mp.mpc(s.real, s.imag))))
print("Computation complete.\n")
# Present as tables (easy to export for papers)
df_Dtilde = pd.DataFrame(Dtilde_grid, index=[f"t={t:.1f}" for t in tvals],
columns=[f"sigma={s:.2f}" for s in sigmas])
df_SJ = pd.DataFrame(SJ_grid, index=[f"t={t:.1f}" for t in tvals],
columns=[f"sigma={s:.2f}" for s in sigmas])
df_Z = pd.DataFrame(Zabs_grid, index=[f"t={t:.1f}" for t in tvals],
columns=[f"sigma={s:.2f}" for s in sigmas])
print("\n--- D_tilde(s) heatmap data (β=π) ---")
print(df_Dtilde)
print("\n" + "="*50 + "\n")
print("\n--- S_J(s) J-self-adjoint misfit heatmap data (β=π) ---")
print(df_SJ)
print("\n" + "="*50 + "\n")
print("\n--- |zeta(s)| heatmap data (for reference) ---")
print(df_Z)
print("\n" + "="*50 + "\n")
# ---------- heatmaps (visual overview) ---------------------------------------
print("Generating heatmap plots...")
plt.figure(figsize=(8,6))
plt.imshow(Dtilde_grid, aspect='auto', origin='lower',
extent=[sigmas.min(), sigmas.max(), tvals.min(), tvals.max()])
plt.colorbar(label="Misfit Value")
plt.xlabel("Re(s) = sigma")
plt.ylabel("Im(s) = t")
plt.title("Heatmap of D_tilde(s) (β=π) – debiased RSC")
plt.savefig("D_tilde_heatmap.png")
plt.show()
plt.figure(figsize=(8,6))
plt.imshow(SJ_grid, aspect='auto', origin='lower',
extent=[sigmas.min(), sigmas.max(), tvals.min(), tvals.max()])
plt.colorbar(label="Normalized Misfit")
plt.xlabel("Re(s) = sigma")
plt.ylabel("Im(s) = t")
plt.title("Heatmap of S_J(s) (β=π) – J-self-adjointness (RBC)")
plt.savefig("S_J_heatmap.png")
plt.show()
plt.figure(figsize=(8,6))
plt.imshow(Zabs_grid, aspect='auto', origin='lower',
extent=[sigmas.min(), sigmas.max(), tvals.min(), tvals.max()])
plt.colorbar(label="|ζ(s)|")
plt.xlabel("Re(s) = sigma")
plt.ylabel("Im(s) = t")
plt.title("Heatmap of |zeta(s)| (classical reference)")
plt.savefig("zeta_heatmap.png")
plt.show()
# ---------- eigenvalues (spectral signatures) --------------------------------
def eigvals_C(s):
"""
Eigenvalues of the coupling operator C_s.
UCF/GUTT expectation:
- On σ=1/2, if JC_s ≈ C_s^*J, spectrum should be ‘most real-like’.
- Near classical zero ordinates, leading modes may tighten/separate.
"""
C = build_C(s, P, alpha=alpha, beta=beta, density_norm=density_norm)
return np.linalg.eigvals(C)
print("Generating eigenvalue plots...")
# Vertical line at t=25.0, compare σ off/on/off the line
for i, sig in enumerate([0.35, 0.50, 0.65]):
s = complex(float(sig), 25.0)
w = eigvals_C(s)
plt.figure(figsize=(6,6))
plt.scatter(w.real, w.imag, s=12)
plt.xlabel("Re(eigenvalue)")
plt.ylabel("Im(eigenvalue)")
plt.title(f"Eigenvalues of C_s at t=25.0, sigma={sig}")
plt.axhline(0, linewidth=0.5, color='gray')
plt.axvline(0, linewidth=0.5, color='gray')
plt.grid(True, linestyle=':')
plt.savefig(f"eigenvalues_t25_sigma{int(sig*100)}.png")
plt.show()
# On the critical line, probe near first zero heights (classic t’s)
for i, t in enumerate([14.134725, 21.022040, 25.010857]):
s = complex(0.5, float(t))
w = eigvals_C(s)
plt.figure(figsize=(6,6))
plt.scatter(w.real, w.imag, s=12)
plt.xlabel("Re(eigenvalue)")
plt.ylabel("Im(eigenvalue)")
plt.title(f"Eigenvalues of C_s on sigma=0.5 at t={t:.6f}")
plt.axhline(0, linewidth=0.5, color='gray')
plt.axvline(0, linewidth=0.5, color='gray')
plt.grid(True, linestyle=':')
plt.savefig(f"eigenvalues_sigma05_t{int(t)}.png")
plt.show()
# ---------- summary of minima (where symmetry “locks in”) --------------------
min_D_idx = np.argmin(Dtilde_grid, axis=1)
min_S_idx = np.argmin(SJ_grid, axis=1)
summary = pd.DataFrame({
"t": tvals,
"sigma_at_min_Dtilde": sigmas[min_D_idx], # debiased RSC valley location
"min_Dtilde": Dtilde_grid[np.arange(len(tvals)), min_D_idx],
"sigma_at_min_SJ": sigmas[min_S_idx], # RBC valley location
"min_SJ": SJ_grid[np.arange(len(tvals)), min_S_idx],
})
print("\n--- For each t: minima locations for D_tilde and S_J (β=π) ---")
print(summary)
print("\n" + "="*50 + "\n")
# ------------------------------ Notes & TODOs --------------------------------
# • Swap f_interact_phase for Gaussian/log/hybrid to test robustness.
# • Replace pi_approx with a sharper π(x) for better normalization.
# • Add weights w(g) in build_C to emphasize gaps or magnitude bands:
# acc += w(g) * f( T[a,g] * conj(T[g,b]) )
# • Finite-size scaling: increase |P| and track valley width & S_J minima.
# • Rigorous path: define a limit operator on ℓ^2(P), prove JC = C^*J on σ=1/2,
# and relate spec(C_s) to ξ(s) via a determinant identity (Hilbert–Pólya echo).