在 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_f
、cons_Jacobian
和 cons_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
我正在尝试使用 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_f
、cons_Jacobian
和 cons_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