112 lines
4.7 KiB
Python
112 lines
4.7 KiB
Python
"""Premise check for entry into the flat regime by ANALOGY (Valeri, 2026-09-21: "рассмотри
|
|
задачу входа в режим на плоских функциях с точки зрения похожести или аналогичности").
|
|
|
|
A pure power f = c(x-r)^m is self-similar: zooming about the root maps every configuration
|
|
of points onto an earlier one (x scaled by L, f by L^m). So the DIMENSIONLESS configuration
|
|
of the last three points,
|
|
xi = (x_k - x_{k-1}) / (x_{k-2} - x_{k-1}),
|
|
phi = (f_k - f_{k-1}) / (f_{k-2} - f_{k-1}),
|
|
RECURS. At a simple root, zooming in makes f look like its tangent, and the configuration
|
|
approaches the LINEAR prototype phi = xi (exact for a linear f) instead. The static
|
|
distance to the line cannot tell them apart (fun1 on a wide bracket looks as non-linear as
|
|
x^9 - diag_contraction_similarity.py); the question is which prototype the configuration
|
|
is NEARER to: the line, or its own past.
|
|
|
|
Nearest-prototype judgment, ordinal, no threshold:
|
|
d_line = |phi - xi| / sqrt(2) (distance to the line phi = xi)
|
|
d_past = min over earlier states j of |(xi, phi)_k - (xi, phi)_j| (Euclidean)
|
|
analogous-to-past <=> d_past < d_line
|
|
Measured at the moments the unkept-promise flag rises (model step, no crossing, r >= 1/4),
|
|
on the proposed rule (projection) with no regime, via the behaviour-neutral trace hook.
|
|
Reported per PROBLEM (entry happens once per problem), per group. Nothing in the method
|
|
changes.
|
|
|
|
python -u diag_flat_analogy.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from collections import defaultdict
|
|
|
|
from simroot.pure import pure_root
|
|
from sweep_full import MAXFEV, XTOL, load_problems
|
|
|
|
FLAT = ("fun3", "fun4", "fun5", "fun6")
|
|
|
|
|
|
def config(s):
|
|
x, fx, xp, fp, xp2, fp2 = s["x"], s["fx"], s["xp"], s["fp"], s["xp2"], s["fp2"]
|
|
if xp2 is None or xp2 == xp or fp2 == fp:
|
|
return None
|
|
xi = (x - xp) / (xp2 - xp)
|
|
phi = (fx - fp) / (fp2 - fp)
|
|
if not (math.isfinite(xi) and math.isfinite(phi)):
|
|
return None
|
|
return xi, phi
|
|
|
|
|
|
def group(s, pid):
|
|
if s == "APS":
|
|
return "APS"
|
|
fam = pid.split(".")[0]
|
|
return "CHA-flat" if fam in FLAT else f"CHA-{fam}"
|
|
|
|
|
|
def pair_order(cur, old):
|
|
"""The order the analogy itself implies: between two analogous states the x-scale
|
|
shrank by L and the f-scale by L^m, so m = ln(f ratio) / ln(x ratio). Scales are the
|
|
last step |x_k - x_(k-1)| and its |f_k - f_(k-1)|. None when undefined."""
|
|
lx = cur[2] / old[2] if old[2] > 0.0 else math.nan
|
|
lf = cur[3] / old[3] if old[3] > 0.0 else math.nan
|
|
if not (math.isfinite(lx) and math.isfinite(lf)) or lx <= 0.0 or lf <= 0.0 or lx == 1.0:
|
|
return None
|
|
return math.log(lf) / math.log(lx)
|
|
|
|
|
|
def main():
|
|
per = defaultdict(lambda: [0, 0, 0, 0]) # problems, flag, flag & analogous, + order >= 2
|
|
ev = defaultdict(lambda: [0, 0, 0]) # flag events, analogous, analogous with m >= 2
|
|
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)
|
|
g = group(s, pid)
|
|
per[g][0] += 1
|
|
past = [] # (xi, phi, |dx|, |df|) of earlier states
|
|
flag_ever = ana_ever = ord_ever = False
|
|
for s_ in st["trace"]:
|
|
c = config(s_)
|
|
fx, fp = s_["fx"], s_["fp"]
|
|
flag = fp is not None and fp != 0.0 and fx / fp >= 0.25
|
|
if c is not None:
|
|
cur = (c[0], c[1], abs(s_["x"] - s_["xp"]), abs(fx - fp))
|
|
if c is not None and flag:
|
|
d_line = abs(c[1] - c[0]) / math.sqrt(2.0)
|
|
best = min(past, key=lambda q: math.hypot(c[0] - q[0], c[1] - q[1]),
|
|
default=None)
|
|
ana = best is not None and math.hypot(c[0] - best[0], c[1] - best[1]) < d_line
|
|
m = pair_order(cur, best) if ana else None
|
|
steep = m is not None and m >= 2.0
|
|
ev[g][0] += 1
|
|
ev[g][1] += ana
|
|
ev[g][2] += steep
|
|
flag_ever = True
|
|
ana_ever = ana_ever or ana
|
|
ord_ever = ord_ever or steep
|
|
if c is not None:
|
|
past.append(cur)
|
|
per[g][1] += flag_ever
|
|
per[g][2] += ana_ever
|
|
per[g][3] += ord_ever
|
|
print(f"{'group':<10} {'problems':>8} {'flag':>6} {'flag&analog':>12} {'&m>=2':>7}"
|
|
f" events: {'flag':>5} {'analog':>7} {'&m>=2':>6}")
|
|
for g in sorted(per):
|
|
n, fl, an, od = per[g]
|
|
e, a, o = ev[g]
|
|
print(f"{g:<10} {n:8d} {fl:6d} {an:12d} {od:7d} {'':8}{e:5d} {a:7d} {o:6d}")
|
|
print("diag done")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|