"""Why the model-order gap remains: the same information, two models. Hypothesis (stated before the run, 2026-09-21). Our step x' = x + (1-S)(far - x) is a CONVEX combination of two points, x' = S.x + (1-S).far, with weights in [0,1]; a third point enters only through the scale sigma, i.e. through a slope. Chandrupatla's step is inverse quadratic interpolation (IQI): x' = sum w_i x_i with Lagrange weights of the values at 0, and whenever the triple's values bracket zero ONE weight is necessarily NEGATIVE - the step pushes away from the stale point. A [0,1] similarity cannot produce a negative weight, so a similarity-weighted average of points is capped at a first-order inverse model: Proposition 4 of the paper, extended from two points to three. The test uses NO new method: replay our own trajectory and, at every state, place IQI on the SAME evaluations we already paid for. If the gap is the model, IQI from our points must contract the error more than our step did. Pre-declared predictions Q1 in every state whose triple brackets zero, exactly one Lagrange weight is < 0 (a sign identity; measured as a check of the argument, must be 100%) Q2 on the problems where we lose to Chandrupatla, IQI from the same points gives more halvings of the error per step than our raw step, on states where IQI lands inside the proven bracket Q3 the advantage sits in the APPROACH class (error at least half the current bracket - the one constant of the method, the bisection 1/2) and shrinks in the endgame FALSIFIER: if IQI on the same points does NOT contract more, the gap is not how the information is used, and the explanation must be sought elsewhere - e.g. WHICH points are kept (Chandrupatla keeps a bracketing triple, we keep the most recent), which is why IQI is placed twice: on our recent triple and on (x, A, B), the bracketing one. python -u diag_model_order.py """ from __future__ import annotations import math from scipy.optimize._tstutils import _CHANDRUPATLA_TESTS_DICTS from simroot.baselines import CHANDRUPATLA_BASELINE from simroot.baselines import chandrupatla, chandrupatla_scipy from simroot.pure import pure_root XTOL, MAXFEV, ACC = 1e-12, 200, 1e-6 OURS = dict(similarity="ratio", scale="derived3", guard="safe", prestep="slope", direction="dissimilar") # reading (3), CHA 2683 per set def iqi(p0, p1, p2): """Inverse quadratic interpolation at f = 0, plus its Lagrange weights.""" (x0, f0), (x1, f1), (x2, f2) = p0, p1, p2 if len({f0, f1, f2}) < 3 or len({x0, x1, x2}) < 3: return None, None d0 = (f0 - f1) * (f0 - f2) d1 = (f1 - f0) * (f1 - f2) d2 = (f2 - f0) * (f2 - f1) # distinct values can still give a product that underflows to 0 (first run of # 2026-09-21 crashed on exactly that); the model is then undefined, not an error if d0 == 0.0 or d1 == 0.0 or d2 == 0.0: return None, None w0 = f1 * f2 / d0 w1 = f0 * f2 / d1 w2 = f0 * f1 / d2 x = w0 * x0 + w1 * x1 + w2 * x2 if not all(math.isfinite(v) for v in (x, w0, w1, w2)): return None, None return x, (w0, w1, w2) def halvings(e_before, landing, r): """-log2 of the error contraction; distances below one ulp of r are not measurable, so the floor is the ulp, not a chosen number.""" after = max(abs(landing - r), math.ulp(r) if r != 0.0 else 5e-324) return math.log2(e_before / after) def ch_cost(f, a, b, r): best = None for impl in (CHANDRUPATLA_BASELINE,): # the library alone (2026-09-21) try: x, n, c = impl(f, a, b, XTOL, MAXFEV) except Exception: continue if c and math.isfinite(float(x)) and abs(float(x) - r) <= ACC: best = int(n) if best is None else min(best, int(n)) return best MODELS = ("ours", "iqiR", "iqiB") def bracket_step(f, lo, flo, hi, fhi, landing): """One evaluation at `landing`, the standard bracket update, and the new width. Evaluated for the diagnosis only - nothing is charged - so every model gets exactly ONE evaluation from the same state, which is the comparison the gap is stated in.""" fl = f(landing) if fl == 0.0: return 0.0 if (fl > 0.0) == (flo > 0.0): lo = landing else: hi = landing return abs(hi - lo) def main(): # per model, per phase: [sum bracket-halvings, sum error-halvings, count] agg = {(m, ph): [0.0, 0.0, 0] for m in MODELS for ph in ("app", "end")} paired = {"iqiR": [0.0, 0], "iqiB": [0.0, 0]} # sum(h_model - h_ours) on common states neg_ok = neg_all = 0 valid = {m: 0 for m in MODELS} states_all = 0 lose = [] results = {} print(f"{'problem':<8} {'ours':>5} {'CH':>4} {'states':>6} " f"bracket halvings per evaluation: {'ours':>6} {'IQI-rec':>8} {'IQI-brk':>8}") for d in _CHANDRUPATLA_TESTS_DICTS: pid = str(d["ID"]) f = d["f"] a, b = (float(v) for v in d["bracket"]) r = float(d["root"]) st = {"trace": []} x, n, conv = pure_root(f, a, b, XTOL, MAXFEV, stats=st, **OURS) if not (conv and abs(float(x) - r) <= ACC): continue ch = ch_cost(f, a, b, r) if ch is None or n <= ch: continue # only the problems where we lose lose.append(pid) per = {m: [] for m in MODELS} cnt = 0 for s in st["trace"]: if s["xp2"] is None: continue e = abs(s["x"] - r) if e == 0.0: continue A, FA, B, FB = s["A"], s["FA"], s["B"], s["FB"] lo, flo, hi, fhi = (A, FA, B, FB) if A < B else (B, FB, A, FA) W = hi - lo if W <= 0.0: continue cnt += 1 phase = "app" if e >= 0.5 * W else "end" recent = ((s["x"], s["fx"]), (s["xp"], s["fp"]), (s["xp2"], s["fp2"])) fs = [p[1] for p in recent] if min(fs) < 0.0 < max(fs): _xq, wq = iqi(*recent) if wq is not None: neg_all += 1 neg_ok += sum(w < 0.0 for w in wq) == 1 # Chandrupatla's own triple: both proven ends plus the latest point that is # neither of them (x itself is always an end by the time a state is recorded) third = None for cx, cf in ((s["xp"], s["fp"]), (s["xp2"], s["fp2"])): if cx is not None and cx != A and cx != B: third = (cx, cf) break land = {"ours": s["x"] + s["raw"], "iqiR": iqi(*recent)[0], "iqiB": iqi((A, FA), (B, FB), third)[0] if third else None} hb = {} for m in MODELS: L = land[m] if L is None or not (lo < L < hi): continue Wn = bracket_step(f, lo, flo, hi, fhi, L) # an exact hit makes the width 0; the floor is one ulp of the root, the # same unmeasurable-distance floor `halvings` uses - not a chosen cap h_b = math.log2(W / max(Wn, math.ulp(r) if r != 0.0 else 5e-324)) h_e = halvings(e, L, r) hb[m] = h_b valid[m] += 1 per[m].append(h_b) cell = agg[(m, phase)] cell[0] += h_b cell[1] += h_e cell[2] += 1 for m in ("iqiR", "iqiB"): if m in hb and "ours" in hb: paired[m][0] += hb[m] - hb["ours"] paired[m][1] += 1 states_all += cnt mean = lambda v: (sum(v) / len(v)) if v else float("nan") # noqa: E731 results[pid] = (n, ch, mean(per["ours"]), mean(per["iqiR"]), mean(per["iqiB"])) print(f"{pid:<8} {n:5d} {ch:4d} {cnt:6d} {'':33} " f"{mean(per['ours']):6.2f} {mean(per['iqiR']):8.2f} {mean(per['iqiB']):8.2f}") print(f"\nproblems where we lose to Chandrupatla: {len(lose)}, states {states_all}") print(f"\nQ1 triples bracketing zero with exactly ONE negative Lagrange weight: " f"{neg_ok}/{neg_all}" + (" -> identity holds" if neg_ok == neg_all else " -> IDENTITY FAILS")) print(" model defined and landing strictly inside the proven bracket: " + ", ".join(f"{m} {100.0 * valid[m] / max(states_all, 1):.0f}%" for m in MODELS)) print("\nQ2/Q3 mean halvings per ONE evaluation from the same state " "(bracket | error), valid states only") for ph, name in (("app", "approach (error >= 1/2 bracket)"), ("end", "endgame")): cells = [] for m in MODELS: sb, se, c = agg[(m, ph)] cells.append(f"{m} {sb / c if c else float('nan'):5.2f} | " f"{se / c if c else float('nan'):5.2f} (n={c})") print(f" {name:<32} " + " ".join(cells)) print("\nPAIRED on states where both are valid: mean (IQI - ours) bracket halvings") for m, (s_, c) in paired.items(): print(f" {m}: {s_ / c if c else float('nan'):+.2f} per evaluation (n={c})") # returned so verify_article.py can check the paper's numbers against a fresh run # instead of against a transcription of this printout return {"per_problem": results, "neg_ok": neg_ok, "neg_all": neg_all, "lose": lose} if __name__ == "__main__": main()