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
+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()