Phase-Margin Residual Jacobians / phase_margin_experiment.py

Mechanism confirmed, baseline not beaten

Raw ⬇ ZIP
  1import json
  2import math
  3from pathlib import Path
  4import numpy as np
  5
  6
  7def rotation(phi):
  8    return np.array([[math.cos(phi), -math.sin(phi)],
  9                     [math.sin(phi), math.cos(phi)]], dtype=float)
 10
 11
 12def certificate_scalar_rotation(a, phi, theta):
 13    """Exact min_gamma ||gamma exp(-j theta) a R(phi)-I||_2.
 14
 15    A planar rotation is a complex scalar. For phase error d in (-pi,pi],
 16    the positive-gamma optimum is gamma=cos(d)/a when cos(d)>0 and the
 17    optimum boundary is gamma -> 0 otherwise.
 18    """
 19    d = (phi - theta + math.pi) % (2 * math.pi) - math.pi
 20    c = math.cos(d)
 21    if c > 0:
 22        gamma = c / a
 23        z = abs(math.sin(d))
 24    else:
 25        gamma = 0.0
 26        z = 1.0
 27    # The certificate is only meaningful for z < 1.
 28    Gamma = math.asin(min(1.0, z))
 29    return gamma, z, Gamma, d
 30
 31
 32def run():
 33    rng = np.random.default_rng(2193)
 34    rows = []
 35
 36    # Prediction 1: Gamma_theta(a R(phi)) = |wrapped(phi-theta)|
 37    phase_errors = np.linspace(-0.9, 0.9, 19)
 38    err = []
 39    for d in phase_errors:
 40        _, z, g, wrapped = certificate_scalar_rotation(1.7, d, 0.0)
 41        err.append(abs(g - abs(d)))
 42    pred1 = float(max(err))
 43
 44    # Prediction 2: phase composition is additive for products.
 45    n = 8
 46    a = 0.91
 47    phis = rng.uniform(-0.28, 0.28, size=n)
 48    P = np.eye(2)
 49    for phi in phis:
 50        P = (a * rotation(phi)) @ P
 51    direct_angle = math.atan2(P[1, 0], P[0, 0])
 52    expected_angle = ((float(np.sum(phis)) + math.pi) % (2 * math.pi)) - math.pi
 53    pred2 = abs(((direct_angle - expected_angle + math.pi) % (2 * math.pi)) - math.pi)
 54
 55    # Prediction 3: for phase sum pi, I+P loses invertibility precisely at a^N=1.
 56    # The predicted distance of the exact product SRG point from -1 equals |1-a^N|.
 57    gains = np.linspace(0.82, 1.18, 73)
 58    sigma = []
 59    margin = []
 60    for gain in gains:
 61        P = (gain * rotation(math.pi / n))
 62        Pn = np.linalg.matrix_power(P, n)
 63        sigma.append(float(np.linalg.svd(np.eye(2) + Pn, compute_uv=False)[-1]))
 64        margin.append(abs(1.0 - gain ** n))
 65    sigma = np.asarray(sigma)
 66    margin = np.asarray(margin)
 67    pred3 = float(np.max(np.abs(sigma - margin)))
 68    observed_cross = float(gains[np.argmin(sigma)])
 69    predicted_cross = 1.0
 70
 71    # Prediction 4 / sharp boundary: a product with phase pi has bounded
 72    # powers below gain 1 and amplification above gain 1.
 73    horizons = np.arange(1, 13)
 74    below, above = 0.97, 1.03
 75    below_norm = np.array([below ** k for k in horizons])
 76    above_norm = np.array([above ** k for k in horizons])
 77    # Fit log growth rates; predicted slopes are log(gain).
 78    slope_below = float(np.polyfit(horizons, np.log(below_norm), 1)[0])
 79    slope_above = float(np.polyfit(horizons, np.log(above_norm), 1)[0])
 80
 81    # Small optimization demo: phase-margin penalty moves phase away from the
 82    # dangerous product angle pi, while a vanilla objective leaves it there.
 83    # Parameters are block phases; target is deliberately unstable at pi.
 84    N = 10
 85    target = np.full(N, math.pi / N)
 86    def optimize(use_penalty, steps=250, lr=0.08, lam=3.0):
 87        x = target.copy()
 88        for _ in range(steps):
 89            # synthetic fitting pressure toward the dangerous target
 90            grad = 2.0 * (x - target)
 91            total = float(np.sum(x))
 92            # keep total phase at least 0.25 rad from pi (a differentiable
 93            # hinge proxy for the estimated -1 exclusion margin)
 94            if use_penalty:
 95                dist = abs(((total - math.pi + math.pi) % (2 * math.pi)) - math.pi)
 96                if dist < 0.25:
 97                    sign = 1.0 if total >= math.pi else -1.0
 98                    grad += lam * 2.0 * (0.25 - dist) * sign
 99            x -= lr * grad
100        P = np.linalg.matrix_power(rotation(float(np.mean(x))), N)
101        return x, float(np.linalg.svd(np.eye(2) + P, compute_uv=False)[-1]), float(abs(1 + np.exp(1j * np.sum(x))))
102    x0, s0, m0 = optimize(False)
103    x1, s1, m1 = optimize(True)
104
105    result = {
106        "certificate_phase_max_abs_error": pred1,
107        "composition_angle_abs_error": pred2,
108        "invertibility_margin_max_abs_error": pred3,
109        "invertibility_crossing_observed": observed_cross,
110        "invertibility_crossing_predicted": predicted_cross,
111        "power_log_slope_below_observed_predicted": [slope_below, math.log(below)],
112        "power_log_slope_above_observed_predicted": [slope_above, math.log(above)],
113        "optimization_baseline_sigma_min": s0,
114        "optimization_phase_margin_sigma_min": s1,
115        "optimization_baseline_margin": m0,
116        "optimization_phase_margin_margin": m1,
117        "n_blocks": n,
118        "gain_sweep": {"gains": gains.tolist(), "sigma_min": sigma.tolist(), "exact_margin": margin.tolist()},
119        "phase_sweep": {"errors": phase_errors.tolist()}
120    }
121    Path("results.json").write_text(json.dumps(result, indent=2))
122    print(json.dumps(result, indent=2))
123
124
125if __name__ == "__main__":
126    run()