Eigenmode-Targeted Hidden-State Actuator Selection / experiment.py

Mechanism failed

Raw ⬇ ZIP
  1"""Numerical MVP for eigenmode-targeted hidden-state actuator selection."""
  2import json
  3import numpy as np
  4
  5SEED = 2944
  6
  7def make_family(rng, lam):
  8    Q, _ = np.linalg.qr(rng.normal(size=(8, 8)))
  9    scales = np.array([1.0, .8, 1.25, .9, 1.1, .75, 1.3, .95])
 10    V = Q @ np.diag(scales)
 11    eigs = np.array([lam, .62, .55, .48, .40, .32, .25, .15])
 12    return V @ np.diag(eigs) @ np.linalg.inv(V), V
 13
 14def mode_data(A):
 15    vals, V = np.linalg.eig(A)
 16    j = int(np.argmax(np.abs(vals)))
 17    lam = float(vals[j].real)
 18    v = V[:, j].real
 19    v /= np.linalg.norm(v)
 20    w = np.real(np.linalg.inv(V)[j, :])
 21    w /= w @ v
 22    return lam, v, w
 23
 24def resolvent_gain(A, C, S, z=1.0):
 25    B = np.eye(A.shape[0])[:, S]
 26    R = C @ np.linalg.solve(np.eye(A.shape[0]) - z * A, B)
 27    return float(np.linalg.svd(R, compute_uv=False)[0])
 28
 29def finite_gain(A, C, S, horizon=300):
 30    B = np.eye(A.shape[0])[:, S]
 31    P, total = np.eye(A.shape[0]), np.zeros((C.shape[0], len(S)))
 32    for _ in range(horizon):
 33        total += C @ P @ B
 34        P = A @ P
 35    return float(np.linalg.svd(total, compute_uv=False)[0])
 36
 37def main():
 38    rng = np.random.default_rng(SEED)
 39    # A readout with nonzero exposure to the dominant mode.
 40    C = np.array([[1., -.7, .4, .2, -.3, .5, .1, -.2]])
 41
 42    A, _ = make_family(rng, .97)
 43    lam, v, w = mode_data(A)
 44    eig_resid = np.linalg.norm(A @ v - lam * v)
 45    left_resid = np.linalg.norm(w @ A - lam * w)
 46    exposure = float(np.linalg.norm(C @ v))
 47
 48    # Fixed eigenbasis: only lambda changes, isolating the predicted 1/(1-lambda)
 49    # growth of the DC resolvent.
 50    base_rng = np.random.default_rng(123)
 51    _, V = make_family(base_rng, .5)
 52    eigvals = np.array([.0, .62, .55, .48, .40, .32, .25, .15])
 53    deltas = np.array([.20, .12, .08, .05, .03, .02, .01])
 54    gains = []
 55    for d in deltas:
 56        D = eigvals.copy(); D[0] = 1.0 - d
 57        Ad = V @ np.diag(D) @ np.linalg.inv(V)
 58        gains.append(resolvent_gain(Ad, C, np.arange(8), z=1.0))
 59    slope = float(np.polyfit(np.log(1 / deltas), np.log(gains), 1)[0])
 60
 61    # Compare the literal prompt score (which is inverse footprint) with the
 62    # modal input-leverage score |w_i| and random coordinate subsets.
 63    rows = []
 64    for seed in [11, 22, 33]:
 65        rr = np.random.default_rng(seed)
 66        At, _ = make_family(rr, .985)
 67        lt, vt, wt = mode_data(At)
 68        k = 2
 69        literal = np.argsort(1.0 / (1e-8 + vt**2))[-k:][::-1]
 70        right_rank = np.argsort(vt**2)[-k:][::-1]
 71        left_rank = np.argsort(wt**2)[-k:][::-1]
 72        sets = [rr.choice(8, k, replace=False) for _ in range(500)]
 73        rg = np.array([finite_gain(At, C, s) for s in sets])
 74        lg = finite_gain(At, C, literal)
 75        wg = finite_gain(At, C, right_rank)
 76        mg = finite_gain(At, C, left_rank)
 77        rows.append({
 78            "seed": seed, "lambda": lt,
 79            "literal_inverse_footprint_set": literal.tolist(),
 80            "right_eigenvector_top_set": right_rank.tolist(),
 81            "left_eigenvector_modal_leverage_set": left_rank.tolist(),
 82            "literal_gain": lg, "right_rank_gain": wg, "modal_left_rank_gain": mg,
 83            "random_mean_gain": float(rg.mean()),
 84            "modal_ratio_to_random_mean": float(mg / rg.mean()),
 85            "literal_ratio_to_random_mean": float(lg / rg.mean()),
 86        })
 87    result = {
 88        "seed": SEED,
 89        "eigenpair_residual": float(eig_resid),
 90        "left_eigenpair_residual": float(left_resid),
 91        "biorthogonal_residual": float(abs(w @ v - 1)),
 92        "mode_exposure": exposure,
 93        "resolvent_deltas": deltas.tolist(), "resolvent_gains": gains,
 94        "resolvent_log_slope": slope, "selection_rows": rows,
 95        "mean_modal_ratio": float(np.mean([r["modal_ratio_to_random_mean"] for r in rows])),
 96        "mean_literal_ratio": float(np.mean([r["literal_ratio_to_random_mean"] for r in rows]))
 97    }
 98    print(json.dumps(result, indent=2))
 99    with open("results.json", "w") as f: json.dump(result, f, indent=2)
100
101if __name__ == "__main__": main()