Python编程实现对拉格朗日和KKT条件求极值

一、拉格朗日和KKT条件求极值概念

求解最优化问题中,拉格朗日乘子法和KKT条件是两种最常用的方法。在有等式约束时使用拉格朗日乘子法,在有不等式约束时使用KKT条件。这个最优化问题指某一函数在作用域上的全局最小值(最小值与最大值可以相互转换)。

最优化问题通常有三种情况(这里说两种):

无约束条件
求解办法是求导等于0得到极值点。将结果带回原函数验证。

等式约束条件
设目标函数f(x),约束条件hk(x),
min f(x)  s.t. hk(x)=0   (k = 1,2…l)
l表示有l个约束条件。
该类问题解决办法是消元法或拉格朗日法。消元法简单,这里讲拉格朗日法,后面提到的KKT条件是对拉格朗日乘子法的泛化。

例题:
椭球内接长方体的最大体积,即求 f(x,y,z) = 8xyz 的最大值。
方法1:消元法
根据条件消去z,然后带入函数转化为无条件极值问题。(有时这种方法麻烦,甚至解不出来)
方法2:拉格朗日乘法
思想:通过引入拉格朗日乘子将含有n个变量和k个约束条件的约束优化问题转化为含有(n+k)个变量的无约束优化问题。
首先定义拉格朗日函数F(x),f(x)为目标函数,h(x)为约束条件:
(λk是各个约束条件的待定系数)
对各个变量求偏导:

方程组的解就可能是最优化值,将结果带回原方程验证。
上面的函数,通过拉格朗日乘数法将问题转化为:

对 F(x,y,z,λ) 求偏导得到

联立前面3个方程得到 bx = ay 和 az = cx,带入第4个方程:

带入原函数得到最大体积:

为什么这么做是最优解?
举个例子:min f(x,y)  s.t.  g(x,y) = c
画出 z = f(x,y)的等高线

绿线是约束g(x,y) = c的轨迹。蓝线是f(x,y)的等高线。箭头表示斜率,和等高线的发现平行。从梯度的方向看,d1>d2(梯度下降法越接近目标,步长越小,前进越慢)。
在没有约束条件,f(x,y)的最小值是落在最里面等高线内部的某一点。加上约束条件的 f(x,y) 最小值是 f(x,y)的等高线和约束线相切的位置,因为如果只是相交意味着还存在其它的等高线在该等高线的内部或外部,使新的等高线与目标函数的交点值更大或更小,只有等高线与目标函数的曲线相切时,取到最优值。

从图看出,想让目标函数 f(x,y) 的等高线和约束 g(x,y) 相切,则他们切点的梯度在一条直线上( f 和 g 斜率平行)。
即在最优解的时候:∇f(x,y)=λ(∇g(x,y)-C) (∇为梯度算子,即:f(x)的梯度 = λ*g(x)的梯度,λ是非0常数)
即:▽[f(x,y)+λ(g(x,y)−c)]=0  (λ≠0)
那么拉格朗日函数: F(x,y)=f(x,y)+λ(g(x,y)−c) 在达到极值时与 f(x,y) 相等,因为 F(x,y) 达到极值时 g(x,y)-c 总等于0。
min(F(x,λ))取得极小值时其导数为0,即f(x)和h(x)的梯度共线。
简单的说,在F(x,λ)取最优解的时候,即F(x,λ)取极值的时候(导数为0,▽[f(x,y)+λ(g(x,y)−c)]=0)。f(x)与g(x)梯度共线,此时就是在条件约束g(x)下,f(x)的最优解。

不等式约束
设目标函数f(x),不等式约束为g(x),等式约束条件h(x)。此时的约束优化问题描述如下:
我们定义不等式约束下的拉格朗日函数L:

其中f(x)是目标函数,hj(x)是第j个等式约束条件,λj是对应的约束系数,gk(x)是第k个不等式约束,uk是对应的约束系数。
不等式约束常用的方法是KKT条件,同样的,把所有的不等式约束、等式约束和目标函数全部写为一个式子L(a, b, x)= f(x) + ag(x)+bh(x)
KKT条件是说最优值必须满足以下条件:
L(a, b, x)对x求导为零;
h(x) =0;
a*g(x) = 0;
求取这些等式之后就能得到候选最优值。其中第三个式子,因为g(x)<=0,如果要满足这个等式,必须a=0或者g(x)=0。

二、手工推导计算

例题:
在这里插入图片描述
推导解答:
在这里插入图片描述

三、Python编程实现

from sympy import *
x1,x2,k = symbols('x1,x2,k')
f = 60-10*x1-4*x2+(x1)**2+(x2)**2-x1*x2
g = x1+x2-8
#构造拉格朗日等式
L=f-k*g
#求导,构造KKT条件
dx1 = diff(L, x1)   # 对x1求偏导
print("dx1=",dx1)
dx2 = diff(L,x2)   #对x2求偏导
print("dx2=",dx2)
dk = diff(L,k)   #对k求偏导
print("dk=",dk)
dx1= -k + 2*x1 - x2 - 10
dx2= -k - x1 + 2*x2 - 4
dk= -x1 - x2 + 8
#求出个变量解
m= solve([dx1,dx2,dk],[x1,x2,k])   
print(m)
{x1: 5, x2: 3, k: -3}
#给变量重新赋值
x1=m[x1]
x2=m[x2]
k=m[k]
#计算方程的值
f = 60-10*x1-4*x2+(x1)**2+(x2)**2-x1*x2
print("方程的极小值为:",f)

运行结果:
在这里插入图片描述

四、总结

通过上述可以发现,使用Python编程求得的结果和经过手工推导的结果是一致的,想要编程实现的话,就必须要自己首先手工推导一遍,掌握推导过程和计算方法,这样使用Python编程思路才会更加清晰有条理,手工推导编程还是比较麻烦的,但是还是要练习的。

参考文献:
https://www.cnblogs.com/keye/p/10916118.html
https://www.cnblogs.com/ty123/p/10529541.html

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
KKT条件(Karush-Kuhn-Tucker条件)是一种优化问题的必要条件,可以用于解决线性规划、非线性规划等问题。在Python中,可以使用scipy库中的optimize.minimize函数来解带有约束条件的优化问题。例如,假设我们要最小化函数f(x) = x1^2 + 2x2^2 - 2x1x2 + 2x1 + 6x2,同时满足如下不等式约束条件: x1 + x2 ≤ 1, x1 - x2 ≥ 1, x2 ≥ 0。我们可以使用scipy库中的optimize.minimize函数来解该优化问题。首先,我们需要定义目标函数和不等式约束条件,然后设置初值和解方法。最后,通过调用optimize.minimize函数,可以得到最优解和最优值。通过手工推导和Python编程解的结果是一致的,但手工推导编程可能比较麻烦,需要练习和掌握推导过程和计算方法。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [Python中的KKT条件](https://blog.csdn.net/Jack_user/article/details/130893443)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Python编程实现拉格朗日KKT条件极值](https://blog.csdn.net/weixin_45137708/article/details/105639366)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值