Skip to content

Commit 8a34063

Browse files
author
Ahmed Gad
committed
Add sample_size parameter
1 parent dede266 commit 8a34063

18 files changed

+81
-39
lines changed

.DS_Store

0 Bytes
Binary file not shown.

example.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import pygad
2+
import numpy
3+
4+
function_inputs = [4,-2,3.5,5,-11,-4.7] # Function inputs.
5+
desired_output = 44 # Function output.
6+
7+
def fitness_func(ga_instance, solution, solution_idx):
8+
output = numpy.sum(solution*function_inputs)
9+
fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)
10+
return fitness
11+
12+
num_generations = 100 # Number of generations.
13+
num_parents_mating = 10 # Number of solutions to be selected as parents in the mating pool.
14+
15+
sol_per_pop = 20 # Number of solutions in the population.
16+
num_genes = len(function_inputs)
17+
18+
ga_instance = pygad.GA(num_generations=num_generations,
19+
num_parents_mating=num_parents_mating,
20+
sol_per_pop=sol_per_pop,
21+
num_genes=num_genes,
22+
fitness_func=fitness_func,
23+
gene_type=int,
24+
gene_space=range(1000),
25+
mutation_by_replacement=True,
26+
sample_size=1000000,
27+
gene_constraint=[lambda x: x[0]>5, lambda x: x[0]>5, lambda x: x[0]>5, lambda x: x[0]>5, lambda x: x[0]>5, lambda x: x[0]>5],
28+
allow_duplicate_genes=False)
29+
30+
# Running the GA to optimize the parameters of the function.
31+
ga_instance.run()
32+
33+
# ga_instance.plot_fitness()
205 Bytes
Binary file not shown.
78.6 KB
Binary file not shown.
260 Bytes
Binary file not shown.
15.7 KB
Binary file not shown.
14.3 KB
Binary file not shown.

pygad/helper/misc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@ def get_valid_gene_constraint_values(self,
507507
-An array with number of values equal to sample_size if sample_size>1. Or
508508
-None if no value found that satisfies the constraint.
509509
"""
510+
511+
print("AAAA", sample_size)
510512
# Either generate the values randomly or from the gene space.
511513
values = self.generate_gene_value(range_min=range_min,
512514
range_max=range_max,

pygad/pygad.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(self,
5151
random_mutation_max_val=1.0,
5252
gene_space=None,
5353
gene_constraint=None,
54+
sample_size=100,
5455
allow_duplicate_genes=True,
5556
on_start=None,
5657
on_fitness=None,
@@ -107,6 +108,7 @@ def __init__(self,
107108
gene_space: It accepts a list of all possible values of the gene. This list is used in the mutation step. Should be used only if the gene space is a set of discrete values. No need for the 2 parameters (random_mutation_min_val and random_mutation_max_val) if the parameter gene_space exists. Added in PyGAD 2.5.0. In PyGAD 2.11.0, the gene_space can be assigned a dict.
108109
109110
gene_constraint: It accepts a list of constraints for the genes. Each constraint is a Python function. Added in PyGAD 3.5.0.
111+
sample_size: To select a gene value that respects a constraint, this variable defines the size of the sample from which a value is selected. Useful if either allow_duplicate_genes or gene_constraint is used. Added in PyGAD 3.5.0.
110112
111113
on_start: Accepts a function/method to be called only once before the genetic algorithm starts its evolution. If functioned, then it must accept a single parameter representing the instance of the genetic algorithm. If method, then it must accept 2 parameters where the second one refers to the method's object. Added in PyGAD 2.6.0.
112114
on_fitness: Accepts a function/method to be called after calculating the fitness values of all solutions in the population. If functioned, then it must accept 2 parameters: 1) a list of all solutions' fitness values 2) the instance of the genetic algorithm. If method, then it must accept 3 parameters where the third one refers to the method's object. Added in PyGAD 2.6.0.
@@ -189,6 +191,19 @@ def __init__(self,
189191

190192
self.mutation_by_replacement = mutation_by_replacement
191193

194+
# Validate the sample_size parameter.
195+
if type(sample_size) in GA.supported_int_types:
196+
if sample_size > 0:
197+
pass
198+
else:
199+
self.valid_parameters = False
200+
raise ValueError(f"The value of the sample_size parameter must be > 0 but the value ({sample_size}) found.")
201+
else:
202+
self.valid_parameters = False
203+
raise TypeError(f"The type of the sample_size parameter must be integer but the value ({sample_size}) of type ({type(sample_size)}) found.")
204+
205+
self.sample_size = sample_size
206+
192207
# Validate allow_duplicate_genes
193208
if not (type(allow_duplicate_genes) is bool):
194209
self.valid_parameters = False
@@ -266,18 +281,6 @@ def __init__(self,
266281

267282
self.gene_space = gene_space
268283

269-
# Validate init_range_low and init_range_high
270-
# if type(init_range_low) in GA.supported_int_float_types:
271-
# if type(init_range_high) in GA.supported_int_float_types:
272-
# self.init_range_low = init_range_low
273-
# self.init_range_high = init_range_high
274-
# else:
275-
# self.valid_parameters = False
276-
# raise ValueError(f"The value passed to the 'init_range_high' parameter must be either integer or floating-point number but the value ({init_range_high}) of type {type(init_range_high)} found.")
277-
# else:
278-
# self.valid_parameters = False
279-
# raise ValueError(f"The value passed to the 'init_range_low' parameter must be either integer or floating-point number but the value ({init_range_low}) of type {type(init_range_low)} found.")
280-
281284
# Validate init_range_low and init_range_high
282285
if type(init_range_low) in GA.supported_int_float_types:
283286
if type(init_range_high) in GA.supported_int_float_types:
@@ -460,11 +463,11 @@ def __init__(self,
460463
max_val=self.init_range_high,
461464
mutation_by_replacement=True,
462465
gene_type=self.gene_type,
463-
sample_size=100)
466+
sample_size=self.sample_size)
464467
else:
465468
self.initial_population[initial_solution_idx], _, _ = self.solve_duplicate_genes_by_space(solution=initial_solution,
466469
gene_type=self.gene_type,
467-
sample_size=100,
470+
sample_size=self.sample_size,
468471
mutation_by_replacement=True,
469472
build_initial_pop=True)
470473

@@ -887,13 +890,17 @@ def __init__(self,
887890

888891
# For tournament selection, validate the K value.
889892
if parent_selection_type == "tournament":
890-
if K_tournament > self.sol_per_pop:
891-
K_tournament = self.sol_per_pop
892-
if not self.suppress_warnings:
893-
warnings.warn(f"K of the tournament selection ({K_tournament}) should not be greater than the number of solutions within the population ({self.sol_per_pop}).\nK will be clipped to be equal to the number of solutions in the population (sol_per_pop).\n")
894-
elif K_tournament <= 0:
893+
if type(K_tournament) in GA.supported_int_types:
894+
if K_tournament > self.sol_per_pop:
895+
K_tournament = self.sol_per_pop
896+
if not self.suppress_warnings:
897+
warnings.warn(f"K of the tournament selection ({K_tournament}) should not be greater than the number of solutions within the population ({self.sol_per_pop}).\nK will be clipped to be equal to the number of solutions in the population (sol_per_pop).\n")
898+
elif K_tournament <= 0:
899+
self.valid_parameters = False
900+
raise ValueError(f"K of the tournament selection cannot be <=0 but ({K_tournament}) found.\n")
901+
else:
895902
self.valid_parameters = False
896-
raise ValueError(f"K of the tournament selection cannot be <=0 but ({K_tournament}) found.\n")
903+
raise ValueError(f"The type of K of the tournament selection must be integer but the value ({K_tournament}) of type ({type(K_tournament)}) found.")
897904

898905
self.K_tournament = K_tournament
899906

@@ -1429,7 +1436,7 @@ def initialize_population(self,
14291436
gene_idx=gene_idx,
14301437
mutation_by_replacement=True,
14311438
solution=solution,
1432-
sample_size=100)
1439+
sample_size=self.sample_size)
14331440
if values_filtered is None:
14341441
if not self.suppress_warnings:
14351442
warnings.warn(f"No value satisfied the constraint for the gene at index {gene_idx} with value {solution[gene_idx]} while creating the initial population.")
@@ -1445,11 +1452,11 @@ def initialize_population(self,
14451452
max_val=self.init_range_high,
14461453
mutation_by_replacement=True,
14471454
gene_type=gene_type,
1448-
sample_size=100)
1455+
sample_size=self.sample_size)
14491456
else:
14501457
self.population[solution_idx], _, _ = self.solve_duplicate_genes_by_space(solution=self.population[solution_idx].copy(),
14511458
gene_type=self.gene_type,
1452-
sample_size=100,
1459+
sample_size=self.sample_size,
14531460
mutation_by_replacement=True,
14541461
build_initial_pop=True)
14551462

332 Bytes
Binary file not shown.
Binary file not shown.
17.4 KB
Binary file not shown.
7.11 KB
Binary file not shown.
Binary file not shown.

pygad/utils/crossover.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ def single_point_crossover(self, parents, offspring_size):
7070
max_val=self.random_mutation_max_val,
7171
mutation_by_replacement=self.mutation_by_replacement,
7272
gene_type=self.gene_type,
73-
sample_size=100)
73+
sample_size=self.sample_size)
7474
else:
7575
offspring[k], _, _ = self.solve_duplicate_genes_by_space(solution=offspring[k],
7676
gene_type=self.gene_type,
77-
sample_size=100,
77+
sample_size=self.sample_size,
7878
mutation_by_replacement=self.mutation_by_replacement,
7979
build_initial_pop=False)
8080

@@ -144,11 +144,11 @@ def two_points_crossover(self, parents, offspring_size):
144144
max_val=self.random_mutation_max_val,
145145
mutation_by_replacement=self.mutation_by_replacement,
146146
gene_type=self.gene_type,
147-
sample_size=100)
147+
sample_size=self.sample_size)
148148
else:
149149
offspring[k], _, _ = self.solve_duplicate_genes_by_space(solution=offspring[k],
150150
gene_type=self.gene_type,
151-
sample_size=100,
151+
sample_size=self.sample_size,
152152
mutation_by_replacement=self.mutation_by_replacement,
153153
build_initial_pop=False)
154154
return offspring
@@ -213,11 +213,11 @@ def uniform_crossover(self, parents, offspring_size):
213213
max_val=self.random_mutation_max_val,
214214
mutation_by_replacement=self.mutation_by_replacement,
215215
gene_type=self.gene_type,
216-
sample_size=100)
216+
sample_size=self.sample_size)
217217
else:
218218
offspring[k], _, _ = self.solve_duplicate_genes_by_space(solution=offspring[k],
219219
gene_type=self.gene_type,
220-
sample_size=100,
220+
sample_size=self.sample_size,
221221
mutation_by_replacement=self.mutation_by_replacement,
222222
build_initial_pop=False)
223223

@@ -279,11 +279,11 @@ def scattered_crossover(self, parents, offspring_size):
279279
max_val=self.random_mutation_max_val,
280280
mutation_by_replacement=self.mutation_by_replacement,
281281
gene_type=self.gene_type,
282-
sample_size=100)
282+
sample_size=self.sample_size)
283283
else:
284284
offspring[k], _, _ = self.solve_duplicate_genes_by_space(solution=offspring[k],
285285
gene_type=self.gene_type,
286-
sample_size=100,
286+
sample_size=self.sample_size,
287287
mutation_by_replacement=self.mutation_by_replacement,
288288
build_initial_pop=False)
289289
return offspring

0 commit comments

Comments
 (0)