Fig. 1B: the conceptual cartoon — from a society in space to a society in time

The paper's key move drawn as a two-panel partner to the programme grid (now
Fig. 1A): on the left, the usual picture — contemporaries exchanging messages
(multi-agent systems, one moment on the clock); on the right, the same
ecosystem seen along its time axis — a pedigree in which a rare capability
(gold dot) is lost under single-parent inheritance, reassembled by merging
complementary parents, and re-supplied by grounding from a reality that can
say no (the globe). Friendly-robot glyphs, colour-coded capability dots;
build.py now stacks multiple PDFs per figure; the Introduction cites 1A and
1B in panel order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkRLcc18rwT2Lysu6PbG7v
This commit is contained in:
Giorgio Gilestro 2026-09-07 12:50:36 +01:00
parent 9c0210ba93
commit b417a66c23
13 changed files with 136 additions and 12 deletions

View file

@ -43,7 +43,7 @@ def save(fig, name):
# ---------------------------------------------------------------- fig 1: experimental programme
def fig1():
def fig1a():
from matplotlib.patches import FancyBboxPatch
TIERS = [
@ -92,6 +92,7 @@ def fig1():
ax.set_axis_off()
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.text(0.0, 0.995, "A", fontsize=13, fontweight="bold", va="top")
x0, gap, sep = 0.205, 0.008, 0.02 # sep: extra gutter between theory and the AI pair
cw = (1.0 - x0 - sep) / 3
xs = [x0, x0 + cw + sep, x0 + 2 * cw + sep]
@ -145,7 +146,118 @@ def fig1():
if tags[j2]: # where the result lives (the ToC role)
ax.text(x + cw - gap - 0.005, y0 + 0.006, tags[j2], ha="right", va="bottom",
fontsize=5.6, style="italic", color=edge)
save(fig, "fig1")
save(fig, "fig1a")
# ------------------------------------------------------- fig 1B: society in space -> in time
BLUE, GREEN, GOLD = "#4292c6", "#41ab5d", "#d4a017"
def _robot(ax, x, y, fc="#e8eef5", dots=(), lost=(), w=0.52, h=0.52):
"""A friendly robot head with capability dots beneath (gold = the rare skill)."""
from matplotlib.patches import Arc, Circle, FancyBboxPatch
ax.add_patch(FancyBboxPatch((x - w / 2, y - h / 2), w, h, boxstyle="round,pad=0.03",
fc=fc, ec="#445", lw=1.1))
for dx in (-w / 4.5, w / 4.5):
ax.add_patch(Circle((x + dx, y + h / 7), w / 9, fc="white", ec="#445", lw=0.7))
ax.add_patch(Circle((x + dx, y + h / 7), w / 24, fc="#334", ec="none"))
ax.add_patch(Arc((x, y - h / 7), w / 2.4, h / 3.2, theta1=195, theta2=345, ec="#445", lw=1.0))
ax.plot([x, x], [y + h / 2 + 0.03, y + h / 2 + 0.10], color="#445", lw=1.1)
ax.add_patch(Circle((x, y + h / 2 + 0.135), 0.04, fc="#445", ec="none"))
marks = [(c, False) for c in dots] + [(c, True) for c in lost]
n = len(marks)
for i, (c, is_lost) in enumerate(marks):
cx = x + (i - (n - 1) / 2) * 0.19
cy = y - h / 2 - 0.17
if is_lost:
ax.add_patch(Circle((cx, cy), 0.07, fc="white", ec=c, lw=0.9, ls=(0, (2, 2))))
ax.text(cx, cy - 0.005, "\u00d7", ha="center", va="center", fontsize=6, color=c)
else:
ax.add_patch(Circle((cx, cy), 0.07, fc=c, ec="none"))
def fig1b():
from matplotlib.patches import Circle, FancyArrowPatch
W, H = 11.4, 4.1
fig, ax = plt.subplots(figsize=(W, H))
ax.set_xlim(0, W)
ax.set_ylim(0, H)
ax.set_aspect("equal")
ax.set_axis_off()
ax.text(0.05, H - 0.05, "B", fontsize=13, fontweight="bold", va="top")
def arrow(p, q, color="#666", lw=1.2, style="-|>", shrink=2.0, ls="-"):
ax.add_patch(FancyArrowPatch(p, q, arrowstyle=style, mutation_scale=9, color=color,
lw=lw, linestyle=ls, shrinkA=shrink, shrinkB=shrink))
# ---------------- left: a society in space (contemporaries exchanging messages)
cx, cy, r = 2.45, 2.45, 0.95
dotsets = [(BLUE, GOLD), (GREEN,), (BLUE, GREEN), (GOLD, GREEN), (BLUE,)]
pos = []
for i, ds in enumerate(dotsets):
a = np.pi / 2 + i * 2 * np.pi / 5
x, y = cx + r * np.cos(a) * 1.4, cy + r * np.sin(a) * 0.95
pos.append((x, y))
_robot(ax, x, y, dots=ds)
for i, j2 in [(0, 2), (1, 3), (2, 4), (0, 3), (1, 4)]:
arrow(pos[i], pos[j2], color="#99a", lw=0.9, style="<|-|>", shrink=26, ls=(0, (4, 2)))
ax.text(pos[0][0] + 0.60, pos[0][1] + 0.30, "\u2026", fontsize=9, ha="center",
bbox=dict(boxstyle="round,pad=0.22", fc="white", ec="#99a", lw=0.8))
clk = (0.55, 3.72)
ax.add_patch(Circle(clk, 0.21, fc="white", ec="#445", lw=1.1))
ax.plot([clk[0], clk[0]], [clk[1], clk[1] + 0.13], color="#445", lw=1.0)
ax.plot([clk[0], clk[0] + 0.10], [clk[1], clk[1]], color="#445", lw=1.0)
ax.text(clk[0], clk[1] - 0.34, "one moment", ha="center", fontsize=6, style="italic",
color="#555")
ax.text(2.45, 0.48, "a society in space", ha="center", fontsize=9.5, fontweight="bold")
ax.text(2.45, 0.22, "contemporaries exchanging messages \u2014 multi-agent systems, agent economies",
ha="center", fontsize=6.6, style="italic", color="#555")
# ---------------- middle: the shift of perspective
arrow((4.62, 2.30), (5.90, 2.30), color="#445", lw=2.0, style="-|>")
ax.text(5.26, 2.44, "the same ecosystem,\nseen along its time axis", ha="center",
va="bottom", fontsize=7, style="italic", color="#334", linespacing=1.3)
# ---------------- right: a society in time (a pedigree)
axx = 6.55
arrow((axx, 3.90), (axx, 0.90), color="#445", lw=1.3)
for gy, lab in [(3.45, "gen 0"), (2.20, "gen 1"), (1.05, "gen 2")]:
ax.text(axx - 0.12, gy, lab, ha="right", va="center", fontsize=6.5, color="#445")
p1, p2 = (7.55, 3.45), (9.25, 3.45)
c1, c2 = (7.15, 2.20), (8.65, 2.20)
g2 = (8.65, 1.05)
_robot(ax, *p1, dots=(BLUE, GOLD))
_robot(ax, *p2, dots=(GREEN, BLUE))
_robot(ax, *c1, dots=(BLUE,), lost=(GOLD,))
_robot(ax, *c2, dots=(BLUE, GREEN, GOLD))
_robot(ax, *g2, dots=(BLUE, GREEN, GOLD))
arrow((7.42, 2.94), (7.20, 2.66), color="#666")
ax.text(7.02, 2.86, "inherit\n(train on output)", ha="right", fontsize=6, style="italic",
color="#555", linespacing=1.2)
arrow((7.72, 2.94), (8.48, 2.66), color="#666")
arrow((9.15, 2.94), (8.84, 2.66), color="#666")
ax.text(8.68, 2.92, "merge (sex)", ha="center", fontsize=6, style="italic", color="#555")
ax.text(7.15, 1.50, "rare skill lost", ha="center", fontsize=5.8, style="italic",
color="#a33")
arrow((8.65, 1.64), (8.65, 1.46), color="#666")
globe = (10.55, 1.60)
ax.add_patch(Circle(globe, 0.30, fc="#eaf4fb", ec="#2c7fb8", lw=1.2))
from matplotlib.patches import Arc as _Arc
ax.add_patch(_Arc(globe, 0.30, 0.60, theta1=90, theta2=270, ec="#2c7fb8", lw=0.8))
ax.add_patch(_Arc(globe, 0.30, 0.60, theta1=270, theta2=90, ec="#2c7fb8", lw=0.8))
ax.plot([globe[0] - 0.30, globe[0] + 0.30], [globe[1], globe[1]], color="#2c7fb8", lw=0.8)
ax.text(globe[0], globe[1] - 0.42, "reality\n(verifier)", ha="center", va="top", fontsize=6,
color="#2c7fb8", linespacing=1.2)
arrow((10.26, 1.45), (9.02, 1.15), color="#2c7fb8", lw=1.2)
ax.text(9.72, 1.52, "ground\n(immigrate)", ha="center", fontsize=6, style="italic",
color="#2c7fb8", linespacing=1.2)
ax.text(8.55, 0.48, "a society in time", ha="center", fontsize=9.5, fontweight="bold")
ax.text(8.55, 0.22, "generations coupled by inheritance, recombination, and grounding \u2014 "
"where population genetics applies",
ha="center", fontsize=6.6, style="italic", color="#555")
save(fig, "fig1b")
# ---------------------------------------------------------------- fig 2: grounding + MNIST
def fig2():
@ -488,5 +600,5 @@ def fig3():
if __name__ == "__main__":
for f in (fig1, fig2, fig3, fig4, fig5, fig6, fig7):
for f in (fig1a, fig1b, fig2, fig3, fig4, fig5, fig6, fig7):
f()