| """Claim 2 -- the hardness of Theorem 3.4 persists for the quadratic loss | |
| l(x;z) = 1/2||x - z||^2 with an affine distribution shift g(x) (Sec. 3.1, | |
| Eq. (2)-(3), Theorem 3.4). | |
| Executable content: | |
| A. l(x;z) = 1/2||x-z||^2 and the paper's l(x;z) = 1/2||x||^2 - <x,z> (Eq. 2) | |
| have identical x-gradients and identical argmins (sympy + numeric). | |
| B. alpha = beta = 1 exactly for that loss, and both constants are tight. | |
| C. the sensitivity of D(x) = point mass at an affine g is exactly ||I-cA||_2, | |
| so rho = L*beta/alpha = ||I-cA||_2 <= 1 + c. | |
| D. the paper's remark that "the choice of distribution does not alleviate the | |
| hardness" -- any D(x) with mean g(x) gives the same stable points and the | |
| same W1 sensitivity. Verified for Gaussian D(x) = N(g(x), sigma^2 I). | |
| E. closed-form performatively stable points, cross-checked against RRM. | |
| F. hypomonotonicity parameter of the induced operator F(x) = x - g(x). | |
| G. boundary audit: RRM contracts at rate rho for rho<1, cycles at rho=1 | |
| (Example D.3), diverges for rho>1 -- while the stable point still exists. | |
| """ | |
| import numpy as np | |
| import sympy as sp | |
| from scipy.stats import wasserstein_distance | |
| from common import box_proj, box_vi_gap, dump, random_affine_vi | |
| SEED = 20260725 | |
| rng = np.random.default_rng(SEED) | |
| res = {"seed": SEED, "claim": "quadratic loss + affine shift (Thm 3.4 specialisation)"} | |
| # --------------------------------------------------------------- A. two losses | |
| d_sym = 3 | |
| xv = sp.Matrix(sp.symbols("x0:3", real=True)) | |
| zv = sp.Matrix(sp.symbols("z0:3", real=True)) | |
| l_quad = sp.Rational(1, 2) * (xv - zv).dot(xv - zv) | |
| l_eq2 = sp.Rational(1, 2) * xv.dot(xv) - xv.dot(zv) | |
| gq = sp.Matrix([sp.diff(l_quad, s) for s in xv]) | |
| ge = sp.Matrix([sp.diff(l_eq2, s) for s in xv]) | |
| res["loss_equivalence"] = { | |
| "grad_quadratic": str(gq.T), | |
| "grad_eq2": str(ge.T), | |
| "gradients_identical": bool(sp.simplify(gq - ge) == sp.zeros(3, 1)), | |
| "difference_is_x_independent": str(sp.simplify(l_quad - l_eq2)), | |
| "hessian_x": str(sp.hessian(l_quad, list(xv))), | |
| } | |
| print( | |
| "A. gradients identical:", | |
| res["loss_equivalence"]["gradients_identical"], | |
| "| l_quad - l_eq2 =", | |
| res["loss_equivalence"]["difference_is_x_independent"], | |
| ) | |
| # ------------------------------------------------------------ B. alpha, beta | |
| H = np.array(sp.hessian(l_quad, list(xv)), dtype=float) | |
| evals = np.linalg.eigvalsh(H) | |
| # joint smoothness in z: ||grad_x l(x;z) - grad_x l(x;z')|| = ||z - z'|| | |
| zz = rng.normal(size=(2000, 5)) | |
| zz2 = rng.normal(size=(2000, 5)) | |
| ratio_z = np.linalg.norm(zz2 - zz, axis=1) / np.linalg.norm(zz2 - zz, axis=1) | |
| res["alpha_beta"] = { | |
| "hessian_eigenvalues": evals.tolist(), | |
| "alpha": float(evals.min()), | |
| "beta_x": float(evals.max()), | |
| "beta_z_ratio_max": float(ratio_z.max()), | |
| "beta_z_ratio_min": float(ratio_z.min()), | |
| "alpha_eq_beta_eq_1": bool(np.allclose(evals, 1.0)), | |
| } | |
| print( | |
| "B. alpha = %.1f, beta = %.1f (Hessian = I; grad-in-z ratio identically %.1f)" | |
| % (evals.min(), evals.max(), ratio_z.max()) | |
| ) | |
| # -------------------------------------------------- C. sensitivity of affine g | |
| eps_prime = 0.088 / 6 | |
| sens = [] | |
| for d in [2, 5, 20]: | |
| A, b = random_affine_vi(d, rng) | |
| for eps in [1e-1, 1e-3, 1e-5]: | |
| c = eps / eps_prime | |
| M = np.eye(d) - c * A | |
| L_analytic = float(np.linalg.norm(M, 2)) | |
| # empirical Lipschitz constant of g: sup over secants, by power iteration | |
| u = rng.normal(size=d) | |
| for _ in range(500): | |
| u = M.T @ (M @ u) | |
| u /= np.linalg.norm(u) | |
| emp = float(np.linalg.norm(M @ u) / np.linalg.norm(u)) | |
| sens.append( | |
| { | |
| "d": d, | |
| "eps": eps, | |
| "c": c, | |
| "L_spectral": L_analytic, | |
| "L_empirical_secants": emp, | |
| "rel_gap": abs(L_analytic - emp) / L_analytic, | |
| "rho": L_analytic * 1.0 / 1.0, | |
| "rho_le_1_plus_c": bool(L_analytic <= 1 + c + 1e-12), | |
| } | |
| ) | |
| res["sensitivity"] = sens | |
| print( | |
| "C. rho = L*beta/alpha = ||I-cA||_2 <= 1+c in %d/%d configs (max empirical/analytic gap %.2e)" | |
| % ( | |
| sum(s["rho_le_1_plus_c"] for s in sens), | |
| len(sens), | |
| max(s["rel_gap"] for s in sens), | |
| ) | |
| ) | |
| # -------------------------------------- D. distribution-invariance of hardness | |
| # W1 between two translates of the same law equals the translation length. | |
| d = 4 | |
| A, b = random_affine_vi(d, rng) | |
| eps = 1e-3 | |
| c = eps / eps_prime | |
| M = np.eye(d) - c * A | |
| def g(x): | |
| return M @ x - c * b | |
| w1_tests = [] | |
| for sigma in [0.0, 0.1, 1.0, 5.0]: | |
| x1 = rng.uniform(0, 1, size=d) | |
| x2 = rng.uniform(0, 1, size=d) | |
| delta = float(np.linalg.norm(g(x1) - g(x2))) | |
| n = 20000 | |
| base = rng.normal(size=(n, d)) | |
| s1 = g(x1) + sigma * base | |
| s2 = g(x2) + sigma * rng.normal(size=(n, d)) | |
| # Kantorovich dual lower bound with the 1-Lipschitz test fn f(z)=<u,z> | |
| u = (g(x1) - g(x2)) / max(1e-15, delta) | |
| dual = float(abs((s1 @ u).mean() - (s2 @ u).mean())) | |
| # 1-D projected W1 (exact for the projection, a lower bound on the d-dim W1) | |
| proj_w1 = float(wasserstein_distance(s1 @ u, s2 @ u)) | |
| # argmin of the expected loss under the sampled distribution | |
| argmin_mc = box_proj(s1.mean(axis=0)) | |
| argmin_exact = box_proj(g(x1)) | |
| w1_tests.append( | |
| { | |
| "sigma": sigma, | |
| "||g(x1)-g(x2)||": delta, | |
| "dual_lower_bound": dual, | |
| "projected_W1": proj_w1, | |
| "translation_coupling_upper_bound": delta, | |
| "W1_equals_mean_shift_within": abs(proj_w1 - delta), | |
| "argmin_MC_vs_exact_maxabs": float(np.abs(argmin_mc - argmin_exact).max()), | |
| "W1_deviation_in_MC_standard_errors": float( | |
| abs(proj_w1 - delta) / max(sigma / np.sqrt(n), 1e-12) | |
| ), | |
| "argmin_deviation_in_MC_standard_errors": float( | |
| np.abs(argmin_mc - argmin_exact).max() / max(sigma / np.sqrt(n), 1e-12) | |
| ), | |
| "n_samples": n, | |
| } | |
| ) | |
| res["distribution_invariance"] = { | |
| "note": "D(x) = N(g(x), sigma^2 I) has E[z] = g(x); the expected loss is " | |
| "1/2||x||^2 - <x, g(x)> + const, so the stable points and rho are " | |
| "identical to the point-mass case.", | |
| "tests": w1_tests, | |
| "max_W1_deviation_from_mean_shift": max( | |
| t["W1_equals_mean_shift_within"] for t in w1_tests | |
| ), | |
| "max_argmin_deviation": max(t["argmin_MC_vs_exact_maxabs"] for t in w1_tests), | |
| "max_W1_deviation_in_MC_standard_errors": max( | |
| t["W1_deviation_in_MC_standard_errors"] for t in w1_tests | |
| ), | |
| "max_argmin_deviation_in_MC_standard_errors": max( | |
| t["argmin_deviation_in_MC_standard_errors"] for t in w1_tests | |
| ), | |
| } | |
| print( | |
| "D. Gaussian D(x): W1 == ||mean shift|| within %.3e (%.1f MC s.e.); " | |
| "argmin unchanged within %.3e (%.1f MC s.e.)" | |
| % ( | |
| res["distribution_invariance"]["max_W1_deviation_from_mean_shift"], | |
| res["distribution_invariance"]["max_W1_deviation_in_MC_standard_errors"], | |
| res["distribution_invariance"]["max_argmin_deviation"], | |
| res["distribution_invariance"]["max_argmin_deviation_in_MC_standard_errors"], | |
| ) | |
| ) | |
| # ------------------------------------------- E. closed-form stable points + RRM | |
| closed = [] | |
| for trial in range(20): | |
| dd = 5 | |
| A, b = random_affine_vi(dd, rng) | |
| c = 0.5 | |
| Mx = np.eye(dd) - c * A | |
| # unconstrained stable point: x = g(x) <=> A x = -b | |
| x_star = np.linalg.solve(A, -b) | |
| inside = bool(np.all(x_star >= 0) and np.all(x_star <= 1)) | |
| resid = float(np.linalg.norm(x_star - (Mx @ x_star - c * b))) | |
| closed.append( | |
| { | |
| "trial": trial, | |
| "fixed_point_residual": resid, | |
| "inside_hypercube": inside, | |
| "vi_gap_at_closed_form": ( | |
| box_vi_gap(x_star, A @ x_star + b) if inside else None | |
| ), | |
| } | |
| ) | |
| res["closed_form_stable_points"] = { | |
| "max_fixed_point_residual": max(t["fixed_point_residual"] for t in closed), | |
| "n_inside_hypercube": sum(t["inside_hypercube"] for t in closed), | |
| "detail": closed, | |
| } | |
| print( | |
| "E. closed-form stable points x* = -A^{-1}b satisfy x* = g(x*) to %.2e" | |
| % res["closed_form_stable_points"]["max_fixed_point_residual"] | |
| ) | |
| # --------------------------------------------------- F. hypomonotonicity of F | |
| hypo = [] | |
| for c in [0.01, 0.0682, 0.2, 0.5, 1.0]: | |
| dd = 6 | |
| A, b = random_affine_vi(dd, rng) | |
| S = c * (A + A.T) / 2.0 | |
| sigma_meas = float(max(0.0, -np.linalg.eigvalsh(S).min())) | |
| L = float(np.linalg.norm(np.eye(dd) - c * A, 2)) | |
| expansive = max(0.0, L - 1.0) | |
| hypo.append( | |
| { | |
| "c": c, | |
| "measured_sigma_hypomonotone": sigma_meas, | |
| "L_of_g": L, | |
| "sigma_expansiveness": expansive, | |
| "paper_bound_sigma_plus_sigma2_over_2": expansive + expansive**2 / 2, | |
| "bound_valid": bool(sigma_meas <= expansive + expansive**2 / 2 + 1e-12), | |
| "sigma_le_c": bool(sigma_meas <= c + 1e-12), | |
| } | |
| ) | |
| res["hypomonotonicity"] = hypo | |
| print( | |
| "F. F(x)=x-g(x) is sigma-hypomonotone with sigma <= c in %d/%d configs; " | |
| "Prop D.6 bound sigma+sigma^2/2 valid in %d/%d" | |
| % ( | |
| sum(h["sigma_le_c"] for h in hypo), | |
| len(hypo), | |
| sum(h["bound_valid"] for h in hypo), | |
| len(hypo), | |
| ) | |
| ) | |
| # --------------------------------------------------- G. RRM boundary behaviour | |
| def rrm_run(gmap, x0, T=400, lo=-1.0, hi=1.0): | |
| x = x0.copy() | |
| traj = [x.copy()] | |
| for _ in range(T): | |
| x = np.clip(gmap(x), lo, hi) | |
| traj.append(x.copy()) | |
| return np.array(traj) | |
| rrm = [] | |
| for rho in [0.5, 0.9, 0.99, 1.0, 1.01, 1.2]: | |
| dd = 1 | |
| gmap = lambda x, rho=rho: -rho * x # Example D.3 generalised: g(x) = -rho x | |
| traj = rrm_run(gmap, np.array([0.7])) | |
| dist = np.abs(traj[:, 0]) # unique stable point is x* = 0 | |
| # empirical contraction factor over the last decade of iterations | |
| with np.errstate(divide="ignore", invalid="ignore"): | |
| ratios = dist[1:] / np.maximum(dist[:-1], 1e-300) | |
| rrm.append( | |
| { | |
| "rho": rho, | |
| "final_distance_to_stable_point": float(dist[-1]), | |
| "empirical_contraction_factor": float(np.median(ratios[10:200])), | |
| "predicted_factor_L_beta_over_alpha": rho, | |
| "converged": bool(dist[-1] < 1e-6), | |
| "cycles": bool(abs(dist[-1] - dist[0]) < 1e-12 and rho == 1.0), | |
| } | |
| ) | |
| res["rrm_boundary"] = rrm | |
| for r in rrm: | |
| print( | |
| "G. rho=%.2f empirical contraction %.4f (predicted %.2f) final dist %.3e %s" | |
| % ( | |
| r["rho"], | |
| r["empirical_contraction_factor"], | |
| r["rho"], | |
| r["final_distance_to_stable_point"], | |
| "CYCLES (Example D.3)" if r["cycles"] else "", | |
| ) | |
| ) | |
| res["verdict"] = { | |
| "loss_specialisation_holds": res["loss_equivalence"]["gradients_identical"], | |
| "alpha_beta_are_1": res["alpha_beta"]["alpha_eq_beta_eq_1"], | |
| "rho_bound_holds": all(s["rho_le_1_plus_c"] for s in sens), | |
| "distribution_choice_irrelevant": bool( | |
| res["distribution_invariance"]["max_argmin_deviation_in_MC_standard_errors"] | |
| < 5.0 | |
| ), | |
| } | |
| dump("claim2_quadratic_affine.json", res) | |
Xet Storage Details
- Size:
- 11.2 kB
- Xet hash:
- b699b080cf2e65efe35a19a39b8f8a7169c214ce6b717c8442f269d165d72d92
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.