Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 2 additions & 25 deletions axelrod/cooperation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from math import sqrt
from . import eigen
from axelrod import Actions
from axelrod.payoff import player_count

C, D = Actions.C, Actions.D

Expand Down Expand Up @@ -48,31 +49,7 @@ def cooperation_matrix(interactions):
and column (j) represents an individual player and the the value Cij
is the number of times player i cooperated against opponent j.
"""

# The number of ways (c) to select groups of r members from a set of n
# members is given by:
#
# c = n! / r!(n - r)!
#
# In this case, we are selecting pairs of players (p) and thus r = 2,
# giving:
#
# p = n(n-1) / 2 or p = (n^2 - n) / 2
#
# However, we also have the case where each player plays itself gving:
#
# p = (n^2 + n) / 2
#
# Using the quadratic equation to rearrange for n gives:
#
# n = (-1 +- sqrt(1 + 8p)) / 2
#
# Taking only the real roots allows us to derive the number of players
# given the number of pairs:
#
# n = (sqrt(8p + 1) -1) / 2

nplayers = int((sqrt(len(interactions) * 8 + 1) - 1) / 2)
nplayers = player_count(interactions)
cooperation = [[0 for i in range(nplayers)] for j in range(nplayers)]
for players, actions in interactions.items():
p1_actions, p2_actions = zip(*actions)
Expand Down
58 changes: 57 additions & 1 deletion axelrod/payoff.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,63 @@
C, D = Actions.C, Actions.D


def player_count(interactions):
"""
The number of players derived from a dictionary of interactions

Parameters
----------
interactions : dictionary
A dictionary of the form:

e.g. for a round robin between Cooperator, Defector and Alternator
with 2 turns per round:
{
(0, 0): [(C, C), (C, C)].
(0, 1): [(C, D), (C, D)],
(0, 2): [(C, C), (C, D)],
(1, 1): [(D, D), (D, D)],
(1, 2): [(D, C), (D, D)],
(2, 2): [(C, C), (D, D)]
}

i.e. the key is a pair of player index numbers and the value, a list of
plays. The list contains one pair per turn in the round robin.
The dictionary contains one entry for each combination of players.

Returns
-------
nplayers : integer
The number of players in the round robin

The number of ways (c) to select groups of r members from a set of n
members is given by:

c = n! / r!(n - r)!

In this case, we are selecting pairs of players (p) and thus r = 2,
giving:

p = n(n-1) / 2 or p = (n^2 - n) / 2

However, we also have the case where each player plays itself gving:

p = (n^2 + n) / 2

Using the quadratic equation to rearrange for n gives:

n = (-1 +- sqrt(1 + 8p)) / 2

Taking only the real roots allows us to derive the number of players
given the number of pairs:

n = (sqrt(8p + 1) -1) / 2
"""
return int((math.sqrt(len(interactions) * 8 + 1) - 1) / 2)


# As yet unused until RoundRobin returns interactions
def payoff_matrix(interactions, nplayers, game):
def payoff_matrix(interactions, game):
"""
The payoff matrix from a single round robin.

Expand Down Expand Up @@ -50,6 +105,7 @@ def payoff_matrix(interactions, nplayers, game):
and column (j) represents an individual player and the the value Pij
is the payoff value for player (i) versus player (j).
"""
nplayers = player_count(interactions)
payoffs = [[0 for i in range(nplayers)] for j in range(nplayers)]
for players, actions in interactions.items():
payoff = interaction_payoff(actions, game)
Expand Down
14 changes: 10 additions & 4 deletions axelrod/tests/unit/test_payoff.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ def setUpClass(cls):
cls.expected_wins = [[2, 0], [0, 0], [0, 2]]

cls.diff_means = [
[ 0. , 0. , 0.5],
[ 0. , 0. , -0.5],
[-0.5, 0.5, 0. ]
[0.0, 0.0, 0.5],
[0.0, 0.0, -0.5],
[-0.5, 0.5, 0.0]
]

cls.expected_score_diffs = [
Expand All @@ -74,8 +74,14 @@ def setUpClass(cls):
[-1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
]

def test_player_count(self):
nplayers = ap.player_count(self.interactions)
self.assertEqual(nplayers, 3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth including some edge cases? A single player etc...?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, probably! I'll think of something to add

nplayers = ap.player_count({'test': 'test'})
self.assertEqual(nplayers, 1)

def test_payoff_matrix(self):
payoff_matrix = ap.payoff_matrix(self.interactions, 3, Game())
payoff_matrix = ap.payoff_matrix(self.interactions, Game())
self.assertEqual(payoff_matrix, self.expected_payoff_matrix)

def test_interaction_payoff(self):
Expand Down