在约束边界上,最优点的梯度可以不为零。要证明它最优,可以找出一个所有可行点都无法低于的下界,再让候选点恰好达到这个下界。给出下界的拉格朗日乘子,就是这里的“对偶证书”;依据是 Boyd 与 Vandenberghe,第 5 章的拉格朗日下界与最优性条件。
凸优化总览介绍了凸性与 KKT 的基本关系;梯度与多维优化解释梯度和 Hessian。如果还不熟悉怎样确定变量、目标与可行域,可以先看优化建模。下面把这些概念放进同一道题里计算。
目标与可行域
令 x,y 为两个实数变量,求解原问题:
minimizesubject tof(x,y)=21((x−2)2+(y−1)2)c1(x,y)=x+y−2≤0,c2(x,y)=−x≤0,c3(x,y)=−y≤0.
可行域 C={(x,y):x≥0, y≥0, x+y≤2} 是闭三角形。目标是到点 (2,1) 的平方距离的一半。C 非空且紧,连续目标一定取得最小值;Hessian 为单位矩阵,所以目标严格凸,最优点唯一。
这符合 CVXPY 的二次规划示例所用的形式 21zTPz+qTz、Gz≤h,其中 P 半正定。本题 z=(x,y)T,P=I2,q=(−2,−1)T,
G=1−1010−1,h=200,f(z)=21zTz+qTz+25.
常数 5/2 不改变最优点。要得到这里定义的 f 和 g 的值,就必须保留它;若从二者中同时减去 5/2,原始–对偶间隙不变。
先算出候选点
无约束最小点 (2,1) 违反 x+y≤2。先试边界 x+y=2,代入 y=2−x:
f(x,2−x)=21((x−2)2+(1−x)2)=(x−23)2+41.
这条边上的最小点为
(x∗,y∗)=(23,21),f(x∗,y∗)=41.
它确实位于边上,因为两坐标都为正。不过,只在一条边上求出最小值,还没有排除三角形内其他点。后面的对偶下界会补上全局证明。
约束在候选点处取等号时称为活跃约束。这里 c1=0,而 c2=−3/2、c3=−1/2,所以只有总量约束活跃。此时 ∇f=(−1/2,−1/2):沿负梯度移动会增大 x+y,离开可行域。
拉格朗日函数与对偶下界
采用 ci≤0 的符号约定,分别给三个约束配上非负乘子 λ,μ,ν。按 Boyd 与 Vandenberghe,§§5.1.1–5.1.3,构造
L(x,y,λ,μ,ν)=f(x,y)+λ(x+y−2)−μx−νy.
对固定乘子,对偶函数取 L 在变量定义域上的下确界:
g(λ,μ,ν)=(x,y)∈R2infL(x,y,λ,μ,ν).
这里要在整个 R2 上取下确界。三个不等式已放进 L,不能再把这个计算限制在三角形内。
L 关于 (x,y) 的 Hessian 仍为 I2。因此令偏导为零就能找到它唯一的全局最小点:
∂xL=x−2+λ−μ=0,∂yL=y−1+λ−ν=0,
即 xL=2−λ+μ、yL=1−λ+ν。配方后得到
Lg(λ,μ,ν)=21((x−xL)2+(y−yL)2)+g(λ,μ,ν),=λ−2μ−ν−21((λ−μ)2+(λ−ν)2).
对偶问题是最大化 g,约束为 λ,μ,ν≥0。本题 g 对所有有限乘子都有限。对任意可行 (x,y) 和非负乘子,
g(λ,μ,ν)≤L(x,y,λ,μ,ν)≤f(x,y).
第二个不等式来自“非负乘子 × 非正约束值”。记原问题最优值为 p∗、对偶最优值为 d∗=supλ,μ,ν≥0g,便有 d∗≤p∗。这叫弱对偶;上述不等式的证明不需要凸性。
算出乘子,检查四项 KKT
互补松弛要求每个乘子与相应约束值的乘积为零。由于候选点的 x∗,y∗>0,μ∗=ν∗=0。再代入驻点方程:
−21+λ∗=0⟹(λ∗,μ∗,ν∗)=(21,0,0).
教材 §5.5.3的四项 KKT 条件在本题中逐项如下:
| 条件 | 本题的计算 | 结果 |
|---|
| 原问题可行 | (c1,c2,c3)=(0,−3/2,−1/2) | 均不大于零 |
| 乘子非负 | (λ∗,μ∗,ν∗)=(1/2,0,0) | 乘子均非负 |
| 驻点条件 | ∇x,yL=(−1/2+1/2,−1/2+1/2) | (0,0) |
| 互补松弛 | (λ∗c1,μ∗c2,ν∗c3)=(0,0,0) | 全部为零 |
要给出有限的对偶下界,还须 g>−∞。本题自动满足这一点;但对一般问题,不能仅凭乘子非负就断定下界有限。
正乘子对应的约束一定活跃,非活跃约束的乘子一定为零;活跃约束却可以有零乘子。例如把本题的上限改为 3,无约束最小点 (2,1) 就落在 x+y=3 上,而所有乘子都为零。
在可微凸问题中,目标和不等式函数凸、等式约束仿射,满足 KKT 足以证明全局最优。本题还能把证书直接写成数值:
g(21,0,0)=21−(21)2=41=f(23,21).
任何可行点的目标都至少为 1/4,候选点恰好达到它,所以 p∗=d∗=1/4。平方项也给出同一结论:
f(x,y)−41=21((x−23)2+(y−21)2)+21(2−x−y)≥0((x,y)∈C).
等号只在 (3/2,1/2) 处成立。这证明了最优性和唯一性,而不必逐一搜索所有可行点。
用间隙衡量候选解
给定原问题可行点和对偶可行乘子,原始–对偶间隙为 f(x,y)−g(λ,μ,ν)。它给出候选解与最优值之间误差的上界:
0≤f(x,y)−p∗≤f(x,y)−g(λ,μ,ν).
下面各行都是可行的原始–对偶组合,但前两行的乘子还不是最优乘子。
| (x,y) | (λ,μ,ν) | f | g | f−g |
|---|
| (1,1) | (0,0,0) | 1/2 | 0 | 1/2 |
| (1,1) | (1/4,0,0) | 1/2 | 3/16 | 5/16 |
| (3/2,1/2) | (1/2,0,0) | 1/4 | 1/4 | 0 |
第二行给出 3/16≤p∗≤1/2,以及候选解误差至多 5/16=0.3125。它的实际误差是 1/2−1/4=1/4。某组候选值的正间隙,不等于最优值之间存在正的对偶间隙;本题的最优对偶间隙 p∗−d∗ 为零。
正则性与非凸性分别影响什么
凸问题的最优点可能没有 KKT 乘子
教材 §5.2.3 的 Slater 条件要求:凸问题在共同定义域的相对内部存在满足等式约束、且严格满足所有不等式的点。它保证强对偶;若最优值有限,还保证对偶最优值能由有限乘子取得。结合可微性,KKT 就成为最优性的必要且充分条件。对于仿射不等式,教材给出的放宽版本允许不取严格不等号。
本题 (1/2,1/2) 严格满足三个不等式,所以 Slater 条件成立。它保证最优证书存在;已经找到的凸问题 KKT 证书,其充分性本身不需要再假设 Slater。
考虑另一个凸问题:
x∈Rminxsubject tox2≤0.
唯一可行点为 x∗=0,p∗=0。不存在 x2<0 的点,Slater 条件失败。拉格朗日函数 L=x+λx2 的驻点方程为 1+2λx=0;在 x∗=0 处,任何有限乘子都无法使它成立。
当 λ>0,L 的最小点为 −1/(2λ),所以 g(λ)=−1/(4λ);λ=0 时 g(0)=−∞。因此 d∗=supλ≥0g(λ)=0=p∗,却没有取得该上确界的有限乘子。这个例子失败的是乘子存在性和 KKT 必要性;强对偶仍然成立。
非凸问题的 KKT 点可以是最大点
考虑
x∈Rmin−x2subject tox−1≤0,−x−1≤0.
可行域是 [−1,1],目标不是凸函数。在 x=0、两个乘子都为零时,原问题可行、乘子非负、梯度为零、互补松弛也成立,四项 KKT 全部通过。但 f(0)=0,而 f(−1)=f(1)=−1;这个 KKT 点是可行域上的严格最大点。
原因是 L=−x2 在零点的驻点并非全局最小点,infx∈RL=−∞。实际上,任何有限乘子都只能添加仿射项,无法改变向下开口的二次项,所以本题 d∗=−∞。弱对偶仍成立,却给不出有限下界。虽然 x=0 严格满足两个约束,Slater 的凸问题定理也不能用于这个非凸目标。
用 Python 复算
下面只用 Python 标准库的有理数运算。它检查已算出的点和乘子,复算间隙与两个反例;计算证书所需的全局下确界依据是上面的配方推导。
from fractions import Fraction as F
def objective(x, y):
return F(1, 2) * ((x - 2)**2 + (y - 1)**2)
def dual(lam, mu, nu):
return lam - 2*mu - nu - F(1, 2)*((lam-mu)**2 + (lam-nu)**2)
def vector(values):
return '(' + ', '.join(map(str, values)) + ')'
x, y = F(3, 2), F(1, 2)
lam, mu, nu = F(1, 2), F(0), F(0)
constraints = (x+y-2, -x, -y)
multipliers = (lam, mu, nu)
stationarity = (x-2+lam-mu, y-1+lam-nu)
kkt = (
all(c <= 0 for c in constraints),
all(m >= 0 for m in multipliers),
all(s == 0 for s in stationarity),
all(m*c == 0 for m, c in zip(multipliers, constraints)),
)
assert all(kkt)
print('x=' + vector((x, y)) + ', multipliers=' + vector(multipliers))
print('constraints=' + vector(constraints))
print('stationarity=' + vector(stationarity))
print('KKT=' + vector(kkt))
for label, a, b, l in [('candidate', F(1), F(1), F(1, 4)),
('optimum', x, y, lam)]:
p, d = objective(a, b), dual(l, F(0), F(0))
print(f'{label}: f={p}, g={d}, gap={p-d}')
for l in (F(1), F(10), F(100)):
z = -1/(2*l)
g = z + l*z*z
assert g == -1/(4*l)
print(f'degenerate: lambda={l}, x_min_L={z}, g={g}')
z = F(0)
nonconvex_constraints = (z-1, -z-1)
nonconvex_multipliers = (F(0), F(0))
nonconvex_kkt = (
all(c <= 0 for c in nonconvex_constraints),
all(m >= 0 for m in nonconvex_multipliers),
-2*z + nonconvex_multipliers[0] - nonconvex_multipliers[1] == 0,
all(m*c == 0 for m, c in zip(nonconvex_multipliers, nonconvex_constraints)),
)
print('nonconvex: KKT=' + vector(nonconvex_kkt)
+ f', f(0)={-z*z}, f(-1)=f(1)={-F(1)**2}')
实际输出:
x=(3/2, 1/2), multipliers=(1/2, 0, 0)
constraints=(0, -3/2, -1/2)
stationarity=(0, 0)
KKT=(True, True, True, True)
candidate: f=1/2, g=3/16, gap=5/16
optimum: f=1/4, g=1/4, gap=0
degenerate: lambda=1, x_min_L=-1/2, g=-1/4
degenerate: lambda=10, x_min_L=-1/20, g=-1/40
degenerate: lambda=100, x_min_L=-1/200, g=-1/400
nonconvex: KKT=(True, True, True, True), f(0)=0, f(-1)=f(1)=-1
若用求解器处理更大的二次规划,CVXPY 示例通过约束对象的 dual_value 读取乘子。要保持约束顺序和符号约定一致,再检查可行性、驻点残差、互补乘积,以及实际对偶函数给出的下界。小的驻点残差本身无法排除上面的非凸最大点。