我使用scipy.optimize.minimize' SLSQP'方法,根据文件:
bounds:sequence,optional
变量的界限(仅适用于L-BFGS-B,TNC和SLSQP)。 (min,max)对> x中的每个元素对,定义该参数的边界。当在该方向上没有绑定时,使用None作为min> gt或max之一。
我想知道是否有可能为变量x定义一个不连续的边界,如(0,15)& (30,50); (x介于0到15之间,介于30和50之间)
或者还有其他更好的方法来实现这个目标吗?
提前谢谢你们!
答案 0 :(得分:2)
x介于0和15之间,介于30和50之间
这会使模型不可行。没有这样的x
。你可能意味着:
x介于0和15之间 OR 介于30和50之间
这是非凸的,因此标准的局部求解器会遇到麻烦。它通常使用额外的二进制变量建模:
30 δ ≤ x ≤ 15(1-δ) + 50 δ
δ ∈ {0,1}
当然,这假设您可以处理二进制变量(SLSQP不能)。具有二元变量和非线性约束(或目标函数)的模型称为MINLP模型(混合整数非线性编程)。这些类型的模型的求解器很容易获得。
其他可行的方法:
0 ≤ x ≤ 15
,一次使用30 ≤ x ≤ 50
。然后选择最佳解决方案。scipy.optimize.basinhopping
全局求解器帮助您摆脱局部最优。这不是一个严格的算法(没有保证),但它可以帮助。一些通常不起作用的方法:
δ ∈ {0,1}
使用连续变量δ ∈ [0,1]
并添加约束δ(1-δ)=0
。通常这会让你陷入困境。x ∈ [15,30]
,则为目标添加惩罚。这也不适用于本地解算器。答案 1 :(得分:2)
这是尝试实施流域购物方法described by Erwin Kalvelagen。
首先,构造一个根在0,15,30和50的多项式 在所需区域是正面的:
In [123]: x = np.linspace(-1, 51, 100)
In [124]: plt.plot(x,-(x-0)*(x-15)*(x-30)*(x-50))
Out[124]: [<matplotlib.lines.Line2D at 0x7fa01d65b748>]
In [125]: plt.axhline(color='red')
Out[145]: <matplotlib.lines.Line2D at 0x7fa01d6620b8>
In [146]: plt.show()
现在您可以将该多项式用作约束:
import numpy as np
import scipy.optimize as optimize
cons = (
{'type': 'ineq', 'fun': lambda x: -(x-0)*(x-15)*(x-30)*(x-50)}, )
def f(x):
return (x-20)**2
res = optimize.basinhopping(f, [40], minimizer_kwargs={'method':'SLSQP', 'constraints': cons}, niter=10, stepsize=20)
print(res)
产量
message: 'Optimization terminated successfully.'
nfev: 13
nit: 4
njev: 4
status: 0
success: True
x: array([15.])
message: ['requested number of basinhopping iterations completed successfully']
minimization_failures: 0
nfev: 178
nit: 10
njev: 56
x: array([15.])
请注意,初始猜测位于40
,而optimize.basinhopping
设法在x = 15
的另一个非连续间隔中找到最小值。
使用两个间隔之间距离的步长非常重要,以便basinhopping
有机会从两个区间进行采样。
如果没有使用购物盆,optimize.minimize
使用具有非凸约束的SLSQP可能无法从所有允许的间隔中进行采样。例如,
import scipy.optimize as optimize
cons = ({'type': 'ineq', 'fun': lambda x: -(x-0)*(x-15)*(x-30)*(x-50)}, )
def f(x):
return (x-20)**2
res = optimize.minimize(
f, [40], method='SLSQP', constraints=cons)
print(res.x)
# [30.]
res = optimize.minimize(
f, [5], method='SLSQP', constraints=cons)
print(res.x)
# [15.]
表示您必须在每个间隔中猜测两次optimize.minimize
为了找到真正的最小值。