量化交易中文教材

第 14 章 线性规划:内点法

学习目标

读完本章,你应当能够:

  1. 把 LP 的 KKT 条件写成非线性方程组 \(F(x,\lambda,s)=0\) 加非负约束,并说明为什么必须让迭代点严格保持 \((x,s)>0\)。
  2. 理解中心路径、对偶度量 \(\mu=x^Ts/n\) 与中心化参数 \(\sigma\) 的含义,说清仿射尺度方向(\(\sigma=0\))与中心化方向(\(\sigma=1\))的取舍。
  3. 写出路径跟踪方法的两种邻域 \(\mathcal N_2(\theta)\)、\(\mathcal N_{-\infty}(\gamma)\),读懂长步路径跟踪算法 \(O(n\log1/\epsilon)\) 复杂度证明的主线。
  4. 按步骤实现 Mehrotra 预测–校正算法,并知道它是绝大多数商业内点求解器的基础。
  5. 理解每步线性代数的两种形式(增广系统、正规方程 \(AD^2A^T\)),知道稠密列和后期病态带来的问题。
  6. 能读懂内点求解器日志(\(\mu\)、原始/对偶残差、对偶间隙),并在实际 LP 中比较单纯形法与内点法。

读前导读

这一章在解决什么问题

上一章的单纯形法沿着可行区域的"棱角"一个顶点一个顶点地走,问题一大,要走的顶点就成千上万。本章换一个思路:不走边界,从可行区域内部直接穿过去,逼近最优点。做法是把 LP 的 KKT 条件(原始可行、对偶可行、互补松弛)看成一组方程,用牛顿法求解,同时始终保持变量严格为正。

牛顿法你其实很熟。金融计算器求 IRR 或到期收益率时,就是在反复"用切线近似、解出下一个猜测值",几步就收敛,这就是一元牛顿法。本章把它推广到几百上千个方程同时求解。难点不在牛顿法本身,而在"互补松弛 \(x_is_i=0\)"这类条件:直接解会掉进错误的解(变量变负)。内点法的对策是先把目标放宽成"\(x_is_i\) 都等于一个小正数 \(\tau\)",再让 \(\tau\) 逐步降到零。这条随 \(\tau\) 移动的轨迹叫中心路径。

可以把它想成风控里的"软限额":不是到了限额才硬性禁止,而是越接近限额惩罚越重,于是组合自然停在限额内部;再逐步减轻惩罚,组合就慢慢贴近真正的最优边界。读完本章你还能看懂 MOSEK、Gurobi 等求解器的 barrier 日志:每行打印的 \(\mu\) 就是对偶间隙(离最优还有多远)的平均值。

需要先想起来的数学

1. 牛顿法解方程组。 一元情形:解 \(g(x)=0\),在当前点做切线 \(g(x)+g'(x)\Delta x=0\),得 \(\Delta x=-g(x)/g'(x)\)。例:解 \(x^2-2=0\),从 \(x=1\) 出发,\(\Delta x=-(1-2)/2=0.5\),得 1.5,再一步得 1.4167,已很接近 \(\sqrt2\)。多元情形把 \(g'\) 换成 Jacobian 矩阵 \(J\)(第 \(i\) 个方程对第 \(j\) 个变量的偏导排成的矩阵),解线性方程组 \(J\Delta=-F\)。见 第 00 册第 05 章 多元微积分与优化。

2. 对角矩阵记号。 \(X=\mathrm{diag}(x)\) 是把向量 \(x\) 放在对角线上、其余为 0 的方阵;\(e\) 是全 1 向量。于是 \(XSe\) 就是逐分量乘积组成的向量 \((x_1s_1,\dots,x_ns_n)^T\),\(X^{-1}\) 就是对角线取倒数。这只是一种紧凑写法,没有新内容。见 第 00 册第 06 章 线性代数速成。

3. 范数。 \(\|v\|_2=\sqrt{\sum v_i^2}\) 是通常的长度;\(\|v\|_1=\sum|v_i|\);\(\|v\|_\infty=\max|v_i|\)。例:\(v=(3,-4)\),三者分别是 5、7、4。本章用范数衡量"离中心路径有多远"。

4. 对数与几何衰减。 若每步把误差乘以 \((1-\delta/n)\),\(k\) 步后误差约为原来的 \(e^{-k\delta/n}\)。要从 \(\mu_0\) 降到 \(\epsilon\),需要 \(k\approx\frac n\delta\ln\frac{\mu_0}\epsilon\) 步。这和"按固定比例摊销的贷款余额多久降到某个水平"是同一种计算。记号 \(O(\cdot)\) 表示"同阶增长,忽略常数"。见 第 00 册第 04 章 级数与收敛 和 第 07 章 概率中的分析工具。

怎么读这一章

核心必读是 14.2(原始–对偶框架:KKT 方程组、牛顿步、中心路径、\(\mu\) 和 \(\sigma\))、14.4(Mehrotra 预测–校正,实际软件用的就是它)和 14.7(代码与求解器日志)。建议先读 14.2,再直接跳到 14.4 和 14.7.2,对照代码输出理解每一步。

第一次可以跳过的是 14.3.1 的复杂度证明(只需记住结论:迭代次数随问题规模增长很慢)、14.3.2 的其他方法简介和 14.6 的推广。14.5 的线性代数如果你不打算自己写求解器,看懂"每步的主要成本是解一个 \(AD^2A^T\) 方程组,稠密的约束行会让它变慢"这一点就够了。


14.1 动机:从内部逼近解

先说结论:原始–对偶内点法(primal–dual interior-point methods)对 LP 的 KKT 条件施用牛顿法,同时让所有迭代点严格位于非负象限内部。它每步代价比单纯形法高,但迭代次数很少(通常 20–60 次),且几乎不随问题规模增长,在大规模问题上与单纯形法强有力地竞争。

历史线索。单纯形法最坏情况下是指数时间(第 13 章 Klee–Minty 例子)。Khachiyan 的椭球法在最坏情况下是多项式的,但它在几乎所有问题上都接近最坏界,毫无竞争力。1984 年 Karmarkar 提出的投影算法既是多项式的,又有不错的实际表现,引发了大量研究:仿射尺度、对数障碍、势函数下降、路径跟踪、原始–对偶、不可行内点等方法相继出现。到 90 年代初,原始–对偶方法脱颖而出,成为最有效的实用方法。

两类方法的几何区别:单纯形法沿可行多面体的边界逐个检查顶点;内点法只在极限时才接近边界,可以从内部甚至外部(不可行内点法)逼近解,但从不落在边界上。


14.2 原始–对偶框架

14.2.1 KKT 条件写成方程组

原始问题与对偶问题:

\[ \min c^Tx\ \ \text{s.t.}\ Ax=b,\ x\ge0;\qquad \max b^T\lambda\ \ \text{s.t.}\ A^T\lambda+s=c,\ s\ge0.\tag{14.1–14.2} \]

本章对偶变量记为 \(\lambda\)(第 13 章记为 \(\pi\))。KKT 条件:

\[ A^T\lambda+s=c,\quad Ax=b,\quad x_is_i=0\ (i=1,\dots,n),\quad (x,s)\ge0.\tag{14.3} \]

写成映射 \(F:\mathbb R^{2n+m}\to\mathbb R^{2n+m}\):

\[ F(x,\lambda,s)=\begin{bmatrix}A^T\lambda+s-c\\Ax-b\\XSe\end{bmatrix}=0,\qquad (x,s)\ge0,\tag{14.4} \]

其中 \(X=\mathrm{diag}(x)\),\(S=\mathrm{diag}(s)\),\(e=(1,\dots,1)^T\)。

三个等式中前两个线性、第三个只是"轻度非线性"(双线性),单独求解并不难。非负性要求才是内点法一切复杂性的来源。如果只解 \(F=0\) 而不管符号,会碰到大量伪解(spurious solutions):满足 \(F=0\) 但 \((x,s)\) 有负分量的点,它们与 LP 的解毫无关系。

例(习题 14.1):\(\min x_1\) s.t. \(x_1+x_2=1\),\(x\ge0\)。真正的原始–对偶解是 \(x^*=(0,1)\),\(\lambda^*=0\),\(s^*=(1,0)\)。但 \(x=(1,0)\),\(\lambda=1\),\(s=(0,-1)\) 也满足 \(F=0\):\(A^T\lambda+s=(1,1)+(0,-1)=(1,0)=c\),\(x_1+x_2=1\),\(x_1s_1=x_2s_2=0\)。它只是违反了 \(s\ge0\)。

所以内点法要求迭代点严格满足 \(x>0,\ s>0\),"内点"之名即由此而来。定义可行集与严格可行集:

\[ \mathcal F=\{(x,\lambda,s):Ax=b,\ A^T\lambda+s=c,\ (x,s)\ge0\},\qquad \mathcal F^o=\{\cdots,\ (x,s)>0\}.\tag{14.6} \]

14.2.2 牛顿步与仿射尺度方向

对 \(F=0\) 用牛顿法:\(J(x,\lambda,s)\,(\Delta x,\Delta\lambda,\Delta s)=-F\)。若当前点严格可行(前两块残差为零),牛顿方程为

\[ \begin{bmatrix}0&A^T&I\\A&0&0\\S&0&X\end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\lambda\\\Delta s\end{bmatrix} =\begin{bmatrix}0\\0\\-XSe\end{bmatrix}.\tag{14.7} \]

推导拆解:(14.7) 的系数矩阵就是 \(F\) 的 Jacobian,逐块求导即可。第一块 \(A^T\lambda+s-c\):对 \(x\) 求导为 0,对 \(\lambda\) 为 \(A^T\),对 \(s\) 为单位阵 \(I\)。第二块 \(Ax-b\):只对 \(x\) 有导数 \(A\)。第三块的第 \(i\) 个分量 \(x_is_i\):对 \(x_i\) 求导得 \(s_i\),对 \(s_i\) 求导得 \(x_i\),排成矩阵就是 \(S\) 和 \(X\)。 第三行的含义最直观:\((x_i+\Delta x_i)(s_i+\Delta s_i)=x_is_i+s_i\Delta x_i+x_i\Delta s_i+\Delta x_i\Delta s_i\)。牛顿法丢掉最后的二阶项,令前三项等于目标值 0,就得到 \(s_i\Delta x_i+x_i\Delta s_i=-x_is_i\)。被丢掉的 \(\Delta x_i\Delta s_i\) 后面会在 Mehrotra 校正步里被补回来。

这个纯牛顿方向称为仿射尺度方向(affine scaling direction)。问题在于:沿它走全步通常会违反 \((x,s)\ge0\),只能走很小的步 \(\alpha\ll1\),进展有限。原始–对偶方法做两项修改:

  1. 让方向偏向非负象限内部,以便走得更远;
  2. 防止 \((x,s)\) 的分量过早靠近边界。

14.2.3 中心路径

中心路径(central path) \(\mathcal C\) 是由参数 \(\tau>0\) 刻画的一条严格可行点曲线,每点 \((x_\tau,\lambda_\tau,s_\tau)\) 满足

\[ A^T\lambda+s=c,\quad Ax=b,\quad x_is_i=\tau\ (i=1,\dots,n),\quad (x,s)>0.\tag{14.8} \]

它与 KKT 条件唯一的差别是互补条件的右端从 \(0\) 变成 \(\tau\):要求所有乘积 \(x_is_i\) 相等。可以证明,\(\mathcal F^o\) 非空时每个 \(\tau>0\) 唯一确定中心路径上的一点;\(\tau\to0\) 时 (14.8) 越来越接近 (14.3),若 \(\mathcal C\) 收敛,必收敛到 LP 的原始–对偶解。

直观上,中心路径是一条"避开伪解的安全通道":沿着它走,\(x,s\) 始终严格为正,所有 \(x_is_i\) 以大致相同的速率降到零,不会有某个分量过早撞到边界。

白话解释:回忆第 13 章 (13.6):任一可行方案的成本 = 对偶给出的资源总价值 + "浪费项" \(x^Ts=\sum_ix_is_i\)。最优就是浪费为零。KKT 的互补条件要求每一项 \(x_is_i\) 都为零,但"为零"有两种方式(\(x_i=0\) 或 \(s_i=0\)),直接解方程分不清哪种是对的,还可能用负数凑出零,这就是上面的伪解。 中心路径的做法是暂时不要求为零,而是要求每一项都等于同一个正数 \(\tau\)。这时 \(x_i\) 和 \(s_i\) 都必须严格为正,伪解自然被排除。然后让 \(\tau\) 从大到小逐步降到 0:\(x_i\) 和 \(s_i\) 中"该为零的那个"会慢慢趋于零,"不该为零的那个"留在正值。哪个该为零,交给算法在过程中自然决定,不需要像单纯形法那样一个个去猜。 金融上的类比是软限额:与其在限额处设一堵硬墙,不如设一个越靠近越贵的惩罚(对数障碍 \(-\tau\log x_i\),\(x_i\to0\) 时趋于无穷),组合就会停在墙内;惩罚系数 \(\tau\) 逐步减小,组合就逐步贴近真正的最优边界。

第 17 章将看到,中心路径正是对数障碍函数 \(c^Tx-\tau\sum\log x_i\) 的极小点轨迹;\(x_is_i=\tau\) 就是障碍问题的一阶条件。

14.2.4 对偶度量与中心化参数

定义对偶度量(duality measure)

\[ \mu=\frac1n\sum_{i=1}^nx_is_i=\frac{x^Ts}{n}.\tag{14.10} \]

对可行点,\(x^Ts=c^Tx-b^T\lambda\) 就是对偶间隙,所以 \(\mu\) 直接衡量离最优还有多远。原始–对偶方法不朝 \(F=0\) 走纯牛顿步,而是朝中心路径上 \(\tau=\sigma\mu\) 的点走牛顿步,\(\sigma\in[0,1]\) 称为中心化参数(centering parameter):

\[ \begin{bmatrix}0&A^T&I\\A&0&0\\S&0&X\end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\lambda\\\Delta s\end{bmatrix} =\begin{bmatrix}0\\0\\-XSe+\sigma\mu e\end{bmatrix}.\tag{14.11} \]
  • \(\sigma=1\):中心化方向,朝 \(x_is_i=\mu\) 的中心点走,强烈偏向内部,几乎不降低 \(\mu\),但为下一步走大步打下基础;
  • \(\sigma=0\):标准牛顿步,即仿射尺度方向;
  • 多数算法取 \(\sigma\in(0,1)\),在降低 \(\mu\) 与改善中心性之间权衡。

白话解释:\(\mu\) 是平均每个变量的"浪费",\(n\mu\) 就是对偶间隙:当前方案的成本与对偶下界之差,相当于"最多还能再省多少"。\(\sigma\) 决定这一步的目标是把 \(\mu\) 降到多少:\(\sigma=0\) 是一步到位地追求零间隙,\(\sigma=1\) 是间隙不变、只把各个 \(x_is_i\) 拉平。 为什么不总是取 \(\sigma=0\)?因为如果某些 \(x_is_i\) 远小于平均值,它们离边界太近,沿牛顿方向稍走一步就会变负,只能走极小的步,反而进展很慢。适度中心化(\(\sigma>0\))先把落后的分量拉回来,下一步才能放心走大步。这有点像再平衡:先把偏离太大的头寸拉回目标附近,后续调整才有空间。

Framework 14.1(原始–对偶框架):给定 \((x^0,\lambda^0,s^0)\in\mathcal F^o\)。对 \(k=0,1,\dots\):选 \(\sigma_k\in[0,1]\),以 \(\mu_k=(x^k)^Ts^k/n\) 解 (14.11) 得方向;取步长 \(\alpha_k\) 使 \((x^{k+1},s^{k+1})>0\),更新。\(\sigma_k\) 与 \(\alpha_k\) 的选法决定了具体算法及其理论性质。

14.2.5 不可行内点法

严格可行的初始点通常很难找。**不可行内点法(infeasible-interior-point methods)**只要求 \(x^0,s^0>0\)。定义残差

\[ r_b=Ax-b,\qquad r_c=A^T\lambda+s-c,\tag{14.14} \]

步方程改为

\[ \begin{bmatrix}0&A^T&I\\A&0&0\\S&0&X\end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\lambda\\\Delta s\end{bmatrix} =\begin{bmatrix}-r_c\\-r_b\\-XSe+\sigma\mu e\end{bmatrix}.\tag{14.15} \]

由于前两块方程是线性的,若某步取全步 \(\alpha=1\),残差立刻归零,此后迭代保持可行;取 \(\alpha<1\) 时残差按 \((1-\alpha)\) 的比例缩小。实用软件都用这种形式。


14.3 路径跟踪方法

**路径跟踪方法(path-following methods)**显式地把迭代点限制在中心路径的某个邻域内,沿 \(\mathcal C\) 走向解,以 \(\mu\) 作为进展的度量,迫使 \(\mu_k\to0\)。两种常用邻域:

\[ \mathcal N_2(\theta)=\{(x,\lambda,s)\in\mathcal F^o:\ \|XSe-\mu e\|_2\le\theta\mu\},\quad\theta\in[0,1),\tag{14.16} \]
\[ \mathcal N_{-\infty}(\gamma)=\{(x,\lambda,s)\in\mathcal F^o:\ x_is_i\ge\gamma\mu,\ \forall i\},\quad\gamma\in(0,1].\tag{14.17} \]

典型取值 \(\theta=0.5\)、\(\gamma=10^{-3}\)。\(\mathcal N_{-\infty}(\gamma)\) 只要求每个乘积不低于平均值的 \(\gamma\) 倍,非常宽松,\(\gamma\) 很小时几乎覆盖整个可行域;\(\mathcal N_2(\theta)\) 严格得多。与一般非线性方程的同伦法相比,同伦法停留在路径的一个"细管"里,而原始–对偶方法的邻域是锥形的:\(\mu\) 大时宽松,\(\mu\to0\) 时收窄。

白话解释:两个邻域都在问"各个 \(x_is_i\) 是否足够均匀"。\(\mathcal N_2(\theta)\) 要求它们与平均值 \(\mu\) 的整体偏差(欧氏距离)不超过 \(\theta\mu\);\(\mathcal N_{-\infty}(\gamma)\) 只要求没有哪一项低于平均值的 \(\gamma\) 倍,相当于"只设下限、不设上限"的集中度规则。例:\(n=2\)、\(x_1s_1=0.1\)、\(x_2s_2=1.9\),则 \(\mu=1\),\(\|XSe-\mu e\|_2=\sqrt{0.81+0.81}\approx1.27\),不在 \(\mathcal N_2(0.5)\) 里;但 \(0.1\ge10^{-3}\times1\),在 \(\mathcal N_{-\infty}(10^{-3})\) 里。同伦法是解非线性方程的一类方法:从一个容易解的方程出发,逐步变形到目标方程,沿途跟踪解的轨迹。

Algorithm 14.2(长步路径跟踪,long-step path-following):给定 \(\gamma\in(0,1)\),\(0<\sigma_{\min}<\sigma_{\max}<1\),初始点 \(\in\mathcal N_{-\infty}(\gamma)\)。每步选 \(\sigma_k\in[\sigma_{\min},\sigma_{\max}]\),解 (14.11),取 \(\alpha_k\) 为 \([0,1]\) 中使新点仍在 \(\mathcal N_{-\infty}(\gamma)\) 内的最大值,更新。

\(\sigma_{\min}>0\) 保证每个方向一开始先改善中心性(离开邻域边界),所以总能走一个不太小的步。下面证明它是多项式算法。

14.3.1 复杂度分析

整条证明链只用初等不等式:引理 14.1 → 引理 14.2 → 定理 14.3 → 定理 14.4。

引理 14.1:\(u,v\in\mathbb R^n\),\(u^Tv\ge0\),则 \(\|UVe\|\le2^{-3/2}\|u+v\|^2\)。

证明思路:对 \(\alpha\beta\ge0\) 有 \(\sqrt{|\alpha\beta|}\le\frac12|\alpha+\beta|\)(算术–几何平均)。把指标分成 \(u_iv_i\ge0\) 与 \(<0\) 两组,由 \(u^Tv\ge0\),前一组的和不小于后一组,于是 \(\|UVe\|\le\sqrt2\,\|[u_iv_i]_{\mathcal P}\|_1\le\sqrt2\sum_{\mathcal P}\frac14(u_i+v_i)^2\le2^{-3/2}\|u+v\|^2\)。∎

引理 14.2:若 \((x,\lambda,s)\in\mathcal N_{-\infty}(\gamma)\),则 (14.11) 的步满足

\[ \|\Delta X\Delta Se\|\le2^{-3/2}(1+1/\gamma)\,n\mu. \]

证明思路:由 (14.11) 前两行,\(\Delta x\in\mathrm{Null}(A)\),\(\Delta s=-A^T\Delta\lambda\),故 \(\Delta x^T\Delta s=0\)(14.35)。第三行乘 \((XS)^{-1/2}\),记 \(D=X^{1/2}S^{-1/2}\):\(D^{-1}\Delta x+D\Delta s=(XS)^{-1/2}(-XSe+\sigma\mu e)\)。对 \(u=D^{-1}\Delta x\)、\(v=D\Delta s\)(\(u^Tv=0\))用引理 14.1,再利用 \(x_is_i\ge\gamma\mu\) 估计 \(\sum1/(x_is_i)\le n/(\gamma\mu)\),得到界 \(2^{-3/2}(1-2\sigma+\sigma^2/\gamma)n\mu\le2^{-3/2}(1+1/\gamma)n\mu\)。∎

定理 14.3:存在与 \(n\) 无关的常数 \(\delta\) 使

\[ \mu_{k+1}\le\Big(1-\frac\delta n\Big)\mu_k.\tag{14.37} \]

证明思路。第一步,证明步长下界 \(\alpha_k\ge2^{3/2}\frac{\sigma_k}n\gamma\frac{1-\gamma}{1+\gamma}\):展开 \(x_i(\alpha)s_i(\alpha)=x_is_i+\alpha(x_i\Delta s_i+s_i\Delta x_i)+\alpha^2\Delta x_i\Delta s_i\),用第三行方程和引理 14.2 给出下界,与邻域条件 \(x_i(\alpha)s_i(\alpha)\ge\gamma\mu(\alpha)\) 比较即得。第二步,利用 \(\Delta x^T\Delta s=0\),

\[ \mu_{k+1}=(1-\alpha_k(1-\sigma_k))\mu_k\le\Big(1-\frac{2^{3/2}}n\gamma\frac{1-\gamma}{1+\gamma}\sigma_k(1-\sigma_k)\Big)\mu_k.\tag{14.43–14.44} \]

\(\sigma(1-\sigma)\) 在区间端点取最小值,取 \(\delta=2^{3/2}\gamma\frac{1-\gamma}{1+\gamma}\min\{\sigma_{\min}(1-\sigma_{\min}),\sigma_{\max}(1-\sigma_{\max})\}\) 即可。∎

推导拆解:(14.43) 中 \(\mu_{k+1}=(1-\alpha(1-\sigma))\mu_k\) 这个等式值得自己推一遍,它也解释了 14.7.2 日志里 \(\mu\) 的下降速度。 第一步,展开新点的内积:\((x+\alpha\Delta x)^T(s+\alpha\Delta s)=x^Ts+\alpha(s^T\Delta x+x^T\Delta s)+\alpha^2\Delta x^T\Delta s\)。 第二步,把 (14.11) 第三行 \(s_i\Delta x_i+x_i\Delta s_i=-x_is_i+\sigma\mu\) 对 \(i\) 求和:\(s^T\Delta x+x^T\Delta s=-x^Ts+n\sigma\mu=-(1-\sigma)n\mu\)。 第三步,\(\Delta x^T\Delta s=0\)(\(\Delta x\) 在 \(A\) 的零空间里,\(\Delta s=-A^T\Delta\lambda\),所以 \(\Delta x^T\Delta s=-(A\Delta x)^T\Delta\lambda=0\))。 合起来 \(n\mu_{k+1}=n\mu_k-\alpha(1-\sigma)n\mu_k\)。读法:走全步 \(\alpha=1\) 时,间隙恰好按 \(\sigma\) 的比例缩小;\(\sigma=0.01\) 就是每步缩小 100 倍。

定理 14.4(复杂度):若初始点在 \(\mathcal N_{-\infty}(\gamma)\) 中且 \(\mu_0\le1/\epsilon^\kappa\),则存在 \(K=O(n\log1/\epsilon)\) 使 \(k\ge K\) 时 \(\mu_k\le\epsilon\)。

证明:对 (14.37) 取对数递推,用 \(\log(1+\beta)\le\beta\):\(\log\mu_k\le-k\delta/n+\kappa\log\frac1\epsilon\)。要使右端 \(\le\log\epsilon\),只需 \(k\ge K=\frac{(1+\kappa)n}\delta\log\frac1\epsilon\)。∎(原书证明中此处误印为 \(n\omega\),应为 \(n\)。)

这个界是理论保证;实际算法(下一节)的迭代次数远少于 \(O(n)\),基本与规模无关。

金融直觉:(14.37) 说 \(\mu\) 每步至少按固定比例 \(\delta/n\) 下降,这是几何(复利式)衰减,和按固定比例摊销的贷款余额一样。\(k\) 步后 \(\mu_k\le(1-\delta/n)^k\mu_0\approx e^{-k\delta/n}\mu_0\),要降到 \(\epsilon\) 只需 \(k\approx\frac n\delta\ln\frac{\mu_0}\epsilon\)。关键在 \(\ln\frac1\epsilon\):精度每提高 10 倍,只多花一个固定的步数,正如资金翻倍所需的年数(72 法则)不依赖本金大小。单纯形法的最坏情况则是"顶点个数"那样的指数增长。

14.3.2 其他原始–对偶方法(简介)

  • 短步路径跟踪:取略小于 1 的保守 \(\sigma\),使全步 \(\alpha=1\) 不离开严格的 \(\mathcal N_2\) 邻域。理论漂亮(\(O(\sqrt n\log1/\epsilon)\)),但进展慢。
  • Mizuno–Todd–Ye 预测–校正法:使用两个嵌套的 \(\mathcal N_2\) 邻域,预测步(\(\sigma=0\))从内邻域走到外邻域边界以大幅降低 \(\mu\),校正步(\(\sigma=1\),\(\alpha=1\))拉回内邻域。\(\mu_k\) 超线性收敛到零。
  • 势函数下降法:不显式跟踪中心路径,而用 Tanabe–Todd–Ye 势函数
\[ \Phi_\rho(x,s)=\rho\log x^Ts-\sum_{i=1}^n\log x_is_i,\quad\rho>n,\tag{14.30} \]

要求每步固定量下降。第一项推动对偶间隙下降,第二项阻止单个乘积独立趋零。取 \(\sigma_k\equiv n/(n+\sqrt n)\) 即可保证 \(\Phi_\rho\) 每步固定下降。


14.4 实用算法:Mehrotra 预测–校正

几乎所有通用 LP 内点代码都基于 Mehrotra 预测–校正算法(predictor–corrector),它有两个特点:

  1. 在方向上加一个校正步(corrector),补偿线性化忽略的二阶项,更紧密地跟踪通往解的轨迹;
  2. 自适应地选择中心化参数 \(\sigma\):先试算纯牛顿方向,若它能大幅降低 \(\mu\),就少中心化;否则多中心化。

具体步骤(每步只做一次矩阵分解,三个右端共用):

  1. 预测步:在 (14.15) 中取 \(\sigma=0\),
\[ \begin{bmatrix}0&A^T&I\\A&0&0\\S&0&X\end{bmatrix} \begin{bmatrix}\Delta x^{\rm aff}\\\Delta\lambda^{\rm aff}\\\Delta s^{\rm aff}\end{bmatrix} =\begin{bmatrix}-r_c\\-r_b\\-XSe\end{bmatrix}.\tag{14.20} \]
  1. 沿预测方向不违反非负性的最大步长:
\[ \alpha^{\rm pri}_{\rm aff}=\min\Big(1,\min_{i:\Delta x^{\rm aff}_i<0}-\frac{x_i}{\Delta x^{\rm aff}_i}\Big),\quad \alpha^{\rm dual}_{\rm aff}=\min\Big(1,\min_{i:\Delta s^{\rm aff}_i<0}-\frac{s_i}{\Delta s^{\rm aff}_i}\Big),\tag{14.21} \]
\[ \mu_{\rm aff}=(x+\alpha^{\rm pri}_{\rm aff}\Delta x^{\rm aff})^T(s+\alpha^{\rm dual}_{\rm aff}\Delta s^{\rm aff})/n.\tag{14.22} \]

(原书 (14.22) 中第二个因子的步长也印成 \(\alpha^{\rm pri}_{\rm aff}\),按 Mehrotra 原意应为对偶步长。)

  1. 自适应中心化:\(\sigma=(\mu_{\rm aff}/\mu)^3\)。预测方向效果好时 \(\mu_{\rm aff}\ll\mu\),\(\sigma\) 接近 0。

  2. 校正 + 中心化:真实的互补条件是 \((x_i+\Delta x_i)(s_i+\Delta s_i)=\sigma\mu\),线性化丢掉了二阶项 \(\Delta x_i\Delta s_i\)。用预测步的 \(\Delta x^{\rm aff}_i\Delta s^{\rm aff}_i\) 近似补上:

\[ \begin{bmatrix}0&A^T&I\\A&0&0\\S&0&X\end{bmatrix} \begin{bmatrix}\Delta x\\\Delta\lambda\\\Delta s\end{bmatrix} =\begin{bmatrix}-r_c\\-r_b\\-XSe-\Delta X^{\rm aff}\Delta S^{\rm aff}e+\sigma\mu e\end{bmatrix}.\tag{14.23} \]
  1. 原始与对偶分别取步长:
\[ \alpha^{\rm pri}_k=\min(1,\eta\,\alpha^{\rm pri}_{\max}),\qquad \alpha^{\rm dual}_k=\min(1,\eta\,\alpha^{\rm dual}_{\max}),\tag{14.25} \]

\(\eta\in[0.9,1)\),接近解时 \(\eta\to1\) 以加速收敛。\(x\) 用原始步长更新,\((\lambda,s)\) 用对偶步长更新。

金融直觉:Mehrotra 的"预测 + 校正"和"久期 + 凸性"的思路一样。预测步是一阶近似,相当于只用久期估算债券价格变化;它丢掉了二阶项 \(\Delta x_i\Delta s_i\)。校正步用预测步算出来的 \(\Delta x^{\rm aff}_i\Delta s^{\rm aff}_i\) 当作二阶项的估计补回去,相当于加上凸性修正。两者用的是同一个系数矩阵,只换右端,所以只需一次矩阵分解,额外成本很低。 \(\sigma=(\mu_{\rm aff}/\mu)^3\) 的直觉是"看路况决定车速":试走一步发现间隙能降得很多(\(\mu_{\rm aff}/\mu\) 小),说明前路通畅,就少做中心化;降得不多,说明离边界太近,就多做中心化。三次方是经验选择,没有理论推导。 原始、对偶分别取步长,是因为 \(x\) 与 \(s\) 离各自边界的距离不同,强制同一步长会让离边界远的一方白白少走。

注意:上述形式的 Mehrotra 算法没有收敛理论,甚至能构造出发散的例子。可以加保护措施纳入 14.3 节的收敛框架,但多数软件不这么做,因为它在实践中表现极好。现代软件还常加 Gondzio 的"高阶校正"。


14.5 每步的线性代数

主要计算量在于解 (14.15)、(14.20)、(14.23)。系数矩阵大而稀疏,但可以化为更紧凑的对称形式。

增广系统(augmented system):由于 \(x,s>0\),从第三行消去 \(\Delta s\):

\[ \begin{bmatrix}0&A\\A^T&-D^{-2}\end{bmatrix} \begin{bmatrix}\Delta\lambda\\\Delta x\end{bmatrix} =\begin{bmatrix}-r_b\\-r_c+s-\sigma\mu X^{-1}e\end{bmatrix},\qquad D=S^{-1/2}X^{1/2}.\tag{14.26–14.27} \]

正规方程(normal equations):再消去 \(\Delta x\),

\[ AD^2A^T\Delta\lambda=-r_b+A(-S^{-1}Xr_c+x-\sigma\mu S^{-1}e),\tag{14.28a} \]
\[ \Delta s=-r_c-A^T\Delta\lambda,\qquad \Delta x=-x+\sigma\mu S^{-1}e-S^{-1}X\Delta s.\tag{14.28b,c} \]

之所以叫"正规方程",是因为 (14.28a) 可看作系数矩阵为 \(DA^T\) 的最小二乘问题的正规方程(本册第 10 章 10.2.3 节)。多数实现基于 (14.28):对 \(AD^2A^T\) 做稀疏 Cholesky 分解,再回代恢复 \(\Delta s,\Delta x\)。

推导拆解:从 (14.15) 消元得到 (14.28),记第三行右端为 \(-r_{xs}\),\(r_{xs}=XSe-\sigma\mu e\)。 第一步,由第一行解出 \(\Delta s=-r_c-A^T\Delta\lambda\),这就是 (14.28b)。 第二步,第三行 \(S\Delta x+X\Delta s=-r_{xs}\),两边左乘 \(S^{-1}\)(\(s>0\) 所以可逆):\(\Delta x=-S^{-1}r_{xs}-S^{-1}X\Delta s\)。注意 \(S^{-1}r_{xs}=x-\sigma\mu S^{-1}e\),这就是 (14.28c)。 第三步,把第一步的 \(\Delta s\) 代入第二步,得 \(\Delta x=-S^{-1}r_{xs}+D^2r_c+D^2A^T\Delta\lambda\)(\(D^2=S^{-1}X\))。 第四步,代入第二行 \(A\Delta x=-r_b\),把含 \(\Delta\lambda\) 的项留在左边,就得到 (14.28a)。 和读者熟悉的回归对照:\(AD^2A^T\) 的形状与加权最小二乘(WLS)的 \(X^TWX\) 相同,权重 \(D^2_{ii}=x_i/s_i\)。接近最优时,"该为正"的变量 \(x_i/s_i\to\infty\),"该为零"的变量 \(x_i/s_i\to0\),权重悬殊越来越大,这正是下面说的后期病态。 Cholesky 分解是把对称正定矩阵写成 \(LL^T\)(\(L\) 下三角)的方法,之后解方程只需两次回代,可以理解为对称矩阵专用的、更快更稳的"求逆"。

两个需要注意的数值问题:

  • 后期病态。接近解时,\(x_i\to0\)、\(s_i>0\) 的分量使 \(D^2_{ii}\to0\),反之 \(D^2_{ii}\to\infty\),\(AD^2A^T\) 极度病态甚至数值奇异。通用 Cholesky 需要小改动(如遇到极小主元时置为大数)。奇妙的是,由于结构特殊,算出的方向仍然足够好。
  • 稠密列。\(A\) 中只要有一列稠密,\(AD^2A^T\) 就会完全稠密。增广系统 (14.26) 没有这个问题,也能自然处理自由变量,但需要稀疏对称不定分解,更复杂。

量化提示:组合优化里的预算约束 \(\mathbf 1^Tw=1\)、因子暴露约束 \(B^Tw=0\) 都是稠密行;情景型模型(CVaR、MAD、\(\ell_1\) 跟踪)的情景收益矩阵则整块稠密。这正是 14.7 节实验中内点法每步代价偏高的原因。自己写求解器时,要么用增广系统,要么利用 Sherman–Morrison–Woodbury 公式(附录 A)把稠密的低秩部分单独处理。


14.6 推广(简介)

原始–对偶框架可以推广到:

  • 单调线性互补问题(LCP):求 \(x,s\) 使 \(s=Mx+q\),\((x,s)\ge0\),\(x^Ts=0\),\(M\) 半正定。美式期权定价的离散化(障碍问题)就是 LCP。
  • 凸二次规划 \(\min c^Tx+\frac12x^TGx\) s.t. \(Ax=b,\ x\ge0\),\(G\succeq0\):第 16b 章 16.9 节(原书 §16.7)详细讨论,均值–方差组合优化即属此类。
  • 非线性规划:把 KKT 写成类似 (14.3) 的形式,用牛顿法并截短步长保持正性,第 17 章 17.3 节(原书 §17.2)讨论。
  • 半定规划(SDP):变量为须半正定的对称矩阵。最近相关阵修复、某些稳健组合问题是 SDP。

LCP 与凸 QP 的推广保留了 LP 算法的收敛性与多项式复杂度。


14.7 量化实战

14.7.1 在哪里用

  • 读懂求解器日志。MOSEK、Gurobi barrier、CPLEX barrier、HiGHS-IPM 的每行日志通常打印原始残差 \(\|r_b\|\)、对偶残差 \(\|r_c\|\)、对偶间隙或 \(\mu\)。理解本章后你会知道:残差先降到零(全步之后保持),\(\mu\) 随后以几乎固定的比例下降;若 \(\mu\) 停滞而残差不降,多半是问题不可行或数值病态。
  • 对偶间隙做停止准则。内点法天然给出对偶界,可以量化"当前组合离最优还有多远",适合盘中需要时效的再优化:间隙小于预期交易成本即可提前停止。
  • 顶点解与交叉(crossover)。内点法给出的是内部近似解,若需要精确的顶点(稀疏)解,求解器会做 crossover。对需要严格稀疏持仓或要拿基状态做后续分析的场景,要打开这一选项或改用单纯形。

14.7.2 代码一:自己实现 Mehrotra 预测–校正

按原书习题 14.12 的方法构造已知解的随机 LP:\(x^*\) 前 \(m\) 个分量为正、其余为零,\(s^*\) 相反,\(c=A^T\lambda^*+s^*\),\(b=Ax^*\)。

import numpy as np
from scipy.optimize import linprog

def mehrotra_lp(A, b, c, tol=1e-9, eta=0.99, max_iter=100, verbose=True):
    """Algorithm 14.3:Mehrotra 预测-校正原始-对偶内点法,标准形 LP。
    线性系统用正规方程 (14.28):A D^2 A^T dlam = rhs,D^2 = X S^{-1}。"""
    m, n = A.shape
    x, lam, s = np.ones(n) * 10, np.zeros(m), np.ones(n) * 10   # 只要求 x,s>0
    def step_len(v, dv):
        neg = dv < 0
        return min(1.0, np.min(-v[neg] / dv[neg])) if neg.any() else 1.0
    def solve(rc, rb, rxs):
        # 解 [0 A^T I; A 0 0; S 0 X][dx;dl;ds] = [-rc; -rb; -rxs]
        d2 = x / s
        M = (A * d2) @ A.T
        rhs = -rb + A @ (-d2 * rc + rxs / s)
        dl = np.linalg.solve(M, rhs)
        ds = -rc - A.T @ dl
        dx = -(rxs + x * ds) / s
        return dx, dl, ds
    for k in range(max_iter):
        rb, rc = A @ x - b, A.T @ lam + s - c
        mu = x @ s / n
        if verbose:
            print(f"{k:2d}  mu={mu:9.2e}  |rb|={np.linalg.norm(rb):8.1e}  "
                  f"|rc|={np.linalg.norm(rc):8.1e}  obj={c@x:12.6f}")
        if mu < tol and np.linalg.norm(rb) < tol * (1 + np.linalg.norm(b)) \
                and np.linalg.norm(rc) < tol * (1 + np.linalg.norm(c)):
            return x, lam, s, k
        # 预测步 (14.20)
        dxa, dla, dsa = solve(rc, rb, x * s)
        ap, ad = step_len(x, dxa), step_len(s, dsa)
        mu_aff = (x + ap * dxa) @ (s + ad * dsa) / n          # (14.22)
        sigma = (mu_aff / mu) ** 3                            # 自适应中心化
        # 校正 + 中心化 (14.23)
        dx, dl, ds = solve(rc, rb, x * s + dxa * dsa - sigma * mu)
        ap = min(1.0, eta * step_len(x, dx))                  # (14.25)
        ad = min(1.0, eta * step_len(s, ds))
        x, lam, s = x + ap * dx, lam + ad * dl, s + ad * ds   # 原始/对偶分别步长
    raise RuntimeError("not converged")

# 按习题 14.12 构造已知解的随机 LP
rng = np.random.default_rng(0)
m, n = 50, 120
A = rng.standard_normal((m, n))
xs = np.zeros(n); xs[:m] = rng.uniform(0.5, 2, m)
ss = np.zeros(n); ss[m:] = rng.uniform(0.5, 2, n - m)
lam_s = rng.standard_normal(m)
c, b = A.T @ lam_s + ss, A @ xs
x, lam, s, it = mehrotra_lp(A, b, c)
print("迭代次数:", it, " ||x - x*|| =", np.linalg.norm(x - xs),
      " 对偶间隙 c'x-b'lam =", c @ x - b @ lam)
r = linprog(c, A_eq=A, b_eq=b, bounds=[(0, None)] * n, method="highs-ipm")
print("HiGHS-IPM 目标:", r.fun, " 自写目标:", c @ x, " HiGHS 迭代:", r.nit)

输出:

 0  mu= 1.00e+02  |rb|= 7.9e+02  |rc|= 1.2e+02  obj= 1373.510406
 1  mu= 2.42e+01  |rb|= 9.6e+01  |rc|= 3.3e+01  obj=  632.328463
 2  mu= 3.39e+00  |rb|= 9.6e-01  |rc|= 3.3e-01  obj=  344.738557
 3  mu= 8.47e-01  |rb|= 2.2e-01  |rc|= 8.3e-02  obj=   97.131765
 4  mu= 4.19e-01  |rb|= 1.0e-01  |rc|= 2.3e-02  obj=   66.559230
 5  mu= 2.43e-01  |rb|= 1.3e-02  |rc|= 6.7e-03  obj=   51.791762
 6  mu= 5.45e-02  |rb|= 2.0e-03  |rc|= 1.5e-03  obj=   37.154846
 7  mu= 1.32e-02  |rb|= 4.0e-04  |rc|= 3.1e-04  obj=   34.285874
 8  mu= 9.04e-04  |rb|= 3.3e-05  |rc|= 1.1e-05  obj=   33.516065
 9  mu= 9.53e-06  |rb|= 3.4e-07  |rc|= 1.2e-07  obj=   33.441618
10  mu= 9.53e-08  |rb|= 3.4e-09  |rc|= 1.2e-09  obj=   33.440846
11  mu= 9.53e-10  |rb|= 3.4e-11  |rc|= 1.2e-11  obj=   33.440838
迭代次数: 11  ||x - x*|| = 9.56524778620355e-08  对偶间隙 c'x-b'lam = 1.1435405156134948e-07
HiGHS-IPM 目标: 33.44083822507707  自写目标: 33.44083830303802  HiGHS 迭代: 9

这就是一份"求解器日志"。前几步原始、对偶残差和 \(\mu\) 同步下降;第 8 步以后每步 \(\mu\) 缩小约 100 倍——步长 \(\eta=0.99\) 接近全步、\(\sigma\) 接近 0 时,\(\mu\) 每步乘以约 \(1-\eta\)。从远离可行的起点出发,11 次迭代就把对偶间隙降到 \(10^{-7}\),与 HiGHS 的结果一致。

14.7.3 代码二:\(\ell_1\) 指数跟踪——单纯形法与内点法的迭代次数

指数增强 / 被动跟踪中,常用 MAD(平均绝对偏差)度量跟踪误差:

\[ \min_w\ \frac1T\sum_{t=1}^T|R_tw-r_{t}^{\rm idx}|\quad\text{s.t.}\quad\mathbf 1^Tw=1,\ 0\le w\le0.05. \]

把每期误差 \(e_t\) 拆成 \(u_t-v_t\)(第 13 章技巧),就是一个 LP。

import numpy as np, time
from scipy.optimize import linprog
from scipy.sparse import hstack, vstack, eye, csr_matrix

def l1_tracking(n, T, seed=1):
    """指数跟踪:min (1/T) sum_t |R_t w - r_idx,t|, s.t. sum w = 1, 0<=w<=0.05
    拆分 e_t = u_t - v_t, u,v>=0(第 13 章的 x = x+ - x- 技巧)"""
    rng = np.random.default_rng(seed)
    f = 0.01 * rng.standard_normal(T)
    R = np.outer(f, rng.uniform(0.6, 1.4, n)) + 0.02 * rng.standard_normal((T, n))
    idx_w = rng.dirichlet(np.full(n, 0.2))   # 头部集中的指数权重
    r_idx = R @ idx_w
    c = np.r_[np.zeros(n), np.full(2 * T, 1.0 / T)]
    A_eq = vstack([hstack([csr_matrix(R), -eye(T), eye(T)]),
                   csr_matrix(np.r_[np.ones(n), np.zeros(2 * T)][None, :])])
    b_eq = np.r_[r_idx, 1.0]
    bounds = [(0, 0.05)] * n + [(0, None)] * (2 * T)
    out = {}
    for meth in ["highs-ds", "highs-ipm"]:
        t0 = time.perf_counter()
        r = linprog(c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method=meth)
        out[meth] = (r.nit, time.perf_counter() - t0, r.fun)
    return out

print(f"{'n':>5}{'T':>6} | {'单纯形迭代':>8}{'用时s':>8} | {'内点迭代':>8}{'用时s':>8} | 跟踪误差(日均|e|)")
for n, T in [(50, 250), (200, 500), (500, 1000)]:
    o = l1_tracking(n, T)
    print(f"{n:5d}{T:6d} | {o['highs-ds'][0]:10d}{o['highs-ds'][1]:8.2f} | "
          f"{o['highs-ipm'][0]:10d}{o['highs-ipm'][1]:8.2f} | {o['highs-ipm'][2]*1e4:.2f}bp")

输出:

    n     T |    单纯形迭代     用时s |     内点迭代     用时s | 跟踪误差(日均|e|)
   50   250 |        400    0.01 |         21    0.02 | 22.31bp
  200   500 |       1007    0.17 |         21    0.20 | 0.52bp
  500  1000 |       2999    2.26 |         23    1.15 | 1.96bp

(用时一栏随机器而异,迭代次数是确定的。)规律很清楚:单纯形迭代次数随规模大致线性增长(几百到几千),内点法稳定在 21–23 次。用时则取决于每步代价:本例情景收益矩阵 \(R\) 是稠密的,内点法每步的 \(AD^2A^T\) 分解很贵,所以小问题上单纯形更快、大问题上内点法反超。这也说明为什么商业求解器默认会"并发"运行单纯形和内点法,谁先完成用谁。跟踪误差一栏说明了个股 5% 上限的作用:头部权重超过 5% 的成分股无法完全复制,误差不为零。


本章小结

原始–对偶内点法把 LP 的 KKT 条件写成 \(F(x,\lambda,s)=0\) 加 \((x,s)\ge0\),对等式部分用牛顿法,同时严格保持 \((x,s)>0\) 以避开伪解。关键概念是中心路径(所有 \(x_is_i\) 相等的严格可行曲线)、对偶度量 \(\mu=x^Ts/n\) 和中心化参数 \(\sigma\):方向在纯牛顿(\(\sigma=0\))和中心化(\(\sigma=1\))之间权衡。路径跟踪方法让迭代点留在中心路径的锥形邻域里,长步算法每步 \(\mu\) 至少缩小 \(1-\delta/n\),因此是多项式的。实用的 Mehrotra 预测–校正算法用预测步自适应选 \(\sigma=(\mu_{\rm aff}/\mu)^3\),再加二阶校正,一次分解、原始对偶分别取步长,虽无收敛理论但实践中极好,迭代次数几乎不随规模增长。每步的核心是解正规方程 \(AD^2A^T\Delta\lambda=\cdots\),要注意后期病态和稠密列。这一框架直接推广到凸二次规划(第 16 章)和非线性规划(第 17 章)。

概念 公式 / 要点
KKT 映射 \(F=(A^T\lambda+s-c,\ Ax-b,\ XSe)=0\),\((x,s)\ge0\)
中心路径 \(A^T\lambda+s=c\),\(Ax=b\),\(x_is_i=\tau\),\((x,s)>0\)
对偶度量 \(\mu=x^Ts/n\)(可行时 \(=\) 对偶间隙\(/n\))
步方程 \(\begin{bmatrix}0&A^T&I\\A&0&0\\S&0&X\end{bmatrix}\Delta=\begin{bmatrix}-r_c\\-r_b\\-XSe+\sigma\mu e\end{bmatrix}\)
邻域 \(\mathcal N_2(\theta)\):\(|XSe-\mu e|\le\theta\mu\);\(\mathcal N_{-\infty}(\gamma)\):\(x_is_i\ge\gamma\mu\)
复杂度 长步:\(\mu_{k+1}\le(1-\delta/n)\mu_k\),\(O(n\log1/\epsilon)\) 次迭代
Mehrotra 预测(\(\sigma=0\))→ \(\sigma=(\mu_{\rm aff}/\mu)^3\) → 校正项 \(-\Delta X^{\rm aff}\Delta S^{\rm aff}e\) → 原始/对偶步长 \(\eta\alpha_{\max}\)
正规方程 \(AD^2A^T\Delta\lambda=\cdots\),\(D^2=XS^{-1}\);稀疏 Cholesky
势函数 \(\Phi_\rho=\rho\log x^Ts-\sum\log x_is_i\),\(\rho>n\)

练习

基础

  1. 验证 14.2.1 节的伪解例子:写出 \(F\) 的三个分量并逐一代入。再找出该问题 \(F=0\) 的全部解。
  2. 证明:(i) \(\theta_1<\theta_2\) 时 \(\mathcal N_2(\theta_1)\subset\mathcal N_2(\theta_2)\);\(\gamma_2\le\gamma_1\) 时 \(\mathcal N_{-\infty}(\gamma_1)\subset\mathcal N_{-\infty}(\gamma_2)\);(ii) \(\gamma\le1-\theta\) 时 \(\mathcal N_2(\theta)\subset\mathcal N_{-\infty}(\gamma)\);(iii) \(\mathcal N_{-\infty}(1)=\mathcal N_2(0)=\mathcal C\)。 提示:(ii) \(|x_is_i-\mu|\le\|XSe-\mu e\|_2\le\theta\mu\)。
  3. 证明 (14.11) 的系数矩阵非奇异当且仅当 \(A\) 行满秩(设 \(x,s>0\))。
  4. 证明 \(AD^2A^T\) 对称正定当且仅当 \(A\) 行满秩(\(D\) 对角元全正)。若 \(D\) 恰有 \(m\) 个正对角元、其余为零,结论是否仍成立?这和内点法后期病态有什么联系?
  5. 在 14.7.2 的代码中把 \(\sigma\) 固定为 0(纯仿射尺度)和固定为 0.5,比较迭代次数。

进阶

  1. 证明 Tanabe–Todd–Ye 势函数满足:若某个 \(x_is_i\to0\) 而 \(\mu\) 不趋于零,则 \(\Phi_\rho\to\infty\)。
  2. 对含自由变量 \(y\) 的 LP \(\min c^Tx+d^Ty\) s.t. \(A_1x+A_2y=b\),\(x\ge0\),写出最优性条件、原始–对偶步方程和增广系统形式,解释为什么它不能化为对称正定的正规方程。
  3. 对轨迹 \(\mathcal H\):\(F(\hat x(\tau),\hat\lambda(\tau),\hat s(\tau))=(1-\tau)(r_c,r_b,XSe)\),求 \(\tau=0\) 处一阶、二阶导数满足的方程,说明 Mehrotra 校正项 \(-\Delta X^{\rm aff}\Delta S^{\rm aff}e\) 正是二阶 Taylor 项。
  4. 在 14.7.3 的跟踪问题中,分别固定 \(T\) 增大 \(n\)、固定 \(n\) 增大 \(T\),记录内点法的迭代次数和每次迭代的平均用时。用正规方程 \(AD^2A^T\) 的维数(等式约束个数 \(T+1\))和稠密程度解释你看到的规律。 提示:迭代次数几乎不变;每步代价主要由 \((T+1)\times(T+1)\) 稠密矩阵的分解决定。
  5. 用 14.7.2 的代码求解一个不可行的 LP(如 \(x_1+x_2=-1,\ x\ge0\)),观察 \(\mu\) 与残差的行为,总结如何从日志判断不可行。

原书推荐习题:14.1(伪解)、14.2、14.5(中心路径与邻域)、14.9、14.11(正规方程与增广系统的适用条件)、14.10(预测–校正的 Taylor 展开)、14.12(亲手实现 Mehrotra 算法,最有实践价值)。原书第 14 章共 14.1–14.12 题。


原书对照

本章内容 原书位置 PDF 页码
14.1 动机与历史 第 14 章引言 PDF p.412–413
14.2 原始–对偶框架、中心路径、Framework 14.1、不可行内点法 §14.1 Primal–Dual Methods,式 (14.1)–(14.15) PDF p.413–419
14.3 路径跟踪、邻域、Algorithm 14.2 §14.1 Path-Following Methods,式 (14.16)–(14.19) PDF p.419–421
14.4–14.5 Mehrotra 预测–校正、Algorithm 14.3、线性代数 §14.2 A Practical Primal–Dual Algorithm,式 (14.20)–(14.28) PDF p.421–426
14.3.2、14.6 其他算法与推广 §14.3 Other Primal–Dual Algorithms and Extensions,式 (14.29)–(14.32) PDF p.426–428
14.3.1 复杂度分析 §14.4 Analysis of Algorithm 14.2,引理 14.1–14.2,定理 14.3–14.4 PDF p.428–433
注释与参考 Notes and References PDF p.433–434
习题 14.1–14.12 Exercises PDF p.434–436

更正说明:原书 (14.22) 第二个因子的步长应为对偶步长;定理 14.4 证明中的 \(n\omega\) 应为 \(n\)。原书正文页码 = PDF 页码减 19(已用 PDF 页眉核对,第 12–16 章均如此)。