量化交易中文教材

第 16a 章 二次规划:KKT 系统与有效集方法

原书第 16 章是组合优化最直接的数学工具,本册拆为第 16a、16b 两章。上篇(第 16a 章,本文件)讲等式约束 QP、KKT 系统的各种解法、不等式 QP 的最优性条件和有效集方法;下篇(第 16b 章,16b_二次规划_梯度投影内点法与组合优化实战.md)讲梯度投影法、内点法、对偶,并给出带换手、行业约束的完整组合优化实例。

学习目标

读完本章上篇,你应当能够:

  1. 写出 QP 的一般形式,识别凸 QP 与非凸 QP,并把 Markowitz 均值–方差模型写成 QP。
  2. 推导等式约束 QP 的 KKT 系统,说明 \(A\) 行满秩加约化 Hessian \(Z^TGZ\) 正定时解唯一且全局最优;知道约化 Hessian 不正定时会发生什么。
  3. 比较 KKT 系统的四类解法(对称不定分解、值空间法、零空间法、共轭基方法),能按问题结构(\(G\) 是否易逆、\(m\) 与 \(n-m\) 的大小)选择;会用惯性 \((n,m,0)\) 检查约化 Hessian 的正定性。
  4. 写出不等式 QP 的 KKT 条件,理解退化(线性相关、弱有效约束)的含义和危害。
  5. 手算并编程实现凸 QP 的原始有效集方法(工作集、阻挡约束、删去最负乘子),理解有限终止的论证和热启动的价值。
  6. 了解不定 QP 的惯性控制有效集方法和它可能的失败方式。

读前导读

这一章在解决什么问题

二次规划(QP)就是"目标是二次函数、约束是线性"的优化问题。对读者来说,它有一个再熟悉不过的名字:均值–方差组合优化。组合方差 \(w^T\Sigma w\) 是权重的二次函数,预算、只做多、个股上限、行业偏离全是线性约束。所以本章是整个第 04 册里与组合管理关系最直接的一章。

本章分两半。前一半处理只有等式约束的 QP(如"允许卖空、只有预算和目标收益"的经典 Markowitz 问题)。这时 KKT 条件就是一个线性方程组,CFA 里的有效前沿闭式解、两基金分离都来自它;你会看到求解这个方程组的几种方法和它们各自适用的场景。

后一半处理不等式约束,介绍有效集方法。它的思路和组合经理手工调仓的直觉一致:先猜哪些股票会"顶格"、哪些会"清仓",把它们固定住,对剩下的自由股票解一个等式约束问题;如果某只自由股票的权重算出来越界了,就把它固定到边界;如果某个被固定的股票,其乘子(影子价格)显示"放开它反而更好",就放开它。如此反复,直到所有乘子符号都正确。第 12 章 12.10.3 节的"等边际原则"表,就是这个算法的终点检查表。

需要先想起来的数学

1. 二次型与它的梯度。 \(\tfrac12x^TGx\) 是二次函数的矩阵写法。例:\(G=\begin{bmatrix}2&1\\1&4\end{bmatrix}\),\(\tfrac12x^TGx=x_1^2+x_1x_2+2x_2^2\)。当 \(G\) 对称时,\(q(x)=\tfrac12x^TGx+d^Tx\) 的梯度是 \(Gx+d\),Hessian 就是 \(G\),类比一元的 \(\frac d{dx}(\tfrac12ax^2+bx)=ax+b\)。组合方差 \(w^T\Sigma w\) 的梯度 \(2\Sigma w\) 的第 \(i\) 个分量,就是资产 \(i\) 的边际风险(与组合协方差的 2 倍)。见 第 00 册第 05 章 多元微积分与优化。

2. 正定、半正定与特征值。 对称矩阵 \(G\) 正定 ⇔ 所有特征值都大于 0 ⇔ 对任何非零 \(x\),\(x^TGx>0\)。协方差矩阵永远半正定;若资产数多于样本期数,它是奇异的(有零特征值),意味着存在方差为零的组合。惯性是正、负、零特征值的个数三元组,例如 \(\mathrm{diag}(3,-1,0)\) 的惯性是 \((1,1,1)\)。见 第 00 册第 06 章 线性代数速成。

3. 分块矩阵与方程组。 把几个矩阵拼成一个大矩阵,例如 \(\begin{bmatrix}G&-A^T\\A&0\end{bmatrix}\begin{bmatrix}x\\\lambda\end{bmatrix}=\begin{bmatrix}-d\\b\end{bmatrix}\),展开就是两组方程 \(Gx-A^T\lambda=-d\) 和 \(Ax=b\)。分块消元和标量消元一样:从一组方程解出一个未知数块,代入另一组。见 第 00 册第 06 章。

4. 零空间与 KKT 条件。 第 12 章的 KKT 条件、乘子符号和互补松弛,第 15 章的零空间基 \(Z\)("不破坏约束的调仓方向"),本章都直接使用。如果这两处还不熟,建议先回看第 12 章 12.3、12.10 节和第 15 章 15.2.2 节。

怎么读这一章

核心必读是 16.1(QP 与 Markowitz)、16.2(等式约束 QP 的 KKT 系统、约化 Hessian)、16.4(不等式 QP 的最优性条件)和 16.5.1–16.5.5(有效集方法的思路与例 16.3 手算)。建议把例 16.3 用纸笔跟一遍,再对照 16.7.1 代码的输出。

第一次可以只看结论的是 16.3 中四种解法的细节(记住"\(G\) 易逆或约束少用值空间法、自由度少用零空间法"即可)、16.3.4 共轭基方法、16.5.8 分解更新和 16.6 不定 QP。16.6 末尾的量化提示值得一读:协方差矩阵不是半正定时,优化器可能悄悄给出错误结果。


16.1 二次规划与组合优化

二次规划(quadratic program, QP):目标为二次函数、约束为线性。一般形式

\[ \min_x\ q(x)=\tfrac12x^TGx+x^Td\tag{16.1a} \]
\[ \text{s.t.}\quad a_i^Tx=b_i,\ i\in\mathcal E;\qquad a_i^Tx\ge b_i,\ i\in\mathcal I.\tag{16.1b,c} \]

\(G\) 为 \(n\times n\) 对称矩阵。QP 总能在有限步内解出或判定不可行,但工作量强烈依赖于目标的性质和不等式约束的个数:

  • \(G\) 半正定时称凸 QP(convex QP),局部解就是全局解,难度有时与 LP 相当;
  • \(G\) 不定时为非凸 QP,可能有多个驻点和局部极小;判断一个可行点是否全局极小是 NP-hard 的(Murty–Kabadi)。本章只求凸 QP 的解或一般 QP 的驻点 / 局部解。

QP 本身重要,也是一般约束优化的核心子问题:SQP(第 18 章)每步解一个 QP,增广拉格朗日法(第 17 章)的子问题也常用 QP 技术求解。

16.1.1 引例:Markowitz 组合优化

\(n\) 种资产收益 \(r_i\) 是随机变量,均值 \(\mu_i=E[r_i]\),方差 \(\sigma_i^2\),相关系数 \(\rho_{ij}\)。投资比例 \(x_i\),全额投资且禁止卖空:\(\sum_ix_i=1\),\(x\ge0\)。组合收益 \(R=\sum_ix_ir_i\) 的期望为 \(x^T\mu\),方差为

\[ E[(R-E[R])^2]=\sum_{i,j}x_ix_j\sigma_i\sigma_j\rho_{ij}=x^TGx,\qquad G_{ij}=\rho_{ij}\sigma_i\sigma_j, \]

\(G\) 是协方差矩阵,半正定。Markowitz 模型用参数 \(\kappa\ge0\) 把"高收益"与"低风险"合成一个目标:

\[ \max_x\ x^T\mu-\kappa\,x^TGx\quad\text{s.t.}\quad\sum_ix_i=1,\ x\ge0. \]

\(\kappa\) 是风险厌恶系数(原书称"risk tolerance parameter",但它越大越保守,实为风险厌恶)。保守投资者取大 \(\kappa\),激进投资者取接近零的 \(\kappa\)。改写成极小化:\(G\to2\kappa G\),\(d=-\mu\),就是标准的凸 QP。

推导拆解:改写只有两步。第一步,\(\max\) 变 \(\min\):\(\max(x^T\mu-\kappa x^TGx)=-\min(\kappa x^TGx-x^T\mu)\)。第二步,对齐 (16.1a) 的 \(\tfrac12x^TGx\) 写法:\(\kappa x^TGx=\tfrac12x^T(2\kappa G)x\),所以新 Hessian 是 \(2\kappa G\),线性项系数 \(d=-\mu\)。 与 CFA 的效用函数对照:CFA 写 \(U=E(R)-\tfrac12A\sigma^2\),\(A\) 是风险厌恶系数,所以 \(\kappa=A/2\)。\(A=4\) 的投资者对应 \(\kappa=2\)。

原书提醒的实际困难至今没变:\(\mu_i,\sigma_i,\rho_{ij}\) 很难估计。历史数据未必代表未来,新资产没有历史;从业者常把历史数据和主观判断结合。从优化角度,这意味着 QP 的输入有很大噪声——求解器给出的"最优"组合对 \(\mu\) 极其敏感,这是量化实务中做收缩估计、加约束、加换手惩罚的根本原因。

实务中的 QP 组合模型(下篇实现):

\[\max_w\ \alpha^Tw-\kappa w^T\Sigma w-c^T(b+s)\quad\text{s.t.}\quad \mathbf 1^Tw=1,\ w=w^0+b-s,\ b,s\ge0,\ 0\le w\le u,\ |H^T(w-w_b)|\le\delta,\ \mathbf 1^T(b+s)\le\tau.\]

预算、换手拆分是等式,个股上限、行业偏离、换手预算是不等式——全部线性,目标二次凸。


16.2 等式约束 QP

有效集方法每步都要解一个等式约束 QP,所以先把它彻底弄清楚。设

\[ \min_x\ q(x)=\tfrac12x^TGx+x^Td\quad\text{s.t.}\quad Ax=b,\tag{16.3} \]

\(A\) 为 \(m\times n\)(\(m\le n\))约束 Jacobian,先假设行满秩。

16.2.1 KKT 系统

由定理 12.1,存在乘子 \(\lambda^*\) 使

\[ \begin{bmatrix}G&-A^T\\A&0\end{bmatrix}\begin{bmatrix}x^*\\\lambda^*\end{bmatrix}=\begin{bmatrix}-d\\b\end{bmatrix}.\tag{16.4} \]

计算上常写成"步"的形式:设当前估计为 \(x\),\(x^*=x+p\),记 \(c=Ax-b\)(约束残差)、\(g=d+Gx\)(当前梯度),则

\[ \begin{bmatrix}G&A^T\\A&0\end{bmatrix}\begin{bmatrix}-p\\\lambda^*\end{bmatrix}=\begin{bmatrix}g\\c\end{bmatrix}.\tag{16.5} \]

系数矩阵

\[ K=\begin{bmatrix}G&A^T\\A&0\end{bmatrix}\tag{16.7} \]

推导拆解:(16.4) 怎么来。Lagrange 函数 \(\mathcal L=\tfrac12x^TGx+x^Td-\lambda^T(Ax-b)\)。对 \(x\) 求梯度:二次项给 \(Gx\),线性项给 \(d\),约束项给 \(-A^T\lambda\)(\(\lambda^TAx\) 对 \(x\) 的梯度是 \(A^T\lambda\))。令其为零得 \(Gx-A^T\lambda=-d\),再配上可行性 \(Ax=b\),就是 (16.4) 的两行。因为目标二次、约束线性,KKT 条件是线性方程组,一次求解即得答案,不需要迭代。 在 Markowitz 问题 \(\min\tfrac12w^T\Sigma w\) s.t. \(\mathbf 1^Tw=1\)、\(\mu^Tw=R\) 中,第一行读作 \(\Sigma w=\lambda_1\mathbf 1+\lambda_2\mu\)。左边第 \(i\) 个分量是资产 \(i\) 与前沿组合的协方差。移项得 \(\mu_i=(\operatorname{Cov}(r_i,r_p)-\lambda_1)/\lambda_2\):每个资产的期望收益是它与前沿组合协方差的线性函数。这正是 Black 零 beta CAPM 的数学来源:CAPM 的"期望收益与 beta 成线性关系",不过是最优组合 KKT 平稳性条件的另一种写法。

称为 KKT 矩阵。记 \(Z\) 为 \(A\) 零空间的一组基(\(n\times(n-m)\),列满秩,\(AZ=0\))。\(Z^TGZ\) 称为约化 Hessian(reduced Hessian):它是目标在可行方向上的曲率。

引理 16.1:若 \(A\) 行满秩、\(Z^TGZ\) 正定,则 KKT 矩阵非奇异,(16.4) 有唯一解。

证明:设 \(K\begin{bmatrix}p\\v\end{bmatrix}=0\),则 \(Ap=0\),且 \(0=[p;v]^TK[p;v]=p^TGp\)。\(p\) 在零空间中,写成 \(p=Zu\),得 \(u^TZ^TGZu=0\),由正定性 \(u=0\),\(p=0\)。再由 \(A^Tv=0\) 与 \(A\) 行满秩得 \(v=0\)。∎

注意:\(G\) 本身不必正定,只要在可行方向上正定即可。均值–方差中若协方差矩阵奇异(资产数多于样本数),只要约化 Hessian 正定,等式约束问题仍有唯一解。

金融直觉:\(Z\) 的每一列是一种"不改变约束的调仓",在只有预算约束时就是多空相抵的自融资调仓。\(u^TZ^TGZu=(Zu)^T\Sigma(Zu)\) 就是这笔调仓本身的方差。约化 Hessian 正定,意思是"任何一笔非零的允许调仓都有风险",于是最优组合唯一:偏离它的每一种方式都会增加方差。 反过来,如果存在一笔方差为零的允许调仓(例如两只股票在样本里完全同涨同跌,买一只卖一只的组合零波动),沿这个方向加减任意多,组合方差都不变,最优解就有无穷多个,求解器会随便给出其中一个。这就是 12.10.3 节说的"样本协方差在大截面上让解对数据极度敏感"的数学原因。

定理 16.2:在引理 16.1 的条件下,满足 (16.4) 的 \(x^*\) 是 (16.3) 的唯一全局解。

证明:任取可行 \(x\),令 \(p=x^*-x\),\(Ap=0\)。展开得 \(q(x)=\frac12p^TGp-p^TGx^*-d^Tp+q(x^*)\)。由 (16.4),\(Gx^*=-d+A^T\lambda^*\),所以 \(p^TGx^*=-p^Td+(Ap)^T\lambda^*=-p^Td\),于是

\[ q(x)=\tfrac12p^TGp+q(x^*)=\tfrac12u^TZ^TGZu+q(x^*),\qquad p=Zu. \]

\(x\ne x^*\) 时 \(u\ne0\),故 \(q(x)>q(x^*)\)。∎

例 16.1:

\[ \min\ 3x_1^2+2x_1x_2+x_1x_3+2.5x_2^2+2x_2x_3+2x_3^2-8x_1-3x_2-3x_3\quad\text{s.t.}\quad x_1+x_3=3,\ x_2+x_3=0. \]

即

\[ G=\begin{bmatrix}6&2&1\\2&5&2\\1&2&4\end{bmatrix},\ d=\begin{bmatrix}-8\\-3\\-3\end{bmatrix},\ A=\begin{bmatrix}1&0&1\\0&1&1\end{bmatrix},\ b=\begin{bmatrix}3\\0\end{bmatrix}. \]

解为 \(x^*=(2,-1,1)^T\),\(\lambda^*=(3,-2)^T\)。\(G\) 正定,零空间基可取 \(Z=(-1,-1,1)^T\)(16.10)。

约化 Hessian 不正定时。若 \((x^*,\lambda^*)\) 满足 KKT 但存在 \(u\) 使 \(u^TZ^TGZu\le0\),令 \(p=Zu\),则 \(x^*+\alpha p\) 对所有 \(\alpha\) 可行,且

\[ q(x^*+\alpha p)=q(x^*)+\alpha p^T(Gx^*+d)+\tfrac12\alpha^2p^TGp=q(x^*)+\tfrac12\alpha^2p^TGp\le q(x^*), \]

(用到 \(Gx^*+d=A^T\lambda^*\) 和 \(p^TA^T\lambda^*=0\))。若 \(Z^TGZ\) 有负特征值,沿该方向目标趋于 \(-\infty\),问题无下界;若只是半正定奇异,解不唯一(习题 16.10)。


16.3 求解 KKT 系统

只要 \(m\ge1\),KKT 矩阵总是不定的(有正有负特征值)。矩阵的**惯性(inertia)**指其正、负、零特征值的个数三元组。

引理 16.3:若 \(A\) 行满秩、\(Z^TGZ\) 正定,则 KKT 矩阵恰有 \(n\) 个正特征值、\(m\) 个负特征值、无零特征值。

更一般的结论是定理 16.6(由 Sylvester 惯性定律推出):

\[ \mathrm{inertia}(K)=\mathrm{inertia}(Z^TGZ)+(m,m,0). \]

所以检查 KKT 矩阵的惯性是否为 \((n,m,0)\),就能判断约化 Hessian 是否正定,而不必显式构造 \(Z\)。这在内点法、SQP 中检测非凸性非常有用。

白话解释:用例 16.1 核对一下定理 16.6。\(n=3\)、\(m=2\),零空间基 \(Z=(-1,-1,1)^T\),算得 \(GZ=(-7,-5,1)^T\),\(Z^TGZ=7+5+1=13>0\),所以 \(\mathrm{inertia}(Z^TGZ)=(1,0,0)\)。加上 \((m,m,0)=(2,2,0)\),得 \(K\) 的惯性 \((3,2,0)\),与 16.7.1 代码输出一致。读法是:KKT 矩阵里"天生"有 \(m\) 个正、\(m\) 个负特征值来自约束结构,剩下的正负号全由约化 Hessian 决定。数一数 \(K\) 有几个负特征值,多于 \(m\) 个就说明某个可行方向上曲率为负,问题非凸。

16.3.1 直接法:对称不定分解

KKT 矩阵不定,不能用 Cholesky;带部分主元的 LU 浪费了对称性。最有效的是对称不定分解(symmetric indefinite factorization):

\[ P^TKP=LBL^T,\tag{16.12} \]

\(P\) 为置换阵(为数值稳定并保持稀疏),\(L\) 单位下三角,\(B\) 是由 \(1\times1\) 和 \(2\times2\) 块组成的块对角阵。成本约为 Gauss 消元的一半。求解时依次解 \(Ly=P^T[g;c]\)、\(B\hat y=y\)、\(L^T\bar y=\hat y\),再置换回来。\(B\) 与 \(K\) 惯性相同,且 \(2\times2\) 块通常一正一负,所以从分解中可以直接读出惯性。

风险在于:若选主元的启发式不能很好保持稀疏性,\(L\) 会比原矩阵稠密得多(填充)。迭代法方面,CG 在不定系统上不稳定,不推荐;可以用 QMR、LSQR 等。

16.3.2 值空间法

假设 \(G\) 正定。用 \(G\) 做块消元:(16.5) 第一行左乘 \(AG^{-1}\) 再减第二行,得

\[ (AG^{-1}A^T)\lambda^*=AG^{-1}g-c,\tag{16.13} \]

解这个 \(m\times m\) 对称正定系统得 \(\lambda^*\),再由

\[ Gp=A^T\lambda^*-g\tag{16.14} \]

得 \(p\)。适用场景:\(G\) 易求逆(对角、块对角、或有 \(G^{-1}\) 的显式拟牛顿近似),或约束个数 \(m\) 很小。对应的显式逆公式为

\[ \begin{bmatrix}G&A^T\\A&0\end{bmatrix}^{-1}=\begin{bmatrix}C&E\\E^T&F\end{bmatrix},\quad \begin{aligned} C&=G^{-1}-G^{-1}A^T(AG^{-1}A^T)^{-1}AG^{-1},\\ E&=G^{-1}A^T(AG^{-1}A^T)^{-1},\quad F=-(AG^{-1}A^T)^{-1}. \end{aligned}\tag{16.15} \]

量化提示:经典的 Markowitz 闭式解就是值空间法。只有预算和收益两条等式约束时 \(m=2\),\(\lambda\) 由一个 \(2\times2\) 系统给出,\(w=\Sigma^{-1}A^T\lambda\)——这就是"两基金定理"的来源。因子模型 \(\Sigma=BFB^T+D\) 下,\(\Sigma^{-1}\) 可以用 Sherman–Morrison–Woodbury 公式(附录 A)以 \(O(nk^2)\) 的代价作用到向量上,值空间法对数千只股票也极快。

16.3.3 零空间法

零空间法不要求 \(G\) 非奇异,只需引理 16.1 的条件,但需要零空间基 \(Z\)。把步分解为

\[ p=Yp_Y+Zp_Z,\tag{16.16} \]

\(Y\) 为任意使 \([Y\,|\,Z]\) 非奇异的 \(n\times m\) 矩阵。\(Yp_Y\) 负责满足约束,\(Zp_Z\) 是沿约束的位移。

  • 代入 (16.5) 第二行(\(AZ=0\)):\((AY)p_Y=-c\)。(16.17)
  • 代入第一行并左乘 \(Z^T\):
\[ (Z^TGZ)p_Z=-[Z^TGYp_Y+Z^Tg],\tag{16.18} \]

用 \((n-m)\) 阶约化 Hessian 的 Cholesky 分解求解。

  • 乘子:第一行左乘 \(Y^T\),\((AY)^T\lambda^*=Y^T(g+Gp)\)。(16.19)

例 16.2:沿用例 16.1,取 \(Y=\begin{bmatrix}2/3&-1/3\\-1/3&2/3\\1/3&1/3\end{bmatrix}\)(此时 \(AY=I\)),\(Z=(-1,-1,1)^T\)。从 \(x=0\) 出发:\(c=-b\),\(g=d\),算得 \(p_Y=(3,0)^T\),\(p_Z=0\),\(p=(2,-1,1)^T\);由 (16.19) 得 \(\lambda^*=(3,-2)^T\)。

适用场景:自由度 \(n-m\) 小时很有效。主要缺点是需要 \(Z\),大问题中可能昂贵;\(Z\) 选得差会使 (16.18) 病态(第 15 章的数值实验)。中小规模软件常用列正交的 \(Z\)(QR),此时 \(Z^TGZ\) 的条件数不差于 \(G\)。(16.18) 也可以用 CG 求解,只需要 \(Z\)、\(Z^T\) 与向量的乘积,不必显式形成 \(Z^TGZ\)。

选择经验:\(G\) 正定且 \(AG^{-1}A^T\) 便宜(\(G\) 易逆或 \(m\ll n\))用值空间法;否则零空间法常更好,尤其当分解 \(G\) 比求 \(Z\) 与 \(Z^TGZ\) 的分解昂贵得多时。没有硬性规则。

16.3.4 基于共轭性的方法(简介)

\(G\) 正定时,可以构造非奇异 \(W\) 使

\[ W^TGW=I,\qquad AW=\begin{bmatrix}0&U\end{bmatrix},\tag{16.20} \]

\(U\) 为 \(m\times m\) 上三角。前 \(n-m\) 列(记为 \(Z\))在零空间中且关于 \(G\) 共轭规范,后 \(m\) 列记为 \(Y\)。于是 \(Z^TGZ=I\)、\(Z^TGY=0\),(16.17)–(16.19) 简化为

\[ Up_Y=-c,\qquad p_Z=-Z^Tg,\qquad U^T\lambda^*=Y^Tg+p_Y.\tag{16.23} \]

只需两次三角回代和几个矩阵–向量乘。构造方法:对 \(A\) 做 QR 变体得 \(AQ=[0\ \hat U]\),对 \(Q^TGQ=LL^T\) 做 Cholesky,令 \(W=QL^{-T}\)。这是一些高效凸 QP 有效集代码(如 Goldfarb–Idnani 对偶方法)的基础。


16.4 不等式约束 QP 的最优性条件

求解不等式 QP 的三大类方法:有效集方法(1970 年代以来最常用,凸与非凸都适用,中小规模首选)、梯度投影法(允许有效集快速变化,最适合界约束)、内点法(大规模凸 QP 有效)。也可以用第 17 章的增广拉格朗日法或第 18 章的 S\(\ell_1\)QP。

Lagrange 函数

\[ \mathcal L(x,\lambda)=\tfrac12x^TGx+x^Td-\sum_{i\in\mathcal I\cup\mathcal E}\lambda_i(a_i^Tx-b_i).\tag{16.24} \]

最优点的有效集(active set) \(\mathcal A(x^*)=\{i\in\mathcal E\cup\mathcal I:\ a_i^Tx^*=b_i\}\)。一阶条件:

\[ \begin{aligned} &Gx^*+d-\sum_{i\in\mathcal A(x^*)}\lambda_i^*a_i=0,\\ &a_i^Tx^*=b_i,\quad i\in\mathcal A(x^*),\\ &a_i^Tx^*\ge b_i,\quad i\in\mathcal I\setminus\mathcal A(x^*),\\ &\lambda_i^*\ge0,\quad i\in\mathcal I\cap\mathcal A(x^*). \end{aligned}\tag{16.26} \]

由于约束线性本身就是约束规范,QP 的最优性条件不需要假设有效约束梯度线性无关。

金融直觉:(16.26) 就是第 12 章 12.10.3 节"等边际原则"表的一般形式。第一行说:在最优点,目标的边际变化 \(Gx^*+d\) 被有效约束"定价"后完全抵消,每条有效约束的乘子 \(\lambda_i^*\) 是它的影子价格。第四行说:不等式约束的影子价格非负,因为放宽一条"\(\ge\)"约束不会让结果变差。非有效约束不出现在第一行,相当于它们的影子价格为零(没用满的限额不值钱)。 组合经理可以把它当检查清单:拿到一个优化结果,算出每只股票的边际"风险减收益",看自由持仓是否相等、清仓的是否不够好、顶格的是否更好,就能判断结果是否真的最优,而不必信任求解器的"成功"状态码。

  • 凸 QP:(16.26) 既必要又充分,满足它的点就是全局解。
  • 二阶充分条件:\(Z^TGZ\) 正定,\(Z\) 为有效约束 Jacobian 的零空间基。
  • 非凸 QP:可能有多个严格局部极小。例如 \(G\) 一正一负特征值、盒子约束下,盒子中心可能是驻点,某些顶点是局部极大、另一些是局部极小。

16.4.1 退化

"退化(degeneracy)"有两种含义:

(a) 解处有效约束梯度 \(a_i,\ i\in\mathcal A(x^*)\) 线性相关(例如 \(\mathbb R^2\) 中三条约束线交于一点);

(b) 严格互补不成立:某个有效约束的乘子 \(\lambda_i^*=0\),称为**弱有效(weakly active)**约束。

一个隐蔽的例子:\(\min x_1^2+(x_2+1)^2\) s.t. \(x\ge0\),解 \(x^*=0\)。无约束极小点 \((0,-1)\) 不在约束上,有效约束也只有 2 个,但 \(x_1\ge0\) 的乘子为零(\(\partial q/\partial x_1=2x_1=0\)),故退化。

危害:(1) 梯度线性相关使计算 \(Z\) 数值困难,使值空间法的 \(AG^{-1}A^T\) 奇异;(2) 弱有效约束让算法难以判断它在解处是否有效,有效集法和梯度投影法会反复加入、移出它,产生锯齿(zigzag)。

量化提示:组合优化中大量股票恰好卡在 \(w_i=0\) 下界、其乘子又接近零(这只股票"可有可无"),就是弱有效约束。表现是:数据的微小扰动使最优组合里这些股票时进时出,换手率虚高。这是数值性质而不是信号,治理办法是加换手惩罚、提高持仓门槛或做组合平滑。


16.5 凸 QP 的原始有效集方法

16.5.1 思路

若事先知道最优有效集 \(\mathcal A(x^*)\),只需解等式约束 QP \(\min q(x)\) s.t. \(a_i^Tx=b_i,\ i\in\mathcal A(x^*)\)。难点就是找到这个集合。有效集方法维护一个对它的猜测,每步修正一个指标。

与单纯形法(也是有效集方法)的区别:QP 的迭代点不一定在顶点间移动,解可以在边界的任何位置甚至在可行域内部。有效集方法分原始、对偶、原始–对偶三类,本书讲原始方法:迭代点保持原始可行,目标单调下降。

工作集(working set) \(\mathcal W_k\):全部等式约束加上部分(不一定全部)在 \(x_k\) 处有效的不等式约束,要求其中梯度线性无关。

白话解释:在只做多、带个股上限的组合问题里,工作集就是"当前被钉在边界上的股票清单"(哪些钉在 0,哪些钉在上限),再加上预算约束。算法每一轮做三件事之一: (1) 把清单里的股票当作固定,对其余自由股票解等式约束 QP(16.5.2 节的子问题),朝那个解移动; (2) 移动途中若某只自由股票先撞到 0 或上限,就停在那里,把它加入清单("加约束"); (3) 若已经到达当前清单下的最优,就看清单里每只股票的乘子:乘子为负,说明把它钉住是在"帮倒忙",就把乘子最负的那只放出来("删约束")。 第 12 章 12.11.2 节代码"先识别活跃集、再解 KKT 方程组"做的是最后一轮;有效集方法是把"猜清单"这件事系统化。

16.5.2 子问题与步长

令 \(p=x-x_k\),\(g_k=Gx_k+d\),在工作集上求方向:

\[ \min_p\ \tfrac12p^TGp+g_k^Tp\quad\text{s.t.}\quad a_i^Tp=0,\ i\in\mathcal W_k.\tag{16.27} \]

解为 \(p_k\)。工作集中的约束沿 \(p_k\) 保持有效。

步长:若 \(x_k+p_k\) 对所有约束可行,取全步;否则沿 \(p_k\) 走到第一个碰上的约束。对 \(i\notin\mathcal W_k\):若 \(a_i^Tp_k\ge0\),任何 \(\alpha\ge0\) 都不会违反;若 \(a_i^Tp_k<0\),需要 \(\alpha\le(b_i-a_i^Tx_k)/(a_i^Tp_k)\)。所以

\[ \alpha_k=\min\Big(1,\ \min_{i\notin\mathcal W_k,\ a_i^Tp_k<0}\frac{b_i-a_i^Tx_k}{a_i^Tp_k}\Big).\tag{16.29} \]

这和单纯形法的比值检验是同一个想法。达到最小值的约束称为阻挡约束(blocking constraints),\(\alpha_k<1\) 时把其中一个加入工作集。\(\alpha_k=0\) 是可能的(某约束在 \(x_k\) 有效但不在 \(\mathcal W_k\) 中且 \(a_i^Tp_k<0\))。

16.5.3 何时删约束:看乘子符号

不断加约束,直到某点 \(\hat x\) 在当前工作集 \(\hat{\mathcal W}\) 上已经是极小点,即子问题解 \(p=0\)。此时

\[ \sum_{i\in\hat{\mathcal W}}a_i\hat\lambda_i=G\hat x+d.\tag{16.30} \]

令工作集外的不等式乘子为零,(16.26) 的前三条都满足。

  • 若工作集中不等式约束的乘子全部非负,\(\hat x\) 是 KKT 点,凸 QP 下即全局解。
  • 若某个 \(\hat\lambda_j<0\),说明约束 \(j\) "在往回拉"——放开它能让目标下降,应把它从工作集删去。

定理 16.4:设 \(\hat x\) 在工作集 \(\hat{\mathcal W}\) 上满足 (16.30),工作集梯度线性无关,\(\hat\lambda_j<0\)。删去 \(j\) 后解 (16.31)(即 (16.27) 去掉第 \(j\) 个约束),则 \(a_j^Tp\ge0\)(新方向不会违反约束 \(j\));若 \(p\) 满足二阶充分条件,则 \(a_j^Tp>0\) 且 \(p\) 是下降方向。

证明要点:把新子问题的一阶条件与 (16.30) 相减并与 \(p\) 作内积,利用 \(a_i^Tp=0\)(\(i\ne j\))得

\[ -\hat\lambda_j\,a_j^Tp=p^TGp\ge0,\tag{16.34} \]

由 \(\hat\lambda_j<0\) 得 \(a_j^Tp\ge0\)。∎

推导拆解:(16.34) 的来历。删去 \(j\) 前,\(\hat x\) 满足 \(G\hat x+d=\sum_{i\in\hat{\mathcal W}}\hat\lambda_ia_i\)(16.30)。删去 \(j\) 后,新子问题的解 \(p\) 满足 \(Gp+(G\hat x+d)=\sum_{i\ne j}\mu_ia_i\)(\(\mu_i\) 是新乘子)。两式相减得 \(Gp=\sum_{i\ne j}(\mu_i-\hat\lambda_i)a_i-\hat\lambda_ja_j\)。两边与 \(p\) 作内积,因为 \(a_i^Tp=0\)(\(i\ne j\),其余约束仍在工作集里),求和项全部消失,只剩 \(p^TGp=-\hat\lambda_ja_j^Tp\)。凸 QP 中 \(p^TGp\ge0\),而 \(-\hat\lambda_j>0\),所以 \(a_j^Tp\ge0\):新方向朝约束 \(j\) 的可行一侧离开,不会违反它。

金融直觉:乘子为负是什么意思?以 \(w_i\ge0\) 为例。工作集把 \(w_i\) 钉在 0,相当于临时把它当作等式 \(w_i=0\)。等式的乘子可正可负;若算出来为负,按 12.4 节的敏感性,意思是"把右端从 0 往上放宽,目标会下降",也就是这只股票其实值得买,当前是被错误地钉在了零。按第 12 章等边际原则表的语言,它的边际"风险减收益" \(g_i\) 低于预算影子价格 \(\nu\),应当进入组合。删掉这条约束,让 \(w_i\) 自由变化,目标就会下降。

定理 16.5:若 (16.27) 的解 \(p_k\ne0\) 且满足二阶充分条件,则 \(q\) 沿 \(p_k\) 严格下降。(因为 \(p=0\) 可行,所以 \(\frac12p_k^TGp_k+g_k^Tp_k<0\),再由 \(p_k^TGp_k\ge0\) 得 \(g_k^Tp_k<0\)。)

实践中通常删最负乘子对应的约束:由第 12 章的敏感性分析,目标对约束的变化率正比于乘子大小。但这个规则对约束缩放敏感(约束乘以 \(\beta>0\),乘子变为 \(1/\beta\) 倍),与单纯形法的 Dantzig 规则类似。

16.5.4 算法 16.1

计算可行初始点 x0;取 W0 为 x0 处有效约束的子集;
for k = 0,1,2,...
    解 (16.27) 得 pk;
    if pk = 0
        由 (16.30) 计算乘子 λ̂i,令 Ŵ = Wk;
        if 对所有 i ∈ Wk∩I 有 λ̂i ≥ 0:STOP,x* = xk;
        else  j = argmin_{j∈Wk∩I} λ̂j;x_{k+1} = xk;W_{k+1} = Wk \ {j};
    else
        按 (16.29) 计算 αk;x_{k+1} = xk + αk pk;
        若有阻挡约束:把其中一个加入工作集得 W_{k+1};否则 W_{k+1} = Wk;
end

16.5.5 例 16.3:手算一遍

\[ \min\ q(x)=(x_1-1)^2+(x_2-2.5)^2 \]

s.t.

\[ \begin{aligned} &(1)\ x_1-2x_2+2\ge0, &&(2)\ -x_1-2x_2+6\ge0, &&(3)\ -x_1+2x_2+2\ge0,\\ &(4)\ x_1\ge0, &&(5)\ x_2\ge0. \end{aligned} \]

从 \(x^0=(2,0)\) 出发,约束 3、5 有效,取 \(\mathcal W_0=\{3,5\}\)(上标为迭代号,下标为分量)。

  • 迭代 0:\(x^0\) 是顶点,\(p=0\)。\(g=\nabla q=(2,-5)\)。解 \(\begin{bmatrix}-1\\2\end{bmatrix}\hat\lambda_3+\begin{bmatrix}0\\1\end{bmatrix}\hat\lambda_5=\begin{bmatrix}2\\-5\end{bmatrix}\),得 \((\hat\lambda_3,\hat\lambda_5)=(-2,-1)\)。删去最负的约束 3,\(\mathcal W_1=\{5\}\)。
  • 迭代 1:在 \(x_2=0\) 上极小化,\(p^1=(-1,0)\),无阻挡,\(\alpha=1\),\(x^2=(1,0)\)。
  • 迭代 2:\(p=0\),\(\hat\lambda_5=-5<0\),删去,\(\mathcal W_3=\emptyset\)。
  • 迭代 3:无约束方向 \(p^3=(0,2.5)\),碰到约束 1 时 \(\alpha_3=0.6\),\(x^4=(1,1.5)\),\(\mathcal W_4=\{1\}\)。
  • 迭代 4:在约束 1 上极小化,\(p^4=(0.4,0.2)\),\(\alpha=1\),\(x^5=(1.4,1.7)\)。
  • 迭代 5:\(p=0\),\(\nabla q(x^5)=(0.8,-1.6)=\hat\lambda_1(1,-2)\),\(\hat\lambda_1=0.8\ge0\),最优 \(x^*=(1.4,1.7)\)。

(原书正文此处印为 \(\hat\lambda_1=1.25\);按 \(\nabla q(x^*)=\hat\lambda_1a_1\) 直接计算应为 \(0.8\),下面的程序也给出 0.8。)

推导拆解:几个关键数字的手算过程。 迭代 0 的乘子:\(\hat\lambda_3a_3+\hat\lambda_5a_5=g\) 逐分量写出,第一个分量 \(-\hat\lambda_3=2\) 得 \(\hat\lambda_3=-2\);第二个分量 \(2\hat\lambda_3+\hat\lambda_5=-5\) 得 \(\hat\lambda_5=-1\)。 迭代 1 的方向:工作集只剩 \(x_2=0\),在这条线上极小化 \((x_1-1)^2+(0-2.5)^2\),最优 \(x_1=1\),所以 \(p=(1,0)-(2,0)=(-1,0)\)。 迭代 3 的步长:无约束极小点是 \((1,2.5)\),\(p=(0,2.5)\)。检查每个不在工作集的约束:约束 1 是 \(x_1-2x_2+2\ge0\),沿 \(p\) 有 \(a_1^Tp=-5<0\),当前余量 \(b_1-a_1^Tx=-2-(1-0)=-3\),比值 \(-3/-5=0.6\);其余约束比值更大或不受影响,所以 \(\alpha=0.6\),到达 \((1,1.5)\)。这就是 (16.29) 的比值检验。 迭代 4 的方向:在直线 \(x_1-2x_2=-2\) 上找离 \((1,2.5)\) 最近的点(目标就是到 \((1,2.5)\) 的距离平方)。沿法向 \(a_1=(1,-2)\) 投影:\((1,2.5)\) 处 \(a_1^Tx=-4\),需要调到 \(-2\),移动 \(t\,a_1\) 使 \(-4+5t=-2\),\(t=0.4\),得 \((1.4,1.7)\)。 迭代 5 的乘子:\(\nabla q=(2(1.4-1),2(1.7-2.5))=(0.8,-1.6)=0.8\,(1,-2)\),所以 \(\hat\lambda_1=0.8>0\),停止。

几点观察:

  • 初始工作集不同,路径不同。\(\mathcal W_0=\emptyset\) 时,无约束方向 \(p=(-1,2.5)\),\(\alpha=2/3\),\(x^1=(4/3,5/3)\) 碰到约束 1,再一步即得最优——只用 3 次迭代。
  • 每步至多增删一个约束,这给迭代次数一个下界:若解处有 \(t\) 个有效约束而 \(x_0\) 严格可行,至少需要 \(t\) 次迭代。这是有效集法在大规模问题上的软肋(下篇的梯度投影法和内点法解决这个问题)。
  • 线性无关性自动保持:阻挡约束的法向不可能是当前工作集法向的线性组合(习题 16.15),删约束也不会引入相关性。

16.5.6 有限终止

设 \(G\) 正定,且 \(p_k\ne0\) 时 \(\alpha_k>0\)。

  1. 若 \(p_k=0\),\(x_k\) 是 \(q\) 在 \(\mathcal W_k\) 上的唯一全局极小。若非最优,由定理 16.4、16.5,删约束后下一方向严格下降,此后 \(q\) 始终低于 \(q(x_k)\),因此永远不会回到 \(\mathcal W_k\)。
  2. 至少每 \(n\) 步出现一次 \(p_k=0\):\(p_k\ne0\) 时要么 \(\alpha_k=1\)(到达当前工作集的极小,下一步 \(p=0\)),要么加一个约束;连加 \(n\) 次后工作集含 \(n\) 个线性无关约束,只有 \(p=0\)。
  3. 工作集个数有限,每个至多访问一次,故有限终止。∎

假设 \(\alpha_k>0\) 排除了循环:删约束后立刻碰到新约束、原地不动、若干步后回到同一工作集。处理方法与 LP 类似,但多数 QP 实现直接忽略这种情况。

16.5.7 初始可行点

  • Phase I:同第 13 章。变体是允许用户给一个"不太不可行"的初值 \(\tilde x\),求解可行性 LP
\[ \min_{(x,z)}e^Tz\quad\text{s.t.}\quad a_i^Tx+\gamma_iz_i=b_i\ (\mathcal E),\ a_i^Tx+\gamma_iz_i\ge b_i\ (\mathcal I),\ z\ge0, \]

\(\gamma_i=-\mathrm{sign}(a_i^T\tilde x-b_i)\)(\(\mathcal E\)),\(\gamma_i=1\)(\(\mathcal I\)),以 \(x=\tilde x\) 和相应的 \(z\) 为初始可行点。

  • 大 M 法(big M):省去 Phase I,引入一个标量 \(t\) 度量最大违反量:
\[ \min_{(x,t)}\ \tfrac12x^TGx+x^Td+Mt\quad\text{s.t.}\quad t\ge|a_i^Tx-b_i|\ (\mathcal E),\ t\ge b_i-a_i^Tx\ (\mathcal I),\ t\ge0.\tag{16.35} \]

由精确罚理论,原问题可行时 \(M\) 足够大(大于乘子的某种范数)则解有 \(t=0\)。启发式选 \(M\),若解出 \(t>0\) 就增大 \(M\) 重解。它基于 \(\ell_\infty\) 范数,与第 18 章的 S\(\ell_1\)QP 思想相通。

白话解释:大 M 法与第 15 章 15.3.2 节的"罚款必须高于违规收益"是同一个道理。\(t\) 是最大违规量,\(M\) 是每单位违规的罚款。只要 \(M\) 超过各约束影子价格(乘子)合起来的某个量级,违规就不划算,解自动落在 \(t=0\) 的可行区域里。\(M\) 太小,求解器会"交罚款换收益";\(M\) 太大,数值上又会病态,所以实务中从中等大小开始、不够再加。

量化提示:热启动。日频调仓时,昨天的最优组合和最优工作集是今天极好的初始猜测:大部分"顶格"和"零持仓"的股票不会变。有效集法从昨日工作集出发,往往几步就收敛。这是有效集类 QP 求解器(如 qpOASES、Gurobi 的单纯形型 QP)在日常再平衡中的一大优势;内点法很难利用这类先验信息。

16.5.8 分解的更新

工作集每步只变一个指标,KKT 矩阵至多变一行一列(\(G\) 不变),所以应该更新分解而不是重算。以零空间法 + QR 为例,\(A^T\Pi=Q\begin{bmatrix}R\\0\end{bmatrix}=[Q_1\ Q_2]\begin{bmatrix}R\\0\end{bmatrix}\),\(Z=Q_2\):

  • 加一个约束 \(a\):利用 \(Q_1Q_1^T+Q_2Q_2^T=I\),
\[ \bar A^T\begin{bmatrix}\Pi&0\\0&1\end{bmatrix}=Q\begin{bmatrix}R&Q_1^Ta\\0&Q_2^Ta\end{bmatrix},\tag{16.38} \]

再用一个正交变换 \(\hat Q\)(Householder 或一串 Givens 旋转)把 \(Q_2^Ta\) 变成 \((\gamma,0,\dots,0)^T\)。新零空间基是 \(Q_2\hat Q^T\) 的后 \(n-m-1\) 列。成本 \(O(n(n-m))\),而重算 QR 是 \(O(n^2m)\)。

  • 删一个约束:从 \(R\) 删一列,次对角线出现非零元,用一串 Givens 旋转恢复上三角;新零空间基为 \(\bar Z=[Z\ \bar z]\),多一列。
  • 约化 Hessian 的 Cholesky 因子也随之更新:子问题中 \(c=0\),\(p_Y=0\),\((Z^TGZ)p_Z=-Z^Tg\)(16.40)。删约束时 \(Z\) 增一列,用平面旋转把 \(L\) 扩展为 \(\bar L\)。

16.6 不定 QP 的有效集方法(简介)

\(G\) 有负特征值时,若约化 Hessian \(Z^TGZ\) 正定,算法逻辑不变;若它有负特征值,子问题解只是鞍点,不能用。这时改用约化 Hessian 的负曲率方向 \(s_Z\):

\[ q(x+\alpha Zs_Z)\to-\infty\quad(\alpha\to\infty),\tag{16.41} \]

选符号使其非上升。沿此方向必然碰到某个约束(否则问题无界),加入工作集,重复直到约化 Hessian 正定。

惯性控制方法(inertia-controlling methods):从不让约化 Hessian 有多于一个负特征值。要求初始点是顶点(约化 Hessian 为空矩阵)或约化 Hessian 正定的约束驻点。加约束只会让约化 Hessian 维数变小、保持正定,所以不定性只可能在删约束时出现。具体做法(Fletcher 的伪约束 + Gill–Murray 的 \(LDL^T\)):设 \(Z^TGZ=LDL^T\),删约束后 \(Z\) 增一列,\(D\) 增一个对角元 \(d_{\rm new}\)。若 \(d_{\rm new}<0\),解 \(L_+^Ts_Z=e_{\rm last}\) 得负曲率方向 \(s=Z_+s_Z\),\(s^TGs=d_{\rm new}<0\);同时把被删的约束作为**伪约束(pseudo-constraint)**暂留在工作集中,等以后能删且保持约化 Hessian 正定时再删。

原书用

\[ \min\ \tfrac12(x_1^2-x_2^2)\quad\text{s.t.}\quad x_2\ge0,\ x_1+2x_2\ge2,\ -5x_1+4x_2\le10,\ x_1\le3\tag{16.42} \]

演示了完整过程:从顶点 \((2,0)\) 出发,先后删约束、发现约化 Hessian \(Z^TGZ=16-25=-9<0\)、沿负曲率方向 \((4,5)\) 走到 \((3,25/4)\),最终乘子 \((\lambda_3,\lambda_4)=(25/16,77/16)>0\),得到局部解(也是全局解)。

有效集方法的失败:\(G\) 不正定时,惯性控制算法不保证找到局部极小。例:\(\min -x_1x_2\) s.t. \(0\le x_1,x_2\le1\),从 \((0,0)\)、两个下界都在工作集出发。该点是驻点,乘子为零;删去任一约束后约化 Hessian 为 0(奇异),找不到负曲率方向,算法停止——但沿 \((1,1)\) 目标是下降的,它不是局部解。根本原因是:对有效集方法而言,一阶最优并不导致二阶最优,有时需要同时删两个约束。实践中舍入误差往往让算法离开这类点。

量化提示:协方差矩阵由成对删除缺失数据、或直接用样本估计而资产数超过样本数时,可能不是半正定的,均值–方差就变成不定 QP。有效集法可能停在非最优点、内点法可能失败。务必先修正协方差(特征值截断、收缩到对角或单因子目标、最近相关阵投影),保证凸性。


16.7 量化实战(上)

16.7.1 代码一:KKT 系统的三种解法与有效集法

import numpy as np
from scipy.linalg import ldl

# ---------- 例 16.1:等式约束 QP 的三种解法 ----------
G = np.array([[6., 2, 1], [2, 5, 2], [1, 2, 4]]); d = np.array([-8., -3, -3])
A = np.array([[1., 0, 1], [0, 1, 1]]); b = np.array([3., 0])
n, m = 3, 2
K = np.block([[G, -A.T], [A, np.zeros((m, m))]])
sol = np.linalg.solve(K, np.r_[-d, b])
print("KKT 直接解: x* =", sol[:n], " λ* =", sol[n:])
# 惯性:对称不定分解 LBL^T,B 的特征值符号 = K 的惯性
_, Bblk, _ = ldl(K)
ev = np.linalg.eigvalsh(Bblk)
print("KKT 惯性 (正,负,零) =", (int((ev > 0).sum()), int((ev < 0).sum()), int((abs(ev) < 1e-12).sum())))
# 值空间法 (16.13)-(16.14),从 x=0 出发:g = d, c = -b
g, c = d.copy(), -b
Gi = np.linalg.inv(G)
lam = np.linalg.solve(A @ Gi @ A.T, A @ Gi @ g - c)
p = np.linalg.solve(G, A.T @ lam - g)
print("值空间法:   x* =", p, " λ* =", lam)
# 零空间法 (16.16)-(16.19),用例 16.2 的 Y, Z
Y = np.array([[2/3, -1/3], [-1/3, 2/3], [1/3, 1/3]]); Z = np.array([[-1.], [-1], [1]])
pY = np.linalg.solve(A @ Y, -c)
pZ = np.linalg.solve(Z.T @ G @ Z, -(Z.T @ G @ Y @ pY + Z.T @ g))
p = Y @ pY + Z @ pZ
lam = np.linalg.solve((A @ Y).T, Y.T @ (g + G @ p))
print("零空间法:   x* =", p, " λ* =", lam, " pY =", pY, " pZ =", pZ)

# ---------- 算法 16.1:凸 QP 原始有效集法,复现例 16.3 ----------
def fmt(W, lam):
    return "{" + ", ".join(f"λ{i+1}={float(l):.3g}" for i, l in zip(W, lam)) + "}"

def active_set_qp(G, d, Ain, bin_, x, W, verbose=True, max_iter=50):
    """min 1/2 x'Gx + d'x  s.t.  Ain x >= bin_(只含不等式)。W: 初始工作集。"""
    W = list(W)
    for k in range(max_iter):
        gk = G @ x + d
        Aw = Ain[W] if W else np.zeros((0, len(x)))
        mw = len(W)
        KK = np.block([[G, -Aw.T], [Aw, np.zeros((mw, mw))]])
        sol = np.linalg.solve(KK, np.r_[-gk, np.zeros(mw)])   # 子问题 (16.27)
        p, lam = sol[:len(x)], sol[len(x):]
        if np.linalg.norm(p) < 1e-10:
            if mw == 0 or lam.min() >= -1e-10:
                if verbose: print(f"  迭代 {k}: p=0, 乘子 {fmt(W, lam)} 全非负 → 最优 x* = {x}")
                return x, W, dict(zip(W, lam))
            j = int(np.argmin(lam))
            if verbose: print(f"  迭代 {k}: p=0, 乘子 {fmt(W, lam)},删去约束 {W[j]+1}")
            W.pop(j)
        else:
            alpha, block = 1.0, None
            for i in range(len(bin_)):
                if i in W: continue
                ap = Ain[i] @ p
                if ap < -1e-12:
                    t = (bin_[i] - Ain[i] @ x) / ap
                    if t < alpha: alpha, block = t, i
            x = x + alpha * p
            if block is not None: W.append(block)
            if verbose: print(f"  迭代 {k}: p={p.round(3)}, α={alpha:.3f}, x={x.round(3)}, "
                              f"{'加入约束 ' + str(block+1) if block is not None else '无阻挡'}")
    raise RuntimeError

G2 = 2 * np.eye(2); d2 = np.array([-2., -5])            # (x1-1)^2+(x2-2.5)^2
Ain = np.array([[1., -2], [-1, -2], [-1, 2], [1, 0], [0, 1]])
bin_ = np.array([-2., -6, -2, 0, 0])
print("例 16.3,W0 = {3,5}:")
active_set_qp(G2, d2, Ain, bin_, np.array([2., 0]), W=[2, 4])
print("例 16.3,W0 = ∅:")
active_set_qp(G2, d2, Ain, bin_, np.array([2., 0]), W=[])

输出:

KKT 直接解: x* = [ 2. -1.  1.]  λ* = [ 3. -2.]
KKT 惯性 (正,负,零) = (3, 2, 0)
值空间法:   x* = [ 2. -1.  1.]  λ* = [ 3. -2.]
零空间法:   x* = [ 2. -1.  1.]  λ* = [ 3. -2.]  pY = [3. 0.]  pZ = [-1.36642834e-16]
例 16.3,W0 = {3,5}:
  迭代 0: p=0, 乘子 {λ3=-2, λ5=-1},删去约束 3
  迭代 1: p=[-1.  0.], α=1.000, x=[1. 0.], 无阻挡
  迭代 2: p=0, 乘子 {λ5=-5},删去约束 5
  迭代 3: p=[-0.   2.5], α=0.600, x=[1.  1.5], 加入约束 1
  迭代 4: p=[0.4 0.2], α=1.000, x=[1.4 1.7], 无阻挡
  迭代 5: p=0, 乘子 {λ1=0.8} 全非负 → 最优 x* = [1.4 1.7]
例 16.3,W0 = ∅:
  迭代 0: p=[-1.   2.5], α=0.667, x=[1.333 1.667], 加入约束 1
  迭代 1: p=[0.067 0.033], α=1.000, x=[1.4 1.7], 无阻挡
  迭代 2: p=0, 乘子 {λ1=0.8} 全非负 → 最优 x* = [1.4 1.7]

三种 KKT 解法结果一致,与例 16.1、16.2 的手算相同;KKT 矩阵惯性为 \((n,m,0)=(3,2,0)\),验证了约化 Hessian 正定。有效集法完整复现了例 16.3 的六步迭代;换成空的初始工作集只需三步,说明好的初始工作集(热启动)能显著减少迭代。

16.7.2 代码二:等式约束均值–方差、影子价格与两基金定理

允许卖空、只有预算和收益两条等式约束时,均值–方差问题 \(\min\frac12w^T\Sigma w\) s.t. \(\mathbf 1^Tw=1,\ \mu^Tw=R\) 就是 16.2 节的等式 QP。第 12 章 12.10.2 节已从 KKT 条件推导过有效前沿与两基金分离,这里从 KKT 系统的数值解法角度复核同一结论。

import numpy as np

# 等式约束均值-方差:min 1/2 w'Σw  s.t.  1'w = 1,  μ'w = R   (允许卖空)
rng = np.random.default_rng(1)
n = 6
L = rng.standard_normal((n, n)) * 0.1
Sigma = L @ L.T + np.diag(rng.uniform(0.01, 0.04, n))
mu = rng.uniform(0.02, 0.12, n)
A = np.vstack([np.ones(n), mu])
K = np.block([[Sigma, -A.T], [A, np.zeros((2, 2))]])
print(" R      σ(R)     λ_budget  λ_return  d(½σ²)/dR 数值")
prev = None
for R in [0.04, 0.06, 0.08, 0.10]:
    sol = np.linalg.solve(K, np.r_[np.zeros(n), 1.0, R])
    w, lam = sol[:n], sol[n:]
    var = w @ Sigma @ w
    # 数值导数:目标 1/2 w'Σw 对 R 的导数应等于 λ_return
    sol2 = np.linalg.solve(K, np.r_[np.zeros(n), 1.0, R + 1e-6])
    dobj = (0.5 * sol2[:n] @ Sigma @ sol2[:n] - 0.5 * var) / 1e-6
    print(f"{R:.2f}  {np.sqrt(var):.4%}  {lam[0]:+.5f}  {lam[1]:+.5f}  {dobj:+.5f}")
# 两基金定理:任意两个前沿组合的线性组合仍在前沿上
w1 = np.linalg.solve(K, np.r_[np.zeros(n), 1.0, 0.04])[:n]
w2 = np.linalg.solve(K, np.r_[np.zeros(n), 1.0, 0.10])[:n]
w_mix = 0.5 * w1 + 0.5 * w2
w_07 = np.linalg.solve(K, np.r_[np.zeros(n), 1.0, 0.07])[:n]
print("两基金定理: ||0.5 w(4%) + 0.5 w(10%) - w(7%)|| =", np.linalg.norm(w_mix - w_07))

输出:

 R      σ(R)     λ_budget  λ_return  d(½σ²)/dR 数值
0.04  14.3814%  +0.04021  -0.48831  -0.48830
0.06  9.0229%  +0.01647  -0.13875  -0.13874
0.08  9.7890%  -0.00728  +0.21081  +0.21082
0.10  15.8133%  -0.03103  +0.56037  +0.56038
两基金定理: ||0.5 w(4%) + 0.5 w(10%) - w(7%)|| = 1.1385919347227337e-16

解读:

  1. 乘子 = 影子价格:收益约束的乘子与目标对 \(R\) 的数值导数完全一致。
  2. 乘子符号与有效集逻辑:\(R=4\%,6\%\) 时 \(\lambda_{\rm return}<0\),说明这两个收益目标低于最小方差组合的收益,把等式约束换成"\(\mu^Tw\ge R\)"时它会被有效集法删除(定理 16.4);\(R=8\%,10\%\) 时乘子为正,约束有效。这正是"有效前沿只取最小方差组合以上那一半"的优化解释。
  3. 两基金定理:KKT 系统是线性的,解 \(w(R)\) 关于 \(R\) 是仿射函数,所以任意两个前沿组合的凸组合仍在(等式约束的)前沿上。加入 \(w\ge0\) 后,有效集随 \(R\) 变化,\(w(R)\) 变成分段仿射——前沿由若干段"拐点"连接,每个拐点就是一次工作集的增删。

本章(上)小结

QP 由二次目标和线性约束组成;凸 QP 局部即全局,非凸 QP 判全局最优是 NP-hard。Markowitz 均值–方差是 QP 的标准应用。等式约束 QP 的解由 KKT 系统给出;\(A\) 行满秩且约化 Hessian \(Z^TGZ\) 正定时 KKT 矩阵非奇异、惯性为 \((n,m,0)\),解唯一且全局最优;约化 Hessian 有负特征值时问题无下界。KKT 系统可用对称不定分解直接求解,\(G\) 易逆或 \(m\) 小时用值空间法(Markowitz 闭式解即此),\(n-m\) 小时用零空间法,\(G\) 正定时还可用共轭基方法。不等式 QP 的 KKT 条件不需要约束规范;退化(梯度相关或弱有效约束)会导致锯齿。原始有效集方法维护工作集,每步解等式子问题,用比值检验 (16.29) 决定步长并加入阻挡约束,在工作集极小点处检查乘子、删去最负者;严格凸且无循环时有限终止。分解更新与热启动是有效集法高效的关键。不定 QP 需要惯性控制,且可能停在一阶驻点。

概念 公式 / 要点
QP \(\min\frac12x^TGx+d^Tx\),线性约束;\(G\succeq0\) 为凸 QP
KKT 系统 \(\begin{bmatrix}G&-A^T\\A&0\end{bmatrix}\begin{bmatrix}x\\\lambda\end{bmatrix}=\begin{bmatrix}-d\\b\end{bmatrix}\)
唯一性条件 \(A\) 行满秩,\(Z^TGZ\succ0\)
惯性 \(\mathrm{inertia}(K)=\mathrm{inertia}(Z^TGZ)+(m,m,0)\)
值空间法 \((AG^{-1}A^T)\lambda=AG^{-1}g-c\),\(Gp=A^T\lambda-g\)
零空间法 \((AY)p_Y=-c\),\((Z^TGZ)p_Z=-Z^TGYp_Y-Z^Tg\)
有效集子问题 \(\min\frac12p^TGp+g_k^Tp\) s.t. \(a_i^Tp=0,\ i\in\mathcal W_k\)
步长 \(\alpha=\min(1,\min_{a_i^Tp<0}(b_i-a_i^Tx)/(a_i^Tp))\)
删约束 \(p=0\) 且某 \(\hat\lambda_j<0\) ⇒ 删最负者;\(-\hat\lambda_ja_j^Tp=p^TGp\)
大 M 法 \(\min q(x)+Mt\),\(t\ge\) 各约束违反量
不定 QP 惯性控制:约化 Hessian 至多一个负特征值,伪约束

练习

基础

  1. 证明从定理 12.1、12.6 可以推出 (16.4) 与等式 QP 的二阶充分条件。
  2. 点 \(x_0\) 到仿射集 \(\{x:Ax=b\}\) 的最短距离:解 \(\min\frac12\|x-x_0\|^2\) s.t. \(Ax=b\),证明 \(\lambda^*=(AA^T)^{-1}(b-Ax_0)\),\(x^*=x_0+A^T(AA^T)^{-1}(b-Ax_0)\);\(A\) 为行向量 \(a^T\) 时距离为 \(|b-a^Tx_0|/\|a\|\)。(原书习题给出的 \(x^*\) 符号有误,应为加号。)
  3. 证明:只要 \(A\ne0\),KKT 矩阵一定不定;若 KKT 矩阵非奇异,则 \(A\) 行满秩。
  4. 对例 16.3 分别取 \(\mathcal W_0=\{3\}\) 和 \(\mathcal W_0=\{5\}\),手算前两步,再用 16.7.1 的代码核对。 提示:\(\mathcal W_0=\{3\}\) 时 \(p^0=(0.2,0.1)\),\(x^1=(2.2,0.1)\)。
  5. 证明乘子的大小依赖约束的缩放:把约束 \(a_i^Tx\ge b_i\) 乘以 \(\beta>0\),乘子变为 \(\lambda_i/\beta\)。由此说明"删最负乘子"规则对缩放不变性的缺陷。

进阶

  1. 等式 QP 的三种情形:(a) \(Z^TGZ\) 正定 ⇔ 有唯一强局部极小;(b) \(Z^TGZ\) 半正定奇异且 KKT 系统相容 ⇒ 无穷多解;(c) \(Z^TGZ\) 不定或 KKT 系统不相容 ⇒ 无有限解。
  2. 证明阻挡约束的梯度不可能是当前工作集梯度的线性组合,从而工作集始终保持线性无关。
  3. 用 Sylvester 惯性定律证明定理 16.6。 提示:用 \([Y\ Z]\) 构造合同变换,把 \(K\) 化为块三角形式。
  4. 在 16.7.2 的代码中加入 \(w\ge0\),用 16.7.1 的 active_set_qp(把等式约束写成两条不等式,或修改代码支持等式)求解 \(R\) 从最小方差收益到最大单资产收益的一系列前沿组合,记录每个 \(R\) 的工作集,找出前沿的"拐点"。
  5. 设 \(\Sigma=BFB^T+D\)(\(k\) 个因子),给出值空间法 (16.13)–(16.14) 中所有含 \(\Sigma^{-1}\) 运算的 \(O(nk^2)\) 实现,并估计 \(n=5000,\ k=40,\ m=50\) 时的运算量。

原书推荐习题:16.2(最小距离投影,组合约束投影的原型)、16.8、16.9(手算/编程有效集法)、16.10、16.11(KKT 矩阵与约化 Hessian 的性质)、16.15(工作集线性无关性)。原书第 16 章共 16.1–16.18 题,其余在下篇列出。


原书对照

本章内容 原书位置 PDF 页码
16.1 QP 定义、组合优化引例 第 16 章引言、Portfolio Optimization,式 (16.1)–(16.2) PDF p.458–460
16.2 等式约束 QP、引理 16.1、定理 16.2、例 16.1 §16.1 Equality-Constrained QPs,式 (16.3)–(16.11) PDF p.460–464
16.3 KKT 系统解法、例 16.2、共轭基方法 §16.2 Solving the KKT System,式 (16.12)–(16.23) PDF p.464–470
16.4 不等式 QP 最优性条件、退化 §16.3 Inequality-Constrained Problems,式 (16.24)–(16.26) PDF p.470–473
16.5 凸 QP 有效集法、定理 16.4–16.5、算法 16.1、例 16.3、更新 §16.4 Active-Set Methods for Convex QP,式 (16.27)–(16.40) PDF p.474–487
16.6 不定 QP、惯性控制、定理 16.6 §16.5 Active-Set Methods for Indefinite QP,式 (16.41)–(16.42) PDF p.487–493
习题 Exercises PDF p.503–505

更正说明:例 16.3 最后一步的乘子按 \(\nabla q(x^*)=\hat\lambda_1a_1\) 计算为 \(\hat\lambda_1=0.8\);原书 16.3 节"不需要假设有效约束梯度线性相关"应为"线性无关";习题 16.2 中 \(x^*\) 的符号应为加号。原书正文页码 = PDF 页码减 19(已用 PDF 页眉核对,第 12–16 章均如此)。