简介:一套完善的CPLEX与YALMIP联合优化环境资源包,面向需要在MATLAB中求解线性规划、混合整数规划、二次规划以及非线性规划问题的人员,包括高校师生、科研工作者和工业界算法工程师。包体内含IBM官方提供的Windows 64位求解器安装程序、YALMIP主分支源码,以及大量M脚本文件、C语言接口文件、MAT数据文件和几个文本说明,全部文件数共一千三百一十二个,压缩包总体积约七百四十九兆。用户借助YALMIP的简洁建模语法,可以快速定义决策变量、目标函数与约束条件,并调用CPLEX完成高效求解,适用于运筹学、生产调度、路径优化、经济调度等典型场景。目前已有两千七百一十四人学习下载,资源目录结构合理,便于按功能模块检索,能够帮助使用者显著缩短搭建优化建模环境的时间,顺利开展学术研究与实际项目验证。
1. 搜索 cplex12.8+yalmip安装包的人,多半是在复现一篇老论文
搜索“cplex12.8+yalmip安装包”的人,手里的活通常不是新项目选型,而是被旧代码或论文仿真锁定的复现任务:YALMIP 负责在 MATLAB 里把优化问题描述成模型,CPLEX 12.8 负责在底层把这些模型真正解出来。CPLEX 12.8 是 2017 年底发布的版本,距今已有年头,但大量教材、开源代码和学术复现脚本都默认它能直接跑通,这使它成了优化问题求解中绕不开的经典组合。这篇笔记把从拿到安装包到 MATLAB 里跑通第一个混合整数线性规划(MILP)的完整路径拆开讲,适合刚接触 MATLAB 优化工具箱的新手,也适合被版本兼容问题反复折磨的老手。
2. 版本匹配先想清楚再做:为什么非得是 CPLEX 12.8 + YALMIP
2.1 CPLEX 12.8 至今没被淘汰的真实原因
优化求解器是个迭代非常快的领域,新版本年年出,功能更强、算法更快。可现实中大量团队还在用 CPLEX 12.8,原因很直接:他们的依赖链不允许升级。教材里给的示例代码是按 12.x 的调用方式写的;开源项目里 MATLAB 脚本直接 cd 到cplex\matlab目录执行 install;论文复现包里的参数设置项是cplex.mip.tolerances.mipgap,而不是新版改掉的名字。一旦换成新版本,这些脚本至少有一半要手动改接口,改完还不一定能复现论文里的结果。
商业求解器的许可证机制也是原因之一。很多老许可证只覆盖特定小版本,升级到新版意味着要重新谈授权、重新配许可服务器,对个人研究者来说成本很高。CPLEX 12.8 这类版本因此成了“文档全、踩坑记录多、行为稳定”的保守选择。与其说它是最好的,不如说它是被验证过最多次的。
YALMIP 这边情况相反:它是持续更新的开源建模层,新版本对旧版 CPLEX 的适配反而维护得很好。也就是说,你大可以用最新版 YALMIP 去配 CPLEX 12.8,这组搭配比“老 YALMIP + 新 CPLEX”要稳得多。这也是我推荐做法:YALMIP 尽量用新,CPLEX 锁定 12.8,互相之间兼容性最省心。
2.2 建模层与求解层的分工,决定了安装顺序
要理解安装步骤,得先搞清 YALMIP 和 CPLEX 在 MATLAB 里各干各的活。YALMIP 是建模层,它用sdpvar、intvar、binvar这类变量对象帮你描述目标函数和约束条件,然后统一转换成求解器能吃的标准形式。CPLEX 是求解层,它接收标准形式后调用内部的单纯形法、分支定界、割平面等算法去算。你写在 MATLAB 里的优化问题并不是 YALMIP 解的,而是 YALMIP 翻译给 CPLEX 解的。
这层分工决定了安装顺序:先把 YALMIP 装好,再把 CPLEX 的 MATLAB 接口装好,最后验证 YALMIP 能不能“看见” CPLEX。如果顺序反了,比如先装 CPLEX 再装 YALMIP,也能用,但后面配置路径时容易漏掉 YALMIP 的依赖目录,查起来更费劲。
CPLEX 为 MATLAB 提供的接口是一组编译好的二进制文件,官方叫法通常叫cplexlink。这组二进制绑定特定操作系统和 MATLAB 版本,不是随便拿个新版 MATLAB 就能跑的。这正是很多人安装失败的根本原因:不是安装包坏了,而是版本对不上。理解这一点之后,你就知道安装前应先查版本支持矩阵,而不是先解压安装包。
2.3 安装前检查清单:五个项逐一核对
我在给模拟项目X配置环境时都会先走一遍下面的检查,全绿再动手,能省掉八成后续排查时间。按重要性排列:
| 检查项 | 要求 | 核对方法 |
|---|---|---|
| MATLAB 版本 | CPLEX 12.8 发布时对应的主流版本,64 位 | MATLAB 里执行version和computer |
| 操作系统位数 | 必须是 64 位 Windows / Linux / macOS | 系统设置里查看 |
| 许可证文件 | 有没有可用的.lic文件或网络许可服务器地址 | 确认文件存在即可 |
| YALMIP 版本 | 建议用官方发布的最新版 | 解压后看目录里的 README |
| 磁盘空间 | 安装包解压后约几个 GB | 解压前检查剩余空间 |
我见过最典型的问题是 32 位 MATLAB 配 64 位 CPLEX,install脚本跑完不报错,但一调用cplex就提示脚本格式错误。另外,MATLAB 安装路径和 CPLEX 安装路径都尽量不要包含中文或空格,后面配路径和跑脚本时少很多麻烦。
2.4 版本对应关系里最容易被忽视的“接口代差”
MATLAB 官方和 CPLEX 的兼容性策略是“向前兼容到某个版本,向后不保证”。CPLEX 12.8 官方支持矩阵覆盖的 MATLAB 大致是 R2014b 到 R2017b 这一代。也就是说,如果你机器上装的是 R2019b 甚至更新的版本,cplex\matlab目录下编译好的 mex 文件很可能加载不成功,具体表现是执行which cplex能找到文件,但一调用就崩溃或报段错误。
面对这种代差,我一般不会去折腾第三方重新编译,而是直接装一个与 12.8 匹配的 MATLAB 老版本。运维上更省事的做法是用双 MATLAB 环境:日常写作和数据处理用新版本,需要跑优化复现时切到老版本。环境变量里用MATLABPATH区分也行,如果你不想装两个 MATLAB,可以用setenv在启动脚本里临时切换搜索路径。
理解这层关系后,你就能理解为什么这篇笔记要花一整章讲版本匹配:cplex12.8+yalmip 的安装难点不在解压和复制文件,而在让两个软件在同一个 MATLAB 环境里互相认得出对方。
3. 动手安装:把 cplex12.8+yalmip 装进 MATLAB 的完整步骤
3.1 安装 YALMIP:从解压目录到路径持久化
YALMIP 的安装本身非常简单,它不编译任何二进制,本质上是把源码目录挂到 MATLAB 搜索路径下。先到 YALMIP 官方渠道下载最新的 zip 包,解压到某个固定位置,然后打开 MATLAB 执行下面这段:
% 把 yalmip 主目录递归加入搜索路径,genpath 会包含所有子目录 addpath(genpath('D:\toolbox\yalmip-master')); % 检查核心函数 sdpvar 是否已被识别,显示路径说明加载成功 which sdpvar % 保存路径到 pathdef,使下次启动 MATLAB 时依然生效 status = savepath;这里三个步骤各有一个关键点。addpath(genpath(...))和addpath(...)的区别在于:YALMIP 有@sdpvar、@constraint这样的类目录,必须用genpath递归添加,只加主目录会导致某些函数找不到。which sdpvar返回的路径应该指向你解压的目录,如果指向 MATLAB 自带的其他工具箱,说明路径冲突,需要把 YALMIP 目录移到搜索路径更靠前的位置。savepath这步特别容易被跳过,不保存的话,重启 MATLAB 后所有配置全部丢失,又得重新 addpath,新手在这一步翻车的比例很高。
我通常在savepath后检查返回值status,如果等于 0 说明保存成功,非 0 表示 MATLAB 没有写权限,常见于安装在C:\Program Files下的 MATLAB。解决方法是右键以管理员身份运行 MATLAB 后再执行一次savepath,或者把pathdef.m复制到当前用户目录下的 MATLAB 启动文件夹里。
3.2 安装 CPLEX 12.8:解压、许可文件与环境变量
拿到 cplex12.8 安装包后,解压到不含空格的路径。Windows 下我习惯放到C:\cplex128,Linux 下放到/opt/cplex128,这样后续 MATLAB 里写路径不用加引号转义空格。解压后目录结构一般是这样的:
| 子目录 | 作用 |
|---|---|
cplex\matlab | MATLAB 接口主目录,稍后要重点处理 |
cplex\examples | 官方示例,安装完成后值得翻一翻 |
cplex\bin | 可执行文件和动态库 |
cplex\include | C/C++ 头文件,MATLAB 用户用不到 |
许可证文件是接下来最关键的输入。单机版拿到的是一个.lic文件,把它放到固定目录,然后通过环境变量告诉 CPLEX 去哪里找它。Linux 下这样配置:
# 创建存放许可文件的目录 mkdir -p $HOME/cplex-license # 把安装包里的许可文件复制过去,文件名以实际拿到的为准 cp license.lic $HOME/cplex-license/ # 写入 shell 配置文件,每次登录自动生效 echo 'export ILOG_LICENSE_FILE=$HOME/cplex-license/license.lic' >> $HOME/.bashrc # 立即在当前终端生效 source $HOME/.bashrcILOG_LICENSE_FILE是 CPLEX 读取许可证的默认环境变量,它的优先级高于安装目录里的许可文件。没有装服务器版许可的情况下,只要这个环境变量指向正确的.lic文件,求解器就能启动。如果用的是网络许可服务器,环境变量则是ILOG_LICENSE_FILE指向服务器的port@host格式地址,例如27000@license-server,具体端口以实验室发放的许可信息为准。
Windows 上配置环境变量的方式是在 PowerShell 里执行:
# 设置用户级环境变量,重启 MATLAB 后生效 setx ILOG_LICENSE_FILE "C:\cplex-license\license.lic"注意setx设置的是用户环境变量,需要在“此电脑 → 属性 → 高级系统设置 → 环境变量”里确认是否写入成功,而不是只设置当前终端窗口的临时变量。这一步漏掉的话,后面 MATLAB 调用 CPLEX 时会报许可证找不到,千万不要跳过。
3.3 在 MATLAB 里注册 CPLEX 接口:install 脚本的两行关键操作
CPLEX 安装包自带 MATLAB 接口注册脚本,我们只需要在 MATLAB 里指向它并运行即可。
% 切换到 CPLEX 的 MATLAB 接口目录 cd('C:\cplex128\cplex\matlab'); % 执行注册脚本,它会自动添加 mex 接口和 Java 类路径 installinstall这个脚本会做三件事:把当前目录加入 MATLAB 搜索路径、把../../../../cplex/matlab相关的动态库路径写入pathdef.m、检查 MATLAB 版本并把 Java 接口所需的.jar文件加入静态 Java 路径。脚本运行完会提示重启 MATLAB,这一步照做就行。
重启后做一次快速确认:
% 检查 cplex 接口函数是否指向 CPLEX 的 matlab 目录 which cplex如果返回路径以C:\cplex128\cplex\matlab开头,说明注册成功。如果显示cplex is a built-in function或者返回其他工具箱的同名文件,通常是 MATLAB 搜索路径顺序问题,需要把 CPLEX 接口目录通过addpath手动移到 YALMIP 和 MATLAB 自带工具箱前面。安装到这一步,cplex12.8+yalmip 的骨架已经搭好,下一步是整个环境能否真正工作的验证。
4. 落地验证:最小测试用例与四个高频踩坑点
4.1 验证安装成功的两条命令
路径配好、许可配好后,不要急着跑你的实际模型,先用 YALMIP 自带的测试套件做一次体检:
% 运行 YALMIP 内置的求解器检测,确认 CPLEX 在列表中 yalmiptestyalmiptest的输出能直接反映出当前所有可用求解器的状态。重点看 CPLEX 那一行的结果,如果显示成功,说明接口和许可证都正常。如果显示找不到或失败,说明前面的某个环节有问题。这个测试会跑好几分钟,因为它会依次尝试每一种检测到的求解器,不建议在配置阶段跳过它。
如果你不想等完整测试,可以跑一个最小 MILP 来验证,注意这里故意用整数变量来避免线性规划走了单纯形法而不触发分支定界模块:
clear; clc; yalmip('clear'); % 定义两个整数变量 x = intvar(2,1); % 约束:x1、x2 非负,且 x1 + x2 <= 4.5 Constraints = [x >= 0, x(1) + x(2) <= 4.5]; % 目标:最大化 2*x1 + 3*x2,YALMIP 默认最小化,取负号转化 Objective = -[2 3]*x; % 指定求解器为 cplex,verbose 设为 2 输出详细求解日志 options = sdpsettings('solver','cplex','verbose',2); % 调用求解器 sol = optimize(Constraints, Objective, options); % 根据返回的 problem 字段判断结果 if sol.problem == 0 fprintf('求解成功: x1 = %.2f, x2 = %.2f\n', value(x(1)), value(x(2))); else disp(sol.info); end这段代码有四个值得展开说明的地方。intvar(2,1)声明两行一列的整数变量,这是 MILP 的关键,换成sdpvar就退化成了线性规划。目标函数里取负号是因为 YALMIP 统一按最小化处理,原问题要找最大化,取反即可。sdpsettings('solver','cplex')里的 solver 参数是精确匹配大小写的,写Cplex或CPLEX都无法识别。sol.problem == 0是全局唯一判定标准,只要不是 0 都表示求解过程出了某种异常,具体原因从sol.info里看。
这段验证代码跑出problem = 0之后,你的 cplex12.8+yalmip 安装包配置才算真正落地。
4.2 避坑一:install 脚本跑完,调用却提示找不到 cplex
现象:install脚本正常执行完,重启 MATLAB 后执行which cplex能找到路径,但实际调用时报错Attempt to execute SCRIPT cplex as a function。
原因:MATLAB 找到的是cplex.m脚本文件,而不是编译好的 mex 接口。常见于 32 位 MATLAB 与 64 位 CPLEX 混用,或者路径指向了cplex\examples而不是cplex\matlab。cplex\matlab目录下应该有cplex.mexw64这样的二进制文件,如果目录里只有.m文件,说明接口没有正确注册。
解决:先执行disp(path)看cplex\matlab是否在列表中;再用fileparts(which('cplex'))查看实际所在目录;最后确认 MATLAB 是 64 位。这三步定位完,基本就能确定是位数不匹配还是路径顺序问题。
4.3 避坑二:许可证报错,错误码一闪而过
现象:求解时 MATLAB 命令行弹出一段以License Manager Error -1或License server does not support this feature开头的提示,然后求解直接中止。
原因:ILOG_LICENSE_FILE环境变量没有正确传递到 MATLAB 进程。很多人在系统里设置了环境变量,但 MATLAB 是从启动栏图标点开的,继承了桌面会话环境而不是新设置的变量,导致 MATLAB 里的getenv('ILOG_LICENSE_FILE')返回空。
解决:在 MATLAB 里先执行getenv('ILOG_LICENSE_FILE')确认环境变量是否可见。如果返回空,推荐做法是在 MATLAB 启动脚本startup.m里加一行setenv('ILOG_LICENSE_FILE','C:\cplex-license\license.lic'),确保每次启动都注入环境变量。这个方法比反复重启系统靠谱得多。
4.4 避坑三:新版 MATLAB 加载 12.8 接口导致 MATLAB 直接崩溃
现象:which cplex一切正常,但第一次调用optimize时 MATLAB 整个进程闪退,没有错误信息。
原因:CPLEX 12.8 的 mex 二进制是针对旧版 MATLAB 的 ABI 编译的,新版 MATLAB 加载旧接口时内置的 C/C++ 运行库不兼容,导致底层崩溃。这个问题几乎没有日志,排查起来非常像玄学,但根源只有一个:版本代差。
解决:最常见的做法是装一个与 12.8 同期的 MATLAB 老版本,比如 R2017b。如果坚持用新版 MATLAB,只能去第三方社区找重新编译过的接口文件,但这会引入无法预期的稳定性风险,我不推荐在重要项目上使用。判断这个问题有个技巧:在 MATLAB 里执行mex.getCompilerConfigurations,能正常显示编译器说明环境还行,再调用cplex崩溃就基本锁定了代差问题。
4.5 避坑四:模型规模上来之后 MATLAB 报内存溢出或 Java 堆栈溢出
现象:小模型能跑通,换成大一点的模型后 MATLAB 警告Out of Memory,或者 Java 层报java.lang.OutOfMemoryError: Java heap space。
原因:MATLAB 的 Java 堆内存默认值偏小,而 CPLEX 的 MATLAB 接口会通过 Java 层做数据转换。当模型变量数量上到几千甚至几万时,Java 堆区被占满,求解还没开始就终止了。
解决:调整 MATLAB 的 Java 堆大小。在 MATLAB 的 Preferences 里打开“常规 → Java 堆内存”,把数值调大,比如从默认的几百 MB 调到2GB以上。如果还不够,可以编辑 MATLAB 安装目录下bin文件夹里的java.opts文件,加入一行-Xmx4096m。注意调大后 MATLAB 启动速度会变慢,这是正常现象。感性的判断标准是:模型变量数超过一万,默认 Java 堆基本稳挂。
5. 进阶:用 sdpsettings 透传 CPLEX 参数,绕开 YALMIP 的默认设置
5.1 把求解器参数直接透传下去
YALMIP 的sdpsettings里所有以cplex.开头的字段,都会被原样映射到 CPLEX 自身的参数树。这意味着你在 YALMIP 里写优化问题时,不需要放弃 CPLEX 的精细控制。我一般会固定的几个参数如下:
options = sdpsettings('solver','cplex', ... 'cplex.mip.tolerances.mipgap', 1e-4, ... % 设置 MIP 间隙收敛精度 'cplex.timelimit', 120, ... % 求解时间上限 120 秒 'cplex.threads', 4); % 多线程并行分支定界这里cplex.mip.tolerances.mipgap是 CPLEX 里控制 MIP 求解精度的关键参数,设成1e-4意味着允许最优解有千分之一以内的偏差,换来明显更快的求解速度。timelimit是按秒计算的,适合你不想某个模型无限跑下去的情况。threads设为 4 不代表一定快 4 倍,但模型有分支结构时通常有可观的加速效果。
5.2 什么时候绕开 YALMIP 直接调 CPLEX 接口
YALMIP 方便,但有代价。当模型规模极大、大量约束需要按迭代动态添加,或者你需要获取 LP 对偶变量、回调函数这类底层信息时,YALMIP 的封装反而碍事。这时可以考虑直接调用 CPLEX 的 MATLAB 接口,以标准线性规划为例:
model = cplex; model.ModelSense = 'minimize'; model.f = [2 3]; model.Aineq = [1 1; 2 1]; model.bineq = [4; 5]; model.lb = [0 0]; cplex.solve(model);直接调用接口的优势在于没有建模层的转换损耗,数据规模上去后能明显感觉到生成模型的耗时少了一截,调试时也能直接看到 CPLEX 最原始的输出日志。回报也很直接:你把 CPLEX 12.8 的参数体系摸熟了之后,YALMIP 里那层cplex.开头的透传参数对你来说就没有黑匣子可言了。
我在跑模拟项目X的调度优化时吃过一次亏:默认 MIP 间隙下大规模模型总是停在次优解,花了两天才意识到是cplex.mip.tolerances.mipgap没有透传,YALMIP 用了自己偏宽松的默认值。从那以后我把参数透传养成了习惯,每条模型必备三件套:solver 指定、mipgap、timelimit。这个习惯帮我挡掉了不少隐藏的求解精度问题。希望帮到你。
本文还有配套的精品资源,点击获取