OptaPlanner逐步学习(0) : 基本概念

Stella981
• 阅读 1103

  之前的文章中,分别从APS,排产到规划引擎叙述了一些理论基础;并介绍了一些OptaPlanner大概的情况;并一步步将Optaplanner的示例运行起来,将示例源码导进Eclipse分析了一下它的Hello world入门示例,从本篇开始,我们将分步学习它的一些概念及用法。 

什么是OptaPlanner

  其实这个名称是作者将这个引擎贡献给了Jboss社区后,才使用的名,之前叫做Drools planner。没错,它就是结合Drools(一个开源规则引擎)一起应用的(也可以单独使用),Drools在这里的作用主要是用来作编写计分脚本,事实上完全可以抛开Drools,直接使用OptaPlanner自己的API,通过Java代码自己来计分,但这个难度就大得多。详细情况讲到相应的章节再细说。

  名称的前缀应该是Optimize的词根,或取近音吧,因为OptaPlanner其实就是一个对待规划的方案组合进行优化的引擎。好了,关于它的名称就不花费太多的口水去深究,我们看看官方是怎么定义OptaPlanner的。"OptaPlanner is a constraint solver. It optimizes business resource planning use cases, such as Vehicle Routing, Employee Rostering, Cloud Optimization, Task Assignment, Job Scheduling, Bin Packing and many more. " - Optaplanner 是一个约束解决器,它可以优化业务资源,规划各种案例,例如车间调度,职员排班,云优化,任务分配,工作排程,装箱等相关的问题,例如下图。

  OptaPlanner逐步学习(0) : 基本概念

  而我对OptaPlanner的理解,它是一个Planning Engine - 规划引擎,针对各行各业的业务需求,开发人员需要将一些业务规则翻译成约束,并对业务场景中的实体进行抽象建模,规划引擎根据上述约束和模型对象进行规划,找出一个相对最优化的方案出来返回给用户。其实如果需要规划的业务对象不多(种类和数量都不多),规则不太复杂,人类是可以通过自己的经验、推算和规则运行,得到一个可行方案的,甚至当问题规模足够小的时候,是可以找到一个最优方案的。关于规划问题,大家可以参考这个系统文章中的一篇入门介绍《OptaPlanner - 入门介绍》,里面讲到,规划问题其实就是数学上的NP问题或NPC问题,目前数据世界对于这种问题,是没有可用算法直接实现的,当问题足够大的时候,只能够通过一些寻优算法(例如爬山算法,模拟退火及遗传算法等)提高找到问题相对优解的机率。而OptaPlanner正是一个集成了这类算法,实现快速寻找相对最优方案的引擎。它是一个轻量级的,可嵌入的规划引擎,也就是说你可以在自己的程序中通过Jar包直接和相关的配置项来直接使用OptaPalnner. 当然,当你需要一个独立的,具有良好扩展性的规划服务组件时,可以直接使用OptaPlanner建立自己的规划服务器,通过Spring等框架,对外提供规划服务。

  OptaPlanner是基于Apache Software License.协议的,你可以直接使用它作为商业用途。并且它是使用纯Java编写的,最低功能要求下,只需安装一个JVM即可以使用OptaPlanner了。并且它所有的包都可以从Maven中央库中获得,即只需要建立一个Maven项目,简单配置好依赖项,就可以开始基于OptaPlanner的开发了。

下面,就开始对OptaPlanner中概念进行逐一讲解.

什么是规划问题(Planning Problem)

规划问题是 - 基于有限资源,及指定约束条件下达到优化目标(包括资源、排程安排等优化).,例如:

  • 最大化利润
  • 最小化对生态环境的影响
  • 提高员工及客户的满意度
  • ........

要实现这些目标,需要以下条件:

  • 人员
  • 时间
  • 预算(资金)
  • 物理资产(例如机台、汽车,电脑,建筑等等)

下图是Optaplanner官网对规划问题的定义:

  OptaPlanner逐步学习(0) : 基本概念

  上面是对官网的一些翻译。通俗地讲,规划问题就是:

1. 存在一堆对象,例如:任务、人员、资源等,以后称作规划实体 - 官方称planning entity;

2. 还存在一些条件规则,例如:任务最迟需要什么时候完成,人员每天最多只能上班8小时,在指定的时间段内资源是有限的。以后称约束 - 官方称Constraint

3. 根据上述第2点的条件,对第1点所述的规划实体进行资源分配和时间安排,例如,哪个任务应该安排在哪个机台上,在什么时候开始作业;哪个人员安排在哪个车间的哪个班次;哪种资源(例如:机台、原料等)需要确保在哪个时间送到哪个车间等。

  上述第3点所做的工作就是一个规划的过程,也就是引擎会根据约束的限制和规划实体的特性,对这些规划实体进行时间或/和空间上的规划;这个就是规划过程。而我们面对的这些规划实体和这些约束的结合体,就称作规划问题。例如:排定下个学期每个年级的课程表,令每个课程的老师不会出现同一时候分配到不同的班级上课。现有一堆外卖,规划好各个骑手的取餐、送餐路线,令每个骑手都以尽量小的路程和时间成本送最多的单。这些都可以被视作规划问题。

规划实体与规划变量(Planning Entity & Planning Variable)

  我们知道,规划问题,就是对一些规划实体进规划预计分配。例如编造排班表,是一个规划问题,那么抽象出来,一个工人就是一个规划实体(Planning Entity)了,它是被规划的对象。而工人在指定的时间在哪个车间上班,就是这个规划实体的规划变量(Planning vaiable)了。所以,其实解决这个规划问题的过程,就是针对每一个规划实体,根据约束及每个规划实体的情况,来给它的规划变量设置适当的值,令到所有规划实体的所有规划变量的组合达到整体最优。即是设定每个工人(规划实体),在哪个时间,去哪个车间上班(上班时间和车间就是规划变量)。

问题事实(Problem Fact)

  问题事实是相对规则实体而言的,它也是一个业务实体,与规划实体不同的是,它只反映出业务情况,而在规划的过程中,不会被规划引擎进行修改。也就是说,问题事实只是用于提供资料,辅助规划引擎进行规划运算的。在整个规划过程,问题事实是只读的。例如规则班次计划的时间,其中的班次是在开始规则之前已经确定的,所以“班次”这个业务实体只会在规划过程中,提供每个班次具体的时间等信息,而不会改变的。那么“班次”这个业务实体,就是一个问题事实。

约束(硬约束与软约束)

  上而我们把业务规则定义为约束,其实目前针对排程方面的规划问题,主要是通过约束进行评分机制的寻优方法。约束就是根据业务规则抽象出来,针对规划变量,在求解规划问题时候的一种限制,或惩罚机制。也就是说,约束是用来制约引擎对规划变量的赋值行为的。例如一个人不可能有超过24个小时的可用时间。

  硬约束:硬约束是指那些不能违反的约束,违反了就会出现不符合常理,即业务可能出现绝不允许的情况出现。例如上面提高,一个人不可能有超过24小时的可用时间(常理);机台运行过程中,机修工不能进行维修工作(涉及安全生产问题,法律及业务有硬性要求。)。因此,硬约束可以被人视为是用于对规则行为进行定义的。

  软约束:软约束是相对硬约束而言的,它是可违反的。设立软约束之目的并不是不允许它违反,而是定量地制约规划结果(结果,即是下面讲到的"解"或者"方案")的发展方向,起到对规划结果的偏向作用,即让规则结果尽量向指定的一个方向偏移。也就是说在满足了硬约束的前提下,再对软约束进行判断,如果软约束能不违反就最好,要是必须违反,违反得越少,所得的方案就越好。例如成本高低就是一种软约束,生产运营中不可能不产生成本,那么如果成本越低,那么方案肯定越好,当然是在满足了硬约束的前提下。

规划问题其实是NP问题或NP-Hard问题

  其实在《Optaplanner - 入门介绍》中已经有讲解过关于NP或NP-Hard(那讲到NPC问题),大家可以去参考一下那篇文章。这时概括地重述一下,NP或NP-Hard问题是问题以下条件的:

  • 对于一个给定的规划的结果(官网中称作solution, 即是解),很容易在合理的时间内对其进行验证是否可行。例如:课程表编排得正不正确,可以根据约束来核对一下就可以确定了,例如有没有出现同一个时间内,一个老师被分配到不同的班级上课。
  • 不存在一个可确定的方法,在合理的时间内找到一个最优解(这里指的是绝对最优解)。这个也不难理解,对于这种没有任何快捷方法找最优解的规划问题,我们唯一的办法就是把所有不同的组合情况全部排列出来,一个一个比较(即逐一枚举),那必然是可以找到最优解的。但是,因为这种方法其实是一种暴力穷举法,当问题非常复杂、且需要规划的实体数量非常多时,它的时间复杂度是随着组合情况的增加,呈指数式上升的,暴力穷举的方法是不可取的。

规划问题存在巨量搜索空间

  搜索空间:因为目前针对规划问题,只能通过搜索的方式去寻找相对最优解,因为相对一些直接通过算法操作得到的办法而言,规划问题只能将它的解一个一个地对比,逐步收敛逼近的办法来得到相对最优解。所以,你可以认为规划问题的相对最优解是搜索出来的,而且每一步搜索都需要对约束进行运算;从所有经历过的解中,找到相对最优一个。所以规划问题存在一个搜索空间的问题,即有多少种可能的解,就表示搜索空间有多大。例如将3个任务分配到两个机台上,存在多少种可能?大家可以自己去算,其实就是排列组合问题。

  而对实际问题时,稍复杂的约束,稍多一点的规划实体,最后得出的可能解的数量都是非常巨大的,很多问题其搜索空间轻易就是一个天文数字。所以,如果对于所有规则问题,都是使用这些暴力枚举的办法,以现有世界上的计算机的算力,很多问题是没办法找到最优解的。

  规划问题的规模,即是规划实体及每个实体的规划变量的组合,例如时间、空间,及影响因素,及这些因素的所有情况组合。例如,如果上述所有实体,规划的变量和所有因素,展开后的数量是M,而一个解是对其中的N个变量进行规划,那么有多少个解呢?其实就是M到N的排列P(M->N).当遇到实际问题的,这些组合的数量就是天文数字了。

可能解,可行解,相对最优解与绝对最优解

  在规则问题中,需要清楚解的概念,在OptaPlanner里称作solution, 即方案。在本系列文章中,解与方案是相同的意义,请注意。本猿只是根据中文表达的习惯,在不同的场合以最顺口的方式,视情况确定到底应用用“解”,还是“方案”来表述。

在接下来的一系列文章中,我在讲解这些方案的过程中,会用到以下概念:

  可能解:一个规划问题的任意一个解都称为可能解,也就是所有规则实体的所有规则变量,任意一个组合,都称作一个可能解。例如分配工人A,在1月20日晚班,到1号车间;分配工人A在1月20日晚班到2号车间;分别是两个不同的可能解,尽管它们的差别只是分配到不同的车间.而每个工人的每个班次的工作车间,正好是规划变量。所以任意一个规划变量的不同,都会产生不同的可能解。现在知道为什么规划问题存在巨量搜索空间了吧?

  可行解:可行解就是那些完全符合硬约束的解。即若存在一个解,它对任何一个硬约束都是符合的,则称这个解为可行解。可行解是可能解的一个子集。可行解是可验证的,只要根据目前所有的硬约束,对解中的每一个规划实体中的每个规划变量,逐一核对,看是否符合所有硬约束,如果符合,那就表示这个解是可行解。

  相对最优解:上面已经提,规划问题的搜索空间非常巨量,大多数情况下是不可能计算并比较所有解的值,再取得最佳方案(这个解就是绝对最优解)的。在固定的时间内,Optaplanner引擎帮我们找到的最优方案,就是称作相对最优解了。大家来思考一下,相对最优解必然是可行解吗?

  绝对最优解:同样的上面提到,就是所有可能解中最优的那个解,目前是没有直接确定的算法,通过运算在合理的时间内去找到一个问题的绝对最优解的,所以要得到绝对最优解,只有一个办法,就是将所有可能解都遍历一次才能找到。当问题规模不算大的时候,以目前的CPU速度还是能实现的。但如果问题稍复杂一点,规划实体和规划变量稍多一点,那么可能解的数量就是一个天文数字了,这种情况下是没办法完全遍历的。所以,在我们现实中,我们是无法得到绝对最优解的。其实更贴切地说,我们所得到的相对最优解,我们不知道它是不是绝对最优解。因为现在数学上还没有办法(除了遍历)证明一个相对最优解是否绝对最优。

  本篇先介绍一下上述两个概念,下一篇将我们再具体介绍其它概念。

原创不易,如果觉得文章对你有帮助,欢迎点赞、评论。文章有疏漏之处,欢迎批评指正。****


本系列文章在公众号不定时连载,请关注公众号(让APS成为可能)及时接收,二维码:

OptaPlanner逐步学习(0) : 基本概念
如需了解更多关于OptaPlanner的应用,请发电邮致:kentbill@gmail.com
或到讨论组发表你的意见:https://groups.google.com/forum/#!forum/optaplanner-cn
若有需要可添加本人微信(13631823503)或QQ(12977379)实时沟通,但因本人日常工作繁忙,通过微信,QQ等工具可能无法深入沟通,较复杂的问题,建议以邮件或讨论组方式提出。(讨论组属于google邮件列表,国内网络可能较难访问,需自行解决)

点赞
收藏
评论区
推荐文章
凯特林 凯特林
3年前
ES 家族新特性,闪亮登场!
前言前端学习永无止境,学习吧骚年本文集合了ES6至ES11常用到的特性,包括还在规划的ES12,只列举大概使用,详细介绍的话内容量将十分巨大.。PS:使用新特性需要使用最新版的bable就行转义新特性ES6(2015)1\.类(class)class Man   constructor(name)     this.n
御弟哥哥 御弟哥哥
3年前
Groovy基础与循环语句
Groovy入门在这一节中,将真正开始进行Groovy编程。首先,学习如何轻松地安装Groovy(通过EclipseGroovy插件),然后从一些有助于了解Groovy的简单示例开始。轻松安装Groovy为了迅速开始使用Groovy,需要做的全部工作就是安装Eclipse的Groovy插件。打开Ecliplse,在
Stella981 Stella981
3年前
C++中stoi函数
作用:  将n进制的字符串转化为十进制头文件:include<string用法:1stoi(字符串,起始位置,n进制),将n进制的字符串转化为十进制23示例:4stoi(str,0,2);//将字符串str从0位置开始到末尾的2
Stella981 Stella981
3年前
Rust FFI 编程
当我们拥有一组具有良好声明的头文件时,自己定义C库的RustFFI绑定函数是毫无意义的。我们可以使用 bindgen 这种工具从C库的头文件生成RustFFI绑定函数。然后,我们运行一些测试代码以验证其是否正常运行,并对它们进行调整,直到正确为止。本文我们将通过一个示例,讨论如何使用 bindgen 将C库中的函数
Stella981 Stella981
3年前
Sass 变量的声明与使用
本节我们学习Sass中的变量,那么什么是变量呢?Sass中的变量可以用来存储一些信息,并且重复使用。变量可以存储的信息包括字符串、数字、布尔值、颜色值等等。声明变量Sass中声明变量需要用到$符号,格式为:$变量名:变量值;示例:例如下面我们定义一个变量,并给这个变量赋了一个颜色
Stella981 Stella981
3年前
RocketMQ 整合 DLedger(多副本)即主从切换实现平滑升级的设计技巧
源码分析RocketMQDLedger多副本系列已经进行到第8篇了,前面的章节主要是介绍了基于raft协议的选主与日志复制,从本篇开始将开始关注如何将DLedger应用到RocketMQ中。\摘要:详细分析了RocketMQDLedger多副本(主从切换)是如何整合到RocketMQ中,本文的行文思路首先结合已掌握的DLe
可莉 可莉
3年前
22【React基础
写在前面从这篇文章开始,我们重新来学习一下React的官网。本文从经典的HelloWorld示例开始,给大家介绍下react应用的创建,通过本文的介绍,我们学会新建一个react应用。概述React其实就是一个JS文件库,本质上跟我们的jQuery这些JS库是一样的,所以大家在开始的时候不要有任何的心理负担,觉得它很难,其实它一
Wesley13 Wesley13
3年前
Unity Asset Bundle 角色换装示例 官方例子
《Unity官方案例精讲》一书中在第9章介绍了角色换装示例与AssetBundle的使用。示例中还展示了如何用SkinnedMeshRenderer渲染模型。虽然是好几年的示例了,但其中的换装的一些基本思想还是可以借鉴的,示例中动画的播放不用太在意,是legacy动画播放,了解下就好。下面先来看一下运行图。!character
liam liam
6个月前
API 设计:基础知识与最佳实践指南
在这篇深入探讨中,我们将从基础开始,逐步介绍API设计,并探讨定义卓越API的最佳实践。作为一名开发者,你可能已经熟悉了许多这些概念,但我将提供详细解释,以加深你的理解。API设计:电子商务示例让我们考虑一个像这样的电子商务平台的API,如果你不熟悉,Sh