Manuscript revision and pending experiment work, snapshot before restructuring

Clarity pass over the main text (36-item audit), Discussion rewrite and cut,
acknowledgements, Souly et al. as ref 62, lettered SI panels, model section
moved under Results; plus the untracked curriculum/society/compose/smol
configs, runners, figures, stats and tests that the SI already cites.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y64o8FKP7rCuXzC48pxpMm
This commit is contained in:
Giorgio Gilestro 2026-09-13 16:54:09 +01:00
parent e4804adabc
commit 84124de143
450 changed files with 52813 additions and 1202 deletions

View file

@ -0,0 +1,69 @@
"""Differential reproduction in the six-generation population (SI figure).
Left: best-lineage all-families accuracy per generation (mean over seeds, 95% CI) for the four arms:
never merge, declinable merge, and each with culling (the lowest-scoring lineage re-founded from
the highest-scoring one after every generation). Middle: population MEAN accuracy over the three
lineages, same arms (culling acts on the mean first). Right: the number of cull events per
generation in each culled arm (mean over seeds), with the fraction of merges declined in the
culled declinable arm.
Reads the committed curriculum bundles through stats_llm_curriculum (no re-simulation).
Usage: python figures/plot_curriculum_cull.py [out_dir=results/llm_curriculum_v5_cull]
"""
from __future__ import annotations
import sys
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
sys.path.insert(0, str(Path(__file__).parent))
from _figlib import mean_ci, savefig, letter_axes # noqa: E402
from stats_llm_curriculum import best_lineage, load_curriculum # noqa: E402
ARMS = {"isolated": ("#2c7fb8", "-", "never merge"), "veto": ("#2ca02c", "-", "declinable merge"),
"cull_isolated": ("#2c7fb8", "--", "never merge + culling"),
"cull_veto": ("#2ca02c", "--", "declinable merge + culling")}
def main(out_dir: str = "results/llm_curriculum_v5_cull") -> None:
df = load_curriculum()
df = df[df["curriculum"] == "latin"]
best = best_lineage(df)
lin = df[(df["metric"] == "all_families") & df["model"].str.startswith("lineage") & (df["generation"] >= 0)]
pop_mean = lin.groupby(["arm", "seed", "generation"])["value"].mean().reset_index()
fig, (a1, a2, a3) = plt.subplots(1, 3, figsize=(13, 3.8))
for arm, (color, ls, label) in ARMS.items():
for ax, src in ((a1, best), (a2, pop_mean)):
sub = src[src["arm"] == arm]
if len(sub):
x, m, h = mean_ci(sub, "generation", "value")
ax.errorbar(x + 1, m, yerr=np.nan_to_num(h), fmt="o", ls=ls, color=color, capsize=3,
label=label)
for arm, color in (("cull_isolated", "#2c7fb8"), ("cull_veto", "#2ca02c")):
c = df[(df["arm"] == arm) & (df["metric"] == "culled")]
if len(c):
ev = c.groupby(["seed", "generation"])["value"].sum().reset_index()
x, m, _ = mean_ci(ev, "generation", "value")
a3.plot(x + 1, m, "o--", color=color, label=f"{ARMS[arm][2]}: culls")
v = df[(df["arm"] == "cull_veto") & (df["metric"] == "veto_used")]
if len(v):
x, m, h = mean_ci(v, "generation", "value")
a3.errorbar(x + 1, m, yerr=np.nan_to_num(h), fmt="s-", color="#d62728", capsize=3,
label="declined merges (culled arm)")
a1.set(xlabel="generation", ylabel="best-lineage accuracy, all families", ylim=(0.3, 0.9),
title="best lineage")
a2.set(xlabel="generation", ylabel="population mean accuracy", ylim=(0.3, 0.9), title="population mean")
a3.set(xlabel="generation", ylabel="events per generation / fraction", ylim=(-0.05, 1.1),
title="culls and declines")
for a in (a1, a2, a3):
a.set_xticks(range(1, 7)); a.legend(frameon=False, fontsize=7)
fig.tight_layout()
letter_axes(fig)
savefig(fig, out_dir, "curriculum_cull")
if __name__ == "__main__":
main(*sys.argv[1:])