From e1fc7e2fe0d07ed2a7ddeb43e9218e0ced6260d2 Mon Sep 17 00:00:00 2001 From: James Campbell Date: Mon, 19 Sep 2016 12:48:18 +0100 Subject: [PATCH 1/3] Add fuctions to compute the state distribution for a match --- axelrod/interaction_utils.py | 24 ++++++++++++++++++++++++ axelrod/match.py | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/axelrod/interaction_utils.py b/axelrod/interaction_utils.py index a9449f450..73c3cdcfd 100644 --- a/axelrod/interaction_utils.py +++ b/axelrod/interaction_utils.py @@ -9,6 +9,7 @@ interactions. """ import csv +from collections import Counter from .game import Game from axelrod import Actions @@ -87,6 +88,29 @@ def compute_normalised_cooperation(interactions): return normalised_cooperation +def compute_state_distribution(interactions): + """ + Returns the count of each state for a set of interactions. + """ + if len(interactions) == 0: + return None + return Counter(interactions) + + +def compute_normalised_state_distribution(interactions): + """ + Returns the normalized count of each state for a set of interactions. + """ + normalized_count = Counter(interactions) + total = sum(normalized_count.values(), 0.0) + # By starting the sum with 0.0 we make sure total is a floating point value, + # avoiding the Python 2 floor division behaviour of / with integer operands (Stack Overflow) + + for key in normalized_count: + normalized_count[key] /= total + return normalized_count + + def sparkline(actions, c_symbol=u'█', d_symbol=u' '): return u''.join([ c_symbol if play == 'C' else d_symbol for play in actions]) diff --git a/axelrod/match.py b/axelrod/match.py index 8b70b928e..c9fe02d69 100644 --- a/axelrod/match.py +++ b/axelrod/match.py @@ -159,6 +159,12 @@ def normalised_cooperation(self): """Returns the count of cooperations by each player per turn""" return iu.compute_normalised_cooperation(self.result) + def state_distribution(self): + return iu.compute_state_distribution(self.result) + + def normalised_state_distribution(self): + return iu.compute_normalised_state_distribution(self.result) + def sparklines(self, c_symbol=u'█', d_symbol=u' '): return iu.compute_sparklines(self.result, c_symbol, d_symbol) From 8d0033e822f9085c3a024c92eb7324cd7e3918f1 Mon Sep 17 00:00:00 2001 From: James Campbell Date: Mon, 19 Sep 2016 13:40:57 +0100 Subject: [PATCH 2/3] Add tests for state_distribution and these tests currently pass --- axelrod/interaction_utils.py | 3 +++ axelrod/tests/unit/test_interaction_utils.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/axelrod/interaction_utils.py b/axelrod/interaction_utils.py index 73c3cdcfd..fae69b2bb 100644 --- a/axelrod/interaction_utils.py +++ b/axelrod/interaction_utils.py @@ -101,6 +101,9 @@ def compute_normalised_state_distribution(interactions): """ Returns the normalized count of each state for a set of interactions. """ + if len(interactions) == 0: + return None + normalized_count = Counter(interactions) total = sum(normalized_count.values(), 0.0) # By starting the sum with 0.0 we make sure total is a floating point value, diff --git a/axelrod/tests/unit/test_interaction_utils.py b/axelrod/tests/unit/test_interaction_utils.py index 11aab59f2..82cba14d3 100644 --- a/axelrod/tests/unit/test_interaction_utils.py +++ b/axelrod/tests/unit/test_interaction_utils.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import unittest import tempfile +from collections import Counter import axelrod import axelrod.interaction_utils as iu @@ -17,6 +18,14 @@ class TestMatch(unittest.TestCase): winners = [False, 0, 1, None] cooperations = [(1, 1), (0, 2), (2, 1), None] normalised_cooperations = [(.5, .5), (0, 1), (1, .5), None] + state_distribution = [Counter({('C', 'D'): 1, ('D', 'C'): 1}), + Counter({('D', 'C'): 2}), + Counter({('C', 'C'): 1, ('C', 'D'): 1}), + None] + normalised_state_distribution = [Counter({('C', 'D'): 0.5, ('D', 'C'): 0.5}), + Counter({('D', 'C'): 1.0}), + Counter({('C', 'C'): 0.5, ('C', 'D'): 0.5}), + None] sparklines = [ u'█ \n █', u' \n██', u'██\n█ ', None ] @@ -46,6 +55,14 @@ def test_compute_normalised_cooperations(self): for inter, coop in zip(self.interactions, self.normalised_cooperations): self.assertEqual(coop, iu.compute_normalised_cooperation(inter)) + def test_compute_state_distribution(self): + for inter, dist in zip(self.interactions, self.state_distribution): + self.assertEqual(dist, iu.compute_state_distribution(inter)) + + def test_compute_normalised_state_distribution(self): + for inter, dist in zip(self.interactions, self.normalised_state_distribution): + self.assertEqual(dist, iu.compute_normalised_state_distribution(inter)) + def test_compute_sparklines(self): for inter, spark in zip(self.interactions, self.sparklines): self.assertEqual(spark, iu.compute_sparklines(inter)) From 49f7fb7f8248a1d8eb4b8e7b1f7f2db73f6bd22b Mon Sep 17 00:00:00 2001 From: James Campbell Date: Mon, 26 Sep 2016 10:18:06 +0100 Subject: [PATCH 3/3] Improve documentation for state_distribution functions --- axelrod/interaction_utils.py | 39 +++++++++++++++++++++++++++++------- axelrod/match.py | 6 ++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/axelrod/interaction_utils.py b/axelrod/interaction_utils.py index fae69b2bb..dafefc0c2 100644 --- a/axelrod/interaction_utils.py +++ b/axelrod/interaction_utils.py @@ -91,8 +91,20 @@ def compute_normalised_cooperation(interactions): def compute_state_distribution(interactions): """ Returns the count of each state for a set of interactions. + + Parameters + ---------- + interactions : list of tuples + A list containing the interactions of the match as shown at the top of + this file. + + Returns + ---------- + Counter(interactions) : Counter Object + Dictionary where the keys are the states and the values are the number + of times that state occurs. """ - if len(interactions) == 0: + if not interactions: return None return Counter(interactions) @@ -100,17 +112,30 @@ def compute_state_distribution(interactions): def compute_normalised_state_distribution(interactions): """ Returns the normalized count of each state for a set of interactions. + + Parameters + ---------- + interactions : list of tuples + A list containing the interactions of the match as shown at the top of + this file. + + Returns + ---------- + normalized_count : Counter Object + Dictionary where the keys are the states and the values are a normalized + count of the number of times that state occurs. """ - if len(interactions) == 0: + if not interactions: return None - normalized_count = Counter(interactions) - total = sum(normalized_count.values(), 0.0) + interactions_count = Counter(interactions) + total = sum(interactions_count.values(), 0.0) # By starting the sum with 0.0 we make sure total is a floating point value, - # avoiding the Python 2 floor division behaviour of / with integer operands (Stack Overflow) + # avoiding the Python 2 floor division behaviour of / with integer operands + # (Stack Overflow) - for key in normalized_count: - normalized_count[key] /= total + normalized_count = Counter({key: value / total for key, value in + interactions_count.items()}) return normalized_count diff --git a/axelrod/match.py b/axelrod/match.py index c9fe02d69..1fe5f4e7b 100644 --- a/axelrod/match.py +++ b/axelrod/match.py @@ -160,9 +160,15 @@ def normalised_cooperation(self): return iu.compute_normalised_cooperation(self.result) def state_distribution(self): + """ + Returns the count of each state for a set of interactions. + """ return iu.compute_state_distribution(self.result) def normalised_state_distribution(self): + """ + Returns the normalized count of each state for a set of interactions. + """ return iu.compute_normalised_state_distribution(self.result) def sparklines(self, c_symbol=u'█', d_symbol=u' '):