the wide-bracket gap is NOT closed, and now it has an address: the STEP RULE, not the guarantee and not the reading places. fun1 is one function at growing widths — 7/8, 12/12, 19/15, 59/24, 63/44 — so we tie when narrow and lose as it widens, while our observed order is the HIGHER one (3.63 vs 2.02); 59 on a 2e4 bracket is what bisection needs, i.e. one halving per evaluation against their 2.3. With the safeguard removed entirely we still spend 46/57/61/68 against bisection 57/77/45/45 and Chandrupatla 24/44 — worse than bisection on two of them. |f|/|f'| is an absolute length and cannot march across decades; written into the paper as the stated limit. Also fixed a tracer bug that had best_of double-counting evaluations (2993 vs 1487)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""The largest single item of the wide-bracket gap: fun1's endgame (+61 evaluations).
|
||||
|
||||
If it has a structural cause, a derived fix may exist; if it is simply the order of
|
||||
convergence, the answer is "no" and the reason is worth stating. Reports, per fun1 problem:
|
||||
the bracket, the multiplicity-like behaviour of f near the root, the observed order of both
|
||||
methods, and the endgame split.
|
||||
|
||||
python -u diag_fun1_endgame.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from scipy.optimize._tstutils import _CHANDRUPATLA_TESTS_DICTS
|
||||
|
||||
from simroot.baselines import chandrupatla, chandrupatla_scipy
|
||||
from simroot.pure import pure_root
|
||||
from stage4_why import observed_order
|
||||
from sweep_full import ACC, MAXFEV, XTOL
|
||||
|
||||
|
||||
def ours(f, a, b, xtol, maxfev):
|
||||
return pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived3",
|
||||
guard="safe", prestep="slope", direction="dissimilar")
|
||||
|
||||
|
||||
def multiplicity_probe(f, root):
|
||||
"""How does |f| grow away from the root? |f(root+t)| ~ C t^m gives m from two points;
|
||||
m = 1 is a simple root, m >= 2 flattens the endgame for every interpolating method."""
|
||||
t1, t2 = 1e-5, 1e-4
|
||||
f1, f2 = abs(f(root + t1)), abs(f(root + t2))
|
||||
if f1 == 0.0 or f2 == 0.0:
|
||||
return float("nan")
|
||||
return math.log(f2 / f1) / math.log(t2 / t1)
|
||||
|
||||
|
||||
def main():
|
||||
print(f"{'problem':<9} {'bracket':>26} {'root':>10} {'m':>6} "
|
||||
f"{'ours n':>7} {'ord':>6} {'CH n':>6} {'ord':>6}")
|
||||
for d in _CHANDRUPATLA_TESTS_DICTS:
|
||||
pid = str(d["ID"])
|
||||
if not pid.startswith("fun1."):
|
||||
continue
|
||||
f = d["f"]
|
||||
a, b = (float(v) for v in d["bracket"])
|
||||
root = float(d["root"])
|
||||
m = multiplicity_probe(f, root)
|
||||
x_o, n_o, ok_o = ours(f, a, b, XTOL, MAXFEV)
|
||||
best = None
|
||||
for impl in (chandrupatla, chandrupatla_scipy):
|
||||
try:
|
||||
x_c, n_c, ok_c = impl(f, a, b, XTOL, MAXFEV)
|
||||
except Exception:
|
||||
continue
|
||||
if best is None or n_c < best[1]:
|
||||
best = (float(x_c), int(n_c), bool(ok_c))
|
||||
try:
|
||||
ord_o = observed_order(ours, f, a, b, root)
|
||||
except Exception:
|
||||
ord_o = float("nan")
|
||||
try:
|
||||
ord_c = observed_order(chandrupatla, f, a, b, root)
|
||||
except Exception:
|
||||
ord_c = float("nan")
|
||||
print(f"{pid:<9} [{a:10.4g}, {b:10.4g}] {root:10.5g} {m:6.2f} "
|
||||
f"{n_o:7d} {ord_o if isinstance(ord_o, float) else float('nan'):6.2f} "
|
||||
f"{best[1]:6d} {ord_c if isinstance(ord_c, float) else float('nan'):6.2f}")
|
||||
print(f" |f| at root+1e-5 = {abs(f(root + 1e-5)):.3e}, "
|
||||
f"root+1e-2 = {abs(f(root + 1e-2)):.3e}, "
|
||||
f"ours x={x_o:+.10g} ok={ok_o}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user