Piola-Conditioned Fixed-Reference Neural Operator / registered_bench.py
Mechanism confirmed, baseline not beaten
1import json, random, sys
2import numpy as np
3import torch
4sys.path.insert(0, '/home/maxwelhelp/all/math2nn')
5from bench import make_model, train_model, sweep_baseline, evaluate, make_report
6from bench.data import custom_tracks
7TRACK='spherical_incompressible_field'
8RAW = custom_tracks()[TRACK]
9
10def get_raw(seed,ntr,nte):
11 return RAW.get_dataset(seed=seed,n_train=ntr,n_test=nte)
12
13
14SEEDS=[11,29,47,71,89,107,131,149]
15GRID=[{'lr':1e-3},{'lr':3e-3},{'lr':1e-2}]
16EPOCHS=16
17BATCH=64
18
19def seed_all(s):
20 np.random.seed(s); random.seed(s); torch.manual_seed(s)
21 if torch.cuda.is_available(): torch.cuda.manual_seed_all(s)
22
23def frame(x):
24 # Deterministic local tangent frame: e1 is the normalized projection of
25 # a fixed axis, e2 completes the oriented tangent frame.
26 q=np.array([1.,0.,0.],dtype=np.float32)
27 dot=x[:,0:1]
28 e1=q[None,:]-dot*x
29 e1=e1/np.maximum(np.linalg.norm(e1,axis=1,keepdims=True),1e-7)
30 e2=np.cross(x,e1)
31 return e1.astype(np.float32),e2.astype(np.float32)
32
33def transformed(seed, idea, ntr=400, nte=200):
34 d=get_raw(seed,ntr,nte)
35 xtr=np.asarray(d['xtr']); xte=np.asarray(d['xte'])
36 if idea:
37 e1,e2=frame(xtr); yt=np.asarray(d['ytr'])
38 ytr=np.concatenate([np.sum(yt*e1,1,keepdims=True),np.sum(yt*e2,1,keepdims=True),np.zeros((len(yt),1),np.float32)],1)
39 e1,e2=frame(xte); yt=np.asarray(d['yte'])
40 yte=np.concatenate([np.sum(yt*e1,1,keepdims=True),np.sum(yt*e2,1,keepdims=True),np.zeros((len(yt),1),np.float32)],1)
41 else:
42 ytr=np.asarray(d['ytr']); yte=np.asarray(d['yte'])
43 return {'xtr':torch.from_numpy(xtr).float(),'ytr':torch.from_numpy(ytr).float(),
44 'xte':torch.from_numpy(xte).float(),'yte':torch.from_numpy(yte).float(),
45 'task':'regression','metric':'mse','input_shape':(3,), 'out_dim':3}
46
47def run_one(seed,idea,lr,collect=False):
48 seed_all(seed); ds=transformed(seed,idea)
49 model=make_model('mlp_tiny',ds['input_shape'],ds['out_dim'])
50 model,metric,_=train_model(model,ds,epochs=EPOCHS,lr=lr,batch=BATCH)
51 if not collect:return float(metric)
52 dev=next(model.parameters()).device; model.eval()
53 with torch.no_grad(): pred=model(ds['xte'].to(dev)).cpu().numpy()
54 pts=np.asarray(get_raw(seed,400,200)['xte'])
55 e1,e2=frame(pts)
56 if idea: pred_phys=pred[:,0:1]*e1+pred[:,1:2]*e2
57 else: pred_phys=pred
58 obs=np.asarray(get_raw(seed,400,200)['yte'])
59 return float(metric),{'predicted':'tangent-frame output should suppress normal component while preserving physical tangent field',
60 'observed_prediction_normal_abs':float(np.mean(np.abs(np.sum(pred_phys*pts,1)))),
61 'observed_target_normal_abs':float(np.mean(np.abs(np.sum(obs*pts,1)))),
62 'observed_physical_rmse':float(np.sqrt(np.mean((pred_phys-obs)**2))),
63 'confirmed':bool(np.mean(np.abs(np.sum(pred_phys*pts,1))) < np.mean(np.abs(np.sum(pred*pts,1))) if idea else False)}
64
65def main():
66 # The registered track is fixed; this check verifies its fields are tangent.
67 d=get_raw(0,400,100); pts=np.asarray(d['xte']); yy=np.asarray(d['yte'])
68 math_check={'target_tangency_max_abs':float(np.max(np.abs(np.sum(pts*yy,1))))}
69 base=sweep_baseline(lambda c:lambda s:run_one(s,False,c['lr']),GRID,seeds=SEEDS)
70 isweep=[]
71 for c in GRID:
72 r=evaluate(lambda s:run_one(s,True,c['lr']),seeds=SEEDS)
73 isweep.append({'cfg':c,'mean':r['mean']})
74 best=min(isweep,key=lambda z:z['mean'])['cfg']
75 idea=evaluate(lambda s:run_one(s,True,best['lr']),seeds=SEEDS)
76 sigb=run_one(SEEDS[0],False,base['best_cfg']['lr'],True)[1]
77 sigi=run_one(SEEDS[0],True,best['lr'],True)[1]
78 sig={'predicted_effect':'tangent-frame pullback should reduce normal leakage and preserve tangent coefficients',
79 'baseline':sigb,'idea':sigi,'confirmed':sigi['observed_prediction_normal_abs'] < sigb['observed_prediction_normal_abs']}
80 base['parity_grid']=GRID; base['idea_grid']=isweep
81 rep=make_report(TRACK,'mlp_tiny',base,idea,{'mechanism_signature':sig,
82 'protocol_notes':{'seeds':SEEDS,'epochs':EPOCHS,'batch':BATCH,'same_architecture':True,
83 'same_lr_union':True},
84 'registered_track':True})
85 out={'bench_report':rep,'math_check':math_check}
86 open('registered_bench_report.json','w').write(json.dumps(out,indent=2))
87 print(json.dumps(out,indent=2))
88if __name__=='__main__':main()