【机器人感知运控笔记四】理解 IPOPT:原始—对偶内点法与二阶信息
本文主要针对了解数值优化、但主要集中在调库,不理解算法 原理的读者。(比如日常工作是定义一个带约束的优化问题进行求解,求解过程则全部交给优化器。)
本系列讲解了等式/不等式约束、罚函数、对数障碍,拉格朗日乘子法,约束最优性方程,KKT条件,对偶变量等概念,并以casadi和ipopt为例,讲解它如何把不等式约束转为等式约束并进行求解的过程。因此,如果想深入了解,可以阅读本文。
但是,读者需要能留出至少数个小时来阅读本文,否则心急的情况下确实是很难很快理解消化本文的内容。
本系列内容分为两章:
第一节见:【机器人感知运控笔记三】约束优化基础:从简单问题到拉格朗日乘子与 KKT 条件
包含机器人 案例引言及第 1—7 节:牛顿法回顾、消元、平方罚函数、对数障碍、乘子与互补条件。
第二节是本章:
理解 IPOPT:原始—对偶内点法与二阶信息
包含第 8—14 节:松弛变量、最优性方程、联合牛顿步骤、障碍参数更新、Hessian 接口与导数检查。
如果读完觉得不错,欢迎关注我的专栏:
机器人感知运控笔记-微鉴道长的专栏
注意:以下内容在开始前,必须先阅读前一章内容!! CSDN字数的限制使我无法把这两节合并为一节,拆分成两节是有阅读困难的。。
8. 把障碍子问题写成一组方程
第 5 节已经给出了一种直接的求解方式。对贯穿全文的一维例子,固定 μ > 0 \mu>0 μ>0 后,只需要求解:
min x < 1 ( x − 2 ) 2 − μ log ( 1 − x ) . \min_{x<1}(x-2)^2-\mu\log(1-x). x<1min(x−2)2−μlog(1−x).
这个例子可以直接求导,也容易找到满足 x < 1 x<1 x<1 的初值。增加变量和乘子会增加计算步骤,一维例子采用上面的写法已经很方便。
当问题包含很多变量和约束时,求解器还需要处理几个实际问题:初值可能违反部分约束;受到约束限制的最优点,目标梯度可能仍然非零;每次更新变量时,需要同时考虑目标和各条约束的影响。
本章介绍的写法为这些计算提供了一套统一的组织方式:用松弛变量单独表示约束余量,用乘子表达约束在梯度平衡中的作用,再把两者与原变量一起求解。 辅助量会增加未知数,也会提供明确的方程结构,供求解器计算每一轮的联合修正。
下面仍用 f ( x ) = ( x − 2 ) 2 f(x)=(x-2)^2 f(x)=(x−2)2、 g ( x ) = x − 1 ≤ 0 g(x)=x-1\leq0 g(x)=x−1≤0 这个例子,先说明每个辅助量的用途,再展开推导,最后介绍这套结构怎样用于多变量、多约束问题。
8.1 把余量列为变量,并用等式把它与 x 联系起来
原约束要求 x ≤ 1 x\leq1 x≤1。当 x = 0.8 x=0.8 x=0.8 时,约束函数值为 g ( x ) = − 0.2 g(x)=-0.2 g(x)=−0.2,到边界还剩 0.2 0.2 0.2。因此,本例的余量等于 1 − x = − g ( x ) 1-x=-g(x) 1−x=−g(x)。
第 5 节用 t = 1 − x t=1-x t=1−x 简写这个余量。现在把 t t t 单独列为一个待求解的变量,同时用等式规定它与 x x x 的关系:
x − 1 + t = 0 , t ≥ 0. x-1+t=0,\qquad t\geq0. x−1+t=0,t≥0.
这个 t t t 称为松弛变量。等式要求 t = 1 − x t=1-x t=1−x,非负要求又保证 x ≤ 1 x\leq1 x≤1,所以改写前后允许的 x x x 完全相同。例如, x = 0.8 x=0.8 x=0.8 可以配上 t = 0.2 t=0.2 t=0.2; x = 1.2 x=1.2 x=1.2 则要求 t = − 0.2 t=-0.2 t=−0.2,仍然不符合条件。
用 g g g 表示,新增的等式就是 g ( x ) + t = 0 g(x)+t=0 g(x)+t=0。这里的 g g g 仍是原来的约束函数, t t t 是额外引入的变量。对一般不等式 g i ( x ) ≤ 0 g_i(x)\leq0 gi(x)≤0,也可以这样写:
g i ( x ) + t i = 0 , t i ≥ 0. g_i(x)+t_i=0,\qquad t_i\geq0. gi(x)+ti=0,ti≥0.
t i t_i ti 统一称为约束余量。只有在本例这样的特定表达式中,它才恰好等于几何距离。
接着,用第 5 节的对数障碍处理 t ≥ 0 t\geq0 t≥0。固定 μ > 0 \mu>0 μ>0 后,得到:
min x , t ( x − 2 ) 2 − μ log t , x − 1 + t = 0 , t > 0. \min_{x,t}(x-2)^2-\mu\log t, \qquad x-1+t=0,\quad t>0. x,tmin(x−2)2−μlogt,x−1+t=0,t>0.
等式成立时,把 t = 1 − x t=1-x t=1−x 代回目标,就恢复了第 5 节的 ( x − 2 ) 2 − μ log ( 1 − x ) (x-2)^2-\mu\log(1-x) (x−2)2−μlog(1−x)。保留 x , t x,t x,t 两个变量后,模型通过等式规定两者的关联;求解器在迭代过程中可以暂时允许等式有误差,再逐步修正。
这种处理允许算法从违反原约束的初值开始迭代。 假设初值为 x = 1.2 x=1.2 x=1.2,原目标和约束函数都能够计算: f ( 1.2 ) = 0.64 f(1.2)=0.64 f(1.2)=0.64、 g ( 1.2 ) = 0.2 g(1.2)=0.2 g(1.2)=0.2。直接使用障碍项时,需要计算 log ( 1 − 1.2 ) = log ( − 0.2 ) \log(1-1.2)=\log(-0.2) log(1−1.2)=log(−0.2),问题出在这个对数的定义域。
引入 t t t 后,求解器使用的目标变为 ( x − 2 ) 2 − μ log t (x-2)^2-\mu\log t (x−2)2−μlogt。保留 x = 1.2 x=1.2 x=1.2,给新增变量选一个正初值,例如 t = 0.1 t=0.1 t=0.1,就可以计算这个目标。这里的 0.1 是演示用的初值;只考虑对数的定义域,0.2 或 1 也可以。 初值的数值尺度会影响后续迭代。这个 t t t 初值无需与 μ \mu μ 相等:前者是待修正的变量,后者是障碍参数。当前关联等式的误差为:
x − 1 + t = 1.2 − 1 + 0.1 = 0.3. x-1+t=1.2-1+0.1=0.3. x−1+t=1.2−1+0.1=0.3.
求解器可以一边保持 t > 0 t>0 t>0,一边调整 x , t x,t x,t,让这项误差逐步接近零。当 x − 1 + t = 0 x-1+t=0 x−1+t=0 成立时, x = 1 − t < 1 x=1-t<1 x=1−t<1,原不等式也随之满足。这里,初始的 t = 0.1 t=0.1 t=0.1 是待修正的变量值;等式满足后,它才准确表示当前 x x x 到边界的余量。
对一般约束 g i ( x ) ≤ 0 g_i(x)\leq0 gi(x)≤0,这个计算安排也相同:先选正的 t i t_i ti,使 log t i \log t_i logti 可以计算,再修正 g i ( x ) + t i = 0 g_i(x)+t_i=0 gi(x)+ti=0。复杂的约束关系保留在等式中,对数的定义域要求统一变成简单的 t i > 0 t_i>0 ti>0。最终解仍然需要满足约束关系;增加 t i t_i ti 保留了原问题允许的 x x x 范围。
IPOPT 在初始化阶段就按确定的规则安排松弛变量。 它参考当前约束值,并根据内部的边界调整规则把松弛变量放到允许范围内部。之后通过步长控制保持其合法性。讲义中的 t = 0.1 t=0.1 t=0.1 用来说明这种安排,实际数值由求解器的规则与配置决定。这套过程在正式迭代前就已安排,初始化也只保证相关表达式可计算,问题能否达到可行解、能否收敛仍需继续求解。
实际建模时,应把原不等式及其边界交给 IPOPT,由它组织内部的障碍处理。如果自行把 log ( 1 − x ) \log(1-x) log(1−x) 写进目标,求解器会按这个表达式求值;在 x = 1.2 x=1.2 x=1.2 处仍可能发生求值错误。模型中 f , g f,g f,g 自身的定义域也需要满足。讲义用 g ( x ) + t = 0 g(x)+t=0 g(x)+t=0、 t > 0 t>0 t>0 统一说明数学关系,求解器内部可以使用不同的松弛变量符号和边界表示。
8.2 用乘子表达约束的作用,建立联合求解条件
有了余量变量,我们能够检查约束关系是否满足。接下来还需要判断目标是否已经达到约束允许的最优位置。第 7 节用乘子表达梯度平衡,现在把同样的方法用于固定 μ \mu μ 的障碍子问题。
这里会同时求原始变量 x , t x,t x,t 与相应的乘子。 t t t 的加入没有改变乘子的含义:它们仍然表达约束梯度怎样参与最优性条件。
现在需要处理等式 x − 1 + t = 0 x-1+t=0 x−1+t=0。沿用第 7 节的方法,为它引入一个乘子,暂时记为 y y y。等式本身不规定乘子的正负。障碍子问题的拉格朗日函数为:
L μ ( x , t , y ) = ( x − 2 ) 2 − μ log t + y ( x − 1 + t ) . \mathcal L_\mu(x,t,y) =(x-2)^2-\mu\log t+y(x-1+t). Lμ(x,t,y)=(x−2)2−μlogt+y(x−1+t).
此时 μ \mu μ 是已给定的数, x , t , y x,t,y x,t,y 是需要一起求出的未知量。我们用两条梯度平衡方程,加上关联等式,确定它们需要满足的关系。
先对 x x x 求偏导。 在多变量函数中,对 x x x 求偏导时把 t , y t,y t,y 固定: ( x − 2 ) 2 (x-2)^2 (x−2)2 的导数为 2 ( x − 2 ) 2(x-2) 2(x−2), − μ log t -\mu\log t −μlogt 的导数为零, y ( x − 1 + t ) y(x-1+t) y(x−1+t) 的导数为 y y y。因此:
∂ L μ ∂ x = 2 ( x − 2 ) + y = 0. \frac{\partial\mathcal L_\mu}{\partial x} =2(x-2)+y=0. ∂x∂Lμ=2(x−2)+y=0.
这里保留了 x , t x,t x,t 两个独立的变量位置;两者需要满足的关系会由 x − 1 + t = 0 x-1+t=0 x−1+t=0 同时保证。若先代入 t = 1 − x t=1-x t=1−x 消去 t t t,就回到了第 5 节直接对单变量障碍目标求导的做法。
再对 t t t 求偏导。 这次把 x , y x,y x,y 固定: ( x − 2 ) 2 (x-2)^2 (x−2)2 的导数为零, − μ log t -\mu\log t −μlogt 的导数为 − μ / t -\mu/t −μ/t, y ( x − 1 + t ) y(x-1+t) y(x−1+t) 的导数为 y y y。因此:
∂ L μ ∂ t = − μ t + y = 0 ⟹ t y = μ . \frac{\partial\mathcal L_\mu}{\partial t} =-\frac{\mu}{t}+y=0 \quad\Longrightarrow\quad ty=\mu. ∂t∂Lμ=−tμ+y=0⟹ty=μ.
因为 μ > 0 \mu>0 μ>0、 t > 0 t>0 t>0,满足这条方程时必有 y = μ / t > 0 y=\mu/t>0 y=μ/t>0。 y y y 的正号由关于 t t t 的方程推导出来;引入这个等式乘子时,我们没有预设它的符号。
最后,把原有的关联等式也放进来:
2 ( x − 2 ) + y = 0 , x − 1 + t = 0 , t y = μ . \begin{aligned} 2(x-2)+y&=0,\\ x-1+t&=0,\\ ty&=\mu. \end{aligned} 2(x−2)+yx−1+tty=0,=0,=μ.
这三条方程分别要求:目标与约束的梯度平衡,位置与余量对应,余量与乘子的乘积等于当前的 μ \mu μ。到这里,障碍子问题已经变成了一组需要同时满足的方程。
这一乘积关系适用于所有采用标准对数障碍的问题:固定 μ > 0 \mu>0 μ>0、满足一阶最优性条件时,每条不等式的余量与对应乘子的乘积都等于 μ \mu μ。该关系来自对数障碍项对余量变量的求导,与目标函数和约束函数的具体形式无关;迭代中的当前值可以尚未满足它。
8.3 对照原问题,明确 y 与 λ 的对应关系
上一步引入了 y y y,第 7 节使用的则是 λ \lambda λ。要理解两者的关系,可以比较它们在关于 x x x 的方程中分别乘在哪一项前面。
第 7 节原问题的拉格朗日函数为:
L ( x , λ ) = f ( x ) + λ g ( x ) . L(x,\lambda)=f(x)+\lambda g(x). L(x,λ)=f(x)+λg(x).
对 x x x 求偏导,得到:
f ′ ( x ) + λ g ′ ( x ) = 0. f'(x)+\lambda g'(x)=0. f′(x)+λg′(x)=0.
其中, λ \lambda λ 是原约束梯度 g ′ ( x ) g'(x) g′(x) 前面的系数。现在把障碍子问题的拉格朗日函数展开:
L μ ( x , t , y ) = f ( x ) − μ log t + y [ g ( x ) + t ] = f ( x ) + y g ( x ) + y t − μ log t . \begin{aligned} \mathcal L_\mu(x,t,y) &=f(x)-\mu\log t+y[g(x)+t]\\ &=f(x)+yg(x)+yt-\mu\log t. \end{aligned} Lμ(x,t,y)=f(x)−μlogt+y[g(x)+t]=f(x)+yg(x)+yt−μlogt.
对 x x x 求偏导时, t , y t,y t,y 固定,最后两项 y t − μ log t yt-\mu\log t yt−μlogt 的导数为零,所以得到:
f ′ ( x ) + y g ′ ( x ) = 0. f'(x)+y g'(x)=0. f′(x)+yg′(x)=0.
把两个结果放在一起:
f ′ ( x ) + λ g ′ ( x ) = 0 , f ′ ( x ) + y g ′ ( x ) = 0. \begin{aligned} f'(x)+\lambda g'(x)&=0,\\ f'(x)+y g'(x)&=0. \end{aligned} f′(x)+λg′(x)f′(x)+yg′(x)=0,=0.
λ \lambda λ 和 y y y 都是同一个约束梯度 g ′ ( x ) g'(x) g′(x) 前面的系数。 这就是两者在关于 x x x 的方程中承担相同作用的具体含义。在本例中, g ′ ( x ) = 1 g'(x)=1 g′(x)=1,两行分别就是 2 ( x − 2 ) + λ = 0 2(x-2)+\lambda=0 2(x−2)+λ=0 和 2 ( x − 2 ) + y = 0 2(x-2)+y=0 2(x−2)+y=0。
除了梯度平衡,还要比较它们与余量的关系。原问题的互补条件为 λ g ( x ) = 0 \lambda g(x)=0 λg(x)=0;代入 g ( x ) = − t g(x)=-t g(x)=−t,就得到 t λ = 0 t\lambda=0 tλ=0。障碍子问题给出的则是 t y = μ ty=\mu ty=μ,且 y > 0 y>0 y>0。随着 μ \mu μ 减小,乘积要求逐步接近原来的零互补条件。
因此,后文把障碍子问题中的 y y y 也记为 λ \lambda λ,保持它与原不等式的对应关系。这是对同一个未知量换用后文的统一名称。有限的 μ \mu μ 下,障碍子问题的解和乘子数值可以与原问题的最优解和乘子不同。
采用这个记号后,三条方程写成:
2 ( x − 2 ) + λ = 0 , x − 1 + t = 0 , t λ = μ , t > 0 , λ > 0. \begin{aligned} 2(x-2)+\lambda&=0,\\ x-1+t&=0,\\ t\lambda&=\mu, \end{aligned} \qquad t>0,\quad\lambda>0. 2(x−2)+λx−1+ttλ=0,=0,=μ,t>0,λ>0.
第三条称为扰动互补条件:“扰动”指原来的乘积要求 t λ = 0 t\lambda=0 tλ=0 被改为 t λ = μ t\lambda=\mu tλ=μ。它由上一步对 t t t 求偏导得到。
第 7.5 节的 ν \nu ν 继续用于原问题自带的等式 h ( x ) = 0 h(x)=0 h(x)=0。 ν \nu ν 与 λ \lambda λ 这两个名字按约束来源区分;这里写成等式的 g ( x ) + t = 0 g(x)+t=0 g(x)+t=0,仍对应原来的那条不等式。
8.4 代入当前数值,计算每条方程的误差
方程已经列出,接下来需要求出满足它们的数值。求解通常从一组初值开始,因此首先要检查:当前数值代进去以后,每条方程还差多少。
对一条方程,计算“左边减右边”,这个差值就叫残差。例如, t λ = μ t\lambda=\mu tλ=μ 的残差是 t λ − μ t\lambda-\mu tλ−μ。残差为零时,这条方程成立;残差的绝对值反映当前左右两边相差多少。
给三条方程的残差分别命名:
| 要满足的方程 | 残差的名称与表达式 | 检查的内容 |
|---|---|---|
| 2 ( x − 2 ) + λ = 0 2(x-2)+\lambda=0 2(x−2)+λ=0 | r d u a l = 2 ( x − 2 ) + λ r_{\mathrm{dual}}=2(x-2)+\lambda rdual=2(x−2)+λ | 梯度是否平衡 |
| x − 1 + t = 0 x-1+t=0 x−1+t=0 | r i n e q = x − 1 + t r_{\mathrm{ineq}}=x-1+t rineq=x−1+t | 余量是否与位置对应 |
| t λ = μ t\lambda=\mu tλ=μ | r c e n t = t λ − μ r_{\mathrm{cent}}=t\lambda-\mu rcent=tλ−μ | 乘积是否等于当前的 μ \mu μ |
这些 r r r 都由当前的 x , t , λ , μ x,t,\lambda,\mu x,t,λ,μ 计算得到。此处先按右侧的具体含义理解它们,后面再说明下标的来源。
例如,固定 μ = 0.1 \mu=0.1 μ=0.1,当前取 x = 0.8 x=0.8 x=0.8、 t = 0.2 t=0.2 t=0.2、 λ = 0.4 \lambda=0.4 λ=0.4。代入得到:
r d u a l = 2 ( 0.8 − 2 ) + 0.4 = − 2 , r i n e q = 0.8 − 1 + 0.2 = 0 , r c e n t = 0.2 × 0.4 − 0.1 = − 0.02. \begin{aligned} r_{\mathrm{dual}}&=2(0.8-2)+0.4=-2,\\ r_{\mathrm{ineq}}&=0.8-1+0.2=0,\\ r_{\mathrm{cent}}&=0.2\times0.4-0.1=-0.02. \end{aligned} rdualrineqrcent=2(0.8−2)+0.4=−2,=0.8−1+0.2=0,=0.2×0.4−0.1=−0.02.
第二行已经为零,说明余量与位置对应。第一行仍为 − 2 -2 −2,说明梯度还没有平衡。第三行的 − 0.02 -0.02 −0.02 表示:当前乘积为 0.08 0.08 0.08,比要求的 0.1 0.1 0.1 小了 0.02 0.02 0.02。
如果只看第三行,把 λ \lambda λ 从 0.4 0.4 0.4 改为 0.5 0.5 0.5 就能使它归零。但此时第一行等于 − 1.9 -1.9 −1.9,仍未满足梯度平衡。这说明,只修正一条方程还不够;需要联合调整 x , t , λ x,t,\lambda x,t,λ,让三条方程同时成立。
本例可以直接算出三条方程同时成立时的结果。第二行给出 x = 1 − t x=1-t x=1−t,代入第一行得到 λ = 2 ( 1 + t ) \lambda=2(1+t) λ=2(1+t),再代入第三行:
2 t ( 1 + t ) = 0.1. 2t(1+t)=0.1. 2t(1+t)=0.1.
取正根并依次求出 x , λ x,\lambda x,λ,得到:
t ≈ 0.047722558 , x ≈ 0.952277442 , λ ≈ 2.095445115. t\approx0.047722558,\qquad x\approx0.952277442,\qquad \lambda\approx2.095445115. t≈0.047722558,x≈0.952277442,λ≈2.095445115.
这一组数值使三项残差都接近零,其中的 x x x 与第 5.2 节直接求障碍目标最小值得到的结果一致。这里 μ = 0.1 \mu=0.1 μ=0.1 对应的解仍留有正余量;原问题的最优点 x = 1 x=1 x=1 则位于边界上。
8.5 多条不等式各自对应一项乘积残差
前面只有一条不等式,因此 r c e n t r_{\mathrm{cent}} rcent 是一个数。如果有 m m m 条不等式,第 i i i 条有自己的余量 t i t_i ti 和乘子 λ i \lambda_i λi,各自需要满足 t i λ i = μ t_i\lambda_i=\mu tiλi=μ。
把每条方程的残差按顺序放在一起,就得到向量:
r c e n t = [ t 1 λ 1 − μ t 2 λ 2 − μ ⋮ t m λ m − μ ] . r_{\mathrm{cent}}= \begin{bmatrix} t_1\lambda_1-\mu\\ t_2\lambda_2-\mu\\ \vdots\\ t_m\lambda_m-\mu \end{bmatrix}. rcent= t1λ1−μt2λ2−μ⋮tmλm−μ .
这个向量有 m m m 个分量,每个分量计算同一条约束的“余量 × 乘子 − μ”。 例如,两条约束当前有 t = ( 0.2 , 0.1 ) T t=(0.2,0.1)^T t=(0.2,0.1)T、 λ = ( 0.4 , 1.5 ) T \lambda=(0.4,1.5)^T λ=(0.4,1.5)T,且 μ = 0.1 \mu=0.1 μ=0.1,则:
r c e n t = [ 0.2 × 0.4 − 0.1 0.1 × 1.5 − 0.1 ] = [ − 0.02 0.05 ] . r_{\mathrm{cent}}= \begin{bmatrix} 0.2\times0.4-0.1\\ 0.1\times1.5-0.1 \end{bmatrix} =\begin{bmatrix}-0.02\\0.05\end{bmatrix}. rcent=[0.2×0.4−0.10.1×1.5−0.1]=[−0.020.05].
第一个乘积比要求小 0.02 0.02 0.02,第二个乘积比要求大 0.05 0.05 0.05。向量保留了每条约束各自的误差。
为了简写,定义 T = diag ( t 1 , … , t m ) T=\operatorname{diag}(t_1,\ldots,t_m) T=diag(t1,…,tm):对角线上放各个 t i t_i ti,其余位置为零。再用 1 \mathbf1 1 表示长度为 m m m 的全 1 向量。于是:
T λ = [ t 1 λ 1 ⋮ t m λ m ] , μ 1 = [ μ ⋮ μ ] . T\lambda= \begin{bmatrix}t_1\lambda_1\\\vdots\\t_m\lambda_m\end{bmatrix}, \qquad \mu\mathbf1= \begin{bmatrix}\mu\\\vdots\\\mu\end{bmatrix}. Tλ= t1λ1⋮tmλm ,μ1= μ⋮μ .
两者相减,得到同一个残差向量的紧凑写法:
r c e n t = T λ − μ 1. r_{\mathrm{cent}}=T\lambda-\mu\mathbf1. rcent=Tλ−μ1.
下标 cent 来自 centrality,表示中心性。第 5.2 节把不同
μ
\mu
μ 下的障碍子问题解连成中心路径;路径上的解满足梯度平衡、约束关系和
t
i
λ
i
=
μ
t_i\lambda_i=\mu
tiλi=μ。
r
c
e
n
t
r_{\mathrm{cent}}
rcent 专门检查最后一项。它为零时,仍需检查其余方程,才能判断当前值是否满足整组条件。
8.6 加入原始等式,得到一般问题的四组残差
现在把一维例子推广到一般问题: x x x 可以包含多个变量,约束中既有不等式 g ( x ) ≤ 0 g(x)\leq0 g(x)≤0,也有原始等式 h ( x ) = 0 h(x)=0 h(x)=0。不等式继续引入余量 t t t 和乘子 λ \lambda λ,原始等式的乘子记为 ν \nu ν。障碍子问题的拉格朗日函数为:
L μ ( x , t , ν , λ ) = f ( x ) − μ ∑ i log t i + ν T h ( x ) + λ T [ g ( x ) + t ] . \mathcal L_\mu(x,t,\nu,\lambda) =f(x)-\mu\sum_i\log t_i +\nu^Th(x)+\lambda^T[g(x)+t]. Lμ(x,t,ν,λ)=f(x)−μi∑logti+νTh(x)+λT[g(x)+t].
前面关于 x x x 的方程只包含一个导数。现在需要对 x x x 的各个分量求偏导,并把所有约束的贡献加起来。用 J h , J g J_h,J_g Jh,Jg 表示约束的 Jacobian,每一行是一条约束对各个变量的导数,则:
J h ( x ) T ν = ∑ j ν j ∇ h j ( x ) , J g ( x ) T λ = ∑ i λ i ∇ g i ( x ) . \begin{aligned} J_h(x)^T\nu&=\sum_j\nu_j\nabla h_j(x),\\ J_g(x)^T\lambda&=\sum_i\lambda_i\nabla g_i(x). \end{aligned} Jh(x)TνJg(x)Tλ=j∑νj∇hj(x),=i∑λi∇gi(x).
这些矩阵乘法表示:每条约束的梯度乘上自己的乘子,再求和。因此,梯度平衡残差也沿用前面的结构;原始等式另外增加一组残差 h ( x ) h(x) h(x)。四组残差合起来为:
r d u a l = ∇ f ( x ) + J h ( x ) T ν + J g ( x ) T λ , r e q = h ( x ) , r i n e q = g ( x ) + t , r c e n t = T λ − μ 1. \begin{aligned} r_{\mathrm{dual}}&=\nabla f(x)+J_h(x)^T\nu+J_g(x)^T\lambda,\\ r_{\mathrm{eq}}&=h(x),\\ r_{\mathrm{ineq}}&=g(x)+t,\\ r_{\mathrm{cent}}&=T\lambda-\mu\mathbf1. \end{aligned} rdualreqrineqrcent=∇f(x)+Jh(x)Tν+Jg(x)Tλ,=h(x),=g(x)+t,=Tλ−μ1.
它们依次检查:梯度平衡、原始等式、余量与约束值的关联、余量与乘子的乘积。与一维例子相比,新增了原始等式这一组,其余三组的计算含义保持相同。
这里可以补全下标的含义:eq 对应原始等式;ineq 对应原不等式的来源,具体计算的是改写后的等式误差
g
(
x
)
+
t
g(x)+t
g(x)+t;dual 是梯度平衡残差的惯用名称。对应第 7.6 节的术语,扩展模型中的
x
,
t
x,t
x,t 是原始变量,乘子
ν
,
λ
\nu,\lambda
ν,λ 是对偶变量。
8.7 根据残差修正变量,再逐步调整 μ
回到第 8.4 节的数值例子:算法从一组 x , t , λ x,t,\lambda x,t,λ 出发,算出了 ( − 2 , 0 , − 0.02 ) (-2,0,-0.02) (−2,0,−0.02) 这三个残差。它已经知道哪些方程还没满足,接下来需要确定变量应该各自改变多少。
牛顿法可以把这些方程在当前点附近线性化,再求解一个线性方程组,得到联合修正方向:
Δ x , Δ t , Δ λ . \Delta x,\qquad\Delta t,\qquad\Delta\lambda. Δx,Δt,Δλ.
Δ x \Delta x Δx 表示原变量的修正方向,另外两项分别表示余量与乘子的修正方向。三个方向由同一组方程共同确定,因此约束关系、梯度平衡和乘积要求都会参与计算 Δ x \Delta x Δx。求解器选取步长并更新这些量,随后重新计算残差。对一般问题,还需要一起计算原始等式乘子的修正方向 Δ ν \Delta\nu Δν。
保留这些辅助未知量,也便于利用大型问题中的稀疏结构。 如果一条约束只涉及部分变量,那么它对其余变量的偏导为零。每个 t i t_i ti 又只出现在自己的关联等式和乘积方程中。把这些关系组织成线性方程组后,可以用稀疏矩阵保存非零项,并利用稀疏线性求解器计算修正方向。
这解释了增加未知量的计算价值:求解器获得了约束与变量之间的明确关联,可以利用这种结构组织存储和计算。代价是方程组变大,实际速度取决于问题规模、稀疏性和实现方式。一维例子适合直接代入求导;大型问题则可以利用联合方程的结构处理多条约束。
IPOPT 采用原始—对偶内点法,把障碍处理与上述联合更新结合起来,并保持松弛变量和对应的不等式乘子为正。第 8.1 节中 x = 1.2 , t = 0.1 x=1.2,t=0.1 x=1.2,t=0.1 的例子说明了这种迭代允许的中间状态:对数可以计算,原约束和关联等式的误差还需要继续修正。
固定正的 μ \mu μ 时,四组残差都接近零,表示接近当前障碍子问题的一阶最优性条件。当前子问题要求 t i λ i = μ t_i\lambda_i=\mu tiλi=μ。
原问题的互补条件写为 λ i g i ( x ) = 0 \lambda_i g_i(x)=0 λigi(x)=0。引入余量后,关联等式 g i ( x ) + t i = 0 g_i(x)+t_i=0 gi(x)+ti=0 成立时,有 g i ( x ) = − t i g_i(x)=-t_i gi(x)=−ti,因此可以等价改写为:
λ i g i ( x ) = 0 ⟺ − λ i t i = 0 ⟺ t i λ i = 0. \lambda_i g_i(x)=0 \quad\Longleftrightarrow\quad -\lambda_i t_i=0 \quad\Longleftrightarrow\quad t_i\lambda_i=0. λigi(x)=0⟺−λiti=0⟺tiλi=0.
这里用到了引入松弛变量时规定的关联关系。迭代中若 g i ( x ) + t i g_i(x)+t_i gi(x)+ti 还有误差, t i t_i ti 与 − g i ( x ) -g_i(x) −gi(x) 就尚未完全对应。因此,求解器逐步减小 μ \mu μ,并继续调整变量和乘子,在减小关联等式误差的同时,让 t i λ i t_i\lambda_i tiλi 逐渐接近零。
进入下一节前,可以按作用整理已经出现的量:
| 量 | 表达的内容 | 求解过程中怎样变化 |
|---|---|---|
| x x x | 原模型需要的结果 | 与辅助变量一起迭代更新 |
| t t t | 每条不等式的余量 | 保持为正,并逐步与约束值对应 |
| λ , ν \lambda,\nu λ,ν | 约束梯度参与平衡的系数 | 随最优性方程一起求出 |
| μ \mu μ | 当前障碍子问题的参数 | 由障碍参数策略调整 |
| α \alpha α | 一次迭代采用的步长系数 | 根据合法范围和迭代进展选择 |
后面两章分别处理两个计算环节:第 9 节讨论给定 μ \mu μ 时怎样求联合修正方向;第 10 节讨论何时更新 μ \mu μ、选取多大的值。实际求解中, μ \mu μ 的更新可以与变量迭代交替进行。
9. 用牛顿法求解约束最优性方程
上一节已经明确了各个未知量的含义,以及它们需要满足的方程。现在可以使用熟悉的牛顿法计算修正量,只是需要一起更新的量增加了。
固定 μ \mu μ,用 z z z 收集原始变量与乘子,用 R ( z ) R(z) R(z) 收集相应的残差。希望求出的状态满足 R ( z ) = 0 R(z)=0 R(z)=0。在当前点附近做一阶展开:
R ( z + Δ z ) ≈ R ( z ) + J R ( z ) Δ z . R(z+\Delta z)\approx R(z)+J_R(z)\Delta z. R(z+Δz)≈R(z)+JR(z)Δz.
这里的 z z z 表示当前迭代点,我们希望新位置的真实残差 R ( z + Δ z ) R(z+\Delta z) R(z+Δz) 为零。牛顿法先用右侧的线性展开预测这个残差,令预测值为零,求出本轮修正量,再到新位置重新检查真实残差。由此得到需要求解的线性方程:
J R ( z ) Δ z = − R ( z ) . J_R(z)\Delta z=-R(z). JR(z)Δz=−R(z).
这里的 J R J_R JR 是残差对全部未知量的 Jacobian。它包含每条方程对变量和乘子的导数。求出 Δ z \Delta z Δz 后,还需要选择步长、检查新点,再决定本轮采用多大的修正。下面先用已经熟悉的一维例子写出这个矩阵,再推广到一般问题,最后解释其中的二阶信息。
9.1 从一维例子的三条残差写出联合方程
沿用第 8 节的一维例子。固定 μ \mu μ,需要同时满足的三条条件及其残差为:
r d u a l = 2 ( x − 2 ) + λ , r i n e q = x − 1 + t , r c e n t = t λ − μ . \begin{aligned} r_{\mathrm{dual}}&=2(x-2)+\lambda,\\ r_{\mathrm{ineq}}&=x-1+t,\\ r_{\mathrm{cent}}&=t\lambda-\mu. \end{aligned} rdualrineqrcent=2(x−2)+λ,=x−1+t,=tλ−μ.
当前的 x , t , λ x,t,\lambda x,t,λ 已经有数值,右侧残差也能够计算。本轮要决定的是它们的修正量 Δ x , Δ t , Δ λ \Delta x,\Delta t,\Delta\lambda Δx,Δt,Δλ。分别查看修正后每条残差会怎样变化。
梯度平衡这一行对 x x x 的导数为 2,对 λ \lambda λ 的导数为 1,因此修正后的值为:
2 ( x + Δ x − 2 ) + ( λ + Δ λ ) = r d u a l + 2 Δ x + Δ λ . 2(x+\Delta x-2)+(\lambda+\Delta\lambda) =r_{\mathrm{dual}}+2\Delta x+\Delta\lambda. 2(x+Δx−2)+(λ+Δλ)=rdual+2Δx+Δλ.
让它为零,得到 2 Δ x + Δ λ = − r d u a l 2\Delta x+\Delta\lambda=-r_{\mathrm{dual}} 2Δx+Δλ=−rdual。
余量关联这一行同样是线性的。修正后的值为:
( x + Δ x ) − 1 + ( t + Δ t ) = r i n e q + Δ x + Δ t . (x+\Delta x)-1+(t+\Delta t) =r_{\mathrm{ineq}}+\Delta x+\Delta t. (x+Δx)−1+(t+Δt)=rineq+Δx+Δt.
让它为零,得到 Δ x + Δ t = − r i n e q \Delta x+\Delta t=-r_{\mathrm{ineq}} Δx+Δt=−rineq。
乘积条件这一行包含两个未知量的乘积。展开后得到:
( t + Δ t ) ( λ + Δ λ ) − μ = r c e n t + t Δ λ + λ Δ t + Δ t Δ λ . \begin{aligned} (t+\Delta t)(\lambda+\Delta\lambda)-\mu &=r_{\mathrm{cent}}+t\Delta\lambda+\lambda\Delta t\\ &\quad+\Delta t\Delta\lambda. \end{aligned} (t+Δt)(λ+Δλ)−μ=rcent+tΔλ+λΔt+ΔtΔλ.
牛顿法的一阶近似省略最后的二阶项 Δ t Δ λ \Delta t\Delta\lambda ΔtΔλ。令线性预测值为零,得到 t Δ λ + λ Δ t = − r c e n t t\Delta\lambda+\lambda\Delta t=-r_{\mathrm{cent}} tΔλ+λΔt=−rcent。这也说明,走到新位置后仍需要重新检查真实残差。
现在把三行按同一个变量顺序排列。列依次对应 Δ x , Δ λ , Δ t \Delta x,\Delta\lambda,\Delta t Δx,Δλ,Δt,便得到联合线性方程组:
[ 2 1 0 1 0 1 0 t λ ] [ Δ x Δ λ Δ t ] = − [ r d u a l r i n e q r c e n t ] . \begin{bmatrix} 2&1&0\\ 1&0&1\\ 0&t&\lambda \end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\lambda\\\Delta t\end{bmatrix} =- \begin{bmatrix} r_{\mathrm{dual}}\\r_{\mathrm{ineq}}\\r_{\mathrm{cent}} \end{bmatrix}. 21010t01λ ΔxΔλΔt =− rdualrineqrcent .
矩阵的每一行对应一条条件,每一列对应一个量的修正。 例如,第一行第三列为零,因为梯度平衡式不直接含 t t t;第三行第二列为 t t t,因为乘积 t λ t\lambda tλ 对 λ \lambda λ 的偏导为 t t t。
求解这个方程组,就能同时得到三种修正量。左上角的 2 来自目标函数的二阶导数;本例的约束是线性的,其二阶导数为零。一般问题会把这个位置扩展成矩阵,下面先看它在完整方程中的位置。
9.2 多变量、多约束的联合矩阵
上一节已经把三条标量方程排成矩阵。多个变量与约束沿用同样的过程:先写出每条修正方程,再按统一的未知量顺序收集系数。 其中一些系数会组成一个矩阵块。下面先把这些块展开成具体数字,再看一般写法。
本节所有系数和残差都在当前迭代点计算。在一次线性求解中,它们是已知量,要解的是各个 Δ \Delta Δ 修正量。更新到新点后,再重新计算系数和残差。
先用两个变量、一条等式写出完整矩阵。 复用第 3 节的例子,把变量记为 x 1 , x 2 x_1,x_2 x1,x2:
min x 1 , x 2 ( x 1 − 2 ) 2 + x 2 2 , h ( x ) = x 1 + x 2 − 1 = 0. \min_{x_1,x_2}(x_1-2)^2+x_2^2, \qquad h(x)=x_1+x_2-1=0. x1,x2min(x1−2)2+x22,h(x)=x1+x2−1=0.
给等式配上乘子 ν \nu ν,拉格朗日函数为:
L ( x 1 , x 2 , ν ) = ( x 1 − 2 ) 2 + x 2 2 + ν ( x 1 + x 2 − 1 ) . L(x_1,x_2,\nu) =(x_1-2)^2+x_2^2+\nu(x_1+x_2-1). L(x1,x2,ν)=(x1−2)2+x22+ν(x1+x2−1).
对 x 1 , x 2 x_1,x_2 x1,x2 分别求偏导,得到两条梯度平衡方程,再加上等式本身。一共有三项残差:
r d u a l , 1 = 2 ( x 1 − 2 ) + ν , r d u a l , 2 = 2 x 2 + ν , r e q = x 1 + x 2 − 1. \begin{aligned} r_{\mathrm{dual},1}&=2(x_1-2)+\nu,\\ r_{\mathrm{dual},2}&=2x_2+\nu,\\ r_{\mathrm{eq}}&=x_1+x_2-1. \end{aligned} rdual,1rdual,2req=2(x1−2)+ν,=2x2+ν,=x1+x2−1.
现在分别修正 x 1 , x 2 , ν x_1,x_2,\nu x1,x2,ν。第一条残差随 x 1 x_1 x1 改变的系数为 2,随 ν \nu ν 改变的系数为 1;其余两行同理。让修正后的线性预测值为零,就得到:
2 Δ x 1 + Δ ν = − r d u a l , 1 , 2 Δ x 2 + Δ ν = − r d u a l , 2 , Δ x 1 + Δ x 2 = − r e q . \begin{aligned} 2\Delta x_1+\Delta\nu&=-r_{\mathrm{dual},1},\\ 2\Delta x_2+\Delta\nu&=-r_{\mathrm{dual},2},\\ \Delta x_1+\Delta x_2&=-r_{\mathrm{eq}}. \end{aligned} 2Δx1+Δν2Δx2+ΔνΔx1+Δx2=−rdual,1,=−rdual,2,=−req.
列顺序固定为 Δ x 1 , Δ x 2 , Δ ν \Delta x_1,\Delta x_2,\Delta\nu Δx1,Δx2,Δν。第一行的系数依次是 2 , 0 , 1 2,0,1 2,0,1,第二行是 0 , 2 , 1 0,2,1 0,2,1,第三行是 1 , 1 , 0 1,1,0 1,1,0,于是:
[ 2 0 1 0 2 1 1 1 0 ] [ Δ x 1 Δ x 2 Δ ν ] = − [ r d u a l , 1 r d u a l , 2 r e q ] . \begin{bmatrix} 2&0&1\\ 0&2&1\\ 1&1&0 \end{bmatrix} \begin{bmatrix}\Delta x_1\\\Delta x_2\\\Delta\nu\end{bmatrix} =- \begin{bmatrix}r_{\mathrm{dual},1}\\r_{\mathrm{dual},2}\\r_{\mathrm{eq}}\end{bmatrix}. 201021110 Δx1Δx2Δν =− rdual,1rdual,2req .
例如,从 x 1 = x 2 = 0 , ν = 0 x_1=x_2=0,\nu=0 x1=x2=0,ν=0 出发,右侧为 ( 4 , 0 , 1 ) T (4,0,1)^T (4,0,1)T。求解得到 Δ x 1 = 1.5 \Delta x_1=1.5 Δx1=1.5、 Δ x 2 = − 0.5 \Delta x_2=-0.5 Δx2=−0.5、 Δ ν = 1 \Delta\nu=1 Δν=1。本例的残差展开没有被省略的高阶项,因此采用这组完整修正后,三条方程恰好同时成立。
把同类变量放在一起,就得到分块写法。 将 Δ x 1 , Δ x 2 \Delta x_1,\Delta x_2 Δx1,Δx2 收集成向量 Δ x \Delta x Δx,把前两项残差收集成 r d u a l r_{\mathrm{dual}} rdual。上面矩阵中的系数可以分成四块:
W = [ 2 0 0 2 ] , A = J h ( x ) = [ 1 1 ] , A T = [ 1 1 ] . W=\begin{bmatrix}2&0\\0&2\end{bmatrix},\qquad A=J_h(x)=\begin{bmatrix}1&1\end{bmatrix},\qquad A^T=\begin{bmatrix}1\\1\end{bmatrix}. W=[2002],A=Jh(x)=[11],AT=[11].
因此,同一个 3 × 3 3\times3 3×3 方程组可以写为:
[ W A T A 0 ] [ Δ x Δ ν ] = − [ r d u a l r e q ] . \begin{bmatrix} W&A^T\\ A&0 \end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\nu\end{bmatrix} =- \begin{bmatrix}r_{\mathrm{dual}}\\r_{\mathrm{eq}}\end{bmatrix}. [WAAT0][ΔxΔν]=−[rdualreq].
这里第一块行包含两条梯度平衡方程,第二块行包含一条等式方程。 W W W 是 2 × 2 2\times2 2×2 的矩阵, A T A^T AT 是 2 × 1 2\times1 2×1 的列向量, A A A 是 1 × 2 1\times2 1×2 的行向量,右下角的零在本例中只有一个元素。
A A A 与 A T A^T AT 的位置可以直接从前面的三条方程核对。变量变化使等式误差改变 Δ x 1 + Δ x 2 = A Δ x \Delta x_1+\Delta x_2=A\Delta x Δx1+Δx2=AΔx。乘子变化则分别给两条梯度平衡式增加一个 Δ ν \Delta\nu Δν,合起来就是 A T Δ ν A^T\Delta\nu ATΔν。等式 h ( x ) h(x) h(x) 本身不依赖 ν \nu ν,所以右下角为零。
一般问题也具有这个结构。 A = J h ( x ) A=J_h(x) A=Jh(x) 的每一行是一条等式对各变量的导数,因此 A Δ x A\Delta x AΔx 计算约束值的线性变化;梯度平衡中各个等式乘子的贡献为 A T ν A^T\nu ATν,因此改变乘子时会出现 A T Δ ν A^T\Delta\nu ATΔν。 W W W 则记录固定当前乘子时,梯度平衡对 x x x 的导数,具体组成在第 9.3 节展开。
加入不等式后,先写出四组修正方程。 现在原问题同时包含 h ( x ) = 0 h(x)=0 h(x)=0 和 g ( x ) ≤ 0 g(x)\leq0 g(x)≤0,需要一起修正 x , ν , λ , t x,\nu,\lambda,t x,ν,λ,t。沿用第 8 节的残差,并记 A = J h ( x ) A=J_h(x) A=Jh(x)、 G = J g ( x ) G=J_g(x) G=Jg(x)。
第一组是梯度平衡。改变 x x x 产生的线性变化记为 W Δ x W\Delta x WΔx;改变两类乘子,分别产生 A T Δ ν A^T\Delta\nu ATΔν 和 G T Δ λ G^T\Delta\lambda GTΔλ。所以这一组方程为:
W Δ x + A T Δ ν + G T Δ λ = − r d u a l . W\Delta x+A^T\Delta\nu+G^T\Delta\lambda =-r_{\mathrm{dual}}. WΔx+ATΔν+GTΔλ=−rdual.
这里 W W W 已经包含约束梯度随 x x x 变化的影响。 G T G^T GT 的来源与前面 A T A^T AT 相同:每条不等式的乘子乘在自己的约束梯度前面。
第二组是原始等式。它只依赖 x x x,因此:
A Δ x = − r e q . A\Delta x=-r_{\mathrm{eq}}. AΔx=−req.
第三组是余量关联等式 g ( x ) + t = 0 g(x)+t=0 g(x)+t=0。改变 x x x 给出 G Δ x G\Delta x GΔx,改变 t t t 则直接增加 Δ t \Delta t Δt,因此:
G Δ x + Δ t = − r i n e q . G\Delta x+\Delta t=-r_{\mathrm{ineq}}. GΔx+Δt=−rineq.
第四组是乘积条件。第 i i i 条的线性变化为 t i Δ λ i + λ i Δ t i t_i\Delta\lambda_i+\lambda_i\Delta t_i tiΔλi+λiΔti。定义 T = diag ( t ) T=\operatorname{diag}(t) T=diag(t)、 Λ = diag ( λ ) \Lambda=\operatorname{diag}(\lambda) Λ=diag(λ),把这些逐项乘积排列起来,就得到:
T Δ λ + Λ Δ t = − r c e n t . T\Delta\lambda+\Lambda\Delta t=-r_{\mathrm{cent}}. TΔλ+ΛΔt=−rcent.
四组方程已经分别写出,接下来只需收集系数。把列顺序统一为 Δ x , Δ ν , Δ λ , Δ t \Delta x,\Delta\nu,\Delta\lambda,\Delta t Δx,Δν,Δλ,Δt:
| 对应的方程 | Δ x \Delta x Δx 前的系数 | Δ ν \Delta\nu Δν 前的系数 | Δ λ \Delta\lambda Δλ 前的系数 | Δ t \Delta t Δt 前的系数 |
|---|---|---|---|---|
| 梯度平衡 | W W W | A T A^T AT | G T G^T GT | 0 0 0 |
| 原始等式 | A A A | 0 0 0 | 0 0 0 | 0 0 0 |
| 余量关联 | G G G | 0 0 0 | 0 0 0 | I I I |
| 乘积条件 | 0 0 0 | 0 0 0 | T T T | Λ \Lambda Λ |
表中的零块表示该行没有直接依赖相应的修正量。第三行最后一格为 I I I,因为单位矩阵满足 I Δ t = Δ t I\Delta t=\Delta t IΔt=Δt。第四行只使用 Δ λ , Δ t \Delta\lambda,\Delta t Δλ,Δt,因为我们把 t t t 作为独立变量,各项 t i λ i t_i\lambda_i tiλi 对 x x x 的直接偏导为零; x x x 与 t t t 的联系由第三行负责。
将系数表与各行右侧的负残差放在一起,得到完整矩阵形式:
[ W A T G T 0 A 0 0 0 G 0 0 I 0 0 T Λ ] [ Δ x Δ ν Δ λ Δ t ] = − [ r d u a l r e q r i n e q r c e n t ] . \begin{bmatrix} W&A^T&G^T&0\\ A&0&0&0\\ G&0&0&I\\ 0&0&T&\Lambda \end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\nu\\\Delta\lambda\\\Delta t\end{bmatrix} =- \begin{bmatrix}r_{\mathrm{dual}}\\r_{\mathrm{eq}}\\r_{\mathrm{ineq}}\\r_{\mathrm{cent}}\end{bmatrix}. WAG0AT000GT00T00IΛ ΔxΔνΔλΔt =− rdualreqrineqrcent .
读任意一行时,把这一行的系数块分别乘上对应的修正量,再相加,就恢复了刚才逐组写出的方程。例如,第三行就是 G Δ x + I Δ t = − r i n e q G\Delta x+I\Delta t=-r_{\mathrm{ineq}} GΔx+IΔt=−rineq。
图中的四行表示四组方程,每一组可以包含多条。若 x x x 有两个分量,另有一条等式和一条不等式,那么未知修正量是 Δ x 1 , Δ x 2 , Δ ν , Δ λ , Δ t \Delta x_1,\Delta x_2,\Delta\nu,\Delta\lambda,\Delta t Δx1,Δx2,Δν,Δλ,Δt,完整矩阵实际为 5 × 5 5\times5 5×5。第一组包含两条梯度平衡方程,另外三组各有一条。
求解这个线性方程组,就能得到各组未知量的联合修正。下一节展开左上角的 W W W,说明目标和非线性约束的二阶导数怎样进入这一块。
9.3 联合矩阵中的拉格朗日 Hessian
第 9.2 节中的梯度平衡残差为:
r d u a l = ∇ x L = ∇ f + ∑ j ν j ∇ h j + ∑ i λ i ∇ g i . r_{\mathrm{dual}} =\nabla_xL =\nabla f+\sum_j\nu_j\nabla h_j+\sum_i\lambda_i\nabla g_i. rdual=∇xL=∇f+j∑νj∇hj+i∑λi∇gi.
对它关于 x x x 求导,就得到联合矩阵左上角的 W W W:
W = ∇ x x 2 L = ∇ 2 f + ∑ j ν j ∇ 2 h j + ∑ i λ i ∇ 2 g i . W=\nabla_{xx}^2 L =\nabla^2 f+\sum_j\nu_j\nabla^2h_j+\sum_i\lambda_i\nabla^2g_i. W=∇xx2L=∇2f+j∑νj∇2hj+i∑λi∇2gi.
这就是拉格朗日 Hessian。它回答的是:在当前乘子取值下,改变 x x x 会怎样改变梯度平衡。因为平衡式包含目标梯度和约束梯度,对它求导就会同时出现目标与约束的二阶项。
计算这一块时,求的是关于 x x x 的偏导,所以乘子保持不变。乘子自身也会更新,它对梯度平衡的影响由 A T Δ ν A^T\Delta\nu ATΔν、 G T Δ λ G^T\Delta\lambda GTΔλ 表达,对应上一节完整矩阵第一行的另外两个非零块。
在一维示例中, g = x − 1 g=x-1 g=x−1 是线性的, g ′ ′ = 0 g''=0 g′′=0,所以 W = f ′ ′ = 2 W=f''=2 W=f′′=2。换成弯曲边界,约束就会产生自己的二阶项。
用一个圆形边界,可以具体算出非线性约束新增的二阶项。考虑在单位圆盘内寻找最接近 ( 2 , 0 ) (2,0) (2,0) 的点:
min x , y f ( x , y ) = ( x − 2 ) 2 + y 2 , g ( x , y ) = x 2 + y 2 − 1 ≤ 0. \min_{x,y} f(x,y)=(x-2)^2+y^2, \qquad g(x,y)=x^2+y^2-1\leq0. x,yminf(x,y)=(x−2)2+y2,g(x,y)=x2+y2−1≤0.
这里的 x , y x,y x,y 是两个坐标,下面的梯度和 Hessian 都按 ( x , y ) (x,y) (x,y) 的顺序排列。目标 f f f 是当前位置到 ( 2 , 0 ) (2,0) (2,0) 的距离平方,约束要求位置在单位圆盘内。我们分四步算出这个例子的 W W W。
第一步:确定原问题的最优点。 圆盘约束 x 2 + y 2 ≤ 1 x^2+y^2\leq1 x2+y2≤1 给出 x ≤ 1 x\leq1 x≤1,因此 2 − x ≥ 1 2-x\geq1 2−x≥1。对任意可行点,都有:
f ( x , y ) = ( 2 − x ) 2 + y 2 ≥ 1. f(x,y)=(2-x)^2+y^2\geq1. f(x,y)=(2−x)2+y2≥1.
点 ( 1 , 0 ) (1,0) (1,0) 满足圆盘约束,且 f ( 1 , 0 ) = 1 f(1,0)=1 f(1,0)=1,恰好达到这个下界。所以原问题的最优点是 ( 1 , 0 ) (1,0) (1,0)。这里先手算出最优点,用它检查后面的乘子和矩阵。
第二步:由梯度平衡求出乘子。 先分别对目标和约束求一阶偏导:
∇ f ( x , y ) = [ 2 ( x − 2 ) 2 y ] , ∇ g ( x , y ) = [ 2 x 2 y ] . \nabla f(x,y)= \begin{bmatrix}2(x-2)\\2y\end{bmatrix}, \qquad \nabla g(x,y)= \begin{bmatrix}2x\\2y\end{bmatrix}. ∇f(x,y)=[2(x−2)2y],∇g(x,y)=[2x2y].
本例只有一条不等式,因此只有一个对应的乘子 λ \lambda λ。把 ( x , y ) = ( 1 , 0 ) (x,y)=(1,0) (x,y)=(1,0) 代入梯度平衡条件 ∇ f + λ ∇ g = 0 \nabla f+\lambda\nabla g=0 ∇f+λ∇g=0:
[ − 2 0 ] + λ [ 2 0 ] = [ 0 0 ] . \begin{bmatrix}-2\\0\end{bmatrix} +\lambda\begin{bmatrix}2\\0\end{bmatrix} =\begin{bmatrix}0\\0\end{bmatrix}. [−20]+λ[20]=[00].
第一行要求 − 2 + 2 λ = 0 -2+2\lambda=0 −2+2λ=0,所以 λ ∗ = 1 \lambda^*=1 λ∗=1;第二行已经是 0 = 0 0=0 0=0。再检查其余条件: g ( 1 , 0 ) = 0 g(1,0)=0 g(1,0)=0, λ ∗ = 1 ≥ 0 \lambda^*=1\geq0 λ∗=1≥0,并且 λ ∗ g ( 1 , 0 ) = 0 \lambda^*g(1,0)=0 λ∗g(1,0)=0。因此,这组点与乘子满足原问题的 KKT 条件。
第三步:继续求导,得到两个 Hessian。 对目标梯度的第一项 2 ( x − 2 ) 2(x-2) 2(x−2) 求导:关于 x x x 的导数为 2,关于 y y y 的导数为 0。对第二项 2 y 2y 2y 求导:关于 x x x 的导数为 0,关于 y y y 的导数为 2。按行排列,得到:
∇ 2 f = [ ∂ 2 f ∂ x 2 ∂ 2 f ∂ x ∂ y ∂ 2 f ∂ y ∂ x ∂ 2 f ∂ y 2 ] = [ 2 0 0 2 ] = 2 I . \nabla^2 f= \begin{bmatrix} \dfrac{\partial^2 f}{\partial x^2}&\dfrac{\partial^2 f}{\partial x\partial y}\\[2mm] \dfrac{\partial^2 f}{\partial y\partial x}&\dfrac{\partial^2 f}{\partial y^2} \end{bmatrix} =\begin{bmatrix}2&0\\0&2\end{bmatrix} =2I. ∇2f= ∂x2∂2f∂y∂x∂2f∂x∂y∂2f∂y2∂2f =[2002]=2I.
约束梯度的两项是 2 x 2x 2x 和 2 y 2y 2y,继续求导同样得到:
∇ 2 g = [ 2 0 0 2 ] = 2 I . \nabla^2 g=\begin{bmatrix}2&0\\0&2\end{bmatrix}=2I. ∇2g=[2002]=2I.
这里的 I I I 是 2 × 2 2\times2 2×2 单位矩阵。目标梯度中的 2 ( x − 2 ) 2(x-2) 2(x−2) 与约束梯度中的 2 x 2x 2x 相差一个常数,对 x x x 再求一次导数都得到 2,因此两个 Hessian 恰好相同。
第四步:按乘子加权,组成拉格朗日 Hessian。 本例的拉格朗日函数是 L = f + λ g L=f+\lambda g L=f+λg。计算关于 ( x , y ) (x,y) (x,y) 的二阶偏导时固定 λ \lambda λ,于是:
W = ∇ 2 f + λ ∇ 2 g = 2 I + λ 2 I = 2 ( 1 + λ ) I . W=\nabla^2 f+\lambda\nabla^2 g =2I+\lambda\,2I =2(1+\lambda)I. W=∇2f+λ∇2g=2I+λ2I=2(1+λ)I.
在刚才求出的原问题最优点处,乘子为 λ ∗ = 1 \lambda^*=1 λ∗=1,所以:
W ∣ λ = 1 = 2 I + 2 I = 4 I = [ 4 0 0 4 ] . W\big|_{\lambda=1} =2I+2I =4I =\begin{bmatrix}4&0\\0&4\end{bmatrix}. W λ=1=2I+2I=4I=[4004].
也可以直接展开来核对。固定 λ = 1 \lambda=1 λ=1 时:
L ( x , y , 1 ) = ( x − 2 ) 2 + y 2 + ( x 2 + y 2 − 1 ) = 2 x 2 + 2 y 2 − 4 x + 3. \begin{aligned} L(x,y,1) &=(x-2)^2+y^2+(x^2+y^2-1)\\ &=2x^2+2y^2-4x+3. \end{aligned} L(x,y,1)=(x−2)2+y2+(x2+y2−1)=2x2+2y2−4x+3.
这个表达式关于 x , y x,y x,y 的二阶偏导分别为 4,混合偏导为 0,因此同样得到 W = 4 I W=4I W=4I。
这里目标贡献了 2 I 2I 2I,非线性约束在乘子 λ = 1 \lambda=1 λ=1 时又贡献了 2 I 2I 2I。如果只提供目标函数的 Hessian,就会缺少后面这一部分。迭代过程中,求解器按当前乘子计算 W = 2 ( 1 + λ ) I W=2(1+\lambda)I W=2(1+λ)I; 4 I 4I 4I 是本例在 λ = 1 \lambda=1 λ=1 时的具体值。
9.4 消去余量和乘子的修正量,联系障碍曲率
回看一维例子,拉格朗日 Hessian 是 W = 2 W=2 W=2,而第 5 节算出的障碍目标二阶导数是 2 + μ / ( 1 − x ) 2 2+\mu/(1-x)^2 2+μ/(1−x)2。两种写法记录曲率的位置不同:直接消去余量后,障碍曲率包含在目标的二阶导里;保留余量和乘子后,这部分信息还分布在乘积方程及其导数中。本节通过消元把这两种写法联系起来。
先看第 9.2 节完整矩阵的第三行:
G Δ x + Δ t = − r i n e q ⟹ Δ t = − r i n e q − G Δ x . G\Delta x+\Delta t=-r_{\mathrm{ineq}} \quad\Longrightarrow\quad \Delta t=-r_{\mathrm{ineq}}-G\Delta x. GΔx+Δt=−rineq⟹Δt=−rineq−GΔx.
它把 Δ t \Delta t Δt 表达为 Δ x \Delta x Δx 与当前残差的组合。代入第四行 T Δ λ + Λ Δ t = − r c e n t T\Delta\lambda+\Lambda\Delta t=-r_{\mathrm{cent}} TΔλ+ΛΔt=−rcent,得到:
Δ λ = T − 1 Λ G Δ x + T − 1 ( Λ r i n e q − r c e n t ) . \Delta\lambda =T^{-1}\Lambda G\Delta x +T^{-1}(\Lambda r_{\mathrm{ineq}}-r_{\mathrm{cent}}). Δλ=T−1ΛGΔx+T−1(Λrineq−rcent).
这里各个 t i > 0 t_i>0 ti>0,所以对角矩阵 T T T 可以求逆。再把这个 Δ λ \Delta\lambda Δλ 代入第一行,收集所有乘在 Δ x \Delta x Δx 前面的项,便得到:
W + G T T − 1 Λ G . W+G^TT^{-1}\Lambda G. W+GTT−1ΛG.
其他由当前残差组成的项可以移到方程右侧。这个结果说明,消去余量与乘子的修正量后,原变量方向上的系数同时包含 W W W,以及由约束 Jacobian、余量和乘子共同构成的附加项。
接下来要把消元结果与障碍目标的二阶导数对应起来,需要先回顾第 5.2 节的中心路径。固定一个 μ > 0 \mu>0 μ>0,求出对应障碍子问题的理想解;让 μ \mu μ 连续变化,再把这些解连起来,就得到本讲义例子中的中心路径。它描述不同障碍参数对应的解的位置。
例如,第 5.2 节的一维问题有以下结果:
| 固定的 μ \mu μ | 对应子问题的最优点 x μ x_\mu xμ |
|---|---|
| 0.1 0.1 0.1 | 约 0.952277 0.952277 0.952277 |
| 0.01 0.01 0.01 | 约 0.995025 0.995025 0.995025 |
| 0.001 0.001 0.001 | 约 0.999500 0.999500 0.999500 |
每个 x μ x_\mu xμ 还对应自己的余量 t μ t_\mu tμ 和乘子 λ μ \lambda_\mu λμ,所以这里也可以把中心路径看成随 μ \mu μ 变化的一系列 ( x μ , t μ , λ μ ) (x_\mu,t_\mu,\lambda_\mu) (xμ,tμ,λμ)。这些理想解满足相应子问题的完整一阶条件;实际迭代点通常还带有求解误差,可以偏离这条路径。
下面在其中一个固定 μ \mu μ 的解处比较两种曲率写法。中心路径上的解同时满足余量关联和扰动互补条件:
g ( x ) + t = 0 , t λ = μ . g(x)+t=0,\qquad t\lambda=\mu. g(x)+t=0,tλ=μ.
第一条给出 t = − g ( x ) t=-g(x) t=−g(x),第二条给出 λ = μ / t \lambda=\mu/t λ=μ/t。把两者连起来,就得到后面要用的关系:
λ = μ t = − μ g ( x ) . \lambda=\frac{\mu}{t}=-\frac{\mu}{g(x)}. λ=tμ=−g(x)μ.
因为 g ( x ) < 0 g(x)<0 g(x)<0,所以右侧仍然是正数,符合当前障碍子问题对乘子的要求。
在一维例子中, G = 1 G=1 G=1、 W = 2 W=2 W=2,消元后的系数为 2 + λ / t 2+\lambda/t 2+λ/t。此时 g ( x ) = x − 1 g(x)=x-1 g(x)=x−1,余量为 t = 1 − x t=1-x t=1−x。代入刚才的乘子关系,得到:
2 + λ t = 2 + μ t 2 = 2 + μ ( 1 − x ) 2 . 2+\frac{\lambda}{t} =2+\frac{\mu}{t^2} =2+\frac{\mu}{(1-x)^2}. 2+tλ=2+t2μ=2+(1−x)2μ.
这就恢复了第 5 节直接对障碍目标求出的二阶导数。类似地,对于只有目标 f f f 和一条不等式 g ( x ) ≤ 0 g(x)\leq0 g(x)≤0 的问题,在 g ( x ) < 0 g(x)<0 g(x)<0 时直接对障碍目标求二阶导数,得到:
∇ 2 [ f − μ log ( − g ) ] = ∇ 2 f − μ g ∇ 2 g + μ g 2 ∇ g ∇ g T . \nabla^2\!\left[f-\mu\log(-g)\right] =\nabla^2 f-\frac{\mu}{g}\nabla^2g +\frac{\mu}{g^2}\nabla g\nabla g^T. ∇2[f−μlog(−g)]=∇2f−gμ∇2g+g2μ∇g∇gT.
这里的前两项可以与 W W W 直接对应。本段只包含目标 f f f 和一条不等式 g g g,拉格朗日函数为 L = f + λ g L=f+\lambda g L=f+λg。按照固定当前乘子、对原变量求二阶偏导的定义:
W = ∇ 2 f + λ ∇ 2 g . W=\nabla^2 f+\lambda\nabla^2g. W=∇2f+λ∇2g.
在中心路径上的同一个点,代入 λ = − μ / g \lambda=-\mu/g λ=−μ/g,就有:
∇ 2 f − μ g ∇ 2 g = ∇ 2 f + ( − μ g ) ∇ 2 g = ∇ 2 f + λ ∇ 2 g = W . \begin{aligned} \nabla^2 f-\frac{\mu}{g}\nabla^2g &=\nabla^2 f+\left(-\frac{\mu}{g}\right)\nabla^2g\\ &=\nabla^2 f+\lambda\nabla^2g\\ &=W. \end{aligned} ∇2f−gμ∇2g=∇2f+(−gμ)∇2g=∇2f+λ∇2g=W.
这就是“前两项等于 W W W”的具体代入过程。计算 W W W 时乘子仍作为常数,上面的代入用于比较同一点上的矩阵数值。因此,沿中心路径,障碍目标的完整 Hessian 可以写为:
∇ 2 [ f − μ log ( − g ) ] = W + μ g 2 ∇ g ∇ g T . \nabla^2\!\left[f-\mu\log(-g)\right] =W+\frac{\mu}{g^2}\nabla g\nabla g^T. ∇2[f−μlog(−g)]=W+g2μ∇g∇gT.
其中最后一项对应消去余量和乘子后出现的附加曲率。对于这里的一条不等式, G = ∇ g T G=\nabla g^T G=∇gT,且 λ / t = μ / t 2 = μ / g 2 \lambda/t=\mu/t^2=\mu/g^2 λ/t=μ/t2=μ/g2,所以它恰好与前面的 G T T − 1 Λ G G^TT^{-1}\Lambda G GTT−1ΛG 对应。
IPOPT 在原始—对偶方程中结合这些信息计算方向:模型的二阶导数接口提供
W
W
W,求解器结合约束 Jacobian、余量和乘子处理其余部分。第 13 节的 hess_lag 对应其中的
W
W
W。实际求解还会结合边界处理、缩放、正则化、惯性修正和线搜索,完成本轮更新。
10. 障碍参数的更新策略:mu_strategy
第 8—9 节讨论了固定 μ \mu μ 时的求解:计算残差和导数,形成线性方程组,求出变量与乘子的方向,再选择步长并更新状态。第 5.5 节还指出,为了接近原问题的解,需要继续调整 μ \mu μ。
这就产生了一个独立的算法选择:当前子问题求到什么程度时更新
μ
\mu
μ,以及下一次使用多大的
μ
\mu
μ。IPOPT 用 mu_strategy 选择这套更新规则。
μ
\mu
μ 的变化会调整乘积要求
t
i
λ
i
=
μ
t_i\lambda_i=\mu
tiλi=μ,从而影响接下来的修正方向;每一步实际移动多远仍由步长控制。
选择这个选项,相当于为求解器选择安排障碍子问题的规则。使用者提供原目标和约束,求解器根据规则与迭代表现更新 μ \mu μ。下面比较两种安排。
10.1 按阶段减小 μ:monotone
monotone 通常维持当前
μ
\mu
μ,让当前障碍子问题达到与该
μ
\mu
μ 相配的精度,然后减小
μ
\mu
μ,进入下一阶段。概念流程是:
μ 0 ⟶ μ 1 ⟶ μ 2 ⟶ ⋯ , μ j + 1 < μ j . \mu_0\ \longrightarrow\ \mu_1\ \longrightarrow\ \mu_2\ \longrightarrow\cdots, \qquad \mu_{j+1}<\mu_j. μ0 ⟶ μ1 ⟶ μ2 ⟶⋯,μj+1<μj.
每个阶段内部可以包含多次牛顿迭代。这里的单调性指障碍参数的更新,并不要求原始目标函数在每次迭代都下降。
IPOPT 的相关选项包括 mu_init 和 barrier_tol_factor。后者参与控制当前障碍子问题需要达到的精度。忽略停止阈值等细节,减小规则的核心形式为:
μ n e w = min ( κ μ μ , μ θ μ ) , 0 < κ μ < 1 , θ μ > 1. \mu_{\mathrm{new}}=\min\!\left(\kappa_\mu\mu,\ \mu^{\theta_\mu}\right), \qquad 0<\kappa_\mu<1,\quad\theta_\mu>1. μnew=min(κμμ, μθμ),0<κμ<1,θμ>1.
10.2 随迭代表现调整 μ:adaptive
我们还可以利用当前迭代的残差与进展,为下一次迭代选择
μ
\mu
μ。adaptive 的自由模式采用这种做法;“自由”指参数可以根据当前情况调整,序列可以增大或减小。这些值由算法规则根据当前状态计算。
默认的 mu_oracle="quality-function" 使用质量函数评价候选参数,综合考虑对偶残差、原始残差、互补性与中心性等信息。
进展不足时,IPOPT 会根据 adaptive_mu_globalization 的规则切换到单调模式。默认规则 obj-constr-filter 观察目标与约束违反的进展。这个切换有助于维持收敛行为;全局化机制处理从较远初值出发时的进展,无法保证非凸问题的全局最优解。
10.3 两种策略的迭代特点与比较方法
两种策略都利用障碍子问题逼近原问题,它们安排参数更新的方式不同。比较时,可以先观察参数更新时机,再检查这种安排对求解过程的影响。
| 问题 | monotone | adaptive |
|---|---|---|
| 何时更新 μ | 当前阶段达到相应精度后 | 自由模式下随迭代表现选择 |
| μ 的变化 | 阶段间减小 | 自由模式下可增可减 |
| 可能收益 | 阶段逻辑清晰,轨迹较有规律 | 某些问题可以减少阶段等待和迭代次数 |
| 可能代价 | 某些阶段可能耗费较多迭代 | 参数选择与搜索轨迹更复杂,某些问题可能变慢或失败 |
mu_strategy 会影响优化轨迹,在非凸问题中还可能影响最终到达的局部解。比较它们时,应固定目标、约束、初值、导数和停止条件,记录成功率、迭代数与总时间。
mu_init 主要用于 monotone。使用 adaptive 时,应按照 IPOPT 选项文档理解其独立的参数选择机制。
11. 最优性误差与求解停止条件
前面已经说明了变量、乘子和 μ \mu μ 的更新过程。为了判断何时结束,还需要检查当前点距离原问题的最优性条件有多远。第 7 节列出的条件对应三类误差:可行性误差、梯度平衡误差和互补误差。直观上可以观察:
primal error : h ( x ) , max ( g ( x ) , 0 ) , dual error : ∇ x L ( x , ν , λ ) , complementarity : t i λ i . \begin{aligned} \text{primal error}&:\quad h(x),\ \max(g(x),0),\\ \text{dual error}&:\quad \nabla_xL(x,\nu,\lambda),\\ \text{complementarity}&:\quad t_i\lambda_i. \end{aligned} primal errordual errorcomplementarity:h(x), max(g(x),0),:∇xL(x,ν,λ),:tiλi.
约束误差很小,表示当前结果已经接近可接受范围;梯度平衡误差很小,表示目标与约束的局部作用接近平衡;乘积接近零,表示互补关系接近原问题的要求。检查这三类误差,才能同时了解可行性与最优性的进展。
第 8 节固定 μ \mu μ 时使用的残差为 t i λ i − μ t_i\lambda_i-\mu tiλi−μ;这里判断原问题时关心的是 t i λ i t_i\lambda_i tiλi 接近零。即使当前障碍子问题已经解得很准,较大的 μ \mu μ 仍可能让结果离原问题的最优性条件有距离。
IPOPT 的实际判断还包含变量边界、误差缩放和具体容差。tol 管理整体最优性误差,constr_viol_tol、dual_inf_tol、compl_inf_tol 分别约束相应分量。acceptable_* 配置可以允许在较宽松的条件连续满足时结束。
max_iter、CPU 或墙钟时间限制、外部回调中止也会结束求解。求解器可以在预算耗尽前收敛;预算耗尽本身无法说明已经得到满足要求的解。
IPOPT 日志中常用的字段为:
| 字段 | 阅读方式 |
|---|---|
objective | 当前原始目标值 |
inf_pr | 当前原始约束违反的度量;默认显示原问题约束违反 |
inf_du | 内部缩放问题的梯度平衡误差;也称对偶不可行性度量 |
lg(mu) | 障碍参数的十进制对数,例如 −3 对应 0.001 |
alpha_pr / alpha_du | 原始变量 / 乘子采用的步长系数 |
ls | 当前迭代的回溯线搜索次数 |
如果总时间增加,可以分开检查迭代次数、每次导数求值成本、线性方程求解成本和线搜索次数。仅凭一次求解时间,很难定位是哪一部分变化。
12. 二阶信息的来源:hessian_approximation
到这里,我们已经把求解方向、障碍参数更新和停止条件串了起来。实际实现中还要解决一个计算问题:第 9 节使用的拉格朗日 Hessian 从哪里获得。直接求二阶导可以利用模型曲率,也可能花费较多时间,因此 IPOPT 允许选择二阶信息的来源。
IPOPT 通过非线性规划(NLP)接口获取模型值与导数。选项 hessian_approximation 决定其中的二阶信息怎样获得,提供两种主要方式:
| 选项值 | 二阶信息来源 | 常见考虑 |
|---|---|---|
"exact" | 使用 NLP 接口提供的拉格朗日 Hessian | 模型能够高效计算可靠二阶导时,可以利用其曲率结构 |
"limited-memory" | 根据近期迭代信息构造有限内存拟牛顿近似 | 二阶导难以获得或成本较高时,可以减少显式 Hessian 求值 |
在 CasADi 中可以明确写为:
options = {"ipopt.hessian_approximation": "exact"}
# 或者选择另一种二阶信息来源:
options = {"ipopt.hessian_approximation": "limited-memory"}
有限内存方法利用变量与梯度等信息的变化,近似拉格朗日函数的曲率,具体实现属于 L-BFGS 类方法。它仍然需要目标梯度和约束 Jacobian。两种选项使用相同的原目标、约束和最优性条件,变化的是计算修正方向时采用的曲率信息。
exact 模式调用接口给出的矩阵。当应用程序自定义了一个不完整的 Hessian 时,求解器会使用这个近似矩阵,接口名称不会自动补齐缺失项。
这两个选项管理不同的事情:mu_strategy 决定障碍参数如何更新;hessian_approximation 决定方向系统从哪里获得拉格朗日曲率。因此可以交叉组合并做对照实验。
13. 自定义 Hessian 的接口:hess_lag
上一节的 exact 模式需要 NLP 接口提供一个数值矩阵。对于纯符号模型,CasADi 通常可以自动生成相应的导数函数;需要接入专用导数或明确构造近似矩阵时,也可以通过 hess_lag 自定义它。下面把第 9 节的公式对应到这个接口。
13.1 接口的输入与输出
在每次需要二阶信息时,IPOPT 已经有当前的变量与乘子数值。CasADi 的 hess_lag 接口接收这些数值,返回对应的拉格朗日 Hessian 上三角部分,供求解器组装方向方程。
在 CasADi 的统一约束向量写法中:
min x f ( x , p ) , l g ≤ g ( x , p ) ≤ u g . \min_x f(x,p),\qquad l_g\leq g(x,p)\leq u_g. xminf(x,p),lg≤g(x,p)≤ug.
接口要求的矩阵为:
H ( x , p , σ , λ ) = ∇ x x 2 [ σ f ( x , p ) + λ T g ( x , p ) ] . H(x,p,\sigma,\lambda)=\nabla_{xx}^2\!\left[\sigma f(x,p)+\lambda^Tg(x,p)\right]. H(x,p,σ,λ)=∇xx2[σf(x,p)+λTg(x,p)].
这对应第 9 节的拉格朗日曲率。用户提供这个矩阵后,IPOPT 会组装松弛变量与互补条件产生的其他项。
| 输入 | 含义 |
|---|---|
| x x x | 当前决策变量 |
| p p p | 求解期间固定的模型参数;没有参数时长度为 0 |
σ
\sigma
σ,接口名 lam_f | 接口传入的目标函数系数 |
λ
\lambda
λ,接口名 lam_g | 与约束向量逐项对应的乘子 |
lam_f 与障碍参数
μ
\mu
μ 各自独立。lam_g 由求解器更新,目标函数中的手工权重已经包含在
f
f
f 内。实现这个接口时,我们提供计算规则;每次调用所用的乘子数值由求解器传入。
前文采用
g
≤
0
g\leq0
g≤0 的写法,因此乘子非负。CasADi 支持上下两侧边界,合并后的 lam_g 可以带正负号。读取其数值时,应结合该约束使用的是上界、下界还是等式。
13.2 圆盘问题的符号实现
现在把第 9.3 节已经手算过的圆盘问题写成代码。这样可以同时核对目标、约束、乘子和矩阵。下面的 Python 写法与 C++ 中的 MX::hessian、MX::triu 对应:
import casadi as ca
x = ca.MX.sym("x", 2)
p = ca.MX.sym("p", 0)
sigma = ca.MX.sym("lam_f")
lam = ca.MX.sym("lam_g", 1)
f = (x[0] - 2)**2 + x[1]**2
g = ca.vertcat(ca.dot(x, x) - 1)
L = sigma * f + ca.dot(lam, g)
H = ca.hessian(L, x)[0]
hess_lag = ca.Function(
"my_hess_lag", [x, p, sigma, lam], [ca.triu(H)]
)
solver = ca.nlpsol("circle", "ipopt", {"x": x, "f": f, "g": g}, {
"ipopt.mu_strategy": "adaptive",
"ipopt.hessian_approximation": "exact",
"hess_lag": hess_lag,
})
result = solver(x0=[0, 0], lbg=[-ca.inf], ubg=[0])
逐步对应数学含义:
L建立 σ f + λ T g \sigma f+\lambda^Tg σf+λTg 的符号表达式。ca.hessian(L,x)[0]对决策变量求二阶导。Python 接口同时返回 Hessian 与梯度,[0]取 Hessian。ca.triu(H)保留上三角。对称矩阵只需传递一半元素,CasADi 的这个接口采用上三角约定。ca.Function保存计算规则。每次求值都会使用当时的 x , p , σ , λ x,p,\sigma,\lambda x,p,σ,λ 生成数值矩阵。hess_lag属于 CasADi 选项;带ipopt.前缀的两个选项传递给 IPOPT。
在传给 nlpsol 的问题字典中,x 是决策变量;sigma 和 lam 则是 hess_lag 的符号输入。IPOPT 在需要矩阵时把当前系数传进来。整个调用关系是:CasADi 保存求导规则,IPOPT 提供当前数值,函数返回矩阵,IPOPT 再用矩阵计算联合修正方向。
13.3 符号约束与外部约束的二阶信息
圆盘例子的目标和约束都由 CasADi 符号表达式给出,因此可以直接求出全部二阶导。实际模型有时还会调用外部几何库,外部接口能够提供的导数阶数决定了这部分曲率能否直接计算。把约束向量按来源分成两部分:
g = [ g s y m g e x t ] , λ = [ λ s y m λ e x t ] , g=\begin{bmatrix}g_{\mathrm{sym}}\\g_{\mathrm{ext}}\end{bmatrix}, \qquad \lambda=\begin{bmatrix}\lambda_{\mathrm{sym}}\\\lambda_{\mathrm{ext}}\end{bmatrix}, g=[gsymgext],λ=[λsymλext],
完整拉格朗日 Hessian 为:
W = σ ∇ 2 f + ∑ i λ s y m , i ∇ 2 g s y m , i + ∑ j λ e x t , j ∇ 2 g e x t , j . W=\sigma\nabla^2f +\sum_i\lambda_{\mathrm{sym},i}\nabla^2g_{\mathrm{sym},i} +\sum_j\lambda_{\mathrm{ext},j}\nabla^2g_{\mathrm{ext},j}. W=σ∇2f+i∑λsym,i∇2gsym,i+j∑λext,j∇2gext,j.
如果外部接口只提供约束值和一阶导,可以显式构造以下近似:
W ~ = σ ∇ 2 f + ∑ i λ s y m , i ∇ 2 g s y m , i . \widetilde W=\sigma\nabla^2f +\sum_i\lambda_{\mathrm{sym},i}\nabla^2g_{\mathrm{sym},i}. W =σ∇2f+i∑λsym,i∇2gsym,i.
此时外部约束仍保留在完整的 g g g 与 Jacobian 中,求解器继续使用它们判断可行性并形成搜索方向;二阶矩阵中省略了外部约束的曲率项。
原代码里的 Slice(0, m_sym) 选择前一段乘子,dot(...) 形成
λ
s
y
m
T
g
s
y
m
\lambda_{\mathrm{sym}}^Tg_{\mathrm{sym}}
λsymTgsym,随后求 Hessian。切片顺序必须与完整约束向量的排列一致。
提供更多二阶信息可能改善局部模型,也会增加导数求值成本。整体收益取决于迭代数、每次求值和线性求解的总成本,需要通过同条件实验判断。
14. 实际求解中的导数检查与结果验证
14.1 模型与初值
明确目标、约束和结果验收条件,检查变量尺度,并保证目标与约束在初值处能够计算。
14.2 导数一致性:derivative_test
IPOPT 用梯度、Jacobian 和 Hessian 计算修正方向。如果函数值与提供的导数不一致,方向计算就可能受到影响。接入外部 Callback 或自定义 hess_lag 后,可以先用 derivative_test 核对这些接口。
一阶与二阶检查各自比较什么。 检查器在正式优化迭代前,用有限差分估计导数,再与接口返回的导数逐项比较。
derivative_test 的取值 | 检查内容 |
|---|---|
"none" | 关闭检查,默认值 |
"first-order" | 检查目标梯度 ∇ f \nabla f ∇f 和约束 Jacobian J g J_g Jg |
"second-order" | 先检查一阶导,再检查目标与各约束的 Hessian |
"only-second-order" | 只检查二阶导,适合一阶导已核对的情况 |
以一维函数为例,一阶检查利用函数值的变化:
f ′ ( x ) ≈ f ( x + h ) − f ( x ) h . f'(x)\approx\frac{f(x+h)-f(x)}{h}. f′(x)≈hf(x+h)−f(x).
二阶检查利用一阶导数的变化:
f ′ ′ ( x ) ≈ f ′ ( x + h ) − f ′ ( x ) h . f''(x)\approx\frac{f'(x+h)-f'(x)}{h}. f′′(x)≈hf′(x+h)−f′(x).
这里 h h h 是一个小扰动。多变量时,检查器逐个扰动变量,比较对应的梯度、Jacobian 和 Hessian 元素。先核对一阶导,再看二阶导,可以避免错误的一阶导继续影响二阶差分结果。
二阶检查通过拉格朗日 Hessian 接口分别核对目标和各约束的二阶项,因此要检查变量顺序、乘子顺序及目标系数 lam_f。使用 limited-memory 时,通常只启用一阶检查。
在 CasADi 中启用检查。 可以向创建求解器的选项字典中加入:
options = {
"ipopt.derivative_test": "first-order",
"ipopt.derivative_test_print_all": "yes",
"ipopt.derivative_test_perturbation": 1e-8,
"ipopt.derivative_test_tol": 1e-4,
"ipopt.point_perturbation_radius": 0.0,
}
一阶检查通过后,将 "first-order" 改为 "second-order"。derivative_test 控制检查过程,hessian_approximation 选择优化迭代的二阶信息来源。
derivative_test_print_all="yes"输出全部比较项,便于查看正确项与异常项;默认"no"只输出可疑项。derivative_test_perturbation设置相对扰动尺度,默认 10 − 8 10^{-8} 10−8。扰动太大会增加差分近似误差,太小则容易受到浮点舍入或外部函数噪声影响。derivative_test_tol设置标记差异的阈值,默认 10 − 4 10^{-4} 10−4。它控制导数检查的判定,与优化停止容差tol各自独立。point_perturbation_radius=0.0关闭检查中心点默认允许的随机扰动,便于围绕指定初值复查;有限差分本身的小扰动仍然保留。
阅读输出并定位差异。 grad_f、jac_g、obj_hess、constr_hess 分别对应目标梯度、约束 Jacobian、目标 Hessian 和约束 Hessian。每行给出接口值、有限差分估计值和偏差;行首的 * 标记超过阈值的项。Jacobian 或 Hessian 条目后的 v 表示该位置已经列入接口声明的稀疏结构。
发现差异后,先检查变量与约束的排列、导数符号及系数,再结合扰动尺度复查。最近距离、接触切换等函数可能在几何分支切换处不光滑,可以选择分支稳定的位置检查局部导数。
第 13.3 节主动省略外部约束曲率时,二阶检查会在对应项上报告差异。此时应核对差异是否与省略项一致,同时确认保留的二阶项以及完整的一阶导正确。检查通过说明测试位置的函数与导数一致;模型是否表达了任务要求,仍需要结合任务检查。
导数检查会增加函数调用次数,适合调试阶段使用。检查完成后恢复 derivative_test="none",再测量正常求解耗时。
14.3 结果与耗时
结合求解状态、约束误差和任务要求判断结果。比较参数时固定模型与初值,一次改变一个因素,同时记录迭代次数与总耗时。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)