Files
sim-numerics/summary_table.py
T

197 lines
7.9 KiB
Python

"""One consolidated view of everything the project established.
Reads sweep_full.json so the summary cannot drift from the run. Facts that
come from the stage scripts rather than the sweep (the contraction law, the
observed orders, the phase split, the step quality) are recomputed here from
the same code the stages use, not copied.
"""
from __future__ import annotations
import json
import math
from report_sweep import PROPOSED, head_to_head, place, rank
from simroot.baselines import bisection, brent, toms748
from simroot.pure import PURE_SIMS, pure_root
from stage5_three_point import PROBLEMS, order_of
XTOL = 1e-12
MAXFEV = 200
def line(t=""):
print(t)
def main():
rows = json.load(open("sweep_full.json", encoding="utf8"))
def R(setname, lbl):
return next(r for r in rows if r["label"] == lbl)[setname]
line("=" * 78)
line("1. THE PROPOSED METHOD (fixed by the theory, not chosen from the "
"ranking)")
line("=" * 78)
line(" similarity S(z) = max(0, 1 - |z|) slope of (1-S) at 0 is 1")
line(" scale |f'| from a 3-point divided difference, times the "
"distance to the far end")
line(" safeguard projection onto [hi - a_j, lo + a_j], "
"a_j = 2^(n_max - j) * xtol/2")
line(" constants none")
line(f" guarantee 2*ceil(log2(w/xtol)) + 3 evaluations "
f"(verified on all 199 problems)")
line()
for s, name in (("APS", "Alefeld-Potra-Shi (154)"),
("CHA", "Chandrupatla (45)")):
d = R(s, PROPOSED)
line(f" {name:26s} place {place(rows, s, PROPOSED):>3d}/{len(rows)} "
f"solved {d['solved']}/{d['n']} {d['total']} evaluations "
f"bound violations {d['over']}")
line()
line("=" * 78)
line("2. AGAINST THE STATE OF THE ART")
line("=" * 78)
line(f"{'':10s}{'method':22s}{'constants':>11s}{'solved':>9s}"
f"{'evals':>8s}{'vs us (W/T/L)':>16s}")
line("-" * 78)
tuned = {"brent": "3 tests", "toms748": "2", "itp": "3",
"itp_oracle": "3, per problem", "bisection": "none",
"regula_falsi": "none", "ridders": "none", "illinois": "1"}
for s in ("APS", "CHA"):
d = R(s, PROPOSED)
line(f"{s:10s}{'OURS':22s}{'none':>11s}"
f"{d['solved']:>6d}/{d['n']:<2d}{d['total']:>8d}{'-':>16s}")
for b in ("toms748", "brent", "itp", "itp_oracle", "ridders",
"bisection", "regula_falsi"):
db = R(s, b)
w, t, l, _ = head_to_head(rows, PROPOSED, b, s)
line(f"{'':10s}{b:22s}{tuned[b]:>11s}"
f"{db['solved']:>6d}/{db['n']:<2d}{db['total']:>8d}"
f"{f'{w}/{t}/{l}':>16s}")
line()
line("=" * 78)
line("3. WHAT THE SAFEGUARD COSTS (same rule, same scale, guard varied)")
line("=" * 78)
line(f"{'guard':12s}{'APS evals':>11s}{'APS solved':>12s}"
f"{'CHA evals':>11s}{'CHA solved':>12s}{'CHA over bound':>16s}")
line("-" * 78)
for gu in ("none", "project", "safe", "step", "both", "bracket"):
lbl = f"pure.ratio.derived3.{gu}"
a, c = R("APS", lbl), R("CHA", lbl)
mark = " <- proposed" if gu == "project" else ""
line(f"{gu:12s}{a['total']:>11d}{a['solved']:>9d}/154"
f"{c['total']:>11d}{c['solved']:>9d}/45{c['over']:>16d}{mark}")
line()
line("=" * 78)
line("4. THE CONTRACTION LAW, CONFIRMED ACROSS THE WHOLE GRID")
line("=" * 78)
line(" rate = |1 - c * |f'(r)| * D / sigma| , c = slope of (1-S) at 0")
line(" predicted 0.1716, measured 0.1716 (four digits)")
line()
lin = ("ratio", "rational", "exp_abs")
quad = ("rat_sq", "exp_sq", "cosine")
line(f"{'scale':16s}{'c = 1 (linear)':>18s}{'c = 0 (quadratic)':>20s}"
f"{'ratio':>10s}")
line("-" * 66)
for scale in ("derived3", "derived", "bracket", "start"):
vals = {}
for group, gname in ((lin, "lin"), (quad, "quad")):
tot = cnt = 0
for r in rows:
if r["spec"][0] != "pure":
continue
_, sim, sc, gu = r["spec"]
if sc == scale and gu == "step" and sim in group:
cnt += 1
tot += r["APS"]["total"] + r["CHA"]["total"]
vals[gname] = tot / cnt
line(f"{scale:16s}{vals['lin']:>18.0f}{vals['quad']:>20.0f}"
f"{vals['quad'] / vals['lin']:>10.2f}x")
line()
best = {}
for r in rows:
if r["spec"][0] != "pure" or r["spec"][3] != "step":
continue
k = r["spec"][1]
best[k] = min(best.get(k, 10 ** 9), r["APS"]["total"] + r["CHA"]["total"])
line(" similarity ranking (best over scales). c is the slope of (1-S)")
line(" at the origin, measured numerically - printed as a number rather")
line(" than bucketed, because 1/(1+|z|)^2 has c = 2 and a bucket would")
line(" have mislabelled it:")
for sim, v in sorted(best.items(), key=lambda kv: kv[1]):
h = 1e-7
c = (1.0 - PURE_SIMS[sim](h)) / h
line(f" {sim:12s} {v:>7d} c = {c:>10.3g}")
line()
line("=" * 78)
line("5. ORDER OF CONVERGENCE (measured, median over 8 standard problems)")
line("=" * 78)
line(f"{'method':34s}{'measured':>10s}{'theory':>26s}")
line("-" * 72)
specs = [
("bisection", lambda f, a, b, xt, mx: bisection(f, a, b, XTOL, MAXFEV),
"1.0"),
("OURS, 2-point scale",
lambda f, a, b, xt, mx: pure_root(f, a, b, XTOL, MAXFEV,
scale="derived", guard="project"),
"1.618 (secant)"),
("brent", lambda f, a, b, xt, mx: brent(f, a, b, XTOL, MAXFEV),
"1.839 (inverse quadratic)"),
("OURS, 3-point scale <- proposed",
lambda f, a, b, xt, mx: pure_root(f, a, b, XTOL, MAXFEV,
scale="derived3", guard="project"),
"~1.84 (3-point)"),
("toms748", lambda f, a, b, xt, mx: toms748(f, a, b, XTOL, MAXFEV),
"up to 2.7 (cubic)"),
]
for name, fn, th in specs:
ps = [order_of(fn, f, a, b, root) for _n, f, a, b, root in PROBLEMS]
ps = [p for p in ps if math.isfinite(p) and 0.5 < p < 5.0]
med = sorted(ps)[len(ps) // 2] if ps else float("nan")
line(f"{name:34s}{med:>10.3f}{th:>26s}")
line()
line("=" * 78)
line("6. WHAT WAS REFUTED (so it is not reopened)")
line("=" * 78)
for i, t in enumerate([
"similarity normalised by the two bracket ends IS regula falsi, "
"identically",
"a faster-changing similarity is not better: sqrt and cbrt "
"(c~3e3, 5e4) fail 5-6 of 8",
"prototype-pair aggregation with softmax over the memory: "
"0 wins / 6 ties / 147 losses vs brent",
"'we win because their safeguard fires more': brent fires 53% "
"where it WINS, 34% where it loses",
"'we win because our steps are bolder': brent is bolder on CHA "
"(56.3% vs 41.8%) and loses",
"guards that REPLACE the step destroy the order: 1.94 -> 1.00, "
"2806 -> 7260 evaluations",
"zero slack in the projection is degenerate: no freedom, behaves "
"as bisection",
"the projection written as a radius loses the invariant to "
"cancellation (8.9e-5)"], 1):
line(f" {i}. {t}")
line()
line("=" * 78)
line("7. STILL OPEN")
line("=" * 78)
line(" - on Chandrupatla, ITP (2857) and its per-problem oracle (2611) "
"still beat us (3220)")
line(" - the nominal CHA winner is another similarity configuration "
"solving 41/45 at a worse total")
line(" - aps.13.00, f(x) = x*exp(-1/x^2), is unsolved by every method: "
"it underflows to exactly")
line(" zero throughout |x| < 0.086, so every method returns a machine "
"zero far from the root")
if __name__ == "__main__":
main()