99from numpy .random import uniform
1010from scipy .optimize import minimize
1111from scipy .stats import qmc
12- from cyipopt import Problem as IpoptProb
12+ import warnings
1313from ..surrogate_modeling .gp import GaussianProcess
1414from .acquisition import LCBacquisition , EIacquisition
1515from ..problems .problem import Problem
16- from .optproblem import IpoptProbFromScipy
16+ from .optproblem import IpoptProb
1717
1818# A base class defining a general framework for Bayesian Optimization
1919class BOAlgorithmBase :
@@ -83,9 +83,9 @@ def __init__(self, gpsurrogate, xtrain, ytrain,
8383 assert self .bo_maxiter > 0 , f"Invalid bo_maxiter: { self .bo_maxiter } "
8484
8585 if options and 'solver_options' in options :
86- self .options = options ['solver_options' ]
86+ self .solver_options = options ['solver_options' ]
8787 else :
88- self .options = {"maxiter" : 200 }
88+ self .solver_options = {"maxiter" : 200 }
8989
9090 if options and 'acquisition_type' in options :
9191 acquisition_type = options ['acquisition_type' ]
@@ -110,7 +110,7 @@ def __init__(self, gpsurrogate, xtrain, ytrain,
110110
111111 # Method to set up a callback function to minimize the acquisition function
112112 def _setup_acqf_minimizer_callback (self ):
113- self .acqf_minimizer_callback = lambda fun , x0 : pyminimize (fun , x0 , self .opt_solver , self .bounds , self .constraints , self .options )
113+ self .acqf_minimizer_callback = lambda fun , x0 : minimizer (fun , x0 , self .opt_solver , self .bounds , self .constraints , self .solver_options )
114114
115115 # Method to train the GP model
116116 def _train_surrogate (self , x_train , y_train ):
@@ -143,11 +143,14 @@ def _find_best_point(self, x_train, y_train, x0 = None):
143143 else :
144144 x0 = np .array ([uniform (b [0 ], b [1 ]) for b in self .bounds ])
145145 xopt , yout , success = self .acqf_minimizer_callback (acqf_callback , x0 )
146-
146+
147147 if success :
148148 x_all .append (xopt )
149149 y_all .append (yout )
150-
150+
151+ if not x_all :
152+ raise RuntimeError ("Optimization failed for all initial points — no solution found." )
153+
151154 best_xopt = x_all [np .argmin (np .array (y_all ))]
152155
153156 return best_xopt
@@ -156,9 +159,9 @@ def _find_best_point(self, x_train, y_train, x0 = None):
156159 def set_method (self , method ):
157160 self .opt_solver = method
158161
159- # Set the user options for the Bayesian optimization
160- def set_options (self , options ):
161- self .options = options
162+ # Set the options for the internal optimization solver
163+ def set_options (self , solver_options ):
164+ self .solver_options = solver_options
162165
163166 # Method to perform Bayesian optimization
164167 def optimize (self , prob :Problem ):
@@ -211,24 +214,31 @@ def optimize(self, prob:Problem):
211214 print ()
212215
213216# Find the minimum of the input objective `fun`, using the minimize function from SciPy.
214- def pyminimize (fun , x0 , method , bounds , constraints , options ):
217+ def minimizer (fun , x0 , method , bounds , constraints , solver_options ):
215218 if method != "IPOPT" :
216219 if 'grad' in fun :
217220 y = minimize (fun ['obj' ], x0 , method = method , bounds = bounds , jac = fun ['grad' ], constraints = constraints , options = options )
218221 else :
219- y = minimize (fun ['obj' ], x0 , method = method , bounds = bounds , constraints = constraints , options = options )
222+ y = minimize (fun ['obj' ], x0 , method = method , bounds = bounds , constraints = constraints , options = solver_options )
220223 success = y .success
221224 if not success :
222225 print (y .message )
223226 xopt = y .x
224227 yopt = y .fun
225228 else :
226- ipopt_prob = IpoptProbFromScipy (fun ['obj' ], fun ['grad' ], constraints , bounds )
227- nlp = IpoptProb (n = ipopt_prob .nvar , m = ipopt_prob .ncon , problem_obj = ipopt_prob , lb = ipopt_prob .xl , ub = ipopt_prob .xu , cl = ipopt_prob .cl , cu = ipopt_prob .cu )
229+ ipopt_prob = IpoptProb (fun ['obj' ], fun ['grad' ], constraints , bounds , solver_options )
230+ sol , info = ipopt_prob .solve (x0 )
231+
232+ status = info .get ('status' , - 1 )
233+ msg = info .get ('status_msg' , - 1 )
234+ if status == 0 :
235+ # ipopt returns 0 as success
236+ success = True
237+ else :
238+ warnings .warn (f"Ipopt failed to solve the problem. Status msg: { msg } " )
239+ success = False
228240
229- sol = nlp .solve (x0 )
230- success = not sol [1 ]['status' ] # ipopt returns 0 as success
231- yopt = sol [1 ]['obj_val' ]
232- xopt = sol [0 ]
241+ yopt = info ['obj_val' ]
242+ xopt = sol
233243
234244 return xopt , yopt , success
0 commit comments