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>
87 lines
3.5 KiB
Python
87 lines
3.5 KiB
Python
"""Two checks on diag_model_order.py before its result may be stated.
|
|
|
|
C1 WHAT Chandrupatla does on the problems where we lose, by family: the share of his
|
|
steps that are bisections, from the traced mirror whose evaluation count is asserted
|
|
equal to the original's. If the flat families are won by bisecting, the gap there
|
|
is not a better model on his side.
|
|
C2 the 5 states where "exactly one negative Lagrange weight" failed: print them. The
|
|
sign argument is exact in real arithmetic, so each exception must be a
|
|
floating-point degeneracy (a weight that underflowed to 0, or f values so close
|
|
that a difference cancelled) - or the argument is wrong and must be withdrawn.
|
|
|
|
python -u diag_model_order_checks.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from collections import defaultdict
|
|
|
|
from scipy.optimize._tstutils import _CHANDRUPATLA_TESTS_DICTS
|
|
|
|
from diag_model_order import ACC, MAXFEV, OURS, XTOL, ch_cost, iqi, solved
|
|
from explain_chandrupatla import chandrupatla_traced
|
|
from simroot.baselines import chandrupatla
|
|
from simroot.pure import pure_root
|
|
|
|
|
|
def main():
|
|
fam = defaultdict(lambda: [0, 0, 0, 0, 0]) # bisect, iqi, ours n, ch n, problems
|
|
exceptions = []
|
|
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
|
|
_xc, nc, okc, tr = chandrupatla_traced(f, a, b, XTOL, MAXFEV)
|
|
_xo, no, _oko = chandrupatla(f, a, b, XTOL, MAXFEV)
|
|
assert nc == no, f"mirror drifted on {pid}: {nc} vs {no}"
|
|
k = pid.split(".")[0]
|
|
cell = fam[k]
|
|
cell[0] += tr["bisect"]
|
|
cell[1] += tr["iqi"]
|
|
cell[2] += n
|
|
cell[3] += ch
|
|
cell[4] += 1
|
|
for s in st["trace"]:
|
|
if s["xp2"] is None:
|
|
continue
|
|
pts = ((s["x"], s["fx"]), (s["xp"], s["fp"]), (s["xp2"], s["fp2"]))
|
|
fs = [p[1] for p in pts]
|
|
if not (min(fs) < 0.0 < max(fs)):
|
|
continue
|
|
_xq, w = iqi(*pts)
|
|
if w is not None and sum(v < 0.0 for v in w) != 1:
|
|
exceptions.append((pid, fs, w))
|
|
|
|
print("C1 Chandrupatla on the problems where we lose, by family")
|
|
print(f" {'family':<6} {'probs':>5} {'ours':>6} {'CH':>6} {'gap':>5} "
|
|
f"{'CH bisect share':>16}")
|
|
tot_gap = 0
|
|
for k in sorted(fam):
|
|
bi, iq, on, cn, p = fam[k]
|
|
tot_gap += on - cn
|
|
share = 100.0 * bi / max(bi + iq, 1)
|
|
print(f" {k:<6} {p:5d} {on:6d} {cn:6d} {on - cn:5d} {share:15.0f}%")
|
|
print(f" total gap on the losing problems: {tot_gap}")
|
|
|
|
print(f"\nC2 the {len(exceptions)} states breaking 'exactly one negative weight'")
|
|
for pid, fs, w in exceptions:
|
|
tiny = min(abs(v) for v in fs)
|
|
print(f" {pid:<8} f = [{', '.join(f'{v:.3e}' for v in fs)}] "
|
|
f"w = [{', '.join(f'{v:.3e}' for v in w)}] "
|
|
f"zero weights: {sum(v == 0.0 for v in w)} min|f| {tiny:.1e}")
|
|
# for verify_article.py: {family: (bisect, iqi, ours n, ch n, problems)} and the
|
|
# number of exceptions, each of which must be a weight that underflowed to zero
|
|
return {"fam": dict(fam), "exceptions": exceptions}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|