sentinel-chronos-audit / scripts /exp1c_roots.py
5dimension's picture
Upload scripts/exp1c_roots.py with huggingface_hub
f7c4905 verified
"""
EXPERIMENT 1c: Robust root finding for F(z) = sum z^n/n^n
Using continuation method from known roots.
"""
import numpy as np
from scipy.optimize import fsolve
import json
def F_vec(zv, N=150):
z = complex(zv[0], zv[1])
result = 0.0 + 0.0j
for n in range(1, N+1):
try:
term = z**n / n**n
except (OverflowError, ZeroDivisionError):
break
if abs(term) > 1e100 or np.isnan(abs(term)) or np.isinf(abs(term)):
break
result += term
return [result.real, result.imag]
# Start from known roots and extend
known_roots = [
(-4.305, 14.945),
(-5.386, 32.038),
(-5.996, 49.129),
(-6.421, 66.215),
]
roots = []
for kr in known_roots:
r = complex(kr[0], kr[1])
val = complex(*F_vec([r.real, r.imag]))
if abs(val) < 1e-3:
# Refine with fsolve
refined = fsolve(F_vec, [r.real, r.imag], full_output=False)
r = complex(refined[0], refined[1])
roots.append(r)
# Continue from last known root
if len(roots) > 0:
last_root = roots[-1]
# Estimate next root position
if len(roots) >= 2:
im_step = roots[-1].imag - roots[-2].imag
re_step = roots[-1].real - roots[-2].real
else:
im_step = 17.08
re_step = -0.4
# Extend forward
for k in range(30):
re_guess = last_root.real + re_step
im_guess = last_root.imag + im_step
try:
refined = fsolve(F_vec, [re_guess, im_guess], full_output=False)
r = complex(refined[0], refined[1])
val = complex(*F_vec([r.real, r.imag]))
if abs(val) < 1e-3 and r.imag > 0 and r.real < 0:
# Check not duplicate
is_dup = any(abs(r - ex) < 1.0 for ex in roots)
if not is_dup:
roots.append(r)
last_root = r
# Update step estimates from last two roots
if len(roots) >= 2:
im_step = roots[-1].imag - roots[-2].imag
re_step = roots[-1].real - roots[-2].real
except:
pass
# Also search backward from first root
if len(roots) > 0:
first_root = roots[0]
if len(roots) >= 2:
im_step = roots[1].imag - roots[0].imag
re_step = roots[1].real - roots[0].real
else:
im_step = 17.08
re_step = 0.4 # going backward means Re increases
for k in range(5):
re_guess = first_root.real - re_step # going back
im_guess = first_root.imag - im_step
if im_guess < 5:
break
try:
refined = fsolve(F_vec, [re_guess, im_guess], full_output=False)
r = complex(refined[0], refined[1])
val = complex(*F_vec([r.real, r.imag]))
if abs(val) < 1e-3 and r.imag > 0 and r.real < 0:
is_dup = any(abs(r - ex) < 1.0 for ex in roots)
if not is_dup:
roots.insert(0, r)
first_root = r
except:
pass
roots.sort(key=lambda r: r.imag)
print(f"Found {len(roots)} roots\n")
if len(roots) >= 2:
im_spacings = [roots[i].imag - roots[i-1].imag for i in range(1, len(roots))]
re_shifts = [roots[i].real - roots[i-1].real for i in range(1, len(roots))]
print(f"{'#':>3s} {'Re':>10s} {'Im':>10s} {'Im-gap':>10s} {'Re-shift':>10s}")
for i, r in enumerate(roots):
im_gap = f"{im_spacings[i-1]:10.4f}" if i > 0 else f"{'---':>10s}"
re_shift = f"{re_shifts[i-1]:10.4f}" if i > 0 else f"{'---':>10s}"
print(f"{i:3d} {r.real:10.4f} {r.imag:10.4f} {im_gap} {re_shift}")
mean_im = np.mean(im_spacings)
std_im = np.std(im_spacings)
print(f"\nIm-spacing: mean={mean_im:.6f}, std={std_im:.6f}")
print(f"2*pi*e: {2*np.pi*np.e:.6f}")
print(f"Ratio: {mean_im/(2*np.pi*np.e):.6f}")
print(f"Re-shift: mean={np.mean(re_shifts):.6f}")
# Save
results = {
'roots_re': [r.real for r in roots],
'roots_im': [r.imag for r in roots],
'im_spacings': im_spacings,
're_shifts': re_shifts,
'two_pi_e': float(2*np.pi*np.e),
'mean_im_spacing': float(mean_im),
'std_im_spacing': float(std_im),
}
with open('/app/exp1_results.json', 'w') as f:
json.dump(results, f, indent=2)
print("\nSaved to /app/exp1_results.json")