MATLAB优化利器YALMIP:半定规划与LMI建模实战指南

发布时间:2026/10/28 7:46:02
MATLAB优化利器YALMIP:半定规划与LMI建模实战指南 简介YALMIP-R20210331.zip 是 MATLAB 优化工具箱 YALMIP 在 2021 年 3 月发布的版本面向科研人员、工程师与学生解决线性、非线性、整数、混合整数及半定规划等优化模型的快速建模与求解问题。压缩包共含 1390 个文件主体为 1379 个 m 源文件覆盖核心算法与接口函数另有 4 个 txt 文档、3 个 mat 数据、2 个 c 源文件及少量辅助文件整体仅 1.23MB轻量易用。已有 268 人学习浏览。解压后可获得完整源代码、说明文档、示例与安装指引支持用 sdpvar、intvar 等命令以数学表达式直接建模并可通过统一接口对接 Gurobi、CPLEX、MOSEK 等后端便于在不同求解环境间切换。对于希望在 MATLAB 中高效开展优化建模、算法验证或二次开发的读者这套源码包具有直接参考价值。1. YALMIP-R20210331为什么MATLAB优化问题值得单独装一个工具箱一个做控制的朋友过来问想验证一个Lyapunov不等式手工推导、整理成严格LMI再调求解器折腾了一下午还没出数。我给他装了这个YALMIP工具箱定义变量、写约束、调optimize三行代码五分钟出了结果。YALMIP是一个纯MATLAB建模层工具箱负责把线性规划、二次规划、半定规划、混合整数规划等优化问题翻译成求解器能吃的标准形式实际计算交给下游求解器完成。适合控制理论验证、机器学习稀疏回归、通信信号处理、组合优化等场景尤其是矩阵不等式、半定规划这类手工建模容易写错的问题。这个R20210331版是2021年3月31日发布的稳定快照覆盖绝大多数脱离具体领域研究的优化建模需求下面把安装、语法和踩坑一次说清楚。2. 安装与环境配置把 R20210331 跑起来的完整步骤2.1 前提检查MATLAB 版本与后端求解器缺一不可YALMIP 本身是建模层不包含数值求解内核。这一点特别容易被第一次用的人忽略装完 YALMIP 后直接跑 SDP 例子大概率报 “No suitable solver for problem” 或者 “Could not find a solver”。不是工具箱坏了是因为它没找到能解半定规划的后端求解器。MATLAB 自带的 linprog、quadprog、fmincon 能覆盖一部分 LP 和 QP 问题但碰到半定约束就无能为力。所以在使用 YALMIP 前需要确认两件事一是 MATLAB 版本不过旧R2016a 以上比较稳妥二是准备一个能解 SDP/SOCP 的开源求解器。我一般装过 Parsons 的 sedumi 和 sdpt3两者都是纯 MATLAB 实现不需要编译解压后 addpath 即可用和 YALMIP 的 R20210331 搭配非常顺。如果跑大规模问题可以额外装 SCS通过 mex 编译但官方有预编译包如果做混合整数规划也可以装 GUROBI 或 Mosek但那是商业授权。2.2 解压与 addpath三句话完成安装假设已经把 zip 包下载到本地常见做法是先解压到一个固定的工具目录然后一次性把整个目录递归加入 MATLAB 路径。我用的是一个固定目录 D:\tools\所有第三方工具箱统一放那里。% 把 YALMIP-R20210331.zip 解压到目标目录 unzip(YALMIP-R20210331.zip, D:\tools\); % 递归添加整个工具箱目录及子目录 addpath(genpath(D:\tools\YALMIP-R20210331)); % 保存当前路径配置重启 MATLAB 后仍然生效 savepath第一行解压第一个参数是压缩包路径第二个参数是解压目标。如果手头已经有解压好的文件夹这步可跳过。第二行的 genpath 会自动扫描该目录下所有子文件夹并生成完整路径列表比直接 addpath 单层目录靠谱得多因为 YALMIP 内部目录结构里还嵌套着扩展功能子目录。第三行的 savepath 会把当前工作路径写入 pathdef.m如果这一步提示没有写入权限常见原因是 MATLAB 安装根目录受系统保护解决方法是不要强行保存到安装目录把 addpath 命令写进用户自己的 startup.m每次启动自动加载。2.3 验证安装which 与 yalmiptest 双保险路径加好后的第一步不是急着写代码而是确认核心函数是否在预期路径上。% 查看 YALMIP 核心函数是否被识别 which sdpvar which optimize如果输出显示完整路径比如 D:\tools\YALMIP-R20210331\yalmip\sdpvar.m说明建模层已经挂上。如果显示 ‘sdpvar’ not found说明路径没加对重新检查 2.2 里两步。接下来建议跑一遍自带诊断脚本% 运行安装检查会逐项测试当前环境下可用的求解器 yalmiptest这个脚本会遍历所有 YALMIP 认识的求解器并做小规模自检输出每个求解器的可用状态。如果列表里 sedumi 旁边显示 “OK” 而别的显示 “FAILED”说明 sedumi 已经就绪其余失败只是因为你没装不影响使用。我这里通常会再跑一个最小 LP 实际验证整条链路脚本如下x sdpvar(2, 1); Constraints [x(1) x(2) 1; x(1) - x(2) 1; x 0]; Objective -x(1) - 2*x(2); optimize(Constraints, Objective); value(x)如果输出一个合理的二维解而不是报错说明 YALMIP 建模到 MATLAB 自带 linprog 这条通道是通的。注意这里用分号拼排约束一次建立多个条件YALMIP 会按列拼接。3. 核心建模语法sdpvar、约束、optimize 的底层逻辑3.1 sdpvar 与变量类型矩阵连续、整数与二进制YALMIP 建模的起点是声明变量。最常用的是 sdpvar它既能表示普通实数向量/矩阵也能通过第三个参数声明成对称或 Hermitian 矩阵。这个特性是解决 LMI 问题时最省事的地方手工建模时你需要定义一个对称变量矩阵并额外加对称约束YALMIP 里直接声明类型即可。% 5x5 对称矩阵变量 S sdpvar(5, 5, symmetric); % 2x2 Hermitian 矩阵变量复数域共轭对称 H sdpvar(2, 2, hermitian); % 普通实数列向量 x sdpvar(3, 1); % 二进制变量 b binvar(5, 1); % 一般整数变量 iv intvar(4, 1);关键在第三个参数sdpvar(n, n, symmetric) 声明一个对称变量矩阵求解时内部会自动把它映射到 n(n1)/2 个独立标量不会真的存下 n*n 个独立元素所以变量计数和内存开销都得到控制。如果什么都不写默认按全矩阵独立元素处理。这里最常见的误用是把方形矩阵直接当对称用结果解出来的矩阵不对称后面避坑部分会细说。整数和二进制变量分别用 intvar 和 binvar二者可以和 sdpvar 混在同一组约束里YALMIP 会将其归类为混合整数规划并调用相应求解器如 GUROBI 或 MATLAB 自带 intlinprog。3.2 约束与 optimize把问题交给求解器前发生了什么有了变量下一步是写约束和目标函数。YALMIP 用 、、 表达约束关系而且这几种比较符号在矩阵情形下有明确定义A B 表示 A-B 是半正定矩阵等价于矩阵不等式约束。这一点是初学者最容易吃惊的地方因为 MATLAB 原生语法中比较符号只能用于标量逻辑判断而 YALMIP 对其做了重载。x sdpvar(2, 1); Constraints [x(1) x(2) 1; x(1) - x(2) 1; x 0]; Objective x(1)^2 x(2)^2; ops sdpsettings(solver, fmincon); diagnostics optimize(Constraints, Objective, ops);optimize 的核心参数是三个第一个是约束集合第二个是目标函数第三个是求解器设置。调用会触发 YALMIP 预处理流程展开矩阵约束、检测问题类别LP/QP/SOCP/SDP/MILP、调用可用求解器、把约束和目标转换成求解器要求的线性代数形式。返回的 diagnostics 是结果结构体里面有 problem 字段0 表示问题成功求解。注意这行代码里用 sdpsettings 指定了 fmincon如果不想手动指定YALMIP 会按“当前已装求解器里最合适的一个”自动选择。常见做法是先把约束和目标都写成标准 KY 变量形式再交给 optimize 一次成型。初学者容易犯的错是把约束写完后不拼成数组而是直接传一个约束表达式结果报错说“not a Set object”。解决方法是把多个约束放进方括号拼成数组像上面示例那样。如果约束为 0 个也需要显式传 []。### 3.3 求解器选择不同后端适用边界与切换参数 YALMIP 的优势之一是可切换后端。同样是 SDP不同问题规模、精度要求选择不同的求解器结果和耗时差异显著。我把自己常用的几种后端参数整理成表格方便做选择时一眼对比。 | 求解器 | 适用问题类型 | 特点 | 注意点 | |---|---|---|---| | sedumi | LP/SDP/SOCP | 精度较高内存占用适中纯 MATLAB 实现 | 对病态问题数值稍敏感建议配合平衡约束尺度 | | sdpt3 | LP/SDP/SOCP | 稳定性好适合中等规模 SDP | 收敛速度比 sedumi 稍慢但迭代更稳 | | scs | 大规模 SDP/SOCP/LP | 基于 ADMM适合大规模稀疏问题 | 默认精度低一档需调 tol 参数 | | fmincon | 非凸光滑问题 | MATLAB 自带的 SQP 系列算法 | 不保证全局最优对矩阵不等式支持较差 | | gurobi/mosek | LP/MIP/QP/SOCP/SDP 全覆盖 | 商业求解器速度和数值稳定性顶尖 | 需要授权接入时需留意 mex 版本 | 切换求解器只需要在 sdpsettings 里改 solver 字段。比如我想强行用 sedumi 求一个 SDP 问题 matlab ops sdpsettings(solver, sedumi, verbose, 1); optimize(Constraints, Objective, ops);verbose 参数控制显示详细程度0 安静1 显示基础信息2 输出更详细的迭代日志。调试阶段我会开到 2 看求解器收敛情况稳定运行后调到 0。切换求解器时最常见的坑是先前在用 sedumi后来装了 scs但代码里忘了改 solver 名导致 YALMIP 报 “Solver not found”反过来如果你显式指定了一个没有装的求解器YALMIP 会直接报错而不是自动退回。所以要么用自动选择要么在切换脚本里先通过 available 求解器列表做判断。4. 实战用 YALMIP 求解 SDP/LMI 问题的两个典型场景4.1 最小化矩阵最大特征值SDP 建模在控制理论和组合优化里经常遇到“让某个矩阵的最大特征值尽量小”的问题。这类问题本质上是半定规划手工推导的拆解工作非常繁琐而 YALMIP 只需要把矩阵不等式直接写出来即可。考虑一个给定对称矩阵 M要求一个标量 t 使得 tI - M 半正定同时最小化 t。半正定条件等价于 t 大于等于 M 的最大特征值所以求解结果就是 M 的最大特征值。rng(1); M randn(5, 5); M M M; % 强制对称保证特征值全部为实数 t sdpvar(1, 1); Constraints [t*eye(5) - M 0]; % 矩阵半正定约束 Objective t; optimize(Constraints, Objective); % 回读结果做交叉验证 t_star value(t); lambda_max max(eig(M)); fprintf(YALMIP 得到的最大特征值上界: %.6f\n, t_star); fprintf(直接 eig 计算的真实最大特征值: %.6f\n, lambda_max);代码里 Constraints 中使用了 eye(5) 把标量 t 扩成对角阵再与 M 相减。YALMIP 会识别这个约束为线性矩阵不等式归类为 SDP 问题自动交给 sedumi 或 sdpt3 求解。交叉验证部分建议保留通过 value(t) 取回结果后再用 MATLAB 裸命令 eig(M) 直接计算最大特征值两者理论值一致但数值路径完全不同可以互相验证。如果求解出现问题这个对比是重要的诊断手段。这里有个细节约束中没有像手工推导那样写“M 是对称的”因为前面已经对 M 做了对称化。如果原问题中 M 本身是对称的这步省略即可如果 M 非对称半正定约束本身就不成立因为只有对称矩阵才能定义半正定性。4.2 Lyapunov 稳定性验证线性系统的控制器权衡在控制理论里线性时不变系统 x Ax 渐近稳定的充分必要条件是存在对称正定矩阵 P满足 Lyapunov 不等式 AP PA 0。手工验证时需要先猜一个 P再检查特征值费时且不保证找到。把问题交给 YALMIP 后把不等式直接写出来即可。A [-0.8 0.2; -0.1 -1.2]; P sdpvar(2, 2, symmetric); epsilon 1e-6; Constraints [A*P P*A -epsilon*eye(2); P epsilon*eye(2)]; Objective []; optimize(Constraints, Objective); if optimize(Constraints, Objective) 0 P_sol value(P); disp(找到满足 Lyapunov 条件的对称正定矩阵 P); disp(P_sol); else disp(系统可能不稳定或条件过严); end这个例子里我用 epsilon 1e-6 代替严格的 0避免求解器在可行域边界处数值抖动。这是 LMI 求解中的常规做法半正定约束通常写成 0但实际求解时留一点余量会让数值更稳。如果既想找 P 又要优化某个控制指标只需把目标函数改为最小化 P 的迹或最大化某个二次型的上界比如 trace(P) 越小对应的 Lyapunov 函数越“扁”体现了不同的控制效果。这种多目标权衡是手工推导时很难做到而 YALMIP 只需改 Objective 的表达式即可。4.3 稀疏回归用 L1 范数做特征选择稀疏回归是机器学习里经常遇到的基础问题给定观测矩阵 A 和响应 b找一个稀疏系数向量 x使得拟合误差最小。L1 范数能够诱导稀疏解但目标函数非光滑直接手工实现梯度投影非常麻烦。YALMIP 里 L1 范数有原生支持norm(b-A*x, 1) 会被自动展开为等价的线性规划。A randn(30, 10); b A * [1; 0; 0; 0; 0.5; 0; 0; 0; 0; 0] 0.01*randn(30, 1); x sdpvar(10, 1); Constraints []; Objective norm(b - A*x, 1); % L1 范数目标 optimize(Constraints, Objective); x_l1 value(x); disp(L1 稀疏回归系数); disp(x_l1); % 对比最小二乘解 x_ols A \ b; disp(最小二乘系数); disp(x_ols);运行后可以看到 x_l1 中若干分量接近 0而 x_ols 几乎全是非零值。这就是 L1 约束的实际效果在同一个框架里可以顺手把 L2 范数换成 norm(b-A*x, 2) 求解经典最小二乘再用一个 sdpsettings 切求解器方法论层面完全不用重新建模型。这里的 A 和 b 如果有真实数据集模拟随机数据只是为了演示流程数据驱动应用场景直接替换即可。5. 避坑与常见问题R20210331 版本最容易翻车的五个位置5.1 现象明明装了 sedumioptimize 仍报 “No suitable solver”建模代码写得完全没问题optimize 却报错说找不到适合的求解器。翻回去检查 sedumi 的路径已经 addpath 过了。后来定位到是因为 YALMIP 并不是通过通用的“求解器列表”来认 sedumi而是通过 whos 和 information 子目录里的具体文件检测。如果解压 sedumi 时没有把根目录加进路径YALMIP 扫描不到它的能力文件就会认为 sedumi 不存在。解决方法是确认你的路径里包含 sedumi 的安装根目录并重启 MATLAB 重新加载也可以运行 yalmiptest 观察 sedumi 的状态如果显示 “FAILED”检查路径里是否有多个版本的 sedumi 冲突把旧版本全部移出。5.2 现象约束写的是对称矩阵求解结果却不完全对称用 sdpvar(3, 3) 声明矩阵变量 X 并写了 X 0 的约束求解后 value(X) 的结果对角线对称但右上和左下略不一致。原因是我没有使用第三参数 symmetric 声明。YALMIP 在半正定约束中不会自动把 X 投影到对称子空间它会按全矩阵的独立元素进行求解得到的数值解受到求解器容差影响不一定完全对称。解决方法是声明时写明 sdpvar(3, 3, symmetric)这样内部变量数从 9 个降为 6 个求解时自动约束对称性结果精确满足对称。这个坑在一切矩阵变量场景都会踩我每次写约束前固定会检查一遍变量声明格式。5.3 现象混合整数规划求解特别慢甚至直接卡死一个带 30 个二进制变量的混合整数二次规划用默认自动选择求解器跑了一个小时没出结果。原因是 YALMIP 自动选了 MATLAB 自带 intlinprog而这个问题规模大、分支定界效率差。排查时发现机器上其实装了 GUROBI但 YALMIP 的版本没匹配上。解决方法是先用 yalmiptest 逐一确认哪些 MIP 求解器可用然后在 sdpsettings 中显式指定 solver 为 gurobi 或 mosek并且把 verbose 开到 2 观察分支进度。从那以后我遇到 MIP 问题都会先检查可用求解器而不是依赖自动选择。5.4 现象优化问题明明有可行解返回的诊断却显示 Infeasible一个带多个耦合矩阵不等式的 SDP理论上存在可行解但 optimize 返回 problem 1不可行。主要原因是约束条件之间数值尺度差异过大有的矩阵元素在 1e-12 量级有的在 1e8 量级求解器的预处理和数值容差直接被击穿。解决方法是尽量对输入数据做归一化处理把矩阵约束两边同时除以最大量级数同时考虑把严格的 0 改成 epsilon*I给求解器留足可行域间隙。这种数值病态问题在 YALMIP 里不报语法错误但会表现为“怎么都算不出来”是最容易消耗排查精力的类型。5.5 现象新版 MATLAB 上解出来的值与其他软件结果不一致同一份代码和数据在 MATLAB R2021b 上跑出的解和旧版本 R2019a 差异明显。定位到根因是 MATLAB 本身数值库在不同版本上的 BLAS 实现和线程调度不同这会影响 sedumi 等纯 MATLAB 求解器的迭代路径但不代表其中一个是错的。验证方法是把两个版本求出的目标函数值做对比如果目标值差异在 1e-6 以内可以认为是数值噪声如果差异明显需要排查是不是路径里加载了不同版本的 YALMIP 或 sedumi。更进一步的验证方式是固定求解器随机种子并关闭多线程尽量保证可复现性。6. 进阶验证与提速check 残差、约束尺度调优、横向对比求解器6.1 check 与 value 双重确认解的真实质量optimize 返回 problem 0 不代表模型真正满足所有约束它只是说明“求解器认为找到了一个满足容差内的解”。因此我每跑一个模型都会强制用 check 对约束逐条做残差检查。check 返回一个列向量每个元素对应一条约束的残差量级越接近 0 表示该约束满足得越彻底。optimize(Constraints, Objective); residuals check(Constraints); if max(residuals) 1e-6 disp(所有约束残差在可接受范围内); else disp(存在超差约束需要检查数据尺度或容差设置); end在这里我同时会取回所有核心变量的值用独立的 MATLAB 原生计算再验一遍目标函数。如果 value(Objective) 和直接用解算出的目标值一致就基本可以确认这个解是真的可用而不是传入了黑匣子里某个逻辑分支。6.2 sdpsettings 的关键参数与收敛性调优sdpsettings 不只是切换求解器它还能控制精度、诊断输出和求解器行为。我最常用的一组设置如下ops sdpsettings(solver, sedumi, ... verbose, 1, ... savesolveroutput, 1, ... sedumi.eps, 1e-8, ... sedumi.maxiter, 5000);sedumi.eps 是其对偶间隙容差减小到 1e-8 可以换更高精度sedumi.maxiter 防止大规模问题迭代次数不足导致提前终止。savesolveroutput 设置为 1 后YALMIP 会把求解器的原始输出结构体保存在 diagnostics.solveroutput 里当你怀疑 YALMIP 翻译模型有误时这是最直接的查阅入口。对 scs 则通常调 scs.abs_eps 和 scs.max_iters。这些参数名带前缀含义就是“传递给对应求解器的参数”格式固化。改参数时我一般只动容差和最大迭代数其他默认值不动避免调整过度。6.3 求解器横向对比用同一模型测 sedumi 与 scs 的真实表现最后落地到实际提速同一份 SDP 模型分别用 sedumi 和 scs 求解用 tic/toc 记录时间并对比目标值与残差。这样能在具体模型上判断到底哪个后端更适配当前场景。ops_sedumi sdpsettings(solver, sedumi, verbose, 0); ops_scs sdpsettings(solver, scs, verbose, 0); % 用相同的约束和目标分别求解 optimize(Constraints, Objective, ops_sedumi); val_sedumi value(Objective); res_sedumi max(check(Constraints)); t_sedumi toc; % ... 重新初始化变量或用新变量副本 % 另一组结果 optimize(Constraints, Objective, ops_scs); val_scs value(Objective); res_scs max(check(Constraints)); t_scs toc; fprintf(sedumi: 目标 %.6f, 残差 %.2e, 耗时 %.3fs\n, val_sedumi, res_sedumi, t_sedumi); fprintf(scs: 目标 %.6f, 残差 %.2e, 耗时 %.3fs\n, val_scs, res_scs, t_scs);对比时注意用一个新变量矩阵重新建模因为上一次的 value 值会保留在旧变量中。实际工作中我跑出来的典型结果是 sedumi 在中小规模 SDP 上精度更高scs 在大规模稀疏问题上速度快一个数量级但精度低一档所以没有“绝对最好”的求解器必须按当前数据规模实测。这段 tic/toc 对比是每个新模型的必备流程从此以后我每次接手新的优化问题都强制走一遍“变量声明检查、约束重读、check 残差、求解器横向对比”四个步骤极少再被莫名奇妙的解带偏。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询