From 11789016fb3a3f5e53244a9045dcab7a2299ada3 Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Mon, 2 Nov 2015 09:25:32 +0000 Subject: [PATCH 1/8] adds stubs and tests for nplayers and scores_matrix functions --- axelrod/payoff.py | 64 +++++++++++++++++++++++++++++++ axelrod/tests/unit/test_payoff.py | 8 ++++ 2 files changed, 72 insertions(+) diff --git a/axelrod/payoff.py b/axelrod/payoff.py index 7067695ba..d76fd95f2 100644 --- a/axelrod/payoff.py +++ b/axelrod/payoff.py @@ -4,6 +4,61 @@ C, D = Actions.C, Actions.D +def nplayers(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): @@ -91,6 +146,15 @@ def interaction_payoff(actions, game): return (player1_payoff, player2_payoff) +# As yet unused until RoundRobin returns interactions +def scores_matrix(actions, game): + """ + + """ + scores = [] + return scores + + def scores(payoff): """ The scores matrix excluding self-interactions diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index 49d485330..ee9b4bebb 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -74,6 +74,10 @@ def setUpClass(cls): [-1.0, 0.0, 0.0, 1.0, 0.0, 0.0] ] + def test_nplayers(self): + nplayers = ap.nplayers(self.interactions) + self.assertEqual(nplayers, 5) + def test_payoff_matrix(self): payoff_matrix = ap.payoff_matrix(self.interactions, 3, Game()) self.assertEqual(payoff_matrix, self.expected_payoff_matrix) @@ -82,6 +86,10 @@ def test_interaction_payoff(self): payoff = ap.interaction_payoff(self.interactions[(2, 2)], Game()) self.assertEqual(payoff, (13, 3)) + def test_scores_matrix(self): + scores = ap.normalised_scores(self.interactions, Game()) + self.assertEqual(scores, self.expected_scores) + def test_scores(self): scores = ap.scores(self.expected_payoff) self.assertEqual(scores, self.expected_scores) From ff8fdd1179239ca2de807f8373c42059cd83c242 Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Mon, 2 Nov 2015 19:05:30 +0000 Subject: [PATCH 2/8] fixes up test_scores_matrix --- axelrod/tests/unit/test_payoff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index ee9b4bebb..6fb1a6dd4 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -76,7 +76,7 @@ def setUpClass(cls): def test_nplayers(self): nplayers = ap.nplayers(self.interactions) - self.assertEqual(nplayers, 5) + self.assertEqual(nplayers, 3) def test_payoff_matrix(self): payoff_matrix = ap.payoff_matrix(self.interactions, 3, Game()) @@ -87,7 +87,7 @@ def test_interaction_payoff(self): self.assertEqual(payoff, (13, 3)) def test_scores_matrix(self): - scores = ap.normalised_scores(self.interactions, Game()) + scores = ap.scores_matrix(self.interactions, Game()) self.assertEqual(scores, self.expected_scores) def test_scores(self): From 5bcb74ab8b8d8ce7160f8f77913e9b2c225d6a51 Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Mon, 2 Nov 2015 19:08:46 +0000 Subject: [PATCH 3/8] uses player_count in payoff_matrix --- axelrod/payoff.py | 5 +++-- axelrod/tests/unit/test_payoff.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/axelrod/payoff.py b/axelrod/payoff.py index d76fd95f2..68177c608 100644 --- a/axelrod/payoff.py +++ b/axelrod/payoff.py @@ -4,7 +4,7 @@ C, D = Actions.C, Actions.D -def nplayers(interactions): +def player_count(interactions): """ The number of players derived from a dictionary of interactions @@ -61,7 +61,7 @@ def nplayers(interactions): # 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. @@ -105,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) diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index 6fb1a6dd4..08b18a2e6 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -74,12 +74,12 @@ def setUpClass(cls): [-1.0, 0.0, 0.0, 1.0, 0.0, 0.0] ] - def test_nplayers(self): - nplayers = ap.nplayers(self.interactions) + def test_player_count(self): + nplayers = ap.player_count(self.interactions) self.assertEqual(nplayers, 3) 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): From 796c882b1d2b6988bc515d4b220b2e2299d7adde Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Mon, 2 Nov 2015 19:10:18 +0000 Subject: [PATCH 4/8] uses player_count in cooperation_matrix --- axelrod/cooperation.py | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/axelrod/cooperation.py b/axelrod/cooperation.py index 08177c423..d5528888d 100644 --- a/axelrod/cooperation.py +++ b/axelrod/cooperation.py @@ -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 @@ -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) From 9bedd1f5e26552e7e6850d6b5cc7219a13e53265 Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Mon, 2 Nov 2015 19:11:11 +0000 Subject: [PATCH 5/8] fixes pep8 errors --- axelrod/tests/unit/test_payoff.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index 08b18a2e6..c2df1e375 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -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 = [ From 3e6254ef5e94f2bc04d897b909b358fd3fbe6ecc Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Mon, 2 Nov 2015 19:46:13 +0000 Subject: [PATCH 6/8] adds scores_matrix implementation --- axelrod/payoff.py | 40 ++++++++++++++++++++++++++++--- axelrod/tests/unit/test_payoff.py | 11 +++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/axelrod/payoff.py b/axelrod/payoff.py index 68177c608..464af28f3 100644 --- a/axelrod/payoff.py +++ b/axelrod/payoff.py @@ -4,6 +4,7 @@ C, D = Actions.C, Actions.D + def player_count(interactions): """ The number of players derived from a dictionary of interactions @@ -56,7 +57,6 @@ def player_count(interactions): n = (sqrt(8p + 1) -1) / 2 """ - return int((math.sqrt(len(interactions) * 8 + 1) - 1) / 2) @@ -148,11 +148,45 @@ def interaction_payoff(actions, game): # As yet unused until RoundRobin returns interactions -def scores_matrix(actions, game): +def scores_matrix(interactions, game): """ + Parameters + ---------- + interactions : list + A list containing an interactions dictionary for each repetition in a + tournmament. + game : axelrod.Game + The game object to score the tournament. + + Returns + ------- + list + A scores matrix of the form: + + [ + [a, b, c], + [d, e, f], + [g, h, i], + ] + + i.e. one row per player which lists the total score for each + repetition. + + In Axelrod's original tournament, there were no self-interactions + (e.g. player 1 versus player 1) and so these are also excluded from the + scores here. """ - scores = [] + nplayers = player_count(interactions[0]) + repetitions = len(interactions) + scores = [ + [0 for repetition in range(repetitions)] for player in range(nplayers)] + for repetition in range(repetitions): + payoff = payoff_matrix(interactions[repetition], game) + for player in range(nplayers): + for opponent in range(nplayers): + if player != opponent: + scores[player][repetition] += payoff[player][opponent] return scores diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index c2df1e375..d433e88b0 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -28,6 +28,12 @@ def setUpClass(cls): [13, 11, 13] ] + cls.expected_scores_matrix = [ + [26, 26], + [24, 24], + [24, 24] + ] + cls.expected_payoff = [ [[11.0, 11.0], [13, 13], [15, 12]], [[13, 13], [15.0, 15.0], [14, 7]], @@ -87,8 +93,9 @@ def test_interaction_payoff(self): self.assertEqual(payoff, (13, 3)) def test_scores_matrix(self): - scores = ap.scores_matrix(self.interactions, Game()) - self.assertEqual(scores, self.expected_scores) + interactions = [self.interactions, self.interactions] + scores = ap.scores_matrix(interactions, Game()) + self.assertEqual(scores, self.expected_scores_matrix) def test_scores(self): scores = ap.scores(self.expected_payoff) From f13a098fcd5bc9fab8dc5196357584fe47f2021b Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Tue, 3 Nov 2015 08:55:43 +0000 Subject: [PATCH 7/8] removes scores_matrix function --- axelrod/payoff.py | 43 ------------------------------- axelrod/tests/unit/test_payoff.py | 11 -------- 2 files changed, 54 deletions(-) diff --git a/axelrod/payoff.py b/axelrod/payoff.py index 464af28f3..77572b8b3 100644 --- a/axelrod/payoff.py +++ b/axelrod/payoff.py @@ -147,49 +147,6 @@ def interaction_payoff(actions, game): return (player1_payoff, player2_payoff) -# As yet unused until RoundRobin returns interactions -def scores_matrix(interactions, game): - """ - Parameters - ---------- - interactions : list - A list containing an interactions dictionary for each repetition in a - tournmament. - - game : axelrod.Game - The game object to score the tournament. - - Returns - ------- - list - A scores matrix of the form: - - [ - [a, b, c], - [d, e, f], - [g, h, i], - ] - - i.e. one row per player which lists the total score for each - repetition. - - In Axelrod's original tournament, there were no self-interactions - (e.g. player 1 versus player 1) and so these are also excluded from the - scores here. - """ - nplayers = player_count(interactions[0]) - repetitions = len(interactions) - scores = [ - [0 for repetition in range(repetitions)] for player in range(nplayers)] - for repetition in range(repetitions): - payoff = payoff_matrix(interactions[repetition], game) - for player in range(nplayers): - for opponent in range(nplayers): - if player != opponent: - scores[player][repetition] += payoff[player][opponent] - return scores - - def scores(payoff): """ The scores matrix excluding self-interactions diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index d433e88b0..b077891fd 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -28,12 +28,6 @@ def setUpClass(cls): [13, 11, 13] ] - cls.expected_scores_matrix = [ - [26, 26], - [24, 24], - [24, 24] - ] - cls.expected_payoff = [ [[11.0, 11.0], [13, 13], [15, 12]], [[13, 13], [15.0, 15.0], [14, 7]], @@ -92,11 +86,6 @@ def test_interaction_payoff(self): payoff = ap.interaction_payoff(self.interactions[(2, 2)], Game()) self.assertEqual(payoff, (13, 3)) - def test_scores_matrix(self): - interactions = [self.interactions, self.interactions] - scores = ap.scores_matrix(interactions, Game()) - self.assertEqual(scores, self.expected_scores_matrix) - def test_scores(self): scores = ap.scores(self.expected_payoff) self.assertEqual(scores, self.expected_scores) From d80221c921b6918c73bd25c996bf96917b6ea2da Mon Sep 17 00:00:00 2001 From: Owen Campbell Date: Tue, 3 Nov 2015 08:58:35 +0000 Subject: [PATCH 8/8] adds single player to test_player_count --- axelrod/tests/unit/test_payoff.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/axelrod/tests/unit/test_payoff.py b/axelrod/tests/unit/test_payoff.py index b077891fd..592bb62f4 100644 --- a/axelrod/tests/unit/test_payoff.py +++ b/axelrod/tests/unit/test_payoff.py @@ -77,6 +77,8 @@ def setUpClass(cls): def test_player_count(self): nplayers = ap.player_count(self.interactions) self.assertEqual(nplayers, 3) + nplayers = ap.player_count({'test': 'test'}) + self.assertEqual(nplayers, 1) def test_payoff_matrix(self): payoff_matrix = ap.payoff_matrix(self.interactions, Game())