"""Pins the corrections the revision made. Each of these replaced a statement in the paper that was wrong or too broad. They are asserted here so a later edit cannot quietly restore the old claim. """ from __future__ import annotations from simroot.baselines import _opposite, _same_sign # 2026-09-21 fix import math import os import sys import pytest sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from simroot.pure import PURE_SIMS, pure_root from stage5_three_point import PROBLEMS, order_of R2 = math.sqrt(2.0) F = lambda x: x * x - 2.0 XTOL, MAXFEV = 1e-12, 200 def iterate(S, n, sigma=2.0, x0=0.0, xfar=2.0): x, errs = x0, [] for _ in range(n): x = x + (1.0 - S(F(x) / sigma)) * (xfar - x) errs.append(abs(x - R2)) return errs # -------------------------------------------------------------------------- # the naming contradiction: the proposed similarity is the tent, and its # degeneracy is a property of the CHOSEN scale only # -------------------------------------------------------------------------- def test_the_tent_is_captured_under_the_chosen_scale(): """Table 1's last row. Not a slow rate - capture at the far end on the first step.""" e = iterate(PURE_SIMS["ratio"], 200) assert abs(e[0] - e[-1]) < 1e-15, (e[0], e[-1]) assert abs(e[0] - 0.5858) < 1e-3, e[0] def test_the_tent_is_the_best_similarity_under_the_derived_scale(): """The same function, the other scale. If these two tests ever agree in sign, the paper's central thesis - that the content is in the scale - has been broken.""" tot = {} for sim in PURE_SIMS: s = 0 for _n, f, a, b, root in PROBLEMS: x, n, conv = pure_root(f, a, b, XTOL, MAXFEV, similarity=sim, scale="derived3", guard="project") s += n if (conv and abs(x - root) <= 1e-8) else MAXFEV tot[sim] = s assert min(tot, key=lambda k: tot[k]) == "ratio", tot def test_the_tent_never_clips_under_the_derived_scale(): """Why the degeneracy disappears: |f|/sigma stays below 1, so the truncation in max(0, 1-|z|) never engages.""" from simroot.pure import _slope3 a, b = 0.0, 2.0 fa, fb = F(a), F(b) A, FA, B = a, fa, b x, fx, xp, fp = a, fa, b, fb xp2 = fp2 = None clipped = steps = 0 for _ in range(40): if abs(B - A) <= XTOL: break far = B if abs(B - x) >= abs(A - x) else A sc = abs(_slope3(x, fx, xp, fp, xp2, fp2)) * abs(far - x) if sc == 0.0: break steps += 1 clipped += abs(fx) / sc >= 1.0 xn = x + min(1.0, abs(fx) / sc) * (far - x) if not (min(A, B) < xn < max(A, B)): xn = 0.5 * (A + B) fn = F(xn) xp2, fp2, xp, fp, x, fx = xp, fp, x, fx, xn, fn if _opposite(FA, fn): B = xn else: A, FA = xn, fn assert steps > 0 assert clipped == 0, f"{clipped} of {steps} steps clipped" # -------------------------------------------------------------------------- # Proposition 1 is specific; Proposition 1' locates the boundary # -------------------------------------------------------------------------- def test_only_the_ratio_form_reproduces_regula_falsi(): a, b = 1.0, 4.0 fa, fb = F(a), F(b) falsi = (a * fb - b * fa) / (fb - fa) matches = [] for name, S in (("rational", PURE_SIMS["rational"]), ("exp_abs", PURE_SIMS["exp_abs"]), ("rat_sq", PURE_SIMS["rat_sq"]), ("cosine", PURE_SIMS["cosine"]), ("ratio", PURE_SIMS["ratio"])): pt = a + (1.0 - S(F(a) / abs(fb))) * (b - a) if abs(pt - falsi) < 1e-12: matches.append(name) assert matches == ["rational"], matches def test_the_bracket_end_difference_gives_regula_falsi_exactly(): """Proposition 1'. This is why 'most recent' in the definition of the divided difference is load-bearing.""" a, b = 1.0, 4.0 fa, fb = F(a), F(b) falsi = (a * fb - b * fa) / (fb - fa) sigma = abs((fb - fa) / (b - a)) * abs(b - a) pt = a + min(1.0, abs(fa) / sigma) * (b - a) assert pt == falsi # -------------------------------------------------------------------------- # Table 1's c = 0 rows: a sublinear law with a predicted coefficient # -------------------------------------------------------------------------- @pytest.mark.parametrize("sim,want", [("rat_sq", 0.8536), ("exp_sq", 0.8536), ("cosine", 1.7071)]) def test_the_quadratic_similarities_are_sublinear_with_a_predicted_constant(sim, want): S = PURE_SIMS[sim] h = 1e-4 c2 = (1.0 - S(h)) / (h * h) fp, D, sigma = 2.0 * R2, 2.0 - R2, 2.0 predicted = sigma * sigma / (c2 * fp * fp * D) assert abs(predicted - want) < 1e-3, predicted e = iterate(S, 4001) assert abs(4000 * e[4000] - predicted) < 0.02, (4000 * e[4000], predicted) def test_there_is_no_rate_to_measure_for_those_rows(): """The old table reported 0.93-0.94 as a 'measured rate'; the ratio creeps to 1, so that number was the window's end, not a rate.""" e = iterate(PURE_SIMS["rat_sq"], 4001) ratios = [e[n] / e[n - 1] for n in (10, 100, 1000, 4000)] assert ratios == sorted(ratios), ratios assert ratios[0] < 0.94 < ratios[-1] assert ratios[-1] > 0.999 # -------------------------------------------------------------------------- # the order is 2, not Muller's 1.84 # -------------------------------------------------------------------------- def test_the_three_point_order_is_two(): ps = [order_of(lambda f_, a_, b_, xt, mx: pure_root( f_, a_, b_, XTOL, MAXFEV, scale="derived3", guard="project"), 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] assert abs(med - 2.0) < 0.1, med # -------------------------------------------------------------------------- # the two evaluation-count conventions must both be reported and must differ # in the direction the paper says # -------------------------------------------------------------------------- @pytest.mark.skipif(not os.path.exists(os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "sweep_full.json")), reason="sweep not present") def test_charged_totals_are_what_section_5_reports(): import json root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) with open(os.path.join(root, "sweep_full.json"), encoding="utf8") as fh: rows = {r["label"]: r for r in json.load(fh)} # since 2026-09-21 the competitors are the library alone: brent is # scipy.brentq (7004; our pure-Python implementation, timed in section 5.2, # is 6991) and chandrupatla is scipy's elementwise.find_root (5228; the # earlier 5208 came from a per-problem best of ours and the library, with # ours stopping on a bracket twice as wide) for lbl, want in (("pure.ratio.derived3.project", 6026), ("brent", 7004), ("bisection", 10620), ("chandrupatla", 5228)): got = rows[lbl]["APS"]["total"] + rows[lbl]["CHA"]["total"] assert got == want, (lbl, got, want)