Faithful Latent Fixed-Point Solver / experiment.py
Mechanism confirmed, baseline not beaten
1import json, random
2import numpy as np
3import torch
4
5SEED = 7
6np.random.seed(SEED); random.seed(SEED); torch.manual_seed(SEED)
7torch.set_num_threads(4)
8DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
9try:
10 torch.zeros(1, device=DEVICE)
11except Exception:
12 DEVICE = 'cpu'
13
14# A 10D system with an exactly rank-2 invariant state manifold.
15# x = c + Bq, S(x) = c + B M q. Thus the faithful latent dimension is 2.
16def make_map(gamma):
17 rng = np.random.RandomState(23)
18 B, _ = np.linalg.qr(rng.randn(10, 2))
19 B = B.astype(np.float32)
20 c = np.array([.4,-.2,.3,.1,-.1,.2,.05,-.15,.12,.08], np.float32)
21 M = np.diag([gamma, .72 * gamma]).astype(np.float32)
22 A = B @ M @ B.T
23 b = c - A @ c
24 return A.astype(np.float32), b.astype(np.float32), B, c, M
25
26def apply(A, b, x):
27 return x @ A.T + b
28
29def manifold_states(B, c, n, seed=11):
30 q = np.random.RandomState(seed).randn(n, 2).astype(np.float32) * 1.4
31 return c[None, :] + q @ B.T
32
33def train_latent(A, b, B, c, m, epochs=1300):
34 x = manifold_states(B, c, 1800, 11 + m)
35 y = apply(A, b, x)
36 E = torch.nn.Linear(10, m, device=DEVICE)
37 D = torch.nn.Linear(m, 10, device=DEVICE)
38 T = torch.nn.Linear(m, m, device=DEVICE)
39 opt = torch.optim.Adam(list(E.parameters()) + list(D.parameters()) + list(T.parameters()), lr=.025)
40 xt, yt = torch.tensor(x, device=DEVICE), torch.tensor(y, device=DEVICE)
41 for _ in range(epochs):
42 idx = torch.randint(0, len(x), (128,), device=DEVICE)
43 xv, yv = xt[idx], yt[idx]
44 z, zn = E(xv), T(E(xv))
45 loss = ((E(yv)-zn)**2).mean() + ((D(zn)-yv)**2).mean() + .5*((D(z)-xv)**2).mean()
46 opt.zero_grad(); loss.backward(); opt.step()
47 return E, D, T
48
49def learned_metrics(A, b, B, c, E, D, T, gamma):
50 x = torch.tensor(manifold_states(B, c, 300, 99), device=DEVICE)
51 y = torch.tensor(apply(A, b, x.cpu().numpy()), device=DEVICE)
52 with torch.no_grad():
53 enc = ((E(y)-T(E(x)))**2).mean().sqrt().item()
54 dec = ((D(T(E(x)))-y)**2).mean().sqrt().item()
55 rec = ((D(E(x))-x)**2).mean().sqrt().item()
56 z = E(x); gaps=[]
57 for _ in range(12):
58 gaps.append(torch.linalg.vector_norm(D(T(z))-D(z), dim=1).mean().item())
59 z = T(z)
60 ratio = float(np.median(np.array(gaps[6:]) / np.array(gaps[5:11])))
61 fp = c + np.zeros(10, np.float32) # exact fixed point is c
62 fp_t = torch.tensor(fp[None, :], device=DEVICE)
63 fp_res = torch.linalg.vector_norm(D(T(E(fp_t)))-fp_t, dim=1).item()
64 return {'enc_residual':enc, 'decode_residual':dec, 'reconstruction':rec,
65 'decoded_fixed_point_residual':fp_res, 'decoded_rate':ratio,
66 'predicted_rate':gamma}
67
68def exact_checks():
69 # Prediction 1: scalar contraction boundary is gamma*Lambda=gamma < 1.
70 boundary=[]
71 for g in [.6,.9,.99,1.,1.01,1.2]:
72 d=1.;
73 for _ in range(12): d=g*d
74 boundary.append({'gamma':g, 'predicted_contracts':g < 1,
75 'observed_contracts':d < 1, '12_step_ratio':d})
76 # Prediction 2: an m-dimensional faithful representation needs m >= rank(M)=2.
77 A,b,B,c,M=make_map(.82)
78 x=manifold_states(B,c,500,41)
79 # exact best rank-m linear reconstruction of centered manifold states
80 _,s,_=np.linalg.svd((x-c).T, full_matrices=False)
81 rank=[]
82 for m in [1,2,3]:
83 residual=np.sqrt(np.maximum(0., np.sum(s[m:]**2) / x.shape[0])) if m < len(s) else 0.
84 rank.append({'m':m, 'predicted_zero_residual':m>=2,
85 'observed_reconstruction_rmse':float(residual)})
86 # Prediction 3: ideal decoded trajectory contracts at dominant latent rate gamma.
87 rates=[]
88 for g in [.55,.70,.82,.92]:
89 _,_,_,_,M=make_map(g); q=1.; vals=[]
90 for _ in range(12): vals.append(abs(q)); q=g*q
91 rates.append({'gamma':g, 'predicted_asymptotic_rate':g,
92 'observed_rate':float(np.median(np.array(vals[6:]) / np.array(vals[5:11])))})
93 return boundary,rank,rates
94
95def main():
96 boundary, rank, rates = exact_checks()
97 A,b,B,c,_=make_map(.82)
98 learned=[]
99 for m in [1,2,3]:
100 E,D,T=train_latent(A,b,B,c,m)
101 row=learned_metrics(A,b,B,c,E,D,T,.82); row['m']=m; learned.append(row)
102 # Same manifold initial states and 12 update evaluations.
103 x=manifold_states(B,c,300,123); fixed=c
104 direct=x.copy()
105 for _ in range(12): direct=apply(A,b,direct)
106 E,D,T=train_latent(A,b,B,c,2)
107 with torch.no_grad():
108 z=E(torch.tensor(x,device=DEVICE))
109 for _ in range(12): z=T(z)
110 idea=D(z).cpu().numpy()
111 out={'device':DEVICE, 'exact_predictions':{'contraction_boundary':boundary,
112 'rank_threshold':rank, 'rate_transfer':rates}, 'learned_sweep':learned,
113 'comparison':{'baseline_S_evals':12,'idea_S_evals':0,'idea_T_evals':12,
114 'baseline_fixed_point_rmse':float(np.sqrt(np.mean((direct-fixed)**2))),
115 'idea_fixed_point_rmse':float(np.sqrt(np.mean((idea-fixed)**2))),
116 'baseline_output_residual':float(np.sqrt(np.mean((apply(A,b,direct)-direct)**2))),
117 'idea_output_residual':float(np.sqrt(np.mean((apply(A,b,idea)-idea)**2)))}}
118 with open('results.json','w') as f: json.dump(out,f,indent=2)
119 print(json.dumps(out, indent=2))
120
121if __name__ == '__main__': main()