Consensus-Safe RoPE Residual Attention / consensus_rope_experiment.py
Mechanism confirmed, baseline not beaten
1import json
2import math
3from pathlib import Path
4import numpy as np
5
6SEED = 1362
7rng = np.random.default_rng(SEED)
8
9
10def normalize(x):
11 return x / np.linalg.norm(x, axis=-1, keepdims=True)
12
13
14def rope(x, positions, omegas):
15 # x: [n,d], d even; rotations act independently on each pair.
16 y = x.copy()
17 for l, w in enumerate(omegas):
18 a, b = 2*l, 2*l+1
19 th = w * positions
20 c, s = np.cos(th), np.sin(th)
21 y[:, a] = c*x[:, a] - s*x[:, b]
22 y[:, b] = s*x[:, a] + c*x[:, b]
23 return y
24
25
26def attention(x, positions, omegas, beta):
27 q = rope(x, positions, omegas)
28 scores = q @ q.T
29 z = np.exp(beta * (scores - scores.max(axis=1, keepdims=True)))
30 a = z / z.sum(axis=1, keepdims=True)
31 return a, scores
32
33
34def spherical_step(x, a, eta):
35 m = a @ x
36 v = m - (m*x).sum(axis=1, keepdims=True)*x
37 return normalize(x + eta*v)
38
39
40def angular_diameter(x):
41 c = np.clip(x @ x.T, -1.0, 1.0)
42 return float(np.arccos(c).max())
43
44
45def make_consensus(n, d, positions, omegas, beta):
46 u = normalize(rng.normal(size=(1,d)))[0]
47 x = np.repeat(u[None,:], n, axis=0)
48 a, scores = attention(x, positions, omegas, beta)
49 return x, a, scores, u
50
51
52def stability_trial(a, z, u, eta, steps=8, eps=1e-6):
53 # At consensus, exp(beta*scores) is symmetric and A is reversible.
54 # If S=D^(1/2) A D^(-1/2), S w=lambda w, then
55 # A(D^(-1/2)w)=lambda(D^(-1/2)w). Use the worst transverse mode.
56 dz = np.sqrt(z)
57 s = dz[:, None] * a / dz[None, :]
58 vals, vecs = np.linalg.eigh((s + s.T) / 2)
59 lam_min = float(vals[0])
60 mode = vecs[:, 0] / dz
61 mode /= np.linalg.norm(mode)
62 tangent = np.zeros_like(u)
63 tangent[0] = 1.0
64 if abs(np.dot(tangent, u)) > .9:
65 tangent[:] = 0; tangent[1] = 1.0
66 tangent -= np.dot(tangent, u)*u
67 tangent /= np.linalg.norm(tangent)
68 x = normalize(u[None, :] + eps*mode[:, None]*tangent[None, :])
69 initial = np.linalg.norm(x - u[None, :])
70 for _ in range(steps):
71 x = spherical_step(x, a, eta)
72 final = np.linalg.norm(x - u[None, :])
73 return final / initial, lam_min
74
75
76def main():
77 n, d = 12, 8
78 positions = np.arange(n, dtype=float)
79 omegas = np.array([1.0, 0.37, 0.13, 0.047])
80 betas = [0.5, 1.0, 2.0, 3.0]
81 results = {"seed": SEED, "n": n, "d": d, "predictions": {}, "rows": []}
82
83 # Prediction 1: scores in [-1,1] imply exact softmax floor.
84 x_random = normalize(rng.normal(size=(n,d)))
85 a_rand, scores_rand = attention(x_random, positions, omegas, beta=2.0)
86 alpha = math.exp(-4.0)/n
87 floor_observed = float(a_rand.min())
88 floor_pass = floor_observed + 1e-14 >= alpha
89 delta = max(0.5*np.abs(a_rand[i]-a_rand[j]).sum() for i in range(n) for j in range(n))
90 delta_bound = 1-math.exp(-4.0)
91 results["predictions"]["kernel_floor"] = {
92 "predicted_alpha": alpha, "observed_min_weight": floor_observed,
93 "predicted_dobrushin_bound": delta_bound, "observed_dobrushin": float(delta),
94 "pass": bool(floor_pass and delta <= delta_bound + 1e-12)
95 }
96
97 # Prediction 2: norm-preserving update remains on the sphere.
98 x0 = normalize(rng.normal(size=(n,d))); aa, _ = attention(x0, positions, omegas, beta=1.5)
99 x1 = spherical_step(x0, aa, eta=2.0)
100 results["predictions"]["sphere_invariance"] = {
101 "max_norm_error": float(np.max(np.abs(np.linalg.norm(x1,axis=1)-1))),
102 "pass": bool(np.max(np.abs(np.linalg.norm(x1,axis=1)-1)) < 1e-12)
103 }
104
105 # Prediction 3: transverse Euler boundary eta_c=2/(1-lambda_min).
106 # At consensus the score matrix is symmetric, so the similarity transform is A itself.
107 for beta in betas:
108 xcons, a, scores, u = make_consensus(n,d,positions,omegas,beta)
109 z = np.exp(beta * scores).sum(axis=1)
110 dz = np.sqrt(z)
111 sim = dz[:, None] * a / dz[None, :]
112 ev = np.linalg.eigvalsh((sim + sim.T) / 2)
113 lam_min = float(ev[0])
114 eta_c = 2.0/(1.0-lam_min)
115 # sweep relative to predicted boundary; classify by growth of worst mode
116 ratios = []
117 for rel in [0.70, 0.90, 0.99, 1.01, 1.10, 1.30]:
118 eta = rel*eta_c
119 ratio, lam_mode = stability_trial(a, z, u, eta)
120 ratios.append({"relative_eta":rel, "growth_ratio":float(ratio), "grows":bool(ratio>1.01)})
121 # nearest grid transition (first point with clear growth)
122 growing = [r["relative_eta"] for r in ratios if r["grows"]]
123 observed_rel = min(growing) if growing else None
124 # Direct linear prediction for this eigenmode is |1+eta*(lambda_min-1)|.
125 predicted_at_110 = abs(1+1.10*eta_c*(lam_min-1))**8
126 results["rows"].append({
127 "beta":beta, "lambda_min":lam_min, "predicted_eta_c":eta_c,
128 "observed_transition_relative_grid":observed_rel,
129 "predicted_growth_ratio_at_1.10xc":float(predicted_at_110),
130 "sweep":ratios,
131 "dobrushin_bound":1-math.exp(-2*beta),
132 "dobrushin_observed":float(max(0.5*np.abs(a[i]-a[j]).sum() for i in range(n) for j in range(n)))
133 })
134 # Explicitly check the claimed boundary: all below 0.99 should contract, all 1.10 should grow.
135 below_ok = all(r["sweep"][2]["growth_ratio"] < 1 for r in results["rows"])
136 above_ok = all(r["sweep"][4]["growth_ratio"] > 1 for r in results["rows"])
137 results["predictions"]["euler_stability"] = {
138 "prediction": "eta<2/(1-lambda_min) contracts; eta>boundary grows",
139 "all_0.99x_contract": bool(below_ok), "all_1.10x_grow": bool(above_ok),
140 "pass": bool(below_ok and above_ok)
141 }
142 # A compact baseline comparison: unconstrained residual has norm growth, spherical does not.
143 xb = x0.copy()
144 for _ in range(20): xb = xb + 2.0*(aa@xb)
145 xs = x0.copy()
146 for _ in range(20): xs = spherical_step(xs, aa, 2.0)
147 results["baseline_vs_idea"] = {
148 "unconstrained_max_norm_after_20": float(np.linalg.norm(xb,axis=1).max()),
149 "spherical_max_norm_after_20": float(np.linalg.norm(xs,axis=1).max()),
150 "initial_angular_diameter": angular_diameter(x0),
151 "spherical_angular_diameter_after_20": angular_diameter(xs)
152 }
153 out = Path("results.json")
154 out.write_text(json.dumps(results, indent=2))
155 print(json.dumps(results, indent=2))
156
157if __name__ == "__main__":
158 main()