前言
求解器对于运筹算法工程师而言,常常像一个黑盒,我们扔进去输入数据和数学模型,求解器给我们吐出一个解出来。这种状态在面临规模小、形式简单的数学模型是还可以应付的,但一旦问题难度上来,原本用着舒服的求解器可能求解你的问题太慢了,又或者根本无法给到符合预期的解,这时就会面临到底选择哪个求解器更合适的问题?
这里的合适代表既准又快,需要综合考虑:
- 自己的问题类型是什么?线性规划?整数规划?二次规划?这里可以参考我的文章运筹学算法分类快速判断;
- 不同求解器适用的问题类型;
- 开源还是商用?
2和3都会在接下来的梳理中体现。
求解器对比
求解器 | 国家 | 类型 | 支持的数学问题 | 优点 | 缺点 | Python API |
---|---|---|---|---|---|---|
Gurobi | 美国 | 商用 | 擅长:LP、MIP、凸和非凸的二次混合整数规划; 支持:(1) 线性约束和目标模型(连续变量、混合整数);(2)二阶锥模型(连续变量、混合整数);(3)二次凸约束和目标模型(连续变量、混合整数);(4)二次非凸(双线性、二次等式约束)约束和目标模型(连续变量、混合整数);(5)非线性模型(除式、高阶多项式、指数、对数、三角函数、范数等)(连续变量、混合整数) | 可以叠加许多功能:(1)约束和目标中带有最大、最小、绝对值等数学函数,或者带有AND、OR、INDICATOR逻辑条件的模型;(2)多目标优化;(3)需要获得部分或者全部可行解或者最优解的模型;(4)不可行或者无解分析;(5)优化参数自动调优功能;(6)分布式计算或者多线程计算 | 支持 | |
Cplex | 美国 | 商用 | LP、QP、QCQP、二阶锥规划(SOCP)、MIP | 支持 | ||
Xpress | 美国 | 商用 | LP、MILP、QP、QCQP、SOCP、NLP、CP | 支持 | ||
COPT | 中国 | 商用 | LP、MIP、二阶锥规划、半定规划、凸二次(约束)规划 | 支持 | ||
SCIP | 德国 | 开源 | MIP、MINLP、非凸优化问题 | 用于MIP的最快的非商业求解器之一、支持Branch&Price、支持 McCormick relaxation 和 convex envelope relaxation 这两种非凸问题处理方法 | 支持 | |
OR-TOOLs | 美国 | 开源 | LP、IP、约束规划、MIP | 跨平台性 | 不支持非线性规划 | 支持 |
IPOPT | 美国 | 开源 | 非线性规划问题(凸和非凸均可) | 对初始值敏感(影响算法收敛和迭代次数)、对于非凸问题可能陷入局部最优 | 支持 | |
GLPK | 美国 | 开源 | 大规模线性规划、MIP | 不支持非线性规划 | 支持 | |
CBC | 美国 | 开源 | LP、MIP | 不支持非线性问题 | 支持 |
梳理的过程中发现了一个wikipedia提供的表格:
问题延伸:商用求解器和开源求解器的差别是什么?
不同求解器底层的差异是它们是否能够正确的识别并利用模型的结构,而这直接决定了求解器的表现(求解速度、支持准确求解的问题类型、支持的问题规模、解的质量)。有些问题开源求解器无法支持,只有一些商业求解器才能求解,还有的问题,商业求解器的求解速度更佳。
导致这一差距的原因也很好理解——“Commercial vendors with their teams of full-time developers and their large customer base who provide models from a diverse set of applications are just in a much better position to develop, implement, and tune algorithms to cover all these different aspects and structures that appear in real-world models.”
求解器PK
目前主要是参考 H. Mittelmann 教授的评测网站,会从很多维度对各个求解器进行测试,最终从解决的问题数和耗时两个方面评分。
比如对于MIP问题,最新的测评结果是:
总结
回到我们文章标题的问题,拿到实际问题后怎么选择合适的求解器呢,我总结了3个步骤:
(1)判断数学问题类型,看看手头已有的求解器是否就能支持(判断方法可以查阅上面的表格);
啰嗦一句:排除不支持你这类问题的求解器,为什么单独强调这么一句呢?举个例子,你建模的问题是个整数规划问题,而IPOPT主要是用于求解非线性规划的,就不太适用于你这个问题。那问题来了,我就是把这个整数规划问题丢给IPOPT求解会怎么样呢?我亲自踩过这样的坑Pyomo调用IPOPT:0-1变量给出小数解,血泪教训!
(2)快速实验,找一个支持的求解器在小规模case上测试下;
如果你的问题规模本身就很小,而且在这一步的求解质量和速度都已经满足要求了,那么恭喜你,不用再继续往下看了!多测试一些case保证模型的鲁棒性即可。
(3)遇到性能瓶颈时怎么办?
如果你不幸的发现,小规模测试OK,但测试案例规模放大,模型求解很久仍然没有给到解,无法支持上线实时计算的规模和时间要求(和现在的我一样),那么就进入下一步的打怪中。
- 约束加紧,缩小可行域;
需要一定业务输入(例如top10可行缩减为top5)+建模技巧(同样能表达某一个业务逻辑的约束,不同写法的松紧可能不一样),较难;
- 对比不同求解器的速度,挑一个表现最佳的;
experience + experiment,某清华大佬教我的。。。。
- 模型内部参数调整:time limit 、gap limit等。
如果业务对于解的质量要求没有高到一定要是最优解,那么稍微放松一下gap limit是个节约搜索时间的好方法。此外,对于一些实时求解的运筹模型,要求在一定时间内要能输出方案,实时下发下去,那么有必要设置一个time limit兜底,但离线应该测试清楚,解的质量会折损多少(不要只盯着gap,也要注意业务同学能够听得懂的业务指标,比如目标函数里的cost等等)。