Floquet Monodromy Optimizer / floquet_experiment.py

Failed on benchmark

Raw ⬇ ZIP
  1import json
  2import numpy as np
  3
  4SEED = 1053
  5rng = np.random.default_rng(SEED)
  6
  7# Two positive-definite phase Hessians. They do not commute.
  8H1 = np.array([[4.0, 1.0], [1.0, 1.0]])
  9H2 = np.array([[1.5, -0.7], [-0.7, 3.0]])
 10I = np.eye(2)
 11
 12
 13def monodromy(scale, order=(1, 2)):
 14    # eta1=1.6s and eta2=.4s: same two-step average LR s as baseline.
 15    e1, e2 = 1.6 * scale, 0.4 * scale
 16    J1, J2 = I - e1 * H1, I - e2 * H2
 17    return (J2 @ J1) if order == (1, 2) else (J1 @ J2)
 18
 19
 20def rho(M):
 21    return float(np.max(np.abs(np.linalg.eigvals(M))))
 22
 23
 24def boundary():
 25    # Largest stable scale, found from the exact rho(M)=1 crossing.
 26    lo, hi = 0.0, 2.0
 27    while rho(monodromy(hi)) < 1.0:
 28        hi *= 2
 29    for _ in range(70):
 30        mid = (lo + hi) / 2
 31        if rho(monodromy(mid)) < 1:
 32            lo = mid
 33        else:
 34            hi = mid
 35    return (lo + hi) / 2
 36
 37
 38def growth_check(s, periods=80):
 39    M = monodromy(s)
 40    vals, vecs = np.linalg.eig(M)
 41    j = int(np.argmax(np.abs(vals)))
 42    v = np.real(vecs[:, j])
 43    v /= np.linalg.norm(v)
 44    x = v.copy()
 45    norms = []
 46    for _ in range(periods):
 47        x = M @ x
 48        norms.append(np.linalg.norm(x))
 49    # Geometric mean removes initial normalization and reports empirical Floquet growth.
 50    empirical = float((norms[-1] / norms[0]) ** (1.0 / (periods - 1)))
 51    return rho(M), empirical, float(norms[-1])
 52
 53
 54def commutator_scaling():
 55    C = H2 @ H1 - H1 @ H2
 56    c_norm = np.linalg.norm(C, 2)
 57    rows = []
 58    for s in [0.01, 0.02, 0.04, 0.08, 0.16]:
 59        # Exact antisymmetric part is eta1*eta2*(H2 H1-H1 H2).
 60        M = monodromy(s)
 61        observed = np.linalg.norm(M - M.T, 2)
 62        predicted = (1.6 * s) * (0.4 * s) * c_norm
 63        rows.append({"scale": s, "observed": observed, "predicted": predicted,
 64                     "ratio": observed / predicted})
 65    return {"commutator_norm": c_norm, "rows": rows}
 66
 67
 68def quadratic_optimizer(scale=0.20, periods=60):
 69    # Both methods see the same alternating phase gradients. Baseline uses constant
 70    # LR s; Floquet uses the two phase LRs while preserving the same average LR.
 71    x0 = np.array([2.0, -1.5])
 72    x_const, x_periodic = x0.copy(), x0.copy()
 73    e1, e2 = 1.6 * scale, .4 * scale
 74    trace = []
 75    Hbar = .5 * (H1 + H2)
 76    def objective(x):
 77        return float(.5 * x @ Hbar @ x)
 78    for p in range(periods):
 79        # phase 1
 80        x_const -= scale * (H1 @ x_const)
 81        x_periodic -= e1 * (H1 @ x_periodic)
 82        # phase 2
 83        x_const -= scale * (H2 @ x_const)
 84        x_periodic -= e2 * (H2 @ x_periodic)
 85        if p in (0, 4, 9, 19, 39, periods - 1):
 86            trace.append({"period": p + 1, "constant_loss": objective(x_const),
 87                          "periodic_loss": objective(x_periodic)})
 88    return {"scale": scale, "periods": periods, "trace": trace,
 89            "final_constant_loss": objective(x_const),
 90            "final_periodic_loss": objective(x_periodic)}
 91
 92
 93def main():
 94    s_star = boundary()
 95    # Boundary prediction is the formula rho[(I-e2 H2)(I-e1 H1)]=1;
 96    # observed transition is independently classified by long-run norm behavior.
 97    scales = [0.90 * s_star, 0.99 * s_star, 1.01 * s_star, 1.10 * s_star]
 98    growth = []
 99    for s in scales:
100        r, empirical, final_norm = growth_check(s)
101        growth.append({"scale": s, "rho_predicted": r,
102                       "empirical_per_period_growth": empirical,
103                       "final_perturbation_norm": final_norm,
104                       "classification": "stable" if empirical < 1 else "unstable"})
105    # A direct sweep gives an independently observable transition bracket.
106    sweep = []
107    for s in np.linspace(.8 * s_star, 1.2 * s_star, 17):
108        r, empirical, _ = growth_check(float(s), periods=50)
109        sweep.append([float(s), r, empirical])
110    order_difference = np.linalg.norm(monodromy(.25, (1, 2)) - monodromy(.25, (2, 1)))
111    result = {
112        "seed": SEED,
113        "hessians": {"H1": H1.tolist(), "H2": H2.tolist()},
114        "predictions": {
115            "critical_scale_exact": s_star,
116            "stability_rule": "rho(M)<1 predicts decay and rho(M)>1 predicts growth",
117            "commutator_rule": "||M-M.T|| = eta1*eta2*||[H2,H1]|| for symmetric H phases"
118        },
119        "growth_near_boundary": growth,
120        "boundary_sweep": sweep,
121        "commutator_scaling": commutator_scaling(),
122        "reversed_order_matrix_difference_at_scale_.25": order_difference,
123        "quadratic_optimizer": quadratic_optimizer()
124    }
125    print(json.dumps(result, indent=2))
126
127if __name__ == "__main__":
128    main()