A' code frozen BEFORE the corpus-4 run (PREREG_close_sub): close (borrowed Dekker/Brent tolerance step, only after a kept promise) and sub (overshoot branch m <= 2/3; the shallow memory is not cleared by the exit - amendment documented). Development on the five seen corpora (uniform sign-change criterion): A' below A everywhere; vs Chandrupatla APS 103/31, CHA 31/10, new-1 109/65, Roots.jl 44/20 p=0.004, applied 48/32 p=0.09 with total 1382 vs 1380. Tests: 1223 passed (full), 358 (gate files).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
vvs
2026-09-21 20:02:43 +01:00
co-authored by Claude Opus 5
parent 657df10634
commit 8027d7f5ef
6 changed files with 255 additions and 3 deletions
+13
View File
@@ -48,3 +48,16 @@ arcsinh) — целевой для `close`**. Успех — смена знак
«A′ переносится» — F1, F2, F3 одновременно. Сообщается также вывод **без целевых классов** «A′ переносится» — F1, F2, F3 одновременно. Сообщается также вывод **без целевых классов**
(D1, D2, D4, D5), против Брента и TOMS748, и A′ на всех увиденных корпусах (описательно). (D1, D2, D4, D5), против Брента и TOMS748, и A′ на всех увиденных корпусах (описательно).
## Поправка из разработки (до прогона на корпусе 4)
1. **`close` только для достоверного обещания:** шаг на xtol/2 делается, лишь если предыдущий шаг
модели сдержал своё обещание (|f| упала ниже порога флага ¼). Без этого на x¹⁹ из увиденного
набора в начале прогона наклон, в котором доминирует f(100) = 10³⁸, обещает корень в x = −10, и
закрытие заменяло середину почти повторными точками (23 → 32). Новой константы нет — тот же ¼.
2. ~~**Выход снимает и пологую память**~~ — **ОТМЕНЕНО** той же разработкой: правило выхода («ближе к
прямой, чем к нулю») отличает плоский корень от простого, но у корня порядка m < 1 f далеко от
нуля с обеих сторон — выход срабатывает ложно; сохранённая пологая память возвращает режим на
ближайшем перелёте (√|x|·sgn: 19 с памятью, 65 без). Пологая память выходом НЕ снимается.
Обе поправки сделаны на увиденных корпусах; корпус 4 ещё не запускался.
+7
View File
@@ -0,0 +1,7 @@
SEEN corpora (development, descriptive): totals; A' vs Chandrupatla w/t/l
APS base 2634 A 2380 Aprime 2259 Aprime-close 2389 Aprime-sub 2253 chandrupatla 2595 brent 2707 toms748 2635 A' vs Ch 103/20/31 p=3.2e-10
CHA base 2357 A 1109 Aprime 1074 Aprime-close 1109 Aprime-sub 1074 chandrupatla 1505 brent 3238 toms748 3111 A' vs Ch 31/4/10 p=0.0015
NEW base 5388 A 3380 Aprime 3289 Aprime-close 3387 Aprime-sub 3282 chandrupatla 3717 brent 6391 toms748 5727 A' vs Ch 109/32/65 p=0.0011
RJL base 1888 A 1464 Aprime 1371 Aprime-close 1449 Aprime-sub 1387 chandrupatla 1566 brent 2455 toms748 2338 A' vs Ch 44/14/20 p=0.0037
APP base 1588 A 1577 Aprime 1382 Aprime-close 1512 Aprime-sub 1447 chandrupatla 1380 brent 1502 toms748 1757 A' vs Ch 48/52/32 p=0.093
fourth done
+44 -3
View File
@@ -764,19 +764,21 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# category variables below then carry the same string the old tests compared. # category variables below then carry the same string the old tests compared.
if "+" in prestep: if "+" in prestep:
parts = prestep.split("+") parts = prestep.split("+")
cats = ({"defect"}, {"contra"}, {"exp"}, {"half"}, {"flatanalog", "flatanalogmem", "flatanalogpt", cats = ({"defect"}, {"contra"}, {"exp"}, {"half"}, {"close"}, {"sub"},
{"flatanalog", "flatanalogmem", "flatanalogpt",
"flatanalogmempt"}) "flatanalogmempt"})
if (len(parts) != len(set(parts)) or any(not any(p in c for c in cats) for p in parts) if (len(parts) != len(set(parts)) or any(not any(p in c for c in cats) for p in parts)
or any(sum(p in c for p in parts) > 1 for c in cats)): or any(sum(p in c for p in parts) > 1 for c in cats)):
raise ValueError(f"unknown composite prestep {prestep!r}") raise ValueError(f"unknown composite prestep {prestep!r}")
if "exp" in parts and not any(p.startswith("flatanalog") for p in parts): if (("exp" in parts or "sub" in parts)
and not any(p.startswith("flatanalog") for p in parts)):
# the translation limit changes how the analogy reads its order; without the # the translation limit changes how the analogy reads its order; without the
# flat regime there is no analogy to read (PREREG_flat_exp_limit) # flat regime there is no analogy to read (PREREG_flat_exp_limit)
raise ValueError("prestep component 'exp' needs a flatanalog* component") raise ValueError("prestep component 'exp' needs a flatanalog* component")
elif prestep not in ("none", "progress", "slope", "band", "defect", "simpair", "flat", elif prestep not in ("none", "progress", "slope", "band", "defect", "simpair", "flat",
"flat2", "flatcreep", "flatstick", "flatstickmid", "flatstickexit", "flat2", "flatcreep", "flatstick", "flatstickmid", "flatstickexit",
"flatjudge", "flatanalog", "flatanalogmem", "contra", "flatjudge", "flatanalog", "flatanalogmem", "contra",
"flatanalogpt", "flatanalogmempt", "half"): "flatanalogpt", "flatanalogmempt", "half", "close"):
raise ValueError(f"unknown prestep {prestep!r}") raise ValueError(f"unknown prestep {prestep!r}")
parts = prestep.split("+") parts = prestep.split("+")
pre_dec = next((p for p in parts if p in ("band", "defect", "simpair")), "none") pre_dec = next((p for p in parts if p in ("band", "defect", "simpair")), "none")
@@ -788,6 +790,8 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
pre_contra = "contra" in parts pre_contra = "contra" in parts
pre_exp = "exp" in parts # PREREG_flat_exp_limit: translation similarity, m = inf pre_exp = "exp" in parts # PREREG_flat_exp_limit: translation similarity, m = inf
pre_half = "half" in parts # PREREG_half_contra: the half promised vs the bracket pre_half = "half" in parts # PREREG_half_contra: the half promised vs the bracket
pre_close = "close" in parts # PREREG_close_sub: the tolerance step (borrowed)
pre_sub = "sub" in parts # PREREG_close_sub: the overshoot branch, m <= 2/3
if pre_dec != "none" and scale not in ( if pre_dec != "none" and scale not in (
"derived3", "derived3_cap", "derived3_m", "bracket", "far"): "derived3", "derived3_cap", "derived3_m", "bracket", "far"):
# the decision reads a TRIPLE; under the two-point scale there is no third point # the decision reads a TRIPLE; under the two-point scale there is no third point
@@ -847,6 +851,8 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
analogy_seen = False # flatanalogmem: the run has been judged analogous to its past analogy_seen = False # flatanalogmem: the run has been judged analogous to its past
analogy_m = math.inf # flatanalog*pt: the order read from the latest analogous pair analogy_m = math.inf # flatanalog*pt: the order read from the latest analogous pair
regime_target = None # flatanalog*pt: the point the regime step aimed at regime_target = None # flatanalog*pt: the point the regime step aimed at
shallow_seen = False # sub: the run has been judged analogous with m <= 2/3
shallow_m = math.inf # sub: the order of that pair
if stats is not None: if stats is not None:
stats['forced'] = 0 stats['forced'] = 0
stats['pre_refused'] = 0 stats['pre_refused'] = 0
@@ -1079,15 +1085,32 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
and fx / f_prev >= 0.25) and fx / f_prev >= 0.25)
m_pair = _analogy_order(cur, configs, translation=pre_exp) m_pair = _analogy_order(cur, configs, translation=pre_exp)
steep = m_pair is not None and m_pair >= 2.0 steep = m_pair is not None and m_pair >= 2.0
# PREREG_close_sub 2026-09-21 (sub): the tangent step loses to a halving
# when |1 - 1/m| > 1/2 - for m > 2 (undershoot, the branch above) AND
# for m < 2/3 (overshoot). The overshoot shows as an unkept promise WITH
# a sign change; the pair's order says which branch it is.
shallow = (pre_sub and m_pair is not None
and 0.0 < m_pair <= 2.0 / 3.0)
flag_over = (pre_sub and sticky_m is None and last_model
and f_prev != 0.0 and fx / f_prev <= -0.25)
if flat_mem: if flat_mem:
if steep: if steep:
analogy_seen = True analogy_seen = True
analogy_m = m_pair analogy_m = m_pair
if shallow:
shallow_seen = True
shallow_m = m_pair
enter = flag and analogy_seen enter = flag and analogy_seen
if not enter and flag_over and shallow_seen:
enter = True
analogy_m = shallow_m
else: else:
enter = flag and steep enter = flag and steep
if enter: if enter:
analogy_m = m_pair analogy_m = m_pair
elif flag_over and shallow:
enter = True
analogy_m = m_pair
if enter: if enter:
sticky_m = math.inf sticky_m = math.inf
if stats is not None: if stats is not None:
@@ -1207,6 +1230,19 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
reach = abs(far - x) reach = abs(far - x)
step = (longer if abs(longer) <= reach step = (longer if abs(longer) <= reach
else math.copysign(reach, step)) else math.copysign(reach, step))
if (pre_close and abs(step) < 0.5 * xtol and last_model
and f_prev != 0.0 and abs(fx / f_prev) < 0.25):
# Only a CREDIBLE promise is closed on: the model's previous step
# kept its own promise (|f| fell below the flag's 1/4). Measured in
# development on x^19: at the start, a slope dominated by f(100) =
# 1e38 promises the root at x = -10, and closing on that promise
# replaced the midpoint by near-duplicate points (23 -> 32).
# PREREG_close_sub 2026-09-21 (close) - BORROWED: Dekker (1969) and
# Brent (1973) step at least the tolerance. A model promising the
# root closer than xtol/2 is taken at its word one step further: the
# new point lands past the root and the bracket closes to the
# tolerance, instead of being halved down from the far end.
step = math.copysign(0.5 * xtol, far - x)
model_target = x + step # the model's own proposal model_target = x + step # the model's own proposal
if stats is not None and "trace" in stats: if stats is not None and "trace" in stats:
# DIAGNOSTIC HOOK, behaviour-neutral: records the state each # DIAGNOSTIC HOOK, behaviour-neutral: records the state each
@@ -1272,6 +1308,11 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# flatanalogmem: "linear" refutes "flat" - the remembered analogy is # flatanalogmem: "linear" refutes "flat" - the remembered analogy is
# cleared and must be established anew (PREREG_flat_analogy_mem) # cleared and must be established anew (PREREG_flat_analogy_mem)
analogy_seen = False analogy_seen = False
# NOT shallow_seen (PREREG_close_sub, amendment): the exit judgment - f nearer
# the line than 0 - tells a flat root from a simple one; at a root of order
# m < 1 f is far from 0 on both sides, the exit fires falsely, and keeping the
# shallow memory lets the regime resume at the next overshoot (development:
# sqrt|x| sgn 19 with it, 65 without)
if stats is not None: if stats is not None:
stats['stick_exits'] = stats.get('stick_exits', 0) + 1 stats['stick_exits'] = stats.get('stick_exits', 0) + 1
if prestep == "flatjudge": if prestep == "flatjudge":
+152
View File
@@ -0,0 +1,152 @@
"""PREREG_close_sub_2026-09-21: A' = A + close + sub against A, its two ablations and the
library rivals.
python -u sweep_fourth.py --seen development: the five SEEN corpora (descriptive)
python -u sweep_fourth.py --fourth the ONE check on corpus_fourth.py -> sweep_fourth.json
python -u sweep_fourth.py --report verdicts from sweep_fourth.json
"""
from __future__ import annotations
import json
import math
import sys
from multiprocessing import Pool
from corpus_roots_jl import solved
from sweep_full import MAXFEV, XTOL, load_problems, make_method
from sweep_oos import CONFIGS as OOS
from sweep_oos import sign_p
def spec(pre):
return ("pure", "ratio", "derived3", "project", "x", pre, "recent", "distance", "none",
"pattern")
CONFIGS = {
"base": OOS["base"],
"A": OOS["A"],
"Aprime": spec("contra+flatanalogmempt+exp+half+close+sub"),
"Aprime-close": spec("contra+flatanalogmempt+exp+half+sub"),
"Aprime-sub": spec("contra+flatanalogmempt+exp+half+close"),
"chandrupatla": OOS["chandrupatla"],
"brent": OOS["brent"],
"toms748": OOS["toms748"],
}
def corpus(which):
"""[(set, id, f, a, b)] - success is always a sign change within 1e-6."""
out = []
if which == "fourth":
from corpus_fourth import build
out += [("D", pid, f, a, b) for _c, pid, f, a, b, _r in build()[0]]
return out
out += [(s, pid, f, a, b) for s, pid, f, a, b, _r in load_problems()]
from corpus_new import build as b1
out += [("NEW", pid, f, a, b) for _c, pid, f, a, b, _r in b1()[0]]
from corpus_roots_jl import build as b2
out += [("RJL", pid, f, a, b) for pid, f, a, b, ins in b2()[0] if not ins]
from corpus_applied import build as b3
out += [("APP", pid, f, a, b) for pid, f, a, b in b3()[0]]
return out
def evaluate(job):
name, which = job
import random
import scipy.optimize._tstutils as T
method = make_method(CONFIGS[name])
res = {}
for s, pid, f, a, b in corpus(which):
T._f6_cache.clear()
random.seed(20260921)
try:
x, n, conv = method(f, a, b, XTOL, MAXFEV)
x = float(x)
except Exception:
x, n, conv = float("nan"), MAXFEV, False
ok = bool(conv and solved(f, x))
over = ok and int(n) > 2 * math.ceil(math.log2(abs(b - a) / XTOL)) + 4
res.setdefault(s, {})[pid] = [int(n), ok, bool(over)]
return name, res
def cost(v):
return v[0] if v[1] else MAXFEV
def h2h(r, o, s, keep=lambda p: True):
ps = [p for p in r[s] if keep(p)]
w = sum(cost(r[s][p]) < cost(o[s][p]) for p in ps)
l = sum(cost(r[s][p]) > cost(o[s][p]) for p in ps)
return w, len(ps) - w - l, l
def tot(r, s, keep=lambda p: True):
return sum(cost(v) for p, v in r[s].items() if keep(p))
def report_seen(R):
print("SEEN corpora (development, descriptive): totals; A' vs Chandrupatla w/t/l")
for s in ("APS", "CHA", "NEW", "RJL", "APP"):
w, t, l = h2h(R["Aprime"], R["chandrupatla"], s)
print(f" {s:<4} " + " ".join(f"{k} {tot(R[k], s)}" for k in CONFIGS)
+ f" A' vs Ch {w}/{t}/{l} p={sign_p(w, l):.2g}")
def report_fourth(R):
s, ch, ap = "D", R["chandrupatla"], R["Aprime"]
print("FOURTH corpus (the one check)")
for k in CONFIGS:
r = R[k]
print(f" {k:<14} total {tot(r, s):6d} solved {sum(v[1] for v in r[s].values())}/"
f"{len(r[s])} violations {sum(v[2] for v in r[s].values())}")
w, t, l = h2h(ap, ch, s)
f1 = tot(ap, s) < tot(ch, s)
f2 = w > l and sign_p(w, l) < 0.05
f3 = (sum(v[2] for v in ap[s].values()) == 0
and sum(v[1] for v in ap[s].values()) >= sum(v[1] for v in ch[s].values()))
f4 = tot(ap, s) < tot(R["A"], s)
print(f" F1 {'✓' if f1 else '✗'} ({tot(ap, s)} vs {tot(ch, s)}, "
f"{100 * (tot(ap, s) - tot(ch, s)) / tot(ch, s):+.1f}%) F2 {'✓' if f2 else '✗'} "
f"({w}/{t}/{l} p={sign_p(w, l):.2g}) F3 {'✓' if f3 else '✗'} F4 {'✓' if f4 else '✗'} "
f"(A' {tot(ap, s)} vs A {tot(R['A'], s)}) -> "
+ ("A' TRANSFERS" if f1 and f2 and f3 else "A' does NOT transfer"))
for comp in ("close", "sub"):
d = tot(R[f"Aprime-{comp}"], s) - tot(ap, s)
print(f" ablation - {comp}: {d:+d} ({'earned' if d > 0 else 'NOT earned'})")
nt = lambda p: p[:2] in ("D1", "D2", "D4", "D5")
w, t, l = h2h(ap, ch, s, nt)
print(f" without the targeted classes (D1 D2 D4 D5): A' {tot(ap, s, nt)} vs Ch {tot(ch, s, nt)}"
f" {w}/{t}/{l} p={sign_p(w, l):.2g}")
for rn in ("brent", "toms748"):
w, t, l = h2h(ap, R[rn], s)
print(f" vs {rn:<8} {tot(ap, s)} vs {tot(R[rn], s)} {w}/{t}/{l} p={sign_p(w, l):.2g}")
print(" per class: A' / A / Chandrupatla / Brent / TOMS748 (A' vs Ch w/t/l)")
for cls in ("D1", "D2", "D3", "D4", "D5", "D6"):
k = lambda p, c=cls: p.startswith(c)
w, t, l = h2h(ap, ch, s, k)
print(f" {cls}: " + " / ".join(f"{tot(R[n], s, k):5d}" for n in
("Aprime", "A", "chandrupatla", "brent", "toms748"))
+ f" {w}/{t}/{l}")
def main():
which = "fourth" if "--fourth" in sys.argv else ("seen" if "--seen" in sys.argv else None)
if which is not None:
with Pool(len(CONFIGS)) as pool:
R = dict(pool.map(evaluate, [(n, which) for n in CONFIGS]))
with open(f"sweep_fourth_{which}.json", "w", encoding="utf8") as fh:
json.dump(R, fh)
else:
which = "fourth"
with open(f"sweep_fourth_{which}.json", encoding="utf8") as fh:
R = json.load(fh)
(report_fourth if which == "fourth" else report_seen)(R)
print("fourth done")
if __name__ == "__main__":
main()
File diff suppressed because one or more lines are too long
+38
View File
@@ -449,3 +449,41 @@ def test_half_is_silent_on_a_line_and_breaks_the_fun9_flank():
guard="project", prestep=p)[1] guard="project", prestep=p)[1]
for p in ("defect+flatanalogmempt+exp", "defect+flatanalogmempt+exp+half")] for p in ("defect+flatanalogmempt+exp", "defect+flatanalogmempt+exp+half")]
assert n[1] < n[0], n assert n[1] < n[0], n
# ---- PREREG_close_sub_2026-09-21: bracket closing (borrowed) and the overshoot branch ----
APRIME = "contra+flatanalogmempt+exp+half+close+sub"
@pytest.mark.parametrize("bad", ("sub", "defect+sub", "contra+sub"))
def test_sub_needs_the_flat_regime(bad):
with pytest.raises(ValueError):
pure_root(lambda t: t - 1.0, 0.0, 3.0, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep=bad)
@pytest.mark.parametrize("f,a,b", PROBS)
@pytest.mark.parametrize("guard", ("project", "credit"))
@pytest.mark.parametrize("pre", ("close", APRIME))
def test_the_guarantee_holds_with_close_and_sub(f, a, b, guard, pre):
x, n, ok = pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard=guard, prestep=pre, extrapolate="pattern")
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 _n(f, a, b, pre):
return pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard="project", prestep=pre, extrapolate="pattern")[1]
def test_close_and_sub_measured_in_development():
"""Measured before pinning: sin[3,4] 24 -> 7, sqrt|x| sgn 84 -> 19, x^19 unchanged."""
a_ = "contra+flatanalogmempt+exp+half"
assert _n(math.sin, 3.0, 4.0, APRIME) < _n(math.sin, 3.0, 4.0, a_)
sq = lambda x: math.sqrt(abs(x)) * (0.0 if x == 0 else math.copysign(1.0, x)) # noqa: E731
assert _n(sq, -1 / 3, 1.0, APRIME) < _n(sq, -1 / 3, 1.0, a_)
p19 = lambda x: x ** 19 # noqa: E731
assert _n(p19, -10.0, 100.0, APRIME) == _n(p19, -10.0, 100.0, a_)
assert _n(lambda x: 3.0 * x - 1.0, -2.0, 5.0, APRIME) == 4