在 Scipy 优化中使用 LinearOperator 作为非线性约束

Using LinearOperator as nonlinear constraints in Scipy optimize

我正在尝试使用 SciPy 中的优化模块来解决约束优化问题。我需要实现 'hess' 参数。在scipy的文档和教程中,他们的hessian只是[[2, 0], [0, 0]][[2, 0], [0, 0]]。但是,我的 hessian 类似于 [[(-24)*x[0]**2 + 48*x[0]-16, 0], [0, 0]][[(-48)*x[0]**2 + 192*x[0]-176, 0], [0, 0]],因此我不能简单地使用 numpy.array 进行乘法运算。看来我应该向 'hess' 争论发送一个 LinearOperator 对象。 scipy.optimize tutorial and LinearOperator documentation 中使用 LinearOperator 的示例都不清楚,因为它们仅显示较低维度的示例。我想知道如何正确使用它?

问题的表述是

我的代码是:

import numpy as np
from scipy.optimize import Bounds
from scipy.optimize import NonlinearConstraint
from scipy.optimize import minimize

def f(x):
    return (-x[0]-x[1])
def grad(x):
    return np.array([-1, -1])
def hess(x):
    return np.array([[0, 0], [0, 0]])

def cons_f(x):
    return [(-2)*x[0]**4 + 8*x[0]**3 + (-8)*x[0]**2 + x[1] -2, (-4)*x[0]**4 + 32*x[0]**3 + (-88)*x[0]**2 + 96*x[0] + x[1] -36]
    
def cons_Jacobian(x):
    return [[(-8)*x[0]**3 + 24*x[0]**2 - 16*x[0], 1], [(-16)*x[0]**3 + 96*x[0]**2 - 176*x[0] +96, 1]]

def cons_Hessian(x,v):
    # TODO
    return v[0]*[[(-24)*x[0]**2 + 48*x[0]-16, 0], [0, 0]] + v[1]*[[(-48)*x[0]**2 + 192*x[0]-176, 0], [0, 0]]

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 0, jac=cons_Jacobian, hess=cons_Hessian)

bounds = Bounds([0, 0], [3.0, 4.0])
x0 = np.array([0.5, 1])
res = minimize(f, x0, method='trust-constr', jac=grad, hess=hess,
               constraints=[nonlinear_constraint],bounds=bounds)

我的代码中的 cons_Hessian(x,v) 完全错误。

在他们的例子中,虽然 hessians 只是 [[2, 0], [0, 0]][[2, 0], [0, 0]],但用法令人困惑。我不明白 p 是从哪里来的。

from scipy.sparse.linalg import LinearOperator
def cons_H_linear_operator(x, v):
    def matvec(p):
        return np.array([p[0]*2*(v[0]+v[1]), 0])
    return LinearOperator((2, 2), matvec=matvec)
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
                                          jac=cons_J, hess=cons_H_linear_operator)

无需使用 LinearOperator。您只需要确保 cons_fcons_Jacobiancons_Hessian return np.ndarrays。这就是您无法评估 cons_Hessian 的原因。此外,强烈建议使用双文字而不是整数,即 -2.0 而不是 2 以防止函数 returns np.ndarrays 与整数 dtype .

你的示例通过编写如下这些函数对我有用:

def cons_f(x):
    con1 = (-2.0)*x[0]**4 + 8*x[0]**3 + (-8)*x[0]**2 + x[1] - 2
    con2 = (-4)*x[0]**4 + 32*x[0]**3 + (-88)*x[0]**2 + 96*x[0] + x[1] -36
    return np.array([con1, con2])
    
def cons_Jacobian(x):
    con1_grad = [(-8.0)*x[0]**3 + 24*x[0]**2 - 16*x[0], 1]
    con2_grad = [(-16)*x[0]**3 + 96*x[0]**2 - 176*x[0] +96, 1]
    return np.array([con1_grad, con2_grad])

def cons_Hessian(x,v):
    con1_hess = np.array([[(-24.0)*x[0]**2 + 48*x[0]-16, 0], [0, 0]])
    con2_hess = np.array([[(-48)*x[0]**2 + 192*x[0]-176, 0], [0, 0]])
    return v[0]*con1_hess + v[1]*con2_hess