"""Why the proposed rule loses on fun9 (exp(x) - 2 - 0.01/x^2 + 2e-6/x^3, brackets from [2e-4, 1] to [2e-4, 81]) - and whether the cause is a distinguishing sign. On fun9.4 the two negative powers nearly cancel at the left end: f(2e-4) = -1 against 5e11 at the right end, so the rule reads the root as near the left end, while f dives to -3.7e4 before it turns up to the root at 0.703. 17 model steps in a row DOUBLE |f|: the local slope has the sign opposite to the one the bracket demands (f must rise from its negative end to its positive end). The sign considered: the local secant of the last two points, (fx - fp)/(x - xp), against the bracket's, (FB - FA)/(B - A). Opposite signs = the local picture contradicts the bracket. Per state (trace hook, proposed rule, no regime) and per problem, per group. Nothing in the method changes. python -u diag_fun9_slope_sign.py """ from __future__ import annotations from collections import defaultdict from simroot.pure import pure_root from sweep_full import MAXFEV, XTOL, load_problems FLAT = ("fun3", "fun4", "fun5", "fun6") def main(): per = defaultdict(lambda: [0, 0, 0, 0]) # problems, with any contradiction, states, contradicting for s, pid, f, a, b, _root in load_problems(): st = {"trace": []} pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3", guard="project", stats=st) fam = pid.split(".")[0] g = "APS" if s == "APS" else ("CHA-flat" if fam in FLAT else f"CHA-{fam}") bad = 0 for t in st["trace"]: if t["x"] == t["xp"]: continue loc = (t["fx"] - t["fp"]) / (t["x"] - t["xp"]) brk = (t["FB"] - t["FA"]) / (t["B"] - t["A"]) per[g][2] += 1 if loc != 0.0 and (loc > 0.0) != (brk > 0.0): bad += 1 per[g][0] += 1 per[g][1] += bad > 0 per[g][3] += bad print(f"{'group':<10} {'problems':>8} {'any contradiction':>18} {'states':>7} {'contradicting':>14}") for g in sorted(per): n, anyc, sts, c = per[g] print(f"{g:<10} {n:8d} {anyc:18d} {sts:7d} {c:14d}") print("diag done") if __name__ == "__main__": main()