Running Axelrod’s First Tournament

This tutorial will bring together topics from the previous tutorials to reproduce Axelrod’s original tournament from [Axelrod1980].

Selecting our players

We will use the players from Axelrod’s first tournament which are contained in the axelrod.axelrod_first_strategies list:

>>> import axelrod as axl
>>> first_tournament_participants_ordered_by_reported_rank = [s() for s in axl.axelrod_first_strategies]
>>> number_of_strategies = len(first_tournament_participants_ordered_by_reported_rank)
>>> for player in first_tournament_participants_ordered_by_reported_rank:
...     print(player)
Tit For Tat
First by Tideman and Chieruzzi: (D, D)
First by Nydegger
First by Grofman
First by Shubik
First by Stein and Rapoport: 0.05: (D, D)
Grudger
First by Davis: 10
First by Graaskamp: 0.05
First by Downing
First by Feld: 1.0, 0.5, 200
First by Joss: 0.9
First by Tullock
First by Anonymous
Random: 0.5

Creating the tournament

Now we create and run the tournament, we will set a seed to ensure reproducibility and 50 repetitions to smooth the random effects. We use 5 repetitions as this is what was done in [Axelrod1980]:

>>> axl.seed(0)
>>> tournament = axl.Tournament(
...      players=first_tournament_participants_ordered_by_reported_rank,
...      turns=200,
...      repetitions=5
... )
>>> results = tournament.play()

Viewing the ranks of the participants

The results object contains the ranked names:

>>> for name in results.ranked_names:
...     print(name)
First by Stein and Rapoport: 0.05: (D, D)
First by Grofman
First by Shubik
Tit For Tat
First by Tideman and Chieruzzi: (D, D)
First by Nydegger
First by Davis: 10
Grudger
First by Graaskamp: 0.05
First by Downing
First by Feld: 1.0, 0.5, 200
First by Joss: 0.9
First by Tullock
Random: 0.5
First by Anonymous

We see that TitForTat does not in fact win this tournament. We can plot the reported rank (from [Axelrod1980]) versus the reproduced one:

>>> import matplotlib.pyplot as plt
>>> plt.figure(figsize=(15, 6)) 
>>> plt.plot((0, 15), (0, 15), color="grey", linestyle="--")  
>>> for original_rank, strategy in enumerate(first_tournament_participants_ordered_by_reported_rank):
...     rank = results.ranked_names.index(str(strategy))
...     if rank == original_rank:
...         symbol = "+"
...         plt.plot((rank, rank), (rank, 0), color="grey")
...     else:
...         symbol = "o"
...     plt.scatter([rank], [original_rank], marker=symbol, color="black", s=50)  
>>> plt.xticks(
...     range(number_of_strategies),
...     results.ranked_names,
...     rotation=90
... )  
>>> plt.ylabel("Reported rank")  
>>> plt.xlabel("Reproduced rank");  
>>> plt.show()
../../_images/rank_comparison.svg

Visualising the scores

We see that the first 6 strategies do not match the ranks of the original paper, we can take a look the variation in the scores:

>>> plot = axl.Plot(results)
>>> p = plot.boxplot()
>>> p.show()
../../_images/boxplot.svg

The first 6 strategies have similar scores which could indicate that the original work by Axelrod was not run with sufficient repetitions. Another explanation is that all the strategies are implemented from the descriptions given in [Axelrod1980] and there is no source code to base this on. This leads to some strategies being ambigious. These are all clearly explained in the strategy docstrings. For example:

>>> print(axl.FirstByAnonymous.__doc__)

    Submitted to Axelrod's first tournament by a graduate student whose name was
    withheld.

    The description written in [Axelrod1980]_ is:

    > "This rule has a probability of cooperating, P, which is initially 30% and
    > is updated every 10 moves. P is adjusted if the other player seems random,
    > very cooperative, or very uncooperative. P is also adjusted after move 130
    > if the rule has a lower score than the other player. Unfortunately, the
    > complex process of adjustment frequently left the probability of cooperation
    > in the 30% to 70% range, and therefore the rule appeared random to many
    > other players."

    Given the lack of detail this strategy is implemented based on the final
    sentence of the description which is to have a cooperation probability that
    is uniformly random in the 30 to 70% range.

    Names:

    - (Name withheld): [Axelrod1980]_

Other outcomes

If we run the tournament with other seeds, the results are different. For example, with 130 Tit For Tat wins:

>>> axl.seed(130)
>>> tournament = axl.Tournament(
...      players=first_tournament_participants_ordered_by_reported_rank,
...      turns=200,
...      repetitions=5
... )
>>> results = tournament.play()
>>> for name in results.ranked_names:
...     print(name)
Tit For Tat
First by Stein and Rapoport: 0.05: (D, D)
First by Grofman
First by Shubik
First by Nydegger
First by Tideman and Chieruzzi: (D, D)
First by Davis: 10
Grudger
First by Graaskamp: 0.05
First by Downing
First by Feld: 1.0, 0.5, 200
First by Joss: 0.9
First by Tullock
Random: 0.5
First by Anonymous

With 1238 the strategy submitted by Shubik wins:

>>> axl.seed(1238)
>>> tournament = axl.Tournament(
...      players=first_tournament_participants_ordered_by_reported_rank,
...      turns=200,
...      repetitions=5
... )
>>> results = tournament.play()
>>> for name in results.ranked_names:
...     print(name)
First by Shubik
First by Stein and Rapoport: 0.05: (D, D)
First by Grofman
Tit For Tat
First by Nydegger
First by Tideman and Chieruzzi: (D, D)
Grudger
First by Davis: 10
First by Graaskamp: 0.05
First by Downing
First by Feld: 1.0, 0.5, 200
First by Tullock
First by Joss: 0.9
First by Anonymous
Random: 0.5