import json, random from pathlib import Path import numpy as np import torch import sys sys.path.insert(0, '/home/maxwelhelp/all/math2nn') from bench import get_dataset, make_model, train_model, sweep_baseline, evaluate, make_report TRACK='dynamics'; MODEL='rnn_small' # Equal-budget settings; the union is used on both sides. LR_GRID=[1e-3, 3e-3, 6e-3] EPOCHS=12 N_TRAIN=400 N_POOL=1600 SEEDS=tuple(range(8)) def seed_all(s): random.seed(s); np.random.seed(s); torch.manual_seed(s) if torch.cuda.is_available(): try: torch.cuda.manual_seed_all(s) except Exception: pass def state_view(x): # Last observed pendulum state in each 8-step input window. return np.asarray(x, dtype=np.float64).reshape(len(x), 8, 3)[:, -1, :] def residual(x): # Conservative, task-independent safety margin: theta and angular velocity. z=state_view(x) return np.minimum(1.25-np.abs(z[:,0]), 2.0-0.35*np.abs(z[:,1])) def cover_radius(query, samples): # Small pool: exact vectorized nearest-neighbor radius. q=np.asarray(query); s=np.asarray(samples) best=np.full(len(q), np.inf) for j in range(0,len(s),128): d=((q[:,None,:]-s[None,j:j+128,:])**2).sum(2) best=np.minimum(best, np.sqrt(d.min(1))) return float(best.max()), best def adaptive_indices(pool_x, n, seed, gamma=0.35): z=state_view(pool_x) rng=np.random.default_rng(seed) # Four seed states, then q = normalized distance + gamma*low-margin. chosen=list(rng.choice(len(pool_x), size=8, replace=False)) chosen_set=set(chosen) scale=np.std(z,axis=0)+1e-6 zn=z/scale r=residual(pool_x) eps=0.15 while len(chosen)= r(samples).min()-L*d-1e-10 return {'checked':True,'L':L,'delta':d,'sample_min':float(r(samples).min()),'cloud_min':float(r(cloud).min()),'bound':float(r(samples).min()-L*d)} def main(): check=math_check() grid=[{'lr':x} for x in LR_GRID] base=sweep_baseline(lambda cfg: lambda s: run_one(s,'baseline',cfg),grid,seeds=(0,1,2,3)) # Explicitly evaluate idea at all three settings; best is selected on the same tuning seeds. idea_cfg_results=[] for cfg in grid: rr=evaluate(lambda s,cfg=cfg: run_one(s,'idea',cfg),seeds=(0,1,2,3)) idea_cfg_results.append((rr['mean'],cfg)) idea_cfg=min(idea_cfg_results,key=lambda x:x[0])[1] idea=evaluate(lambda s: run_one(s,'idea',idea_cfg),seeds=SEEDS) # Signature uses trained models, not a toy identity: compare pool coverage and # boundary/general-region prediction errors for one paired seed. bm,bnet,bds,bpool,bidx=run_one(0,'baseline',base['best_cfg'],True) im,inet,ids,ipool,iidx=run_one(0,'idea',idea_cfg,True) with torch.no_grad(): bx=bpool['xtr']; by=bpool['ytr']; ix=ipool['xtr']; iy=ipool['ytr'] bdev=next(bnet.parameters()).device; idev=next(inet.parameters()).device bp=bnet(bx.to(bdev)).detach().cpu().numpy().reshape(-1); ip=inet(ix.to(idev)).detach().cpu().numpy().reshape(-1) bz=state_view(bpool['xtr'].numpy()); iz=state_view(ipool['xtr'].numpy()) bdelta=cover_radius(bz,state_view(bpool['xtr'][bidx].numpy()))[0] idelta=cover_radius(iz,state_view(ipool['xtr'][iidx].numpy()))[0] br=residual(bpool['xtr'].numpy()); ir=residual(ipool['xtr'].numpy()) sig={'prediction':'adaptive reachable-state selection should reduce empirical coverage radius at equal simulator budget', 'observed':{'baseline_delta':bdelta,'idea_delta':idelta,'baseline_pool_mse':float(np.mean((bp-by.numpy())**2)),'idea_pool_mse':float(np.mean((ip-iy.numpy())**2)), 'baseline_min_sample_residual':float(br[bidx].min()),'idea_min_sample_residual':float(ir[iidx].min())}, 'relative_delta_reduction_pct':float(100*(bdelta-idelta)/bdelta), 'confirmed':bool(idelta < bdelta)} report=make_report(TRACK,MODEL,base,idea,extra={'math_check':check,'mechanism_signature':sig,'idea_grid_results':idea_cfg_results,'selected_idea_cfg':idea_cfg,'budget':{'epochs':EPOCHS,'train_samples':N_TRAIN,'pool_samples':N_POOL}}) Path('bench_report.json').write_text(json.dumps(report,indent=2)) print(json.dumps(report,indent=2)) if __name__=='__main__': main()