92 lines
4.0 KiB
Python
92 lines
4.0 KiB
Python
"""Implementation gates R1-R4 for the pre-step gate (PREREG_prestep_gate_2026-09-21.md).
|
|
|
|
The measured cause of our cost is that the safeguard REPAIRS 77.5 % of evaluations after
|
|
the fact, while Chandrupatla REFUSES its model for free on 72 % of steps and halves
|
|
instead. The gate under test asks, BEFORE spending an evaluation, whether the similarity
|
|
step promises at least what bisection would remove — a comparison of two lengths already
|
|
in hand, no threshold and no new constant.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import inspect
|
|
import math
|
|
import re
|
|
|
|
import pytest
|
|
|
|
from simroot import pure as P
|
|
|
|
PROBLEMS = [
|
|
(lambda t: t ** 3 - 2.0 * t - 5.0, 2.0, 3.0),
|
|
(lambda t: math.exp(t) - 5.0, 0.0, 3.0),
|
|
(lambda t: t ** 2 - 2.0, 0.5, 2.0),
|
|
(lambda t: math.cos(t) - t, 0.0, 1.0),
|
|
(lambda t: (t - 1.0) ** 3, -1.0, 4.0),
|
|
]
|
|
|
|
|
|
def test_R1_the_published_path_is_bit_identical_with_the_gate_off():
|
|
for f, a, b in PROBLEMS:
|
|
for guard in ("credit", "project", "safe", "step"):
|
|
base = P.pure_root(f, a, b, 1e-12, 300, similarity="ratio",
|
|
scale="derived3", guard=guard)
|
|
off = P.pure_root(f, a, b, 1e-12, 300, similarity="ratio",
|
|
scale="derived3", guard=guard, prestep="none")
|
|
assert base == off, (guard, base, off)
|
|
|
|
|
|
def test_R2_the_gate_carries_no_chosen_constant():
|
|
src = inspect.getsource(P.pure_root)
|
|
start = src.index('if prestep == "progress":')
|
|
end = src.index('if step is None and space ==', start) # the gate block only
|
|
body = src[start:end]
|
|
# comments carry the MEASURED numbers that justify the gate (77.5 %, 2.310 halvings);
|
|
# they are documentation, not constants, so the check reads the code only
|
|
code = "\n".join(line.split("#", 1)[0] for line in body.splitlines())
|
|
literals = set(re.findall(r"(?<![\w.])\d+\.\d+(?![\w.])", code))
|
|
# 0.5 is the definition of bisection, 1.0 comes from S in [0,1]
|
|
assert literals <= {"0.0", "0.5", "1.0"}, f"chosen constants in the gate: {literals}"
|
|
|
|
|
|
def test_R3_a_refusal_costs_no_extra_evaluation_PER_STEP():
|
|
"""R3 as the prereg states it: a refusal REPLACES the step, so evaluations never exceed
|
|
steps + the two bracket probes.
|
|
|
|
NOT claimed (and measured false on 2026-09-21): that the whole RUN cannot become more
|
|
expensive. Forcing bisection changes the trajectory — it removes more bracket but less
|
|
error than a good secant step — and one probe problem went 25 -> 29 evaluations. Whether
|
|
that trade pays over the two benchmark sets is exactly what P2/P3 measure; a unit test
|
|
must not pre-judge it."""
|
|
for f, a, b in PROBLEMS:
|
|
st = {}
|
|
_x, n, ok = P.pure_root(f, a, b, 1e-12, 300, similarity="ratio", scale="derived3",
|
|
guard="credit", prestep="progress", stats=st)
|
|
assert ok
|
|
# every evaluation is one step (the gate spends the same probe on the midpoint),
|
|
# plus f(a) and f(b)
|
|
assert st["pre_refused"] <= n - 2, (st, n)
|
|
|
|
|
|
def test_R4_refusals_are_counted_separately_from_repairs():
|
|
st = {}
|
|
f = PROBLEMS[4][0]
|
|
x, n, ok = P.pure_root(f, -1.0, 4.0, 1e-10, 300, similarity="ratio", scale="derived3",
|
|
guard="credit", prestep="progress", stats=st)
|
|
assert ok and abs(x - 1.0) < 1e-3
|
|
assert set(("forced", "pre_refused")) <= set(st)
|
|
assert st["pre_refused"] >= 1 # a cubic with a triple root refuses often
|
|
assert isinstance(st["forced"], int) and isinstance(st["pre_refused"], int)
|
|
|
|
|
|
def test_the_gate_is_validated_not_silently_ignored():
|
|
with pytest.raises(ValueError):
|
|
P.pure_root(lambda t: t, -1.0, 1.0, 1e-10, 100, prestep="whatever")
|
|
|
|
|
|
def test_the_gate_still_solves_every_probe_problem():
|
|
for f, a, b in PROBLEMS:
|
|
x, n, ok = P.pure_root(f, a, b, 1e-12, 300, similarity="ratio", scale="derived3",
|
|
guard="credit", prestep="progress")
|
|
assert ok and abs(f(x)) < 1e-6, (a, b, x, n, ok)
|