Skip to content

Commit fff94d5

Browse files
Packaging (#27)
* Add a lower bound to requirements.txt * Write setup.py and restructure. * Write tests for outputer. * Tests written for prepare objective. * Tests for the objective score function. * Write tests for score diff. * Write tests and fix a bug for Moran objective. * Write tests for base parameters class. * Add tests for score_params. * Add mypy to gigignore I have no idea what generated these files. * Move the fsm params class. Very slight modification of the repr parser. * Make tests discoverable. * Write an integration test for the FSM. * Make scripts work with library. * Minor clean up of README.md * Add CI. * Correct path for tests. * Fix coverage path. * Add another seed in the integration test. * Add instructions to run tests.
1 parent 994f0c2 commit fff94d5

23 files changed

+656
-157
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ docs/_build/
5656
# PyBuilder
5757
target/
5858
data/
59+
60+
*.mypy*

.travis.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
language: python
2+
python:
3+
- 3.5
4+
- 3.6
5+
6+
7+
before_install:
8+
- export DISPLAY=:99.0
9+
- sh -e /etc/init.d/xvfb start
10+
install:
11+
- pip install -r requirements.txt
12+
- pip install coverage
13+
- pip install coveralls
14+
script:
15+
- python setup.py develop
16+
- coverage run --source=src -m unittest discover tests
17+
- coverage report -m
18+
after_success:
19+
- coveralls

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Axelrod Evolvers
22

3+
4+
35
This repository contains reinforcement learning training code for the following
46
strategy types:
7+
58
* Lookup tables (LookerUp)
69
* Particle Swarm algorithms (PSOGambler), a stochastic version of LookerUp
710
* Feed Forward Neural Network (EvolvedANN)
@@ -10,9 +13,25 @@ strategy types:
1013

1114
Model training is by [evolutionary algorithms](https://en.wikipedia.org/wiki/Evolutionary_algorithm)
1215
or [particle swarm algorithms](https://en.wikipedia.org/wiki/Particle_swarm_optimization).
13-
There is another repository in the [Axerlod project](https://github.com/Axelrod-Python/Axelrod)
16+
There is another repository in the [Axelrod project](https://github.com/Axelrod-Python/Axelrod)
1417
that trains Neural Networks with gradient descent (using tensorflow)
15-
that will likely be incorporated here. In this repository there are scripts
18+
that will likely be incorporated here.
19+
20+
You can use this as a library.
21+
22+
## Development
23+
24+
Install a development version of the library:
25+
26+
$ python setup.py develop
27+
28+
Run the test:
29+
30+
$ python -m unittest discover tests
31+
32+
## Scripts
33+
34+
In this repository there are scripts
1635
for each strategy type with a similar interface:
1736

1837
* [looker_evolve.py](looker_evolve.py)
@@ -21,6 +40,7 @@ for each strategy type with a similar interface:
2140
* [fsm_evolve.py](fsm_evolve.py)
2241
* [hmm_evolve.py](hmm_evolve.py)
2342

43+
2444
See below for usage instructions.
2545

2646
In the original iteration the strategies were run against all the default

ann_evolve.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,12 @@
3333
import random
3434

3535
from docopt import docopt
36-
import numpy as np
3736

38-
from axelrod import Actions
37+
from axelrod import Action
3938
from axelrod.strategies.ann import ANN
40-
from evolve_utils import Params, Population, prepare_objective
39+
from axelrod_dojo import Params, Population, prepare_objective
4140

42-
C, D = Actions.C, Actions.D
41+
C, D = Action.C, Action.D
4342

4443

4544
## Todo: mutation decay

fsm_evolve.py

Lines changed: 1 addition & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -24,140 +24,9 @@
2424
--states NUM_STATES Number of FSM states [default: 8]
2525
"""
2626

27-
import random
28-
from random import randrange, choice
29-
3027
from docopt import docopt
31-
import numpy as np
32-
33-
from axelrod import Actions, flip_action
34-
from axelrod.strategies.finite_state_machines import FSMPlayer
35-
36-
from evolve_utils import Params, Population, prepare_objective
37-
38-
C, D = Actions.C, Actions.D
39-
40-
41-
def copy_lists(rows):
42-
new_rows = list(map(list, rows))
43-
return new_rows
44-
45-
46-
class FSMParams(Params):
47-
48-
def __init__(self, num_states, mutation_rate=None, rows=None,
49-
initial_state=0, initial_action=C):
50-
self.PlayerClass = FSMPlayer
51-
self.num_states = num_states
52-
if mutation_rate is None:
53-
self.mutation_rate = 1 / (2 * num_states)
54-
else:
55-
self.mutation_rate = mutation_rate
56-
if rows is None:
57-
self.randomize()
58-
else:
59-
# Make sure to copy the lists
60-
self.rows = copy_lists(rows)
61-
self.initial_state = initial_state
62-
self.initial_action = initial_action
63-
64-
65-
def player(self):
66-
player = self.PlayerClass(self.rows, self.initial_state,
67-
self.initial_action)
68-
return player
69-
70-
def copy(self):
71-
return FSMParams(self.num_states, self.mutation_rate,
72-
self.rows, self.initial_state, self.initial_action)
73-
74-
@staticmethod
75-
def random_params(num_states):
76-
rows = []
77-
actions = (C, D)
78-
for j in range(num_states):
79-
for action in actions:
80-
next_state = randrange(num_states)
81-
next_action = choice(actions)
82-
row = [j, action, next_state, next_action]
83-
rows.append(row)
84-
initial_state = randrange(num_states)
85-
initial_action = choice([C, D])
86-
return rows, initial_state, initial_action
87-
88-
def randomize(self):
89-
rows, initial_state, initial_action = self.random_params(self.num_states)
90-
self.rows = rows
91-
self.initial_state = initial_state
92-
self.initial_action = initial_action
93-
94-
@staticmethod
95-
def mutate_rows(rows, mutation_rate):
96-
randoms = np.random.random(len(rows))
97-
# Flip each value with a probability proportional to the mutation rate
98-
for i, row in enumerate(rows):
99-
if randoms[i] < mutation_rate:
100-
row[3] = flip_action(row[3])
101-
# Swap Two Nodes?
102-
if random.random() < 0.5:
103-
nodes = len(rows) // 2
104-
n1 = randrange(nodes)
105-
n2 = randrange(nodes)
106-
for j, row in enumerate(rows):
107-
if row[1] == n1:
108-
row[1] = n2
109-
elif row[1] == n2:
110-
row[1] = n1
111-
return rows
112-
113-
def mutate(self):
114-
self.rows = self.mutate_rows(self.rows, self.mutation_rate)
115-
if random.random() < self.mutation_rate / 10:
116-
self.initial_action = flip_action(self.initial_action)
117-
if random.random() < self.mutation_rate / (10 * self.num_states):
118-
self.initial_state = randrange(self.num_states)
119-
# Change node size?
120-
121-
@staticmethod
122-
def crossover_rows(rows1, rows2):
123-
num_states = len(rows1) // 2
124-
crosspoint = 2 * randrange(num_states)
125-
new_rows = copy_lists(rows1[:crosspoint])
126-
new_rows += copy_lists(rows2[crosspoint:])
127-
return new_rows
128-
129-
def crossover(self, other):
130-
# Assuming that the number of states is the same
131-
new_rows = self.crossover_rows(self.rows, other.rows)
132-
return FSMParams(self.num_states, self.mutation_rate, new_rows,
133-
self.initial_state, self.initial_action)
134-
135-
@staticmethod
136-
def repr_rows(rows):
137-
ss = []
138-
for row in rows:
139-
ss.append("_".join(list(map(str, row))))
140-
return ":".join(ss)
141-
142-
def __repr__(self):
143-
return "{}:{}:{}".format(
144-
self.initial_state,
145-
self.initial_action,
146-
self.repr_rows(self.rows)
147-
)
148-
149-
@classmethod
150-
def parse_repr(cls, s):
151-
rows = []
152-
lines = s.split(':')
153-
initial_state = int(lines[0])
154-
initial_action = lines[1]
15528

156-
for line in lines[2:]:
157-
row = line.split('_')
158-
rows.append(row)
159-
num_states = len(rows) // 2
160-
return cls(num_states, 0.1, rows, initial_state, initial_action)
29+
from axelrod_dojo import FSMParams, Population, prepare_objective
16130

16231

16332
if __name__ == '__main__':

hmm_evolve.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@
3535
from docopt import docopt
3636
import numpy as np
3737

38-
from axelrod import Actions, flip_action
38+
from axelrod import Action
3939
from axelrod.strategies.hmm import HMMPlayer
40+
from axelrod_dojo import Params, Population, prepare_objective
4041

41-
from evolve_utils import Params, Population, prepare_objective
42-
43-
C, D = Actions.C, Actions.D
42+
C, D = Action.C, Action.D
4443

4544

4645
def copy_lists(rows):
@@ -145,7 +144,7 @@ def mutate(self):
145144
self.emission_probabilities = mutate_row(
146145
self.emission_probabilities, self.mutation_rate)
147146
if random.random() < self.mutation_rate / 10:
148-
self.initial_action = flip_action(self.initial_action)
147+
self.initial_action = self.initial_action.flip()
149148
if random.random() < self.mutation_rate / (10 * self.num_states):
150149
self.initial_state = randrange(self.num_states)
151150
# Change node size?

lookup_evolve.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@
3131
from docopt import docopt
3232
import numpy as np
3333

34-
from axelrod import Actions, flip_action
34+
from axelrod import Action
3535
from axelrod.strategies.lookerup import LookerUp, create_lookup_table_keys
36+
from axelrod_dojo import Params, Population, prepare_objective
3637

37-
from evolve_utils import Params, Population, prepare_objective
38-
39-
C, D = Actions.C, Actions.D
38+
C, D = Action.C, Action.D
4039

4140

4241
class LookerUpParams(Params):
@@ -92,7 +91,7 @@ def mutate_table(table, mutation_rate):
9291
# Flip each value with a probability proportional to the mutation rate
9392
for i, (history, move) in enumerate(table.items()):
9493
if randoms[i] < mutation_rate:
95-
table[history] = flip_action(move)
94+
table[history] = move.flip()
9695
return table
9796

9897
def mutate(self):
@@ -101,7 +100,7 @@ def mutate(self):
101100
for i in range(len(self.initial_actions)):
102101
r = random.random()
103102
if r < 0.05:
104-
self.initial_actions[i] = flip_action(self.initial_actions[i])
103+
self.initial_actions[i] = self.initial_actions[i].flip()
105104

106105
@staticmethod
107106
def crossover_tables(table1, table2):

pso_evolve.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from axelrod import Gambler
3535
from axelrod.strategies.lookerup import (
3636
create_lookup_table_keys, Plays)
37-
from evolve_utils import prepare_objective, score_for
37+
from axelrod_dojo import prepare_objective, score_for
3838

3939

4040
def optimizepso(param_args, objective, opponents=None):

requirements.txt

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

setup.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from setuptools import setup, find_packages
2+
import unittest
3+
import doctest
4+
import os
5+
6+
# Read in the version number
7+
exec(open('src/axelrod_dojo/version.py', 'r').read())
8+
9+
# Read in the requirements.txt file
10+
with open('requirements.txt') as f:
11+
requirements = []
12+
for library in f.read().splitlines():
13+
if "docopt" not in library: # Skip: used only for command line scripts
14+
requirements.append(library)
15+
16+
setup(
17+
name='axelrod_dojo',
18+
version=__version__,
19+
install_requires=requirements,
20+
author='Marc Harper; Vince Knight; Martin Jones; Georgios Koutsovoulos',
21+
packages=find_packages('src'),
22+
package_dir={"": "src"},
23+
url='',
24+
license='The MIT License (MIT)',
25+
description='A library to train strategies for the Iterated Prisoners Dilemma',
26+
classifiers=[
27+
'Programming Language :: Python :: 3.5',
28+
'Programming Language :: Python :: 3.6',
29+
'Programming Language :: Python :: 3 :: Only',
30+
],
31+
python_requires='>=3.0',
32+
)

0 commit comments

Comments
 (0)