bashopping_bounds() получил неожиданный аргумент ключевого слова 'f_new'
Я получаю эту ошибку при использовании бассейна-прыжка:basinhopping_bounds() got an unexpected keyword argument 'f_new'
Я пытаюсь реализовать анализ моделей X,F в Python для решения проблемы DTLZ7.
Итак, я начал с проблемы с 4 линейными FO, результат которой я знаю. При попытке решить проблему, используя скачкообразную перестройку бассейна для глобальной минимизации, я получаю ошибку выше (scipy-1.2.1.). Кто-нибудь знает, что идет не так?
Здесь следует часть кода:
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'
2 ответа
Ваше определение границ неверно. В basinhopping
ваши границы должны быть определены как экземпляр класса. Вы должны использовать следующее:
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)
Также рассмотрите возможность объединения ваших ограничений. Если вы используете массивы вместо поэлементных ограничений, у вас будет только три ограничения. Однако, глядя на ваши ограничения (за исключением последнего), вы просто снова определяете свои границы.
https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.optimize.basinhopping.html
Этот документ описывает accept_test
аргумент. Это должен быть вызываемый, который распознает набор аргументов ключевого слова (или, по крайней мере, не задыхается, когда их дают):
accept_test : callable, accept_test(f_new=f_new, x_new=x_new, f_old=fold, x_old=x_old), optional
Define a test which will be used to judge whether or not to accept the step.
This will be used in addition to the Metropolis test based on “temperature” T.
The acceptable return values are True, False, or "force accept". If any of the
tests return False then the step is rejected. If the latter, then this will
override any other tests in order to accept the step. This can be used, for
example, to forcefully escape from a local minimum that basinhopping is
trapped in.
Ваша функция принимает только позиционный аргумент:
def basinhopping_bounds(x):
Вы также можете увидеть, как minimize
вызывает вашу функцию в трассировке ошибок:
testres = test(f_new=energy_after_quench, x_new=x_after_quench,
--> 129 f_old=self.energy, x_old=self.x)