llm_society: the composed society at LLM scale (C3) — loop, tests, smoke green

E11 re-instantiated in a population of LoRA agents, closing the paper's stated
gap before submission (GG: a weeks-scale experiment a reviewer would demand).
One grounding knob in the evaluation channel (g*verifier + (1-g)*conformity,
exactly E11); inheritance is identical in all arms and deliberately ungrounded
(children distilled from their source's own answers - self-consumption made
literal). Directed sex = complementary pairing + Dirichlet offspring screened
on the arm's own signal (the verifier never enters the no_grounding loop);
QD selection on verifier-free behavioural distance; terminal-degeneration
fallback copies the parent instead of crashing a sweep. Pure operators
unit-tested (155 green); smoke run end-to-end on the local A4000 already
shows the self-consumption signature (conformity up, diversity down in one
generation). Design, falsifiers, cost table: tasks/workorder-llm-society.md.

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 11:55:19 +01:00
parent d75c58474a
commit 9b0ca32f51
8 changed files with 531 additions and 1 deletions

View file

@ -138,3 +138,62 @@ def test_lora_delta_inner_matches_brute_force():
A2, B2 = torch.randn(4, 20, generator=g), torch.randn(12, 4, generator=g)
brute = float(((B1 @ A1) * (B2 @ A2)).sum())
assert abs(lora_delta_inner(A1, B1, A2, B2) - brute) < 1e-3
# ---------------------------------------------------------------------- society (pure operators)
def test_society_consensus_is_modal_and_deterministic():
from llm.society import consensus_answers
outs = [["5", "cat", "[1, 2]"],
["5", "dog", "[1, 2]"],
["7", "dog", "[2, 1]"]]
cons = consensus_answers(outs)
assert cons[0] == "5" and cons[1] == "dog" and cons[2] == "[1, 2]"
# a full three-way tie breaks lexicographically (deterministic)
tie = consensus_answers([["a"], ["b"], ["c"]])
assert tie == ["a"]
def test_society_conformity_and_distance():
from llm.society import behavioural_distance, conformity_scores, consensus_answers
outs = [["5", "dog"], ["5", "dog"], ["7", "cat"]]
cons = consensus_answers(outs)
conf = conformity_scores(outs, cons)
assert conf[0] == conf[1] == 1.0 and conf[2] == 0.0 # majority conforms, dissenter does not
d = behavioural_distance(outs)
assert d[0, 1] == 0.0 and d[0, 2] == 1.0 and np.allclose(d, d.T)
def test_society_selection_greedy_vs_quality_diversity():
from llm.society import select_parents
scores = np.array([1.0, 0.95, 0.94, 0.1])
# agents 0 and 1 are behavioural clones; agent 2 is distant from both
d = np.zeros((4, 4))
d[0, 2] = d[2, 0] = d[1, 2] = d[2, 1] = 1.0
d[0, 3] = d[3, 0] = d[1, 3] = d[3, 1] = d[2, 3] = d[3, 2] = 1.0
greedy = select_parents(scores, d, 2, diversity=False)
assert greedy == [0, 1] # pure score: takes the clones
qd = select_parents(scores, d, 2, diversity=True, lam=0.3)
assert qd == [0, 2] # QD: prefers the distant near-peer
def test_society_pairs_and_arms():
import pytest
from llm.society import arm_settings, complementary_pairs
d = np.zeros((4, 4))
d[0, 1] = d[1, 0] = 0.9
d[0, 2] = d[2, 0] = 0.2
d[1, 2] = d[2, 1] = 0.5
pairs = complementary_pairs([0, 1, 2], d, 4)
assert pairs[0] == (0, 1) and pairs[1] == (1, 2) # most-complementary pair breeds first
assert len(pairs) == 4 and pairs[3] == pairs[0] # cycles to fill the slots
assert arm_settings("no_grounding", 0.5)["g"] == 0.0
assert arm_settings("no_sex", 0.5) == {"g": 0.5, "sex": False, "diversity": True}
with pytest.raises(ValueError):
arm_settings("bogus", 0.5)