MachineSex/figures/plot_E9.py
Giorgio Gilestro 48181a1c84 society: make the sexual-transmission model rigorous (E9 epistasis, E10 directed sex)
Deepen the sexual-reproduction frame before entering the full society, on
the two facets GG chose: landscape robustness and directed recombination.
Adds a Kauffman NK landscape (genotype.nk_fitness, tunable ruggedness),
finite n-parent crossover (genotype.crossover, per-gap recombination rate),
and hill-climb (parents = local optima = trained models).

E9 (recomb_landscape) -- the "why sex?" test: E8's dramatic super-parent
result used an ADDITIVE landscape. On rugged/epistatic landscapes, blindly
recombining local optima causes OUTBREEDING DEPRESSION -- offspring fall
below the parents, worse with both ruggedness and recombination rate (K=8,
free recomb: ~ -0.23), and the optimal recombination rate shrinks as
ruggedness grows. Design rule: merge freely when skills are complementary/
additive; sparingly (and with selection) when entangled.

E10 (directed_sex) -- directed sex beats biological sex: biology is stuck
with 2 random-mating parents and no offspring preview; an AI can choose
complementary mates, evaluate many recombinant offspring, keep the fittest,
and use unbounded parents (iterated recombine-then-select). Random
("biological") sex craters with ruggedness (0.66->0.51); directed sex
tracks/exceeds the best parent at every ruggedness -- converting the
outbreeding-depression catastrophe into a win. No biological analog.

Complete sexual-transmission picture: dramatic super-parent offspring when
skills are complementary (E8); outbreeding-depression risk when entangled
(E9); directed sex resolves the risk (E10). configs/layer1/{E9,E10}.yaml,
figures/plot_{E9,E10}.py, READMEs, +5 tests (117 green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:13:37 +01:00

66 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""E9 figure — landscape robustness: when recombination helps, and the outbreeding-depression risk.
The credibility test for the sexual metaphor. E8 used an additive landscape where recombination
trivially helps; here parents are local optima ("trained models") of a Kauffman NK landscape whose
ruggedness (epistasis) is tunable. Blindly recombining entangled models breaks co-adapted allele
blocks and offspring fall *below* the parents — outbreeding depression — worse the more rugged the
landscape and the higher the recombination rate. With selection (best offspring), a nonzero optimal
recombination rate re-emerges. Design rule: merge freely when skills are complementary; merge
sparingly (and always select) when they are entangled.
Two panels: (A) the risk — mean offspring fitness minus best-parent vs recombination rate, one curve
per ruggedness K (all ≤0, steeper as K grows); (B) with offspring selection — best-of-brood fitness
vs rate per K, showing an intermediate optimum on rugged landscapes. Reads only the bundle.
Usage: python figures/plot_E9.py [results/E9]
"""
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 load_bundle, savefig # noqa: E402
def main(results_dir: str = "results/E9") -> None:
df, _ = load_bundle(results_dir)
Ks = sorted(df["K"].unique())
rates = sorted(df["rate"].unique())
colors = plt.cm.viridis(np.linspace(0, 0.85, len(Ks)))
bp = df.groupby("K")["best_parent"].mean()
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
# Panel A: the risk — mean offspring minus best parent vs rate, per K.
ax = axes[0]
for K, c in zip(Ks, colors):
s = df[df["K"] == K].groupby("rate")["mean_offspring"].mean() - bp[K]
ax.plot(s.index, s.values, "-o", color=c, ms=4, label=f"K={K}")
ax.axhline(0, ls=":", color="gray", lw=1)
ax.set(xlabel="recombination rate", ylabel="mean offspring best parent",
title="The risk: outbreeding depression\n(worse with ruggedness K and recombination rate)")
ax.legend(frameon=False, fontsize=8, title="ruggedness")
# Panel B: with selection — best offspring vs rate, per K (intermediate optimum on rugged).
ax = axes[1]
for K, c in zip(Ks, colors):
s = df[df["K"] == K].groupby("rate")["best_offspring"].mean()
ax.plot(s.index, s.values, "-o", color=c, ms=4, label=f"K={K}")
ax.axhline(bp[K], ls=":", color=c, lw=0.8, alpha=0.6)
ax.set(xlabel="recombination rate", ylabel="best-of-brood fitness (with selection)",
title="With offspring selection, an optimal\nrecombination rate re-emerges (dotted = parents)")
ax.legend(frameon=False, fontsize=8, title="ruggedness")
fig.suptitle("E9 — landscape robustness: recombination helps when skills are complementary, but "
"blindly merging entangled models causes outbreeding depression", y=1.02, fontsize=11)
fig.tight_layout()
savefig(fig, results_dir, "E9")
if __name__ == "__main__":
main(*sys.argv[1:])