Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8bbc4c8

Browse files
Reduce time of crossover functions
1 parent 4eba80b commit 8bbc4c8

File tree

1 file changed

+47
-24
lines changed

1 file changed

+47
-24
lines changed

‎pygad/utils/crossover.py

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,26 @@ def single_point_crossover(self, parents, offspring_size):
2626
offspring = numpy.empty(offspring_size, dtype=object)
2727

2828
# 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.
2930
crossover_points = numpy.random.randint(low=0,
3031
high=parents.shape[1],
3132
size=offspring_size[0])
33+
3234
for k in range(offspring_size[0]):
3335
# Check if the crossover_probability parameter is used.
3436
if not (self.crossover_probability is None):
3537
probs = numpy.random.random(size=parents.shape[0])
36-
indices = numpy.where(probs <= self.crossover_probability)[0]
38+
indices = list(set(numpy.where(probs <= self.crossover_probability)[0]))
3739

38-
# 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.
3941
if len(indices) == 0:
4042
offspring[k, :] = parents[k % parents.shape[0], :]
4143
continue
4244
elif len(indices) == 1:
4345
parent1_idx = indices[0]
4446
parent2_idx = parent1_idx
4547
else:
46-
indices = random.sample(list(set(indices)), 2)
48+
indices = random.sample(indices, 2)
4749
parent1_idx = indices[0]
4850
parent2_idx = indices[1]
4951
else:
@@ -88,17 +90,23 @@ def two_points_crossover(self, parents, offspring_size):
8890
else:
8991
offspring = numpy.empty(offspring_size, dtype=object)
9092

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+
91105
for k in range(offspring_size[0]):
92-
if (parents.shape[1] == 1): # If the chromosome has only a single gene. In this case, this gene is copied from the second parent.
93-
crossover_point1 = 0
94-
else:
95-
crossover_point1 = numpy.random.randint(low=0, high=numpy.ceil(parents.shape[1]/2 + 1), size=1)[0]
96-
97-
crossover_point2 = crossover_point1 + int(parents.shape[1]/2) # The second point must always be greater than the first point.
98106

99107
if not (self.crossover_probability is None):
100108
probs = numpy.random.random(size=parents.shape[0])
101-
indices = numpy.where(probs <= self.crossover_probability)[0]
109+
indices = list(set(numpy.where(probs <= self.crossover_probability)[0]))
102110

103111
# If no parent satisfied the probability, no crossover is applied and a parent is selected.
104112
if len(indices) == 0:
@@ -108,7 +116,7 @@ def two_points_crossover(self, parents, offspring_size):
108116
parent1_idx = indices[0]
109117
parent2_idx = parent1_idx
110118
else:
111-
indices = random.sample(list(set(indices)), 2)
119+
indices = random.sample(indices, 2)
112120
parent1_idx = indices[0]
113121
parent2_idx = indices[1]
114122
else:
@@ -118,11 +126,11 @@ def two_points_crossover(self, parents, offspring_size):
118126
parent2_idx = (k+1) % parents.shape[0]
119127

120128
# The genes from the beginning of the chromosome up to the first point are copied from the first parent.
121-
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]]
122130
# The genes from the second point up to the end of the chromosome are copied from the first parent.
123-
offspring[k, crossover_point2:] = parents[parent1_idx, crossover_point2:]
131+
offspring[k, crossover_points_2[k]:] = parents[parent1_idx, crossover_points_2[k]:]
124132
# The genes between the 2 points are copied from the second parent.
125-
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]]
126134

127135
if self.allow_duplicate_genes == False:
128136
if self.gene_space is None:
@@ -153,10 +161,18 @@ def uniform_crossover(self, parents, offspring_size):
153161
else:
154162
offspring = numpy.empty(offspring_size, dtype=object)
155163

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+
156172
for k in range(offspring_size[0]):
157173
if not (self.crossover_probability is None):
158174
probs = numpy.random.random(size=parents.shape[0])
159-
indices = numpy.where(probs <= self.crossover_probability)[0]
175+
indices = list(set(numpy.where(probs <= self.crossover_probability)[0]))
160176

161177
# If no parent satisfied the probability, no crossover is applied and a parent is selected.
162178
if len(indices) == 0:
@@ -166,7 +182,7 @@ def uniform_crossover(self, parents, offspring_size):
166182
parent1_idx = indices[0]
167183
parent2_idx = parent1_idx
168184
else:
169-
indices = random.sample(list(set(indices)), 2)
185+
indices = random.sample(indices, 2)
170186
parent1_idx = indices[0]
171187
parent2_idx = indices[1]
172188
else:
@@ -175,12 +191,11 @@ def uniform_crossover(self, parents, offspring_size):
175191
# Index of the second parent to mate.
176192
parent2_idx = (k+1) % parents.shape[0]
177193

178-
genes_source = numpy.random.randint(low=0, high=2, size=offspring_size[1])
179194
for gene_idx in range(offspring_size[1]):
180-
if (genes_source[gene_idx] == 0):
195+
if (genes_sources[k, gene_idx] == 0):
181196
# The gene will be copied from the first parent if the current gene index is 0.
182197
offspring[k, gene_idx] = parents[parent1_idx, gene_idx]
183-
elif (genes_source[gene_idx] == 1):
198+
elif (genes_sources[k, gene_idx] == 1):
184199
# The gene will be copied from the second parent if the current gene index is 1.
185200
offspring[k, gene_idx] = parents[parent2_idx, gene_idx]
186201

@@ -214,10 +229,18 @@ def scattered_crossover(self, parents, offspring_size):
214229
else:
215230
offspring = numpy.empty(offspring_size, dtype=object)
216231

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+
217240
for k in range(offspring_size[0]):
218241
if not (self.crossover_probability is None):
219242
probs = numpy.random.random(size=parents.shape[0])
220-
indices = numpy.where(probs <= self.crossover_probability)[0]
243+
indices = list(set(numpy.where(probs <= self.crossover_probability)[0]))
221244

222245
# If no parent satisfied the probability, no crossover is applied and a parent is selected.
223246
if len(indices) == 0:
@@ -227,7 +250,7 @@ def scattered_crossover(self, parents, offspring_size):
227250
parent1_idx = indices[0]
228251
parent2_idx = parent1_idx
229252
else:
230-
indices = random.sample(list(set(indices)), 2)
253+
indices = random.sample(indices, 2)
231254
parent1_idx = indices[0]
232255
parent2_idx = indices[1]
233256
else:
@@ -236,9 +259,9 @@ def scattered_crossover(self, parents, offspring_size):
236259
# Index of the second parent to mate.
237260
parent2_idx = (k+1) % parents.shape[0]
238261

239-
# 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.
240-
gene_sources=numpy.random.randint(0, 2, size=self.num_genes)
241-
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, :])
242265

243266
if self.allow_duplicate_genes == False:
244267
if self.gene_space is None:

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /