108 lines
4.6 KiB
Python
108 lines
4.6 KiB
Python
"""Gates for the logarithmic space mode — checked BEFORE the ranking is consulted.
|
|
|
|
PREREG_logarithmic_2026-09-20.md, amendment 1:
|
|
G1 the transform is parameter-free: c and s come from the bracket and the caller
|
|
(c = the end with the smaller |f|, s = xtol), never from a chosen constant.
|
|
G2' on APS-154 the cost must not grow (measured by the sweep, not here); what IS
|
|
checkable here is that the deviation from the x-space step is of SECOND order
|
|
in the bracket width, i.e. it vanishes as the bracket collapses.
|
|
|
|
Also pinned: the transform round-trips, u-space is rejected where it cannot be read
|
|
(no silent fallback to a different scale), and the mode still solves.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import inspect
|
|
import math
|
|
import re
|
|
|
|
import pytest
|
|
|
|
from simroot import pure as P
|
|
|
|
|
|
def _steps(width, space, fun=None):
|
|
"""The points probed on a NONLINEAR f from a bracket of the given width around 1.
|
|
|
|
Nonlinear on purpose: on a linear f the two spaces coincide EXACTLY (deviation
|
|
0.0, measured 2026-09-20), because the derived scale makes the step the Newton
|
|
step and that lands on the root in either space — so a linear probe cannot see
|
|
the deviation at all."""
|
|
calls = []
|
|
g = fun or (lambda t: t * t * t - 1.0)
|
|
|
|
def f(x):
|
|
calls.append(x)
|
|
return g(x)
|
|
|
|
P.pure_root(f, 1.0 - width, 1.0 + width, xtol=1e-14, maxfev=200,
|
|
similarity="ratio", scale="derived", guard="none", space=space)
|
|
return calls
|
|
|
|
|
|
def test_G1_the_transform_carries_no_chosen_constant():
|
|
src = "".join(inspect.getsource(fn) for fn in (P._log_map, P._log_unmap, P._log_space_step))
|
|
literals = set(re.findall(r"(?<![\w.])\d+\.\d+(?![\w.])", src))
|
|
assert literals <= {"0.0", "1.0"}, f"chosen constants in the transform: {literals}"
|
|
# and the unit really is the caller's tolerance, not something invented inside
|
|
call_site = inspect.getsource(P.pure_root)
|
|
assert "_log_space_step(S, x, fx, far, slope, c_near, xtol)" in call_site
|
|
|
|
|
|
def test_G1_the_near_end_is_read_from_the_data_not_fixed():
|
|
call_site = inspect.getsource(P.pure_root)
|
|
assert "c_near = A if abs(FA) <= abs(FB) else B" in call_site
|
|
|
|
|
|
def test_the_transform_round_trips():
|
|
for s in (1e-12, 1e-6, 1.0, 1e6):
|
|
for c in (-3.0, 0.0, 7.5):
|
|
for t in (c - 1e3, c - 1e-9, c, c + 1e-9, c + 1e3):
|
|
u = P._log_map(t, c, s)
|
|
back = P._log_unmap(u, c, s)
|
|
assert math.isclose(back, t, rel_tol=1e-12, abs_tol=1e-12)
|
|
|
|
|
|
def test_G2_deviation_from_the_x_space_step_is_second_order_in_the_bracket():
|
|
"""The march needs a RATIO of distances and identity needs an ABSOLUTE unit, so the
|
|
strict identity gate is unreachable (FINDINGS §1). What must hold is that the
|
|
deviation SHRINKS as the bracket collapses — otherwise the wide-bracket families
|
|
would be bought at the price of the canonical set."""
|
|
dev = {}
|
|
for width in (1e-2, 1e-3, 1e-4):
|
|
xs_x = _steps(width, "x")
|
|
xs_log = _steps(width, "log")
|
|
# the first probing evaluations are the bracket ends; compare the first step
|
|
i = 2
|
|
assert len(xs_x) > i and len(xs_log) > i
|
|
dev[width] = abs(xs_log[i] - xs_x[i]) / width
|
|
# exact zero is a STRONGER pass than a shrinking deviation, so it is allowed
|
|
assert dev[1e-3] <= dev[1e-2] / 3.0 or dev[1e-2] == 0.0, dev
|
|
assert dev[1e-4] <= dev[1e-3] / 3.0 or dev[1e-3] == 0.0, dev
|
|
|
|
|
|
def test_the_mode_is_rejected_where_it_cannot_be_read():
|
|
with pytest.raises(ValueError):
|
|
P.pure_root(lambda x: x, -1.0, 1.0, 1e-10, 100, scale="bracket", space="log")
|
|
with pytest.raises(ValueError):
|
|
P.pure_root(lambda x: x, -1.0, 1.0, 1e-10, 100, space="nope")
|
|
|
|
|
|
def test_the_mode_still_solves_both_a_narrow_and_a_wide_bracket():
|
|
for lo, hi in ((0.5, 1.5), (-1e12, 3.0)):
|
|
x, nfev, ok = P.pure_root(lambda t: t - 1.0, lo, hi, xtol=1e-10, maxfev=500,
|
|
similarity="ratio", scale="derived3", guard="credit",
|
|
space="log")
|
|
assert ok and abs(x - 1.0) < 1e-8, (lo, hi, x, nfev, ok)
|
|
|
|
|
|
def test_x_space_is_untouched_by_the_new_parameter():
|
|
"""The published configuration must be bit-identical with the default space."""
|
|
for lo, hi in ((0.5, 1.5), (0.5, 1e6)): # both brackets must straddle sqrt(2)
|
|
a = P.pure_root(lambda t: t * t - 2.0, lo, hi, 1e-12, 300,
|
|
similarity="ratio", scale="derived3", guard="credit")
|
|
b = P.pure_root(lambda t: t * t - 2.0, lo, hi, 1e-12, 300,
|
|
similarity="ratio", scale="derived3", guard="credit", space="x")
|
|
assert a == b
|