Skip to content

Commit a1ac0a7

Browse files
Add weights to objective (#28)
* Use numpy average in score_params. This is with a view to use the weights so that we can weight scoring according to weights for each opponent. (Mainly to be able to use the regression model type work in Axelrod's second paper.) * Write tests for weights in utils.score_params. * Add ability to weight opponents. This is with a view to use the coefficients from the regression analysis in the training. * Remove tqdm
1 parent 7c05f46 commit a1ac0a7

File tree

4 files changed

+89
-5
lines changed

4 files changed

+89
-5
lines changed

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
axelrod>=3.3.0
2-
tqdm>=3.4.0
32
pyswarm>=0.6
43
docopt>=0.6.2

src/axelrod_dojo/utils.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import csv
88
import os
99

10+
import numpy as np
1011
import axelrod as axl
1112

1213

@@ -130,7 +131,7 @@ def crossover(self, other):
130131
pass
131132

132133

133-
def score_params(params, objective, opponents):
134+
def score_params(params, objective, opponents, weights=None):
134135
"""
135136
Return the overall mean score of a Params instance.
136137
"""
@@ -144,14 +145,15 @@ def score_params(params, objective, opponents):
144145
mean_vs_opponent = mean(scores_for_this_opponent)
145146
scores_for_all_opponents.append(mean_vs_opponent)
146147

147-
overall_mean_score = mean(scores_for_all_opponents)
148+
overall_mean_score = np.average(scores_for_all_opponents,
149+
weights=weights)
148150
return overall_mean_score
149151

150152

151153
class Population(object):
152154
"""Population class that implements the evolutionary algorithm."""
153155
def __init__(self, params_class, params_args, size, objective, output_filename,
154-
bottleneck=None, opponents=None, processes=1):
156+
bottleneck=None, opponents=None, processes=1, weights=None):
155157
self.params_class = params_class
156158
self.bottleneck = bottleneck
157159
self.pool = Pool(processes=processes)
@@ -169,12 +171,14 @@ def __init__(self, params_class, params_args, size, objective, output_filename,
169171
self.generation = 0
170172
self.params_args = params_args
171173
self.population = [params_class(*params_args) for _ in range(self.size)]
174+
self.weights = weights
172175

173176
def score_all(self):
174177
starmap_params = zip(
175178
self.population,
176179
repeat(self.objective),
177-
repeat(self.opponents))
180+
repeat(self.opponents),
181+
repeat(self.weights))
178182
results = self.pool.starmap(score_params, starmap_params)
179183
return results
180184

tests/integration/test_fsm.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,55 @@ def test_score(self):
6060
self.assertIsInstance(parameters, dojo.FSMParams)
6161

6262
self.assertEqual(best[0].__repr__(), best_params)
63+
64+
def test_score_with_weights(self):
65+
name = "score"
66+
turns = 10
67+
noise = 0
68+
repetitions = 5
69+
num_states = 2
70+
mutation_rate = .1
71+
opponents = axl.demo_strategies
72+
size = 10
73+
74+
objective = dojo.prepare_objective(name=name,
75+
turns=turns,
76+
noise=noise,
77+
repetitions=repetitions)
78+
79+
population = dojo.Population(params_class=dojo.FSMParams,
80+
params_args=(num_states, mutation_rate),
81+
size=size,
82+
objective=objective,
83+
output_filename=self.temporary_file.name,
84+
opponents=opponents,
85+
weights=[5, 1, 1, 1, 1],
86+
bottleneck=2,
87+
processes=1)
88+
89+
generations = 4
90+
axl.seed(0)
91+
population.run(generations)
92+
self.assertEqual(population.generation, 4)
93+
94+
# Manually read from tempo file to find best strategy
95+
best_score, best_params = 0, None
96+
with open(self.temporary_file.name, "r") as f:
97+
reader = csv.reader(f)
98+
for row in reader:
99+
_, mean_score, sd_score, max_score, arg_max = row
100+
if float(max_score) > best_score:
101+
best_score = float(max_score)
102+
best_params = arg_max
103+
104+
# Test the load params function
105+
for num in range(1, 4 + 1):
106+
best = dojo.load_params(params_class=dojo.FSMParams,
107+
filename=self.temporary_file.name,
108+
num=num)
109+
self.assertEqual(len(best), num)
110+
111+
for parameters in best:
112+
self.assertIsInstance(parameters, dojo.FSMParams)
113+
114+
self.assertEqual(best[0].__repr__(), best_params)

tests/unit/test_utils.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,32 @@ def test_score(self):
190190
opponents=opponents)
191191
expected_score = 2.0949
192192
self.assertEqual(score, expected_score)
193+
194+
def test_score_with_weights(self):
195+
axl.seed(0)
196+
opponents = axl.demo_strategies
197+
objective = utils.prepare_objective()
198+
params = DummyParams()
199+
score = utils.score_params(params,
200+
objective=objective,
201+
opponents=opponents,
202+
# All weight on Coop
203+
weights=[1, 0, 0, 0, 0])
204+
expected_score = 3
205+
self.assertEqual(score, expected_score)
206+
207+
score = utils.score_params(params,
208+
objective=objective,
209+
opponents=opponents,
210+
# Shared weight between Coop and Def
211+
weights=[2, 2, 0, 0, 0])
212+
expected_score = 1.5
213+
self.assertEqual(score, expected_score)
214+
215+
score = utils.score_params(params,
216+
objective=objective,
217+
opponents=opponents,
218+
# Shared weight between Coop and Def
219+
weights=[2, -.5, 0, 0, 0])
220+
expected_score = 4.0
221+
self.assertEqual(score, expected_score)

0 commit comments

Comments
 (0)