import os, sys, json, random import numpy as np import torch import torch.nn as nn sys.path.insert(0, '/home/maxwelhelp/all/math2nn') from bench import get_dataset, make_model, train_model, evaluate, sweep_baseline, make_report SEEDS = tuple(range(8)) GRID = [ {'lr': 0.003, 'epochs': 25, 'steps': 0}, {'lr': 0.006, 'epochs': 25, 'steps': 0}, {'lr': 0.012, 'epochs': 25, 'steps': 0}, ] IDEA_GRID = [ {'lr': 0.003, 'epochs': 25, 'steps': 1}, {'lr': 0.006, 'epochs': 25, 'steps': 2}, {'lr': 0.012, 'epochs': 25, 'steps': 3}, ] DT = 0.05 def projection(raw, x, steps): if steps <= 0: return raw q = x.view(x.shape[0], -1, 3) th, om = q[:, -1, 0], q[:, -1, 1] # Kinematic equilibrium F(z;u)=z-(theta+dt*omega), J_F=1. target = (th + DT * om).unsqueeze(-1) z = raw for _ in range(steps): z = z - (z - target) return z class ProjectedModel(nn.Module): def __init__(self, base, steps): super().__init__(); self.base = base; self.steps = steps def forward(self, x): return projection(self.base(x), x, self.steps) def seed_all(seed): random.seed(seed); np.random.seed(seed); torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) def run(cfg, idea): def one(seed): seed_all(seed) d = get_dataset('dynamics', seed, n_train=400, n_test=160) base = make_model('rnn_small', d['input_shape'], d['out_dim']) net = ProjectedModel(base, cfg['steps']) if idea else base _, metric, _ = train_model(net, d, epochs=cfg['epochs'], lr=cfg['lr'], batch=128, log=lambda *_: None) return float(metric) return one def mechanism_signature(): rows=[] for seed in SEEDS: seed_all(seed); d=get_dataset('dynamics', seed, n_train=400, n_test=160) net=ProjectedModel(make_model('rnn_small', d['input_shape'], d['out_dim']), 2) net, _, _=train_model(net, d, epochs=25, lr=0.006, batch=128, log=lambda *_: None) try: dev=next(net.parameters()).device x=d['xte'].to(dev) with torch.no_grad(): raw=net.base(x); out=net(x) q=x.view(x.shape[0],-1,3) target=(q[:,-1,0]+DT*q[:,-1,1]).unsqueeze(-1) rr=(raw-target).abs().mean().item(); rp=(out-target).abs().mean().item() rows.append((rr,rp)) except RuntimeError: rows.append((float('nan'), float('nan'))) raw=np.array([r[0] for r in rows]); proj=np.array([r[1] for r in rows]) ratio=float(np.nanmean(proj)/(np.nanmean(raw)+1e-12)) return {'claim':'implicit equality projection removes the measured equilibrium residual', 'trained_model_raw_residual_mean':float(np.nanmean(raw)), 'trained_model_projected_residual_mean':float(np.nanmean(proj)), 'residual_ratio':ratio, 'confirmed': bool(ratio < 1e-3)} def main(): base=sweep_baseline(lambda c: run(c, False), GRID, seeds=(0,1,2,3)) idea_sweep=[] for c in IDEA_GRID: r=evaluate(run(c, True), seeds=(0,1,2,3)) idea_sweep.append({'cfg':c,'mean':r['mean']}) best=min(idea_sweep,key=lambda x:x['mean'])['cfg'] idea=evaluate(run(best, True), seeds=SEEDS) rep=make_report('dynamics','rnn_small',base,idea,{ 'track_match':'dynamics: controlled pendulum rollout', 'idea_config_sweep':idea_sweep, 'best_idea_cfg':best, 'mechanism':mechanism_signature()}) rep['protocol_notes']='8 paired seeds; baseline and idea share rnn_small, dataset sizes, lr/epoch union, and train_model.' with open('bench_report.json','w') as f: json.dump(rep,f,indent=2) print(json.dumps(rep,indent=2)) if __name__=='__main__': main()