Skip to content

Commit d0b4d79

Browse files
committed
New mutation method for Moran processes
1 parent f68cb0d commit d0b4d79

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

axelrod/graph.py

Lines changed: 26 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,42 @@ 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+
edges = []
152+
# Two complete graphs
153+
for cluster in range(2):
154+
for i in range(length):
155+
for j in range(i + 1, length):
156+
edges.append(("{}:{}".format(cluster, i),
157+
"{}:{}".format(cluster, j)))
158+
# Attach at one node
159+
edges.append(("0:0", "1:0"))
160+
graph = Graph(directed=directed, edges=edges)
142161
if loops:
143162
graph.add_loops()
144163

axelrod/moran.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(
5656
interaction_graph: Graph = None,
5757
reproduction_graph: Graph = None,
5858
fitness_transformation: Callable = None,
59+
mutation_method="transition"
5960
) -> None:
6061
"""
6162
An agent based Moran process class. In each round, each player plays a
@@ -120,6 +121,11 @@ def __init__(
120121
self.score_history = [] # type: List
121122
self.winning_strategy_name = None # type: Optional[str]
122123
self.mutation_rate = mutation_rate
124+
m = mutation_method.lower()
125+
if m in ["atomic", "transition"]:
126+
self.mutation_method = m
127+
else:
128+
raise ValueError("Invalid mutation method {}".format(mutation_method))
123129
assert (mutation_rate >= 0) and (mutation_rate <= 1)
124130
assert (noise >= 0) and (noise <= 1)
125131
mode = mode.lower()
@@ -176,6 +182,12 @@ def mutate(self, index: int) -> Player:
176182
index:
177183
The index of the player to be mutated
178184
"""
185+
186+
if self.mutation_method == "atomic":
187+
mutant = self.players[index].clone()
188+
mutant.mutate()
189+
return mutant
190+
179191
# Choose another strategy at random from the initial population
180192
r = random.random()
181193
if r < self.mutation_rate:

0 commit comments

Comments
 (0)