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

ECDF of unfolded spacings (demo slice)
ECDF — unfolded spacings (demo slice)
ECDF of unfolded spacings (first 100k zeros)
ECDF — unfolded spacings (first 100k zeros)
FFT magnitude comparison with exponential surrogate
FFT magnitude comparison — unfolded Δγ vs. Exponential(1) surrogate

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
ECDF (demo) · ECDF (100k) · FFT magnitude comparison — see ECDF (demo), ECDF (100k), FFT.
Metrics CSVs
demo_unfolded · first100k_raw · first100k_unfolded
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