import 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, train_model, sweep_baseline, make_report from bench.protocol import evaluate # Dynamics is the structurally matched built-in: it is an actuated pendulum # rollout task and the proposal claims improved recurrent stability/long horizon behavior. SEEDS = tuple(range(8)) SWEEP_SEEDS = (0, 1, 2, 3) 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) class StandardRNN(nn.Module): def __init__(self, input_dim, hidden=64, out_dim=1): super().__init__(); self.inp=nn.Linear(input_dim, hidden) self.rec=nn.Linear(hidden, hidden); self.head=nn.Linear(hidden, out_dim) def forward(self, x): # x is (batch, features) for the bench dynamics task; make it one-step. h=torch.tanh(self.inp(x)); h=torch.tanh(self.rec(h)+h) return self.head(h) class CrossRatioRNN(nn.Module): """Real-channel implementation of the cross-ratio completion rule. Four complex points are represented by 8 real hidden channels. Three points are retained from the ordinary recurrent proposal; the fourth is replaced by d=((b-c)a-(a-b)c)/((b-c)-(a-b)). A bounded fallback is used only for near-singular denominators, avoiding NaNs during optimization. """ def __init__(self, input_dim, hidden=64, out_dim=1, eps=1e-4): super().__init__(); assert hidden % 8 == 0 self.inp=nn.Linear(input_dim, hidden); self.rec=nn.Linear(hidden, hidden) self.head=nn.Linear(hidden, out_dim); self.eps=eps def forward(self, x, return_signature=False): q=torch.tanh(self.inp(x)+self.rec(torch.zeros(x.shape[0], self.rec.in_features, device=x.device))) # q has 8-channel blocks: each block is four complex lattice points. v=q.reshape(q.shape[0], -1, 8) a=v[...,0]+1j*v[...,1]; b=v[...,2]+1j*v[...,3] c=v[...,4]+1j*v[...,5] den=(b-c)-(a-b); num=(b-c)*a-(a-b)*c safe=torch.where(den.abs() >= self.eps, den, torch.ones_like(den)) d=num/safe d=torch.where(den.abs() >= self.eps, d, c) complete=torch.stack((d.real,d.imag), dim=-1) # replace the fourth point while retaining the learned three corners v2=torch.cat((v[...,:6], complete), dim=-1) h=v2.reshape(q.shape[0], -1) out=self.head(h) if return_signature: cr=(a-b)*(c-d)/((b-c)*(d-a)+1e-12) residual=(cr+1).abs().mean() return out, float(residual.detach().cpu()), float((den.abs()