在优化问题中,我们常常遇到带有约束条件的极值问题。传统的无约束极值求解方法无法直接处理此类问题,而拉格朗日乘数法正是为了解决这一问题而提出的。
考虑一个目标函数
f ( x 1 , x 2 , … , x n ) f(x_1,x_2,\dots,x_n) f(x1,x2,…,xn)
在满足约束条件
g ( x 1 , x 2 , … , x n ) = 0 g(x_1,x_2,\dots,x_n)=0 g(x1,x2,…,xn)=0
下求极值。直观上,由于约束条件将可行域限制在一个低维曲面上,我们无法简单地求偏导令其为零。拉格朗日乘数法的基本思想是引入一个辅助变量 λ \lambda λ,构造拉格朗日函数
L ( x 1 , x 2 , … , x n , λ ) = f ( x 1 , x 2 , … , x n ) − λ g ( x 1 , x 2 , … , x n ) L(x_1,x_2,\dots,x_n,\lambda)=f(x_1,x_2,\dots,x_n)-\lambda g(x_1,x_2,\dots,x_n) L(x1,x2,…,xn,λ)=f(x1,x2,…,xn)−λg(x1,x2,…,xn)
在满足
∇ L ( x 1 , x 2 , … , x n , λ ) = 0 \nabla L(x_1,x_2,\dots,x_n,\lambda)=0 ∇L(x1,x2,…,xn,λ)=0
的条件下,即可得到极值点。直观上,这一方法可以理解为在原问题中加入一项“惩罚因子”,使得在求解无约束问题时自动满足约束条件。
设目标函数 f ( x ) f(\mathbf{x}) f(x) 与约束条件 g ( x ) = 0 g(\mathbf{x})=0 g(x)=0,令
L ( x , λ ) = f ( x ) − λ g ( x ) L(\mathbf{x},\lambda)=f(\mathbf{x})-\lambda g(\mathbf{x}) L(x,λ)=f(x)−λg(x)
则有以下必要条件:
∂ L ∂ x i = ∂ f ∂ x i − λ ∂ g ∂ x i = 0 , i = 1 , 2 , … , n , \frac{\partial L}{\partial x_i} = \frac{\partial f}{\partial x_i} - \lambda \frac{\partial g}{\partial x_i} = 0,\quad i=1,2,\dots,n, ∂xi∂L=∂xi∂f−λ∂xi∂g=0,i=1,2,…,n,
∂ L ∂ λ = − g ( x ) = 0. \frac{\partial L}{\partial \lambda} = -g(\mathbf{x}) = 0. ∂λ∂L=−g(x)=0.
这组方程同时包含了目标函数在可行域上的导数信息与约束条件,因此可以同时求得变量 x \mathbf{x} x 与乘数 λ \lambda λ 的值。注意,在某些问题中,可能有多个约束,此时需要引入多个拉格朗日乘数,构造
L ( x , λ 1 , λ 2 , … , λ m ) = f ( x ) − ∑ j = 1 m λ j g j ( x ) L(\mathbf{x},\lambda_1,\lambda_2,\dots,\lambda_m)=f(\mathbf{x})-\sum_{j=1}^{m}\lambda_j g_j(\mathbf{x}) L(x,λ1,λ2,…,λm)=f(x)−j=1∑mλjgj(x)
并求解相应的梯度为零的方程组。
下面给出基于拉格朗日乘数法求解约束优化问题的一般步骤:
构造拉格朗日函数
根据目标函数 f ( x ) f(\mathbf{x}) f(x) 和约束条件 g ( x ) = 0 g(\mathbf{x})=0 g(x)=0 构造
L ( x , λ ) = f ( x ) − λ g ( x ) . L(\mathbf{x},\lambda)=f(\mathbf{x})-\lambda g(\mathbf{x}). L(x,λ)=f(x)−λg(x).
求偏导并构造方程组
对每个变量 x i x_i xi 求偏导并令其为零,得到
∂ f ∂ x i − λ ∂ g ∂ x i = 0 , i = 1 , … , n , \frac{\partial f}{\partial x_i}-\lambda \frac{\partial g}{\partial x_i}=0,\quad i=1,\dots,n, ∂xi∂f−λ∂xi∂g=0,i=1,…,n,
同时,考虑约束条件
g ( x ) = 0. g(\mathbf{x})=0. g(x)=0.
求解方程组
联立上述方程组,求解变量 x \mathbf{x} x 与 λ \lambda λ 的值。
验证极值与判别
求得的候选解可能为极大值、极小值或鞍点,必要时需要进一步验证(例如,通过二阶条件或实际问题背景判断)。
在实际工程中,我们通常将上述算法封装为一个类或函数。下面给出一个伪代码示例:
class LagrangeOptimizer:
def __init__(self, f, constraints, variables, lambdas):
self.f = f # 目标函数
self.constraints = constraints # 约束条件列表
self.variables = variables # 优化变量列表
self.lambdas = lambdas # 拉格朗日乘数列表
def construct_lagrangian(self):
# 构造拉格朗日函数 L = f - \sum_i \lambda_i * constraint_i
L = self.f
for lam, g in zip(self.lambdas, self.constraints):
L -= lam * g
return L
def solve(self):
# 求解梯度方程组
L = self.construct_lagrangian()
eqs = []
for var in self.variables:
eqs.append(diff(L, var))
for g in self.constraints:
eqs.append(g) # 约束条件 g = 0
solutions = solve(eqs, self.variables + self.lambdas)
return solutions
以上伪代码利用符号计算(例如 sympy)构造拉格朗日函数,并求解梯度为零的方程组。接下来,将结合具体案例进行详细分析。
接下来我们通过三个经典案例,对拉格朗日乘数法进行具体分析与代码实现。每个案例均包含:
考虑最小化目标函数
f ( x , y ) = x 2 + y 2 f(x,y)=x^2+y^2 f(x,y)=x2+y2
在约束条件
g ( x , y ) = x + y − 1 = 0 g(x,y)=x+y-1=0 g(x,y)=x+y−1=0
下求极值。直观上,函数 x 2 + y 2 x^2+y^2 x2+y2 表示二维平面上到原点的距离平方,约束条件 x + y = 1 x+y=1 x+y=1 则是一条直线。问题的几何意义即为求直线上离原点最近的点。
构造拉格朗日函数:
L ( x , y , λ ) = x 2 + y 2 − λ ( x + y − 1 ) . L(x,y,\lambda)=x^2+y^2-\lambda (x+y-1). L(x,y,λ)=x2+y2−λ(x+y−1).
求解偏导得:
∂ L ∂ x = 2 x − λ = 0 , ( 1 ) \frac{\partial L}{\partial x}=2x-\lambda=0, \quad (1) ∂x∂L=2x−λ=0,(1)
∂ L ∂ y = 2 y − λ = 0 , ( 2 ) \frac{\partial L}{\partial y}=2y-\lambda=0, \quad (2) ∂y∂L=2y−λ=0,(2)
∂ L ∂ λ = − ( x + y − 1 ) = 0. ( 3 ) \frac{\partial L}{\partial \lambda}=-(x+y-1)=0. \quad (3) ∂λ∂L=−(x+y−1)=0.(3)
由 (1) 和 (2) 可知:
2 x = 2 y ⟹ x = y . 2x=2y \Longrightarrow x=y. 2x=2y⟹x=y.
代入 (3) 得:
x + x − 1 = 0 ⟹ x = 1 2 , y = 1 2 . x+x-1=0\Longrightarrow x=\frac{1}{2},\quad y=\frac{1}{2}. x+x−1=0⟹x=21,y=21.
同时由 (1) 可得:
λ = 2 x = 1. \lambda=2x=1. λ=2x=1.
因此,当 x = y = 1 2 x=y=\frac{1}{2} x=y=21 时取得极小值,且最小值为
f ( 1 2 , 1 2 ) = 1 4 + 1 4 = 1 2 . f\left(\frac{1}{2},\frac{1}{2}\right)=\frac{1}{4}+\frac{1}{4}=\frac{1}{2}. f(21,21)=41+41=21.
下面的代码实现利用 sympy 构造符号表达式,求解上述方程组,并利用 matplotlib 绘制目标函数及约束曲线的示意图。
# 案例一:最小化 f(x, y) = x^2 + y^2 在约束 x + y = 1 下的极值
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
def case1_lagrange():
# 定义符号变量
x, y, lam = sp.symbols('x y lam', real=True)
# 定义目标函数和约束条件
f = x**2 + y**2
g = x + y - 1
# 构造拉格朗日函数
L = f - lam * g
# 求偏导并构造方程组
eq1 = sp.Eq(sp.diff(L, x), 0) # 2x - lam = 0
eq2 = sp.Eq(sp.diff(L, y), 0) # 2y - lam = 0
eq3 = sp.Eq(g, 0) # x + y - 1 = 0
# 求解方程组
sol = sp.solve([eq1, eq2, eq3], (x, y, lam), dict=True)
sol = sol[0]
print("案例一求解结果:")
print("x =", sol[x])
print("y =", sol[y])
print("lambda =", sol[lam])
print("最小值 f =", f.subs({x: sol[x], y: sol[y]}))
# 绘制目标函数和约束条件图形
x_vals = np.linspace(-0.5, 1.5, 400)
y_vals = np.linspace(-0.5, 1.5, 400)
X, Y = np.meshgrid(x_vals, y_vals)
Z = X**2 + Y**2
plt.figure(figsize=(8,6))
cp = plt.contour(X, Y, Z, levels=30, cmap='viridis')
plt.clabel(cp, inline=True, fontsize=8)
# 绘制约束直线 x+y=1
plt.plot(x_vals, 1 - x_vals, 'r-', linewidth=2, label='Constraint: $x+y=1$')
# 标出最优点
plt.plot(sol[x], sol[y], 'ko', markersize=8, label='Optimal Point')
plt.xlabel('x')
plt.ylabel('y')
plt.title('案例一:目标函数轮廓与约束直线')
plt.legend()
plt.grid(True)
plt.show()
if __name__ == '__main__':
case1_lagrange()
运行上述代码,即可看到求解结果和图示,其中红色直线表示约束条件,黑色点为最优点。
本案例考虑在单位圆上求函数
f ( x , y ) = x y f(x,y)=xy f(x,y)=xy
的极值。约束条件为
g ( x , y ) = x 2 + y 2 − 1 = 0. g(x,y)=x^2+y^2-1=0. g(x,y)=x2+y2−1=0.
该问题在经济学和工程优化中有一定应用,比如在某些均衡问题中求得最大乘积值。
构造拉格朗日函数:
L ( x , y , λ ) = x y − λ ( x 2 + y 2 − 1 ) . L(x,y,\lambda)=xy-\lambda (x^2+y^2-1). L(x,y,λ)=xy−λ(x2+y2−1).
求偏导得:
∂ L ∂ x = y − 2 λ x = 0 , ( 1 ) \frac{\partial L}{\partial x}=y-2\lambda x=0,\quad (1) ∂x∂L=y−2λx=0,(1)
∂ L ∂ y = x − 2 λ y = 0 , ( 2 ) \frac{\partial L}{\partial y}=x-2\lambda y=0,\quad (2) ∂y∂L=x−2λy=0,(2)
∂ L ∂ λ = − ( x 2 + y 2 − 1 ) = 0. ( 3 ) \frac{\partial L}{\partial \lambda}=-(x^2+y^2-1)=0.\quad (3) ∂λ∂L=−(x2+y2−1)=0.(3)
由 (1) 与 (2) 得:
情形 1:当 x = y x=y x=y 时
代入 (3) 得:
2 x 2 = 1 ⟹ x = ± 1 2 , y = ± 1 2 . 2x^2=1 \Longrightarrow x=\pm\frac{1}{\sqrt{2}}, \quad y=\pm\frac{1}{\sqrt{2}}. 2x2=1⟹x=±21,y=±21.
此时 f ( x , y ) = 1 2 f(x,y)=\frac{1}{2} f(x,y)=21 或 1 2 \frac{1}{2} 21。
情形 2:当 x = − y x=-y x=−y 时
代入 (3) 得:
2 x 2 = 1 ⟹ x = ± 1 2 , y = ∓ 1 2 , 2x^2=1 \Longrightarrow x=\pm\frac{1}{\sqrt{2}}, \quad y=\mp\frac{1}{\sqrt{2}}, 2x2=1⟹x=±21,y=∓21,
此时 f ( x , y ) = − 1 2 f(x,y)=-\frac{1}{2} f(x,y)=−21。
因此,极大值为 1 2 \frac{1}{2} 21,极小值为 − 1 2 -\frac{1}{2} −21。
下面给出基于 sympy 求解该问题的完整代码,同时绘制单位圆和目标函数等高线图,并标记出极值点。
# 案例二:最大化 f(x, y) = x*y 在约束 x^2 + y^2 = 1 下的极值
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
def case2_lagrange():
# 定义符号变量
x, y, lam = sp.symbols('x y lam', real=True)
# 定义目标函数和约束条件
f = x * y
g = x**2 + y**2 - 1
# 构造拉格朗日函数
L = f - lam * g
# 求偏导并构造方程组
eq1 = sp.Eq(sp.diff(L, x), 0) # y - 2*lam*x = 0
eq2 = sp.Eq(sp.diff(L, y), 0) # x - 2*lam*y = 0
eq3 = sp.Eq(g, 0) # x^2+y^2-1 = 0
# 求解方程组
sols = sp.solve([eq1, eq2, eq3], (x, y, lam), dict=True)
print("案例二求解结果:")
for sol in sols:
print("解:x =", sol[x], ", y =", sol[y], ", lambda =", sol[lam])
print("f(x,y) =", f.subs({x: sol[x], y: sol[y]}))
print("------")
# 绘制目标函数等高线和约束条件(单位圆)
x_vals = np.linspace(-1.2, 1.2, 400)
y_vals = np.linspace(-1.2, 1.2, 400)
X, Y = np.meshgrid(x_vals, y_vals)
Z = X * Y
plt.figure(figsize=(8,6))
cp = plt.contour(X, Y, Z, levels=30, cmap='plasma')
plt.clabel(cp, inline=True, fontsize=8)
# 绘制单位圆
theta = np.linspace(0, 2*np.pi, 400)
plt.plot(np.cos(theta), np.sin(theta), 'r-', linewidth=2, label='Constraint: $x^2+y^2=1$')
# 标出候选解
for sol in sols:
x_opt = float(sol[x])
y_opt = float(sol[y])
plt.plot(x_opt, y_opt, 'ko', markersize=8)
plt.xlabel('x')
plt.ylabel('y')
plt.title('案例二:目标函数等高线与单位圆')
plt.legend()
plt.grid(True)
plt.show()
if __name__ == '__main__':
case2_lagrange()
运行代码后,可见单位圆(红色曲线)与目标函数等高线图,黑色点分别代表候选解,极大值和极小值一目了然。
本案例考虑三维空间中的最小化问题。目标函数为
f ( x , y , z ) = ( x − 1 ) 2 + ( y − 2 ) 2 + ( z − 3 ) 2 , f(x,y,z)=(x-1)^2+(y-2)^2+(z-3)^2, f(x,y,z)=(x−1)2+(y−2)2+(z−3)2,
描述了点 ( x , y , z ) (x,y,z) (x,y,z) 与定点 ( 1 , 2 , 3 ) (1,2,3) (1,2,3) 之间的欧氏距离平方。约束条件为
g ( x , y , z ) = x + y + z − 6 = 0 , g(x,y,z)=x+y+z-6=0, g(x,y,z)=x+y+z−6=0,
即所有满足三个坐标和为 6 的点构成的平面。问题实际意义为:在给定平面上寻找与点 ( 1 , 2 , 3 ) (1,2,3) (1,2,3) 最近的点。
构造拉格朗日函数:
L ( x , y , z , λ ) = ( x − 1 ) 2 + ( y − 2 ) 2 + ( z − 3 ) 2 − λ ( x + y + z − 6 ) . L(x,y,z,\lambda)=(x-1)^2+(y-2)^2+(z-3)^2-\lambda(x+y+z-6). L(x,y,z,λ)=(x−1)2+(y−2)2+(z−3)2−λ(x+y+z−6).
求偏导得:
由 (1)、(2)、(3) 可得:
λ = 2 ( x − 1 ) = 2 ( y − 2 ) = 2 ( z − 3 ) . \lambda=2(x-1)=2(y-2)=2(z-3). λ=2(x−1)=2(y−2)=2(z−3).
令 2 ( x − 1 ) = 2 ( y − 2 ) 2(x-1)=2(y-2) 2(x−1)=2(y−2),得到 x − 1 = y − 2 ⟹ x = y + 1 x-1=y-2\Longrightarrow x=y+1 x−1=y−2⟹x=y+1。
同理,由 2 ( y − 2 ) = 2 ( z − 3 ) 2(y-2)=2(z-3) 2(y−2)=2(z−3) 得 y − 2 = z − 3 ⟹ y = z + 1 y-2=z-3\Longrightarrow y=z+1 y−2=z−3⟹y=z+1。
因此,关系为:
x = z + 2 , y = z + 1. x=z+2,\quad y=z+1. x=z+2,y=z+1.
将它们代入约束 (4) 中:
( z + 2 ) + ( z + 1 ) + z = 6 ⟹ 3 z + 3 = 6 ⟹ z = 1. (z+2)+(z+1)+z=6 \Longrightarrow 3z+3=6\Longrightarrow z=1. (z+2)+(z+1)+z=6⟹3z+3=6⟹z=1.
从而得到 y = 2 , x = 3 y=2,\; x=3 y=2,x=3。最终极小值为
f ( 3 , 2 , 1 ) = ( 3 − 1 ) 2 + ( 2 − 2 ) 2 + ( 1 − 3 ) 2 = 2 2 + 0 2 + ( − 2 ) 2 = 8. f(3,2,1)=(3-1)^2+(2-2)^2+(1-3)^2=2^2+0^2+(-2)^2=8. f(3,2,1)=(3−1)2+(2−2)2+(1−3)2=22+02+(−2)2=8.
下面给出完整的 Python 代码实现,同时利用三维图形绘制出目标函数的等值面和约束平面(为了直观展示求解结果)。
# 案例三:最小化 f(x,y,z) = (x-1)^2+(y-2)^2+(z-3)^2 在约束 x+y+z=6 下的极值
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def case3_lagrange():
# 定义符号变量
x, y, z, lam = sp.symbols('x y z lam', real=True)
# 定义目标函数和约束条件
f = (x-1)**2 + (y-2)**2 + (z-3)**2
g = x + y + z - 6
# 构造拉格朗日函数
L = f - lam * g
# 求偏导并构造方程组
eq1 = sp.Eq(sp.diff(L, x), 0) # 2(x-1) - lam = 0
eq2 = sp.Eq(sp.diff(L, y), 0) # 2(y-2) - lam = 0
eq3 = sp.Eq(sp.diff(L, z), 0) # 2(z-3) - lam = 0
eq4 = sp.Eq(g, 0) # x+y+z-6 = 0
# 求解方程组
sol = sp.solve([eq1, eq2, eq3, eq4], (x, y, z, lam), dict=True)[0]
print("案例三求解结果:")
print("x =", sol[x])
print("y =", sol[y])
print("z =", sol[z])
print("lambda =", sol[lam])
print("最小值 f =", f.subs({x: sol[x], y: sol[y], z: sol[z]}))
# 绘制三维图形:约束平面和目标函数等值面
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111, projection='3d')
# 绘制约束平面 x+y+z=6
xx, yy = np.meshgrid(np.linspace(-1, 7, 50), np.linspace(-1, 7, 50))
zz = 6 - xx - yy
ax.plot_surface(xx, yy, zz, alpha=0.3, color='cyan', rstride=1, cstride=1, edgecolor='none', label='Constraint: $x+y+z=6$')
# 绘制目标函数等值面 f(x,y,z)=常数
# 固定一个等值 f0 = f(x_opt, y_opt, z_opt) + delta,选取不同delta
delta_vals = [2, 5, 10]
for delta in delta_vals:
f0 = f.subs({x: sol[x], y: sol[y], z: sol[z]}) + delta
# 解方程 (x-1)^2+(y-2)^2+(z-3)^2 = f0 得到 z 作为函数
# 这里简单绘制 z 面:令 z = 3 + sqrt(f0 - (x-1)^2-(y-2)^2) 和 z = 3 - sqrt(f0 - (x-1)^2-(y-2)^2)
X = np.linspace(-1, 7, 100)
Y = np.linspace(-1, 7, 100)
X, Y = np.meshgrid(X, Y)
under_sqrt = f0 - (X-1)**2 - (Y-2)**2
under_sqrt[under_sqrt < 0] = 0 # 避免负数
Z1 = 3 + np.sqrt(under_sqrt)
Z2 = 3 - np.sqrt(under_sqrt)
ax.plot_surface(X, Y, Z1, alpha=0.2, cmap='autumn')
ax.plot_surface(X, Y, Z2, alpha=0.2, cmap='autumn')
# 标出最优点
ax.scatter(float(sol[x]), float(sol[y]), float(sol[z]), color='k', s=100, label='Optimal Point')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_title('案例三:目标函数等值面与约束平面')
ax.legend()
plt.show()
if __name__ == '__main__':
case3_lagrange()
运行后,可见三维图中以半透明的方式绘制了约束平面和目标函数的不同等值面,并标记了最优点 ( 3 , 2 , 1 ) (3,2,1) (3,2,1)。
本文详细介绍了拉格朗日乘数法的基本原理及数学推导,并通过三个不同维度和问题背景的案例,演示了如何利用该方法求解带约束条件的优化问题。主要内容总结如下:
理论部分
算法实现
案例分析
图形展示
通过这些案例,我们可以看到,拉格朗日乘数法作为一种经典的求解带约束极值问题的方法,不仅在理论上具有严密性,而且在实际工程中有广泛应用。利用 Python 的符号计算和图形绘制能力,可以方便地实现和验证该方法。
在实际应用中,经常会遇到多约束条件问题。对于目标函数 f ( x 1 , … , x n ) f(x_1,\dots,x_n) f(x1,…,xn) 和约束条件 g i ( x 1 , … , x n ) = 0 , i = 1 , … , m g_i(x_1,\dots,x_n)=0,\; i=1,\dots,m gi(x1,…,xn)=0,i=1,…,m,拉格朗日函数构造为
L ( x 1 , … , x n , λ 1 , … , λ m ) = f ( x 1 , … , x n ) − ∑ i = 1 m λ i g i ( x 1 , … , x n ) . L(x_1,\dots,x_n,\lambda_1,\dots,\lambda_m)=f(x_1,\dots,x_n)-\sum_{i=1}^{m}\lambda_i g_i(x_1,\dots,x_n). L(x1,…,xn,λ1,…,λm)=f(x1,…,xn)−i=1∑mλigi(x1,…,xn).
求解时,只需对所有变量求偏导,然后联立方程组求解即可。扩展后的问题在数值计算上可能会更加复杂,此时可以结合数值优化方法进行求解。
在上述案例中,我们使用了 sympy 进行符号求解。但在实际应用中,尤其是当问题较复杂或存在非线性、非凸性时,符号求解可能不适用。此时可以考虑数值优化算法,如牛顿法、梯度下降法或内点法等,并利用 Python 中的 SciPy 库进行求解。同时,可以将拉格朗日乘数法的思想与数值方法相结合,构造罚函数或对偶问题,进而实现求解。
在实际开发过程中,代码需要符合良好的设计规范。上文的每个案例均遵循以下原则:
拉格朗日乘数法作为求解约束极值问题的基本方法,其思想简单却极具威力。本文从理论、流程、代码实现、图形展示等多个角度进行了详细讲解。通过三个案例,不仅展示了该方法在二维和三维问题中的应用,还阐述了如何将算法模块化,方便在实际问题中调用。希望读者通过本文能对拉格朗日乘数法有更深入的理解,并能在工程实践中灵活运用这一方法解决实际问题。
在未来的工作中,还可以探索如下方向:
希望本文能为读者提供系统而全面的参考,欢迎大家提出宝贵意见与建议,共同探讨优化算法在更多领域中的应用与发展。