A in the method (extrapolate='steps', default 'none' = published bit for bit): NOT accepted into the proposed rule by the declared stop rule - X2 fails. Proposed rule without -> with A: APS 2806 -> 2967 (X2 FAIL), CHA 3220 -> 2925 (X1 pass), flat fun3-6 1823 -> 1524 (X4 pass), guarantee intact, 0 violations in 39 family cells (X3 pass). The per-problem edge over Chandrupatla on APS is lost (87/24/42, p=9e-5 -> 42/62/49, p=0.53).
X5: dissimilar+slope with A reaches 2859+2545 = 5404 over both sets, the best total this line has measured (was 5511; Chandrupatla 5228) - but again by trading the canonical set (2726 -> 2859) for the wide brackets (2785 -> 2545). The one-step replay (APS no harm) did not carry over: its bracket-halving metric rewards overshooting the root, which on a simple root costs superlinear convergence in the full run - the declared one-step limitation, now measured. Among the nine functions A helps only the tent (6026 -> 5892) and slightly ratio_soft. Also: pin 'strictly fewer evaluations on every flat problem' was wrong for 6(x-2)^5 on [0,10] - both runs are budget-bound (90 of the guaranteed 91); corrected to the measured claim. verify_article 286/286, 836 tests pass twice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""Pins for PREREG_extrapolate_in_method_2026-09-21.md: step extrapolation (A)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
from simroot.pure import pure_root
|
||||
|
||||
SMOOTH = (
|
||||
(lambda t: t ** 3 - 2.0 * t - 5.0, 1.0, 4.0),
|
||||
(lambda t: math.exp(t) - 2.0, 0.0, 3.0),
|
||||
(lambda t: math.sin(t) - 0.5, 0.0, 1.5),
|
||||
)
|
||||
FLAT = (
|
||||
(lambda t: 6.0 * (t - 2.0) ** 5, 0.0, 10.0),
|
||||
(lambda t: t ** 9, -1.0, 2.0),
|
||||
(lambda t: (t - 3.0) ** 3, 0.0, 10.0),
|
||||
)
|
||||
XTOL, MAXFEV = 1e-12, 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f,a,b", SMOOTH + FLAT)
|
||||
@pytest.mark.parametrize("guard", ("project", "safe", "credit"))
|
||||
def test_default_is_the_published_method_bit_for_bit(f, a, b, guard):
|
||||
ref = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3", guard=guard)
|
||||
off = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3", guard=guard,
|
||||
extrapolate="none")
|
||||
assert ref == off
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f,a,b", SMOOTH + FLAT)
|
||||
@pytest.mark.parametrize("guard", ("project", "credit"))
|
||||
def test_the_guarantee_survives_extrapolation(f, a, b, guard):
|
||||
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
|
||||
guard=guard, extrapolate="steps")
|
||||
assert ok and min(a, b) <= x <= max(a, b)
|
||||
half = math.ceil(math.log2(abs(b - a) / XTOL))
|
||||
bound = 2 * half + 3 if guard == "project" else half + 4
|
||||
assert n <= bound, (n, bound)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f,a,b", FLAT[1:])
|
||||
def test_extrapolation_breaks_the_flat_cycle(f, a, b):
|
||||
"""The mechanism the pre-registration rests on: on a pure power the similar successive
|
||||
undershoots are replaced by a longer step, and the run gets cheaper."""
|
||||
_x, n_off, _ = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
|
||||
guard="project")
|
||||
_x, n_on, _ = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
|
||||
guard="project", extrapolate="steps")
|
||||
assert n_on < n_off, (n_on, n_off)
|
||||
|
||||
|
||||
def test_on_a_budget_bound_run_extrapolation_changes_the_path_not_the_count():
|
||||
"""MEASURED, pinned as measured: on 6(x-2)^5 over [0, 10] both runs cost 90 evaluations
|
||||
against a projection guarantee of 2*44 + 3 = 91 - the budget schedule, not the step,
|
||||
decides when the run ends. The paths differ from the fourth evaluation on (87
|
||||
positions), so the mode is active; its gain is absorbed by the safeguard here. The
|
||||
expectation written first (strictly fewer evaluations) was wrong for this problem."""
|
||||
f, a, b = FLAT[0]
|
||||
ev = {}
|
||||
for mode in ("none", "steps"):
|
||||
seen = []
|
||||
|
||||
def g(t, _s=seen):
|
||||
_s.append(t)
|
||||
return f(t)
|
||||
_x, n, ok = pure_root(g, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
|
||||
guard="project", extrapolate=mode)
|
||||
assert ok
|
||||
ev[mode] = (n, seen)
|
||||
assert ev["steps"][0] <= ev["none"][0]
|
||||
assert ev["steps"][1] != ev["none"][1]
|
||||
|
||||
|
||||
def test_unknown_mode_is_refused():
|
||||
with pytest.raises(ValueError):
|
||||
pure_root(lambda t: t, -1.0, 1.0, XTOL, MAXFEV, extrapolate="aitken")
|
||||
Reference in New Issue
Block a user