Skip to content

Commit 5090660

Browse files
committed
Fix merge conflict
2 parents 16056a0 + ea066ba commit 5090660

File tree

89 files changed

+10610
-1243
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+10610
-1243
lines changed

.travis.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
1+
dist: xenial
2+
services:
3+
- xvfb
24
language: python
35
python:
4-
- 3.5
6+
- 3.7
57
- 3.6
6-
78
cache:
89
directories:
910
- $TRAVIS_BUILD_DIR/.hypothesis
10-
11-
before_install:
12-
- export DISPLAY=:99.0
13-
- sh -e /etc/init.d/xvfb start
1411
install:
1512
- pip install -r requirements.txt
1613
- pip install sphinx

CHANGES.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,63 @@
1+
# v4.8.0, 2019-12-16
2+
3+
Reimplementation of first tournament strategies, rename of second tournament
4+
strategies and
5+
6+
- Reimplement and rename first tournament strategies and rename second
7+
tournament strategies:
8+
https://github.com/Axelrod-Python/Axelrod/pull/1275
9+
- Update citations:
10+
https://github.com/Axelrod-Python/Axelrod/pull/1276
11+
https://github.com/Axelrod-Python/Axelrod/pull/1278
12+
- Add Detective strategy:
13+
https://github.com/Axelrod-Python/Axelrod/pull/1269
14+
- Remove Fool Me Forever (duplicate):
15+
https://github.com/Axelrod-Python/Axelrod/pull/1274
16+
- Add documentation to a testing script:
17+
https://github.com/Axelrod-Python/Axelrod/pull/1271
18+
- Fix documentation render:
19+
https://github.com/Axelrod-Python/Axelrod/pull/1268
20+
21+
https://github.com/Axelrod-Python/Axelrod/compare/v4.8.0...v4.7.0
22+
23+
# v4.7.0, 2019-10-23
24+
25+
New Moran process mechanics, new strategy implementations, drop support for
26+
python 3.5 and various minor fixes.
27+
28+
- Drop support for python 3.5:
29+
https://github.com/Axelrod-Python/Axelrod/pull/1255
30+
https://github.com/Axelrod-Python/Axelrod/pull/1254
31+
- New strategies:
32+
https://github.com/Axelrod-Python/Axelrod/pull/1263
33+
- Bug fix:
34+
https://github.com/Axelrod-Python/Axelrod/pull/1260
35+
- Documentation fixes:
36+
https://github.com/Axelrod-Python/Axelrod/pull/1266
37+
https://github.com/Axelrod-Python/Axelrod/pull/1262
38+
- Implement Evolvable Player for Moran processes:
39+
https://github.com/Axelrod-Python/Axelrod/pull/1267
40+
https://github.com/Axelrod-Python/Axelrod/pull/1256
41+
- Update citations: https://github.com/Axelrod-Python/Axelrod/pull/1249
42+
43+
https://github.com/Axelrod-Python/Axelrod/compare/v4.7.0...v4.6.0
44+
45+
# v4.6.0, 2019-05-20
46+
47+
New history class, new strategy from Axelrod's first tournament and a number of
48+
internal fixes/improvements.
49+
50+
- A new history class: https://github.com/Axelrod-Python/Axelrod/pull/1241
51+
- Minor internal fixes: https://github.com/Axelrod-Python/Axelrod/pull/1236
52+
https://github.com/Axelrod-Python/Axelrod/pull/1237
53+
https://github.com/Axelrod-Python/Axelrod/pull/1243
54+
- Test speed up and refactor:
55+
https://github.com/Axelrod-Python/Axelrod/pull/1238
56+
- New strategy (Graaskamp from RA's first tournament):
57+
https://github.com/Axelrod-Python/Axelrod/pull/1244
58+
59+
https://github.com/Axelrod-Python/Axelrod/compare/v4.6.0...v4.5.0
60+
161
# v4.5.0, 2019-01-31
262

363
Implemented algorithm for memory depth of Finite State Machines, some new

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
environment:
22
matrix:
3-
- PYTHON: "C:\\Python35"
3+
- PYTHON: "C:\\Python37"
44
- PYTHON: "C:\\Python36"
55
install:
66
- "%PYTHON%\\python.exe --version"

axelrod/__init__.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
from axelrod.load_data_ import load_pso_tables, load_weights
66
from axelrod import graph
77
from axelrod.action import Action
8-
from axelrod.random_ import random_choice, seed, Pdf
8+
from axelrod.random_ import random_choice, random_flip, seed, Pdf
99
from axelrod.plot import Plot
1010
from axelrod.game import DefaultGame, Game
11-
from axelrod.player import (
12-
get_state_distribution_from_history,
13-
is_basic,
14-
obey_axelrod,
15-
update_history,
16-
update_state_distribution,
17-
Player,
18-
)
11+
from axelrod.history import History, LimitedHistory
12+
from axelrod.player import is_basic, obey_axelrod, Player
13+
from axelrod.evolvable_player import EvolvablePlayer
1914
from axelrod.mock_player import MockPlayer
2015
from axelrod.match import Match
2116
from axelrod.moran import MoranProcess, ApproximateMoranProcess

axelrod/_strategy_utils.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from functools import lru_cache
55

66
from axelrod.action import Action
7-
from axelrod.player import update_history
87
from axelrod.strategies.cooperator import Cooperator
98
from axelrod.strategies.defector import Defector
109

@@ -56,7 +55,7 @@ def inspect_strategy(inspector, opponent):
5655
----------
5756
inspector: Player
5857
The player doing the inspecting
59-
oponnent: Player
58+
opponent: Player
6059
The player being inspected
6160
6261
Returns
@@ -91,8 +90,8 @@ def _limited_simulate_play(player_1, player_2, h1):
9190
The next action for first player.
9291
"""
9392
h2 = inspect_strategy(player_1, player_2)
94-
update_history(player_1, h1)
95-
update_history(player_2, h2)
93+
player_1.update_history(h1, h2)
94+
player_2.update_history(h2, h1)
9695

9796

9897
def simulate_match(player_1, player_2, strategy, rounds=10):
@@ -190,6 +189,5 @@ def recursive_thue_morse(n):
190189

191190
def thue_morse_generator(start=0):
192191
"""A generator for the Thue-Morse sequence."""
193-
194192
for n in itertools.count(start):
195193
yield recursive_thue_morse(n)

axelrod/action.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ def flip(self):
4242
"""Returns the opposite Action."""
4343
if self == Action.C:
4444
return Action.D
45-
if self == Action.D:
46-
return Action.C
45+
return Action.C
4746

4847
@classmethod
4948
def from_char(cls, character):

axelrod/evolvable_player.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import base64
2+
from pickle import dumps, loads
3+
from random import randrange
4+
from typing import Dict, List
5+
from .player import Player
6+
7+
8+
class InsufficientParametersError(Exception):
9+
"""Error indicating that insufficient parameters were specified to initialize an Evolvable Player."""
10+
def __init__(self, *args):
11+
super().__init__(*args)
12+
13+
14+
class EvolvablePlayer(Player):
15+
"""A class for a player that can evolve, for use in the Moran process or with reinforcement learning algorithms.
16+
17+
This is an abstract base class, not intended to be used directly.
18+
"""
19+
20+
name = "EvolvablePlayer"
21+
parent_class = Player
22+
parent_kwargs = [] # type: List[str]
23+
24+
def overwrite_init_kwargs(self, **kwargs):
25+
"""Use to overwrite parameters for proper cloning and testing."""
26+
for k, v in kwargs.items():
27+
self.init_kwargs[k] = v
28+
29+
def create_new(self, **kwargs):
30+
"""Creates a new variant with parameters overwritten by kwargs."""
31+
init_kwargs = self.init_kwargs.copy()
32+
init_kwargs.update(kwargs)
33+
return self.__class__(**init_kwargs)
34+
35+
# Serialization and deserialization. You may overwrite to obtain more human readable serializations
36+
# but you must overwrite both.
37+
38+
def serialize_parameters(self):
39+
"""Serialize parameters."""
40+
pickled = dumps(self.init_kwargs) # bytes
41+
s = base64.b64encode(pickled).decode('utf8') # string
42+
return s
43+
44+
@classmethod
45+
def deserialize_parameters(cls, serialized):
46+
"""Deserialize parameters to a Player instance."""
47+
init_kwargs = loads(base64.b64decode(serialized))
48+
return cls(**init_kwargs)
49+
50+
# Optional methods for evolutionary algorithms and Moran processes.
51+
52+
def mutate(self):
53+
"""Optional method to allow Player to produce a variant (not in place)."""
54+
pass # pragma: no cover
55+
56+
def crossover(self, other):
57+
"""Optional method to allow Player to produce variants in combination with another player. Returns a new
58+
Player."""
59+
pass # pragma: no cover
60+
61+
# Optional methods for particle swarm algorithm.
62+
63+
def receive_vector(self, vector):
64+
"""Receive a vector of params and overwrite the Player."""
65+
pass # pragma: no cover
66+
67+
def create_vector_bounds(self):
68+
"""Creates the bounds for the decision variables for Particle Swarm Algorithm."""
69+
pass # pragma: no cover
70+
71+
72+
def copy_lists(lists: List[List]) -> List[List]:
73+
return list(map(list, lists))
74+
75+
76+
def crossover_lists(list1: List, list2: List) -> List:
77+
cross_point = randrange(len(list1))
78+
new_list = list(list1[:cross_point]) + list(list2[cross_point:])
79+
return new_list
80+
81+
82+
def crossover_dictionaries(table1: Dict, table2: Dict) -> Dict:
83+
keys = list(table1.keys())
84+
cross_point = randrange(len(keys))
85+
new_items = [(k, table1[k]) for k in keys[:cross_point]]
86+
new_items += [(k, table2[k]) for k in keys[cross_point:]]
87+
new_table = dict(new_items)
88+
return new_table

axelrod/fingerprint.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import csv
21
import os
32
from collections import namedtuple
43
from tempfile import mkstemp
54
from typing import Any, List, Union
65

7-
import dask as da
86
import dask.dataframe as dd
97
import matplotlib.pyplot as plt
108
import numpy as np
@@ -285,10 +283,10 @@ def fingerprint(
285283
"""Build and play the spatial tournament.
286284
287285
Creates the probes and their edges then builds a spatial tournament.
288-
When the coordinates of the probe sum to more than 1, the dual of the
286+
When the coordinates of the probe sum to more than 1, the flip_plays of the
289287
probe is taken instead and then the Joss-Ann Transformer is applied. If
290288
the coordinates sum to less than 1 (or equal), then only the Joss-Ann is
291-
applied, a dual is not required.
289+
applied, a flip_plays is not required.
292290
293291
Parameters
294292
----------

axelrod/graph.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def _add_edges(self, edges):
6666
self._add_edge(*edge)
6767

6868
def add_loops(self):
69-
"""Add all loops to edges."""
69+
"""
70+
Add all loops to edges
71+
"""
7072
self._add_edges((x, x) for x in self.vertices)
7173

7274
@property
@@ -120,25 +122,44 @@ def cycle(length, directed=False):
120122
return Graph(edges=edges, directed=directed)
121123

122124

123-
def complete_graph(size, loops=True):
124-
""" Produces a complete graph of specificies size.
125-
126-
See https://en.wikipedia.org/wiki/Complete_graph for details.
125+
def complete_graph(size, loops=True, directed=False):
126+
"""
127+
Produces a complete graph of size `length`.
128+
https://en.wikipedia.org/wiki/Complete_graph
127129
128130
Parameters
129131
----------
130132
size: int
131133
Number of vertices in the cycle
132134
loops: bool, True
133-
Should the graph contain cycles?
135+
attach loops at each node?
136+
directed: bool, False
137+
Is the graph directed?
134138
135139
Returns
136140
-------
137141
a Graph object for the complete graph
138142
"""
139143
edges = [(i, j) for i in range(size) for j in range(i + 1, size)]
140-
graph = Graph(edges=edges, directed=False)
144+
graph = Graph(directed=directed, edges=edges)
145+
if loops:
146+
graph.add_loops()
147+
return graph
148+
141149

150+
def attached_complete_graphs(length, loops=True, directed=False):
151+
"""Creates two complete undirected graphs of size `length`
152+
attached by a single edge."""
153+
edges = []
154+
# Two complete graphs
155+
for cluster in range(2):
156+
for i in range(length):
157+
for j in range(i + 1, length):
158+
edges.append(("{}:{}".format(cluster, i),
159+
"{}:{}".format(cluster, j)))
160+
# Attach at one node
161+
edges.append(("0:0", "1:0"))
162+
graph = Graph(directed=directed, edges=edges)
142163
if loops:
143164
graph.add_loops()
144165

0 commit comments

Comments
 (0)