【Scipy优化使用教程】二、Scipy中有约束优化的两种算法

参考官网:Scipy.

对于有约束的最小化问题,Scipy提供的minimize这个包有三个:trust-constr, SLSQP'COBYLA。它们要求使用稍微不同的结构来定义约束。
trust-constr需要要求约束被定义成一系列的LinearConstraintNonlinearConstraint两种类型。
SLSQP'COBYLA需要要求约束条件被定义为一连串的字典,其键为typefunjac
考虑有约束的最小化2个变量的Rosenbrock函数
在这里插入图片描述
这个问题有唯一解: [ x 0 , x 1 ] = [ 0.4149 , 0.1701 ] [x_0,x_1]=[0.4149,0.1701] [x0,x1]=[0.4149,0.1701]

信赖域约束算法(method=‘trust-constr’)

信任域约束方法处理的是约束性最小化问题,其形式为:
在这里插入图片描述
除此之外,单边约束可以通过对np.inf设置上限或下限并加上适当的符号来指定。

定义边界约束

边界限制 0 ≤ x 0 ≤ 1 , − 0.5 ≤ x 1 ≤ 2.0 0≤x_0≤1,-0.5≤x_1≤2.0 0x01,0.5x12.0被定义如下:

from scipy.optimize import Bounds
bounds = Bounds([0, -0.5], [1.0, 2.0])

定义线性约束

约束 x 0 + 2 x 1 ≤ 1 , 2 x 0 + x 1 = 1 x_0+2x_1≤1,2x_0+x_1=1 x0+2x112x0+x1=1可以写成如下形式:
在这里插入图片描述
LinearConstraint去定义:

from scipy.optimize import LinearConstraint
linear_constraint = LinearConstraint([[1, 2], [2, 1]], [-np.inf, 1], [1, 1])

定义非线性约束

非线性约束为:
在这里插入图片描述
雅可比矩阵(对每个变量求导)为:
在这里插入图片描述
黑塞矩阵的线性组合:
在这里插入图片描述
NonlinearConstraint去定义:

#定义非线性约束
def cons_f(x):
    return [x[0]**2 + x[1], x[0]**2 - x[1]]
#定义导数
def cons_J(x):
    return [[2*x[0], 1], [2*x[0], -1]]
#定义二阶导数
def cons_H(x, v):
    return v[0]*np.array([[2, 0], [0, 0]]) + v[1]*np.array([[2, 0], [0, 0]])
from scipy.optimize import NonlinearConstraint
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=cons_H)

另外,也可以将Hessian定义为一个稀疏矩阵。

from scipy.sparse import csc_matrix
def cons_H_sparse(x, v):
    return v[0]*csc_matrix([[2, 0], [0, 0]]) + v[1]*csc_matrix([[2, 0], [0, 0]])
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
                                           jac=cons_J, hess=cons_H_sparse)

当黑塞矩阵难以计算的时候,可以使用HessianUpdateStrategy,目前可用的策略有:BFGSSR1

from scipy.optimize import BFGS
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=BFGS())

另外,Hessian可以用有限差分法进行近似。

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess='2-point')

雅可比矩阵也可以用有限差分法估计,然而,在这种情况下,黑塞不能用有限差分计算,需要由用户提供或用之前介绍的HessianUpdateStrategy定义:

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac='2-point', hess=BFGS())

求解

#设置初值
x0 = np.array([0.5, 0])
#这个需要结合之前无约束的算法来计算
res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hess=rosen_hess,
               constraints=[linear_constraint, nonlinear_constraint],
               options={'verbose': 1}, bounds=bounds)
print(res.x)

无约束代码在这里

`gtol` termination condition is satisfied.
Number of iterations: 12, function evaluations: 8, CG iterations: 7, optimality: 2.99e-09, constraint violation: 0.00e+00, execution time: 0.014 s.
[0.41494531 0.17010937]

完整代码

import numpy as np
from scipy.optimize import minimize
#无约束
def rosen(x):
    """The Rosenbrock function"""
    return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

def rosen_der(x):
    xm = x[1:-1]
    xm_m1 = x[:-2]
    xm_p1 = x[2:]
    der = np.zeros_like(x)
    der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm)
    der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
    der[-1] = 200*(x[-1]-x[-2]**2)
    return der
def rosen_hess(x):
    x = np.asarray(x)
    H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1)
    diagonal = np.zeros_like(x)
    diagonal[0] = 1200*x[0]**2-400*x[1]+2
    diagonal[-1] = 200
    diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:]
    H = H + np.diag(diagonal)
    return H

#设置约束
from scipy.optimize import Bounds
bounds = Bounds([0, -0.5], [1.0, 2.0])
from scipy.optimize import LinearConstraint
linear_constraint = LinearConstraint([[1, 2], [2, 1]], [-np.inf, 1], [1, 1])

def cons_f(x):
    return [x[0]**2 + x[1], x[0]**2 - x[1]]
#定义导数
def cons_J(x):
    return [[2*x[0], 1], [2*x[0], -1]]
#定义二阶导数
def cons_H(x, v):
    return v[0]*np.array([[2, 0], [0, 0]]) + v[1]*np.array([[2, 0], [0, 0]])
from scipy.optimize import NonlinearConstraint
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=cons_H)

#求解
x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hess=rosen_hess,
               constraints=[linear_constraint, nonlinear_constraint],
               options={'verbose': 1}, bounds=bounds)

print(res.x)

另外也可以对目标函数的第一和第二导数进行近似,例如,黑塞矩阵可以用SR1准牛顿法近似,梯度可以用有限差分法近似:

from scipy.optimize import SR1
res = minimize(rosen, x0, method='trust-constr',  jac="2-point", hess=SR1(),
               constraints=[linear_constraint, nonlinear_constraint],
               options={'verbose': 1}, bounds=bounds)
`gtol` termination condition is satisfied.
Number of iterations: 12, function evaluations: 24, CG iterations: 7, optimality: 4.48e-09, constraint violation: 0.00e+00, execution time: 0.02 s.
[0.41494531 0.17010937]

序列最小二乘(SLSQP) (method=‘SLSQP’)

SLSQP需要如下形式:
在这里插入图片描述

设置约束

在这里插入图片描述
线性和非线性约束都被定义为字典,其键为type、fun和jac:
首先是定义域:

from scipy.optimize import Bounds
bounds = Bounds([0, -0.5], [1.0, 2.0])

等式与不等式约束:

#不等式约束
ineq_cons = {'type': 'ineq',
             'fun' : lambda x: np.array([1 - x[0] - 2*x[1],
                                         1 - x[0]**2 - x[1],
                                         1 - x[0]**2 + x[1]]),
             #jac是对fun的求导
             'jac' : lambda x: np.array([[-1.0, -2.0],
                                         [-2*x[0], -1.0],
                                         [-2*x[0], 1.0]])}
#等式约束
eq_cons = {'type': 'eq',
           'fun' : lambda x: np.array([2*x[0] + x[1] - 1]),
           'jac' : lambda x: np.array([2.0, 1.0])}

求解

x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='SLSQP', jac=rosen_der,
               constraints=[eq_cons, ineq_cons], options={'ftol': 1e-9, 'disp': True},
               bounds=bounds)
print(res.x)
Optimization terminated successfully    (Exit mode 0)
            Current function value: 0.34271757499419825
            Iterations: 4
            Function evaluations: 5
            Gradient evaluations: 4
[0.41494475 0.1701105 ]

完整代码

import numpy as np
from scipy.optimize import minimize
#定义无约束的目标函数
def rosen(x):
    """The Rosenbrock function"""
    return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

def rosen_der(x):
    xm = x[1:-1]
    xm_m1 = x[:-2]
    xm_p1 = x[2:]
    der = np.zeros_like(x)
    der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm)
    der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
    der[-1] = 200*(x[-1]-x[-2]**2)
    return der
def rosen_hess(x):
    x = np.asarray(x)
    H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1)
    diagonal = np.zeros_like(x)
    diagonal[0] = 1200*x[0]**2-400*x[1]+2
    diagonal[-1] = 200
    diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:]
    H = H + np.diag(diagonal)
    return H

#定义约束
from scipy.optimize import Bounds
bounds = Bounds([0, -0.5], [1.0, 2.0])

ineq_cons = {'type': 'ineq',
             'fun' : lambda x: np.array([1 - x[0] - 2*x[1],
                                         1 - x[0]**2 - x[1],
                                         1 - x[0]**2 + x[1]]),
             'jac' : lambda x: np.array([[-1.0, -2.0],
                                         [-2*x[0], -1.0],
                                         [-2*x[0], 1.0]])}
eq_cons = {'type': 'eq',
           'fun' : lambda x: np.array([2*x[0] + x[1] - 1]),
           'jac' : lambda x: np.array([2.0, 1.0])}
           
#求解
x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='SLSQP', jac=rosen_der,
               constraints=[eq_cons, ineq_cons], options={'ftol': 1e-9, 'disp': True},
               bounds=bounds)

print(res.x)

PS:大部分 trust-constr方法可用的选项对 SLSQP来说是不可用的。

  • 9
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
二次无约束二值优化问题可以使用Python优化库进行求解,比如使用SciPy的minimize函数。 具体的方法是将二次无约束二值优化问题转化为二次无约束优化问题,然后使用优化库进行求解。 假设我们的二次无约束二值优化问题的目标函数为f(x),其x为二值变量,可以取值为0或1。我们可以将x表示为: x = (1-t)/2 + (1+t)/2 * y 其t为一个常数,y为取值为-1或1的实数变量。这样,x的取值就被限制在0和1之间。 将x带入目标函数f(x),得到: f(y) = f((1-t)/2 + (1+t)/2 * y) 这是一个二次无约束优化问题,可以使用SciPy的minimize函数进行求解。我们可以使用BFGS或L-BFGS-B算法进行优化,这两种算法都是梯度下降算法的变种,可以有效地求解二次无约束优化问题。 下面是一个使用SciPy的minimize函数求解二次无约束二值优化问题的示例代码: ```python import numpy as np from scipy.optimize import minimize # 定义目标函数 def f(x): return (x[0]**2 + x[1]**2 - 2*x[0]*x[1] + 2*x[0] - 6*x[1]) # 定义约束条件 def constraint(x): return np.array([x[0]**2 + x[1]**2 - 1]) # 定义初始点 x0 = np.array([0, 0]) # 定义范围 bounds = ((-1, 1), (-1, 1)) # 求解 res = minimize(f, x0, method='L-BFGS-B', bounds=bounds, constraints={'type': 'eq', 'fun': constraint}) # 输出结果 print(res.x) ``` 在这个示例,我们定义了一个二次无约束二值优化问题的目标函数f(x),并使用L-BFGS-B算法进行求解。我们还定义了一个约束条件x[0]**2 + x[1]**2 - 1 = 0,这个约束条件限制了x的取值在一个单位圆内。最后,我们使用初始点x0 = [0, 0]进行求解,得到了最优解res.x。 需要注意的是,这个示例的目标函数和约束条件只是一个例子,实际问题需要根据具体情况进行定义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薯一个蜂蜜牛奶味的愿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值