SabaPivot's picture
download
raw
8.08 kB
"""CLAIM 6 -- Conjecture 5.3: for norm-oblivious comparators the minimax static regret of
uBLO is R_T(u) = Theta( ||u|| sqrt( T (d v log||u||) ) ), left as an OPEN PROBLEM.
This is a conjecture, not a theorem. Nothing numerical can prove it, and this page does not
claim to. What is done here:
1 ACHIEVABILITY side (the O-direction, which the paper already supports via Eq. (5)):
measure the regret of PABLO across ~7 orders of magnitude of ||u||, spanning the
transition point log||u|| = d, on the strongest instance family we can build (max over
a battery of adversarial and stochastic instances), and check whether
R_T(u) / (||u|| sqrt(T (d v log||u||))) stays bounded and roughly flat across the
transition -- i.e. whether the conjectured functional form is the right one.
2 The OBSTRUCTION the paper describes, made executable: the scale/direction decomposition
of Eq. (7), R_T(u) = R^V_T(||u||) + ||u|| R^Z_T(u/||u||), is computed along real
trajectories on (a) the Theorem 5.2 direction-hard instance and (b) a scale-hard
instance. The paper argues the two partial lower bounds do not combine because on a
direction-hard sequence the scale regret can be large and NEGATIVE. That is measured.
3 A cheap falsification probe: is there any instance in the battery on which the measured
regret EXCEEDS C ||u|| sqrt(T(d v log||u||)) for a growing C? (A reproducible instance
family with a growing ratio would falsify the conjectured upper side.)
"""
from __future__ import annotations
import json
import os
import sys
import numpy as np
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from batch import BatchAlg6, fit_exponent, run_pablo_batch
from pablo import env_flip, env_hard, env_rademacher
OUT = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "outputs"
)
SEED = 20260725
G = 1.0
EPSILON = 1.0
def instance_battery(T, d, seed):
"""A battery of loss sequences; the adversary is approximated by taking, for each ||u||,
the instance in the battery that maximises the measured regret."""
out = {}
rng = np.random.default_rng(seed)
out["hypercube_hard"] = env_hard(T, d, G, rng)
out["rademacher_coord"] = env_rademacher(T, d, G, rng)
for amp in [0.05, 0.25, 1.0]:
for nf in [1, 3, 7]:
out["flip_amp%.2f_n%d" % (amp, nf)] = env_flip(
T, d, G, rng, amp=amp, n_flips=nf
)
# a 1-dimensional (scale-hard) sequence embedded in R^d: the Streeter-McMahan geometry
L = np.zeros((T, d))
L[:, 0] = G * (rng.integers(2, size=T) * 2.0 - 1.0)
out["one_dimensional_signs"] = L
return out
def conjectured(u_norm, T, d):
return u_norm * np.sqrt(T * max(d, np.log(max(u_norm, 1.0001))))
def run_instance(losses, T, d, S, seed, eps_pert=1e-3):
olo = BatchAlg6(S, d, T, 2 * d * G, EPSILON / d)
return run_pablo_batch(losses, olo, d, eps_pert, np.random.default_rng(seed), S)
def test1_achievability(T=4000, S=200):
rows = []
for d in [2, 4, 8]:
norms = [10.0**k for k in range(0, 8)]
battery = instance_battery(T, d, SEED + d)
runs = {
k: run_instance(v, T, d, S, SEED + 3 * d + len(k))
for k, v in battery.items()
}
for un in norms:
best, arg = -np.inf, None
for name, r in runs.items():
dirn = -r["sum_losses"] / max(np.linalg.norm(r["sum_losses"]), 1e-12)
m = float(
np.mean(r["cum_play"] - float(np.dot(r["sum_losses"], un * dirn)))
)
if m > best:
best, arg = m, name
c = conjectured(un, T, d)
rows.append(
dict(
d=d,
T=T,
u_norm=un,
worst_instance=arg,
max_mean_regret=best,
conjectured_rate=float(c),
ratio=best / float(c),
regime="d" if np.log(un) <= d else "log||u||",
)
)
# is the ratio flat across the transition?
summary = {}
for d in [2, 4, 8]:
rr = [x["ratio"] for x in rows if x["d"] == d]
nn = [x["u_norm"] for x in rows if x["d"] == d]
sl, _, se = fit_exponent(nn, np.maximum(rr, 1e-12))
summary["d=%d" % d] = dict(
min_ratio=float(np.min(rr)),
max_ratio=float(np.max(rr)),
spread=float(np.max(rr) / max(np.min(rr), 1e-12)),
fitted_slope_of_ratio_vs_u_norm=sl,
stderr=se,
flat_would_be=0.0,
)
return dict(rows=rows, flatness_summary=summary, seeds=S)
def test2_decomposition(T=4000, S=200):
"""Eq. (7): R_T(u) = R^V_T(||u||) + ||u|| R^Z_T(u/||u||) with
R^V_T(||u||) = sum_t (v_t - ||u||) <z_t, l_t>, R^Z_T = sum_t <z_t - u/||u||, l_t>.
"""
rows = []
for d in [4, 16]:
for name, losses in [
(
"theorem_5_2_direction_hard",
env_hard(T, d, G, np.random.default_rng(SEED + d)),
),
("scale_hard_one_dimensional", None),
]:
if losses is None:
losses = np.zeros((T, d))
rng = np.random.default_rng(SEED + 7 * d)
losses[:, 0] = G * (rng.integers(2, size=T) * 2.0 - 1.0)
r = run_instance(losses, T, d, S, SEED + 11 * d)
sl = r["sum_losses"]
dirn = -sl / max(np.linalg.norm(sl), 1e-12)
A = r["sum_dir"] # sum_t <z_t, l_t>
RZ = float(np.mean(A - float(np.dot(sl, dirn))))
for un in [1.0, 100.0, 1e4]:
RV = float(np.mean(r["cum_play"] - un * A))
R = float(np.mean(r["cum_play"] - float(np.dot(sl, un * dirn))))
rows.append(
dict(
d=d,
instance=name,
u_norm=un,
direction_regret_R_Z=RZ,
scale_regret_R_V=RV,
full_regret=R,
identity_residual=abs(R - (RV + un * RZ)),
sqrt_dT=float(np.sqrt(d * T)),
R_Z_over_sqrt_dT=RZ / float(np.sqrt(d * T)),
scale_regret_is_negative=bool(RV < 0),
)
)
return rows
def test3_falsification_probe(T=4000, S=200):
worst = []
for d in [2, 4, 8, 16]:
battery = instance_battery(T, d, SEED + 5 * d)
for name, losses in battery.items():
r = run_instance(losses, T, d, S, SEED + 13 * d + len(name))
dirn = -r["sum_losses"] / max(np.linalg.norm(r["sum_losses"]), 1e-12)
for un in [1.0, 1e2, 1e4, 1e6]:
m = float(
np.mean(r["cum_play"] - float(np.dot(r["sum_losses"], un * dirn)))
)
worst.append(
dict(d=d, instance=name, u_norm=un, ratio=m / conjectured(un, T, d))
)
mx = max(worst, key=lambda x: x["ratio"])
return dict(
instances_probed=len(worst),
worst_case=mx,
max_ratio=mx["ratio"],
any_ratio_above_one=bool(mx["ratio"] > 1.0),
)
if __name__ == "__main__":
res = dict(
claim="claim-6 Conjecture 5.3 (OPEN PROBLEM)",
seed=SEED,
honesty_note="Conjecture 5.3 is an open problem. No simulation can prove the "
"Omega side. The verdict recorded for this claim is 'toy': "
"numerical evidence about the conjectured functional form on "
"synthetic instances, nothing more.",
T1_achievability_shape=test1_achievability(),
T2_scale_direction_decomposition=test2_decomposition(),
T3_falsification_probe=test3_falsification_probe(),
)
os.makedirs(OUT, exist_ok=True)
with open(os.path.join(OUT, "claim6_conjecture.json"), "w") as f:
json.dump(res, f, indent=1)
print(json.dumps(res, indent=1))

Xet Storage Details

Size:
8.08 kB
·
Xet hash:
88e53be766ed04dc101abf5c54690d471cfb4234a4956115a59c2459082fa20c

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.