You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
New parameters added init_range_low and init_range_high
* The attributes are moved from the class scope to the instance scope.
* Raising a `ValueError` exception on passing incorrect values to the parameters.
* Two new parameters are added (`init_rand_high` and `init_rand_high`) allowing the user to customize the range from which the genes values in the initial population are selected.
* The code object `__code__` of the passed fitness function is checked to ensure it has the right number of parameters.
Copy file name to clipboardExpand all lines: pygad.py
+81-77Lines changed: 81 additions & 77 deletions
Original file line number
Diff line number
Diff line change
@@ -4,51 +4,13 @@
4
4
importpickle
5
5
6
6
classGA:
7
-
# Parameters of the genetic algorithm.
8
-
sol_per_pop=None# Number of solutions in the population.
9
-
num_parents_mating=None# Number of solutions to be selected as parents in the mating pool.
10
-
num_generations=None# Number of generations.
11
-
pop_size=None# Population size = (number of chromosomes, number of genes per chromosome)
12
-
keep_parents=-1# If 0, this means the parents of the current populaiton will not be used at all in the next population. If -1, this means all parents in the current population will be used in the next population. If set to a value > 0, then the specified value refers to the number of parents in the current population to be used in the next population. In some cases, the parents are of high quality and thus we do not want to loose such some high quality solutions. If some parent selection operators like roulette wheel selection (RWS), the parents may not be of high quality and thus keeping the parents might degarde the quality of the population.
13
-
14
-
fitness_func=None
15
-
16
-
# Parameters about parent selection.
17
-
parent_selection_type=None# Type of parent selection.
18
-
select_parents=None# Refers to a method that selects the parents based on the parent selection type specified in parent_selection_type.
19
-
20
-
K_tournament=None# For tournament selection, a parent is selected out of K randomly selected solutions.
21
-
22
-
population=None# A NumPy array holding the opulation.
23
-
24
-
crossover_type=None# Type of the crossover opreator.
25
-
crossover=None# A method that applies the crossover operator based on the selected type of crossover in the crossover_type property.
26
-
27
-
mutation_type=None# Type of the mutation opreator.
28
-
mutation=None# A method that applies the mutation operator based on the selected type of mutation in the mutation_type property.
29
-
30
-
best_solution_fitness= [] # A list holding the fitness value of the best solution for each generation.
31
-
32
-
# Parameters of the function to be optimized.
33
-
function_inputs=None# Inputs of the function to be optimized.
34
-
function_output=None# Desired outuput of the function.
35
-
num_genes=None
36
-
37
-
# Mutation parameters.
38
-
mutation_percent_genes=None# Percentage of genes to mutate. This parameter has no action if the parameter mutation_num_genes exists.
39
-
mutation_num_genes=None# Number of genes to mutate. If the parameter mutation_num_genes exists, then no need for the parameter mutation_percent_genes.
40
-
random_mutation_min_val=None
41
-
random_mutation_max_val=None
42
-
43
-
# Some flags.
44
-
run_completed=False# Set to True only when the run() method completes gracefully.
45
-
valid_parameters=False# Set to True when all the paremeters passed in the GA class construtor are valid.
# A list of all parameters necessary for building an instance of the genetic algorithm.
26
+
27
+
# Parameters of the genetic algorithm:
28
+
num_generations = None # Number of generations.
29
+
sol_per_pop = None # Number of solutions in the population.
30
+
num_parents_mating = None # Number of solutions to be selected as parents in the mating pool.
31
+
pop_size = None # Population size = (number of chromosomes, number of genes per chromosome)
32
+
keep_parents = -1 # If 0, this means the parents of the current populaiton will not be used at all in the next population. If -1, this means all parents in the current population will be used in the next population. If set to a value > 0, then the specified value refers to the number of parents in the current population to be used in the next population. In some cases, the parents are of high quality and thus we do not want to loose such some high quality solutions. If some parent selection operators like roulette wheel selection (RWS), the parents may not be of high quality and thus keeping the parents might degarde the quality of the population.
33
+
34
+
fitness_func = None
35
+
36
+
# Initial population parameters:
37
+
# It is OK to set the value of any of the 2 parameters to be equal, higher or lower than the other parameter (i.e. init_range_low is not needed to be lower than init_range_high).
38
+
init_range_low = -4 # The lower value of the random range from which the gene values in the initial population are selected.
39
+
init_range_high = 4 # The upper value of the random range from which the gene values in the initial population are selected.
40
+
41
+
# Parameters about parent selection:
42
+
parent_selection_type = None # Type of parent selection.
43
+
select_parents = None # Refers to a method that selects the parents based on the parent selection type specified in parent_selection_type.
44
+
45
+
K_tournament = None # For tournament selection, a parent is selected out of K randomly selected solutions.
46
+
47
+
population = None # A NumPy array holding the opulation.
48
+
49
+
# Crossover parameters:
50
+
crossover_type = None # Type of the crossover opreator.
51
+
crossover = None # A method that applies the crossover operator based on the selected type of crossover in the crossover_type property.
52
+
53
+
# Mutation parameters:
54
+
mutation_type = None # Type of the mutation opreator.
55
+
mutation = None # A method that applies the mutation operator based on the selected type of mutation in the mutation_type property.
56
+
57
+
best_solution_fitness = [] # A list holding the fitness value of the best solution for each generation.
58
+
59
+
# Parameters of the function to be optimized:
60
+
num_genes = None # Number of parameters in the function.
61
+
62
+
# Mutation parameters:
63
+
mutation_percent_genes=None # Percentage of genes to mutate. This parameter has no action if the parameter mutation_num_genes exists.
64
+
mutation_num_genes=None # Number of genes to mutate. If the parameter mutation_num_genes exists, then no need for the parameter mutation_percent_genes.
65
+
random_mutation_min_val=None
66
+
random_mutation_max_val=None
67
+
68
+
# Some flags:
69
+
run_completed = False # Set to True only when the run() method completes gracefully.
70
+
valid_parameters = False # Set to True when all the paremeters passed in the GA class construtor are valid.
71
+
"""
72
+
62
73
# Validating the number of solutions in the population (sol_per_pop) and the number of parents to be selected for mating (num_parents_mating)
63
74
if (sol_per_pop<=0ornum_parents_mating<=0):
64
-
print("ERROR creating an instance of the GA class with invalid parameters. \nThe following parameters must be > 0: \n1) Population size (i.e. number of solutions per population) (sol_per_pop).\n2) Number of selected parents in the mating pool (num_parents_mating).\n")
65
75
self.valid_parameters=False
66
-
return
76
+
raiseValueError("ERROR creating an instance of the GA class with invalid parameters. \nThe following parameters must be > 0: \n1) Population size (i.e. number of solutions per population) (sol_per_pop).\n2) Number of selected parents in the mating pool (num_parents_mating).\n")
67
77
68
-
# Validating the number of gene.
78
+
# Validating the number of gene.
69
79
if (num_genes<=0):
70
-
print("ERROR: Number of genes cannot be <= 0. \n")
71
80
self.valid_parameters=False
72
-
return
81
+
raiseValueError("ERROR: Number of genes cannot be <= 0. \n")
73
82
74
83
self.num_genes=num_genes# Number of genes in the solution.
75
84
76
85
if (mutation_num_genes==None):
77
86
if (mutation_percent_genes<0ormutation_percent_genes>100):
78
-
print("ERROR: Percentage of selected genes for mutation (mutation_percent_genes) must be >= 0 and <= 100 inclusive.\n")
79
87
self.valid_parameters=False
80
-
return
88
+
raiseValueError("ERROR: Percentage of selected genes for mutation (mutation_percent_genes) must be >= 0 and <= 100 inclusive.\n")
81
89
elif (mutation_num_genes<=0 ):
82
-
print("ERROR: Number of selected genes for mutation (mutation_num_genes) cannot be <= 0.\n")
83
90
self.valid_parameters=False
84
-
return
91
+
raiseValueError("ERROR: Number of selected genes for mutation (mutation_num_genes) cannot be <= 0.\n")
85
92
elif (mutation_num_genes>self.num_genes):
86
-
print("ERROR: Number of selected genes for mutation (mutation_num_genes) cannot be greater than the number of parameters in the function.\n")
87
93
self.valid_parameters=False
88
-
return
94
+
raiseValueError("ERROR: Number of selected genes for mutation (mutation_num_genes) cannot be greater than the number of parameters in the function.\n")
89
95
elif (type(mutation_num_genes) isnotint):
90
-
print("Warning: Number of selected genes for mutation (mutation_num_genes) must be a positive integer >= 1.\n")
91
96
self.valid_parameters=False
92
-
return
97
+
raiseValueError("Error: Number of selected genes for mutation (mutation_num_genes) must be a positive integer >= 1.\n")
93
98
94
99
# Validating the number of parents to be selected for mating: num_parents_mating
95
100
if (num_parents_mating>sol_per_pop):
96
-
print("ERROR creating an instance of the GA class with invalid parameters. \nThe number of parents to select for mating cannot be greater than the number of solutions in the population (i.e., num_parents_mating must always be <= sol_per_pop).\n")
97
101
self.valid_parameters=False
98
-
return
102
+
raiseValueError("ERROR creating an instance of the GA class with invalid parameters. \nThe number of parents to select for mating cannot be greater than the number of solutions in the population (i.e., num_parents_mating must always be <= sol_per_pop).\n")
print("ERROR: undefined crossover type. \nThe assigned value to the crossover_type argument does not refer to one of the supported crossover types which are: \n-single_point (for single point crossover)\n-two_points (for two points crossover)\n-uniform (for uniform crossover).\n")
109
112
self.valid_parameters=False
110
-
return
113
+
raiseValueError("ERROR: undefined crossover type. \nThe assigned value to the crossover_type argument does not refer to one of the supported crossover types which are: \n-single_point (for single point crossover)\n-two_points (for two points crossover)\n-uniform (for uniform crossover).\n")
print("ERROR: undefined mutation type. \nThe assigned value to the mutation_type argument does not refer to one of the supported mutation types which are: \n-random (for random mutation)\n-swap (for swap mutation)\n-inversion (for inversion mutation)\n-scramble (for scramble mutation).\n")
125
127
self.valid_parameters=False
126
-
return
128
+
raiseValueError("ERROR: undefined mutation type. \nThe assigned value to the mutation_type argument does not refer to one of the supported mutation types which are: \n-random (for random mutation)\n-swap (for swap mutation)\n-inversion (for inversion mutation)\n-scramble (for scramble mutation).\n")
print("ERROR: undefined parent selection type. \nThe assigned value to the parent_selection_type argument does not refer to one of the supported parent selection techniques which are: \n-sss (for steady state selection)\n-rws (for roulette wheel selection)\n-sus (for stochastic universal selection)\n-rank (for rank selection)\n-random (for random selection)\n-tournament (for tournament selection).\n")
145
146
self.valid_parameters=False
146
-
return
147
+
raiseValueError("ERROR: undefined parent selection type. \nThe assigned value to the parent_selection_type argument does not refer to one of the supported parent selection techniques which are: \n-sss (for steady state selection)\n-rws (for roulette wheel selection)\n-sus (for stochastic universal selection)\n-rank (for rank selection)\n-random (for random selection)\n-tournament (for tournament selection).\n")
147
148
148
149
if(parent_selection_type=="tournament"):
149
150
if (K_tournament>sol_per_pop):
150
151
K_tournament=sol_per_pop
151
152
print("Warining: K of the tournament selection should not be greater than the number of solutions within the population.\nK will be clipped to be equal to the number of solutions in the population (sol_per_pop).\n")
152
153
elif (K_tournament<=0):
153
-
print("ERROR: K of the tournament selection cannot be <=0.\n")
154
154
self.valid_parameters=False
155
-
return
155
+
raiseValueError("ERROR: K of the tournament selection cannot be <=0.\n")
156
156
157
157
self.K_tournament=K_tournament
158
158
159
159
# Validating the number of parents to keep in the next population: keep_parents
160
160
if (keep_parents>sol_per_poporkeep_parents>num_parents_matingorkeep_parents<-1):
161
-
print("ERROR: Incorrect value to the keep_parents parameter. \nThe assigned value to the keep_parent parameter must satisfy the following conditions: \n1) Less than or equal to sol_per_pop\n2) Less than or equal to num_parents_mating\n3) Greater than or equal to -1.\n")
162
161
self.valid_parameters=False
163
-
return
162
+
raiseValueError("ERROR: Incorrect value to the keep_parents parameter. \nThe assigned value to the keep_parent parameter must satisfy the following conditions: \n1) Less than or equal to sol_per_pop\n2) Less than or equal to num_parents_mating\n3) Greater than or equal to -1.\n")
elif (self.keep_parents>0): # Keep the specified number of parents in the next population.
172
171
self.num_offspring=sol_per_pop-self.keep_parents
173
172
173
+
# Check if the fitness function accepts only a single paramater.
174
+
if (fitness_func.__code__.co_argcount==1):
175
+
self.fitness_func=fitness_func
176
+
else:
177
+
self.valid_parameters=False
178
+
raiseValueError("The fitness function must accept only a single parameter representing the solution to which the fitness value is calculated.\nThe passed fitness function named '{funcname}' accepts {argcount} argument(s).".format(funcname=fitness_func.__code__.co_name, argcount=fitness_func.__code__.co_argcount))
179
+
180
+
self.init_range_low=init_range_low
181
+
self.init_range_high=init_range_high
182
+
174
183
# At this point, all necessary parameters validation is done successfully and we are sure that the parameters are valid.
Running the genetic algorithm. This is the main method in which the genetic algorithm is evolved through a number of generations.
208
215
"""
209
216
ifself.valid_parameters==False:
210
-
print("ERROR calling the run() method: \nThe run() method cannot be executed with invalid parameters. Please check the parameters passed while creating an instance of the GA class.\n")
211
-
return
217
+
raiseValueError("ERROR calling the run() method: \nThe run() method cannot be executed with invalid parameters. Please check the parameters passed while creating an instance of the GA class.\n")
212
218
213
219
forgenerationinrange(self.num_generations):
214
220
# Measuring the fitness of each chromosome in the population.
@@ -245,8 +251,7 @@ def cal_pop_fitness(self):
245
251
-fitness: An array of the calculated fitness values.
246
252
"""
247
253
ifself.valid_parameters==False:
248
-
print("ERROR calling the cal_pop_fitness() method: \nPlease check the parameters passed while creating an instance of the GA class.\n")
249
-
return []
254
+
raiseValueError("ERROR calling the cal_pop_fitness() method: \nPlease check the parameters passed while creating an instance of the GA class.\n")
250
255
251
256
pop_fitness= []
252
257
# Calculating the fitness value of each solution in the current population.
@@ -565,8 +570,7 @@ def best_solution(self):
565
570
-best_solution_fitness: Fitness value of the best solution.
566
571
"""
567
572
ifself.run_completed==False:
568
-
print("Warning calling the best_solution() method: \nThe run() method is not yet called and thus the GA did not evolve the solutions. Thus, the best solution is retireved from the initial random population without being evolved.\n")
569
-
return [], []
573
+
raiseValueError("Warning calling the best_solution() method: \nThe run() method is not yet called and thus the GA did not evolve the solutions. Thus, the best solution is retireved from the initial random population without being evolved.\n")
570
574
571
575
# Getting the best solution after finishing all generations.
572
576
# At first, the fitness is calculated for each solution in the final generation.
0 commit comments