11"""Implementation of the Moran process on Graphs."""
22
3- import random
43from collections import Counter
54from typing import Callable , List , Optional , Set , Tuple
65
1110from .deterministic_cache import DeterministicCache
1211from .graph import Graph , complete_graph
1312from .match import Match
14- from .random_ import randrange
15-
16-
17- def fitness_proportionate_selection (
18- scores : List , fitness_transformation : Callable = None
19- ) -> int :
20- """Randomly selects an individual proportionally to score.
21-
22- Parameters
23- ----------
24- scores: Any sequence of real numbers
25- fitness_transformation: A function mapping a score to a (non-negative) float
26-
27- Returns
28- -------
29- An index of the above list selected at random proportionally to the list
30- element divided by the total.
31- """
32- if fitness_transformation is None :
33- csums = np .cumsum (scores )
34- else :
35- csums = np .cumsum ([fitness_transformation (s ) for s in scores ])
36- total = csums [- 1 ]
37- r = random .random () * total
38-
39- for i , x in enumerate (csums ):
40- if x >= r :
41- break
42- return i
13+ from .random_ import RandomGenerator
4314
4415
4516class MoranProcess (object ):
@@ -57,7 +28,8 @@ def __init__(
5728 reproduction_graph : Graph = None ,
5829 fitness_transformation : Callable = None ,
5930 mutation_method = "transition" ,
60- stop_on_fixation = True
31+ stop_on_fixation = True ,
32+ seed = None
6133 ) -> None :
6234 """
6335 An agent based Moran process class. In each round, each player plays a
@@ -128,6 +100,7 @@ def __init__(
128100 self .winning_strategy_name = None # type: Optional[str]
129101 self .mutation_rate = mutation_rate
130102 self .stop_on_fixation = stop_on_fixation
103+ self ._random = RandomGenerator (seed = seed )
131104 m = mutation_method .lower ()
132105 if m in ["atomic" , "transition" ]:
133106 self .mutation_method = m
@@ -182,6 +155,32 @@ def set_players(self) -> None:
182155 self .players .append (player )
183156 self .populations = [self .population_distribution ()]
184157
158+ def fitness_proportionate_selection (self ,
159+ scores : List , fitness_transformation : Callable = None ) -> int :
160+ """Randomly selects an individual proportionally to score.
161+
162+ Parameters
163+ ----------
164+ scores: Any sequence of real numbers
165+ fitness_transformation: A function mapping a score to a (non-negative) float
166+
167+ Returns
168+ -------
169+ An index of the above list selected at random proportionally to the list
170+ element divided by the total.
171+ """
172+ if fitness_transformation is None :
173+ csums = np .cumsum (scores )
174+ else :
175+ csums = np .cumsum ([fitness_transformation (s ) for s in scores ])
176+ total = csums [- 1 ]
177+ r = self ._random .random () * total
178+
179+ for i , x in enumerate (csums ):
180+ if x >= r :
181+ break
182+ return i
183+
185184 def mutate (self , index : int ) -> Player :
186185 """Mutate the player at index.
187186
@@ -199,10 +198,10 @@ def mutate(self, index: int) -> Player:
199198 # Assuming mutation_method == "transition"
200199 if self .mutation_rate > 0 :
201200 # Choose another strategy at random from the initial population
202- r = random .random ()
201+ r = self . _random .random ()
203202 if r < self .mutation_rate :
204203 s = str (self .players [index ])
205- j = randrange (0 , len (self .mutation_targets [s ]))
204+ j = self . _random . randrange (0 , len (self .mutation_targets [s ]))
206205 p = self .mutation_targets [s ][j ]
207206 return p .clone ()
208207 # Just clone the player
@@ -223,13 +222,13 @@ def death(self, index: int = None) -> int:
223222 """
224223 if index is None :
225224 # Select a player to be replaced globally
226- i = randrange (0 , len (self .players ))
225+ i = self . _random . randrange (0 , len (self .players ))
227226 # Record internally for use in _matchup_indices
228227 self .dead = i
229228 else :
230229 # Select locally
231230 # index is not None in this case
232- vertex = random .choice (
231+ vertex = self . _random .choice (
233232 sorted (self .reproduction_graph .out_vertices (self .locations [index ]))
234233 )
235234 i = self .index [vertex ]
0 commit comments