Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactors match_generator #608

Merged
merged 3 commits into from
May 31, 2016
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
43 changes: 17 additions & 26 deletions axelrod/match_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class MatchGenerator(object):

def __init__(self, players, turns, game, repetitions):
def __init__(self, players, turns, game, repetitions, noise=0):
"""
A class to generate matches. This is used by the Tournament class which
is in charge of playing the matches and collecting the results.
Expand All @@ -22,11 +22,14 @@ def __init__(self, players, turns, game, repetitions):
The game object used to score the match
repetitions : int
The number of repetitions of a given match
noise : float, 0
The probability that a player's intended action should be flipped
"""
self.players = players
self.turns = turns
self.game = game
self.repetitions = repetitions
self.noise = noise
self.opponents = players

@property
Expand All @@ -52,38 +55,28 @@ def build_single_match_params(self):

class RoundRobinMatches(MatchGenerator):

def build_match_chunks(self, noise=0):
def build_match_chunks(self):
"""
A generator that returns player index pairs and match parameters for a
round robin tournament.

parameters
----------
noise : float, 0
The probability that a player's intended action should be flipped

Yields
-------
tuples
((player1 index, player2 index), match object)
"""
for player1_index in range(len(self.players)):
for player2_index in range(player1_index, len(self.players)):
match_params = self.build_single_match_params(noise)
match_params = self.build_single_match_params()
index_pair = (player1_index, player2_index)
yield (index_pair, match_params, self.repetitions)

def build_single_match_params(self, noise=0):
def build_single_match_params(self):
"""
Creates a single set of match parameters.

parameters
----------
noise : float, 0
The probability that a player's intended action should be flipped
"""
cache = None
return (self.turns, self.game, cache, noise)
return (self.turns, self.game, cache, self.noise)

def __len__(self):
"""
Expand All @@ -103,7 +96,7 @@ def estimated_size(self):

class ProbEndRoundRobinMatches(RoundRobinMatches):

def __init__(self, players, prob_end, game, repetitions):
def __init__(self, players, prob_end, game, repetitions, noise=0):
"""
A class that generates matches for which the players do not
know the length of the Match (to their knowledge it is infinite) but
Expand All @@ -117,23 +110,21 @@ def __init__(self, players, prob_end, game, repetitions):
The probability that a turn of a Match is the last
game : axelrod.Game
The game object used to score the match
deterministic_cache : an instance of axelrod.DeterministicCache
A cache of resulting actions for deterministic matches
repetitions : int
The number of repetitions of a given match
noise : float, 0
The probability that a player's intended action should be flipped
"""
super(ProbEndRoundRobinMatches, self).__init__(
players, turns=float("inf"), game=game, repetitions=repetitions)
players, turns=float("inf"), game=game, repetitions=repetitions,
noise=noise)
self.prob_end = prob_end

def build_single_match_params(self, noise=0):
def build_single_match_params(self):
"""
Creates a single set of match parameters.

parameters
----------
noise : float, 0
The probability that a player's intended action should be flipped
"""
return (self.sample_length(self.prob_end), self.game, None, noise)
return (self.sample_length(self.prob_end), self.game, None, self.noise)

def sample_length(self, prob_end):
"""
Expand Down
8 changes: 6 additions & 2 deletions axelrod/tests/unit/test_match_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ def test_build_single_match_params(self):
self.assertEqual(len(match), test_turns)

# Testing with noise
match_params = rr.build_single_match_params(noise=.5)
rr = axelrod.RoundRobinMatches(
self.players, test_turns, test_game, test_repetitions, noise=0.5)
match_params = rr.build_single_match_params()
self.assertIsInstance(match_params, tuple)
self.assertEqual(match_params[0], rr.turns)
self.assertEqual(match_params[1], rr.game)
Expand Down Expand Up @@ -178,7 +180,9 @@ def test_build_single_match_params(self, prob_end, rm):
self.assertGreater(len(match), 0)

# Testing with noise
match_params = rr.build_single_match_params(noise=.5)
rr = axelrod.ProbEndRoundRobinMatches(
self.players, prob_end, test_game, test_repetitions, noise=0.5)
match_params = rr.build_single_match_params()
self.assertIsInstance(match_params, tuple)
self.assertLess(match_params[0], float('inf'))
self.assertGreater(match_params[0], 0)
Expand Down
2 changes: 1 addition & 1 deletion axelrod/tests/unit/test_tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import warnings

from hypothesis import given, example, settings
from hypothesis.strategies import integers, lists, sampled_from, random_module, floats
from hypothesis.strategies import integers
from axelrod.tests.property import tournaments, prob_end_tournaments

import axelrod
Expand Down
8 changes: 4 additions & 4 deletions axelrod/tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def __init__(self, players, match_generator=RoundRobinMatches,
self.game = game
self.players = players
self.repetitions = repetitions
self.match_generator = match_generator(players, turns, self.game,
self.repetitions)
self.match_generator = match_generator(
players, turns, self.game, self.repetitions, self.noise)
self._with_morality = with_morality
self._logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -130,7 +130,7 @@ def _run_serial(self, progress_bar=False):
progress_bar : bool
Whether or not to update the tournament progress bar
"""
chunks = self.match_generator.build_match_chunks(noise=self.noise)
chunks = self.match_generator.build_match_chunks()

for chunk in chunks:
results = self._play_matches(chunk)
Expand Down Expand Up @@ -171,7 +171,7 @@ def _run_parallel(self, processes=2, progress_bar=False):
done_queue = Queue()
workers = self._n_workers(processes=processes)

chunks = self.match_generator.build_match_chunks(noise=self.noise)
chunks = self.match_generator.build_match_chunks()
for chunk in chunks:
work_queue.put(chunk)

Expand Down
8 changes: 4 additions & 4 deletions docs/tutorials/advanced/making_tournaments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ To do this let us create a new class to generate matches::
>>> class StochasticMatchups(axl.RoundRobinMatches):
... """Inherit from the `axelrod.match_generator.RoundRobinMatches` class"""
...
... def build_match_chunks(self, noise=0):
... def build_match_chunks(self):
... """
... A generator that yields match parameters only with a given probability.
...
Expand All @@ -32,7 +32,7 @@ To do this let us create a new class to generate matches::
... for player1_index in range(len(self.players)):
... for player2_index in range(player1_index, len(self.players)):
... if random.random() < 0.5: # This is the modification
... match_params = self.build_single_match_params(noise)
... match_params = self.build_single_match_params()
... index_pair = (player1_index, player2_index)
... yield (index_pair, match_params, self.repetitions)

Expand Down Expand Up @@ -75,12 +75,12 @@ builds matches that were either 200 turns or single 1 shot games::
... """Inherit from the `axelrod.match_generator.RoundRobinMatches` class"""
...
...
... def build_single_match_params(self, noise=0):
... def build_single_match_params(self):
... """Create a single set of match parameters"""
... turns = 1
... if random.random() < 0.5:
... turns = 200
... return (turns, self.game, None, noise)
... return (turns, self.game, None, self.noise)

We can take a look at the match lengths when using this generator::

Expand Down