1
1
from collections import Counter
2
2
import random
3
- from typing import Sequence , List , Tuple
4
3
5
4
import numpy as np
6
5
9
8
from .random_ import randrange
10
9
11
10
12
- def fitness_proportionate_selection (scores : Sequence [ int ]) -> int :
11
+ def fitness_proportionate_selection (scores ) :
13
12
"""Randomly selects an individual proportionally to score.
14
13
15
14
Parameters
@@ -31,8 +30,8 @@ def fitness_proportionate_selection(scores: Sequence[int]) -> int :
31
30
32
31
33
32
class MoranProcess (object ):
34
- def __init__ (self , players , turns : int = 100 , noise : float = 0 , deterministic_cache = None ,
35
- mutation_rate : float = 0. , mode : str = 'bd' , match_class = Match ):
33
+ def __init__ (self , players , turns = 100 , noise = 0 , deterministic_cache = None ,
34
+ mutation_rate = 0. , mode = 'bd' , match_class = Match ):
36
35
"""
37
36
An agent based Moran process class. In each round, each player plays a
38
37
Match with each other player. Players are assigned a fitness score by
@@ -108,7 +107,7 @@ def set_players(self):
108
107
self .players .append (player )
109
108
self .populations = [self .population_distribution ()]
110
109
111
- def mutate (self , index : int ) -> List [ str ] :
110
+ def mutate (self , index ) :
112
111
"""Mutate the player at index."""
113
112
# Choose another strategy at random from the initial population
114
113
r = random .random ()
@@ -122,7 +121,7 @@ def mutate(self, index: int) -> List[str] :
122
121
new_player = self .players [index ].clone ()
123
122
return new_player
124
123
125
- def death (self , index : int = None ) -> int :
124
+ def death (self , index = None ):
126
125
"""Selects the player to be removed. Note that the in the birth-death
127
126
case, the player that is reproducing may also be replaced. However in
128
127
the death-birth case, this player will be excluded from the choices.
@@ -132,7 +131,7 @@ def death(self, index: int=None) -> int:
132
131
i = randrange (0 , len (self .players ))
133
132
return i
134
133
135
- def birth (self , index : int = None ) -> int :
134
+ def birth (self , index = None ):
136
135
"""The birth event."""
137
136
# Compute necessary fitnesses.
138
137
scores = self .score_all ()
@@ -148,7 +147,7 @@ def birth(self, index: int=None) -> int:
148
147
j = fitness_proportionate_selection (scores )
149
148
return j
150
149
151
- def fixation_check (self ) -> bool :
150
+ def fixation_check (self ):
152
151
"""Is the population of a single type?"""
153
152
if self .mutation_rate > 0 :
154
153
return False
@@ -191,7 +190,7 @@ def __next__(self):
191
190
self .fixation_check ()
192
191
return self
193
192
194
- def _matchup_indices (self ) -> Tuple [ str ] :
193
+ def _matchup_indices (self ):
195
194
"""Generate the matchup pairs."""
196
195
indices = []
197
196
N = len (self .players )
@@ -204,7 +203,7 @@ def _matchup_indices(self) -> Tuple[str]:
204
203
indices .append ((i , j ))
205
204
return indices
206
205
207
- def score_all (self ) -> Tuple [ str ] :
206
+ def score_all (self ):
208
207
"""Plays the next round of the process. Every player is paired up
209
208
against every other player and the total scores are recorded."""
210
209
N = len (self .players )
@@ -222,7 +221,7 @@ def score_all(self) -> Tuple[str]:
222
221
self .score_history .append (scores )
223
222
return scores
224
223
225
- def population_distribution (self ) -> int :
224
+ def population_distribution (self ):
226
225
"""Returns the population distribution of the last iteration."""
227
226
player_names = [str (player ) for player in self .players ]
228
227
counter = Counter (player_names )
@@ -249,14 +248,14 @@ def play(self):
249
248
break
250
249
return self .populations
251
250
252
- def __len__ (self ) -> int :
251
+ def __len__ (self ):
253
252
return len (self .populations )
254
253
255
254
256
255
class MoranProcessGraph (MoranProcess ):
257
256
def __init__ (self , players , interaction_graph , reproduction_graph = None ,
258
- turns : int = 100 , noise : float = 0 , deterministic_cache = None ,
259
- mutation_rate : float = 0. , mode : str = 'bd' , match_class = Match ):
257
+ turns = 100 , noise = 0 , deterministic_cache = None ,
258
+ mutation_rate = 0. , mode = 'bd' , match_class = Match ):
260
259
"""
261
260
An agent based Moran process class. In each round, each player plays a
262
261
Match with each neighboring player according to the interaction graph.
@@ -321,7 +320,7 @@ def __init__(self, players, interaction_graph, reproduction_graph=None,
321
320
self .index = dict (zip (interaction_graph .vertices (),
322
321
range (len (players ))))
323
322
324
- def birth (self , index : int = None ) -> int :
323
+ def birth (self , index = None ):
325
324
"""Compute the birth index."""
326
325
scores = self .score_all ()
327
326
if index :
@@ -335,7 +334,7 @@ def birth(self, index: int=None) -> int:
335
334
j = fitness_proportionate_selection (scores )
336
335
return j
337
336
338
- def death (self , index : int = None ) -> int :
337
+ def death (self , index = None ):
339
338
"""Selects the player to be removed."""
340
339
if self .mode == "db" :
341
340
# Select a player to be replaced globally
@@ -350,7 +349,7 @@ def death(self, index: int=None) -> int:
350
349
i = self .index [vertex ]
351
350
return i
352
351
353
- def _matchup_indices (self ) -> Tuple [ str ] :
352
+ def _matchup_indices (self ):
354
353
"""Generate the matchup pairs"""
355
354
indices = set ()
356
355
# For death-birth we only want the neighbors of the dead node
@@ -373,7 +372,7 @@ def _matchup_indices(self) -> Tuple[str]:
373
372
indices .add ((i , j ))
374
373
return indices
375
374
376
- def population_distribution (self ) -> int :
375
+ def population_distribution (self ):
377
376
"""Returns the population distribution of the last iteration."""
378
377
player_names = [str (player ) for player in self .players ]
379
378
counter = Counter (player_names )
0 commit comments