"""Part 3 of stage12_validation.py alone: is the projection's doubling load-bearing? The canonical text (ยง3.1 of article/sim_numerics.md) says "the doubling is not a tuning constant". simroot/pure.py (project_credit) says the opposite: the argument is circular and 1.25 is cheaper. stage12 measured it but its output was never kept, so this reruns exactly that part - the same `ours`, the same problems, the same charging - and returns the numbers for verify_article.py. The credit safeguard, which needs no multiplier, is put beside it from the same run. python -u measure_budget_factor.py """ from __future__ import annotations from simroot.pure import pure_root from stage12_validation import XTOL, load, ours, per_problem, totals FACTORS = (1.0, 1.25, 1.5, 2.0, 3.0, 4.0) def credit(f, a, b, xtol, maxfev): return pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived3", guard="credit") def main(): probs = load() out = {} print(f"{'factor':>8} {'APS':>6} {'solved':>7} {'CHA':>6} {'solved':>7} {'both':>6}") for fac in FACTORS: p = per_problem(lambda f, a, b, xt, mx, _f=fac: ours(f, a, b, xt, mx, _f), probs, 200) t, ok = totals(p, probs) out[fac] = (t["APS"], ok["APS"], t["CHA"], ok["CHA"]) mark = " <- the text's choice" if fac == 2.0 else "" print(f"{fac:8.2f} {t['APS']:6d} {ok['APS']:4d}/154 {t['CHA']:6d} {ok['CHA']:4d}/45 " f"{t['APS'] + t['CHA']:6d}{mark}") p = per_problem(credit, probs, 200) t, ok = totals(p, probs) out["credit"] = (t["APS"], ok["APS"], t["CHA"], ok["CHA"]) print(f"{'credit':>8} {t['APS']:6d} {ok['APS']:4d}/154 {t['CHA']:6d} {ok['CHA']:4d}/45 " f"{t['APS'] + t['CHA']:6d} <- no multiplier, bound = bisection + 1 step") # The credit rule's own number, the endowment C0, promises bisection + ceil(C0) # steps. Every C0 in (0,1] promises the same single step; the claim in the code is # that 1, the most permissive of them, is also the cheapest - measured here. print(f"\n{'C0':>8} {'APS':>6} {'CHA':>6} {'both':>6} promise") out["endowment"] = {} for c0 in (0.1, 0.5, 1.0, 2.0, 5.0): p = per_problem(lambda f, a, b, xt, mx, _c=c0: pure_root( f, a, b, xt, mx, similarity="ratio", scale="derived3", guard="credit", endowment=_c), probs, 200) t, ok = totals(p, probs) out["endowment"][c0] = (t["APS"], t["CHA"]) steps = -(-c0 // 1) print(f"{c0:8.2f} {t['APS']:6d} {t['CHA']:6d} {t['APS'] + t['CHA']:6d} " f"bisection + {int(steps)} step(s)") return out if __name__ == "__main__": main()