Buckets:
| """Claims 1, 2, 3 -- corrected scaling sweeps. | |
| Fixes relative to exp_scaling.py: | |
| * the tr(H) sweep now uses d = k+2 so that the alpha-tail contributes ~0.02 to | |
| tr(H) instead of ~10 (in the first version tr(H) was inflated at small k, | |
| which biased the fitted exponent upwards); | |
| * every sweep is checked to be BIAS-limited (h* strictly inside the grid), so | |
| that the discretisation error, not the burn-in, is what sets h; | |
| * each fit is reported both raw and after dividing out the logarithmic burn-in | |
| factor L = log(KL(mu_0||pi)/eps^2), which Otilde(.) is entitled to hide. | |
| Also measures the W_2 complexity (for the comparison with Liu et al. 2023). | |
| """ | |
| import numpy as np | |
| import common as C | |
| import ulmc_core as U | |
| NGRID = U.n_grid(int(2e10), 1.03) | |
| HS = lambda b: C.hgrid(b, n=30, ratio=1.32) | |
| PRED = { | |
| "ulmc": {"eps": -1.0, "trH": 0.5, "kappa": 1.5, "beta": -0.5, "d": 0.0}, | |
| "rmd": {"eps": -2 / 3, "trH": 1 / 3, "kappa": 1.0, "beta": -1 / 3, "d": 0.0}, | |
| } | |
| def kl0(a, mult, beta): | |
| S0, m0 = C.init_cold(a, beta) | |
| return float(np.sum(mult * U.kl_per_coord(S0, m0, a))) | |
| def run(scheme, a, mult, beta, eps): | |
| S0, m0 = C.init_cold(a, beta) | |
| r = C.sweep_neps(scheme, a, mult, beta, eps, S0, m0, hs=HS(beta), ngrid=NGRID) | |
| r.pop("table") | |
| r["bias_limited"] = bool(r["h_star"] < HS(beta)[0] * 0.999) | |
| r["KL0"] = kl0(a, mult, beta) | |
| r["L"] = float(np.log(max(r["KL0"] / eps**2, 1.0001))) | |
| r["N_over_L"] = r["N_eps"] / r["L"] | |
| return r | |
| def fits(rows, xkey, pred): | |
| x = [r[xkey] for r in rows] | |
| s, r2 = C.fit_exponent(x, [r["N_eps"] for r in rows]) | |
| sl, r2l = C.fit_exponent(x, [r["N_over_L"] for r in rows]) | |
| sh, _ = C.fit_exponent(x, [r["h_star"] for r in rows]) | |
| return { | |
| "rows": rows, | |
| "fit_exponent": s, | |
| "r2": r2, | |
| "fit_exponent_log_corrected": sl, | |
| "r2_log_corrected": r2l, | |
| "h_star_exponent": sh, | |
| "predicted": pred, | |
| "all_bias_limited": bool(all(r["bias_limited"] for r in rows)), | |
| } | |
| res = { | |
| "note": "N_eps = min over h<=1/gamma of steps to KL<=eps^2, exact", | |
| "grid_resolution_pct": 3.0, | |
| } | |
| for scheme in ("ulmc", "rmd"): | |
| blk = {} | |
| # ---- eps ---- | |
| a = np.array([1.0, 0.02]) | |
| m = np.array([20.0, 2.0]) # trH=20.04, kappa=50 | |
| epss = ( | |
| np.geomspace(1.5e-3, 2e-2, 9) | |
| if scheme == "ulmc" | |
| else np.geomspace(3e-3, 3e-2, 9) | |
| ) | |
| rows = [dict(eps=float(e), **run(scheme, a, m, 1.0, e)) for e in epss] | |
| blk["eps"] = fits(rows, "eps", PRED[scheme]["eps"]) | |
| blk["eps"].update(trH=float((a * m).sum()), kappa=50.0, d=22) | |
| # ---- tr(H): d = k+2 so tr(H) ~= k exactly ---- | |
| eps = 3e-3 if scheme == "ulmc" else 8e-3 | |
| rows = [] | |
| for k in (2, 4, 8, 16, 32, 64, 128, 256): | |
| a = np.array([1.0, 0.01]) | |
| m = np.array([float(k), 2.0]) | |
| rows.append( | |
| dict(trH=float(k + 0.02), k=k, d=k + 2, **run(scheme, a, m, 1.0, eps)) | |
| ) | |
| blk["trH"] = fits(rows, "trH", PRED[scheme]["trH"]) | |
| blk["trH"].update(eps=eps, kappa=100.0) | |
| # ---- kappa ---- | |
| eps = 8e-3 if scheme == "ulmc" else 1.2e-2 | |
| rows = [] | |
| for alpha in np.geomspace(0.5, 1e-3, 10): | |
| a = np.array([1.0, float(alpha)]) | |
| m = np.array([20.0, 2.0]) | |
| rows.append( | |
| dict( | |
| kappa=float(1 / alpha), | |
| alpha=float(alpha), | |
| trH=float((a * m).sum()), | |
| **run(scheme, a, m, 1.0, eps) | |
| ) | |
| ) | |
| blk["kappa"] = fits(rows, "kappa", PRED[scheme]["kappa"]) | |
| blk["kappa"].update(eps=eps, d=22) | |
| # ---- beta (kappa, tr(H) fixed) ---- | |
| eps = 5e-3 if scheme == "ulmc" else 1e-2 | |
| rows = [] | |
| for beta in (0.25, 0.5, 1.0, 2.0, 4.0, 8.0): | |
| k = int(round(20.0 / beta)) | |
| a = np.array([beta, beta / 50.0]) | |
| m = np.array([float(k), 2.0]) | |
| rows.append( | |
| dict( | |
| beta=float(beta), | |
| trH=float((a * m).sum()), | |
| **run(scheme, a, m, beta, eps) | |
| ) | |
| ) | |
| blk["beta"] = fits(rows, "beta", PRED[scheme]["beta"]) | |
| blk["beta"].update(eps=eps, kappa=50.0) | |
| # ---- d at FIXED (alpha, beta, tr(H)) : the dimension-free test ---- | |
| eps = 4e-3 if scheme == "ulmc" else 5e-3 | |
| rows = [] | |
| for d in (11, 20, 40, 80, 160, 320, 640, 900): | |
| a, m = C.spectrum(d, 0.01, 1.0, 10.0) | |
| rows.append( | |
| dict( | |
| d=d, | |
| trH=10.0, | |
| sum_a2=float((a * a * m).sum()), | |
| **run(scheme, a, m, 1.0, eps) | |
| ) | |
| ) | |
| blk["d_fixed_trH"] = fits(rows, "d", 0.0) | |
| blk["d_fixed_trH"].update( | |
| eps=eps, | |
| growth_factor_over_82x_d=float(rows[-1]["N_eps"] / rows[0]["N_eps"]), | |
| sqrt_d_prediction=float(np.sqrt(900 / 11)), | |
| d_prediction=float(900 / 11), | |
| ) | |
| # ---- control: H = beta I, tr(H) = beta d ---- | |
| rows = [] | |
| for d in (10, 20, 40, 80, 160, 320, 640): | |
| a = np.array([1.0, 0.01]) | |
| m = np.array([float(d - 1), 1.0]) | |
| rows.append(dict(d=d, trH=float((a * m).sum()), **run(scheme, a, m, 1.0, eps))) | |
| blk["d_control_H_eq_betaI"] = fits(rows, "d", PRED[scheme]["trH"]) | |
| res[scheme] = blk | |
| print( | |
| scheme, | |
| { | |
| k: ( | |
| round(v["fit_exponent"], 3), | |
| round(v["fit_exponent_log_corrected"], 3), | |
| v["predicted"], | |
| v["all_bias_limited"], | |
| ) | |
| for k, v in blk.items() | |
| }, | |
| flush=True, | |
| ) | |
| # --------------------------------------------------------------------------- | |
| # W2 complexity (Talagrand consequence) -- comparison with Liu et al. (2023), | |
| # who prove Otilde(kappa^{5/3} beta^{-2/3} [tr H]^{1/3} eps^{-2/3}) in W2 for a | |
| # doubly randomized ULD algorithm. The paper claims its Thm 5.2 implies | |
| # Otilde(kappa^{4/3} beta^{-2/3} [tr H]^{1/2}/eps), i.e. a strictly better kappa. | |
| # --------------------------------------------------------------------------- | |
| def w2_curve(maps, S0, m0, a, mult, grid, final_ulmc=None): | |
| A, T, q = maps | |
| Aug = U._augment(T, q) | |
| K = Aug.shape[0] | |
| accS = np.broadcast_to(np.eye(4), (K, 4, 4)).copy() | |
| accM = np.broadcast_to(np.eye(2), (K, 2, 2)).copy() | |
| S0a = np.concatenate([S0, np.ones((K, 1))], -1) | |
| out, prev = np.empty(len(grid)), 0 | |
| for i, n in enumerate(grid): | |
| d = int(n) - prev | |
| if d > 0: | |
| accS = accS @ np.linalg.matrix_power(Aug, d) | |
| accM = accM @ np.linalg.matrix_power(A, d) | |
| prev = int(n) | |
| S = np.einsum("kij,kj->ki", accS, S0a)[:, :3] | |
| mm = np.einsum("kij,kj->ki", accM, m0) | |
| if final_ulmc is not None: | |
| S, mm = U.compose_step(final_ulmc[1], final_ulmc[2], final_ulmc[0], S, mm) | |
| var = np.maximum(S[:, 0] - mm[:, 0] ** 2, 0.0) | |
| w2sq = mm[:, 0] ** 2 + (np.sqrt(var) - np.sqrt(1.0 / a)) ** 2 | |
| out[i] = float(np.sum(mult * w2sq)) | |
| return np.sqrt(out) | |
| w2 = {} | |
| for scheme in ("ulmc", "rmd"): | |
| rows = [] | |
| for alpha in np.geomspace(0.5, 2e-3, 8): | |
| a = np.array([1.0, float(alpha)]) | |
| m = np.array([20.0, 2.0]) | |
| S0, m0 = C.init_cold(a, 1.0) | |
| g = C.gamma_of(1.0) | |
| best = None | |
| for h in HS(1.0): | |
| mp = U.ulmc_maps(a, h, g) if scheme == "ulmc" else U.rmd_maps(a, h, g, 48) | |
| fin = U.ulmc_maps(a, h, g) if scheme == "rmd" else None | |
| v = w2_curve(mp, S0, m0, a, m, NGRID, final_ulmc=fin) | |
| n = U.first_below(NGRID, v, 0.05) | |
| if n and (best is None or n < best[0]): | |
| best = (n, float(h)) | |
| rows.append({"kappa": float(1 / alpha), "N_w2": best[0], "h_star": best[1]}) | |
| s, r2 = C.fit_exponent([r["kappa"] for r in rows], [r["N_w2"] for r in rows]) | |
| w2[scheme] = {"rows": rows, "kappa_exponent": s, "r2": r2, "w2_target": 0.05} | |
| print("W2", scheme, "kappa exponent", round(s, 3), flush=True) | |
| w2["liu_2023_kappa_exponent"] = 5 / 3 | |
| w2["paper_claimed_kappa_exponent_for_RMD_in_W2"] = 4 / 3 | |
| res["w2_complexity"] = w2 | |
| C.dump("scaling2", res) | |
Xet Storage Details
- Size:
- 8.07 kB
- Xet hash:
- 1c20b00318b0bd4bc6ac8edb2cc33e869d3811d257f1fed2ccf0a87dc2df3eb0
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.