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:
vvs
2026-09-20 23:05:22 +01:00
co-authored by Claude Opus 5
parent 84ff1c796f
commit be10fc0b22
3 changed files with 251 additions and 0 deletions
+149
View File
@@ -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()