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
69 lines
3.4 KiB
Python
69 lines
3.4 KiB
Python
"""Conflict-arrival curricula (SI figure): does the declinable merge's decline rate, and the obligate
|
|
merge's collapse, follow the generation at which conflicting conventions arrive?
|
|
|
|
Left: fraction of proposed merges declined per generation (mean over seeds, 95% CI) for each
|
|
curriculum; a filled marker on the curve marks the first generation at which both conflicting
|
|
families (boolq, winogrande) are present in every lineage. Right: best-lineage all-families accuracy
|
|
of the OBLIGATE society arm per curriculum, same marker. Curricula: Latin square (conflict from
|
|
generation 5), decorrelated (from 4), conflict-early (from 2), conflict-late (from 6).
|
|
|
|
Reads the committed curriculum bundles through stats_llm_curriculum (no re-simulation).
|
|
Usage: python figures/plot_curriculum_timing.py [out_dir=results/llm_curriculum_v5_early]
|
|
"""
|
|
|
|
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 CONFLICT_FROM, best_lineage, decline_table, load_curriculum # noqa: E402
|
|
|
|
STYLE = {"latin": ("#7f7f7f", "Latin square"), "decor": ("#2c7fb8", "decorrelated"),
|
|
"early": ("#d62728", "conflict-early"), "late": ("#2ca02c", "conflict-late")}
|
|
OBLIGATE = {"latin": "society", "early": "early_society", "late": "late_society"}
|
|
|
|
|
|
def main(out_dir: str = "results/llm_curriculum_v5_early") -> None:
|
|
df = load_curriculum()
|
|
tab = decline_table(df)
|
|
best = best_lineage(df)
|
|
fig, (a1, a2) = plt.subplots(1, 2, figsize=(10, 3.8))
|
|
for cur, (color, label) in STYLE.items():
|
|
sub = tab[tab["curriculum"] == cur]
|
|
if len(sub):
|
|
x, m, h = mean_ci(sub, "generation", "declined")
|
|
a1.errorbar(x + 1, m, yerr=np.nan_to_num(h), fmt="-o", color=color, capsize=3, label=label,
|
|
markerfacecolor="white")
|
|
g0 = CONFLICT_FROM[cur]
|
|
if g0 in set(x):
|
|
a1.plot(g0 + 1, m[list(x).index(g0)], "o", color=color, ms=12, markeredgecolor="black", markeredgewidth=1.2)
|
|
arm = OBLIGATE.get(cur)
|
|
ob = best[(best["curriculum"] == cur) & (best["arm"] == arm)] if arm else best.iloc[0:0]
|
|
if len(ob):
|
|
x, m, h = mean_ci(ob, "generation", "value")
|
|
a2.errorbar(x + 1, m, yerr=np.nan_to_num(h), fmt="-o", color=color, capsize=3, label=label,
|
|
markerfacecolor="white")
|
|
g0 = CONFLICT_FROM[cur]
|
|
if g0 in set(x):
|
|
a2.plot(g0 + 1, m[list(x).index(g0)], "o", color=color, ms=12, markeredgecolor="black", markeredgewidth=1.2)
|
|
a1.set(xlabel="generation", ylabel="fraction of merges declined", ylim=(-0.02, 1.05),
|
|
title="declinable merge: decline rate")
|
|
a2.set(xlabel="generation", ylabel="best-lineage accuracy, all families", ylim=(0.1, 0.9),
|
|
title="obligate merge: accuracy")
|
|
a1.plot([], [], "o", color="white", ms=10, markeredgecolor="black", markeredgewidth=1.2,
|
|
label="first generation with both\nconflicting conventions")
|
|
a1.legend(frameon=False, fontsize=8); a2.legend(frameon=False, fontsize=8)
|
|
for a in (a1, a2):
|
|
a.set_xticks(range(1, 7))
|
|
fig.tight_layout()
|
|
letter_axes(fig)
|
|
savefig(fig, out_dir, "curriculum_timing")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(*sys.argv[1:])
|