(2) The proposed method is again the scheduled projection (2806/3220/6026), its budget multiplier DECLARED as the one free constant: the canonical total is the same for every multiplier 1.25-4, the wide-bracket one is not. The earned projection is the constant-free variant (3568/3020/6588). What the old tables hid: problem by problem the proposed rule beats Chandrupatla on the canonical set 87/24/42, exact sign test p = 9e-5, while trailing him by 0.7% in total; on the wide-bracket set he is genuinely stronger (26 to 9, p = 0.006). Gap decomposition recomputed with the library: 244 (was 262), 160 of it on the flat families (two thirds), fun1 58 (a quarter, not a third as the abstract said). Also corrected on the way: the 'subsumed by Chandrupatla' pin claimed he is better on the worst single problem - true only with the looser tolerance (84 against the credit rule's 83 once fixed); §8.3 still called zero slack degenerate, which Table 1a refutes; §5.2's Brent figure is our pure-Python implementation and now says so. verify_article.py 286/286, 802 tests pass twice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
108 lines
5.1 KiB
Python
108 lines
5.1 KiB
Python
"""Does the canonical Alefeld-Potra-Shi set carry the same scoring artefact as fun7?
|
|
|
|
On the wide-bracket set five problems are scored unsolved for every method although every
|
|
method returns a point where f(x) = 0 exactly (diag_rescore_cha.py). Every method also
|
|
reports 153 of 154 on the canonical set, so exactly one problem there is unsolved by
|
|
everyone — this asks whether that is the same artefact, a different one, or a real failure.
|
|
|
|
Both criteria are applied to the SAME runs:
|
|
strict : |x - declared_root| <= ACC (the harness rule)
|
|
honest : strict OR f(x) == 0 (a root is a root)
|
|
and every problem that the two criteria disagree about is printed with its diagnosis.
|
|
|
|
python -u diag_rescore_aps.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
from simroot.baselines import BRENT_BASELINE, CHANDRUPATLA_BASELINE
|
|
from simroot.baselines import (best_of, bisection, brent, brent_scipy, chandrupatla,
|
|
chandrupatla_scipy, itp, toms748)
|
|
from simroot.pure import pure_root
|
|
from sweep_full import ACC, MAXFEV, XTOL, load_problems
|
|
|
|
METHODS = {
|
|
"ours (shape)": lambda f, a, b: pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio",
|
|
scale="derived3", guard="safe",
|
|
prestep="slope", points="shape"),
|
|
"ours (dissimilar)": lambda f, a, b: pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio",
|
|
scale="derived3", guard="safe",
|
|
prestep="slope", direction="dissimilar"),
|
|
"ours (published proj)": lambda f, a, b: pure_root(f, a, b, XTOL, MAXFEV,
|
|
similarity="ratio", scale="derived3",
|
|
guard="project"),
|
|
"chandrupatla": lambda f, a, b: CHANDRUPATLA_BASELINE(f, a, b, XTOL,
|
|
MAXFEV),
|
|
"toms748": lambda f, a, b: toms748(f, a, b, XTOL, MAXFEV),
|
|
"brent": lambda f, a, b: BRENT_BASELINE(f, a, b, XTOL, MAXFEV),
|
|
"itp": lambda f, a, b: itp(f, a, b, XTOL, MAXFEV),
|
|
"bisection": lambda f, a, b: bisection(f, a, b, XTOL, MAXFEV),
|
|
}
|
|
TINY = 2.2250738585072014e-308 # smallest normal double, for reporting only
|
|
|
|
|
|
def main():
|
|
probs = [p for p in load_problems() if p[0] == "APS"]
|
|
print(f"APS problems: {len(probs)}")
|
|
print(f"\n{'method':<22} {'strict solved/total':>22} {'honest solved/total':>22} "
|
|
f"{'disagreements':>14}")
|
|
disagree = {}
|
|
never_strict = {pid: 0 for _s, pid, *_ in probs}
|
|
for name, run in METHODS.items():
|
|
s_solved = s_total = h_solved = h_total = 0
|
|
diffs = []
|
|
for _s, pid, f, a, b, root in probs:
|
|
try:
|
|
x, n, conv = run(f, a, b)
|
|
except Exception:
|
|
x, n, conv = float("nan"), MAXFEV, False
|
|
x = float(x)
|
|
n = int(n)
|
|
fin = conv and math.isfinite(x)
|
|
strict = bool(fin and abs(x - root) <= ACC)
|
|
honest = bool(strict or (fin and f(x) == 0.0))
|
|
s_total += n if strict else MAXFEV
|
|
h_total += n if honest else MAXFEV
|
|
s_solved += int(strict)
|
|
h_solved += int(honest)
|
|
never_strict[pid] += int(strict)
|
|
if honest != strict:
|
|
diffs.append((pid, x, root, f(x), n))
|
|
disagree[name] = diffs
|
|
print(f"{name:<22} {s_solved:8d}/154 {s_total:8d} {h_solved:8d}/154 {h_total:8d} "
|
|
f"{len(diffs):14d}")
|
|
|
|
print("\nproblems where the two criteria disagree (a root found, scored a failure):")
|
|
any_diff = False
|
|
for name, diffs in disagree.items():
|
|
for pid, x, root, fx, n in diffs:
|
|
any_diff = True
|
|
print(f" {name:<22} {pid:<12} x={x:+.10g} root={root:+.10g} "
|
|
f"f(x)={fx:+.3e} after {n} evals")
|
|
if not any_diff:
|
|
print(" none — the canonical set does NOT carry the fun7 artefact")
|
|
|
|
print("\nproblems no method solved under the strict rule:")
|
|
for pid, cnt in sorted(never_strict.items(), key=lambda kv: kv[1])[:6]:
|
|
print(f" {pid:<12} solved by {cnt} of {len(METHODS)} methods")
|
|
|
|
# inspect the hardest one in the same way fun7 was inspected
|
|
worst = min(never_strict, key=lambda k: never_strict[k])
|
|
for _s, pid, f, a, b, root in probs:
|
|
if pid != worst:
|
|
continue
|
|
print(f"\ndiagnosis of {pid}: bracket [{a:.6g}, {b:.6g}] declared root {root:.10g}")
|
|
print(f" f(a)={f(a):+.6e} f(b)={f(b):+.6e} f(root)={f(root):+.6e}")
|
|
for t in (1e-12, 1e-9, 1e-6, 1e-3):
|
|
print(f" f(root+{t:g}) = {f(root + t):+.6e} f(root-{t:g}) = {f(root - t):+.6e}")
|
|
x, n, conv = METHODS["ours (dissimilar)"](f, a, b)
|
|
print(f" ours returns x={float(x):+.12g} after {n} evals, f(x)={f(float(x)):+.3e}, "
|
|
f"|x-root|={abs(float(x) - root):.3g}")
|
|
print(f" |f(x)| below smallest normal? {abs(f(float(x))) < TINY}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|