70 lines
2.8 KiB
Python
70 lines
2.8 KiB
Python
"""PREREG_estimated_transform_2026-09-22: the control K3 must be Chandrupatla's method itself when
|
|
no order is estimated, and must stay a bracketing method when one is."""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
import pytest
|
|
|
|
from simroot.baselines import chandrupatla
|
|
from simroot.transformed import chandrupatla_transformed
|
|
from sweep_full import load_problems
|
|
|
|
PROBS = load_problems()
|
|
|
|
|
|
def test_without_an_estimate_it_is_chandrupatla_bit_for_bit():
|
|
bad = []
|
|
for s, pid, f, a, b, _r in PROBS:
|
|
r1 = chandrupatla(f, a, b, 1e-12, 200)
|
|
r2 = chandrupatla_transformed(f, a, b, 1e-12, 200, estimator="none")
|
|
if (float(r1[0]).hex(), r1[1], r1[2]) != (float(r2[0]).hex(), r2[1], r2[2]):
|
|
bad.append(pid)
|
|
assert not bad, bad[:5]
|
|
|
|
|
|
def test_the_post_hoc_branch_never_holds_a_fractional_order():
|
|
"""POSTHOC_lag_branch_2026-09-22: 'lag2' takes only readings m >= 2."""
|
|
for s, pid, f, a, b, _r in PROBS:
|
|
st = {}
|
|
x, n, ok = chandrupatla_transformed(f, a, b, 1e-12, 200, estimator="lag2", stats=st)
|
|
assert min(a, b) <= x <= max(a, b), pid
|
|
assert st.get("m_hat", 1.0) == 1.0 or st["m_hat"] >= 2.0, (pid, st)
|
|
|
|
|
|
@pytest.mark.parametrize("estimator", ("lag", "analogy"))
|
|
def test_with_an_estimate_it_still_brackets(estimator):
|
|
for s, pid, f, a, b, _r in PROBS:
|
|
x, n, ok = chandrupatla_transformed(f, a, b, 1e-12, 200, estimator=estimator)
|
|
assert min(a, b) <= x <= max(a, b), pid
|
|
assert n <= 200
|
|
|
|
|
|
def test_the_estimate_is_read_and_used_on_a_pure_power():
|
|
"""The analogy estimator must reach m_hat on (t - 1)^9 and pay. Lagouanelle's is NOT asserted:
|
|
on Chandrupatla's iterates, which alternate sides of the root, its three-point parabola reads
|
|
m ~ 1 at every step - an outcome of the experiment, reported by the run, not a property
|
|
to pin here."""
|
|
f = lambda t: (t - 1.0) ** 9 # noqa: E731
|
|
plain = chandrupatla_transformed(f, -2.0, 5.0, 1e-12, 200, estimator="none")[1]
|
|
st = {}
|
|
x, n, ok = chandrupatla_transformed(f, -2.0, 5.0, 1e-12, 200, estimator="analogy", stats=st)
|
|
assert ok and abs(x - 1.0) < 1e-6
|
|
assert st.get("updates", 0) >= 1
|
|
assert n < plain, (n, plain)
|
|
x, n, ok = chandrupatla_transformed(f, -2.0, 5.0, 1e-12, 200, estimator="lag")
|
|
assert ok and abs(x - 1.0) < 1e-6
|
|
|
|
|
|
def test_an_overflowing_transform_halves_instead_of_raising():
|
|
"""Found 2026-09-22: on the fractional branch 1/m_hat > 1 and |f|^(1/m_hat) overflowed with
|
|
an OverflowError that escaped the solver. Now it is inf, the interpolation is refused, and
|
|
the step halves."""
|
|
from simroot.transformed import _G
|
|
assert _G(1e300, 3.0) == math.inf and _G(-1e300, 3.0) == -math.inf
|
|
|
|
|
|
def test_unknown_estimator_is_refused():
|
|
with pytest.raises(ValueError):
|
|
chandrupatla_transformed(math.sin, 3.0, 4.0, 1e-12, 200, estimator="guess")
|