File size: 4,438 Bytes
f7c4905 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | """
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")
|