Scipy.optimize.minimize method='SLSQP' 忽略约束

Posted

技术标签:

【中文标题】Scipy.optimize.minimize method=\'SLSQP\' 忽略约束【英文标题】:Scipy.optimize.minimize method='SLSQP' ignores constraintScipy.optimize.minimize method='SLSQP' 忽略约束 【发布时间】:2016-02-04 07:45:56 【问题描述】:

我正在使用 SciPy 进行优化,SLSQP 方法似乎忽略了我的限制。

具体来说,我希望 x[3] 和 x[4] 在 [0-1] 范围内

我收到消息:'不等式约束不兼容'

下面是执行结果,后面是示例代码(使用虚拟函数):

  status: 4
  success: False
njev: 2
nfev: 24
 fun: 0.11923608071680103
   x: array([-10993.4278558 , -19570.77080806, -23495.15914299, -26531.4862831 ,
     4679.97660534])
message: 'Inequality constraints incompatible'
 jac: array([ 12548372.4766904 ,  12967696.88362279,  39928956.72239509,
    -9224613.99092537,   3954696.30747453,         0.        ])
 nit: 2

这是我的代码:

from random import random
from scipy.optimize import minimize

def func(x):
   """ dummy function to optimize """
   print 'x'+str(x)
   return random()

my_constraints = ('type':'ineq', 'fun':lambda(x):1-x[3]-x[4],
                  'type':'ineq', 'fun':lambda(x):x[3],
                  'type':'ineq', 'fun':lambda(x):x[4],
                  'type':'ineq', 'fun':lambda(x):1-x[4],
                  'type':'ineq', 'fun':lambda(x):1-x[3])

minimize(func, [57.9499 ,-18.2736,1.1664,0.0000,0.0765],
         method='SLSQP',constraints=my_constraints)

编辑 - 即使删除第一个约束,问题仍然存在。

当我尝试使用 bounds 变量时,问题仍然存在。 即,

bounds_pairs = [(None,None),(None,None),(None,None),(0,1),(0,1)]
minimize(f,initial_guess,method=method_name,bounds=bounds_pairs,constraints=non_negative_prob)

【问题讨论】:

为什么要使用无意义的函数来优化?如果函数只返回random()(特别是对于相同的输入,甚至不会返回一致的结果),当然 SciPy 会感到困惑。 为了这个例子。无论我使用什么功能,都会出现此问题。我不认为这是问题@user2357112 至少在 scipy 文档中,当使用 lambda 时,他们会煞费苦心地返回一个 np.array(),例如:'fun' : lambda x: np.array([x[0]* *3 - x[1]])。 感谢@JonCuster,但事实并非如此。无论我使用 np.array 还是仅使用序列,问题仍然存在。我试图用最小的例子来重现这个问题。 @JonCuster 我实际上也需要这个约束。当我删除第一个约束时问题仍然存在。我之前也尝试过 bounds 变量,但没有成功! 【参考方案1】:

我知道这是一个非常古老的问题,但我很感兴趣。

什么时候发生?

当优化函数不能可靠可微时,就会出现此问题。如果您使用这样的平滑函数:

opt = numpy.array([2, 2, 2, 2, 2])

def func(x):
   return sum((x - opt)**2)

问题消失了。

如何施加硬约束?

请注意,scipy.minimize 中的任何约束算法都不能保证函数永远不会在约束之外进行评估。如果这是您的要求,您应该使用转换。因此,例如,为了确保 x[3] 没有使用任何负值,您可以使用转换 x3_real = 10^x[3]。这样 x[3] 可以是任何值,但你使用的变量永远不会是负数。

深入分析

调查 slsqp 的 Fortran 代码可以得出以下关于何时发生此错误的见解。该例程返回一个MODE 变量,它可以采用以下值:

C*        MODE = -1: GRADIENT EVALUATION, (G&A)                        *
C*                0: ON ENTRY: INITIALIZATION, (F,G,C&A)               *
C*                   ON EXIT : REQUIRED ACCURACY FOR SOLUTION OBTAINED *
C*                1: FUNCTION EVALUATION, (F&C)                        *
C*                                                                     *
C*                   FAILURE MODES:                                    *
C*                2: NUMBER OF EQUALITY CONTRAINTS LARGER THAN N       *
C*                3: MORE THAN 3*N ITERATIONS IN LSQ SUBPROBLEM        *
C*                4: INEQUALITY CONSTRAINTS INCOMPATIBLE               *
C*                5: SINGULAR MATRIX E IN LSQ SUBPROBLEM               *
C*                6: SINGULAR MATRIX C IN LSQ SUBPROBLEM               *

分配模式4的部分(这是您得到的错误)如下:

C   SEARCH DIRECTION AS SOLUTION OF QP - SUBPROBLEM

      CALL dcopy_(n, xl, 1, u, 1)
      CALL dcopy_(n, xu, 1, v, 1)
      CALL daxpy_sl(n, -one, x, 1, u, 1)
      CALL daxpy_sl(n, -one, x, 1, v, 1)
      h4 = one
      CALL lsq (m, meq, n , n3, la, l, g, a, c, u, v, s, r, w, iw, mode)

C   AUGMENTED PROBLEM FOR INCONSISTENT LINEARIZATION

      IF (mode.EQ.6) THEN
          IF (n.EQ.meq) THEN
              mode = 4
          ENDIF
      ENDIF

所以基本上你可以看到它试图找到一个下降方向,如果约束是活动的,它会尝试沿着约束进行导数评估,并在 lsq 子问题 (mode = 6) 中以奇异矩阵失败,那么它的理由是,如果所有对约束方程进行了评估,但没有一个产生成功的下降方向,这一定是一组矛盾的约束 (mode = 4)。

【讨论】:

这真的很旧,所以甚至无法检查它。无论如何,感谢您挖掘它。

以上是关于Scipy.optimize.minimize method='SLSQP' 忽略约束的主要内容,如果未能解决你的问题,请参考以下文章

使用 scipy.optimize.minimize 提前停止损失函数

当 scipy.optimize.minimize 可能用于相同的事情时,为啥 scipy.optimize.least_squares 存在?

`scipy.optimize.minimize` 中的 Jacobian 和 Hessian 输入

scipy.optimize.minimize 选择无视约束的参数

为啥 scipy.optimize.minimize (默认)在不使用 Skyfield 的情况下报告成功?

打印选择的 scipy.optimize.minimize 方法