[英]Scipy.optimize.minimize SLSQP with linear constraints fails
Consider the following (convex) optimization problem: 考虑以下(凸)优化问题:
minimize 0.5 * y.T * y
s.t. A*x - b == y
where the optimization (vector) variables are x
and y
and A
, b
are a matrix and vector, respectively, of appropriate dimensions. 其中优化(矢量)变量是
x
和y
, A
, b
分别是适当尺寸的矩阵和矢量。
The code below finds a solution easily using the SLSQP
method from Scipy: 下面的代码使用Scipy的
SLSQP
方法轻松找到解决方案:
import numpy as np
from scipy.optimize import minimize
# problem dimensions:
n = 10 # arbitrary integer set by user
m = 2 * n
# generate parameters A, b:
np.random.seed(123) # for reproducibility of results
A = np.random.randn(m,n)
b = np.random.randn(m)
# objective function:
def obj(z):
vy = z[n:]
return 0.5 * vy.dot(vy)
# constraint function:
def cons(z):
vx = z[:n]
vy = z[n:]
return A.dot(vx) - b - vy
# constraints input for SLSQP:
cons = ({'type': 'eq','fun': cons})
# generate a random initial estimate:
z0 = np.random.randn(n+m)
sol = minimize(obj, x0 = z0, constraints = cons, method = 'SLSQP', options={'disp': True})
Optimization terminated successfully. (Exit mode 0) Current function value: 2.12236220865 Iterations: 6 Function evaluations: 192 Gradient evaluations: 6
Note that the constraint function is a convenient 'array-output' function. 请注意,约束函数是一个方便的“数组输出”函数。
Now, instead of an array-output function for the constraint, one could in principle use an equivalent set of 'scalar-output' constraint functions (actually, the scipy.optimize documentation discusses only this type of constraint functions as input to minimize
). 现在,代替约束的数组输出函数,原则上可以使用一组等效的“标量输出”约束函数(实际上,scipy.optimize文档仅讨论这种类型的约束函数作为
minimize
输入)。
Here is the equivalent constraint set followed by the output of minimize
(same A
, b
, and initial value as the above listing): 这是等效约束集,后跟
minimize
的输出(与上面列表相同的A
, b
和初始值):
# this is the i-th element of cons(z):
def cons_i(z, i):
vx = z[:n]
vy = z[n:]
return A[i].dot(vx) - b[i] - vy[i]
# listable of scalar-output constraints input for SLSQP:
cons_per_i = [{'type':'eq', 'fun': lambda z: cons_i(z, i)} for i in np.arange(m)]
sol2 = minimize(obj, x0 = z0, constraints = cons_per_i, method = 'SLSQP', options={'disp': True})
Singular matrix C in LSQ subproblem (Exit mode 6) Current function value: 6.87999270692 Iterations: 1 Function evaluations: 32 Gradient evaluations: 1
Evidently, the algorithm fails (the returning objective value is actually the objective value for the given initialization), which I find a bit weird. 显然,算法失败(返回的目标值实际上是给定初始化的目标值),我觉得有点奇怪。 Note that running
[cons_per_i[i]['fun'](sol.x) for i in np.arange(m)]
shows that sol.x
, obtained using the array-output constraint formulation, satisfies all scalar-output constraints of cons_per_i
as expected (within numerical tolerance). 请注意,
[cons_per_i[i]['fun'](sol.x) for i in np.arange(m)]
中运行[cons_per_i[i]['fun'](sol.x) for i in np.arange(m)]
表示使用数组输出约束公式获得的sol.x
满足所有标量输出约束cons_per_i
符合预期(在数值公差范围内)。
I would appreciate if anyone has some explanation for this issue. 如果有人对此问题有一些解释,我将不胜感激。
You've run into the "late binding closures" gotcha . 你已经遇到了“后期绑定关闭” 问题 。 All the calls to
cons_i
are being made with the second argument equal to 19. 对
cons_i
所有调用都是在第二个参数等于19的情况下进行的。
A fix is to use the args
dictionary element in the dictionary that defines the constraints instead of the lambda function closures: 修复是使用字典中的
args
字典元素来定义约束而不是lambda函数闭包:
cons_per_i = [{'type':'eq', 'fun': cons_i, 'args': (i,)} for i in np.arange(m)]
With this, the minimization works: 有了这个,最小化工作:
In [417]: sol2 = minimize(obj, x0 = z0, constraints = cons_per_i, method = 'SLSQP', options={'disp': True})
Optimization terminated successfully. (Exit mode 0)
Current function value: 2.1223622086
Iterations: 6
Function evaluations: 192
Gradient evaluations: 6
You could also use the the suggestion made in the linked article, which is to use a lambda expression with a second argument that has the desired default value: 您还可以使用链接文章中提出的建议,即使用具有所需默认值的第二个参数的lambda表达式:
cons_per_i = [{'type':'eq', 'fun': lambda z, i=i: cons_i(z, i)} for i in np.arange(m)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.