Optaplanner与Google OR-Tools的区别
在规划相关的项目工作中,近两年我们的项目主要使用的是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邮件列表,国内网络可能较难访问,需自行解决)
Optaplanner与Google OR-Tools的区别的更多相关文章
- Google performance Tools (gperftools) 使用心得
Google performance Tools (gperftools) 使用心得 gperftools是google开发的一款非常实用的工具集,主要包括:性能优异的malloc free内存分配器 ...
- Google PageSpeed Tools 性能测试分析
今天给大家介绍下一个工具:Google PageSpeed Tools,根据官方的介绍,简单梳理如下: Page Speed Insights能针对移动设备和电脑设备衡量网页的性能.该工具会抓取网址两 ...
- Google Optimization Tools实现加工车间任务规划【Python版】
上一篇介绍了<使用.NET Core与Google Optimization Tools实现加工车间任务规划>,这次将Google官方文档python实现的版本的完整源码献出来,以满足喜爱 ...
- 使用.NET Core与Google Optimization Tools实现加工车间任务规划
前一篇文章<使用.NET Core与Google Optimization Tools实现员工排班计划Scheduling>算是一种针对内容的规划,而针对时间顺序任务规划,加工车间的工活儿 ...
- Google Optimization Tools实现员工排班计划Scheduling【Python版】
上一篇介绍了<使用.Net Core与Google Optimization Tools实现员工排班计划Scheduling>,这次将Google官方文档python实现的版本的完整源码献 ...
- 使用.NET Core与Google Optimization Tools实现员工排班计划Scheduling
上一篇说完<Google Optimization Tools介绍>,让大家初步了解了Google Optimization Tools是一款约束求解(CP)的高效套件.那么我们用.NET ...
- Google Optimization Tools介绍
Google Optimization Tools(OR-Tools)是一款专门快速而便携地解决组合优化问题的套件.它包含了: 约束编程求解器. 简单而统一的接口,用于多种线性规划和混合整数规划求解, ...
- Apache的Mesos/Marathon与Google的Kubernets的区别
Apache的Mesos与Google的Kubernets的区别 – China Hadoophttp://chinahadoop.com/archives/2150 有哪些是Apache Mesos ...
- Google perf tools for nginx
注意:本教程仅适用于Linux. 下面为大家介绍google-perftools的安装,并配置Nginx和MySQL支持google-perftools. 首先,介绍如何优化Nginx: 1,首先下载 ...
随机推荐
- ztree实现拖拽移动和复制
1.官网下载ztree:http://www.treejs.cn/v3/api.php 2.引入jquery.ztree.all.min.js 注意,这是基于jQuery的插件,请引入相关js 3.设 ...
- 三、Spring的@Scope设置组件作用域
还是和上节一样,首先来看下配置类:MainConfig2 @Configuration 名 public class MainConfig2 { @Scope("singleton" ...
- MySQL面试题看这一篇就够了
现在mysql相关的面试,面试官总会问一些相关的技术问题.在这里,因此就总结一些常见的mysql面试题,都是自己平时工作的总结以及经验.希望大家看完,能避开”面试坑”. 1.MySQL主从复制的原理. ...
- java笔记2—函数
函数: 1.什么是函数? 函数是定义在类中具有特定功能的一段独立小程序. 函数也称方法. 2.函数的格式: [ 修饰符 ] 返回值类型 函数名(参数类型 形式参数) ...
- 【Linux】一步一步学Linux——初识Linux命令解析器(10)
目录 00. 目录 01. Shell简介 02. Shell分类 03. 交互式shell和非交互式shell 04. 登录shell和非登录shell 05. Shell类型 06. 参考 00. ...
- springMvc之常用注解介绍
@requestbody和@requestparam的用法 获取请求参数的方法 get请求: 直接获取request 如: public String getHtml(HttpServletR ...
- NIO开发Http服务器(2):项目结构
最近学习了Java NIO技术,觉得不能再去写一些Hello World的学习demo了,而且也不想再像学习IO时那样编写一个控制台(或者带界面)聊天室.我们是做WEB开发的,整天围着tomcat.n ...
- Bad state: Stream has already been listened to.
https://stackoverflow.com/questions/51396769/flutter-bad-state-stream-has-already-been-listened-to T ...
- 【转载】C#中List集合使用Reverse方法对集合中的元素进行倒序反转
在C#的List集合操作中,有时候需要对List集合中的元素的顺序进行倒序反转操作,此时就可使用到List集合中的Reverse方法来实现此功能,Reverse方法的签名为void Reverse() ...
- 5.安装CentOS后,开机找不到Win10的启动选项解决办法
现象:在Win10下安装了CentOS7双系统,开机后,居然发现找不到Win10启动选项,默认进入了CentOS系统. 解决办法: 方法一:笔者一般是用创建一个Win10启动盘,电脑重启进入启动盘后, ...