Why the analogy entry is late on the flat families (diagnostics only, method unchanged). At flag moments before entry: unlike-past 118, no-memory 7, m<2 2 - the order is not the bottleneck. The period-4 cycle: the flag rises in the phases whose configuration does NOT recur (the undershoot whose relative step shrinks every cycle, and the crossing); the recurring phases have the flag down and read the true order (fun4 = 6(x-2)^5: m ~ 4.9). The entry demands both at the same state. Remembering the analogy until the next flag: flat entry state 12.9 -> 8.2; problems entered APS 3 -> 8, fun9 0 -> 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
vvs
2026-09-21 14:58:20 +01:00
co-authored by Claude Opus 5
parent 1842eb0765
commit b7271a1ce4
4 changed files with 262 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
"""Consequence check for diag_analogy_sequence.py: the flag rises in the phases of the
period-4 cycle whose configuration does NOT recur (the undershoot whose relative step
shrinks every cycle, the crossing), while the recurring phases are the ones with the flag
down. The entry demands both AT THE SAME STATE, so it waits until a flag state happens
to recur.
Candidate (not in the method): the analogy is a property of the RUN, the flag of the
MOMENT - once any state has been analogous to its past with m >= 2, enter at the next
flag. Per problem, on traces of the proposed rule with NO regime (so both rules see the
same states): the state of entry under 'same state' and under 'analogy remembered', and
how many problems would enter at all, per group. Nothing in the method changes.
python -u diag_analogy_decoupled.py
"""
from __future__ import annotations
from collections import defaultdict
from simroot.pure import _analogous_and_steep, _config3, pure_root
from sweep_full import MAXFEV, XTOL, load_problems
FLAT = ("fun3", "fun4", "fun5", "fun6")
def entries(trace):
past, seen = [], False
same = remembered = None
for k, s in enumerate(trace):
cur = _config3(s["x"], s["fx"], s["xp"], s["fp"], s["xp2"], s["fp2"])
flag = s["fp"] != 0.0 and s["fx"] / s["fp"] >= 0.25
ana = _analogous_and_steep(cur, past)
if flag and ana and same is None:
same = k
if flag and (seen or ana) and remembered is None:
remembered = k
seen = seen or ana
if cur is not None:
past.append(cur)
return same, remembered
def main():
per = defaultdict(lambda: [0, 0, 0, 0, 0]) # problems, same, remembered, sum same, sum rem
for s, pid, f, a, b, _root in load_problems():
st = {"trace": []}
pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3",
guard="project", stats=st)
fam = pid.split(".")[0]
g = "APS" if s == "APS" else ("CHA-flat" if fam in FLAT else f"CHA-{fam}")
same, rem = entries(st["trace"])
p = per[g]
p[0] += 1
p[1] += same is not None
p[2] += rem is not None
if g == "CHA-flat" and same is not None and rem is not None:
p[3] += same
p[4] += rem
print(f"{'group':<10} {'problems':>8} {'enter: same state':>18} {'analogy remembered':>19}")
for g in sorted(per):
n, a_, b_, s1, s2 = per[g]
print(f"{g:<10} {n:8d} {a_:18d} {b_:19d}")
fl = per["CHA-flat"]
print(f"\nflat: mean entry state {fl[3] / fl[1]:.1f} (same state) -> "
f"{fl[4] / fl[1]:.1f} (analogy remembered)")
print("diag done")
if __name__ == "__main__":
main()
+99
View File
@@ -0,0 +1,99 @@
"""Why does the analogy entry come late on the flat families? (Valeri, 2026-09-21)
The entry is flag AND _analogous_and_steep(cur, memory). The method calls the second
only when the flag has risen on a model step (short-circuit `and`), so a spy on it sees
exactly the flag moments. At each one it records how many evaluations of f were spent
and which condition held back the entry:
no-config the last three points give no (xi, phi)
no-memory nothing to compare with yet
unlike-past the configuration is nearer to the line than to any past one
m<2 analogous, but the pair's similarity exponent is below 2 (value kept)
ENTER
Compared with flatstickexit, which enters at the first flag. Nothing in the method
changes; problems are the 20 flat CHA problems (fun3-6), proposed rule (projection).
python -u diag_analogy_late.py
"""
from __future__ import annotations
import math
from collections import Counter as Tally
import simroot.pure as P
from sweep_full import MAXFEV, XTOL, load_problems
FLAT = ("fun3", "fun4", "fun5", "fun6")
_orig = P._analogous_and_steep
LOG = []
CALLS = [0]
def reason(cur, past):
if cur is None:
return "no-config", None
if not past:
return "no-memory", None
xi, phi = cur[0], cur[1]
best = min(past, key=lambda q: math.hypot(xi - q[0], phi - q[1]))
d_past = math.hypot(xi - best[0], phi - best[1])
d_line = abs(phi - xi) / math.sqrt(2.0)
if not d_past < d_line:
return "unlike-past", (d_past, d_line)
lx, lf = cur[2] / best[2], cur[3] / best[3]
m = math.log(lf) / math.log(lx) if lx not in (0.0, 1.0) and lf > 0.0 else math.nan
return ("ENTER" if m >= 2.0 else "m<2"), m
def spy(cur, past):
ok = _orig(cur, past)
why, val = reason(cur, past)
LOG.append((CALLS[0], why, val, len(past), ok))
return ok
def counted(f):
def g(x):
CALLS[0] += 1
return f(x)
return g
def run(f, a, b, gate):
st = {}
CALLS[0] = 0
_x, n, _ok = P.pure_root(counted(f), a, b, XTOL, MAXFEV, similarity="ratio",
scale="derived3", guard="project", prestep=gate, stats=st)
return n
def main():
P._analogous_and_steep = spy
tally = Tally()
ms_before = []
print(f"{'problem':<10} {'exit: n':>7} {'analog: n':>9} {'first flag @':>12} "
f"{'entry @':>8} reasons before entry")
for s, pid, f, a, b, _root in load_problems():
if s != "CHA" or pid.split(".")[0] not in FLAT:
continue
n_exit = run(f, a, b, "flatstickexit")
LOG.clear()
n_an = run(f, a, b, "flatanalog")
first = LOG[0][0] if LOG else None
entry = next((e for e, why, *_ in LOG if why == "ENTER"), None)
before = [(why, val) for e, why, val, _, _ in LOG if entry is None or e < entry]
for why, val in before:
tally[why] += 1
if why == "m<2" and val is not None and math.isfinite(val):
ms_before.append(val)
print(f"{pid:<10} {n_exit:7d} {n_an:9d} {str(first):>12} {str(entry):>8} "
+ " ".join(why for why, _ in before))
print("\nreasons at flag moments before entry, all 20 problems:", dict(tally))
if ms_before:
ms = sorted(ms_before)
print("m read at analogous-but-refused moments:",
" ".join(f"{m:.2f}" for m in ms))
print("diag done")
if __name__ == "__main__":
main()
+58
View File
@@ -0,0 +1,58 @@
"""The state-by-state picture behind diag_analogy_late.py, for a few flat problems.
Every state the gate sees (trace hook, flatanalog, projection), in order:
n evaluations spent (the trace does not carry it; states are numbered instead)
flag r = f/f_prev >= 1/4 (the promise failed, sign kept)
xi, phi the configuration
ratio d_past / d_line (< 1 means analogous to the nearest past configuration)
lag how many states back that nearest past configuration is
m the pair's similarity exponent
Nothing in the method changes.
python -u diag_analogy_sequence.py fun6.3 fun4.1 fun3.4
"""
from __future__ import annotations
import math
import sys
from simroot.pure import _config3, pure_root
from sweep_full import MAXFEV, XTOL, load_problems
def show(pid, f, a, b):
st = {"trace": []}
pure_root(f, a, b, XTOL, MAXFEV, similarity="ratio", scale="derived3", guard="project",
prestep="flatanalog", stats=st)
print(f"\n== {pid} (state, flag, xi, phi, d_past/d_line, lag, m)")
past = []
for k, s in enumerate(st["trace"][:30]):
cur = _config3(s["x"], s["fx"], s["xp"], s["fp"], s["xp2"], s["fp2"])
flag = s["fp"] != 0.0 and s["fx"] / s["fp"] >= 0.25
if cur is None:
print(f" {k:3d} {'F' if flag else '.'} (no configuration)")
continue
line = abs(cur[1] - cur[0]) / math.sqrt(2.0)
if past:
j = min(range(len(past)), key=lambda i: math.hypot(cur[0] - past[i][0],
cur[1] - past[i][1]))
q = past[j]
ratio = math.hypot(cur[0] - q[0], cur[1] - q[1]) / line if line > 0 else math.inf
lx, lf = cur[2] / q[2], cur[3] / q[3]
m = (math.log(lf) / math.log(lx)) if lx not in (0.0, 1.0) and lf > 0 else math.nan
lag = len(past) - j
print(f" {k:3d} {'F' if flag else '.'} xi {cur[0]:+9.4f} phi {cur[1]:+10.4f} "
f"ratio {ratio:7.3f} lag {lag:2d} m {m:6.2f}")
else:
print(f" {k:3d} {'F' if flag else '.'} xi {cur[0]:+9.4f} phi {cur[1]:+10.4f} (no memory)")
past.append(cur)
def main(ids):
for s, pid, f, a, b, _root in load_problems():
if s == "CHA" and pid in ids:
show(pid, f, a, b)
if __name__ == "__main__":
main(sys.argv[1:] or ["fun6.3", "fun4.1"])
+36
View File
@@ -0,0 +1,36 @@
problem exit: n analog: n first flag @ entry @ reasons before entry
fun3.1 46 49 4 11 unlike-past unlike-past unlike-past unlike-past
fun3.2 48 53 4 16 unlike-past unlike-past unlike-past
fun3.3 58 71 4 17 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun3.4 64 82 4 22 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun3.5 77 76 6 12 unlike-past unlike-past unlike-past
fun4.1 46 60 4 18 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun4.2 48 62 4 18 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun4.3 58 68 4 14 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun4.4 65 68 6 13 m<2 unlike-past unlike-past
fun4.5 78 82 6 13 m<2 unlike-past unlike-past
fun5.1 46 49 3 9 no-memory unlike-past unlike-past unlike-past unlike-past
fun5.2 46 50 3 9 no-memory unlike-past unlike-past unlike-past unlike-past
fun5.3 47 50 3 9 no-memory unlike-past unlike-past unlike-past unlike-past
fun5.4 49 52 3 9 no-memory unlike-past unlike-past unlike-past unlike-past
fun5.5 50 53 3 9 no-memory unlike-past unlike-past unlike-past unlike-past
fun6.1 39 58 3 18 no-memory unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun6.2 46 59 3 16 no-memory unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun6.3 47 63 4 22 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun6.4 49 66 4 22 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
fun6.5 50 67 4 22 unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past unlike-past
reasons at flag moments before entry, all 20 problems: {'unlike-past': 118, 'm<2': 2, 'no-memory': 7}
m read at analogous-but-refused moments: 0.92 0.92
diag done
group problems enter: same state analogy remembered
APS 154 3 8
CHA-flat 20 20 20
CHA-fun1 5 1 1
CHA-fun2 5 0 0
CHA-fun7 5 3 3
CHA-fun8 5 0 0
CHA-fun9 5 0 1
flat: mean entry state 12.9 (same state) -> 8.2 (analogy remembered)
diag done