I'm getting this error when using basin-hopping:
basinhopping_bounds() got an unexpected keyword argument 'f_new'
I'm trying to implement the analysis of X,F models in Python to solving a DTLZ7 problem.
So, I've started with a problem with 4 linear FO, which the result I know. When trying to solve the problem using basin-hopping for global minimization, I'm getting the error above (scipy-1.2.1.). Does anybody knows what is going wrong?
Here follows part of the code:
f1 = f_linear([0.06, 0.53, 0.18, 0.18, 0.06], "max")
f2 = f_linear([25, 70, 60, 95, 45], "max")
f3 = f_linear([0, 32.5, 300, 120, 0], "min")
f4 = f_linear([0.1, 0.1, 0.11, 0.35, 0.33], "min")
A_eq = np.array([[1, 1, 1, 1, 1]])
b_eq = np.array([3000])
x0_bounds = (0, 850)
x1_bounds = (0, 220)
x2_bounds = (0, 1300)
x3_bounds = (0, 1615)
x4_bounds = (0, 700)
F = [f1, f2, f3, f4]
def mu_D(x, F):
x = np.array(x)
return max([f_.mu(x) for f_ in F])
def basinhopping_bounds(x):
resp = True
if np.dot(x, A_eq[0]) != b_eq[0]:
resp = False
if x[0] < x0_bounds[0] or x[0] > x0_bounds[1]:
resp = False
if x[1] < x1_bounds[0] or x[1] > x1_bounds[1]:
resp = False
if x[2] < x2_bounds[0] or x[2] > x2_bounds[1]:
resp = False
if x[3] < x3_bounds[0] or x[3] > x3_bounds[1]:
resp = False
if x[4] < x4_bounds[0] or x[4] > x4_bounds[1]:
resp = False
return resp
cobyla_constraints = [
{"type": "ineq", "fun": lambda x: x[0]},
{"type": "ineq", "fun": lambda x: x0_bounds[1] - x[0]},
{"type": "ineq", "fun": lambda x: x[1]},
{"type": "ineq", "fun": lambda x: x1_bounds[1] - x[1]},
{"type": "ineq", "fun": lambda x: x[2]},
{"type": "ineq", "fun": lambda x: x2_bounds[1] - x[2]},
{"type": "ineq", "fun": lambda x: x[3]},
{"type": "ineq", "fun": lambda x: x3_bounds[1] - x[3]},
{"type": "ineq", "fun": lambda x: x[4]},
{"type": "ineq", "fun": lambda x: x4_bounds[1] - x[4]},
{"type": "eq", "fun": lambda x: np.dot(x, A_eq[0]) - b_eq[0]},
]
minimizer_kwargs = {"args": F, "method": "SLSQP", "constraints": cobyla_constraints}
opt.basinhopping(
mu_D,
f1.x_max,
minimizer_kwargs=minimizer_kwargs,
accept_test=basinhopping_bounds,
disp=True,
)
basinhopping step 0: f 1
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-11-ba4f3efaec5d> in <module>
5 minimizer_kwargs=minimizer_kwargs,
6 accept_test=basinhopping_bounds,
----> 7 disp=True,
8 )
~/anaconda3/lib/python3.6/site-packages/scipy/optimize/_basinhopping.py in basinhopping(func, x0, niter, T, stepsize, minimizer_kwargs, take_step, accept_test, callback, interval, disp, niter_success, seed)
674 " successfully"]
675 for i in range(niter):
--> 676 new_global_min = bh.one_cycle()
677
678 if callable(callback):
~/anaconda3/lib/python3.6/site-packages/scipy/optimize/_basinhopping.py in one_cycle(self)
152 new_global_min = False
153
--> 154 accept, minres = self._monte_carlo_step()
155
156 if accept:
~/anaconda3/lib/python3.6/site-packages/scipy/optimize/_basinhopping.py in _monte_carlo_step(self)
127 for test in self.accept_tests:
128 testres = test(f_new=energy_after_quench, x_new=x_after_quench,
--> 129 f_old=self.energy, x_old=self.x)
130 if testres == 'force accept':
131 accept = True
TypeError: basinhopping_bounds() got an unexpected keyword argument 'f_new'
Your bounds definition is incorrect. In basinhopping
your bounds should be defined as a class instance. You should use the following:
import numpy as np
import scipy.optimize as opt
class MyBounds(object):
'''
bounds class to make sure your variable is with in the inspected bounds
'''
def __init__(self, xmin, xmax):
self.xmax = np.array(xmax)
self.xmin = np.array(xmin)
def __call__(self, **kwargs):
x = kwargs["x_new"]
tmax = bool(np.all(x <= self.xmax))
tmin = bool(np.all(x >= self.xmin))
return tmax and tmin
# init bounds
lower_bounds = [ 0, 0, 0, 0, 0]
upper_bounds = [850, 220, 1300, 1615, 700]
my_bounds = MyBounds(lower_bounds, upper_bounds)
...
# optimize
result = opt.basinhopping(mu_D,
f1.x_max,
minimizer_kwargs = minimizer_kwargs,
accept_test = my_bounds,
disp = True)
Also consider merging your constraints. If you use arrays instead of element-wise constraints, you will only have three constraints. However, looking at your constraints (with exception to the last one) you are just defining your boundaries again.