Adaptive Ballistic-to-Diffusive Propagation Schedule / adaptive_diffusion.py
Mechanism confirmed, baseline not beaten
1import json, math
2from pathlib import Path
3import numpy as np
4
5# Reproducible finite-lattice test of the coherent-to-diffusive claim.
6SEED = 1273
7J = 1.0
8N = 81
9center = N // 2
10
11def rhs(rho, gamma):
12 # H=-J(sum |x><x+1| + h.c.), and pure dephasing of off-diagonal entries.
13 H = np.zeros((N, N), dtype=np.complex128)
14 q = np.arange(N - 1)
15 H[q, q + 1] = H[q + 1, q] = -J
16 return -1j * (H @ rho - rho @ H) - gamma * (rho - np.diag(np.diag(rho)))
17
18def run(gamma, T=10.0, dt=0.01):
19 rho = np.zeros((N, N), dtype=np.complex128)
20 rho[center, center] = 1.0
21 times, msd, corr, hf = [], [], [], []
22 steps = int(round(T / dt))
23 for s in range(steps + 1):
24 if s % 5 == 0:
25 p = np.real(np.diag(rho)); p = np.maximum(p, 0)
26 x = np.arange(N) - center
27 msd.append(float(np.sum(x*x*p) / max(np.sum(p), 1e-12)))
28 diag_norm = np.linalg.norm(np.real(np.diag(rho)))
29 corr.append(float(np.linalg.norm(rho - np.diag(np.diag(rho))) / (diag_norm + 1e-12)))
30 # high spatial frequencies of the population (proxy for oscillations)
31 fft = np.abs(np.fft.rfft(p - p.mean())) ** 2
32 hf.append(float(fft[len(fft)//2:].sum() / (fft.sum() + 1e-12)))
33 times.append(s * dt)
34 if s == steps: break
35 # RK4 keeps the integration explicit and makes the mechanism auditable.
36 k1 = rhs(rho, gamma)
37 k2 = rhs(rho + .5*dt*k1, gamma)
38 k3 = rhs(rho + .5*dt*k2, gamma)
39 k4 = rhs(rho + dt*k3, gamma)
40 rho = rho + dt*(k1 + 2*k2 + 2*k3 + k4)/6
41 rho = (rho + rho.conj().T) / 2
42 rho /= np.trace(rho).real
43 return np.array(times), np.array(msd), np.array(corr), np.array(hf)
44
45def fit_power(t, y, lo=3.0):
46 z = (t >= lo) & (y > 1e-10)
47 return float(np.polyfit(np.log(t[z]), np.log(y[z]), 1)[0])
48
49def fit_slope(t, y, lo=5.0):
50 z = t >= lo
51 return float(np.polyfit(t[z], y[z], 1)[0])
52
53def feedback(T=10.0, dt=.01, gamma0=.5, target=.10, alpha=.8, gmin=.02, gmax=32.):
54 rho = np.zeros((N,N), complex); rho[center,center] = 1
55 x=np.arange(N)-center; t=[]; m=[]; gs=[]; rs=[]
56 gamma=gamma0; steps=int(T/dt)
57 for s in range(steps+1):
58 if s % 5 == 0:
59 p=np.maximum(np.real(np.diag(rho)),0)
60 r=np.linalg.norm(rho-np.diag(np.diag(rho)))/(np.linalg.norm(np.real(np.diag(rho)))+1e-12)
61 t.append(s*dt); m.append(np.sum(x*x*p)/max(p.sum(),1e-12)); gs.append(gamma); rs.append(r)
62 if s==steps: break
63 k1=rhs(rho,gamma); k2=rhs(rho+.5*dt*k1,gamma); k3=rhs(rho+.5*dt*k2,gamma); k4=rhs(rho+dt*k3,gamma)
64 rho=(rho+dt*(k1+2*k2+2*k3+k4)/6); rho=(rho+rho.conj().T)/2; rho/=np.trace(rho).real
65 # controller is stopped-gradient by construction: r is a scalar observation.
66 if s % 5 == 4:
67 gamma=float(np.clip(gamma*np.exp(alpha*(r-target)),gmin,gmax))
68 return np.array(t),np.array(m),np.array(gs),np.array(rs)
69
70def main():
71 np.random.seed(SEED)
72 gammas=[0., .5, 1., 2., 4., 8., 16.]
73 rows=[]
74 for g in gammas:
75 t,m,r,h=run(g)
76 slope=fit_slope(t,m); beta=fit_power(t,m)
77 # D prediction says MSD slope = 2D = 4J^2/gamma.
78 pred=None if g==0 else 4*J*J/g
79 rows.append(dict(gamma=g, msd_final=float(m[-1]), late_msd_slope=slope,
80 predicted_slope=pred, slope_ratio=None if pred is None else slope/pred,
81 power_exponent=beta, corr_final=float(r[-1]), hf_final=float(h[-1])))
82 # Selected-frequency crossover: D k^2 = J |sin k|, gamma=2J k^2/|sin k|.
83 kstar=np.pi/2; predicted_cross=2*J*kstar*kstar/abs(np.sin(kstar))
84 # empirical crossover: nearest beta=1.5, with gamma~4J prediction separately.
85 empirical=min(rows[1:], key=lambda z: abs(z['power_exponent']-1.5))['gamma']
86 tc,mm,gg,rr=feedback()
87 out={
88 'parameters': {'J':J,'N':N,'T':10.,'dt':.01,'seed':SEED},
89 'predictions': {
90 'diffusion_slope': 'MSD/t = 4 J^2/gamma',
91 'crossover_bandwidth': 'gamma approximately 4J',
92 'selected_k_crossover': predicted_cross,
93 'ballistic_exponent': 2.0, 'diffusive_exponent': 1.0
94 },
95 'sweep': rows,
96 'observed': {'beta_1p5_crossover_gamma': empirical,
97 'feedback_initial_gamma':.5,'feedback_final_gamma':float(gg[-1]),
98 'feedback_final_msd':float(mm[-1]),'feedback_max_gamma':float(gg.max())}
99 }
100 Path('results.json').write_text(json.dumps(out, indent=2))
101 print(json.dumps(out, indent=2))
102
103if __name__=='__main__': main()