import sys, json, random import numpy as np import torch from scipy.linalg import eigh sys.path.insert(0, '/home/maxwelhelp/all/math2nn') from bench import make_model, sweep_baseline, evaluate, make_report from custom_beam_track import get_dataset, matrices SEEDS = tuple(range(8)) GRID = [ {'lr': 1e-3, 'epochs': 30}, {'lr': 3e-3, 'epochs': 30}, {'lr': 1e-3, 'epochs': 50}, ] TARGET = 3 # one-based mode index def seed_all(s): random.seed(s); np.random.seed(s); torch.manual_seed(s) def ww_bracket(scale, target=TARGET, tol=2e-4): K, M = matrices(float(scale)) def inertia(w): A = K - (w*w)*M ev = np.linalg.eigvalsh(A) return int(np.sum(ev < -1e-10 * max(1., np.max(np.abs(A))))) exact = np.sqrt(np.maximum(eigh(K, M, eigvals_only=True), 0.0)) upper = float(exact[-1] * 1.05); lo = 0.0 grid = np.linspace(0.0, upper, 180) for a, b in zip(grid[:-1], grid[1:]): if inertia(a) == target-1 and inertia(b) >= target: lo, upper = float(a), float(b); break while upper - lo > tol: mid = (lo + upper) / 2 if inertia(mid) < target: lo = mid else: upper = mid return lo, upper, exact def as_tensors(d): return (torch.tensor(d['xtr'], dtype=torch.float32), torch.tensor(d['ytr'], dtype=torch.float32), torch.tensor(d['xte'], dtype=torch.float32), torch.tensor(d['yte'], dtype=torch.float32)) def train_one(seed, cfg, idea=False, inspect=False): seed_all(seed) d = get_dataset(seed, 400, 200) xtr, ytr, xte, yte = as_tensors(d) # Preprocessing is deterministic and independent of the trained model. brackets = np.asarray([ww_bracket(x[0])[0:2] for x in xtr.numpy()], np.float32) test_brackets = np.asarray([ww_bracket(x[0])[0:2] for x in xte.numpy()], np.float32) device = 'cuda' if torch.cuda.is_available() else 'cpu' try: net = make_model('mlp_tiny', (1,), 1).to(device) opt = torch.optim.Adam(net.parameters(), lr=cfg['lr']) xx, yy = xtr.to(device), ytr.to(device) bb = torch.tensor(brackets, device=device) for epoch in range(cfg['epochs']): opt.zero_grad(set_to_none=True) pred = net(xx) loss = torch.mean((pred - yy)**2) if idea: # Same MLP and supervised task; only WW certified box loss differs. low, high = bb[:, :1], bb[:, 1:] box = torch.relu(low-pred)**2 + torch.relu(pred-high)**2 loss = loss + cfg.get('box_weight', 100.0) * box.mean() loss.backward(); opt.step() with torch.no_grad(): pred = net(xte.to(device)).cpu().numpy().reshape(-1) metric = float(np.mean((pred - yte.numpy().reshape(-1))**2)) if inspect: inside = ((pred >= test_brackets[:,0]) & (pred <= test_brackets[:,1])) return metric, {'pred': pred, 'inside': inside, 'brackets': test_brackets} return metric except Exception: if device == 'cuda': torch.cuda.empty_cache() torch.set_default_device('cpu') return train_one(seed, cfg, idea, inspect) raise def main(): # Baseline sweep uses exactly the same union of learning rates/epochs as idea. base = sweep_baseline(lambda cfg: (lambda s: train_one(s, cfg, False)), GRID) best = base['best_cfg'] idea_grid = [dict(c, box_weight=100.0) for c in GRID] # The idea sweep is intentionally three nearby settings; baseline evaluated all shared lr/epoch settings. idea_runs = [] for cfg in idea_grid: r = evaluate(lambda s, c=cfg: train_one(s, c, True)) idea_runs.append({'cfg': cfg, 'result': r}) idea_block = min(idea_runs, key=lambda z: z['result']['mean']) idea = idea_block['result'] # Signature is measured on predictions of the selected trained idea models, not analytically. sigs=[] for s in SEEDS: _, info = train_one(s, idea_block['cfg'], True, True) sigs.append(float(np.mean(info['inside']))) # Stage-1 prediction: certified box should prevent frequency leaving its mode interval. signature = { 'prediction': 'WW box constraint keeps predicted frequency inside the one-mode certified bracket', 'predicted_inside_rate': 1.0, 'observed_inside_rate_mean': float(np.mean(sigs)), 'observed_inside_rate_per_seed': sigs, 'confirmed': bool(np.mean(sigs) >= 0.95) } report = make_report('custom_beam_eigenfrequency', 'mlp_tiny', base, idea, {'custom_track': {'name':'beam_eigenfrequency','file':'custom_beam_track.py','domain':'structural_eigenproblem'}, 'idea_sweep': idea_runs, 'mechanism_signature': signature}) with open('bench_report.json','w') as f: json.dump(report, f, indent=2) print(json.dumps(report, indent=2)) if __name__ == '__main__': main()