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:
@@ -48,3 +48,16 @@ arcsinh) — целевой для `close`**. Успех — смена знак
|
||||
|
||||
«A′ переносится» — F1, F2, F3 одновременно. Сообщается также вывод **без целевых классов**
|
||||
(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 ещё не запускался.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
if "+" in prestep:
|
||||
parts = prestep.split("+")
|
||||
cats = ({"defect"}, {"contra"}, {"exp"}, {"half"}, {"flatanalog", "flatanalogmem", "flatanalogpt",
|
||||
cats = ({"defect"}, {"contra"}, {"exp"}, {"half"}, {"close"}, {"sub"},
|
||||
{"flatanalog", "flatanalogmem", "flatanalogpt",
|
||||
"flatanalogmempt"})
|
||||
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)):
|
||||
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
|
||||
# flat regime there is no analogy to read (PREREG_flat_exp_limit)
|
||||
raise ValueError("prestep component 'exp' needs a flatanalog* component")
|
||||
elif prestep not in ("none", "progress", "slope", "band", "defect", "simpair", "flat",
|
||||
"flat2", "flatcreep", "flatstick", "flatstickmid", "flatstickexit",
|
||||
"flatjudge", "flatanalog", "flatanalogmem", "contra",
|
||||
"flatanalogpt", "flatanalogmempt", "half"):
|
||||
"flatanalogpt", "flatanalogmempt", "half", "close"):
|
||||
raise ValueError(f"unknown prestep {prestep!r}")
|
||||
parts = prestep.split("+")
|
||||
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_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_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 (
|
||||
"derived3", "derived3_cap", "derived3_m", "bracket", "far"):
|
||||
# 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_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
|
||||
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:
|
||||
stats['forced'] = 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)
|
||||
m_pair = _analogy_order(cur, configs, translation=pre_exp)
|
||||
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 steep:
|
||||
analogy_seen = True
|
||||
analogy_m = m_pair
|
||||
if shallow:
|
||||
shallow_seen = True
|
||||
shallow_m = m_pair
|
||||
enter = flag and analogy_seen
|
||||
if not enter and flag_over and shallow_seen:
|
||||
enter = True
|
||||
analogy_m = shallow_m
|
||||
else:
|
||||
enter = flag and steep
|
||||
if enter:
|
||||
analogy_m = m_pair
|
||||
elif flag_over and shallow:
|
||||
enter = True
|
||||
analogy_m = m_pair
|
||||
if enter:
|
||||
sticky_m = math.inf
|
||||
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)
|
||||
step = (longer if abs(longer) <= reach
|
||||
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
|
||||
if stats is not None and "trace" in stats:
|
||||
# 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
|
||||
# cleared and must be established anew (PREREG_flat_analogy_mem)
|
||||
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:
|
||||
stats['stick_exits'] = stats.get('stick_exits', 0) + 1
|
||||
if prestep == "flatjudge":
|
||||
|
||||
+152
@@ -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
@@ -449,3 +449,41 @@ def test_half_is_silent_on_a_line_and_breaks_the_fun9_flank():
|
||||
guard="project", prestep=p)[1]
|
||||
for p in ("defect+flatanalogmempt+exp", "defect+flatanalogmempt+exp+half")]
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user