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 0e8be9d

Browse files
Merge pull request #286 from ahmedfgad/github-actions
GitHub actions
2 parents 272aaa5 + 8bbc4c8 commit 0e8be9d

File tree

5 files changed

+63
-35
lines changed

5 files changed

+63
-35
lines changed

‎docs/source/pygad.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -927,8 +927,10 @@ shuffles their order randomly.
927927
``adaptive_mutation()``
928928
~~~~~~~~~~~~~~~~~~~~~~~
929929

930-
Applies the adaptive mutation which selects a subset of genes and
931-
shuffles their order randomly.
930+
Applies the adaptive mutation which selects the number/percentage of
931+
genes to mutate based on the solution's fitness. If the fitness is high
932+
(i.e. solution quality is high), then small number/percentage of genes
933+
is mutated compared to a solution with a low fitness.
932934

933935
.. _bestsolution:
934936

‎examples/example_multi_objective.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def on_generation(ga_instance):
5353
# Running the GA to optimize the parameters of the function.
5454
ga_instance.run()
5555

56-
ga_instance.plot_fitness(labels=['Obj 1', 'Obj 2'])
56+
ga_instance.plot_fitness(label=['Obj 1', 'Obj 2'])
5757

5858
# Returning the details of the best solution.
5959
solution, solution_fitness, solution_idx = ga_instance.best_solution(ga_instance.last_generation_fitness)

‎pygad/pygad.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,8 +1135,9 @@ def __init__(self,
11351135

11361136
# Validate delay_after_gen
11371137
if type(delay_after_gen) in GA.supported_int_float_types:
1138-
if not self.suppress_warnings:
1139-
warnings.warn("The 'delay_after_gen' parameter is deprecated starting from PyGAD 3.3.0. To delay or pause the evolution after each generation, assign a callback function/method to the 'on_generation' parameter to adds some time delay.")
1138+
if delay_after_gen != 0.0:
1139+
if not self.suppress_warnings:
1140+
warnings.warn("The 'delay_after_gen' parameter is deprecated starting from PyGAD 3.3.0. To delay or pause the evolution after each generation, assign a callback function/method to the 'on_generation' parameter to adds some time delay.")
11401141
if delay_after_gen >= 0.0:
11411142
self.delay_after_gen = delay_after_gen
11421143
else:

‎pygad/utils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
from pygad.utils import mutation
44
from pygad.utils import nsga2
55

6-
__version__ = "1.1.1"
6+
__version__ = "1.2.1"

‎pygad/utils/crossover.py

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
(0)

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