Entropy-Feedback Zeroth-Order Cooling / verify_entropy_cooling.py
Mechanism confirmed, baseline not beaten
1import json, math
2import numpy as np
3
4
5def sigmoid(x):
6 return 1.0 / (1.0 + np.exp(-np.clip(x, -60, 60)))
7
8
9def weights(losses, tau):
10 z = -(losses - np.min(losses)) / max(tau, 1e-15)
11 z -= np.max(z)
12 w = np.exp(np.clip(z, -80, 0))
13 return w / w.sum()
14
15
16def entropy(w):
17 return float(-(w * np.log(np.maximum(w, 1e-300))).sum())
18
19
20def controller_rate(h, alpha=.05, eps=.02, hc=.5, delta=.05):
21 b = sigmoid((h-hc)/delta)
22 return alpha * (eps + (1-eps)*b)
23
24
25def main():
26 rng = np.random.default_rng(1234)
27 N = 128; hc=.5; delta=.05; alpha=.05; eps=.02
28 # Prediction 1: ESS identity and transition ESS, across random populations.
29 identity_errors=[]
30 for _ in range(100):
31 losses=rng.normal(size=N)*rng.uniform(.1, 5)
32 w=weights(losses, rng.uniform(.01, 3))
33 H=entropy(w); h=H/math.log(N); ess=math.exp(H)
34 identity_errors.append(abs(ess/N - math.exp(-(1-h)*math.log(N))))
35 transition_pred=N**hc
36 # Make a population with exactly uniform weights over K candidates; h=log(K)/log(N).
37 K=round(transition_pred)
38 w=np.zeros(N); w[:K]=1/K
39 h_transition=entropy(w)/math.log(N)
40 ess_transition=math.exp(entropy(w))
41
42 # Prediction 2: tau log slope is controller_rate in fixed-entropy regimes.
43 rate_rows=[]
44 for h in [.1, .9, .5]:
45 tau=1.0; logs=[]
46 for _ in range(200):
47 logs.append(math.log(tau)); tau *= math.exp(-controller_rate(h,alpha,eps,hc,delta))
48 observed=-(logs[-1]-logs[0])/(len(logs)-1)
49 rate_rows.append({'h':h, 'predicted_abs_slope':controller_rate(h,alpha,eps,hc,delta), 'observed_abs_slope':observed})
50
51 # Prediction 3: entropy threshold crossing in a temperature sweep. Candidate losses are
52 # 0 for K good candidates and 1 for the rest; solve/search tau where h ~= hc.
53 sweep=[]
54 for K0 in [1, 2, 4, 8, 16, 32, 64]:
55 taus=np.logspace(-3,2,500)
56 hs=[]
57 for tau in taus:
58 ll=np.ones(N); ll[:K0]=0
59 hs.append(entropy(weights(ll,tau))/math.log(N))
60 idx=int(np.argmin(np.abs(np.asarray(hs)-hc)))
61 sweep.append({'good_candidates':K0, 'tau_at_hc':float(taus[idx]), 'h':float(hs[idx])})
62
63 # Mini optimizer: diagonal ill-conditioned quadratic, same perturbations for all methods per seed.
64 d=24; T=180; pop=64; sigma=.18; gamma=1.0
65 curv=np.geomspace(1, 20, d)
66 def run(seed, mode):
67 r=np.random.default_rng(seed); theta=r.normal(0, 2, d); tau=1.0
68 vals=[]; hs=[]
69 for t in range(T):
70 e=r.normal(size=(pop,d)); cand=theta[None,:]+sigma*e
71 loss=.5*np.sum(curv[None,:]*cand*cand,axis=1)
72 if mode=='constant': tau_use=1.0
73 else: tau_use=tau
74 w=weights(loss,tau_use); H=entropy(w); h=H/math.log(pop)
75 theta=(1-gamma)*theta+gamma*(w[:,None]*cand).sum(axis=0)
76 if mode=='feedback': tau*=math.exp(-controller_rate(h,alpha,eps,hc,delta))
77 elif mode=='fixed': tau*=math.exp(-alpha)
78 vals.append(float(.5*np.sum(curv*theta*theta))); hs.append(h)
79 return {'final':vals[-1], 'best':min(vals), 'mean_h_last20':float(np.mean(hs[-20:])), 'tau_final':tau, 'loss_curve':vals}
80 results={}
81 for mode in ['feedback','fixed','constant']:
82 runs=[run(s,mode) for s in range(5)]
83 results[mode]={'final_mean':float(np.mean([x['final'] for x in runs])), 'final_std':float(np.std([x['final'] for x in runs])), 'best_mean':float(np.mean([x['best'] for x in runs])), 'h_last20_mean':float(np.mean([x['mean_h_last20'] for x in runs])), 'tau_final_mean':float(np.mean([x['tau_final'] for x in runs]))}
84
85 out={'config':{'N':N,'hc':hc,'delta':delta,'alpha':alpha,'epsilon':eps},
86 'prediction_1_ess_identity_max_abs_error':max(identity_errors),
87 'prediction_1_transition':{'predicted_ESS':transition_pred,'constructed_K':K,'observed_h':h_transition,'observed_ESS':ess_transition},
88 'prediction_2_rates':rate_rows,
89 'prediction_3_temperature_sweep':sweep,
90 'mini_experiment':results}
91 with open('results.json','w') as f: json.dump(out,f,indent=2)
92 print(json.dumps(out,indent=2))
93
94if __name__=='__main__': main()