68AMoK2YNk / repro /src /verify_incontext.py
DineshAI's picture
Reproduce Theorem 4.3: exact error formula is non-monotonic in context length under task misalignment (peak at M=1, 1.19) but monotone-decreasing when aligned
7e7cffb verified
Raw
History Blame Contribute Delete
5.18 kB
#!/usr/bin/env python3
"""In-Context Continual Learning error analysis (arXiv:2605.28705), Theorem 4.3. Closed-form test error
for the current task t as a function of the in-context length M:
E[(y_q - yhat)^2] = irreducible
+ [ M / (t^2 (M+1)^2) ] * sum_{s=1}^t tr(Sigma_s Gamma^{-2} Lambda) (variance)
+ sum_i (1/lambda_i) [ (lambda_i(alpha s_i - m_i) - m_i (lambda_i+tr Lambda)/N)
/ (lambda_i + (lambda_i+tr Lambda)/N) ]^2 (bias)
alpha = M/(t(M+1)), s_i = v_i^T sum_{s<=t} mu_s, m_i = v_i^T mu_t,
Gamma = Lambda + (1/N) Lambda + (1/N) tr(Lambda) I.
Headline claim [2]: the error is NON-MONOTONIC in context length M when task means MISALIGN --
"below a threshold, additional context misleads the model and degrades generalization"; for ALIGNED
tasks the error decreases monotonically. We evaluate the exact formula and check both regimes.
Deterministic.
"""
import numpy as np, json, hashlib
def error_curve(thetas_deg, Ms, d=2, N=100, t=2):
Lam = np.eye(d); lam = np.ones(d); Vv = np.eye(d) # Lambda = I -> eigenpairs
trL = float(np.trace(Lam)); Gamma = Lam + Lam / N + (trL / N) * np.eye(d)
Ginv2 = np.linalg.inv(Gamma) @ np.linalg.inv(Gamma)
Sig = np.eye(d) # per-task noise covariance
out = {}
for th in thetas_deg:
r = np.deg2rad(th)
mu1 = np.array([1.0, 0.0]); mu2 = np.array([np.cos(r), np.sin(r)])
mus = [mu1, mu2]; mu_t = mus[t - 1]; mu_sum = sum(mus)
s_i = Vv.T @ mu_sum; m_i = Vv.T @ mu_t
errs = []
for M in Ms:
alpha = M / (t * (M + 1))
var = (M / (t ** 2 * (M + 1) ** 2)) * sum(np.trace(Sig @ Ginv2 @ Lam) for _ in range(t))
bias = 0.0
for i in range(d):
num = lam[i] * (alpha * s_i[i] - m_i[i]) - m_i[i] * (lam[i] + trL) / N
den = lam[i] + (lam[i] + trL) / N
bias += (1.0 / lam[i]) * (num / den) ** 2
errs.append(float(var + bias)) # drop constant irreducible term
out[th] = np.array(errs)
return out
def main():
R = {"claim": "InContext_ContinualLearning_Thm4.3_nonmonotone", "paper": "arXiv:2605.28705"}
Ms = list(range(0, 41))
curves = error_curve([0, 150], Ms) # 0 deg aligned, 150 deg misaligned
def is_nonmonotone_up_then_down(e):
"""error rises above e[0] for some small M then ends below the peak -> 'context hurts below threshold'."""
peak = int(np.argmax(e)); return peak > 0 and e[peak] > e[0] + 1e-9 and e[-1] < e[peak] - 1e-9
e_align = curves[0]; e_mis = curves[150]
R["aligned_theta0"] = {"err_M0": round(float(e_align[0]), 4), "err_M1": round(float(e_align[1]), 4),
"err_M40": round(float(e_align[-1]), 4),
"monotone_decreasing": bool(np.all(np.diff(e_align) <= 1e-9))}
peak = int(np.argmax(e_mis))
R["misaligned_theta150"] = {"err_M0": round(float(e_mis[0]), 4), "err_M1": round(float(e_mis[1]), 4),
"peak_M": peak, "err_peak": round(float(e_mis[peak]), 4),
"err_M40": round(float(e_mis[-1]), 4),
"non_monotonic_hurts_then_helps": is_nonmonotone_up_then_down(e_mis)}
R["aligned_is_monotone"] = R["aligned_theta0"]["monotone_decreasing"]
R["misaligned_is_nonmonotone"] = R["misaligned_theta150"]["non_monotonic_hurts_then_helps"]
# threshold: smallest M beyond which error keeps decreasing to the end
thr = next((M for M in Ms if all(e_mis[M] >= e_mis[k] for k in range(M, len(Ms)))), None)
R["misaligned_threshold_M"] = thr
R["verdict"] = "supports" if (R["aligned_is_monotone"] and R["misaligned_is_nonmonotone"]) else "inconclusive"
print("claim: " + R["claim"])
print("Exact evaluation of Theorem 4.3 test-error formula; current task t=2, d=2, Lambda=I, N=100.")
print()
a = R["aligned_theta0"]
print(f"ALIGNED (theta=0): err(M=0)={a['err_M0']}, err(M=1)={a['err_M1']}, err(M=40)={a['err_M40']} "
f"-> monotone decreasing: {a['monotone_decreasing']}")
mm = R["misaligned_theta150"]
print(f"MISALIGNED (theta=150): err(M=0)={mm['err_M0']}, err(M=1)={mm['err_M1']} (peak at M={mm['peak_M']}, "
f"err={mm['err_peak']}), err(M=40)={mm['err_M40']}")
print(f" -> non-monotonic (context HURTS below threshold then HELPS): {mm['non_monotonic_hurts_then_helps']}; "
f"threshold M={R['misaligned_threshold_M']}")
print(f"verdict: {R['verdict']}")
def _np(o):
if isinstance(o, np.bool_): return bool(o)
if isinstance(o, np.integer): return int(o)
if isinstance(o, np.floating): return float(o)
raise TypeError
import os; os.makedirs("outputs", exist_ok=True)
open("outputs/incontext_results.json", "w").write(json.dumps(R, indent=2, default=_np))
print("RESULTS_SHA256=" + hashlib.sha256(json.dumps(R, sort_keys=True, default=_np).encode()).hexdigest())
return 0 if R["verdict"] == "supports" else 1
if __name__ == "__main__":
raise SystemExit(main())