@@ -42,7 +42,8 @@ def __init__(self, func, boundary,
4242 generation = 50 ,
4343 cross_rate = 0.8 ,
4444 mutate_rate = 0.1 ,
45- selection = 'roulette_wheel' ,
45+ selection = 'tournament' ,
46+ tournament_size = 3 ,
4647 crossover = 'one_point' ):
4748
4849 self .population_size = population_size
@@ -52,6 +53,7 @@ def __init__(self, func, boundary,
5253 self .boundary = boundary
5354 self .population = []
5455 self .selection_method = selection
56+ self .tournament_size = tournament_size
5557 self .crossover_method = crossover
5658 self .fitness_func = func
5759
@@ -78,24 +80,23 @@ def selection(self, population, k):
7880 """
7981 Select k genes based on certain rules. Accepted rules:
8082 - roulette-wheel
81- - tournament (TO DO)
82- - stochastic (To DO)
83+ - tournament
84+ - stochastic
8385 - truncation (To DO)
8486 :param population: The population to select from.
8587 :param k: Number of genes to select.
8688 :return: list of genes.
8789 """
8890 ret = []
8991
92+ # Calculate accumulated normalized fitness.
93+ fitness = [x .get_fitness () for x in population ]
94+ reverse_fitness = [1 / fit for fit in fitness ]
95+ normalized_fitness = [f / sum (reverse_fitness ) for f in reverse_fitness ]
96+ for i in range (1 , len (fitness )):
97+ normalized_fitness [i ] += normalized_fitness [i - 1 ]
98+
9099 if self .selection_method == "roulette_wheel" :
91- # Calculate accumulated normalized fitness.
92- fitness = [x .get_fitness () for x in population ]
93- # print(fitness)
94- reverse_fitness = [1 / fit for fit in fitness ]
95- normalized_fitness = [f / sum (reverse_fitness ) for f in reverse_fitness ]
96- for i in range (1 , len (fitness )):
97- normalized_fitness [i ] += normalized_fitness [i - 1 ]
98- #print(normalized_fitness)
99100 # Selection based on fitness.
100101 for j in range (k ):
101102 r = random .random ()
@@ -104,11 +105,29 @@ def selection(self, population, k):
104105 ret .append (population [index ])
105106 break
106107
108+ if self .selection_method == "stochastic" :
109+ for j in range (k ):
110+ candidates = []
111+ for _ in range (2 ):
112+ r = random .random ()
113+ for index in range (len (fitness )):
114+ if normalized_fitness [index ] >= r :
115+ candidates .append (population [index ])
116+ break
117+ candidates .sort (key = lambda x : x .get_fitness (), reverse = False )
118+ ret .append (candidates [0 ])
119+
120+ if self .selection_method == "tournament" :
121+ for j in range (k ):
122+ candidates = random .choices (self .population , k = self .tournament_size )
123+ candidates .sort (key = lambda x : x .get_fitness (), reverse = False )
124+ ret .append (candidates [0 ])
125+
107126 return ret
108127
109128 def crossover (self , gene1 , gene2 ):
110129 """
111- Crossover between two genes and return the offsprings.
130+ Crossover between two genes and return the offsprings if they are better .
112131 Methods accepted:
113132 - one_point
114133 - two-points (To DO)
@@ -129,6 +148,9 @@ def crossover(self, gene1, gene2):
129148 offspring1 = Gene (data = offspring1_data )
130149 offspring2 = Gene (data = offspring2_data )
131150
151+ offspring1 .set_fitness (self .evaluate (offspring1 .get_data ()))
152+ offspring2 .set_fitness (self .evaluate (offspring2 .get_data ()))
153+
132154 return offspring1 , offspring2
133155
134156 def mutation (self , gene ):
@@ -145,7 +167,7 @@ def mutation(self, gene):
145167 lower , upper = self .boundary [pos ]
146168 new_val = random .uniform (lower , upper )
147169 data [pos ] = new_val
148- return Gene (data = data )
170+ return Gene (data = data , fitness = self . evaluate ( data ) )
149171
150172 def population_info (self , population ):
151173 """
@@ -207,10 +229,6 @@ def fit(self):
207229 # Replace old population with new.
208230 self .population = next_gen
209231
210- # Update fitness for all genes.
211- for gene in self .population :
212- gene .set_fitness (self .evaluate (gene .get_data ()))
213-
214232 cur_generation += 1
215233 temp = self .population_info (self .population )
216234
0 commit comments