scipy.opimize.minimize 因有序解向量的约束而失败

scipy.opimize.minimize fails with constraints for ordered solution vector

我正在尝试使用最小化 (algorithm=SLSQP) 求解线性方程,具有一组约束:解矢量分量的总和必须为 1(或至少非常接近它,以最小化错误)和第二个约束强制对矢量分量进行排序,x_0 最大,x_n 最小。此外,我设置了界限,因为每个向量分量都有

到目前为止,这是我的代码:

from scipy.optimize import minimize
import numpy as np
from scipy.sparse import rand
from scipy.optimize import lsq_linear

#Linear equation Ax = b


def fmin(x,A,b):
    y = np.dot(A, x) - b
    return np.dot(y, y)


#Test data
b = np.array([172,8,7.4,24,21,0.8,0.1]) 

A_t = np.array(
    [[188,18.4,16.5,3.4,2.1,1.77,0.075],
     [405,0,0,99.8,99.8,0,0.0054],
     [90.5,0.4,0.009,19.7,15.6,1.06,0.012],
     [322,0,0,79,79,0.3,0.3],
     [0,0,0,0,0,0,0],
     [362,0.25,0.009,89.2,0,0.43,0.019],
     [37,1.4,0.2,7.3,1,4.5,0.1],
     [26,0.29,0.038,6.1,2.4,0.4,0.053]])
A = A_t.T
#=========================


m = np.shape(A)[0]
n = np.shape(A)[1]


x0 = np.full(n, 0.5) 

args = (A,b)
bnds = (( (1*10e-100, 1), )*n) #all x_i must be between 0 and 1
cons = [{'type': 'eq', 'fun': lambda x: 1.0-np.sum(x) }] #sum(x_i) = 1

#consider order of vectors as constraints
for i in range(n-1):
    cons = cons + [{'type': 'ineq', 'fun': lambda x : x[i] - x[i+1] }]

res = minimize(fmin, x0, args, method='SLSQP',
bounds=bnds,constraints=cons,tol=1e-2,options={'disp': False})

print ("\n res\n", res)
print("Sum of coefficients {}".format(np.sum(res.x)))
print("Difference vector:\n{}".format(np.dot(A,res.x) - b))

不幸的是算法错误

 res
      fun: 317820.09898084006
     jac: array([205597.34765625, 481389.625     , 105853.7265625 , 382592.76953125,
            0.        , 416196.953125  ,  42268.78125   ,  30196.81640625])
 message: 'Positive directional derivative for linesearch'
    nfev: 10
     nit: 5
    njev: 1
  status: 8
 success: False
       x: array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5])
Sum of coefficients 4.0
Difference vector:
[5.4325e+02 2.3700e+00 9.7800e-01 1.2825e+02 7.8950e+01 3.4300e+00
 1.8220e-01]

如果有人能帮我解决这个问题,我将不胜感激。事实上,对于这个例子中的测试数据,我知道 x_0 的正确解应该是 0.58,x_2 的正确解应该是 0.12。 非常感谢!

澄清评论中的讨论:您的 objective 函数在优化变量 x 中是非线性的。因此,这是一个非线性优化问题。错误消息的原因很简单:您的初始猜测 x0 位于可行域之外。您可以轻松地验证它不满足您的第一个约束 1.0 - np.sum(x) = 0.

但是,另请注意,在循环中创建 lambda 约束表达式时,您需要捕获循环变量 i。否则,您添加约束 lambda x: x[n-2] - x[n-1] 七次。看,例如here 了解更多详情。

通过

正确创建约束
for i in range(n-1):
    cons = cons + [{'type': 'ineq', 'fun': lambda x, i=i: x[i] - x[i+1] }]

并提供可行的初始猜测 x0 = np.ones(n)/n 产量

     fun: 114.90196737679031
     jac: array([3550.86690235, 7911.74978828, 1787.36224174, 6290.006423  ,
          0.        , 7580.9283762 ,  757.60069752,  528.41590595])
 message: 'Optimization terminated successfully'
    nfev: 66
     nit: 6
    njev: 6
  status: 0
 success: True
       x: array([0.38655391, 0.08763516, 0.08763516, 0.08763516, 0.08763516,
       0.08763515, 0.08763516, 0.08763516])

但是,对于更大的问题,强烈建议重写第二个约束:

D = np.eye(n) - np.eye(n, k=1)
D[-1, -1] = 0.0

cons = [{'type': 'eq', 'fun': lambda x: 1.0-np.sum(x) }]
cons += [{'type': 'ineq', 'fun': lambda x: D @ x}]

现在求解器只需在每次迭代中评估 2 个约束而不是 n+1 个约束。您可以通过提供梯度和雅可比矩阵进一步加速求解器,see this answer for more details.