PREREG_flat_twice outcome: stage 1 passed (twice-in-a-row fires on 27.8% of model steps on the flat families, 8.7% on APS, 4.3% on fun1; flat/APS ratio 3.20 against the single flag's 2.47), stage 2 FAILED: under the projection APS 2806 -> 2803 (W2 holds, the per-problem edge over Chandrupatla kept at 83/28/42) but CHA 3220 -> 3341 and the flat families 1823 -> 1975 (W1, W4 fail); with G2 the same. Under safe/step the twice gate is inert (3390 -> 3388) where the single one gave 3037.

Mechanism: the flat cycle is undershoot, undershoot, crossing, near-empty step. The single flag fires after the first undershoot and replaces the second - a useless step; the twice flag fires after the second and replaces the CROSSING, the one step of the cycle that collapses the bracket. The second undershoot's r is ~0.26, next to the 1/4 threshold, so the pair often does not even form. Again a detectability gain that did not carry to run cost. Next candidate (not pre-registered): the unkept promise AND a creep - the same step moving the same way as the previous one.

Removed a vacuous pin I had written (s2 <= max(s1, s2)). Regression on the branch: 935 pass twice; the only red test is the paper-number check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
vvs
2026-09-21 13:45:20 +01:00
co-authored by Claude Opus 5
parent 6a8bb2315f
commit 9884b21204
7 changed files with 156 additions and 16 deletions
+8 -7
View File
@@ -9,8 +9,8 @@ import json
from analyze_extrap import FAMILY, FLAT, fam_sum, h2h, load, sign_p from analyze_extrap import FAMILY, FLAT, fam_sum, h2h, load, sign_p
def main(): def main(path="sweep_flat.json", gate="flat"):
rows = load("sweep_flat.json") rows = load(path)
cha = {r["label"]: r for r in load("sweep_full.json")}["chandrupatla"] cha = {r["label"]: r for r in load("sweep_full.json")}["chandrupatla"]
cell = {} cell = {}
for r in rows: for r in rows:
@@ -19,7 +19,7 @@ def main():
print("tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6") 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 gu in ("none", "step", "bracket", "both", "project", "safe", "credit"):
for ext in ("none", "pattern"): for ext in ("none", "pattern"):
a, b = cell[("ratio", gu, ext, "none")], cell[("ratio", gu, ext, "flat")] a, b = cell[("ratio", gu, ext, "none")], cell[("ratio", gu, ext, gate)]
print(f" {gu:<8} {'+G2' if ext == 'pattern' else ' '} " print(f" {gu:<8} {'+G2' if ext == 'pattern' else ' '} "
f"{a['APS']['total']:5d}->{b['APS']['total']:<5d} {a['CHA']['total']:5d}->" 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['CHA']['total']:<5d} {a['APS']['total'] + a['CHA']['total']:5d}->"
@@ -28,8 +28,8 @@ def main():
f"over {b['APS']['over'] + b['CHA']['over']}") f"over {b['APS']['over'] + b['CHA']['over']}")
print("\nVERDICTS") print("\nVERDICTS")
for ext, name in (("none", "proposed rule"), ("pattern", "proposed rule + G2")): for ext, name in (("none", "proposed rule"), ("pattern", "proposed rule + G2")):
a, b = cell[("ratio", "project", ext, "none")], cell[("ratio", "project", ext, "flat")] a, b = cell[("ratio", "project", ext, "none")], cell[("ratio", "project", ext, gate)]
fam = [r for k, r in cell.items() if k[3] == "flat" and k[1] in FAMILY] fam = [r for k, r in cell.items() if k[3] == gate and k[1] in FAMILY]
viol = sum(r["APS"]["over"] + r["CHA"]["over"] for r in fam) 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) low = sum(1 for r in fam if r["APS"]["solved"] + r["CHA"]["solved"] < 193)
z1 = b["CHA"]["total"] < a["CHA"]["total"] z1 = b["CHA"]["total"] < a["CHA"]["total"]
@@ -44,10 +44,11 @@ def main():
f"p={sign_p(w, l):.2g}" + (" ACCEPTED" if z1 and z2 and z3 else " not accepted")) 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:") print("\nnine functions, projection, no gate -> flat gate, both sets:")
for sim in sorted({k[0] for k in cell}): for sim in sorted({k[0] for k in cell}):
a, b = cell[(sim, "project", "none", "none")], cell[(sim, "project", "none", "flat")] a, b = cell[(sim, "project", "none", "none")], cell[(sim, "project", "none", gate)]
print(f" {sim:<11} {a['APS']['total'] + a['CHA']['total']:6d} -> " print(f" {sim:<11} {a['APS']['total'] + a['CHA']['total']:6d} -> "
f"{b['APS']['total'] + b['CHA']['total']:6d}") f"{b['APS']['total'] + b['CHA']['total']:6d}")
if __name__ == "__main__": if __name__ == "__main__":
main() import sys
main(*sys.argv[1:3]) if len(sys.argv) > 2 else main()
+89
View File
@@ -0,0 +1,89 @@
sweep: 140 configurations x 199 problems (FULL)
wrote sweep_flat2.json (8s total)
====================================================================================
APS: 154 problems (top 20 of 140)
====================================================================================
configuration solved total fev over 2x
------------------------------------------------------------------------------------
pure+extP+flat2.ratio.derived3.project 153/154 2781 0
pure+extP+flat2.ratio.derived3.none 153/154 2781 0
pure+extP.ratio.derived3.project 153/154 2782 0
pure+extP.ratio.derived3.none 153/154 2782 0
flat2.ratio.derived3.none 153/154 2803 0
flat2.ratio.derived3.project 153/154 2803 0
pure.ratio.derived3.none 153/154 2806 0
pure.ratio.derived3.project 153/154 2806 0
pure.ratio.derived3.step 153/154 3036 0
pure.ratio.derived3.safe 153/154 3036 0
flat2.ratio.derived3.step 153/154 3042 0
flat2.ratio.derived3.safe 153/154 3042 0
pure+extP.ratio.derived3.step 153/154 3089 0
pure+extP.ratio.derived3.safe 153/154 3089 0
pure+extP+flat2.ratio.derived3.safe 153/154 3097 0
pure+extP+flat2.ratio.derived3.step 153/154 3097 0
flat2.exp_abs.derived3.none 153/154 3257 0
flat2.exp_abs.derived3.project 153/154 3257 0
pure.exp_abs.derived3.none 153/154 3264 0
pure.exp_abs.derived3.project 153/154 3264 0
====================================================================================
CHA: 45 problems (top 20 of 140)
====================================================================================
configuration solved total fev over 2x
------------------------------------------------------------------------------------
flat2.cbrt.derived3.credit 40/45 3016 0
pure.cbrt.derived3.credit 40/45 3016 0
pure.ratio.derived3.credit 40/45 3020 0
flat2.ratio.derived3.credit 40/45 3040 0
pure.exp_abs.derived3.credit 40/45 3049 0
pure.ratio_soft.derived3.credit 40/45 3054 0
flat2.ratio_soft.derived3.credit 40/45 3054 0
pure+extP.ratio.derived3.credit 40/45 3064 0
flat2.exp_abs.derived3.credit 40/45 3066 0
pure+extP+flat2.ratio.derived3.credit 40/45 3084 0
pure.cosine.derived3.credit 40/45 3129 0
flat2.cosine.derived3.credit 40/45 3129 0
pure.exp_sq.derived3.credit 40/45 3130 0
flat2.exp_sq.derived3.credit 40/45 3130 0
pure.rat_sq.derived3.credit 40/45 3130 0
flat2.rat_sq.derived3.credit 40/45 3130 0
flat2.rational.derived3.credit 40/45 3130 0
pure.rational.derived3.credit 40/45 3130 0
pure.sqrt.derived3.credit 40/45 3130 0
flat2.sqrt.derived3.credit 40/45 3130 0
====================================================================================
THE STAGE-0C LAW ACROSS THE GRID
====================================================================================
scale=derived3 slope c=1 (linear) mean total 6829 mean solved 193.0/199
scale=derived3 slope c=0 (quadratic) mean total 19620 mean solved 193.0/199
tent, 3-point, pairs (no gate -> flat gate) APS CHA both flat fun3-6
none 2806->2803 4104->3571 6910->6374 2707->2205 solved 193 over 15
none +G2 2782->2781 3863->3585 6645->6366 2474->2217 solved 193 over 15
step 3036->3042 3524->3522 6560->6564 2111->2111 solved 193 over 15
step +G2 3089->3097 3529->3528 6618->6625 2106->2106 solved 193 over 15
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->2803 3220->3341 6026->6144 1823->1975 solved 193 over 0
project +G2 2782->2781 3169->3345 5951->6126 1780->1977 solved 193 over 0
safe 3036->3042 3390->3388 6426->6430 1977->1977 solved 193 over 0
safe +G2 3089->3097 3392->3386 6481->6483 1969->1964 solved 193 over 0
credit 3568->3603 3020->3040 6588->6643 1044->1064 solved 193 over 0
credit +G2 3799->3800 3064->3084 6863->6884 1044->1064 solved 193 over 0
VERDICTS
proposed rule APS 2806->2803 (Z2 ✓) CHA 3220->3341 (Z1 ✗) Z3 ✓ (0 viol, 0 cells <193) Z4 ✗ both 6144 vs Chandrupatla APS 83/28/42 p=0.00031 not accepted
proposed rule + G2 APS 2782->2781 (Z2 ✓) CHA 3169->3345 (Z1 ✗) Z3 ✓ (0 viol, 0 cells <193) Z4 ✗ both 6126 vs Chandrupatla APS 92/21/40 p=7e-06 not accepted
nine functions, projection, no gate -> flat gate, both sets:
cbrt 18003 -> 18006
cosine 19741 -> 18984
exp_abs 6652 -> 6858
exp_sq 19786 -> 16993
rat_sq 19793 -> 17677
ratio 6026 -> 6144
ratio_soft 9352 -> 9299
rational 6823 -> 6908
sqrt 13388 -> 13416
+9
View File
@@ -0,0 +1,9 @@
group model steps single twice
APS 1275 21.6% 8.7%
CHA fun1 47 17.0% 4.3%
CHA flat fun3-6 1251 53.6% 27.8%
CHA fun7 0 0.0% 0.0%
CHA other 174 36.2% 20.7%
T1 twice: flat 27.8% > APS 8.7% and > fun1 4.3% -> PASS
T2 flat/APS ratio: twice 3.20 vs single 2.47 -> PASS
+16 -1
View File
@@ -665,7 +665,8 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
"{'derived3', 'derived3_cap', 'bracket', 'far'}") "{'derived3', 'derived3_cap', 'bracket', 'far'}")
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"):
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"):
@@ -719,6 +720,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
slope = 0.0 slope = 0.0
slope_prev = None slope_prev = None
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)
if stats is not None: if stats is not None:
stats['forced'] = 0 stats['forced'] = 0
stats['pre_refused'] = 0 stats['pre_refused'] = 0
@@ -900,6 +902,14 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# the model's again and is judged by its own result. # the model's again and is judged by its own result.
step = 0.5 * (A + B) - x step = 0.5 * (A + B) - x
pre_refused += 1 pre_refused += 1
if step is None and prestep == "flat2" and unkept_run >= 2:
# PREREG_flat_twice 2026-09-21. The same unkept promise as
# "flat" (model step, no crossing, r >= 1/4), but only after it has
# failed TWICE IN A ROW: on a flat function the undershoot repeats,
# at a simple root a single failure is usually followed by fast
# convergence. Two is the fewest at which "repeats" is defined.
step = 0.5 * (A + B) - x
pre_refused += 1
if step is None and prestep == "slope": if step is None and prestep == "slope":
# PRE-STEP GATE ON SHAPE (PREREG 2026-09-21). The step trusts the # 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 # local slope, so the question of trust is whether that slope has
@@ -998,6 +1008,11 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
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)
fnew = g(x_new) fnew = g(x_new)
# 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:
unkept_run += 1
else:
unkept_run = 0
sg.j += 1 # one step of the bisection budget is spent sg.j += 1 # one step of the bisection budget is spent
sg.allow *= 0.5 sg.allow *= 0.5
x_prev2, f_prev2 = x_prev, f_prev x_prev2, f_prev2 = x_prev, f_prev
+1
View File
File diff suppressed because one or more lines are too long
+11 -8
View File
@@ -219,24 +219,24 @@ def _preflight_extrap_mode():
raise SystemExit("extrapolate preflight FAILED: refusing to report zeros") raise SystemExit("extrapolate preflight FAILED: refusing to report zeros")
def build_grid_flat(smoke): def build_grid_flat(smoke, gate="flat"):
"""PREREG_flat_regime_2026-09-21 stage 2: the flat gate (prestep='flat') in pairs, """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').""" 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", 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") scale="derived3", guard="project", prestep=gate)
if not (ok and abs(x - 1.0) < 1e-8): if not (ok and abs(x - 1.0) < 1e-8):
raise SystemExit("prestep=flat preflight FAILED: refusing to report zeros") raise SystemExit(f"prestep={gate} preflight FAILED: refusing to report zeros")
guards = ("project", "credit") if smoke else GUARD_MODES guards = ("project", "credit") if smoke else GUARD_MODES
specs = [] specs = []
for gu in guards: for gu in guards:
for ext in ("none", "pattern"): for ext in ("none", "pattern"):
for pre in ("none", "flat"): for pre in ("none", gate):
specs.append(("pure", "ratio", "derived3", gu, "x", pre, "recent", specs.append(("pure", "ratio", "derived3", gu, "x", pre, "recent",
"distance", "none", ext)) "distance", "none", ext))
sims = ["sqrt"] if smoke else [s for s in sorted(PURE_SIMS) if s != "ratio"] sims = ["sqrt"] if smoke else [s for s in sorted(PURE_SIMS) if s != "ratio"]
for sim in sims: for sim in sims:
for gu in guards: for gu in guards:
for pre in ("none", "flat"): for pre in ("none", gate):
specs.append(("pure", sim, "derived3", gu, "x", pre, "recent", specs.append(("pure", sim, "derived3", gu, "x", pre, "recent",
"distance", "none", "none")) "distance", "none", "none"))
return specs return specs
@@ -412,10 +412,12 @@ def main():
extmode = "--extrap" in sys.argv # A in the method: step extrapolation extmode = "--extrap" in sys.argv # A in the method: step extrapolation
ext2mode = "--extrap2" in sys.argv # gates G1-G3 on the lengthening ext2mode = "--extrap2" in sys.argv # gates G1-G3 on the lengthening
flatmode = "--flat" in sys.argv # the flat-regime gate flatmode = "--flat" in sys.argv # the flat-regime gate
flat2mode = "--flat2" in sys.argv # the flat gate, promise failed twice
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) if flatmode else specs = (build_grid_flat(smoke, "flat2") if flat2mode else
build_grid_flat(smoke) if flatmode else
build_grid_extrap2(smoke) if ext2mode else build_grid_extrap2(smoke) if ext2mode else
build_grid_extrap(smoke) if extmode else build_grid_extrap(smoke) if extmode else
build_grid_decision(smoke) if decmode else build_grid_decision(smoke) if decmode else
@@ -442,8 +444,9 @@ 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 flatmode or ext2mode or extmode or decmode or ordermode or capmode or combomode or pointsmode or dirmode: if flat2mode or flatmode or ext2mode or extmode or decmode or ordermode or capmode or combomode or pointsmode or dirmode:
base = ("sweep_flat" if flatmode else base = ("sweep_flat2" if flat2mode else
"sweep_flat" if flatmode else
"sweep_extrap2" if ext2mode else "sweep_extrap2" if ext2mode else
"sweep_extrap" if extmode else "sweep_extrap" if extmode else
"sweep_decision" if decmode else "sweep_decision" if decmode else
+22
View File
@@ -36,6 +36,28 @@ def test_the_guarantee_holds_with_the_gate(f, a, b, guard, ext):
assert n <= (2 * half + 3 if guard == "project" else half + 4), n assert n <= (2 * half + 3 if guard == "project" else half + 4), n
@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_twice_gate(f, a, b, guard, ext):
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard=guard, prestep="flat2", 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_twice_gate_is_silent_where_the_model_is_exact_and_fires_on_a_power():
st = {}
pure_root(lambda t: 3.0 * t - 1.0, -2.0, 5.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep="flat2", stats=st)
assert st["pre_refused"] == 0
st = {}
pure_root(lambda t: t ** 9, -1.0, 2.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep="flat2", stats=st)
assert st["pre_refused"] > 0
def test_the_gate_never_fires_where_the_model_is_exact(): 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.""" """On a straight line the model's step lands on the root: r = 0, never >= 1/4."""
st = {} st = {}