Files
sim-numerics/diag_model_order.py
vvsandClaude Opus 5 862feaff86 Revision 1, step 1: one scoring criterion, the correct order, and the internal inconsistencies.
Point 1. The base step's order is Muller's 1.839, not 2: the derivative of the parabola through
the last three points errs by f'''/6 (x_n - x_{n-1})(x_n - x_{n-2}) = O(e_{n-1} e_{n-2}).
order_high_precision.py (3000 digits, to 1e-2900): 1.840 on cos x - x, e^x - 2, x^3 - x - 2,
sin x - 1/2; 2.000 only on x^2 - 2; two-point 1.618. The double-precision medians (2.000, 1.94)
are removed from the text.

Point 3. Every protocol number is re-scored under the criterion of section 9 - a sign change
within 1e-6 or f(x) == 0. rescore_uniform.py re-runs all 2779 distinct configurations of the 25
protocol sweeps on APS and CHA (the runs did not keep x) -> sweep_uniform.json, same row format;
it reproduces the APS/CHA lines of Table 10 exactly (built-in check). verify_article.py,
audit_similarity_places.py and the gap diagnostics read the re-scored data; the multiplier and
endowment measurements score by the same criterion. Table 7 (two criteria side by side) is gone;
7.3 now explains why the criterion is a sign change. Consequences stated in the text: the base
rule 2634 / 2357 against Chandrupatla 2595 / 1505 (1.5% behind on APS, no longer "level"); A'
2259 / 1074 (12.9% and 28.6% below Chandrupatla); the defect reading 2351 is second to the
shape reading 2337, not the record; the remembered analogy is level with no regime (2633 vs
2634) under this criterion; Table 9a's range is 19% to 425%.

Point 8. report_sweep.head_to_head counts every problem, failures charged (it counted only the
problems both methods solved, which is why Table 8 rows summed to 153 and 40). Family-level
comparisons added (A' vs Chandrupatla 8/1/6 of 15 and 7/0/2 of 9 families, not significant), and
an independence paragraph in section 9.

Point 11. sweep_itp.py: ITP (recommended constants and per-problem oracle) on all six corpora ->
Table 10; behind A' on every corpus, 0 bound violations.

Points 7, 9, 10 and the internals: the 2x bound is ours, not the rivals' promise; the law
predicts the group order only; "outside the proven bracket" explained (narrowest bracket of all
observed signs); 7.4's fun1 paragraph corrected (five costs under safe; the unguarded numbers
belong to fun1.4, fun1.5 and to fun3.1, fun5.1 separately); Table 1's last cell; the corpus-4
composition and odd multiplicities stated, also in the abstract.

build_tex.py: pdflatex output decoded with errors="replace" (a UTF-8 character cut by TeX's log
wrap crashed the build). Table 10 column widths rebalanced.

Checks: verify_article on the server 500 OK / 0 BAD (467 existing with the new values, 33 new);
regression x2 on the server 1232 passed, 0 failed; PDF 28 pages, 0 errors, 0 undefined, 0 overfull.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 07:01:36 +01:00

215 lines
9.4 KiB
Python

"""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
# success = the paper's single criterion since 2026-09-22 (revision point 3)
from corpus_roots_jl import solved # noqa: E402
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 solved(f, float(x)):
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 solved(f, float(x))):
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()