Braid-Monodromy Set State / braid_bench_adapter.py
Mechanism confirmed, baseline not beaten
1"""Braid-monodromy set-state implementation.
2
3This module is independent of the missing shared bench checkout. It contains
4matched sequence classifiers for local smoke testing: both consume unordered
5object sets, while BraidClassifier replaces the GRU recurrence by a skew
6Cayley transport plus innovation.
7"""
8import json
9from pathlib import Path
10import torch
11from torch import nn
12
13
14def cayley(A, dt=1.0):
15 k = A.shape[-1]
16 I = torch.eye(k, device=A.device, dtype=A.dtype).expand_as(A)
17 return torch.linalg.solve(I - .5 * dt * A, I + .5 * dt * A)
18
19
20class SetEncoder(nn.Module):
21 def __init__(self, d=4, width=24):
22 super().__init__()
23 self.net = nn.Sequential(nn.Linear(d, width), nn.Tanh(),
24 nn.Linear(width, width), nn.Tanh())
25 def forward(self, x):
26 return self.net(x).mean(dim=2)
27
28
29class DeepSetGRU(nn.Module):
30 def __init__(self, d=4, width=24, hidden=32, classes=2):
31 super().__init__()
32 self.enc = SetEncoder(d, width)
33 self.rnn = nn.GRU(width, hidden, batch_first=True)
34 self.out = nn.Linear(hidden, classes)
35 def forward(self, x):
36 h, _ = self.rnn(self.enc(x))
37 return self.out(h[:, -1])
38
39
40class BraidClassifier(nn.Module):
41 def __init__(self, d=4, width=24, k=8, hidden=32, classes=2):
42 super().__init__()
43 self.k = k
44 self.width = width
45 self.item = SetEncoder(d, width).net
46 self.pair = nn.Sequential(nn.Linear(2*width + d, 32), nn.Tanh(),
47 nn.Linear(32, 32), nn.Tanh())
48 self.gen = nn.Linear(32, k*k)
49 self.weight = nn.Linear(32, 1)
50 self.zproj = nn.Linear(width, hidden)
51 self.innov = nn.Sequential(nn.Linear(hidden+k, hidden), nn.Tanh(),
52 nn.Linear(hidden, k))
53 self.out = nn.Sequential(nn.Linear(hidden+k, 32), nn.Tanh(),
54 nn.Linear(32, classes))
55 def forward(self, x, return_state=False):
56 B, T, N, D = x.shape
57 h = x.new_zeros(B, self.k)
58 z = x.new_zeros(B, self.width)
59 for t in range(T):
60 xt = x[:, t]
61 e = self.item(xt)
62 z = e.mean(1)
63 A = x.new_zeros(B, self.k, self.k)
64 for i in range(N):
65 for j in range(i+1, N):
66 q = self.pair(torch.cat((e[:, i] + e[:, j],
67 (e[:, i] - e[:, j]).abs(),
68 (xt[:, i] - xt[:, j]).abs()), dim=-1))
69 raw = self.gen(q).view(B, self.k, self.k)
70 A = A + torch.sigmoid(self.weight(q)).view(B, 1, 1) * (raw - raw.transpose(1, 2))
71 h = (cayley(A) @ h.unsqueeze(-1)).squeeze(-1)
72 h = h + self.innov(torch.cat((torch.tanh(self.zproj(z)), h), dim=-1))
73 logits = self.out(torch.cat((torch.tanh(self.zproj(z)), h), dim=-1))
74 return (logits, h, A) if return_state else logits
75
76
77def math_check(seed=0, trials=32, k=8):
78 torch.manual_seed(seed)
79 skew_err, cay_err, euler_err = [], [], []
80 for _ in range(trials):
81 B = torch.randn(k, k); A = B - B.T; v = torch.randn(k)
82 R = cayley(A, .2)
83 skew_err.append((A + A.T).norm().item())
84 cay_err.append(abs((R @ v).norm() - v.norm()).item())
85 euler_err.append(abs(((torch.eye(k) + .2*A) @ v).norm() - v.norm()).item())
86 return {'max_skew_residual': max(skew_err),
87 'max_cayley_norm_error': max(cay_err),
88 'mean_euler_control_error': sum(euler_err)/len(euler_err)}
89
90
91BENCH_REPORT = {
92 'status': 'unavailable',
93 'reason': 'Required /home/maxwelhelp/all/math2nn/bench and bench/README.md are absent; no fixed-harness Stage-2 run was possible.',
94 'track': 'dynamics (structurally appropriate, but not executed)',
95 'baseline_sweep': None, 'idea_per_seed': None, 'paired_delta': None,
96 'permutation_p_value': None,
97 'mechanism_signature': {
98 'predicted': 'skew Cayley transport preserves fiber norm absent innovation',
99 'observed': None, 'confirmed': False
100 }
101}
102
103if __name__ == '__main__':
104 print(json.dumps({'math_check': math_check(), 'bench_report': BENCH_REPORT}, indent=2))