在规划相关的项目工作中,近两年我们的项目主要使用的是Optaplanner作为规划引擎,其核心也是一个的规划求解器(Solver)。但作为另一个著名开源求解器Google OR-Tools(下称OR-Tools)也日渐流行。且因Google自带流量的支持,OR-Tools有更多专门研究运筹的学者使用和研究。而Optaplanner则更偏向工程实践上的应用。本文就二者在技术特性、使用方法与场景等方面,列出若干差异。希望为需要使用开源求解器进行项目工作的同行提供初步入门参考与选择。
简介
Optaplanner
Optaplanner目前是Apache基金会的一款开源软件,JBOSS社区,基于Apache开源软件协议,该协议对商用友好,因此可以自由地将该技术的部门或全部应用于商用软件项目中。该项目目前由受雇于Redhat的团队在维护.其创业人Geoffrey De Smit先生作为该项目的Leader. 其实Optaplanner已发展了十余年,最初是由Geoffrey在参加运筹规划大赛中,针对各种竞赛题目 开发的一个求解器。后来将它贡献给开源社区,并作为开源项目一直维护至今,其版本发布仍十分高效,除进行一些对用户透明不可视的算法与架构优化外,不时还有极具价值的新功能与新特征发布,如7.09版本发布的多线程支持,本人认为是极具里程碑意义的新特征,可以令对运算资源敏感的求解过程,最大程度上提高对CPU的利用率。
Google OR-Tools
Google OR-Tools, 顾名思义是由Google提供的一套运筹规划的运算工具,它针对不同的规划场景,提供了不同的求解器(以组件方式提供)。OR-Tools同样是基于Apache开源软件协议,它是由受雇于Google的Laurent Perron博士带领团队维护。OR-Tools的讨论区讨论相当热烈,主要原因是它的使用方法与传统商用的求解器(如Cplex, Gurobi等)相当类似,因此相当一些运筹学的学者、学生对该软件比较感兴趣。
下面,从使用方法,结构构成等方面,分别对两个规划引擎进行分别讨论。
开发技术与使用方式的区别
Optaplanner的技术特性
Optaplanner是使用Java语言开发,是基于纯Java技术。因此,使用它的时候也只需要使用Java语言本身的特性,即可满足几乎所有基本的建模、开发及求解过程;而无需使用其它第三方的技术或框架。当然当你在实际的工程实践中,还是需要依赖强大的Java生态圈,才能让项目事半功倍。例如通过第三方组件实现日志,数据的持久化、Web服务等。
Optaplanner的评分逻辑,需要使用Drools作为规则描述语言,实现约束的评分。事实上Optaplanner同时支持Java语言实现约束评分的,即Easy Java Score Calculation与Incremental Java Score Calculation,使用这两种评分方式,评分逻辑可直接使用Java语言实现。仅需通过POJO即可对业务实体进行建模,通过Java程序代码即可描述业务约束。Optaplanner的核心程序以Jar包方式提供;当然你也可以获取它的源代码,从源代码级把它的核心集成到你自己的系统中去。但作为商业软件项目,此方法并非最佳实践,直接使用官方发布的Jar 包即可。Optaplanner不支持MiniZinc作为建模语言,OR-Tools则支持该种约束建模语言。在对MiniZinc的支持方面,可能各位ORer感觉有些许遗憾。
与既有系统集成成
从另一个角度来看,纯Java技术实现的Optaplanner,对使用环境起到简化作用的同时,又会形成了一种限制。例如对于一些非Java技术开发的系统(例如一些旧系统),要与Optaplanner集成到同一个程序中,则无法实现尝试结合。对于这种情况,解决办法是将Optaplanner独立成一个Web服务,以WebAPI 的方式对外提供服务。事实上这种系统结构即使是在整个项目都是用Java开发,也是值得推荐的方法。因为规划服务程序在运行的时候,主要占用的资源是CPU的运算资料,在一些规模大,规则复杂的规划程序中,对CPU资源的占用更明显。从另一方面来看,在某些复杂的规划场景中,CPU的性能,直接决定了在固定时间内,找到相对最优方案的质量。因此,将规划服务独立成一个服务,使用独立的服务器资源作为运行环境,为规划引擎提供充足的CPU资源;同时也消除了规划运算对系统其它部分的影响。
Google OR-Tools的技术特性
OR-Tools内核是使用C++开发,因此,其兼任性相对Optapalnner来说好很多。目前Google OR-Tools支持C++, C#, Java和Python四种语言接口。即它具有动态链接库存(DLL), Jar包和Python包三种提供提供形式。当然因为它的原始形式是dll文件,用过Java对它进行调用的时候,就需要通过JNI对它进行装载,下文的示例中会展示。因为OR-Tools提供丰富的兼容形式,因此,与不同系统集成较容易。可直接将它的源代码或DLL嵌入到自己的系统中去。当然,如果使用源代码的方式集成,只能嵌入到C++开发的系统中。
建模语言方面,OR-Tools同时支持使用程序语言(Python, C++, Java, C#)描述模型,如上文提到,它同时也支持MiniZinc作为约束建模语言。各位科班出身的ORer应该对此较有亲切感。也因此在OR-Tools的讨论区,其中提出讨论的问题,除了工程实践的问题,还有非常多是运筹学方面较专业的理论问题。这也许反映了世界各地存在着大量的ORer正在使用OR-Tools作为他们的研究工具。
与既然有系统的体成
在系统集成方面,因为OR-Tools接口相对开放,集成的问题则基本上不存在任何问题。其核心(规划求解器)可以作为系统的一个组件存在于任何系统中;也可以将其封装成一个服务对外提供服务。
建模方式的区别
在建模方式方面,两者都可以使用程序设计语言进行规则、约束描述。同时也可使用使用其它专用的约束或建模语言;Optaplanner支持Drools, OR-Tools支持MiniZinc。但两者面对的场景,或说偏向解决的具体问题,还是有区别的。
Optaplanner更偏向于面向对象
使用Optaplanner进行系统开发的时候(例如开发APS系统),如其它商用软件一样,先对业务进行分析,设计出具体的业务实体,识别出需要规则的实体和因素(字段),提炼出业务规则,归纳出哪些规则是硬约束,哪些是可以优化的软约束。然后根据Optaplanner的固定对象结构模式,建立Planning Entity, Planning Variable,Problem Fact和Solution等类;并配置好求解器的各种参数。整个核心系统的设计就差不多完成了。
Google OR-Tools偏向于传统的数据建模
OR-Tools除了同样需要进行业务分析与设计外,还需要加多一步工作 - 数学建模。因为OR-Tools求解规划问题时,输出的必须是一个完整的数学模型。也就是在使用OR-Tools进行系统开发时,需要先进行业务分析设计,获得各种业务要素和约束后,需要对这些业务要素进行数学建模,并将这个模型以程序语言(Python, C++, Java, C#)或MiniZinc进行模型描述。然后才能启动规划求解器进行寻找优势方案。实现Optaplanner在使用其求解器进行规划求解时,也需要有相应的数学模型的,只不过它可以在求解之前,把用Java对象表示的业务模型,转换成数学模型;而这个步骤对使用都来说是透明的,因此无需关心。
使用场景的区别
基于上一节中两者建模方式上的差别,对于偏向于理论研究、学习的学者来说,OR-Tools更接近于他们日常接触的各类规模模型,与CPLEX和Gurobi等知名商用(有免费的学术用途授权)求解器的应用方法与设计思想均较接近。因此,对于一些考研类的应用场景,OR-Tools来得更直接。
而Optaplanner则更趋向解决具体的业务问题,从其诞生的背景可以得知,它主要是为解决具体问题而生的。关于 Optaplanner的来历,可以参考其作者Geoffrey的一篇博文《A decade of OptaPlanner》。尽管Optaplanner与OR-Tools其核心是相当接近的,都是通过各种启发式算法,对NP-Hard问题寻找相对最优解。但Optaplanner考虑到非运筹专业人员的数学功底,对问题多做了一层封装,将程序中描述业务问题的各种对象,转换成相应的规划模型,再进行规划求解。从而在商用软件开发环境中,普通的程序设计人员,只需要关注具体的业务细则,根据Optaplanner提供的模式,建立合理的对象模型,来反映业务模型,确保这些业务模型能准确地反映业务需求即可。而无需再将这些业务模型转换成可运筹学上数学规划所需的数学规划模型。从而大大降低了规划程序的开发难度。
从规划到AI
目前两个引擎都号称自己属于AI约束求解器,OR-Tools被纳入作为Google AI的其中一个产品。也难惨,毕竟这两个引擎的规划求解器都是基于启发式算法,确实有对于NP-Hard问题,启发式算法是目前较常用的算法,而这些算法对数据的各要素的具体分布情况依赖较大。一定程度上体现了“智能”的感觉。不过我更觉得这是为了蹭近年AI的火,觉得没必要呀,虽然AI的核心算法追溯回去与运筹规划是同源的。但运筹毕竟已经是一个很成熟独立的分支了。
Google OR-Tools最基础入门
以下代码是OR-Tools的一个最基本的入门示例,它解决的是《Excel与Google Sheets中实现线性规划求解》一文中的生产资源优化问题。读者可以结合这篇文章中相关的模型,来对照这些代码进行理解,从中理解OR-Tools在进行规划求解时所需的规划模型的建立方法。
数学模型
import com.google.ortools.linearsolver.MPConstraint;
import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;
public class HelloOR {
// 通过JNI调用OR-Tools包
static { System.loadLibrary("resources/jniortools"); }
// 创建求解器对象
private static MPSolver createSolver (String solverType) {
return new MPSolver("my_program", MPSolver.OptimizationProblemType.valueOf(solverType));
}
// 程序入口,创建一个线性规划求解器,并求解规模模型。
public static void main(String[] args) throws Exception {
solverTest("GLOP_LINEAR_PROGRAMMING");
}
private static void solverTest(String solverType) {
MPSolver solver = createSolver(solverType);
// 创建决策变量,Optaplanner中称为Planning Variable, 规划变量.
double infinity = MPSolver.infinity();
MPVariable x = solver.makeIntVar(0.0, infinity, "x");
MPVariable y = solver.makeIntVar(0.0, infinity, "y");
// 创建约束
//资源1限制: 5x + 3y <= 280
MPConstraint c1 = solver.makeConstraint(-infinity, 280);
c1.setCoefficient(x, 5);
c1.setCoefficient(y, 3);
//资源2限制: 4x + 8y <= 580
MPConstraint c2 = solver.makeConstraint(-infinity, 580);
c2.setCoefficient(x, 4);
c2.setCoefficient(y, 8);
//资源3限制: 3x + 5y <= 360
MPConstraint c3 = solver.makeConstraint(-infinity, 360);
c3.setCoefficient(x, 3);
c3.setCoefficient(y, 5);
// 创建目标函数,求20*x + 25*y 的最大值.
MPObjective objective = solver.objective();
objective.setCoefficient(x, 20);
objective.setCoefficient(y, 25);
objective.setMaximization();
// 调用求解器求解模型,并输出结果.
solver.solve();
System.out.println("Solution:");
System.out.println("x = " + x.solutionValue());
System.out.println("y = " + y.solutionValue());
System.out.println("20x + 25y = " + (20 * x.solutionValue() + 25 * y.solutionValue()));
}
}
可以看到,使用OR-Tools里,需要先建立Solver对,并将模型中的各不等式以系数方式体现到程序中,最后求解得出结果。因为这是一个线性规划问题,因此代码中创建的是一个线性求解器(以GLOP_LINEAR_PROGRAMMING参数表示)。尽管都是规划问题,但针对不同同的类型,OR-Tools提供不同的Solver解,例如线性规划问题,TSP问题等,有专用的Solver对象解决。
输出结果为:
关于Optaplanner的使用方法,则可以《Optaplanner规划引擎的工作原理及简单示例(2)》。
- End.
如需了解更多关于Optaplanner的应用,请发电邮致:kentbill@gmail.com
或到讨论组发表你的意见:https://groups.google.com/forum/#!forum/optaplanner-cngroups.google.com
若有需要可添加本人微信(13631823503)或QQ(12977379)实时沟通,但因本人日常工作繁忙,通过微信,QQ等工具可能无法深入沟通,较复杂的问题,建议以邮件或讨论组方式提出。(讨论组属于google邮件列表,国内网络可能较难访问,需自行解决)