Skip to content

Commit a042374

Browse files
authored
Merge pull request #33 from Axelrod-Python/move-to-opponents-as-instances
Move to opponents as player instances
2 parents e84fb30 + ee8e3f1 commit a042374

File tree

4 files changed

+86
-17
lines changed

4 files changed

+86
-17
lines changed

src/axelrod_dojo/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
from .version import __version__
22
from .archetypes.fsm import FSMParams
3-
from .utils import prepare_objective, Population, load_params, Params, score_for
3+
from .utils import (prepare_objective,
4+
Population,
5+
load_params,
6+
Params,
7+
score_for,
8+
PlayerInfo)

src/axelrod_dojo/utils.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
from collections import namedtuple
12
from functools import partial
23
from itertools import repeat
3-
from multiprocessing import Pool
4+
from multiprocessing import Pool, cpu_count
45
from operator import itemgetter
56
from random import randrange
67
from statistics import mean, pstdev
@@ -137,17 +138,20 @@ def params(self):
137138
def crossover(self, other):
138139
pass
139140

141+
PlayerInfo = namedtuple('PlayerInfo', ['strategy', 'init_kwargs'])
140142

141-
def score_params(params, objective, opponents, weights=None):
143+
def score_params(params, objective,
144+
opponents_information,
145+
weights=None):
142146
"""
143147
Return the overall mean score of a Params instance.
144148
"""
145149
scores_for_all_opponents = []
146150
player = params.player()
147151

148-
for opponent_class in opponents:
152+
for strategy, init_kwargs in opponents_information:
149153
player.reset()
150-
opponent = opponent_class()
154+
opponent = strategy(**init_kwargs)
151155
scores_for_this_opponent = objective(player, opponent)
152156
mean_vs_opponent = mean(scores_for_this_opponent)
153157
scores_for_all_opponents.append(mean_vs_opponent)
@@ -163,6 +167,8 @@ def __init__(self, params_class, params_args, size, objective, output_filename,
163167
bottleneck=None, opponents=None, processes=1, weights=None):
164168
self.params_class = params_class
165169
self.bottleneck = bottleneck
170+
if processes == 0:
171+
processes = cpu_count()
166172
self.pool = Pool(processes=processes)
167173
self.outputer = Outputer(output_filename, mode='a')
168174
self.size = size
@@ -172,9 +178,11 @@ def __init__(self, params_class, params_args, size, objective, output_filename,
172178
else:
173179
self.bottleneck = bottleneck
174180
if opponents is None:
175-
self.opponents = axl.short_run_time_strategies
181+
self.opponents_information = [
182+
PlayerInfo(s, {}) for s in axl.short_run_time_strategies]
176183
else:
177-
self.opponents = opponents
184+
self.opponents_information = [
185+
PlayerInfo(p.__class__, p.init_kwargs) for p in opponents]
178186
self.generation = 0
179187
self.params_args = params_args
180188
self.population = [params_class(*params_args) for _ in range(self.size)]
@@ -184,7 +192,7 @@ def score_all(self):
184192
starmap_params = zip(
185193
self.population,
186194
repeat(self.objective),
187-
repeat(self.opponents),
195+
repeat(self.opponents_information),
188196
repeat(self.weights))
189197
results = self.pool.starmap(score_params, starmap_params)
190198
return results

tests/integration/test_fsm.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def test_score(self):
1717
repetitions = 5
1818
num_states = 2
1919
mutation_rate = .1
20-
opponents = axl.demo_strategies
20+
opponents = [s() for s in axl.demo_strategies]
2121
size = 10
2222

2323
objective = dojo.prepare_objective(name=name,
@@ -68,7 +68,7 @@ def test_score_with_weights(self):
6868
repetitions = 5
6969
num_states = 2
7070
mutation_rate = .1
71-
opponents = axl.demo_strategies
71+
opponents = [s() for s in axl.demo_strategies]
7272
size = 10
7373

7474
objective = dojo.prepare_objective(name=name,
@@ -112,3 +112,38 @@ def test_score_with_weights(self):
112112
self.assertIsInstance(parameters, dojo.FSMParams)
113113

114114
self.assertEqual(best[0].__repr__(), best_params)
115+
116+
def test_score_with_particular_players(self):
117+
"""
118+
These are players that are known to be difficult to pickle
119+
"""
120+
name = "score"
121+
turns = 10
122+
noise = 0
123+
repetitions = 5
124+
num_states = 2
125+
mutation_rate = .1
126+
opponents = [axl.ThueMorse(),
127+
axl.MetaHunter(),
128+
axl.BackStabber(),
129+
axl.Alexei()]
130+
size = 10
131+
132+
objective = dojo.prepare_objective(name=name,
133+
turns=turns,
134+
noise=noise,
135+
repetitions=repetitions)
136+
137+
population = dojo.Population(params_class=dojo.FSMParams,
138+
params_args=(num_states, mutation_rate),
139+
size=size,
140+
objective=objective,
141+
output_filename=self.temporary_file.name,
142+
opponents=opponents,
143+
bottleneck=2,
144+
processes=0)
145+
146+
generations = 4
147+
axl.seed(0)
148+
population.run(generations)
149+
self.assertEqual(population.generation, 4)

tests/unit/test_utils.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,43 +180,64 @@ class DummyParams(utils.Params):
180180
def player(self):
181181
return axl.Cooperator()
182182

183-
184183
class TestScoreParams(unittest.TestCase):
185184
def test_score(self):
186185
axl.seed(0)
187-
opponents = axl.demo_strategies
186+
opponents_information = [utils.PlayerInfo(s, {})
187+
for s in axl.demo_strategies]
188188
objective = utils.prepare_objective()
189189
params = DummyParams()
190190
score = utils.score_params(params,
191191
objective=objective,
192-
opponents=opponents)
192+
opponents_information=opponents_information)
193193
expected_score = 2.0949
194194
self.assertEqual(score, expected_score)
195195

196+
def test_with_init_kwargs(self):
197+
axl.seed(0)
198+
opponents_information = [utils.PlayerInfo(axl.Random, {"p": 0})]
199+
objective = utils.prepare_objective()
200+
params = DummyParams()
201+
score = utils.score_params(params,
202+
objective=objective,
203+
opponents_information=opponents_information)
204+
expected_score = 0
205+
self.assertEqual(score, expected_score)
206+
207+
opponents_information = [utils.PlayerInfo(axl.Random, {"p": 1})]
208+
objective = utils.prepare_objective()
209+
params = DummyParams()
210+
score = utils.score_params(params,
211+
objective=objective,
212+
opponents_information=opponents_information)
213+
expected_score = 3.0
214+
self.assertEqual(score, expected_score)
215+
196216
def test_score_with_weights(self):
197217
axl.seed(0)
198-
opponents = axl.demo_strategies
218+
opponents_information = [utils.PlayerInfo(s, {})
219+
for s in axl.demo_strategies]
199220
objective = utils.prepare_objective()
200221
params = DummyParams()
201222
score = utils.score_params(params,
202223
objective=objective,
203-
opponents=opponents,
224+
opponents_information=opponents_information,
204225
# All weight on Coop
205226
weights=[1, 0, 0, 0, 0])
206227
expected_score = 3
207228
self.assertEqual(score, expected_score)
208229

209230
score = utils.score_params(params,
210231
objective=objective,
211-
opponents=opponents,
232+
opponents_information=opponents_information,
212233
# Shared weight between Coop and Def
213234
weights=[2, 2, 0, 0, 0])
214235
expected_score = 1.5
215236
self.assertEqual(score, expected_score)
216237

217238
score = utils.score_params(params,
218239
objective=objective,
219-
opponents=opponents,
240+
opponents_information=opponents_information,
220241
# Shared weight between Coop and Def
221242
weights=[2, -.5, 0, 0, 0])
222243
expected_score = 4.0

0 commit comments

Comments
 (0)