6. Scipy Tutorial-有约束优化

约束最优化问题(constrained optimization problem)是指具有约束条件的非线性规划问题。

若是极小化问题,其一般形式为: $$ \min\ F(x) $$ $$ \quad \quad \quad \quad \quad subject\ to: g_i(x) \ge 0(i = 1,2,\cdots,p) $$ $$ \quad \quad \quad \quad \quad \quad \qquad \quad \quad \qquad h_j(x) = 0 (i = q +1,p + 2,\cdots,q) $$ 其中:$g_i(x) \leq 0$为不等式约束,$h_j(x) = 0$为等式约束条件。

  • 下面以$f(x) = 2xy + 2x - x^2 - 2y^2$这个$f(x)$函数为例,看在条件:

$$ x^3 - y = 0 $$ $$ y - 1 \ge 0 $$ 求最优值问题。

#coding:utf-8
import numpy as np
from scipy.optimize import minimize
def func(x, sign=1.0):
    """ 定义目标函数F(x) """
    return sign*(2*x[0]*x[1] + 2*x[0] - x[0]**2 - 2*x[1]**2)
def func_deriv(x, sign=1.0):
    """ 梯度 jac"""
    dfdx0 = sign*(-2*x[0] + 2*x[1] + 2)
    dfdx1 = sign*(2*x[0] - 4*x[1])
    return np.array([ dfdx0, dfdx1 ])
# 约束条件
cons = ({'type': 'eq',#等式约束条件
         'fun' : lambda x: np.array([x[0]**3 - x[1]]),# 方程
         'jac' : lambda x: np.array([3.0*(x[0]**2.0), -1.0])},# 导数
        {'type': 'ineq',#不等式约束条件
         'fun' : lambda x: np.array([x[1] - 1]),#方程
         'jac' : lambda x: np.array([0.0, 1.0])})#导数
res = minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv,
               method='SLSQP', options={'disp': True})
print(res.x) 
res = minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv,
               constraints=cons, method='SLSQP', options={'disp': True})
print(res.x)

程序执行结果:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: -1.9999999999999996
            Iterations: 4
            Function evaluations: 5
            Gradient evaluations: 4
[2. 1.]
Optimization terminated successfully.    (Exit mode 0)
            Current function value: -1.0000001831052137
            Iterations: 9
            Function evaluations: 14
            Gradient evaluations: 9
[1.00000009 1.        ]
  • 下面以目标函数$f(x) = x_1^2 x_2$,在等式约束条件$h(x_1, x_2) = x_1^2 + x_2^2 - 1 = 0$的求最小值的最优解。 $$ min\quad f(x_1, x_2) = x_1^2 x_2 $$ $$ \quad \quad \qquad s.t.\quad h(x_1, x_2) = x_1^2 + x_2^2 - 1 = 0 $$
import numpy as np
from scipy.optimize import minimize
'''目标函数f(x)'''
def f(x):
    return x[0]**2 * x[1]
'''梯度函数jac'''
def f_der(x):
    der = [0, 0]
    der[0] = 2 * x[0] * x[1]
    der[1] = x[0] ** 2
    return np.array(der)     
'''等式约束条件h'''
def h(x):
    return x[0] ** 2 + x[1] ** 2 - 1    

res = minimize(f, [-1.0,1.0], jac=f_der, constraints={"fun": h, "type": "eq"}, method='SLSQP', options={'disp': True})
print res.x 

程序执行结果:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 9.867387900889092e-15
            Iterations: 7
            Function evaluations: 10
            Gradient evaluations: 7
[-9.93347264e-08  1.00000000e+00]

从程序的执行结果[-9.93347264e-08 1.00000000e+00]可以近似认为$x_0 = 0, x_ 1 = 1$是目标函数$f(x)$的一个最优解。显然(0,1)满足$h(x_1, x_2)$函数。

  • 下面以目标函数$f(x) = (x_1 - 2)^2 + (x_2 - 1)^2$,在等式约束条件$h(x_1, x_2) = x_1 + x_2 + 5 = 0$的求最小值的最优解。 $$ min\quad (x_1 - 2)^2 + (x_2 - 1)^2 $$ $$ \quad \quad \quad s.t.\ h(x_1, x_2) =x_1 + x_2 + 5 = 0 $$
import numpy as np
from scipy.optimize import minimize
'''目标函数f(x)'''
def f(x):
    return (x[0]- 2)**2 +  (x[1] - 1) ** 2
'''梯度函数jac'''
def f_der(x):
    der = [0, 0]
    der[0] = 2 * (x[0] - 2)
    der[1] = 2 * (x[1] - 1)
    return np.array(der)     
'''等式约束'''
def h(x):
    return x[0] + x[1]  + 5    

res = minimize(f, [-10.0,10.0], jac=f_der, constraints={"fun": h, "type": "eq"}, method='SLSQP', options={'disp': True})
print(res.x)  

程序执行结果:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 32.00000013512923
            Iterations: 4
            Function evaluations: 6
            Gradient evaluations: 4
[-1.99974007 -3.00025993]

结果里的[-1.99974007 -3.00025993]可视为$x_1 = -2, x_2 = -3 $。