Flat regime: exit by midpoint similarity (flatstickexit), one judgment at entry and exit (flatjudge), entry by analogy (flatanalog).

PREREG_flat_exit: NOT accepted - APS 2806 -> 3125, CHA 3220 -> 2503 (the exit is earned: APS 6897 without it).
PREREG_flat_judge: NOT accepted (smoke) - APS 3009, CHA 2486: at the model's point f is small by construction, the judgment cannot tell flat from simple there.
PREREG_flat_analogy: ACCEPTED with G2. Entry = unkept promise AND the (xi, phi) configuration nearer to its own past than to the line AND the pair's similarity exponent m >= 2. Projection + G2: APS 2782 -> 2780 (below Chandrupatla 2787, per problem 95/20/38 p=8e-7), CHA 3169 -> 2625, guarantee holds. Without G2: APS 2806 -> 2807 (fails by one call), CHA 2635. Simple roots are spared exactly (cost unchanged); flat families 1823 -> 1238, entry comes late. Goal (below Chandrupatla on both) NOT met: CHA 2625 vs 2441, per problem 9/6/25.
Server regression x2: 1052 passed, 1 failed = the expected paper-number check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
vvs
2026-09-21 14:55:45 +01:00
co-authored by Claude Opus 5
parent 42bfab4330
commit 1842eb0765
7 changed files with 321 additions and 5 deletions
+34
View File
@@ -0,0 +1,34 @@
tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6
none 2806->2807 4104->2635 6910->5442 2707->1238 solved 193 over 0
none +G2 2782->2780 3863->2625 6645->5405 2474->1234 solved 193 over 0
step 3036->3035 3524->2650 6560->5685 2111->1237 solved 193 over 0
step +G2 3089->3089 3529->2661 6618->5750 2106->1238 solved 193 over 0
bracket 7260->7260 3604->3604 10864->10864 1730->1730 solved 193 over 0
bracket +G2 6837->6837 3650->3650 10487->10487 1717->1717 solved 193 over 0
both 7239->7239 3515->3515 10754->10754 1529->1529 solved 193 over 0
both +G2 7130->7130 3463->3463 10593->10593 1504->1504 solved 193 over 0
project 2806->2807 3220->2635 6026->5442 1823->1238 solved 193 over 0
project +G2 2782->2780 3169->2625 5951->5405 1780->1234 solved 193 over 0
safe 3036->3035 3390->2650 6426->5685 1977->1237 solved 193 over 0
safe +G2 3089->3089 3392->2661 6481->5750 1969->1238 solved 193 over 0
credit 3568->3568 3020->2960 6588->6528 1044->1014 solved 193 over 0
credit +G2 3799->3799 3064->3034 6863->6833 1044->1014 solved 193 over 0
VERDICTS
proposed rule APS 2806->2807 (Z2 ✗) CHA 3220->2635 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 5442 vs Chandrupatla APS 87/24/42 p=9.2e-05 not accepted
proposed rule + G2 APS 2782->2780 (Z2 ✓) CHA 3169->2625 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 5405 vs Chandrupatla APS 95/20/38 p=8.2e-07 ACCEPTED
nine functions, projection, no gate -> flat gate, both sets:
cbrt 18003 -> 17853
cosine 19741 -> 18885
exp_abs 6652 -> 5969
exp_sq 19786 -> 18877
rat_sq 19793 -> 18873
ratio 6026 -> 5442
ratio_soft 9352 -> 9002
rational 6823 -> 6177
sqrt 13388 -> 13212
flatanalog.ratio.derived3.project APS vs Chandrupatla 87/24/42 p=9.2e-05
flatanalog.ratio.derived3.project CHA vs Chandrupatla 9/6/25 p=0.009
pure+extP+flatanalog.ratio.derived3.project APS vs Chandrupatla 95/20/38 p=8.2e-07
pure+extP+flatanalog.ratio.derived3.project CHA vs Chandrupatla 9/6/25 p=0.009
+62
View File
@@ -0,0 +1,62 @@
===== flatstickexit
tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6
none 2806->3125 4104->2503 6910->5628 2707->1057 solved 193 over 0
none +G2 2782->3175 3863->2508 6645->5683 2474->1057 solved 193 over 0
step 3036->3161 3524->2492 6560->5653 2111->1057 solved 193 over 0
step +G2 3089->3193 3529->2499 6618->5692 2106->1057 solved 193 over 0
bracket 7260->7226 3604->3604 10864->10830 1730->1730 solved 193 over 0
bracket +G2 6837->6874 3650->3650 10487->10524 1717->1717 solved 193 over 0
both 7239->7179 3515->3515 10754->10694 1529->1529 solved 193 over 0
both +G2 7130->7150 3463->3463 10593->10613 1504->1504 solved 193 over 0
project 2806->3125 3220->2503 6026->5628 1823->1057 solved 193 over 0
project +G2 2782->3175 3169->2508 5951->5683 1780->1057 solved 193 over 0
safe 3036->3161 3390->2492 6426->5653 1977->1057 solved 193 over 0
safe +G2 3089->3193 3392->2499 6481->5692 1969->1057 solved 193 over 0
credit 3568->4232 3020->2810 6588->7042 1044->951 solved 193 over 0
credit +G2 3799->4575 3064->2881 6863->7456 1044->951 solved 193 over 0
VERDICTS
proposed rule APS 2806->3125 (Z2 ✗) CHA 3220->2503 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 5628 vs Chandrupatla APS 19/19/115 p=6.1e-18 not accepted
proposed rule + G2 APS 2782->3175 (Z2 ✗) CHA 3169->2508 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 5683 vs Chandrupatla APS 19/20/114 p=1.1e-17 not accepted
nine functions, projection, no gate -> flat gate, both sets:
cbrt 18003 -> 17989
cosine 19741 -> 15076
exp_abs 6652 -> 6349
exp_sq 19786 -> 13379
rat_sq 19793 -> 13636
ratio 6026 -> 5628
ratio_soft 9352 -> 8903
rational 6823 -> 7148
sqrt 13388 -> 13233
===== flatstickmid
tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6
none 2806->6897 4104->3019 6910->9916 2707->1057 solved 193 over 0
none +G2 2782->6918 3863->3055 6645->9973 2474->1057 solved 193 over 0
step 3036->6663 3524->3019 6560->9682 2111->1057 solved 193 over 0
step +G2 3089->6709 3529->3055 6618->9764 2106->1057 solved 193 over 0
bracket 7260->7214 3604->3604 10864->10818 1730->1730 solved 193 over 0
bracket +G2 6837->6886 3650->3650 10487->10536 1717->1717 solved 193 over 0
both 7239->7241 3515->3515 10754->10756 1529->1529 solved 193 over 0
both +G2 7130->7196 3463->3463 10593->10659 1504->1504 solved 193 over 0
project 2806->6897 3220->3019 6026->9916 1823->1057 solved 193 over 0
project +G2 2782->6918 3169->3055 5951->9973 1780->1057 solved 193 over 0
safe 3036->6663 3390->3019 6426->9682 1977->1057 solved 193 over 0
safe +G2 3089->6709 3392->3055 6481->9764 1969->1057 solved 193 over 0
credit 3568->6837 3020->3002 6588->9839 1044->951 solved 193 over 0
credit +G2 3799->6953 3064->3002 6863->9955 1044->951 solved 193 over 0
VERDICTS
proposed rule APS 2806->6897 (Z2 ✗) CHA 3220->3019 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 9916 vs Chandrupatla APS 9/4/140 p=2.3e-31 not accepted
proposed rule + G2 APS 2782->6918 (Z2 ✗) CHA 3169->3055 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 9973 vs Chandrupatla APS 9/4/140 p=2.3e-31 not accepted
nine functions, projection, no gate -> flat gate, both sets:
cbrt 18003 -> 12694
cosine 19741 -> 10825
exp_abs 6652 -> 10621
exp_sq 19786 -> 10810
rat_sq 19793 -> 10793
ratio 6026 -> 9916
ratio_soft 9352 -> 10447
rational 6823 -> 10634
sqrt 13388 -> 11332
+102 -2
View File
@@ -593,6 +593,41 @@ def _order_split(A, FA, B, FB, m):
return A + t * (B - A) return A + t * (B - A)
def _config3(x, fx, xp, fp, xp2, fp2):
"""The dimensionless configuration of the last three points and its two scales
(PREREG_flat_analogy 2026-09-21): xi = where x sits between the earlier two, phi =
where f(x) sits between their values, and |x - xp|, |fx - fp|. A linear f has
phi = xi exactly; a pure power repeats (xi, phi) under zoom. None when undefined."""
if xp2 is None or xp2 == xp or fp2 == fp:
return None
xi = (x - xp) / (xp2 - xp)
phi = (fx - fp) / (fp2 - fp)
if not (math.isfinite(xi) and math.isfinite(phi)):
return None
return xi, phi, abs(x - xp), abs(fx - fp)
def _analogous_and_steep(cur, past):
"""Is the configuration nearer to its own past than to the line phi = xi, and does the
analogous pair scale like a power of order m >= 2? Two ordinal judgments and the
flag's own break-even (1/4 = (1 - 1/2)^2 <-> m = 2); no new constant.
Nearness: Euclidean in the (xi, phi) plane, the line by its perpendicular. Order: the
pair shrank x by L and f by L^m, m = ln(f ratio) / ln(x ratio)."""
if cur is None or not past:
return False
xi, phi = cur[0], cur[1]
best = min(past, key=lambda q: math.hypot(xi - q[0], phi - q[1]))
if not math.hypot(xi - best[0], phi - best[1]) < abs(phi - xi) / math.sqrt(2.0):
return False
if best[2] <= 0.0 or best[3] <= 0.0 or cur[2] <= 0.0 or cur[3] <= 0.0:
return False
lx, lf = cur[2] / best[2], cur[3] / best[3]
if not (math.isfinite(lx) and math.isfinite(lf)) or lx == 1.0 or lf <= 0.0:
return False
return math.log(lf) / math.log(lx) >= 2.0
def _local_order(x2, f2, x1, f1, x0, f0): def _local_order(x2, f2, x1, f1, x0, f0):
"""The local order m of f, from three evaluations and nothing else. """The local order m of f, from three evaluations and nothing else.
@@ -710,7 +745,8 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
if space not in SPACES: if space not in SPACES:
raise ValueError(f"unknown space {space!r}") raise ValueError(f"unknown space {space!r}")
if prestep not in ("none", "progress", "slope", "band", "defect", "simpair", "flat", if prestep not in ("none", "progress", "slope", "band", "defect", "simpair", "flat",
"flat2", "flatcreep", "flatstick", "flatstickmid"): "flat2", "flatcreep", "flatstick", "flatstickmid", "flatstickexit",
"flatjudge", "flatanalog"):
raise ValueError(f"unknown prestep {prestep!r}") raise ValueError(f"unknown prestep {prestep!r}")
if prestep in ("band", "defect", "simpair") and scale not in ( if prestep in ("band", "defect", "simpair") and scale not in (
"derived3", "derived3_cap", "derived3_m", "bracket", "far"): "derived3", "derived3_cap", "derived3_m", "bracket", "far"):
@@ -766,6 +802,8 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
last_model = False # was the step just evaluated the model's own? (flat gate) last_model = False # was the step just evaluated the model's own? (flat gate)
unkept_run = 0 # consecutive model steps whose promise failed (flat2) unkept_run = 0 # consecutive model steps whose promise failed (flat2)
sticky_m = None # order read at entry to the sticky flat regime (flatstick*) sticky_m = None # order read at entry to the sticky flat regime (flatstick*)
judged = 0 # flatjudge: +1 the last point looked flat, -1 linear, 0 tie
configs = [] # flatanalog: the run's memory of (xi, phi, |dx|, |df|)
if stats is not None: if stats is not None:
stats['forced'] = 0 stats['forced'] = 0
stats['pre_refused'] = 0 stats['pre_refused'] = 0
@@ -959,22 +997,58 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# late, before the crossing (flat2's failure). # late, before the crossing (flat2's failure).
step = 0.5 * (A + B) - x step = 0.5 * (A + B) - x
pre_refused += 1 pre_refused += 1
if step is None and prestep in ("flatstick", "flatstickmid"): if step is None and prestep in ("flatstick", "flatstickmid",
"flatstickexit"):
# PREREG_flat_stick 2026-09-21. The same entry as "flat", but the # PREREG_flat_stick 2026-09-21. The same entry as "flat", but the
# regime is a property of the root, not of one step: once the # regime is a property of the root, not of one step: once the
# promise has failed, every later step splits the bracket. The # promise has failed, every later step splits the bracket. The
# single flag replaced one step and the model undershot again. # single flag replaced one step and the model undershot again.
# flatstick splits where |f| ~ |x-r|^m puts the root, m read from # flatstick splits where |f| ~ |x-r|^m puts the root, m read from
# the failed promise itself; flatstickmid halves (the ablation). # the failed promise itself; flatstickmid halves (the ablation).
# flatstickexit halves too, and may LEAVE the regime - see the
# similarity judgment at the midpoint after the evaluation.
if (sticky_m is None and last_model and f_prev != 0.0 if (sticky_m is None and last_model and f_prev != 0.0
and fx / f_prev >= 0.25): and fx / f_prev >= 0.25):
sticky_m = _order_from_promise(fx / f_prev) sticky_m = _order_from_promise(fx / f_prev)
if stats is not None:
stats['stick_entries'] = stats.get('stick_entries', 0) + 1
if sticky_m is not None: if sticky_m is not None:
if prestep == "flatstick": if prestep == "flatstick":
step = _order_split(A, FA, B, FB, sticky_m) - x step = _order_split(A, FA, B, FB, sticky_m) - x
else: else:
step = 0.5 * (A + B) - x step = 0.5 * (A + B) - x
pre_refused += 1 pre_refused += 1
if step is None and prestep == "flatanalog":
# PREREG_flat_analogy 2026-09-21. A pure power is similar to itself
# under zoom: its configuration RECURS, while a simple root's tends
# to the line. Enter on the unkept promise only when the current
# configuration is nearer to its own past than to the line AND the
# analogous pair scales as a power of order >= 2. Every state the
# gate sees joins the memory after it has been judged.
cur = _config3(x, fx, x_prev, f_prev, x_prev2, f_prev2)
if (sticky_m is None and last_model and f_prev != 0.0
and fx / f_prev >= 0.25 and _analogous_and_steep(cur, configs)):
sticky_m = math.inf
if stats is not None:
stats['stick_entries'] = stats.get('stick_entries', 0) + 1
if cur is not None:
configs.append(cur)
if sticky_m is not None:
step = 0.5 * (A + B) - x
pre_refused += 1
if step is None and prestep == "flatjudge":
# PREREG_flat_judge 2026-09-21. Enter only when the unkept promise
# AND the point itself looks flat (judged at its evaluation, below);
# a simple root that trips the flag is usually judged linear there
# and never pays for a midpoint. In the regime every step halves.
if (sticky_m is None and last_model and f_prev != 0.0
and fx / f_prev >= 0.25 and judged > 0):
sticky_m = math.inf
if stats is not None:
stats['stick_entries'] = stats.get('stick_entries', 0) + 1
if sticky_m is not None:
step = 0.5 * (A + B) - x
pre_refused += 1
if step is None and prestep == "flat2" and unkept_run >= 2: if step is None and prestep == "flat2" and unkept_run >= 2:
# PREREG_flat_twice 2026-09-21. The same unkept promise as # PREREG_flat_twice 2026-09-21. The same unkept promise as
# "flat" (model step, no crossing, r >= 1/4), but only after it has # "flat" (model step, no crossing, r >= 1/4), but only after it has
@@ -1080,7 +1154,33 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# step moved by the safeguard says nothing about the model # step moved by the safeguard says nothing about the model
last_model = model_target is not None and x_new == model_target last_model = model_target is not None and x_new == model_target
w_before = abs(B - A) w_before = abs(B - A)
mid_now, lin_mid = 0.5 * (A + B), 0.5 * (FA + FB) # before the bracket moves
fnew = g(x_new) fnew = g(x_new)
if (prestep in ("flatstickexit", "flatanalog") and sticky_m is not None
and x_new == mid_now
and abs(fnew - lin_mid) < abs(fnew)):
# PREREG_flat_exit 2026-09-21. A midpoint evaluated in the regime is judged
# against the two predictions: a simple root (f nearly linear on the
# bracket) puts f(M) at (FA+FB)/2, a flat approach puts it at ~0. More
# like the linear one - the regime is left and the model steps again.
# Ordinal: two distances compared, no threshold; a tie stays.
sticky_m = None
if stats is not None:
stats['stick_exits'] = stats.get('stick_exits', 0) + 1
if prestep == "flatjudge":
# PREREG_flat_judge 2026-09-21. One similarity judgment, made at every new
# point before the bracket moves: is f(x) more like the line through the
# bracket ends (a simple root) or like 0 (a flat approach)? Weighted as
# FA(1-t) + FB t, t in (0,1), so it cannot overflow. At a midpoint it is
# exactly the exit judgment of flatstickexit. Ordinal, no threshold.
t_at = (x_new - A) / (B - A)
lin_at = FA * (1.0 - t_at) + FB * t_at
d_lin, d_flat = abs(fnew - lin_at), abs(fnew)
judged = 1 if d_flat < d_lin else (-1 if d_lin < d_flat else 0)
if sticky_m is not None and x_new == mid_now and judged < 0:
sticky_m = None
if stats is not None:
stats['stick_exits'] = stats.get('stick_exits', 0) + 1
# the run of unkept promises (flat2): x, fx are still the point the step left # the run of unkept promises (flat2): x, fx are still the point the step left
if last_model and fx != 0.0 and fnew / fx >= 0.25: if last_model and fx != 0.0 and fnew / fx >= 0.25:
unkept_run += 1 unkept_run += 1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+12 -3
View File
@@ -419,10 +419,16 @@ def main():
flat2mode = "--flat2" in sys.argv # the flat gate, promise failed twice flat2mode = "--flat2" in sys.argv # the flat gate, promise failed twice
creepmode = "--flatcreep" in sys.argv # the flat gate AND a creep creepmode = "--flatcreep" in sys.argv # the flat gate AND a creep
stickmode = "--flatstick" in sys.argv # the sticky flat regime + its midpoint ablation stickmode = "--flatstick" in sys.argv # the sticky flat regime + its midpoint ablation
exitmode = "--flatexit" in sys.argv # the sticky regime with an exit by similarity
judgemode = "--flatjudge" in sys.argv # one similarity judgment at entry and exit
analogmode = "--flatanalog" in sys.argv # entry by analogy with the run's own past
combomode = "--combo" in sys.argv # modes A and B together combomode = "--combo" in sys.argv # modes A and B together
pointsmode = "--points" in sys.argv # mode A: triple by shape pointsmode = "--points" in sys.argv # mode A: triple by shape
dirmode = "--direction" in sys.argv # mode B: far end by dissimilarity dirmode = "--direction" in sys.argv # mode B: far end by dissimilarity
specs = (build_grid_flat(smoke, ("flatstick", "flatstickmid")) if stickmode else specs = (build_grid_flat(smoke, ("flatanalog", "flatstickexit")) if analogmode else
build_grid_flat(smoke, ("flatjudge", "flatstickexit")) if judgemode else
build_grid_flat(smoke, ("flatstickexit", "flatstickmid")) if exitmode else
build_grid_flat(smoke, ("flatstick", "flatstickmid")) if stickmode else
build_grid_flat(smoke, "flatcreep") if creepmode else build_grid_flat(smoke, "flatcreep") if creepmode else
build_grid_flat(smoke, "flat2") if flat2mode else build_grid_flat(smoke, "flat2") if flat2mode else
build_grid_flat(smoke) if flatmode else build_grid_flat(smoke) if flatmode else
@@ -452,8 +458,11 @@ def main():
# the published sweep_full.json is what verify_article.py checks the paper # the published sweep_full.json is what verify_article.py checks the paper
# against, so the log grid never writes into it # against, so the log grid never writes into it
if stickmode or creepmode or flat2mode or flatmode or ext2mode or extmode or decmode or ordermode or capmode or combomode or pointsmode or dirmode: if analogmode or judgemode or exitmode or stickmode or creepmode or flat2mode or flatmode or ext2mode or extmode or decmode or ordermode or capmode or combomode or pointsmode or dirmode:
base = ("sweep_flatstick" if stickmode else base = ("sweep_flatanalog" if analogmode else
"sweep_flatjudge" if judgemode else
"sweep_flatexit" if exitmode else
"sweep_flatstick" if stickmode else
"sweep_flatcreep" if creepmode else "sweep_flatcreep" if creepmode else
"sweep_flat2" if flat2mode else "sweep_flat2" if flat2mode else
"sweep_flat" if flatmode else "sweep_flat" if flatmode else
+109
View File
@@ -158,3 +158,112 @@ def test_an_infinite_end_gives_the_midpoint_not_nan():
safeguard before the loop checked finiteness.""" safeguard before the loop checked finiteness."""
assert _order_split(0.0, -math.inf, 2.0, 1.0, 3.0) == 1.0 assert _order_split(0.0, -math.inf, 2.0, 1.0, 3.0) == 1.0
assert _order_split(0.0, -math.inf, 2.0, math.inf, 3.0) == 1.0 assert _order_split(0.0, -math.inf, 2.0, math.inf, 3.0) == 1.0
# ---- PREREG_flat_exit_2026-09-21: leaving the sticky regime by similarity at the midpoint ----
@pytest.mark.parametrize("f,a,b", PROBS)
@pytest.mark.parametrize("guard", ("project", "credit"))
@pytest.mark.parametrize("ext", ("none", "pattern"))
def test_the_guarantee_holds_with_the_exit(f, a, b, guard, ext):
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard=guard, prestep="flatstickexit", extrapolate=ext)
assert ok and min(a, b) <= x <= max(a, b)
half = math.ceil(math.log2(abs(b - a) / XTOL))
assert n <= (2 * half + 3 if guard == "project" else half + 4), n
def _exit_stats(f, a, b):
st = {}
pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3", guard="project",
prestep="flatstickexit", stats=st)
return st.get("stick_entries", 0), st.get("stick_exits", 0)
def test_the_exit_leaves_a_false_entry_and_keeps_a_true_one():
"""Measured before pinning: a simple root that trips the flag (the cubic, exp) leaves
the regime at a midpoint; pure powers, scale-invariant, never do."""
assert _exit_stats(lambda t: 3.0 * t - 1.0, -2.0, 5.0) == (0, 0)
assert _exit_stats(lambda t: t ** 3 - 2.0 * t - 5.0, 1.0, 4.0) == (1, 1)
assert _exit_stats(lambda t: math.exp(t) - 2.0, 0.0, 3.0) == (1, 1)
for f, a, b in ((lambda t: t ** 9, -1.0, 2.0), (lambda t: t ** 19, -10.0, 100.0),
(lambda t: 6.0 * (t - 2.0) ** 5, 0.0, 10.0)):
ent, ex = _exit_stats(f, a, b)
assert ent >= 1 and ex == 0, (ent, ex)
def test_the_exit_does_not_touch_the_other_sticky_modes():
for gate in ("flatstick", "flatstickmid"):
st = {}
pure_root(lambda t: math.exp(t) - 2.0, 0.0, 3.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep=gate, stats=st)
assert st.get("stick_exits", 0) == 0
# ---- PREREG_flat_judge_2026-09-21: one similarity judgment at entry and exit ----
@pytest.mark.parametrize("f,a,b", PROBS)
@pytest.mark.parametrize("guard", ("project", "credit"))
@pytest.mark.parametrize("ext", ("none", "pattern"))
def test_the_guarantee_holds_with_the_judge(f, a, b, guard, ext):
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard=guard, prestep="flatjudge", extrapolate=ext)
assert ok and min(a, b) <= x <= max(a, b)
half = math.ceil(math.log2(abs(b - a) / XTOL))
assert n <= (2 * half + 3 if guard == "project" else half + 4), n
def test_the_judge_is_silent_on_a_line_and_holds_a_pure_power():
st = {}
pure_root(lambda t: 3.0 * t - 1.0, -2.0, 5.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep="flatjudge", stats=st)
assert st.get("stick_entries", 0) == 0 and st["pre_refused"] == 0
st = {}
pure_root(lambda t: t ** 19, -10.0, 100.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep="flatjudge", stats=st)
assert st.get("stick_entries", 0) >= 1 and st.get("stick_exits", 0) == 0, st
# ---- PREREG_flat_analogy_2026-09-21: entry by analogy with the run's own past ----
from simroot.pure import _analogous_and_steep, _config3 # noqa: E402
@pytest.mark.parametrize("f,a,b", PROBS)
@pytest.mark.parametrize("guard", ("project", "credit"))
@pytest.mark.parametrize("ext", ("none", "pattern"))
def test_the_guarantee_holds_with_the_analogy_entry(f, a, b, guard, ext):
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard=guard, prestep="flatanalog", extrapolate=ext)
assert ok and min(a, b) <= x <= max(a, b)
half = math.ceil(math.log2(abs(b - a) / XTOL))
assert n <= (2 * half + 3 if guard == "project" else half + 4), n
def test_the_analogy_entry_spares_simple_roots_and_catches_powers():
"""Measured before pinning: the cubic and exp, which trip the single flag, never
enter, and cost exactly what the rule costs without the regime."""
for f, a, b in ((lambda t: 3.0 * t - 1.0, -2.0, 5.0),
(lambda t: t ** 3 - 2.0 * t - 5.0, 1.0, 4.0),
(lambda t: math.exp(t) - 2.0, 0.0, 3.0)):
st = {}
_x, n1, _ = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard="project", prestep="flatanalog", stats=st)
_x, n0, _ = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard="project")
assert st.get("stick_entries", 0) == 0 and n1 == n0
for f, a, b in ((lambda t: t ** 9, -1.0, 2.0), (lambda t: t ** 19, -10.0, 100.0),
(lambda t: 6.0 * (t - 2.0) ** 5, 0.0, 10.0)):
st = {}
pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard="project", prestep="flatanalog", stats=st)
assert st.get("stick_entries", 0) >= 1
def test_a_line_is_never_analogous_and_an_exact_power_repeats_with_its_order():
line = [_config3(x, 3 * x, xp, 3 * xp, xp2, 3 * xp2)
for x, xp, xp2 in ((0.1, 0.5, 1.0), (0.05, 0.1, 0.5))]
assert line[0][0] == pytest.approx(line[0][1]) # phi = xi on a line
assert not _analogous_and_steep(line[1], [line[0]])
p = lambda t: t ** 5 # noqa: E731
old = _config3(0.4, p(0.4), 0.8, p(0.8), 1.6, p(1.6))
new = _config3(0.1, p(0.1), 0.2, p(0.2), 0.4, p(0.4)) # the same shape, zoomed by 4
assert new[0] == pytest.approx(old[0]) and new[1] == pytest.approx(old[1])
assert _analogous_and_steep(new, [old])