Axelrod Python Library: Simulating the Evolution of Cooperation with Iterated Prisoner's Dilemma Tournaments
The question of how cooperation emerges among self-interested agents is one of the most enduring puzzles in social science. Robert Axelrod's landmark 1980 computer tournaments demonstrated that simple reciprocal strategies—most famously Tit-for-Tat—could outperform more aggressive alternatives in repeated interactions. The Axelrod Python library brings this experimental framework into the modern era, providing a rigorous, reproducible platform for running iterated Prisoner's Dilemma (IPD) tournaments, studying evolutionary dynamics, and testing novel strategies at scale.
What Is the Axelrod Library?
The Axelrod library is an open-source Python package (MIT license) that implements a comprehensive framework for IPD research. It ships with over 230 built-in strategies—ranging from classics like Cooperator, Defector, and Tit-for-Tat to sophisticated memory-based and stochastic strategies—and provides a clean API for defining custom strategies. The library supports:
- Round-robin tournaments (every strategy plays every other)
- Probabilistic ending (each match ends with a fixed probability per turn, preventing end-game defection artifacts)
- Evolutionary and ecological simulations (Moran processes, population dynamics)
- Fingerprinting (characterizing strategy behavior against a probe set)
- Reproducible seeding for stochastic strategies
Core Concepts and Architecture
Strategies and Matches
A strategy in Axelrod is a Python class that inherits from axelrod.Player. Each player maintains a history of its own moves and its opponent's moves, and the strategy() method returns axelrod.Action.C (cooperate) or axelrod.Action.D (defect) based on that history.
import axelrod
players = [
axelrod.TitForTat(),
axelrod.Defector(),
axelrod.Cooperator(),
axelrod.GradualKiller(),
axelrod.WinStayLoseShift(),
axelrod.Random(p=0.5),
]
tournament = axelrod.Tournament(players, turns=200, repetitions=20, seed=42)
results = tournament.play()
print(results.ranking)
The Tournament class handles all pairings, score accumulation, and statistical aggregation. The results object exposes ranked scores, cooperation rates, normalised scores, and payoff matrices—all ready for downstream analysis.
Payoff Matrix and Scoring
The default payoff matrix follows the canonical IPD values (R=3, P=1, T=5, S=0), satisfying T > R > P > S and 2R > T + S. Researchers can override these to model different social dilemmas—stag hunt, snowdrift, or asymmetric games—by passing a custom game object:
game = axelrod.Game(r=3, p=1, s=0, t=5)
tournament = axelrod.Tournament(players, game=game, turns=200, repetitions=50)
Evolutionary Dynamics: The Moran Process
Beyond static tournaments, the library implements the Moran process, a stochastic evolutionary model where strategies reproduce proportionally to fitness and less-fit strategies are gradually eliminated. This is particularly valuable for studying which strategies are evolutionarily stable:
initial_population = [
axelrod.TitForTat(),
axelrod.Defector(),
axelrod.Cooperator(),
axelrod.Random(),
]
mp = axelrod.MoranProcess(initial_population, turns=100, seed=0)
populations = mp.play()
print(mp.winning_strategy_name)
The Moran process reveals that cooperation can persist even in mixed populations when reciprocal strategies are present—a result that static tournaments alone cannot demonstrate.

Strategy Fingerprinting
One of the library's most powerful analytical tools is strategy fingerprinting, which characterizes a strategy's behavior by playing it against a parameterized probe strategy (typically axelrod.TitForTat with varying initial cooperation probability). The resulting fingerprint is a 2D heatmap showing cooperation rate as a function of probe parameters, enabling visual comparison of strategy families:
strategy = axelrod.Grudger()
fingerprint = axelrod.Fingerprint(strategy, axelrod.TitForTat)
fingerprint.fingerprint(turns=50, repetitions=10, seed=1)
fingerprint.plot()
Fingerprints are especially useful for detecting behavioral equivalence between strategies that appear syntactically different but produce identical outcomes.

Defining Custom Strategies
Practitioners modeling real-world social dynamics—negotiation protocols, norm enforcement, institutional cooperation—can implement domain-specific strategies:
class PunishThenForgive(axelrod.Player):
"""Defects for N turns after betrayal, then resets."""
name = "PunishThenForgive"
classifier = {
"memory_depth": 5,
"stochastic": False,
"makes_use_of": [],
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
def __init__(self, punishment_length: int = 3):
super().__init__()
self.punishment_length = punishment_length
self._punish_count = 0
def strategy(self, opponent: axelrod.Player) -> axelrod.Action:
if opponent.history and opponent.history[-1] == axelrod.Action.D:
self._punish_count = self.punishment_length
if self._punish_count > 0:
self._punish_count -= 1
return axelrod.Action.D
return axelrod.Action.C
This pattern is directly applicable to modeling graduated sanctions in common-pool resource governance, escalation ladders in international relations, or credit scoring in peer-to-peer lending networks.
Ecological Simulations
The axelrod.Ecosystem class models population dynamics over time without the replacement mechanism of the Moran process. Strategies grow or shrink in proportion to their tournament scores each generation, providing a deterministic view of which behavioral phenotypes dominate:
tournament = axelrod.Tournament(players, turns=100, repetitions=5, seed=7)
results = tournament.play()
ecosystem = axelrod.Ecosystem(results)
ecosystem.reproduce(100)
ecosystem.plot()
Ecological simulations are well-suited to studying market entry dynamics, the spread of social norms, or the long-run viability of altruistic institutions.

Practical Considerations
Reproducibility: Always set seed on both the Tournament and any stochastic players. The library uses Python's random module internally, so a fixed seed guarantees identical results across runs.
Performance: With 230+ strategies, a full round-robin tournament involves ~26,000 pairings. Use with_morality=False and reduce repetitions for exploratory runs; reserve high-repetition runs for publication-quality results. Parallel execution is supported via processes parameter.
Strategy classification: Each built-in strategy carries a classifier dict indicating memory depth, stochasticity, and whether it inspects or manipulates opponent source code. Filter strategies by classifier to construct ecologically meaningful subsets:
short_memory = [s for s in axelrod.all_strategies
if s.classifier["memory_depth"] <= 3
and not s.classifier["stochastic"]]
Applications in Social Simulation Research
The Axelrod library has been applied across a wide range of social science domains:
- Institutional economics: Testing whether conditional cooperation strategies sustain public goods provision under varying punishment regimes
- International relations: Modeling arms-race dynamics and treaty compliance as repeated games between state actors
- Organizational behavior: Studying how reciprocity norms emerge in repeated supplier-buyer relationships
- Network epidemiology: Coupling IPD dynamics with network topology to study how social structure shapes cooperative behavior
Further Resources
- Official documentation
- GitHub repository
- Axelrod's original paper: "The Evolution of Cooperation" (1981)
- Strategies catalogue: Full list of 230+ built-in strategies with classifiers
- Journal of Open Source Software paper: Peer-reviewed description of the library's design
The Axelrod Python library transforms a classic thought experiment into a rigorous computational laboratory. For social simulation researchers, it offers an unmatched combination of breadth—hundreds of strategies, multiple simulation modes—and methodological transparency, making it an essential tool for anyone studying the emergence and stability of cooperative behavior in social systems.