一、拉格朗日乘子法和KKT的介绍
拉格朗日乘子法 | 拉格朗日乘子λ代表当约束条件变动时,目标函数极值的变化。是一种经典的求解条件极值的解析方法,求函数f(x1,x2,…)在约束条件g(x1,x2,…)=0下的极值的方法。这种引进待定乘子,将有等式约束的寻优问题转化为无约束的寻优问题的做法,称为拉格朗日乘子法,又叫升维法。 |
---|
- 等式约束条件
设目标函数为f(x),约束条件为hk(x),形如
s.t. 表示subject to ,“受限于”的意思,l表示有l个约束条件。
定义拉格朗日函数F(x)
其中λk是各个约束条件的待定系数
然后解变量的偏导方程:
如果有n个约束条件,就应该有n+1个方程;求出的方程组的解就是最优化值,将结果带回原方程验证就可得到解。
KKT条件 | KKT条件在约束条件下求解非线性规划问题很有用,是确定某点为最优点的一阶必要条件。 |
---|
-
标准约束优化问题
考虑g(x)≤0,此时最优解x∗ 或者在g(x)<0 的区域中,或者在边界g(x)=0 上
定义拉格朗日函数
其中λ是对应h(x)=0的拉格朗日乘数,μ是对应g(x)⩽0的拉格朗日乘数,对应的KKT条件
当g(x)<0时,μ=0,原式中就不考虑g(x);当g(x)=0时,λ 可取任何大于等于0的值。 -
例题:(我用下面这个例题来对这两种求解非线性规划的拉格朗日乘子法的手工数学推导,考虑有约束情况的python代码统一进行比较,我觉得这样效果更加的明确、直观和对各种方法的对比更有针对性!)
二、手工数学推导
如图
综上所述,假设当 a = b = c = 1时
可以知道 Vmax=(8*根号3) / 9 = 1.5396007
x = y = z = 根号3 / 3 = 0.5773503
三、拉格朗日乘子法的有约束情况
代码如下:
from scipy.optimize import minimize
import numpy as np
e = 1e-10 # 非常接近0的值
fun = lambda x : 8 * (x[0] * x[1] * x[2]) # 约束函数f(x,y,z) =8 *x*y*z
cons = ({'type': 'eq', 'fun': lambda x: x[0]**2+ x[1]**2+ x[2]**2 - 1}, # x^2 + y^2 + z^2=1
{'type': 'ineq', 'fun': lambda x: x[0] - e}, # x>=e,即 x > 0
{'type': 'ineq', 'fun': lambda x: x[1] - e},
{'type': 'ineq', 'fun': lambda x: x[2] - e}
)
x0 = np.array((1.0, 1.0, 1.0)) # 设置初始值
res = minimize(fun, x0, method='SLSQP', constraints=cons)
print('最大值:',res.fun)
print('最优解:',res.x)
print('迭代终止是否成功:', res.success)
print('迭代终止原因:', res.message)
在 jupyter notebook 中运行
运行结果:
四、手工数学推导,考虑有约束情况的比较
综上所述,非线性规划的拉格朗日乘子法的手工数学推导,考虑有约束情况的结果都是一样的,都是假设当 a = b = c = 1时,可以知道 Vmax=(8*根号3) / 9 = 1.5396007;x = y = z = 根号3 / 3 = 0.5773503。但是我觉得作为一个学编程的学生,还是应该多练习用写代码的方式求解数学问题!
五、参考文献
我的用大M法的excel求解、python编程求解和python包分别求解线性规划中的单纯形法在另外的一篇博客里面。
加油!