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

Move processes argument from Tournament.__init__ to tournament.play #582

Merged
merged 5 commits into from
May 12, 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
5 changes: 2 additions & 3 deletions axelrod/tests/integration/test_tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ def test_parallel_play(self):
players=self.players,
game=self.game,
turns=20,
repetitions=self.test_repetitions,
processes=2)
scores = tournament.play(progress_bar=False).scores
repetitions=self.test_repetitions)
scores = tournament.play(processes=2, progress_bar=False).scores
actual_outcome = sorted(zip(self.player_names, scores))
self.assertEqual(actual_outcome, self.expected_outcome)
26 changes: 4 additions & 22 deletions axelrod/tests/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ def tournaments(draw, strategies=axelrod.strategies,
min_size=1, max_size=10,
min_turns=1, max_turns=200,
min_noise=0, max_noise=1,
min_repetitions=1, max_repetitions=20,
max_processes=None):
min_repetitions=1, max_repetitions=20):
"""
A hypothesis decorator to return a tournament and a random seed (to ensure
reproducibility for strategies that make use of the random module when
Expand All @@ -85,8 +84,6 @@ def tournaments(draw, strategies=axelrod.strategies,
The minimum number of repetitions
max_repetitions : integer
The maximum number of repetitions
max_processes : bool
Maximum number of processes to use
"""
seed = draw(random_module())
strategies = draw(strategy_lists(strategies=strategies,
Expand All @@ -98,14 +95,8 @@ def tournaments(draw, strategies=axelrod.strategies,
max_value=max_repetitions))
noise = draw(floats(min_value=min_noise, max_value=max_noise))

if max_processes is not None:
processes = draw(integers(min_value=1, max_value=max_processes))
else:
processes = None

tournament = axelrod.Tournament(players, turns=turns,
repetitions=repetitions, noise=noise,
processes=processes)
repetitions=repetitions, noise=noise)
return tournament, seed


Expand All @@ -114,8 +105,7 @@ def prob_end_tournaments(draw, strategies=axelrod.strategies,
min_size=1, max_size=10,
min_prob_end=0, max_prob_end=1,
min_noise=0, max_noise=1,
min_repetitions=1, max_repetitions=20,
max_processes=None):
min_repetitions=1, max_repetitions=20):
"""
A hypothesis decorator to return a tournament and a random seed (to ensure
reproducibility for strategies that make use of the random module when
Expand All @@ -139,8 +129,6 @@ def prob_end_tournaments(draw, strategies=axelrod.strategies,
The minimum number of repetitions
max_repetitions : integer
The maximum number of repetitions
max_processes : bool
Maximum number of processes to use
"""
seed = draw(random_module())
strategies = draw(strategy_lists(strategies=strategies,
Expand All @@ -152,14 +140,8 @@ def prob_end_tournaments(draw, strategies=axelrod.strategies,
max_value=max_repetitions))
noise = draw(floats(min_value=min_noise, max_value=max_noise))

if max_processes is not None:
processes = draw(integers(min_value=1, max_value=max_processes))
else:
processes = None

tournament = axelrod.ProbEndTournament(players, prob_end=prob_end,
repetitions=repetitions, noise=noise,
processes=processes)
repetitions=repetitions, noise=noise)
return tournament, seed


Expand Down
14 changes: 0 additions & 14 deletions axelrod/tests/unit/test_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ def test_decorator(self, tournament_and_seed):
self.assertGreaterEqual(tournament.noise, 0)
self.assertLessEqual(tournament.repetitions, 50)
self.assertGreaterEqual(tournament.repetitions, 2)
self.assertIsNone(tournament._processes)

@given(tournament_and_seed=tournaments(strategies=axelrod.basic_strategies))
def test_decorator_with_given_strategies(self, tournament_and_seed):
Expand All @@ -127,12 +126,6 @@ def test_decorator_with_stochastic_strategies(self, tournament_and_seed):
for p in tournament.players:
self.assertIn(str(p), stochastic_player_names)

@given(tournament_and_seed=tournaments(max_processes=2))
def test_decorator_with_stochastic_strategies(self, tournament_and_seed):
tournament, seed = tournament_and_seed
self.assertGreaterEqual(tournament._processes, 1)
self.assertLessEqual(tournament._processes, 2)


class TestProbEndTournament(unittest.TestCase):

Expand All @@ -157,7 +150,6 @@ def test_decorator(self, tournament_and_seed):
self.assertGreaterEqual(tournament.noise, 0)
self.assertLessEqual(tournament.repetitions, 50)
self.assertGreaterEqual(tournament.repetitions, 2)
self.assertIsNone(tournament._processes)

@given(tournament_and_seed=prob_end_tournaments(strategies=axelrod.basic_strategies))
def test_decorator_with_given_strategies(self, tournament_and_seed):
Expand All @@ -179,12 +171,6 @@ def test_decorator_with_stochastic_strategies(self, tournament_and_seed):
for p in tournament.players:
self.assertIn(str(p), stochastic_player_names)

@given(tournament_and_seed=prob_end_tournaments(max_processes=2))
def test_decorator_with_stochastic_strategies(self, tournament_and_seed):
tournament, seed = tournament_and_seed
self.assertGreaterEqual(tournament._processes, 1)
self.assertLessEqual(tournament._processes, 2)

class TestGame(unittest.TestCase):

def test_call(self):
Expand Down
40 changes: 15 additions & 25 deletions axelrod/tests/unit/test_tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ def test_init(self):
players=self.players,
game=self.game,
turns=self.test_turns,
processes=4,
noise=0.2)
self.assertEqual(len(tournament.players), len(test_strategies))
self.assertIsInstance(
Expand All @@ -73,7 +72,6 @@ def test_init(self):
self.assertEqual(tournament.turns, self.test_turns)
self.assertEqual(tournament.repetitions, 10)
self.assertEqual(tournament.name, 'test')
self.assertEqual(tournament._processes, 4)
self.assertTrue(tournament._with_morality)
self.assertIsInstance(tournament._logger, logging.Logger)
self.assertEqual(tournament.noise, 0.2)
Expand Down Expand Up @@ -183,10 +181,9 @@ def test_progress_bar_play_parallel(self):
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=2)
repetitions=self.test_repetitions)

results = tournament.play()
results = tournament.play(processes=2)
self.assertIsInstance(results, axelrod.ResultSet)

results = tournament.play(progress_bar=True)
Expand Down Expand Up @@ -229,9 +226,8 @@ def test_parallel_play(self):
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=2)
results = tournament.play(progress_bar=False)
repetitions=self.test_repetitions)
results = tournament.play(processes=2, progress_bar=False)
self.assertIsInstance(results, axelrod.ResultSet)

# The following relates to #516
Expand All @@ -243,9 +239,8 @@ def test_parallel_play(self):
players=players,
game=self.game,
turns=20,
repetitions=self.test_repetitions,
processes=2)
scores = tournament.play(progress_bar=False).scores
repetitions=self.test_repetitions)
scores = tournament.play(processes=2, progress_bar=False).scores
self.assertEqual(len(scores), len(players))

def test_run_serial(self):
Expand All @@ -254,8 +249,7 @@ def test_run_serial(self):
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=2)
repetitions=self.test_repetitions)
tournament._write_interactions = MagicMock(
name='_write_interactions')
self.assertTrue(tournament._run_serial())
Expand All @@ -270,8 +264,7 @@ def test_run_parallel(self):
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=2)
repetitions=self.test_repetitions)
tournament._write_interactions = MagicMock(
name='_write_interactions')
self.assertTrue(tournament._run_parallel())
Expand All @@ -288,18 +281,17 @@ def test_n_workers(self):
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=1)
self.assertEqual(tournament._n_workers(), max_processes)
repetitions=self.test_repetitions)
self.assertEqual(tournament._n_workers(processes=1), max_processes)

tournament = axelrod.Tournament(
name=self.test_name,
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=max_processes + 2)
self.assertEqual(tournament._n_workers(), max_processes)
repetitions=self.test_repetitions)
self.assertEqual(tournament._n_workers(processes=max_processes+2),
max_processes)

@unittest.skipIf(
cpu_count() < 2,
Expand All @@ -313,9 +305,8 @@ def test_2_workers(self):
players=self.players,
game=self.game,
turns=200,
repetitions=self.test_repetitions,
processes=2)
self.assertEqual(tournament._n_workers(), 2)
repetitions=self.test_repetitions,)
self.assertEqual(tournament._n_workers(processes=2), 2)

def test_start_workers(self):
workers = 2
Expand Down Expand Up @@ -521,7 +512,6 @@ def test_init(self):
self.assertEqual(tournament.turns, float("inf"))
self.assertEqual(tournament.repetitions, 10)
self.assertEqual(tournament.name, 'test')
self.assertEqual(tournament._processes, None)
self.assertTrue(tournament._with_morality)
self.assertIsInstance(tournament._logger, logging.Logger)
self.assertEqual(tournament.noise, 0.2)
Expand Down
23 changes: 10 additions & 13 deletions axelrod/tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Tournament(object):

def __init__(self, players, match_generator=RoundRobinMatches,
name='axelrod', game=None, turns=200, repetitions=10,
processes=None, noise=0, with_morality=True):
noise=0, with_morality=True):
"""
Parameters
----------
Expand Down Expand Up @@ -53,7 +53,6 @@ def __init__(self, players, match_generator=RoundRobinMatches,
self.match_generator = match_generator(players, turns, self.game,
self.repetitions)
self._with_morality = with_morality
self._processes = processes
self._logger = logging.getLogger(__name__)

def setup_output_file(self, filename=None):
Expand All @@ -68,7 +67,7 @@ def setup_output_file(self, filename=None):
# Save filename for loading ResultSet later
self.filename = filename

def play(self, build_results=True, filename=None, progress_bar=True):
def play(self, build_results=True, filename=None, processes=None, progress_bar=True):
"""
Plays the tournament and passes the results to the ResultSet class

Expand All @@ -92,10 +91,10 @@ def play(self, build_results=True, filename=None, progress_bar=True):
if not build_results and not filename:
warnings.warn("Tournament results will not be accessible since build_results=False and no filename was supplied.")

if self._processes is None:
if processes is None:
self._run_serial(progress_bar=progress_bar)
else:
self._run_parallel(progress_bar=progress_bar)
self._run_parallel(processes=processes, progress_bar=progress_bar)

# Make sure that python has finished writing to disk
self.outputfile.flush()
Expand Down Expand Up @@ -151,7 +150,7 @@ def _write_interactions(self, results):
row.append(history2)
self.writer.writerow(row)

def _run_parallel(self, progress_bar=False):
def _run_parallel(self, processes=2, progress_bar=False):
"""
Run all matches in parallel

Expand All @@ -166,7 +165,7 @@ def _run_parallel(self, progress_bar=False):
# target functions which can be pickled and instance methods cannot.
work_queue = Queue()
done_queue = Queue()
workers = self._n_workers()
workers = self._n_workers(processes=processes)

chunks = self.match_generator.build_match_chunks()
for chunk in chunks:
Expand All @@ -177,16 +176,16 @@ def _run_parallel(self, progress_bar=False):

return True

def _n_workers(self):
def _n_workers(self, processes=2):
"""
Determines the number of parallel processes to use.

Returns
-------
integer
"""
if (2 <= self._processes <= cpu_count()):
n_workers = self._processes
if (2 <= processes <= cpu_count()):
n_workers = processes
else:
n_workers = cpu_count()
return n_workers
Expand Down Expand Up @@ -297,7 +296,6 @@ class ProbEndTournament(Tournament):

def __init__(self, players, match_generator=ProbEndRoundRobinMatches,
name='axelrod', game=None, prob_end=.5, repetitions=10,
processes=None,
noise=0,
with_morality=True):
"""
Expand All @@ -324,8 +322,7 @@ def __init__(self, players, match_generator=ProbEndRoundRobinMatches,
"""
super(ProbEndTournament, self).__init__(
players, name=name, game=game, turns=float("inf"),
repetitions=repetitions, processes=processes,
noise=noise, with_morality=with_morality)
repetitions=repetitions, noise=noise, with_morality=with_morality)

self.prob_end = prob_end
self.match_generator = ProbEndRoundRobinMatches(
Expand Down