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>
143 lines
6.6 KiB
Python
143 lines
6.6 KiB
Python
"""Numbers the revised text needs beyond verify_article.py's existing checks, all under the
|
|
paper's single criterion (sweep_uniform.json, sweep_fourth_*.json, sweep_itp.json), plus the
|
|
two small fresh runs the re-scoring cannot supply. Run on Linux; stdout is kept as
|
|
results_numbers_uniform.txt and every number quoted from it is checked by verify_article.py.
|
|
|
|
python -u numbers_uniform.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from collections import defaultdict
|
|
|
|
from rescore_uniform import load_uniform
|
|
|
|
PROJ = "pure.ratio.derived3.project"
|
|
CREDIT = "pure.ratio.derived3.credit"
|
|
APRIME = "pure+extP+contra+flatanalogmempt+exp+half+close+sub.ratio.derived3.project"
|
|
|
|
|
|
def cost(v):
|
|
return v[0] if v[1] else 200
|
|
|
|
|
|
def sign_p(w, l):
|
|
k, n = min(w, l), w + l
|
|
return 1.0 if n == 0 else min(1.0, 2.0 * sum(math.comb(n, i) for i in range(k + 1)) / 2.0 ** n)
|
|
|
|
|
|
def rank(rows, s):
|
|
return [r["label"] for r in sorted(rows, key=lambda r: (r[s]["n"] - r[s]["solved"], r[s]["total"]))]
|
|
|
|
|
|
def family(pid):
|
|
"""APS: the function number (aps.NN.MM); CHA: funN; the unit of dependence."""
|
|
return ".".join(pid.split(".")[:2]) if pid.startswith("aps") else pid.split(".")[0]
|
|
|
|
|
|
def families(a, b, s):
|
|
"""Family-level comparison: per family the total of a against the total of b."""
|
|
ta, tb = defaultdict(int), defaultdict(int)
|
|
for p in a[s]["per"]:
|
|
ta[family(p)] += cost(a[s]["per"][p])
|
|
tb[family(p)] += cost(b[s]["per"][p])
|
|
w = sum(ta[k] < tb[k] for k in ta)
|
|
l = sum(ta[k] > tb[k] for k in ta)
|
|
return w, len(ta) - w - l, l, dict(ta), dict(tb)
|
|
|
|
|
|
def main():
|
|
full = load_uniform("sweep_full.json")
|
|
by = {r["label"]: r for r in full}
|
|
for s in ("APS", "CHA"):
|
|
rk = rank(full, s)
|
|
print(f"{s} places: " + ", ".join(
|
|
f"{lb} {rk.index(lb) + 1}" for lb in (
|
|
"chandrupatla", "pure.ratio.derived3.none", PROJ, "toms748", "brent", "dekker",
|
|
"itp_oracle", "ridders", CREDIT, "itp", "illinois", "bisection", "regula_falsi",
|
|
"pure.exp_abs.bracket.both", "pure.exp_abs.bracket.bracket",
|
|
"pure.exp_abs.bracket.credit")))
|
|
for lb in ("dekker", "illinois", "regula_falsi", "brent", "toms748",
|
|
"pure.ratio.derived3.none", "pure.exp_abs.bracket.both"):
|
|
r = by[lb][s]
|
|
print(f" {lb:<28} solved {r['solved']}/{r['n']} total {r['total']} over {r['over']}")
|
|
# Corollary 2: best over scales, step guard (Table 4's individual ranking)
|
|
best = {}
|
|
for r in full:
|
|
if r["spec"][0] == "pure" and r["spec"][3] == "step":
|
|
best[r["spec"][1]] = min(best.get(r["spec"][1], 10 ** 9),
|
|
r["APS"]["total"] + r["CHA"]["total"])
|
|
print("best over scales (step guard):", dict(sorted(best.items(), key=lambda kv: kv[1])))
|
|
|
|
# revision point 8: families as the unit
|
|
ap = {r["label"]: r for r in load_uniform("sweep_aprime.json")}[APRIME]
|
|
for name, a in (("base rule", by[PROJ]), ("A'", ap)):
|
|
for s in ("APS", "CHA"):
|
|
w, t, l, ta, tb = families(a, by["chandrupatla"], s)
|
|
print(f"{name} vs Chandrupatla by family, {s}: {w}/{t}/{l} of {w + t + l} families,"
|
|
f" p={sign_p(w, l):.2g}")
|
|
if name == "A'" and s == "CHA":
|
|
print(" per family A' / Chandrupatla:",
|
|
{k: (ta[k], tb[k]) for k in sorted(ta)})
|
|
for s in ("APS", "CHA"):
|
|
ps = list(a[s]["per"])
|
|
w = sum(cost(a[s]["per"][p]) < cost(by["chandrupatla"][s]["per"][p]) for p in ps)
|
|
l = sum(cost(a[s]["per"][p]) > cost(by["chandrupatla"][s]["per"][p]) for p in ps)
|
|
print(f"{name} vs Chandrupatla by problem, {s}: {w}/{len(ps) - w - l}/{l}"
|
|
f" p={sign_p(w, l):.2g}")
|
|
# Table 6: the 60 paired (function, safeguard) cells of the far-end reading
|
|
order = load_uniform("sweep_order.json")
|
|
cells = {}
|
|
for r in order:
|
|
sim, sc, gu = r["spec"][1], r["spec"][2], r["spec"][3]
|
|
ex = r["spec"][8] if len(r["spec"]) > 8 else "none"
|
|
if sc == "far":
|
|
cells[(sim, gu, ex)] = r["APS"]["total"] + r["CHA"]["total"]
|
|
pairs = [(k[0], k[1]) for k in cells if k[2] == "none" and (k[0], k[1], "order") in cells]
|
|
cheaper = sum(cells[(s_, g, "order")] < cells[(s_, g, "none")] for s_, g in pairs)
|
|
print(f"far-end reading, measured order cheaper in {cheaper} of {len(pairs)} cells")
|
|
fp = [r for r in order if r["spec"][1] == "rational" and r["spec"][2] == "far"
|
|
and r["spec"][3] == "none"]
|
|
for r in fp:
|
|
print(f" false position reading {r['spec'][8]}: APS solved {r['APS']['solved']} "
|
|
f"total {r['APS']['total']}")
|
|
# negative item 9: the capped scale
|
|
cap = {r["label"]: r for r in load_uniform("sweep_cap.json")}
|
|
dire = {r["label"]: r for r in load_uniform("sweep_direction.json")}
|
|
for lb in ("pure+dissim+slope.ratio.derived3_cap.project",
|
|
"pure+dissim+slope.ratio.derived3_cap.safe"):
|
|
r = cap[lb]
|
|
print(f"cap {lb}: {r['APS']['total']} / {r['CHA']['total']} solved "
|
|
f"{r['APS']['solved'] + r['CHA']['solved']}")
|
|
for lb in ("pure+dissim+slope.ratio.derived3.project", "pure+dissim+slope.ratio.derived3.safe"):
|
|
r = dire[lb]
|
|
print(f"control {lb}: {r['APS']['total']} / {r['CHA']['total']}")
|
|
# Table 1a: which canonical problems the multiplier moves
|
|
from simroot.pure import pure_root
|
|
from stage12_validation import load, per_problem
|
|
probs = [p for p in load() if p[0] == "APS"]
|
|
runs = {}
|
|
for fac in (1.25, 1.5, 2.0):
|
|
runs[fac] = per_problem(lambda f, a, b, xt, mx, _f=fac: pure_root(
|
|
f, a, b, xt, mx, similarity="ratio", scale="derived3", guard="project",
|
|
budget_factor=_f), probs, 200, criterion="sign")
|
|
moved = {p: (runs[1.25][p][0], runs[1.5][p][0], runs[2.0][p][0]) for p in runs[2.0]
|
|
if len({runs[1.25][p][0], runs[1.5][p][0], runs[2.0][p][0]}) > 1}
|
|
print("canonical problems moved by the multiplier (1.25, 1.5, 2):", moved)
|
|
# negative item 5: the phase detector (scale derived3_m) on the full benchmark
|
|
allp = load()
|
|
for sc in ("derived3", "derived3_m"):
|
|
pp = per_problem(lambda f, a, b, xt, mx, _s=sc: pure_root(
|
|
f, a, b, xt, mx, similarity="ratio", scale=_s, guard="project"), allp, 200,
|
|
criterion="sign")
|
|
t = {"APS": 0, "CHA": 0}
|
|
for s_, pid, *_ in allp:
|
|
t[s_] += pp[pid][0]
|
|
print(f"phase detector item: scale {sc}: APS {t['APS']} CHA {t['CHA']} "
|
|
f"both {t['APS'] + t['CHA']}")
|
|
print("numbers uniform done")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|