Flat regime (PREREG_flat_regime): the unkept-promise flag - after a model step that did not cross the root, r = f_new/f_old >= 1/4, the tangent-versus-halving break-even at m = 2 - RECOGNISES the regime (stage 1: 53.6% of model steps flagged on the flat families against 21.6% on APS and 17.0% on fun1; recall ten times the m>=2 estimator's 5.8%) and cuts the wide-bracket set by 350-490 wherever the budget does not already bind: safe 3390 -> 3037, step 3524 -> 3037, unguarded 4104 -> 3198.

NOT accepted into the proposed rule by the stop rule: under the projection the flat families are already budget-bound (CHA 3220 -> 3198 only) while the false flags on APS cost 2806 -> 3029 (Z2 fails); with G2 both sets fail. The per-problem edge over Chandrupatla on APS turns into 26/72/55. Guarantee intact in every cell. Next candidate, not pre-registered: require the promise to fail twice in a row.

Regression on the branch: 918 pass (twice); the one red test is the paper-number check awaiting the paper update.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
vvs
2026-09-21 13:25:56 +01:00
co-authored by Claude Opus 5
parent 9df1aa5f13
commit e7e74d71e5
7 changed files with 195 additions and 4 deletions
+53
View File
@@ -0,0 +1,53 @@
"""Verdicts Z1-Z5 of PREREG_flat_regime_2026-09-21.md (stage 2) from sweep_flat.json.
python -u analyze_flat.py
"""
from __future__ import annotations
import json
from analyze_extrap import FAMILY, FLAT, fam_sum, h2h, load, sign_p
def main():
rows = load("sweep_flat.json")
cha = {r["label"]: r for r in load("sweep_full.json")}["chandrupatla"]
cell = {}
for r in rows:
s = r["spec"]
cell[(s[1], s[3], s[9], s[5])] = r
print("tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6")
for gu in ("none", "step", "bracket", "both", "project", "safe", "credit"):
for ext in ("none", "pattern"):
a, b = cell[("ratio", gu, ext, "none")], cell[("ratio", gu, ext, "flat")]
print(f" {gu:<8} {'+G2' if ext == 'pattern' else ' '} "
f"{a['APS']['total']:5d}->{b['APS']['total']:<5d} {a['CHA']['total']:5d}->"
f"{b['CHA']['total']:<5d} {a['APS']['total'] + a['CHA']['total']:5d}->"
f"{b['APS']['total'] + b['CHA']['total']:<5d} {fam_sum(a, FLAT):5d}->"
f"{fam_sum(b, FLAT):<5d} solved {b['APS']['solved'] + b['CHA']['solved']} "
f"over {b['APS']['over'] + b['CHA']['over']}")
print("\nVERDICTS")
for ext, name in (("none", "proposed rule"), ("pattern", "proposed rule + G2")):
a, b = cell[("ratio", "project", ext, "none")], cell[("ratio", "project", ext, "flat")]
fam = [r for k, r in cell.items() if k[3] == "flat" and k[1] in FAMILY]
viol = sum(r["APS"]["over"] + r["CHA"]["over"] for r in fam)
low = sum(1 for r in fam if r["APS"]["solved"] + r["CHA"]["solved"] < 193)
z1 = b["CHA"]["total"] < a["CHA"]["total"]
z2 = b["APS"]["total"] <= a["APS"]["total"]
z3 = viol == 0 and low == 0
z4 = fam_sum(b, FLAT) < fam_sum(a, FLAT)
w, t, l = h2h(b, cha, "APS")
print(f" {name:<20} APS {a['APS']['total']}->{b['APS']['total']} (Z2 {'✓' if z2 else '✗'}) "
f"CHA {a['CHA']['total']}->{b['CHA']['total']} (Z1 {'✓' if z1 else '✗'}) "
f"Z3 {'✓' if z3 else '✗'} ({viol} viol, {low} cells <193) Z4 {'✓' if z4 else '✗'} "
f"both {b['APS']['total'] + b['CHA']['total']} vs Chandrupatla APS {w}/{t}/{l} "
f"p={sign_p(w, l):.2g}" + (" ACCEPTED" if z1 and z2 and z3 else " not accepted"))
print("\nnine functions, projection, no gate -> flat gate, both sets:")
for sim in sorted({k[0] for k in cell}):
a, b = cell[(sim, "project", "none", "none")], cell[(sim, "project", "none", "flat")]
print(f" {sim:<11} {a['APS']['total'] + a['CHA']['total']:6d} -> "
f"{b['APS']['total'] + b['CHA']['total']:6d}")
if __name__ == "__main__":
main()
+32
View File
@@ -0,0 +1,32 @@
sweep: 140 configurations x 199 problems (FULL)
wrote sweep_flat.json (7s total)
tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6
none 2806->3029 4104->3198 6910->6227 2707->1758 solved 193 over 0
none +G2 2782->3089 3863->3214 6645->6303 2474->1749 solved 193 over 0
step 3036->3086 3524->3037 6560->6123 2111->1612 solved 193 over 0
step +G2 3089->3098 3529->3077 6618->6175 2106->1609 solved 193 over 0
bracket 7260->7144 3604->3604 10864->10748 1730->1730 solved 193 over 0
bracket +G2 6837->6801 3650->3650 10487->10451 1717->1717 solved 193 over 0
both 7239->7118 3515->3515 10754->10633 1529->1529 solved 193 over 0
both +G2 7130->7109 3463->3463 10593->10572 1504->1504 solved 193 over 0
project 2806->3029 3220->3198 6026->6227 1823->1758 solved 193 over 0
project +G2 2782->3089 3169->3214 5951->6303 1780->1749 solved 193 over 0
safe 3036->3086 3390->3037 6426->6123 1977->1612 solved 193 over 0
safe +G2 3089->3098 3392->3077 6481->6175 1969->1609 solved 193 over 0
credit 3568->4208 3020->3038 6588->7246 1044->1064 solved 193 over 0
credit +G2 3799->4403 3064->3053 6863->7456 1044->1064 solved 193 over 0
VERDICTS
proposed rule APS 2806->3029 (Z2 ✗) CHA 3220->3198 (Z1 ✓) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 6227 vs Chandrupatla APS 26/72/55 p=0.0017 not accepted
proposed rule + G2 APS 2782->3089 (Z2 ✗) CHA 3169->3214 (Z1 ✗) Z3 ✓ (0 viol, 0 cells <193) Z4 ✓ both 6303 vs Chandrupatla APS 27/70/56 p=0.0019 not accepted
nine functions, projection, no gate -> flat gate, both sets:
cbrt 18003 -> 18270
cosine 19741 -> 15910
exp_abs 6652 -> 7104
exp_sq 19786 -> 14298
rat_sq 19793 -> 14565
ratio 6026 -> 6227
ratio_soft 9352 -> 9690
rational 6823 -> 7777
sqrt 13388 -> 13608
+9
View File
@@ -0,0 +1,9 @@
group model steps flagged share
APS 1275 276 21.6%
CHA fun1 47 8 17.0%
CHA flat fun3-6 1251 670 53.6%
CHA fun7 0 0 0.0%
CHA other 174 63 36.2%
F1 flat > APS and flat > fun1: 53.6% vs 21.6% / 17.0% -> PASS
bar: m>=2 fires 0.2% canonical / 5.8% flat
+19 -1
View File
@@ -665,7 +665,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
"{'derived3', 'derived3_cap', 'bracket', 'far'}")
if space not in SPACES:
raise ValueError(f"unknown space {space!r}")
if prestep not in ("none", "progress", "slope", "band", "defect", "simpair"):
if prestep not in ("none", "progress", "slope", "band", "defect", "simpair", "flat"):
raise ValueError(f"unknown prestep {prestep!r}")
if prestep in ("band", "defect", "simpair") and scale not in (
"derived3", "derived3_cap", "derived3_m", "bracket", "far"):
@@ -718,6 +718,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
dir_changed = 0
slope = 0.0
slope_prev = None
last_model = False # was the step just evaluated the model's own? (flat gate)
if stats is not None:
stats['forced'] = 0
stats['pre_refused'] = 0
@@ -725,6 +726,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
stats['dir_changed'] = 0
while abs(B - A) > xtol:
model_target = None
if sg.bisect_before_step(abs(B - A)):
x_new = 0.5 * (A + B)
forced += 1
@@ -886,6 +888,18 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
x_prev2, f_prev2):
step = 0.5 * (A + B) - x
pre_refused += 1
if (step is None and prestep == "flat" and last_model
and f_prev != 0.0 and fx / f_prev >= 0.25):
# PREREG_flat_regime 2026-09-21. The last step was the model's
# own, it did not cross the root (r > 0), and it left r = f/f_prev
# >= 1/4 of |f|. Under a tangent step on an order-m approach
# r = (1 - 1/m)^m, and the step loses to a halving from m = 2 on,
# where r = (1 - 1/2)^2 = 1/4: bisection's 1/2, carried through
# the same formula, not a chosen number. So the model is losing
# here, and this evaluation is spent halving; the next step is
# the model's again and is judged by its own result.
step = 0.5 * (A + B) - x
pre_refused += 1
if step is None and prestep == "slope":
# PRE-STEP GATE ON SHAPE (PREREG 2026-09-21). The step trusts the
# local slope, so the question of trust is whether that slope has
@@ -941,6 +955,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
reach = abs(far - x)
step = (longer if abs(longer) <= reach
else math.copysign(reach, step))
model_target = x + step # the model's own proposal
if stats is not None and "trace" in stats:
# DIAGNOSTIC HOOK, behaviour-neutral: records the state each
# step was taken from, so another model can be evaluated on the
@@ -978,6 +993,9 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
stats['forced'] = forced; stats['pre_refused'] = pre_refused; stats['triple_changed'] = triple_changed; stats['dir_changed'] = dir_changed
return x_new, g.n, abs(B - A) <= xtol
# the flat gate judges only the model's own steps: a midpoint from a gate or a
# step moved by the safeguard says nothing about the model
last_model = model_target is not None and x_new == model_target
w_before = abs(B - A)
fnew = g(x_new)
sg.j += 1 # one step of the bisection budget is spent
+1
View File
File diff suppressed because one or more lines are too long
+29 -3
View File
@@ -219,6 +219,29 @@ def _preflight_extrap_mode():
raise SystemExit("extrapolate preflight FAILED: refusing to report zeros")
def build_grid_flat(smoke):
"""PREREG_flat_regime_2026-09-21 stage 2: the flat gate (prestep='flat') in pairs,
on the proposed rule and on the proposed rule with G2 (extrapolate='pattern')."""
x, _n, ok = pure_root(lambda t: t - 1.0, 0.0, 3.0, 1e-10, 100, similarity="ratio",
scale="derived3", guard="project", prestep="flat")
if not (ok and abs(x - 1.0) < 1e-8):
raise SystemExit("prestep=flat preflight FAILED: refusing to report zeros")
guards = ("project", "credit") if smoke else GUARD_MODES
specs = []
for gu in guards:
for ext in ("none", "pattern"):
for pre in ("none", "flat"):
specs.append(("pure", "ratio", "derived3", gu, "x", pre, "recent",
"distance", "none", ext))
sims = ["sqrt"] if smoke else [s for s in sorted(PURE_SIMS) if s != "ratio"]
for sim in sims:
for gu in guards:
for pre in ("none", "flat"):
specs.append(("pure", sim, "derived3", gu, "x", pre, "recent",
"distance", "none", "none"))
return specs
def build_grid_extrap2(smoke):
"""PREREG_extrapolation_gates_2026-09-21: the same cells as build_grid_extrap, every
one in all five modes (none, A, G1, G2, G3)."""
@@ -388,10 +411,12 @@ def main():
decmode = "--decision" in sys.argv # slot 2: the reading in the DECISION place
extmode = "--extrap" in sys.argv # A in the method: step extrapolation
ext2mode = "--extrap2" in sys.argv # gates G1-G3 on the lengthening
flatmode = "--flat" in sys.argv # the flat-regime gate
combomode = "--combo" in sys.argv # modes A and B together
pointsmode = "--points" in sys.argv # mode A: triple by shape
dirmode = "--direction" in sys.argv # mode B: far end by dissimilarity
specs = (build_grid_extrap2(smoke) if ext2mode else
specs = (build_grid_flat(smoke) if flatmode else
build_grid_extrap2(smoke) if ext2mode else
build_grid_extrap(smoke) if extmode else
build_grid_decision(smoke) if decmode else
build_grid_order(smoke) if ordermode else
@@ -417,8 +442,9 @@ def main():
# the published sweep_full.json is what verify_article.py checks the paper
# against, so the log grid never writes into it
if ext2mode or extmode or decmode or ordermode or capmode or combomode or pointsmode or dirmode:
base = ("sweep_extrap2" if ext2mode else
if flatmode or ext2mode or extmode or decmode or ordermode or capmode or combomode or pointsmode or dirmode:
base = ("sweep_flat" if flatmode else
"sweep_extrap2" if ext2mode else
"sweep_extrap" if extmode else
"sweep_decision" if decmode else
"sweep_order" if ordermode else
+52
View File
@@ -0,0 +1,52 @@
"""Pins for PREREG_flat_regime_2026-09-21.md: the flat gate (prestep='flat')."""
from __future__ import annotations
import math
import pytest
from simroot.pure import pure_root
XTOL, MAXFEV = 1e-12, 200
PROBS = (
(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: 6.0 * (t - 2.0) ** 5, 0.0, 10.0),
(lambda t: t ** 19, -10.0, 100.0),
)
@pytest.mark.parametrize("f,a,b", PROBS)
@pytest.mark.parametrize("guard", ("project", "credit", "safe"))
def test_the_default_is_untouched(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,
prestep="none")
assert ref == off
@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_gate(f, a, b, guard, ext):
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard=guard, prestep="flat", 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_gate_never_fires_where_the_model_is_exact():
"""On a straight line the model's step lands on the root: r = 0, never >= 1/4."""
st = {}
pure_root(lambda t: 3.0 * t - 1.0, -2.0, 5.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep="flat", stats=st)
assert st["pre_refused"] == 0
def test_the_gate_fires_on_a_pure_power():
"""On x^9 the tangent step leaves (8/9)^9 = 0.35 of |f| on the same side."""
st = {}
pure_root(lambda t: t ** 9, -1.0, 2.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep="flat", stats=st)
assert st["pre_refused"] > 0