Axelrod Python Library

repository·dev·Indexed 21 days ago

https://github.com/axelrod-python/axelrod

A Python library for studying the Iterated Prisoner's Dilemma. It provides a framework for running tournaments, head-to-head matches, and population dynamics simulations, including implementations of strategies from Axelrod's original tournaments, memory-one strategies, and Finite State Machine (FSM) players.

Tokens
29.5K
Snippets
86
Records
103
Agent score
74%

What's inside Axelrod

  1. Overview of Axelrod features

    dev

    Axelrod is a Python library designed for research into the Iterated Prisoner's Dilemma. Key capabilities include:

    • Strategy Access: Over 200 strategies (e.g., Tit For Tat, Win Stay Lose Shift) that are extendable via parametrization and transformers.
    • Match Types: Support for head-to-head matches between pairs or full tournaments among multiple strategies.
    • Population Dynamics: Ability to study Moran processes and infinite population models.
    • Analysis & Visualization: Tools to analyze tournament results, calculate morality metrics, perform strategy fingerprinting, and visualize results.
    • Research Reproduction: Designed to facilitate the reproduction of contemporary research topics.
  2. What is a Strategy Transformer?

    dev

    A strategy transformer is a function that modifies an existing strategy. It takes a strategy class as input and returns a new class. This new class behaves like the original strategy but with modified logic (e.g., flipping actions, adding noise, or changing initial/final moves).

    Important Usage Note: A transformer returns a class, not an instance. You must instantiate the resulting class to create a player.

    Correct instantiation patterns:

    • Transformer(args)(OriginalClass)()
    • Transformer(args)(OriginalClass) (returns the class)

    Naming: Transformers automatically prepend a prefix to the class and player names. You can suppress this by setting name_prefix=None.

    import axelrod as axl
    from axelrod.strategy_transformers import FlipTransformer
    
    # 1. Create the transformed class
    FlippedCooperator = FlipTransformer()(axl.Cooperator)
    
    # 2. Instantiate the class to get a player
    player = FlippedCooperator()
    
    # Example of suppressing name prefix
    NoPrefixClass = FlipTransformer(name_prefix=None)(axl.Cooperator)
    player_no_prefix = NoPrefixClass()
  3. How plays, turns, and matches are structured

    dev

    Understanding the hierarchy of interactions in Axelrod:

    • Play: A single player choosing an action. Calling player.strategy(opponent) constitutes a play.
    • Turn: A single interaction between two players, composed of two plays. There are four possible outcomes: (C, C), (C, D), (D, C), or (D, D).
    • Match: A consecutive sequence of turns. The default number of turns is 200.
    • Win: Determined by the player with the higher total score at the end of a match.
  4. Distinguish between instance equality and strategy equivalence

    dev

    The == operator checks for instance equality (whether all attributes of the objects are identical). It does not check for strategy equivalence (whether two different player classes will behave identically in a game).

    For example, axl.Alternator() and axl.Cycler("CD") are functionally equivalent in behavior, but p1 == p2 will return False because they are different classes/instances. To check if player strategies are functionally equivalent, use the fingerprinting feature.

    import axelrod as axl
    
    p1 = axl.Alternator()
    p2 = axl.Cycler("CD")
    
    # This returns False despite them having equivalent behavior
    print(p1 == p2)
  5. Evolve players using the EvolvablePlayer class

    dev

    Certain strategies in Axelrod derive from the EvolvablePlayer class, which enables them to be used with evolutionary or particle swarm algorithms. To make a custom strategy compatible with these algorithms, you must implement specific methods:

    • For Evolutionary/Moran Process algorithms: Define mutation and crossover methods.
    • For Particle Swarm algorithms: Define methods to serialize the strategy to and from a vector of floats.

    Existing examples of evolvable players include FSMPlayers, ANN (neural networks), LookerUp, and Gambler (lookup tables). For implementations of these algorithms, refer to the axelrod-dojo library.

  6. Difference between OriginalGradual and Gradual strategies

    dev

    The library implements two distinct versions of the 'Gradual' strategy based on different research papers:

    1. OriginalGradual: Punishes defections with a growing number of defections. After punishing for punishment_limit times, it enters a 'calming state' (cooperating for two rounds regardless of the opponent). The punishment_limit is only incremented when the opponent defects and the strategy is not currently in a calming or punishing state.

    2. Gradual: An updated version where the punishment_limit is incremented whenever the opponent defects, regardless of the current state of the player.

  7. Caching in Tournaments and Moran Processes

    dev

    The DeterministicCache can be applied to complex evolutionary simulations:

    • Tournaments: These automatically create and manage caches on a match-by-match basis without explicit configuration.
    • Moran Processes: By default, a Moran process uses a new cache. To use a prebuilt or persistent cache, pass it to the deterministic_cache argument during initialization.
    import axelrod as axl
    
    # Using a persistent cache in a Moran Process
    cache = axl.DeterministicCache("cache.txt")
    players = [axl.GoByMajority(), axl.Alternator(), axl.Cooperator(), axl.Grudger()]
    mp = axl.MoranProcess(players, deterministic_cache=cache)
    mp.play()
  8. How Moran Processes on Graphs work

    dev

    A Moran process on graphs uses two distinct graph structures to govern player behavior:

    1. Interaction Graph: Dictates how players are matched for scoring. Each player plays a match with every neighbor defined in this graph.
    2. Reproduction Graph: Dictates how players replace others. When an individual is selected to reproduce, they replace one of their neighbors in this graph.

    If you only provide one graph to the MoranProcess, it is used for both interaction and reproduction.

    Note on Standard Moran Processes: A standard Moran process (without a specific graph structure) is mathematically equivalent to using a complete graph with no loops for the interaction_graph and a complete graph with loops for the reproduction_graph.

  9. Understand Round Robins, Tournaments, and Noise

    dev

    Axelrod uses several abstractions for large-scale simulations:

    • Round Robin: A set of all potential matches between a given collection of players (order invariant).
    • Tournament: A repetition of round robins used to smooth out stochastic effects.
    • Noise: A probability parameter that can be applied to a match or tournament. It represents the chance that an action dictated by a strategy is swapped (e.g., a C becomes a D).
  10. Understand the Prisoner's Dilemma and Axelrod's Scoring

    dev

    Axelrod's simulations are based on the Prisoner's Dilemma, a two-player game where players choose to either Cooperate or Defect. The goal is to maximize utility, which is inversely related to the years spent in prison.

    Scoring Logic

    The utility ($U$) is calculated based on years in prison ($Y$) using the formula: $U = 5 - Y$ (where $Y ext{ is in } [0, 5]$).

    Payoff Matrix

    Player 1 \ Player 2CooperateDefect
    Cooperate(3, 3)(0, 5)
    Defect(5, 0)(1, 1)
    • Both Cooperate: Each receives a utility of 3.
    • One Cooperates, One Defects: The defector receives 5, the cooperator receives 0.
    • Both Defect: Each receives a utility of 1.
  11. Understand the Prisoner's Dilemma payoff structure

    dev

    Axelrod models the Prisoner's Dilemma using a 4-tuple of payoffs $(R, P, S, T)$ representing the outcomes of different interaction rounds. For a game to be a valid Prisoner's Dilemma, the payoffs must satisfy the condition $T > R > P > S$.

    • R (Reward): Payoff for mutual cooperation.
    • P (Punishment): Payoff for mutual defection.
    • S (Sucker): Payoff for one player cooperating while the other defects.
    • T (Temptation): Payoff for one player defecting while the other cooperates.
  12. Reproducibility in Moran Process and Fingerprints

    dev

    Axelrod provides mechanisms to ensure reproducibility for more complex evolutionary simulations and data structures:

    • Moran Process: Similar to tournaments, the Moran process propagates child seeds to each match to ensure reproducible evolutionary outcomes. Refer to EvolvablePlayers documentation for details on player evolution.
    • Fingerprints: Because fingerprint generation is derived from tournament results, you can provide a seed during fingerprint generation to ensure the resulting fingerprints are reproducible.