Overview
Run 003 reproduces the Run 002 pipeline with the same parameters and layout. It updates only the input range and figure set, and keeps the Summary + Reproducibility sections in place for auditability.
Figures



Methods & Parameters
- Zero set: Odlyzko
zeros6.gz
; parsed first ~120k lines; analyzed first 100k ordinates. - Spacings: consecutive gaps Δγ; unfolded to mean 1.0 for comparison tasks.
- Transforms: FFT on unfolded spacings; surrogate comparison via Exponential(1).
- Random seed: 42 (for surrogate generation only).
Results
Spacings (raw)
Δγ mean ≈ 0.749074, σ ≈ 0.321542 (n = 99,999)
Spacings (unfolded)
mean = 1.000000, σ ≈ 0.429252 (n = 99,999)
ECDF
See figure links above (demo + 100k series)
FFT
Magnitude spectra saved for unfolded Δγ vs. Exponential(1) surrogate (see figure)
Discussion
Run 003 matches Run 002 numerically at the summary-stat level (as expected, given identical pipeline and zero range). This run establishes a clean baseline for adding KS/CvM tests and lattice-prime comparisons in subsequent runs without changing file naming or layout.
Limitations
- Finite-sample effects can influence ECDF tails.
- Unfolding assumes a stable mean over the selected window; alternative baselines may be explored.
Run 003 — Summary
Dataset
Odlyzko zeros (
zeros6.gz
): loaded 120,000 ordinates; analyzed first 100,000.Spacings (raw)
Δγ mean ≈ 0.749074, σ ≈ 0.321542 (n = 99,999).
Spacings (unfolded)
Δγ normalized to mean 1.0 → mean = 1.000000, σ ≈ 0.429252 (n = 99,999).
Figures
Metrics CSVs
Manifest
manifest.json (inputs, outputs, timestamps, hashes)
Notes
- Unfolding behaved as expected (full dataset for the check; demo is only a preview slice).
- ECDF shape on unfolded spacings is consistent with the intended comparison setup.
- This run mirrors Run 2 pipeline and naming, suitable for reproducibility and evidence.
Additional Analyses (pending)
- Kolmogorov–Smirnov (KS) tests: unfolded Δγ vs. exponential(1) and lattice-derived references.
- Cramér–von Mises proxy: L² distance on ECDF curves to quantify fit quality.
- Lattice comparisons: spokes n(r) = 3r² − r + c, c ∈ {2..7}, up to Nmax = 1,000,000.
- FFT correlation metrics: overlap between unfolded Δγ and lattice Δn spectra.
These are planned for Run 004+; Run 003 focuses on reproducibility.
Reproducibility — Python (Run 003)
Self-contained pipeline for run003
. Source zeros file:
zeros6.gz.
Environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install numpy pandas matplotlib
1) Download zeros (optional)
# macOS / Linux
curl -L -o zeros6.gz "https://www-users.cse.umn.edu/~odlyzko/zeta_tables/zeros6.gz"
# Windows (PowerShell)
Invoke-WebRequest -Uri "https://www-users.cse.umn.edu/~odlyzko/zeta_tables/zeros6.gz" -OutFile "zeros6.gz"
2) Parse zeros & compute spacings
import gzip, os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
run_base = "run003"
zeros_path = "zeros6.gz"
os.makedirs(os.path.join(run_base, "metrics"), exist_ok=True)
os.makedirs(os.path.join(run_base, "figures"), exist_ok=True)
os.makedirs(os.path.join(run_base, "data"), exist_ok=True)
# Parse first ~120k rows; analyze first 100k
values = []
with gzip.open(zeros_path, "rt", encoding="utf-8", errors="ignore") as f:
for line in f:
line = line.strip()
if not line: continue
tok = line.split()[0]
try:
values.append(float(tok))
except ValueError:
continue
if len(values) >= 120_000:
break
assert len(values) >= 100_000, f"Only {len(values)} zeros parsed."
z100k = np.array(values[:100_000], float)
demo = np.array(values[:5_000], float)
sp_raw = np.diff(z100k)
sp_demo = np.diff(demo)
3) Unfold to mean 1.0
def unfold(s: np.ndarray):
m = float(np.mean(s))
if m == 0 or not np.isfinite(m):
raise ValueError("Invalid mean for unfolding.")
return s / m, m
sp_unf, mean_raw = unfold(sp_raw)
sp_unf_demo, mean_demo = unfold(sp_demo)
print("Raw mean (first100k):", mean_raw)
4) Write metrics CSVs (r003)
pd.DataFrame({"index": np.arange(sp_unf_demo.size), "spacing": sp_unf_demo}) \
.to_csv(os.path.join(run_base, "metrics", "r003_metrics_demo_unfolded.csv"), index=False)
pd.DataFrame({"index": np.arange(sp_raw.size), "spacing": sp_raw}) \
.to_csv(os.path.join(run_base, "metrics", "r003_metrics_first100k_raw.csv"), index=False)
pd.DataFrame({"index": np.arange(sp_unf.size), "spacing": sp_unf}) \
.to_csv(os.path.join(run_base, "metrics", "r003_metrics_first100k_unfolded.csv"), index=False)
5) ECDF plots (r003)
def plot_ecdf(sp, title, outpng):
x = np.sort(sp)
y = np.arange(1, x.size + 1) / x.size
plt.figure(figsize=(7,4.2), dpi=150)
plt.step(x, y, where="post")
plt.xlabel("spacing"); plt.ylabel("ECDF"); plt.title(title)
plt.tight_layout(); plt.savefig(outpng); plt.close()
plot_ecdf(sp_unf_demo, "ECDF — unfolded spacings (demo slice)",
os.path.join(run_base, "figures", "r003_spacing_ecdf_small.png"))
plot_ecdf(sp_unf, "ECDF — unfolded spacings (first 100k zeros)",
os.path.join(run_base, "figures", "r003_spacing_ecdf_full.png"))
6) FFT magnitude comparison (r003)
rng = np.random.default_rng(42)
exp_sur = rng.exponential(1.0, size=sp_unf.size)
def fft_mag(a):
a0 = a - np.mean(a)
F = np.fft.rfft(a0)
return np.abs(F), np.fft.rfftfreq(a.size, d=1.0)
mag_zeros, fz = fft_mag(sp_unf)
mag_exp, fe = fft_mag(exp_sur)
plt.figure(figsize=(7,4.2), dpi=150)
plt.loglog(fz[1:], mag_zeros[1:], label="Unfolded Δγ (first 100k)")
plt.loglog(fe[1:], mag_exp[1:], label="Exponential(1) surrogate")
plt.xlabel("frequency (arb. units)"); plt.ylabel("|FFT| magnitude")
plt.title("FFT magnitude comparison — Run 003")
plt.legend(); plt.tight_layout()
plt.savefig(os.path.join(run_base, "figures", "r003_fft_magnitude_comp.png"))
plt.close()
7) Manifest (optional)
import json, hashlib, datetime
manifest = {
"run": "run003",
"generated_utc": datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
"inputs": {"zeros_source": "zeros6.gz", "first_n_zeros": 100000, "demo_slice": 5000},
"metrics": {"csv_files": [
"metrics/r003_metrics_demo_unfolded.csv",
"metrics/r003_metrics_first100k_raw.csv",
"metrics/r003_metrics_first100k_unfolded.csv"
]},
"figures": [
"figures/r003_spacing_ecdf_small.png",
"figures/r003_spacing_ecdf_full.png",
"figures/r003_fft_magnitude_comp.png"
]
}
with open(os.path.join(run_base, "manifest.json"), "w") as f:
json.dump(manifest, f, indent=2)
Reproducibility — PowerShell (Run 003, native)
# run003_make_all.ps1
param(
[string]$ZerosPath = "zeros6.gz",
[string]$RunBase = "run003",
[int]$Take = 100000,
[int]$Demo = 5000,
[int]$ParseCap = 120000
)
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.IO.Compression.FileSystem
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
function Read-Zeros {
param([string]$gzPath, [int]$cap)
$fs = [IO.File]::OpenRead($gzPath)
$gz = New-Object IO.Compression.GZipStream($fs,[IO.Compression.CompressionMode]::Decompress)
$sr = New-Object IO.StreamReader($gz)
$vals = New-Object System.Collections.Generic.List[double]
while(-not $sr.EndOfStream -and $vals.Count -lt $cap){
$line = $sr.ReadLine().Trim()
if($line.Length -gt 0){
$tok = $line.Split([char[]]::Parse(" `t"))[0]
[double]$v = 0; if([double]::TryParse($tok,[ref]$v)){ $vals.Add($v) }
}
}
$sr.Close(); $gz.Close(); $fs.Close()
return ,$vals.ToArray()
}
function Diff([double[]]$a){ $n=$a.Length-1; $d=New-Object double[] $n; for($i=0;$i -lt $n;$i++){ $d[$i]=$a[$i+1]-$a[$i] } ,$d }
function Unfold([double[]]$s){
$mean = ($s | Measure-Object -Average).Average
if($mean -eq 0 -or [double]::IsNaN($mean)){ throw "Invalid mean." }
$u = New-Object double[] $s.Length
for($i=0;$i -lt $s.Length;$i++){ $u[$i] = $s[$i]/$mean }
return @{ unfolded=$u; mean=$mean }
}
function Write-CSV($path,[double[]]$series){
$dir=[IO.Path]::GetDirectoryName($path); if(-not(Test-Path $dir)){ New-Item -ItemType Directory $dir | Out-Null }
$sw = New-Object IO.StreamWriter($path,$false,[Text.Encoding]::UTF8)
$sw.WriteLine("index,spacing")
for($i=0;$i -lt $series.Length;$i++){ $sw.WriteLine("$i,$($series[$i].ToString('R'))") }
$sw.Close()
}
function Save-ECDF($outPng,[double[]]$spacings,[string]$title){
$sorted = $spacings | Sort-Object
$n = $sorted.Length
$chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart
$chart.Width=800; $chart.Height=480
$area = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$chart.ChartAreas.Add($area)
$series = New-Object System.Windows.Forms.DataVisualization.Charting.Series
$series.ChartType = 'FastLine'; $series.BorderWidth = 2
for($i=0;$i -lt $n;$i++){ [void]$series.Points.AddXY($sorted[$i], ($i+1)/$n) }
$chart.Titles.Add($title) | Out-Null; $chart.Series.Add($series)
$dir=[IO.Path]::GetDirectoryName($outPng); if(-not(Test-Path $dir)){ New-Item -ItemType Directory $dir | Out-Null }
$chart.SaveImage($outPng,'Png')
}
function Save-FFT($outPng,[double[]]$spacings,[string]$title){
$mean = ($spacings | Measure-Object -Average).Average
$a = $spacings | ForEach-Object { $_ - $mean }
$N = $a.Length; $M = [int][math]::Floor($N/2.0)+1
$mag = New-Object double[] $M
for($k=0;$k -lt $M;$k++){
$re=0.0; $im=0.0
for($n=0;$n -lt $N;$n++){
$ang = -2.0*[math]::PI*$k*$n/$N
$re += $a[$n]*[math]::Cos($ang); $im += $a[$n]*[math]::Sin($ang)
}
$mag[$k] = [math]::Sqrt($re*$re + $im*$im)
}
$chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart
$chart.Width=800; $chart.Height=480
$area = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$area.AxisX.IsLogarithmic = $true; $area.AxisY.IsLogarithmic = $true
$chart.ChartAreas.Add($area)
$series = New-Object System.Windows.Forms.DataVisualization.Charting.Series
$series.ChartType = 'FastLine'; $series.BorderWidth=2
for($k=1;$k -lt $M;$k++){ [void]$series.Points.AddXY([double]$k, $mag[$k]) }
$chart.Titles.Add($title) | Out-Null; $chart.Series.Add($series)
$dir=[IO.Path]::GetDirectoryName($outPng); if(-not(Test-Path $dir)){ New-Item -ItemType Directory $dir | Out-Null }
$chart.SaveImage($outPng,'Png')
}
if(-not(Test-Path $RunBase)){ New-Item -ItemType Directory $RunBase | Out-Null }
$vals = Read-Zeros -gzPath $ZerosPath -cap $ParseCap
if($vals.Length -lt $Take){ throw "Parsed only $($vals.Length) zeros." }
$z100k = $vals[0..($Take-1)]
$demoZ = $vals[0..($Demo-1)]
$spRaw = Diff $z100k
$spDemo = Diff $demoZ
$u = Unfold $spRaw; $spUnf = $u.unfolded; $meanRaw = $u.mean
Write-CSV "$RunBase\metrics\r003_metrics_demo_unfolded.csv" (Unfold $spDemo).unfolded
Write-CSV "$RunBase\metrics\r003_metrics_first100k_raw.csv" $spRaw
Write-CSV "$RunBase\metrics\r003_metrics_first100k_unfolded.csv" $spUnf
Save-ECDF "$RunBase\figures\r003_spacing_ecdf_small.png" (Unfold $spDemo).unfolded "ECDF — demo (unfolded)"
Save-ECDF "$RunBase\figures\r003_spacing_ecdf_full.png" $spUnf "ECDF — first 100k (unfolded)"
Save-FFT "$RunBase\figures\r003_fft_magnitude_comp.png" $spUnf "FFT magnitude — Run 003"
Write-Host "Run003 complete. Raw mean=$([math]::Round($meanRaw,6))"
Reproducibility — PHP (CLI, Run 003)
<?php
// run003_make_all.php (CLI: php run003_make_all.php zeros6.gz)
// Outputs CSVs to run003/metrics and report with inline SVG ECDF
$zeros = $argv[1] ?? 'zeros6.gz';
$run = 'run003';
$take = 100000;
$demo = 5000;
$cap = 120000;
@mkdir("$run/metrics", 0777, true);
@mkdir("$run/figures", 0777, true);
// Parse zeros
$vals = [];
$f = gzopen($zeros, 'r');
if(!$f) die("Cannot open $zeros\n");
while(!gzeof($f) && count($vals) < $cap){
$line = trim(gzgets($f));
if($line === '') continue;
$tok = preg_split('/\s+/', $line)[0];
if(is_numeric($tok)) $vals[] = floatval($tok);
}
gzclose($f);
if(count($vals) < $take) die("Parsed only ".count($vals)." zeros\n");
// Helpers
function diff_arr($a){ $n = count($a)-1; $d = []; for($i=0;$i<$n;$i++) $d[]=$a[$i+1]-$a[$i]; return $d; }
function unfold($s){
$m = array_sum($s)/count($s);
if(!$m) throw new Exception("Invalid mean");
$u=[]; foreach($s as $v){ $u[]=$v/$m; }
return [$u,$m];
}
function write_csv($path,$arr){
$fh = fopen($path,'w'); fputs($fh,"index,spacing\n");
foreach($arr as $i=>$v){ fputs($fh,"$i,$v\n"); }
fclose($fh);
}
// Compute
$z100k = array_slice($vals,0,$take);
$demoZ = array_slice($vals,0,$demo);
$spRaw = diff_arr($z100k);
$spDemo = diff_arr($demoZ);
[$spUnf,$meanRaw] = unfold($spRaw);
[$spUnfDemo,$mDemo] = unfold($spDemo);
// CSVs
write_csv("$run/metrics/r003_metrics_demo_unfolded.csv", $spUnfDemo);
write_csv("$run/metrics/r003_metrics_first100k_raw.csv", $spRaw);
write_csv("$run/metrics/r003_metrics_first100k_unfolded.csv", $spUnf);
// Inline SVG ECDF
function ecdf_svg($sp,$title){
sort($sp); $n=count($sp); $w=800; $h=420; $pad=50;
$minX=$sp[0]; $maxX=$sp[$n-1]; if($maxX==$minX) $maxX=$minX+1e-6;
$path=""; for($i=0;$i<$n;$i++){
$x=$sp[$i]; $y=($i+1)/$n;
$sx=$pad+($w-2*$pad)*(($x-$minX)/($maxX-$minX));
$sy=$h-$pad-($h-2*$pad)*$y;
$path.=($i==0?"M":"L").round($sx,2).",".round($sy,2)." ";
}
return "<svg viewBox='0 0 $w $h' width='$w' height='$h'>
<rect x='0' y='0' width='$w' height='$h' fill='white' stroke='#e5e7eb'/>
<path d='$path' fill='none' stroke='black' stroke-width='1.5'/>
<text x='".($w/2)."' y='24' text-anchor='middle' font-family='sans-serif' font-size='16'>$title</text>
</svg>";
}
$svg_demo = ecdf_svg($spUnfDemo, "ECDF — Demo (unfolded)");
$svg_full = ecdf_svg($spUnf, "ECDF — First 100k (unfolded)");
file_put_contents("$run/report.html", "<!doctype html><meta charset='utf-8'><title>Run003 Report</title>
<h1>Run 003 — Report</h1>
<p>Raw mean (first100k): ".number_format($meanRaw,6)."</p>
<h2>ECDF (Demo)</h2>$svg_demo
<h2>ECDF (Full)</h2>$svg_full
<p>CSVs in <code>$run/metrics</code></p>");
echo "Done. CSVs in $run/metrics, report at $run/report.html\n";
?>
Reproducibility — C# (.NET 6 + ScottPlot, Run 003)
Setup
dotnet new console -o Run003Cs
cd Run003Cs
dotnet add package ScottPlot --version 5.0.19
Program.cs
using System.IO.Compression;
using ScottPlot;
string zerosPath = args.Length > 0 ? args[0] : "zeros6.gz";
string runBase = "run003";
int take = 100_000, demo = 5_000, cap = 120_000;
Directory.CreateDirectory(Path.Combine(runBase, "metrics"));
Directory.CreateDirectory(Path.Combine(runBase, "figures"));
// Parse zeros
List<double> vals = new();
using (var fs = File.OpenRead(zerosPath))
using (var gz = new GZipStream(fs, CompressionMode.Decompress))
using (var sr = new StreamReader(gz))
{
string? line;
while ((line = sr.ReadLine()) != null && vals.Count < cap)
{
line = line.Trim();
if (line.Length == 0) continue;
var tok = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries)[0];
if (double.TryParse(tok, out double v)) vals.Add(v);
}
}
if (vals.Count < take) throw new Exception($"Parsed only {vals.Count} zeros.");
double[] z100k = vals.Take(take).ToArray();
double[] demoZ = vals.Take(demo).ToArray();
static double[] Diff(double[] a)
{
double[] d = new double[a.Length - 1];
for (int i = 0; i < d.Length; i++) d[i] = a[i + 1] - a[i];
return d;
}
static (double[] unfolded, double mean) Unfold(double[] s)
{
double mean = s.Average();
if (mean == 0 || double.IsNaN(mean)) throw new Exception("Invalid mean");
double[] u = new double[s.Length];
for (int i = 0; i < s.Length; i++) u[i] = s[i] / mean;
return (u, mean);
}
static void WriteCsv(string path, double[] s)
{
using var sw = new StreamWriter(path);
sw.WriteLine("index,spacing");
for (int i = 0; i < s.Length; i++)
sw.WriteLine($"{i},{s[i]:R}");
}
double[] spRaw = Diff(z100k);
(double[] spUnf, double meanRaw) = Unfold(spRaw);
double[] spDemo = Diff(demoZ);
(double[] spUnfDemo, double _) = Unfold(spDemo);
// CSVs
WriteCsv(Path.Combine(runBase, "metrics", "r003_metrics_demo_unfolded.csv"), spUnfDemo);
WriteCsv(Path.Combine(runBase, "metrics", "r003_metrics_first100k_raw.csv"), spRaw);
WriteCsv(Path.Combine(runBase, "metrics", "r003_metrics_first100k_unfolded.csv"), spUnf);
// ECDF
static void SaveEcdf(string pngPath, double[] s, string title)
{
double[] x = s.OrderBy(v => v).ToArray();
double[] y = Enumerable.Range(1, x.Length).Select(i => (double)i / x.Length).ToArray();
var plt = new ScottPlot.Plot(800, 480);
plt.Add.SignalXY(x, y);
plt.Title(title); plt.XLabel("spacing"); plt.YLabel("ECDF");
plt.SavePng(pngPath, 800, 480);
}
SaveEcdf(Path.Combine(runBase, "figures", "r003_spacing_ecdf_small.png"), spUnfDemo, "ECDF — demo (unfolded)");
SaveEcdf(Path.Combine(runBase, "figures", "r003_spacing_ecdf_full.png"), spUnf, "ECDF — first 100k (unfolded)");
// FFT (naive DFT magnitude)
static (double[] mag, double[] freq) DFTMag(double[] a)
{
int N = a.Length;
double mean = a.Average();
double[] x = a.Select(v => v - mean).ToArray();
int M = N / 2 + 1;
double[] mag = new double[M];
for (int k = 0; k < M; k++)
{
double re = 0, im = 0;
for (int n = 0; n < N; n++)
{
double ang = -2.0 * Math.PI * k * n / N;
re += x[n] * Math.Cos(ang);
im += x[n] * Math.Sin(ang);
}
mag[k] = Math.Sqrt(re * re + im * im);
}
double[] freq = Enumerable.Range(0, M).Select(i => (double)i).ToArray();
return (mag, freq);
}
var (magZeros, fz) = DFTMag(spUnf);
var pltF = new ScottPlot.Plot(800, 480);
pltF.Add.SignalXY(fz.Skip(1).Select(v=> (double)v).ToArray(), magZeros.Skip(1).ToArray());
pltF.Axes.Bottom.ScaleLog10(true);
pltF.Axes.Left.ScaleLog10(true);
pltF.Title("FFT magnitude — Run 003 (unfolded Δγ)");
pltF.XLabel("frequency (arb. units)"); pltF.YLabel("|FFT|");
pltF.SavePng(Path.Combine(runBase, "figures", "r003_fft_magnitude_comp.png"), 800, 480);
Console.WriteLine($"Run003 complete. Raw mean={meanRaw:F6}");
Run
dotnet run -- zeros6.gz