66actual_num_fitness_calls_keep_elitism = 0
77actual_num_fitness_calls_keep_parents = 0
88
9- num_generations = 100
9+ num_generations = 50
1010sol_per_pop = 10
1111num_parents_mating = 5
1212
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 ):
2113
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.
2618
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 ):
2823 f = []
2924 for sol in solution :
3025 output1 = numpy .sum (sol * function_inputs1 )
@@ -34,26 +29,37 @@ def fitness_func_batch_multi(ga_instance, solution, solution_idx):
3429 f .append ([fitness1 , fitness2 ])
3530 return f
3631
37- def fitness_func_no_batch_multi (ga_instance , solution , solution_idx ):
32+ def fitness_func_no_batch_multi (ga_instance , solution , solution_idx ):
3833 output1 = numpy .sum (solution * function_inputs1 )
3934 output2 = numpy .sum (solution * function_inputs2 )
4035 fitness1 = 1.0 / (numpy .abs (output1 - desired_output1 ) + 0.000001 )
4136 fitness2 = 1.0 / (numpy .abs (output2 - desired_output2 ) + 0.000001 )
4237 return [fitness1 , fitness2 ]
4338
44- def fitness_func_batch_single (ga_instance , solution , solution_idx ):
39+ def fitness_func_batch_single (ga_instance , solution , solution_idx ):
4540 f = []
4641 for sol in solution :
4742 output = numpy .sum (solution * function_inputs1 )
4843 fitness = 1.0 / (numpy .abs (output - desired_output1 ) + 0.000001 )
4944 f .append (fitness )
5045 return f
5146
52- def fitness_func_no_batch_single (ga_instance , solution , solution_idx ):
47+ def fitness_func_no_batch_single (ga_instance , solution , solution_idx ):
5348 output = numpy .sum (solution * function_inputs1 )
5449 fitness = 1.0 / (numpy .abs (output - desired_output1 ) + 0.000001 )
5550 return fitness
5651
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+
5763 if fitness_batch_size is None or (type (fitness_batch_size ) in pygad .GA .supported_int_types and fitness_batch_size == 1 ):
5864 if multi_objective == True :
5965 fitness_func = fitness_func_no_batch_multi
@@ -77,139 +83,64 @@ def fitness_func_no_batch_single(ga_instance, solution, solution_idx):
7783 keep_parents = keep_parents ,
7884 stop_criteria = stop_criteria ,
7985 parent_selection_type = parent_selection_type ,
86+ parallel_processing = parallel_processing ,
8087 suppress_warnings = True )
8188
8289 ga_optimizer .run ()
8390
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 )
15099
151100if __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
155102 print ()
156- test_number_calls_fitness_function_stop_criteria_reach ( )
103+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'thread' , 1 ] )
157104 print ()
158- test_number_calls_fitness_function_stop_criteria_reach ( num = 2 )
105+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'thread' , 2 ] )
159106 print ()
160- test_number_calls_fitness_function_stop_criteria_saturate ( )
107+ test_number_calls_fitness_function_parallel_processing ( parallel_processing = [ 'thread' , 5 ] )
161108 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 ])
163111 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 ])
165114 print ()
166- test_number_calls_fitness_function_stop_criteria_reach (fitness_batch_size = 4 ,
167- num = 2 )
168115 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 ])
173119 print ()
120+ test_number_calls_fitness_function_parallel_processing (multi_objective = True ,
121+ fitness_batch_size = 4 ,
122+ parallel_processing = ['thread' , 5 ])
174123
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 ])
178126 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 ])
181128 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 ] )
183130 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 ] )
186133 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 ] )
189136 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 )
196137 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 ] )
200141 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 ])
205145 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" )
215146
0 commit comments