phase diagram: add per-depth point (fidelity kept, gain depth-stranded)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Nils
2026-07-15 03:25:16 +02:00
co-authored by Claude Fable 5
parent b53538e82c
commit 8981cda31d
2 changed files with 10 additions and 5 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 164 KiB

+10 -5
View File
@@ -16,11 +16,13 @@ OUT = Path(__file__).resolve().parent.parent / "results-loop"
# name rho easy hard color # name rho easy hard color
# name rho(plot x) easy hard color dy # name rho(plot x) easy hard color dy
PTS = [ PTS = [
("untrained α-merge\n(training-free)", 0.38, 0.885, 0.143, "#8a8f98", 16), ("untrained α-merge\n(training-free)\nhard 14%", 0.40, 0.885, 0.143, "#8a8f98", -52),
("trained merge\n(anchored B, curriculum)", 0.29, 0.885, 0.464, "#2b6cb0", -60), ("trained merge\n(anchored B, curriculum)", 0.26, 0.885, 0.464, "#2b6cb0", -60),
("per-depth merges\n(time-varying, anchored)\nhard 36% (depth-stranded)", 0.325, 0.893, 0.357, "#805ad5", 18),
("Parcae rec\n(ρ<1 enforced, learned B)", 0.292, 0.713, 0.429, "#2f855a", -58), ("Parcae rec\n(ρ<1 enforced, learned B)", 0.292, 0.713, 0.429, "#2f855a", -58),
("unconstrained rec\n(learned A,B)", 4.5, 0.697, 0.393, "#c53030", 16), ("unconstrained rec\n(learned A,B)", 4.5, 0.697, 0.393, "#c53030", 16),
] ]
# x jittered around true rho=0.3 for the three anchored arms (visibility)
# untrained merge x offset for visibility (true rho = 0.30) # untrained merge x offset for visibility (true rho = 0.30)
fig, ax = plt.subplots(figsize=(7.6, 5.2)) fig, ax = plt.subplots(figsize=(7.6, 5.2))
@@ -36,15 +38,18 @@ ax.text(3.1, 0.615, "norm projection converts\nexplosion → stationary churn\n"
for name, rho, easy, hard, c, dy in PTS: for name, rho, easy, hard, c, dy in PTS:
ax.scatter(rho, easy, s=90 + 900 * hard, color=c, alpha=0.85, zorder=3, ax.scatter(rho, easy, s=90 + 900 * hard, color=c, alpha=0.85, zorder=3,
edgecolor="white", linewidth=1.5) edgecolor="white", linewidth=1.5)
ax.annotate(f"{name}\nhard {hard:.0%}", lbl = name if ("stranded" in name or "14%" in name) else f"{name}\nhard {hard:.0%}"
(rho, easy), textcoords="offset points", xytext=(0, dy), dx = 62 if "14%" in name else 0
ax.annotate(lbl,
(rho, easy), textcoords="offset points", xytext=(dx, dy),
ha="center", fontsize=8.5, color=c) ha="center", fontsize=8.5, color=c)
ax.annotate("", xy=(0.278, 0.735), xytext=(0.288, 0.862), ax.annotate("", xy=(0.278, 0.735), xytext=(0.288, 0.862),
arrowprops=dict(arrowstyle="->", color="#2f855a", lw=1.3)) arrowprops=dict(arrowstyle="->", color="#2f855a", lw=1.3))
ax.text(0.42, 0.79, "learned B + no curriculum:\nfixed point leaves the\n" ax.text(0.46, 0.775, "learned B + no curriculum:\nfixed point leaves the\n"
"substrate manifold", fontsize=8, color="#2f855a", ha="left") "substrate manifold", fontsize=8, color="#2f855a", ha="left")
ax.set_xlim(0.2, 12) ax.set_xlim(0.2, 12)
ax.set_ylim(0.58, 1.0) ax.set_ylim(0.58, 1.0)
ax.set_xlabel("ρ(A) — spectral radius of the trained state map (dynamics dial)") ax.set_xlabel("ρ(A) — spectral radius of the trained state map (dynamics dial)")