1212from scipy .optimize import differential_evolution
1313
1414class ProgressBarCallback :
15- def __init__ (self , max_generations ):
15+ def __init__ (self , max_generations , desc = "Optimization" ):
1616 self .max_generations = max_generations
1717 self .current_generation = 0
18- self .previous_convergence = 0
19- self .pbar = tqdm (total = 100 , desc = "Optimization Progress %" )
20-
21- def __call__ (self , xk , convergence ):
22- self .current_generation += 1
23- self .pbar .update ((convergence - self .previous_convergence )* 100 ) # Update the progress bar
24- self .previous_convergence = convergence
25- if convergence > 1. : # Convergence threshold
26- self .pbar .close ()
27- return True # Stop optimization early
18+ self .pbar = tqdm (total = max_generations , desc = desc , unit = "gen" )
19+
20+ def __call__ (self , * args ):
21+
22+ # --- scipy differential_evolution: (xk, convergence) ---
23+ if len (args ) == 2 and not hasattr (args [0 ], "evaluator" ):
24+ xk , convergence = args
25+ self .current_generation += 1
26+ self .pbar .update (1 )
27+ self .pbar .set_postfix ({
28+ "conv" : f"{ (100 * (convergence )):6.1f} %"
29+ })
30+ # optional early stopping
31+ if convergence >= 1.0 :
32+ self .pbar .close ()
33+ return True
34+
35+ # --- pymoo minimize: (algorithm) ---
36+ elif len (args ) == 1 :
37+ algorithm = args [0 ]
38+ self .current_generation += 1
39+ self .pbar .update (1 )
40+
41+ # compute convergence metric
42+ F = np .atleast_1d (algorithm .pop .get ("F" ))
43+ gap = float (np .mean (F ) - np .min (F ))
44+ self ._gap0 = getattr (self , "_gap0" , gap if gap > 0 else 1.0 )
45+ convergence = float (np .clip (1.0 - gap / (self ._gap0 + 1e-12 ), 0.0 , 1.0 ))
46+
47+ self .pbar .set_postfix ({
48+ "conv" : f"{ (100 * (convergence )):6.1f} %"
49+ })
50+ # optional early stopping
51+ if convergence >= 1.0 and self .current_generation > 1 :
52+ self .pbar .close ()
53+ return True
2854
2955 def close (self ):
3056 self .pbar .close ()
@@ -73,7 +99,7 @@ def run_scipy_solver(parameterBounds,
7399 - The solution found by the solver.
74100 - A message indicating the solver's status.
75101 """
76- pbar = ProgressBarCallback (maxiter )
102+ pbar = ProgressBarCallback (maxiter , desc = 'Differential Evolution' )
77103 result = differential_evolution (minimization_function ,
78104 parameterBounds ,
79105 popsize = popsize ,
@@ -91,22 +117,6 @@ def run_scipy_solver(parameterBounds,
91117 )
92118 pbar .close ()
93119
94- # Need to be reworked to use the last population as the new initial population to speed up convergence
95- """while ((result.message == 'Maximum number of iterations has been exceeded.') and (iteration_convergence)):
96- warning = 'Increased number of iterations by 10% to reach convergence. \n '
97- maxiter = int(1.1*maxiter)
98- result = differential_evolution(minimization_function,parameterBounds,
99- popsize=popsize, tol=tol, maxiter=maxiter,
100- mutation=mutation, recombination=crossover_rate, polish=False,
101- init='latinhypercube',
102- callback=show_progress_bar,
103- updating='deferred', workers=-1, #vectorized=vectorized
104- )
105-
106- else:
107- warning = ''
108- """
109-
110120 solution , message = result .x , result .message
111121
112122 return solution , message
@@ -206,8 +216,9 @@ def run_pyfde_jade_solver(parameterBounds,
206216 def run_pymoo_cmaes_solver (parameterBounds ,
207217 minimization_function ,
208218 sigma = 0.1 ,
209- maxiter = 1000 ,
210- popsize = 50 ,
219+ maxiter = None , # default: 100 + 150 * (N+3)**2 // popsize**0.5
220+ popsize = None , # defaul: 4 + int(3 * np.log(len(parameterBounds)))
221+ verbose = False ,
211222 ** kwargs ):
212223 """
213224 Runs the pymoo CMAES solver to minimize a given function.
@@ -229,10 +240,10 @@ def run_pymoo_cmaes_solver(parameterBounds,
229240 from pymoo .core .problem import Problem
230241 from pymoo .optimize import minimize
231242 from pymoo .termination import get_termination
232- except :
233- ImportError ('''Please install the pymoo package to use the CMA-ES solver:
234- >>> pip install pymoo
235- ''' )
243+ except ImportError :
244+ raise ImportError ('''Please install the pymoo package to use the CMA-ES solver:
245+ >>> pip install pymoo
246+ ''' )
236247
237248 class OptimizationProblem (Problem ):
238249 def __init__ (self , objective_function , n_var , n_obj , xl , xu ):
@@ -262,14 +273,25 @@ def _evaluate(self, x, out):
262273 sigma = sigma ,
263274 popsize = popsize ,
264275 seed = 42 ,
276+ restarts = 3 ,
277+ restart_from_best = True ,
265278 ** kwargs ,
266279 )
267280 # use ftol and n_gen as stopping criteria
268281 termination_criteria = get_termination ("n_gen" , maxiter )
269282
270- res = minimize (problem , solver , termination_criteria , seed = 42 , verbose = True )
283+ if not verbose :
284+ cb = ProgressBarCallback (maxiter , desc = "CMA-ES evolution" )
285+ else : cb = None
286+
287+ res = minimize (problem , solver , termination_criteria ,
288+ seed = 42 ,
289+ callback = cb ,
290+ verbose = verbose )
291+
292+ if not verbose : cb .close ()
271293
272294 solution = res .X
273- message = "Convergence achieved" # if res. < maxiter else "Maximum iterations reached"
295+ message = "Convergence achieved" if res .algorithm . n_gen < maxiter else "Maximum iterations reached"
274296
275297 return solution , message , res
0 commit comments