6
6
actual_num_fitness_calls_keep_elitism = 0
7
7
actual_num_fitness_calls_keep_parents = 0
8
8
9
- num_generations = 100
9
+ num_generations = 50
10
10
sol_per_pop = 10
11
11
num_parents_mating = 5
12
12
13
- def multi_objective_problem (keep_elitism = 1 ,
14
- keep_parents = - 1 ,
15
- fitness_batch_size = None ,
16
- stop_criteria = None ,
17
- parent_selection_type = 'sss' ,
18
- mutation_type = "random" ,
19
- mutation_percent_genes = "default" ,
20
- multi_objective = False ):
21
13
22
- function_inputs1 = [4 ,- 2 ,3.5 ,5 ,- 11 ,- 4.7 ] # Function 1 inputs.
23
- function_inputs2 = [- 2 ,0.7 ,- 9 ,1.4 ,3 ,5 ] # Function 2 inputs.
24
- desired_output1 = 50 # Function 1 output.
25
- desired_output2 = 30 # Function 2 output.
14
+ function_inputs1 = [4 ,- 2 ,3.5 ,5 ,- 11 ,- 4.7 ] # Function 1 inputs.
15
+ function_inputs2 = [- 2 ,0.7 ,- 9 ,1.4 ,3 ,5 ] # Function 2 inputs.
16
+ desired_output1 = 50 # Function 1 output.
17
+ desired_output2 = 30 # Function 2 output.
26
18
27
- def fitness_func_batch_multi (ga_instance , solution , solution_idx ):
19
+ #### Define the fitness functions in the top-level of the module so that they are picklable and usable in the process-based parallel processing works.
20
+ #### If the functions are defined inside a class/method/function, they are not picklable and this error is raised: AttributeError: Can't pickle local object
21
+ #### Process-based parallel processing must have the used functions picklable.
22
+ def fitness_func_batch_multi (ga_instance , solution , solution_idx ):
28
23
f = []
29
24
for sol in solution :
30
25
output1 = numpy .sum (sol * function_inputs1 )
@@ -34,26 +29,37 @@ def fitness_func_batch_multi(ga_instance, solution, solution_idx):
34
29
f .append ([fitness1 , fitness2 ])
35
30
return f
36
31
37
- def fitness_func_no_batch_multi (ga_instance , solution , solution_idx ):
32
+ def fitness_func_no_batch_multi (ga_instance , solution , solution_idx ):
38
33
output1 = numpy .sum (solution * function_inputs1 )
39
34
output2 = numpy .sum (solution * function_inputs2 )
40
35
fitness1 = 1.0 / (numpy .abs (output1 - desired_output1 ) + 0.000001 )
41
36
fitness2 = 1.0 / (numpy .abs (output2 - desired_output2 ) + 0.000001 )
42
37
return [fitness1 , fitness2 ]
43
38
44
- def fitness_func_batch_single (ga_instance , solution , solution_idx ):
39
+ def fitness_func_batch_single (ga_instance , solution , solution_idx ):
45
40
f = []
46
41
for sol in solution :
47
42
output = numpy .sum (solution * function_inputs1 )
48
43
fitness = 1.0 / (numpy .abs (output - desired_output1 ) + 0.000001 )
49
44
f .append (fitness )
50
45
return f
51
46
52
- def fitness_func_no_batch_single (ga_instance , solution , solution_idx ):
47
+ def fitness_func_no_batch_single (ga_instance , solution , solution_idx ):
53
48
output = numpy .sum (solution * function_inputs1 )
54
49
fitness = 1.0 / (numpy .abs (output - desired_output1 ) + 0.000001 )
55
50
return fitness
56
51
52
+
53
+ def multi_objective_problem (keep_elitism = 1 ,
54
+ keep_parents = - 1 ,
55
+ fitness_batch_size = None ,
56
+ stop_criteria = None ,
57
+ parent_selection_type = 'sss' ,
58
+ mutation_type = "random" ,
59
+ mutation_percent_genes = "default" ,
60
+ multi_objective = False ,
61
+ parallel_processing = None ):
62
+
57
63
if fitness_batch_size is None or (type (fitness_batch_size ) in pygad .GA .supported_int_types and fitness_batch_size == 1 ):
58
64
if multi_objective == True :
59
65
fitness_func = fitness_func_no_batch_multi
@@ -77,139 +83,64 @@ def fitness_func_no_batch_single(ga_instance, solution, solution_idx):
77
83
keep_parents = keep_parents ,
78
84
stop_criteria = stop_criteria ,
79
85
parent_selection_type = parent_selection_type ,
86
+ parallel_processing = parallel_processing ,
80
87
suppress_warnings = True )
81
88
82
89
ga_optimizer .run ()
83
90
84
- return ga_optimizer .generations_completed , ga_optimizer .best_solutions_fitness , ga_optimizer .last_generation_fitness , stop_criteria
85
-
86
- def test_number_calls_fitness_function_default_keep ():
87
- multi_objective_problem ()
88
-
89
- def test_number_calls_fitness_function_stop_criteria_reach (multi_objective = False ,
90
- fitness_batch_size = None ,
91
- num = 10 ):
92
- generations_completed , best_solutions_fitness , last_generation_fitness , stop_criteria = multi_objective_problem (multi_objective = multi_objective ,
93
- fitness_batch_size = fitness_batch_size ,
94
- stop_criteria = f"reach_{ num } " )
95
- # Verify that the GA stops when meeting the criterion.
96
- criterion = stop_criteria .split ('_' )
97
- stop_word = criterion [0 ]
98
- if generations_completed < num_generations :
99
- if stop_word == 'reach' :
100
- if len (criterion ) > 2 :
101
- # multi-objective problem.
102
- for idx , num in enumerate (criterion [1 :]):
103
- criterion [idx + 1 ] = float (num )
104
- else :
105
- criterion [1 ] = float (criterion [1 ])
106
-
107
- # Single-objective
108
- if type (last_generation_fitness [0 ]) in pygad .GA .supported_int_float_types :
109
- assert max (last_generation_fitness ) >= criterion [1 ]
110
- # Multi-objective
111
- elif type (last_generation_fitness [0 ]) in [list , tuple , numpy .ndarray ]:
112
- # Validate the value passed to the criterion.
113
- if len (criterion [1 :]) == 1 :
114
- # There is a single value used across all the objectives.
115
- pass
116
- elif len (criterion [1 :]) > 1 :
117
- # There are multiple values. The number of values must be equal to the number of objectives.
118
- if len (criterion [1 :]) == len (last_generation_fitness [0 ]):
119
- pass
120
- else :
121
- raise ValueError ("Error" )
122
-
123
- for obj_idx in range (len (last_generation_fitness [0 ])):
124
- # Use the objective index to return the proper value for the criterion.
125
- if len (criterion [1 :]) == len (last_generation_fitness [0 ]):
126
- reach_fitness_value = criterion [obj_idx + 1 ]
127
- elif len (criterion [1 :]) == 1 :
128
- reach_fitness_value = criterion [1 ]
129
-
130
- assert max (last_generation_fitness [:, obj_idx ]) >= reach_fitness_value
131
-
132
- def test_number_calls_fitness_function_stop_criteria_saturate (multi_objective = False ,
133
- fitness_batch_size = None ,
134
- num = 5 ):
135
- generations_completed , best_solutions_fitness , last_generation_fitness , stop_criteria = multi_objective_problem (multi_objective = multi_objective ,
136
- fitness_batch_size = fitness_batch_size ,
137
- stop_criteria = f"saturate_{ num } " )
138
- # Verify that the GA stops when meeting the criterion.
139
- criterion = stop_criteria .split ('_' )
140
- stop_word = criterion [0 ]
141
- number = criterion [1 ]
142
- if generations_completed < num_generations :
143
- if stop_word == 'saturate' :
144
- number = int (number )
145
- if type (last_generation_fitness [0 ]) in pygad .GA .supported_int_float_types :
146
- assert best_solutions_fitness [generations_completed - number ] == best_solutions_fitness [generations_completed - 1 ]
147
- elif type (last_generation_fitness [0 ]) in [list , tuple , numpy .ndarray ]:
148
- for obj_idx in range (len (best_solutions_fitness [0 ])):
149
- assert best_solutions_fitness [generations_completed - number ][obj_idx ] == best_solutions_fitness [generations_completed - 1 ][obj_idx ]
91
+ return None
92
+
93
+ def test_number_calls_fitness_function_parallel_processing (multi_objective = False ,
94
+ fitness_batch_size = None ,
95
+ parallel_processing = None ):
96
+ multi_objective_problem (multi_objective = multi_objective ,
97
+ fitness_batch_size = fitness_batch_size ,
98
+ parallel_processing = parallel_processing )
150
99
151
100
if __name__ == "__main__" :
152
- #### Single-objective problem with a single numeric value with stop_criteria.
153
- print ()
154
- test_number_calls_fitness_function_default_keep ()
101
+ #### Thread-based Parallel Processing
155
102
print ()
156
- test_number_calls_fitness_function_stop_criteria_reach ( )
103
+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'thread' , 1 ] )
157
104
print ()
158
- test_number_calls_fitness_function_stop_criteria_reach ( num = 2 )
105
+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'thread' , 2 ] )
159
106
print ()
160
- test_number_calls_fitness_function_stop_criteria_saturate ( )
107
+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'thread' , 5 ] )
161
108
print ()
162
- test_number_calls_fitness_function_stop_criteria_saturate (num = 2 )
109
+ test_number_calls_fitness_function_parallel_processing (fitness_batch_size = 4 ,
110
+ parallel_processing = ['thread' , 5 ])
163
111
print ()
164
- test_number_calls_fitness_function_stop_criteria_reach (fitness_batch_size = 4 )
112
+ test_number_calls_fitness_function_parallel_processing (fitness_batch_size = 4 ,
113
+ parallel_processing = ['thread' , 5 ])
165
114
print ()
166
- test_number_calls_fitness_function_stop_criteria_reach (fitness_batch_size = 4 ,
167
- num = 2 )
168
115
print ()
169
- test_number_calls_fitness_function_stop_criteria_saturate (fitness_batch_size = 4 )
170
- print ()
171
- test_number_calls_fitness_function_stop_criteria_saturate (fitness_batch_size = 4 ,
172
- num = 2 )
116
+ test_number_calls_fitness_function_parallel_processing (multi_objective = True ,
117
+ fitness_batch_size = 4 ,
118
+ parallel_processing = ['thread' , 5 ])
173
119
print ()
120
+ test_number_calls_fitness_function_parallel_processing (multi_objective = True ,
121
+ fitness_batch_size = 4 ,
122
+ parallel_processing = ['thread' , 5 ])
174
123
175
-
176
- #### Multi-objective problem with a single numeric value with stop_criteria.
177
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True )
124
+ #### Process-based Parallel Processing
125
+ test_number_calls_fitness_function_parallel_processing (parallel_processing = ['process' , 1 ])
178
126
print ()
179
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True ,
180
- num = 2 )
127
+ test_number_calls_fitness_function_parallel_processing (parallel_processing = ['process' , 2 ])
181
128
print ()
182
- test_number_calls_fitness_function_stop_criteria_saturate ( multi_objective = True )
129
+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'process' , 5 ] )
183
130
print ()
184
- test_number_calls_fitness_function_stop_criteria_saturate ( multi_objective = True ,
185
- num = 2 )
131
+ test_number_calls_fitness_function_parallel_processing ( fitness_batch_size = 4 ,
132
+ parallel_processing = [ 'thread' , 5 ] )
186
133
print ()
187
- test_number_calls_fitness_function_stop_criteria_reach ( multi_objective = True ,
188
- fitness_batch_size = 4 )
134
+ test_number_calls_fitness_function_parallel_processing ( fitness_batch_size = 4 ,
135
+ parallel_processing = [ 'process' , 5 ] )
189
136
print ()
190
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True ,
191
- fitness_batch_size = 4 ,
192
- num = 2 )
193
- print ()
194
- test_number_calls_fitness_function_stop_criteria_saturate (multi_objective = True ,
195
- fitness_batch_size = 4 )
196
137
print ()
197
- test_number_calls_fitness_function_stop_criteria_saturate (multi_objective = True ,
198
- fitness_batch_size = 4 ,
199
- num = 50 )
138
+ test_number_calls_fitness_function_parallel_processing (multi_objective = True ,
139
+ fitness_batch_size = 4 ,
140
+ parallel_processing = [ 'process' , 5 ] )
200
141
print ()
201
-
202
-
203
- #### Multi-objective problem with multiple numeric values with stop_criteria.
204
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True )
142
+ test_number_calls_fitness_function_parallel_processing (multi_objective = True ,
143
+ fitness_batch_size = 4 ,
144
+ parallel_processing = ['process' , 5 ])
205
145
print ()
206
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True ,
207
- num = "2_5" )
208
- print ()
209
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True ,
210
- fitness_batch_size = 4 )
211
- print ()
212
- test_number_calls_fitness_function_stop_criteria_reach (multi_objective = True ,
213
- fitness_batch_size = 4 ,
214
- num = "10_20" )
215
146
0 commit comments