用 MATLAB + CVX 调用 MOSEK/SeDuMi/SDPT3 求解二维 LP 与 QP,并读懂命令行输出

CVXMATLAB 里的建模层:用接近数学形式的语句写出目标函数和约束,CVX 会把它转换成求解器(MOSEK / SeDuMi / SDPT3 等)能处理的标准形式,然后调用底层求解器求解。 这篇博客用两个二维决策变量的小例子串起来:

  1. 线性规划(LP,Linear Programming):如何在 MATLAB 中用 CVX 调用 MOSEK(也给出如何切换到 SeDuMi / SDPT3)。
  2. 二次规划(QP,Quadratic Programming):如何用 CVX 求解凸 QP

0. 环境准备与基本流程

  • 安装并初始化 CVX(只需一次):

    1
    cvx_setup
  • 在 MATLAB 中,CVX 的典型结构是:

    1
    2
    3
    4
    5
    6
    7
    cvx_begin
    cvx_solver mosek % 或 sdpt3 / sedumi ...
    variable x(2)
    minimize( ... )
    subject to
    ...
    cvx_end
    • 想看求解器命令行输出:不要写 cvx_begin quiet
    • 切换求解器:改 cvx_solver mosek / cvx_solver sdpt3 / cvx_solver sedumi
      • CVX 会在每个模型开始时读取当时的设置/或使用块内设置
      • 可以像上面这样写在 cvx_begin ... cvx_end 里面,也可以在 cvx_begin 之前设置
        • 写在 cvx_begin ... cvx_end 里面:本次模型专用的设置,通常不会影响后面其他 cvx_beginsolver
        • 写在 cvx_begin 之前:全局设置,后面所有的 CVX 模型默认都用它,直到再次 cvx_solver xxx 改掉

1 二维 LP 示例

1.1 问题定义

\(x=[x_1,x_2]^\top \in \mathbb{R}^2\),考虑线性规划:

\[\begin{eqnarray} \min_{x\in\mathbb{R}^2} \quad &&f(x)=x_1+2x_2 \nonumber\\ \text{s.t.} \quad &&x_1 \ge 0,\quad x_2 \ge 0 \nonumber\\ &&x_1 \le 2,\quad x_2 \le 2 \nonumber\\ &&x_1+x_2 \ge 1 \nonumber\\ &&2x_1+x_2 \le 3 \nonumber\\ &&x_1+2x_2 \le 3.5 \end{eqnarray}\]

为了方便写代码,转成 \[\begin{eqnarray} \min_{x\in\mathbb{R}^2} \quad &&c^\top x \nonumber\\ \text{s.t.} \quad &&Ax\le b. \end{eqnarray}\]

其中,

\[\begin{equation} c=[1,2]^\top,\quad A= \begin{bmatrix} -1&0\\ 0&-1\\ 1&0\\ 0&1\\ -1&-1\\ 2&1\\ 1&2 \end{bmatrix},\quad b= \begin{bmatrix} 0\\ 0\\ 2\\ 2\\ -1\\ 3\\ 3.5 \end{bmatrix}, \end{equation}\]


1.2 MATLAB/CVX 代码(LP)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
%% LP: minimize c'*x  s.t. A*x <= b
clear; clc;

c = [1;2];
A = [ -1 0;
0 -1;
1 0;
0 1;
-1 -1;
2 1;
1 2];
b = [0;0;2;2;-1;3;3.5];

% 选择求解器(可改成 sedumi / sdpt3)
cvx_solver mosek

cvx_begin
variable x(2)
minimize( c' * x )
subject to
A*x <= b
cvx_end

fprintf('CVX optimum: x = [%.8f, %.8f]^T, f = %.8f\n', x(1), x(2), cvx_optval);

2 二维 QP 示例:CVX 求解凸二次规划

2.1 问题定义

这里给一个二次目标(\(Q\succeq 0\)),线性约束与上面类似,方便对比:

\[\begin{equation} \min_{x\in\mathbb{R}^2} \quad \frac{1}{2}x^\top Qx + q^\top x \end{equation}\]

\[\begin{equation} Q= \begin{bmatrix} 2&0\\ 0&4 \end{bmatrix}\succ 0,\quad q= \begin{bmatrix} -2\\ -6 \end{bmatrix}. \end{equation}\]

约束仍取一个有界可行域(线性约束): \[\begin{equation} Ax\le b, \end{equation}\] 其中, \[\begin{equation} A =\begin{bmatrix} -1&0\\ 0&-1\\ 1&0\\ 0&1\\ -1&-1\\ 2&1\\ 1&2 \end{bmatrix},\quad b= \begin{bmatrix} 0\\ 0\\ 2\\ 2\\ -1\\ 3\\ 3.5 \end{bmatrix}. \end{equation}\]


2.2 MATLAB/CVX 代码(QP)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
%% QP: minimize 0.5*x'*Q*x + q'*x  s.t. A*x <= b
clear; clc;

Q = [2 0; 0 4]; % 正定 -> 凸
q = [-2; -6];

A = [ -1 0;
0 -1;
1 0;
0 1;
-1 -1;
2 1;
1 2];
b = [0;0;2;2;-1;3;3.5];

% 你可以试:mosek / sedumi / sdpt3
cvx_solver mosek

cvx_begin
variable x(2)
minimize( 0.5*quad_form(x,Q) + q'*x )
subject to
A*x <= b
cvx_end

fprintf('CVX optimum (QP): x = [%.8f, %.8f]^T, f = %.8f\n', x(1), x(2), cvx_optval);

3 不同求解器命令行输出

MatlabCVX 工具箱求解该 LP 问题之后命令行输出的前两行结构类似,均为:

1
2
3
Calling (MOSEK / SeDuMi / SDPT3) (版本号): 7 variables, 2 equality constraints
For improved efficiency, (MOSEK / SeDuMi / SDPT3) is solving the dual problem.
------------------------------------------------------------
  • 这两行:CVX 打印的(不是求解器)

  • 为什么会出现 7 variables, 2 equality constraints,而原问题只有 2 个变量?

  • 因为 CVX 会把你写的形式 \(Ax ≤ b\) 做等价变换后再交给求解器

  • 对 LP 来说,最典型的是交给求解器的是对偶问题:

    • 原问题(primal):

    \[ \min\ c^\top x\quad \text{s.t.}\ Ax\le b \]

    • 对偶问题(dual): \[ \max\ -b^\top y\quad \text{s.t.}\ A^\top y + c = 0,\ y\ge 0 \]
      • 这里 \(y \in \mathbb{R}^7\)每条不等式约束对应一个对偶变量 \(\to\) 7 variables
      • 约束 \(A^\top y + c = 0\) 是 2 维向量等式 \(\to\) 2 equality constraints

下面贴出三种不同求解器(MOSEK / SeDuMi / SDPT3)其余行的输出,再逐块进行解释。

点击展开:MOSEK 求解 LP 的命令行输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
MOSEK Version 9.1.9 (Build date: 2019-11-21 11:34:40)
Copyright (c) MOSEK ApS, Denmark. WWW: mosek.com
Platform: Windows/64-X86

Problem
Name :
Objective sense : min
Type : LO (linear optimization problem)
Constraints : 2
Cones : 0
Scalar variables : 7
Matrix variables : 0
Integer variables : 0

Optimizer started.
Presolve started.
Linear dependency checker started.
Linear dependency checker terminated.
Eliminator started.
Freed constraints in eliminator : 0
Eliminator terminated.
Eliminator started.
Freed constraints in eliminator : 0
Eliminator terminated.
Eliminator - tries : 2 time : 0.00
Lin. dep. - tries : 1 time : 0.00
Lin. dep. - number : 0
Presolve terminated. Time: 0.00
Problem
Name :
Objective sense : min
Type : LO (linear optimization problem)
Constraints : 2
Cones : 0
Scalar variables : 7
Matrix variables : 0
Integer variables : 0

Optimizer - threads : 16
Optimizer - solved problem : the primal
Optimizer - Constraints : 2
Optimizer - Cones : 0
Optimizer - Scalar variables : 7 conic : 0
Optimizer - Semi-definite variables: 0 scalarized : 0
Factor - setup time : 0.00 dense det. time : 0.00
Factor - ML order time : 0.00 GP order time : 0.00
Factor - nonzeros before factor : 3 after factor : 3
Factor - dense dim. : 0 flops : 3.10e+01

ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME
0 4.4e+00 5.5e+00 2.4e+01 0.00e+00 7.571067812e+00 0.000000000e+00 7.7e+00 0.00
1 8.6e-01 1.1e+00 4.6e+00 3.08e-01 2.073929624e+00 1.959556263e-01 1.5e+00 0.00
2 5.4e-02 6.8e-02 2.9e-01 7.76e-01 1.101189936e+00 9.746812673e-01 9.4e-02 0.00
3 2.2e-04 2.8e-04 1.2e-03 9.86e-01 1.000188050e+00 9.996902234e-01 3.8e-04 0.00
4 2.2e-08 2.8e-08 1.2e-07 1.00e+00 1.000000019e+00 9.999999690e-01 3.8e-08 0.00
5 2.2e-12 2.8e-12 1.2e-11 1.00e+00 1.000000000e+00 1.000000000e+00 3.8e-12 0.00
Basis identification started.
Primal basis identification phase started.
Primal basis identification phase terminated. Time: 0.00
Dual basis identification phase started.
Dual basis identification phase terminated. Time: 0.00
Basis identification terminated. Time: 0.00
Optimizer terminated. Time: 0.00


Interior-point solution summary
Problem status : PRIMAL_AND_DUAL_FEASIBLE
Solution status : OPTIMAL
Primal. obj: 1.0000000000e+00 nrm: 2e+00 Viol. con: 2e-12 var: 0e+00
Dual. obj: 1.0000000000e+00 nrm: 2e+00 Viol. con: 0e+00 var: 1e-12

Basic solution summary
Problem status : PRIMAL_AND_DUAL_FEASIBLE
Solution status : OPTIMAL
Primal. obj: 1.0000000000e+00 nrm: 2e+00 Viol. con: 0e+00 var: 0e+00
Dual. obj: 1.0000000000e+00 nrm: 2e+00 Viol. con: 0e+00 var: 1e-13
Optimizer summary
Optimizer - time: 0.00
Interior-point - iterations : 5 time: 0.00
Basis identification - time: 0.00
Primal - iterations : 0 time: 0.00
Dual - iterations : 0 time: 0.00
Clean primal - iterations : 0 time: 0.00
Clean dual - iterations : 0 time: 0.00
Simplex - time: 0.00
Primal simplex - iterations : 0 time: 0.00
Dual simplex - iterations : 0 time: 0.00
Mixed integer - relaxations: 0 time: 0.00

  1. Problem 概览块

    • Type : LO:线性优化(Linear Optimization)
    • Constraints : 2:等式约束数(这里是指对偶问题的等式约束数)
    • Cones : 0:没有锥约束(LP 不需要 SOC/SDP 锥)
    • Scalar variables : 7:变量数(这里是指对偶变量个数)
  2. Presolve 块

    • Presolve / Linear dependency checker / Eliminator:预处理(去冗余、检查线性相关、尝试消去变量等)。这个问题很小,所以时间基本是 0。
  3. Optimizer / Factor

    • Optimizer - threads : 16:MOSEK 使用的 CPU 线程数(并行数)

    • Optimizer - solved problem : the primal:MOSEK 在内部选择以 primal 形式驱动内点法

      • 这说的是MOSEK 当前拿到的模型的 primal/dual 选择;不等同于原始建模问题的 primal/dual
    • Optimizer - Constraints / Scalar variables / Cones ...:再次汇总求解阶段实际处理的模型规模

    • Factor - setup time ... / order time ...:内点法每次迭代都需要解一组 KKT 线性方程组(一阶最优条件线性化后的方程)

      • MOSEK 会对该线性系统做稀疏分解,setup/order time 是分解准备和排序(重排以减少填充)的时间统计
    • Factor - nonzeros before factor : 3 after factor : 3:分解前/后的非零元数量统计(体现稀疏结构与“填充”程度)

      • 该 LP 问题非常小,所以数字也很小,基本没有填充
    • Factor - dense dim ... flops ...:分解时涉及的致密块维度与浮点运算量(同样因为问题小,所以几乎可忽略)

  4. 迭代表

    • ITE:内点法迭代步

    • PFEAS / DFEAS:原始/对偶可行性残差(越接近 \(0\) 越好)

    • GFEAS:与互补性/间隙相关的残差指标(越接近 \(0\) 越好)

    • PRSTATUS:一个“状态指标”,如果问题有最优解它会趋近于 1;否则可能趋近 -1

    • POBJ / DOBJ:原始/对偶目标值估计(收敛时两者几乎相等)

    • MU:障碍参数/互补性量级(应趋近 0)

      • 上面这段输出中,迭代到第 5 步:
        • PFEAS/DFEAS/GFEAS 都到 \(10^{-11}\sim10^{-12}\)
        • POBJ = DOBJ = \(1.0\) 说明收敛到最优
  5. Basis identification

    • 这是一段后处理:内点法解出来的解不一定是基解
    • MOSEK 会尝试构造一个最优基(方便 simplex 热启动/敏感性分析等)
  6. Solution summary

    • Problem status : PRIMAL_AND_DUAL_FEASIBLE:原始和对偶都可行
    • Solution status : OPTIMAL:最优
    • Primal/Dual obj:原始/对偶目标值(两者应一致或非常接近)
    • nrm:解向量的无穷范数(MOSEK 用它作为“规模量级”参考)
    • Viol. con / var:约束/变量违反量(应接近 0)
点击展开:SeDuMi 求解 LP 的命令行输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SeDuMi 1.3.4 by AdvOL, 2005-2008 and Jos F. Sturm, 1998-2003.
Alg = 2: xz-corrector, Adaptive Step-Differentiation, theta = 0.250, beta = 0.500
eqs m = 2, order n = 8, dim = 8, blocks = 1
nnz(A) = 10 + 0, nnz(ADA) = 4, nnz(L) = 3
it : b*y gap delta rate t/tP* t/tD* feas cg cg prec
0 : 1.56E+01 0.000
1 : 1.12E-01 3.81E+00 0.000 0.2446 0.9000 0.9000 2.31 1 1 1.6E+00
2 : 1.01E+00 3.79E-01 0.000 0.0995 0.9900 0.9900 1.09 1 1 2.0E-01
3 : 9.99E-01 7.67E-03 0.000 0.0202 0.9900 0.9900 1.03 1 1
iter seconds digits c*x b*y
3 0.5 Inf 1.0000000000e+00 1.0000000000e+00
|Ax-b| = 2.3e-16, [Ay-c]_+ = 0.0E+00, |x|= 1.4e+00, |y|= 1.0e+00

Detailed timing (sec)
Pre IPM Post
5.280E-01 9.440E-01 4.800E-02
Max-norms: ||b||=2, ||c|| = 2,
Cholesky |add|=0, |skip| = 0, ||L.L|| = 1.

SeDuMi 也是内点法,但它的打印风格不同。

  1. 算法配置行
    • Alg = 2: xz-corrector, Adaptive Step-Differentiation, theta = 0.250, beta = 0.500
      • Alg=2:使用 内点法 的一种实现(带 预测-校正/纠正器,这里标成 xz-corrector
      • Adaptive Step-Differentiation:步长/更新策略是自适应的(更稳、更快收敛)
      • theta, beta:算法内部的参数(影响步长与中心化程度),通常用户不需要改
  2. 问题规模/锥结构摘要
    • eqs m = 2, order n = 8, dim = 8, blocks = 1
      • m=2:等式约束数量(求解器标准化后形式里的等式条数)
      • n=8 / dim=8:标准化后变量(或锥变量)维度规模
      • blocks=1:锥/块结构只有 1 个块(例如一个线性锥块或合并成一个块)
  3. 稀疏性与线性代数工作量提示
    • nnz(A) = 10 + 0, nnz(ADA) = 4, nnz(L) = 3
      • nnz(A):约束矩阵 A 的非零元素个数10+0 常见表示主块+附加块/修正块,关键是稀疏度级别)
      • nnz(ADA):形成/使用的 正规方程/Schur 补矩阵(常记作 (A D A^))的非零数,反映求解线性系统的“密度”
      • nnz(L):Cholesky 分解得到的 下三角因子 L 的非零数(越小越省时省内存)
  4. 迭代表
    • it : b*y gap delta rate t/tP* t/tD* feas cg cg prec
      • it:迭代次数
      • b*y:对偶目标值(通常是 \(b^\top y\) 的当前值)
      • gap:原始-对偶 对偶间隙(衡量离最优还有多远,越接近 0 越好)
      • delta:当前迭代的某种残差/扰动指标(很多时候显示为 0 表示无需额外修正或已很小)
      • rate:gap 等量的收敛比率/下降速度指标(越小通常代表下降更快)
      • t/tP*t/tD*:原始/对偶方向的步长比例(接近 1 通常表示可以走较大步,进展顺利)
      • feas:可行性/残差的量级指标(越接近 1 或越小越好,取决于 SeDuMi 的定义;结合最后的残差行看最可靠)
      • cg cg:是否使用/以及共轭梯度(CG)相关信息(这里基本一直是 1,表示该步的线性系统解法状态正常)
      • prec:预条件/精度相关指标(数值越小通常表示更精)
  5. 收敛汇总行(迭代耗时与目标)
    • iter=3:用了 3 次内点迭代
    • digits=Inf:达到非常高的数值精度/收敛判据(可理解为收敛很好
    • c*x 与 b*y 相等:原始目标 \(c^\top x\) 和对偶目标 \(b^\top y\) 一致(强收敛信号,对偶间隙基本为 0)
  6. 残差与解的规模检查
    • |Ax-b| = 2.3e-16, [Ay-c]_+ = 0.0E+00, |x|=1.4e+00, |y|=1.0e+00
      • |Ax-b|原始等式残差,越近似 0,越说明原始可行性极好
      • [Ay-c]_+:对偶不等式的正部违反量(常用于衡量对偶可行性),为 0 表示对偶可行
      • |x|, |y|:解向量的范数大小,主要用于观察解是否爆炸/异常大
  7. 计时明细
    • Detailed timing (sec)
      • Pre:预处理/建模转换、消元、缩放等耗时
      • IPM:内点法主迭代耗时(解线性系统是大头)
      • Post:后处理/恢复原变量、输出整理耗时 > 这块用于判断时间花在哪:建模预处理 vs 主求解
  8. 规模与分解信息(数值线性代数提示)
    • Max-norms: ||b||=2, ||c|| = 2,
      • (b, c) 的最大范数规模,用于判断数值尺度是否正常(过大/过小可能导致病态)
    • Cholesky |add|=0, |skip| = 0, ||L.L|| = 1.
      • Cholesky 分解时 没有额外填充(add)、也没有跳过(skip) —— 说明分解过程顺利稳定
      • ||L.L||:分解因子的量级提示(这里为 1,尺度正常)
点击展开:SDPT3 求解 LP 的命令行输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 num. of constraints =  2
dim. of linear var = 7
*******************************************************************
SDPT3: Infeasible path-following algorithms
*******************************************************************
version predcorr gam expon scale_data
NT 1 0.000 1 0
it pstep dstep pinfeas dinfeas gap prim-obj dual-obj cputime
-------------------------------------------------------------------
0|0.000|0.000|9.4e+00|5.5e+00|7.0e+02| 5.500000e+01 0.000000e+00| 0:0:00| chol 1 1
1|1.000|0.935|1.6e-06|4.1e-01|8.9e+01| 4.983854e+01 1.218700e+00| 0:0:01| chol 1 1
2|1.000|1.000|9.9e-07|5.9e-03|1.0e+01| 1.047071e+01 3.642978e-01| 0:0:01| chol 1 1
3|0.889|1.000|1.4e-07|5.9e-04|1.2e+00| 1.780218e+00 6.225268e-01| 0:0:01| chol 1 1
4|1.000|0.880|5.8e-08|1.2e-04|2.2e-01| 1.181589e+00 9.583666e-01| 0:0:01| chol 1 1
5|0.983|0.986|9.5e-10|7.6e-06|3.8e-03| 1.003156e+00 9.993401e-01| 0:0:01| chol 1 1
6|0.989|0.989|2.3e-11|6.7e-07|4.3e-05| 1.000035e+00 9.999947e-01| 0:0:01| chol 1 1
7|0.989|0.989|4.1e-12|7.3e-09|4.7e-07| 1.000000e+00 9.999999e-01| 0:0:01| chol 1 1
8|0.996|1.000|3.8e-14|1.0e-12|6.6e-09| 1.000000e+00 1.000000e+00| 0:0:01|
stop: max(relative gap, infeasibilities) < 1.49e-08
-------------------------------------------------------------------
number of iterations = 8
primal objective value = 1.00000001e+00
dual objective value = 9.99999999e-01
gap := trace(XZ) = 6.59e-09
relative gap = 2.20e-09
actual relative gap = 2.19e-09
rel. primal infeas (scaled problem) = 3.82e-14
rel. dual " " " = 1.00e-12
rel. primal infeas (unscaled problem) = 0.00e+00
rel. dual " " " = 0.00e+00
norm(X), norm(y), norm(Z) = 1.4e+00, 1.0e+00, 3.6e+00
norm(A), norm(b), norm(C) = 5.0e+00, 3.2e+00, 4.5e+00
Total CPU time (secs) = 0.70
CPU time per iteration = 0.09
termination code = 0
DIMACS: 4.1e-14 0.0e+00 1.5e-12 0.0e+00 2.2e-09 2.2e-09
-------------------------------------------------------------------
  1. 规模概览
    • num. of constraints = 2:SDPT3 接收到的等式约束数量(通常是 CVX 标准化后的形式)
    • dim. of linear var = 7:SDPT3 标准形式中的线性锥/线性部分变量维度(不一定等于原始 LP 的变量个数,是 CVX 转换后的维度)
  2. 求解器与算法类型提示(横幅)
    • SDPT3: Infeasible path-following algorithms
      • 说明 SDPT3 使用的是一类内点法(路径跟随, path-following)实现
      • 这里的 “Infeasible” 是算法名(允许从不可行初始点出发并逐步逼近可行/最优),不表示该问题不可行
  3. 关键算法开关/参数
    • version predcorr gam expon scale_data
      • predcorr = 1:开启预测-校正(predictor-corrector)内点法(通常更快更稳)
      • scale_data = 0:不做(或不启用)数据缩放/归一化处理(有些问题开启缩放会更稳)
      • gam, expon:算法内部参数,一般只需知道这是内点法参数配置
  4. 迭代
    • it pstep dstep pinfeas dinfeas gap prim-obj dual-obj cputime ... chol 1 1
      • it:迭代次数
      • pstep / dstep:本次迭代的原始/对偶步长(越接近 1 通常越顺利)
      • pinfeas / dinfeas:原始/对偶不可行度(残差),越小越好
      • gap对偶间隙(离最优的差距),越小越好
      • prim-obj / dual-obj:当前原始目标值 / 对偶目标值(收敛时应非常接近)
      • cputime:累计耗时
      • chol 1 1:该迭代主要线性代数步骤采用 Cholesky 分解(后面的数字是内部状态/标记)
    • 迭代过程主要看三件事是否单调变好
      1. pinfeas/dinfeas 从大到接近 0(可行性越来越好)
      2. gap 快速变小到很小(逼近最优)
      3. prim-obj 与 dual-obj 越来越接近(原始/对偶一致性)
    • 停止条件 stop: max(relative gap, infeasibilities) < 1.49e-08
      • 停止判据:相对 gap不可行度 的最大值已经小于阈值 \(1.49\times 10^{-8}\),所以认为收敛
  5. 收敛总结
    • primal / dual objective value = ...原始/对偶目标值,最终非常接近(说明解已稳定)
    • gap = trace(XZ):SDP/锥规划语境下的互补性度量(对 LP 的锥形式也适用),越接近 \(0\) 越好
    • relative gap / actual relative gap:gap 的相对指标(越接近 \(0\) 越好)
  6. 可行性指标(scaled / unscaled)
    • rel. primal(dual) infeas (scaled problem):若内部做了缩放/等价变换,给出在该尺度下的残差
    • rel. primal(dual) infeas (unscaled problem):对应原尺度(或恢复后)的残差;这为 0 表示恢复到原问题尺度后可行性很好
  7. 范数信息(量级检查)
    • norm(·), norm(·), norm(·) = ...
      • 给出变量/数据的量级,主要用于诊断数值问题
      • 如果范数量级极端(特别大或特别小),可能暗示病态、缩放需求等
  8. 时间与退出码
    • Total CPU time ... / per iteration ...总耗时/每步耗时
    • termination code = 0:正常收敛结束(一般 0 表示成功)
  9. DIMACS 误差向量
    • 一组标准化的误差/残差度量(DIMACS 指标),用于统一评价原始可行、对偶可行、互补性等。
    • 数值越小越好

MatlabCVX 工具箱求解该 LP 问题之后命令行输出的最后两行均为:

1
2
3
------------------------------------------------------------
Status: Solved
Optimal value (cvx_optval): +1
  • Status: Solved:CVX 的最终状态,问题已被成功求解并满足其收敛/可行性判据(不是“尝试过”,而是认为已找到可接受的最优解)。

  • Optimal value (cvx_optval): +1:CVX 记录的最优目标函数值,存放在变量 cvx_optval 里。 这里等于 +1,即定义的目标函数在最优解处的值为 1(符号 “+” 只是显示格式)。


4 求解 QP(二次规划)时,命令行输出会有什么变化?

通常会有如下变化:

  1. MOSEK

    • Type 往往不再是 LO,而会显示为CONIC (conic optimization problem)
    • 迭代表依然会有 PFEAS/DFEAS/POBJ/DOBJ/MU 这类列(内点法风格非常像)。
  2. SeDuMi / SDPT3

    • 由于它们本质上解的是锥规划,CVX 会把 QP 的二次目标转成等价的锥形式(常见是 SOC/旋转二次锥)。
    • 因此日志里经常能看到:锥维度/块结构发生变化(例如 cone blocks、dim/order 等统计改变),迭代列名依旧类似(gap、feas、pinfeas、dinfeas 等)。

5 在使用 MOSEK 求解器时遇到的问题

检测到线性相关,但 Presolve 后约束数仍显示不变

现象

在用 CVX + MOSEK 求解某个 LP 的对偶问题时,命令行输出中会出现类似信息:

  • Linear dependency checker started/terminated

  • Lin. dep. - number : 1

  • 但在 Presolve terminated 后,摘要里仍显示:

    • Constraints : 3
    • 并且 Freed constraints in eliminator : 0

与此同时,从数学形式上看,该对偶模型的三条不等式约束中,第 3 条确实可由前两条线性组合得到,例如:

  • (c1) 形如:\[ a^\top y \le 1 \]
  • (c2) 形如:\[ b^\top y \le 2 \]
  • (c3) 形如:\[ (a+b)^\top y \le 3 \]

显然 (c3) = (c1)+(c2),因此 (c3) 是冗余不等式


为什么会这样?

MOSEK 日志里的 Constraints : 3 表示模型里线性约束的“行数”,并不等价于“线性无关约束的数量/约束矩阵的秩”。

  • 即便存在冗余或线性相关,日志摘要仍可能显示原来的约束条数。

更重要的是: MOSEK 的 linear dependency checker 主要针对的是线性等式(或能导致 KKT 系统奇异的那类依赖)去做秩相关的处理;而这里的相关性发生在 不等式 之间。对于不等式来说:

  • 证明“某条不等式被其它不等式蕴含(冗余)”往往更复杂(本质上属于冗余约束检测),求解器通常会做得比较保守;
  • 即使检测到“系数行层面”的线性相关,也不一定会把它安全删除(尤其涉及数值容差、边界可行域是否完全等价等问题);
  • 因此会出现:检测到依赖(Lin. dep. number = 1),但 presolve 不删除约束(freed constraints = 0),约束数仍显示为 3

实战建议(对建模/求解速度更友好)

  • 能人工识别的明显冗余不等式,建议在建模阶段直接删掉。 冗余约束往往会引入退化、增加内点法 KKT 系统的规模或数值负担,删掉通常不会影响结果,反而更稳更快。
  • 不要仅根据日志里 Constraints 的数值判断求解器是否做了冗余消除,那只是行数统计,不是独立约束数

结语

用 CVX 写 LP/QP 的体验是统一的:写数学模型,CVX负责转换,求解器负责迭代。命令行输出里最“承重”的信息其实就三类:

  • 模型规模统计(变量 / 约束 / 锥结构)
  • 迭代表(feasibility + gap + objective)
  • 最终状态(Solved/Optimal + violation)

用 MATLAB + CVX 调用 MOSEK/SeDuMi/SDPT3 求解二维 LP 与 QP,并读懂命令行输出
https://nanana-szz.github.io/01-cvx-LP-QP/
作者
John Doe
发布于
2026年1月8日
许可协议