@@ -25,23 +25,27 @@ def single_point_crossover(self, parents, offspring_size):
2525 else :
2626 offspring = numpy .empty (offspring_size , dtype = object )
2727
28- for k in range (offspring_size [0 ]):
29- # The point at which crossover takes place between two parents. Usually, it is at the center.
30- crossover_point = numpy .random .randint (low = 0 , high = parents .shape [1 ], size = 1 )[0 ]
28+ # Randomly generate all the K points at which crossover takes place between each two parents. The point does not have to be always at the center of the solutions.
29+ # This saves time by calling the numpy.random.randint() function only once.
30+ crossover_points = numpy .random .randint (low = 0 ,
31+ high = parents .shape [1 ],
32+ size = offspring_size [0 ])
3133
34+ for k in range (offspring_size [0 ]):
35+ # Check if the crossover_probability parameter is used.
3236 if not (self .crossover_probability is None ):
3337 probs = numpy .random .random (size = parents .shape [0 ])
34- indices = numpy .where (probs <= self .crossover_probability )[0 ]
38+ indices = list ( set ( numpy .where (probs <= self .crossover_probability )[0 ]))
3539
36- # If no parent satisfied the probability, no crossover is applied and a parent is selected.
40+ # If no parent satisfied the probability, no crossover is applied and a parent is selected as is .
3741 if len (indices ) == 0 :
3842 offspring [k , :] = parents [k % parents .shape [0 ], :]
3943 continue
4044 elif len (indices ) == 1 :
4145 parent1_idx = indices [0 ]
4246 parent2_idx = parent1_idx
4347 else :
44- indices = random .sample (list ( set ( indices )) , 2 )
48+ indices = random .sample (indices , 2 )
4549 parent1_idx = indices [0 ]
4650 parent2_idx = indices [1 ]
4751 else :
@@ -51,9 +55,9 @@ def single_point_crossover(self, parents, offspring_size):
5155 parent2_idx = (k + 1 ) % parents .shape [0 ]
5256
5357 # The new offspring has its first half of its genes from the first parent.
54- offspring [k , 0 :crossover_point ] = parents [parent1_idx , 0 :crossover_point ]
58+ offspring [k , 0 :crossover_points [ k ]] = parents [parent1_idx , 0 :crossover_points [ k ] ]
5559 # The new offspring has its second half of its genes from the second parent.
56- offspring [k , crossover_point :] = parents [parent2_idx , crossover_point :]
60+ offspring [k , crossover_points [ k ] :] = parents [parent2_idx , crossover_points [ k ] :]
5761
5862 if self .allow_duplicate_genes == False :
5963 if self .gene_space is None :
@@ -86,17 +90,23 @@ def two_points_crossover(self, parents, offspring_size):
8690 else :
8791 offspring = numpy .empty (offspring_size , dtype = object )
8892
93+ # Randomly generate all the first K points at which crossover takes place between each two parents.
94+ # This saves time by calling the numpy.random.randint() function only once.
95+ if (parents .shape [1 ] == 1 ): # If the chromosome has only a single gene. In this case, this gene is copied from the second parent.
96+ crossover_points_1 = numpy .zeros (offspring_size [0 ])
97+ else :
98+ crossover_points_1 = numpy .random .randint (low = 0 ,
99+ high = numpy .ceil (parents .shape [1 ]/ 2 + 1 ),
100+ size = offspring_size [0 ])
101+
102+ # The second point must always be greater than the first point.
103+ crossover_points_2 = crossover_points_1 + int (parents .shape [1 ]/ 2 )
104+
89105 for k in range (offspring_size [0 ]):
90- if (parents .shape [1 ] == 1 ): # If the chromosome has only a single gene. In this case, this gene is copied from the second parent.
91- crossover_point1 = 0
92- else :
93- crossover_point1 = numpy .random .randint (low = 0 , high = numpy .ceil (parents .shape [1 ]/ 2 + 1 ), size = 1 )[0 ]
94-
95- crossover_point2 = crossover_point1 + int (parents .shape [1 ]/ 2 ) # The second point must always be greater than the first point.
96106
97107 if not (self .crossover_probability is None ):
98108 probs = numpy .random .random (size = parents .shape [0 ])
99- indices = numpy .where (probs <= self .crossover_probability )[0 ]
109+ indices = list ( set ( numpy .where (probs <= self .crossover_probability )[0 ]))
100110
101111 # If no parent satisfied the probability, no crossover is applied and a parent is selected.
102112 if len (indices ) == 0 :
@@ -106,7 +116,7 @@ def two_points_crossover(self, parents, offspring_size):
106116 parent1_idx = indices [0 ]
107117 parent2_idx = parent1_idx
108118 else :
109- indices = random .sample (list ( set ( indices )) , 2 )
119+ indices = random .sample (indices , 2 )
110120 parent1_idx = indices [0 ]
111121 parent2_idx = indices [1 ]
112122 else :
@@ -116,11 +126,11 @@ def two_points_crossover(self, parents, offspring_size):
116126 parent2_idx = (k + 1 ) % parents .shape [0 ]
117127
118128 # The genes from the beginning of the chromosome up to the first point are copied from the first parent.
119- offspring [k , 0 :crossover_point1 ] = parents [parent1_idx , 0 :crossover_point1 ]
129+ offspring [k , 0 :crossover_points_1 [ k ]] = parents [parent1_idx , 0 :crossover_points_1 [ k ] ]
120130 # The genes from the second point up to the end of the chromosome are copied from the first parent.
121- offspring [k , crossover_point2 :] = parents [parent1_idx , crossover_point2 :]
131+ offspring [k , crossover_points_2 [ k ] :] = parents [parent1_idx , crossover_points_2 [ k ] :]
122132 # The genes between the 2 points are copied from the second parent.
123- offspring [k , crossover_point1 : crossover_point2 ] = parents [parent2_idx , crossover_point1 : crossover_point2 ]
133+ offspring [k , crossover_points_1 [ k ]: crossover_points_2 [ k ]] = parents [parent2_idx , crossover_points_1 [ k ]: crossover_points_2 [ k ] ]
124134
125135 if self .allow_duplicate_genes == False :
126136 if self .gene_space is None :
@@ -151,10 +161,18 @@ def uniform_crossover(self, parents, offspring_size):
151161 else :
152162 offspring = numpy .empty (offspring_size , dtype = object )
153163
164+ # Randomly generate all the genes sources at which crossover takes place between each two parents.
165+ # This saves time by calling the numpy.random.randint() function only once.
166+ # There is a list of 0 and 1 for each offspring.
167+ # [0, 1, 0, 0, 1, 1]: If the value is 0, then take the gene from the first parent. If 1, take it from the second parent.
168+ genes_sources = numpy .random .randint (low = 0 ,
169+ high = 2 ,
170+ size = offspring_size )
171+
154172 for k in range (offspring_size [0 ]):
155173 if not (self .crossover_probability is None ):
156174 probs = numpy .random .random (size = parents .shape [0 ])
157- indices = numpy .where (probs <= self .crossover_probability )[0 ]
175+ indices = list ( set ( numpy .where (probs <= self .crossover_probability )[0 ]))
158176
159177 # If no parent satisfied the probability, no crossover is applied and a parent is selected.
160178 if len (indices ) == 0 :
@@ -164,7 +182,7 @@ def uniform_crossover(self, parents, offspring_size):
164182 parent1_idx = indices [0 ]
165183 parent2_idx = parent1_idx
166184 else :
167- indices = random .sample (list ( set ( indices )) , 2 )
185+ indices = random .sample (indices , 2 )
168186 parent1_idx = indices [0 ]
169187 parent2_idx = indices [1 ]
170188 else :
@@ -173,12 +191,11 @@ def uniform_crossover(self, parents, offspring_size):
173191 # Index of the second parent to mate.
174192 parent2_idx = (k + 1 ) % parents .shape [0 ]
175193
176- genes_source = numpy .random .randint (low = 0 , high = 2 , size = offspring_size [1 ])
177194 for gene_idx in range (offspring_size [1 ]):
178- if (genes_source [ gene_idx ] == 0 ):
195+ if (genes_sources [ k , gene_idx ] == 0 ):
179196 # The gene will be copied from the first parent if the current gene index is 0.
180197 offspring [k , gene_idx ] = parents [parent1_idx , gene_idx ]
181- elif (genes_source [ gene_idx ] == 1 ):
198+ elif (genes_sources [ k , gene_idx ] == 1 ):
182199 # The gene will be copied from the second parent if the current gene index is 1.
183200 offspring [k , gene_idx ] = parents [parent2_idx , gene_idx ]
184201
@@ -212,10 +229,18 @@ def scattered_crossover(self, parents, offspring_size):
212229 else :
213230 offspring = numpy .empty (offspring_size , dtype = object )
214231
232+ # Randomly generate all the genes sources at which crossover takes place between each two parents.
233+ # This saves time by calling the numpy.random.randint() function only once.
234+ # There is a list of 0 and 1 for each offspring.
235+ # [0, 1, 0, 0, 1, 1]: If the value is 0, then take the gene from the first parent. If 1, take it from the second parent.
236+ genes_sources = numpy .random .randint (low = 0 ,
237+ high = 2 ,
238+ size = offspring_size )
239+
215240 for k in range (offspring_size [0 ]):
216241 if not (self .crossover_probability is None ):
217242 probs = numpy .random .random (size = parents .shape [0 ])
218- indices = numpy .where (probs <= self .crossover_probability )[0 ]
243+ indices = list ( set ( numpy .where (probs <= self .crossover_probability )[0 ]))
219244
220245 # If no parent satisfied the probability, no crossover is applied and a parent is selected.
221246 if len (indices ) == 0 :
@@ -225,7 +250,7 @@ def scattered_crossover(self, parents, offspring_size):
225250 parent1_idx = indices [0 ]
226251 parent2_idx = parent1_idx
227252 else :
228- indices = random .sample (list ( set ( indices )) , 2 )
253+ indices = random .sample (indices , 2 )
229254 parent1_idx = indices [0 ]
230255 parent2_idx = indices [1 ]
231256 else :
@@ -234,9 +259,9 @@ def scattered_crossover(self, parents, offspring_size):
234259 # Index of the second parent to mate.
235260 parent2_idx = (k + 1 ) % parents .shape [0 ]
236261
237- # A 0/1 vector where 0 means the gene is taken from the first parent and 1 means the gene is taken from the second parent.
238- gene_sources = numpy . random . randint ( 0 , 2 , size = self . num_genes )
239- offspring [ k , :] = numpy . where ( gene_sources == 0 , parents [ parent1_idx , :], parents [parent2_idx , :])
262+ offspring [ k , :] = numpy . where ( genes_sources [ k ] == 0 ,
263+ parents [ parent1_idx , :],
264+ parents [parent2_idx , :])
240265
241266 if self .allow_duplicate_genes == False :
242267 if self .gene_space is None :
0 commit comments