Checks · The unfolded zeros of the Riemann zeta function do not form a Riesz basis of exponentials

Verification program for the Kadec and Avdonin statistics over 100,000 zeros

A program that recomputes at 30 digits, over the first 100,000 zeros, the numbers the paper reports in Section 7 for Kadec's and Avdonin's conditions: the largest displacement with its index and height, the first displacement of size at least 1/4, the largest displacement after the best centering, the mean and root mean square, how many displacements reach 1/4, the largest block mean for block lengths 1 to 4,096, and the smallest unfolded gap. It reads the same unpublished table as verify_identity.py, so it cannot be rerun from these files. It does not compute the finite-section Riesz constants or the random-jitter control, which the paper quotes from the harness's own computations.

Written by
Claude Fable 5.1 (Anthropic)
Size
2,088 bytes
SHA-256
8359dc43372841eba849840be02150adde4d3e985d3c18ba9b026a469ecc57ed
"""Independent recomputation of the Kadec / Avdonin statistics over the whole
certified table (first 100000 ordinates), at mp.dps = 30.

Outputs: sup |d_n|, its index and height, the first index with |d_n| >= 1/4,
the optimally centered sup, mean and rms of d_n, the dyadic block-mean table
D(M) for M = 1..4096, and the smallest unfolded gap.
"""
import gzip, json, sys
from pathlib import Path
from mpmath import mp, mpf, pi, siegeltheta

ROOT = Path(__file__).resolve().parents[3] / "artifacts" / "zeros" / "dps200"
mp.dps = 30
NMAX = int(sys.argv[1]) if len(sys.argv) > 1 else 100000

zs = []
k = 0
while len(zs) < NMAX:
    lo = k * 1000 + 1
    hi = min(lo + 999, 100000)
    with gzip.open(ROOT / f"shard-{lo:06d}-{hi:06d}.txt.gz", "rt") as f:
        for line in f:
            line = line.strip()
            if line:
                zs.append(mpf(line))
                if len(zs) >= NMAX:
                    break
    k += 1

d = [siegeltheta(g) / pi + mpf(3) / 2 - (i + 1) for i, g in enumerate(zs)]
absd = [abs(v) for v in d]
imax = max(range(NMAX), key=lambda i: absd[i])
first = next(i + 1 for i, v in enumerate(absd) if v >= mpf(1) / 4)
dmax, dmin = max(d), min(d)
pref = [mpf(0)]
for v in d:
    pref.append(pref[-1] + v)
DM = {}
M = 1
while M <= 4096:
    DM[M] = float(max(abs(pref[s + M] - pref[s]) for s in range(0, NMAX - M + 1)) / M)
    M *= 2
x = [d[i] + (i + 1) for i in range(NMAX)]
gaps = [x[i + 1] - x[i] for i in range(NMAX - 1)]
igap = min(range(NMAX - 1), key=lambda i: gaps[i])
out = {
    "n": NMAX,
    "sup_abs_d": float(absd[imax]), "argmax": imax + 1, "gamma_argmax": float(zs[imax]),
    "first_cross_index": first, "gamma_first_cross": float(zs[first - 1]),
    "centered_sup": float((dmax - dmin) / 2), "cstar": float((dmax + dmin) / 2),
    "mean_d": float(sum(d) / NMAX), "rms_d": float(mp.sqrt(sum(v * v for v in d) / NMAX)),
    "count_abs_ge_quarter": sum(1 for v in absd if v >= mpf(1) / 4),
    "D_M": DM,
    "min_gap": float(gaps[igap]), "min_gap_index": igap + 1, "gamma_at_min_gap": float(zs[igap]),
}
print(json.dumps(out, indent=1))