explained, with numbers: Chandrupatla wins the probe by REFUSING its model cheaply, not by trusting it — it accepts the interpolation on only 28% of steps, its gate costs zero evaluations (read from data already in hand) and its refusal branch still halves the bracket; ours repairs 77.5% of evaluations after the fact and drops to 0.92 halvings/eval on fun8/fun9, worse than bisection. In similarity terms: their similarity is a PRE-step GATE on dimensionless ratios (a neighbourhood of the linear configuration), ours is an IN-step SCALE on the residual magnitude — the PLACEMENT of the reading matters more than its form
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
"""Why Chandrupatla wins the probe — measured, and stated in similarity terms.
|
||||
|
||||
ANALYSIS ONLY. The traced copy below mirrors `simroot.baselines.chandrupatla` so its
|
||||
decisions can be counted; it is NEVER used for a ranking number, and its fidelity is
|
||||
asserted against the original (identical evaluation count on all 45 problems). If that
|
||||
assert fails, the mirror has drifted and nothing here may be believed.
|
||||
|
||||
The reading being tested:
|
||||
|
||||
Chandrupatla = similarity(configuration, well-conditioned configuration) used as a
|
||||
GATE on a model step, with bisection as the refusal branch.
|
||||
ours = similarity(residual, 0) used as a SCALE for the step, with the
|
||||
safeguard bolted on afterwards.
|
||||
|
||||
* the decision variable is t in (0,1): the probe is a FRACTION of the bracket, so the
|
||||
method is scale-free by construction (what the logarithmic attempt tried to buy);
|
||||
* the gate is written in two RATIOS, xi = (x1-x2)/(x3-x2) and phi = (f1-f2)/(f3-f2),
|
||||
both invariant under affine rescaling of x and of f — relations, not magnitudes;
|
||||
* for a LINEAR f, phi = xi exactly, and that point lies strictly inside the band
|
||||
1 - sqrt(1-xi) < phi < sqrt(xi), so the band is a neighbourhood of the linear
|
||||
configuration: the model is trusted exactly where the data still look linear enough.
|
||||
|
||||
Metric for "probe quality", parameter-free and comparable across methods:
|
||||
halvings per evaluation = log2(w0 / xtol) / nfev
|
||||
Bisection is 1.0 by definition; more is better.
|
||||
|
||||
python -u explain_chandrupatla.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from simroot.baselines import Counter, chandrupatla
|
||||
from simroot.pure import pure_root
|
||||
from sweep_full import ACC, MAXFEV, XTOL, load_problems
|
||||
|
||||
|
||||
def chandrupatla_traced(f, a, b, xtol, maxfev):
|
||||
"""Mirror of the published routine plus counters. Returns (x, nfev, ok, trace)."""
|
||||
g = Counter(f, maxfev)
|
||||
trace = {"iqi": 0, "bisect": 0, "gate_rejected": 0, "no_third_point": 0}
|
||||
x1, x2 = b, a
|
||||
f1 = f2 = 0.0
|
||||
try:
|
||||
f1, f2 = g(x1), g(x2)
|
||||
if f1 == 0.0:
|
||||
return x1, g.n, True, trace
|
||||
if f2 == 0.0:
|
||||
return x2, g.n, True, trace
|
||||
x3, f3 = x2, f2
|
||||
t = 0.5
|
||||
while True:
|
||||
x = x1 + t * (x2 - x1)
|
||||
fx = g(x)
|
||||
if (fx > 0.0) == (f1 > 0.0):
|
||||
x3, f3 = x1, f1
|
||||
x1, f1 = x, fx
|
||||
else:
|
||||
x3, f3 = x2, f2
|
||||
x2, f2 = x1, f1
|
||||
x1, f1 = x, fx
|
||||
xm, fm = (x1, f1) if abs(f1) < abs(f2) else (x2, f2)
|
||||
if fm == 0.0:
|
||||
return xm, g.n, True, trace
|
||||
tol = 2.0 * 2.22e-16 * abs(xm) + xtol
|
||||
span = abs(x2 - x1)
|
||||
if span == 0.0:
|
||||
return xm, g.n, True, trace
|
||||
tl = tol / span
|
||||
if tl > 0.5:
|
||||
return xm, g.n, True, trace
|
||||
t = 0.5
|
||||
took_iqi = False
|
||||
if x3 != x2 and f3 != f2:
|
||||
xi = (x1 - x2) / (x3 - x2)
|
||||
ph = (f1 - f2) / (f3 - f2)
|
||||
if 0.0 < xi < 1.0 and 1.0 - math.sqrt(1.0 - xi) < ph < math.sqrt(xi):
|
||||
d1, d2, d3 = f1 - f2, f1 - f3, f2 - f3
|
||||
if d1 != 0.0 and d2 != 0.0 and d3 != 0.0:
|
||||
t = (f1 / d1) * (f3 / (-d3)) + \
|
||||
((x3 - x1) / (x2 - x1)) * (f1 / d2) * (f2 / d3)
|
||||
took_iqi = True
|
||||
else:
|
||||
trace["gate_rejected"] += 1
|
||||
else:
|
||||
trace["no_third_point"] += 1
|
||||
if not math.isfinite(t):
|
||||
t = 0.5
|
||||
took_iqi = False
|
||||
if t < tl:
|
||||
t = tl
|
||||
elif t > 1.0 - tl:
|
||||
t = 1.0 - tl
|
||||
trace["iqi" if took_iqi else "bisect"] += 1
|
||||
except Exception:
|
||||
return float("nan"), g.n, False, trace
|
||||
|
||||
|
||||
def main():
|
||||
probs = [p for p in load_problems() if p[0] == "CHA"]
|
||||
print(f"CHA problems: {len(probs)} metric: halvings per evaluation "
|
||||
f"= log2(w0/xtol)/nfev (bisection = 1.0)\n")
|
||||
print(f"{'problem':<16} {'CH nfev':>8} {'CH h/ev':>8} {'gate ok%':>9} "
|
||||
f"{'ours nfev':>10} {'ours h/ev':>10} {'forced%':>8}")
|
||||
|
||||
agg = {"ch_n": 0, "our_n": 0, "ch_h": [], "our_h": [], "gate": [], "forced": []}
|
||||
drift = 0
|
||||
for _s, pid, f, a, b, root in probs:
|
||||
w0 = abs(b - a)
|
||||
decades = math.log2(w0 / XTOL)
|
||||
|
||||
x_ref, n_ref, ok_ref = chandrupatla(f, a, b, XTOL, MAXFEV)
|
||||
x_t, n_t, ok_t, tr = chandrupatla_traced(f, a, b, XTOL, MAXFEV)
|
||||
if (n_ref, ok_ref) != (n_t, ok_t):
|
||||
drift += 1
|
||||
steps = tr["iqi"] + tr["bisect"]
|
||||
gate_ok = 100.0 * tr["iqi"] / steps if steps else float("nan")
|
||||
|
||||
stats = {}
|
||||
x_o, n_o, ok_o = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio",
|
||||
scale="derived3", guard="credit", stats=stats)
|
||||
forced = 100.0 * stats.get("forced", 0) / max(n_o, 1)
|
||||
|
||||
ch_h = decades / n_ref if n_ref else float("nan")
|
||||
our_h = decades / n_o if n_o else float("nan")
|
||||
agg["ch_n"] += n_ref if ok_ref else MAXFEV
|
||||
agg["our_n"] += n_o if ok_o else MAXFEV
|
||||
if ok_ref:
|
||||
agg["ch_h"].append(ch_h)
|
||||
agg["gate"].append(gate_ok)
|
||||
if ok_o:
|
||||
agg["our_h"].append(our_h)
|
||||
agg["forced"].append(forced)
|
||||
print(f"{pid:<16} {n_ref:8d} {ch_h:8.3f} {gate_ok:8.1f}% "
|
||||
f"{n_o:10d} {our_h:10.3f} {forced:7.1f}%")
|
||||
|
||||
mean = lambda v: sum(v) / len(v) if v else float("nan") # noqa: E731
|
||||
print(f"\nmirror fidelity: {'OK' if drift == 0 else f'DRIFTED on {drift} problems'}")
|
||||
print(f"totals (failures charged {MAXFEV}): Chandrupatla {agg['ch_n']}, ours {agg['our_n']}")
|
||||
print(f"halvings per evaluation: Chandrupatla {mean(agg['ch_h']):.3f}, "
|
||||
f"ours {mean(agg['our_h']):.3f}")
|
||||
print(f"Chandrupatla accepted the model on {mean(agg['gate']):.1f}% of steps "
|
||||
f"(the rest it REFUSED and halved)")
|
||||
print(f"our safeguard had to repair {mean(agg['forced']):.1f}% of evaluations")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user