好久没更新过APS系列文章了,这段时间项目工做确实很是紧,因此只能抽点时间学习一下运筹学的入门知识,算是为之后的APS项目积累点基础。看了一些运筹学的书(都是科普级别的)发现原来我目前面对的不少排产、排班、资源分配和路线规划问题,都是运筹学上的典型案例。与此同时,除了继续使用Optaplanner来作咱们的规划类项目外,还花点时间去研究了一下Google OR-Tools开源规划引擎,这是Google旗下的一个开源求解器,接下来我会专门写一些关于Google OR-Tools应用的文章,并与Optaplanner做些关联对比。算法
本篇先向你们展现一下两个规划工具,在求解线性规划问题上的应用方法,分别是Microsoft Office的Excel里的”规划求解”组件和Google Dos中的Spreadsheet上提供的Linear Optimization插件。这两个工具均可以做为规划问题的求解器。由于它们是以插件或软件功能形式提供的,在灵活性和扩展性方面限制仍是比较大,可是由于不涉及软件开发的技能,普通用户都能很好地应用它们来解决一些现实业务中遇到的规则问题。服务器
由于Google的Linear Optimization是Google文件服务中的Spreadsheet(Google提供的相似于Excel的电子表格程序),由于目前国内的网络状况(你懂的),访问它须要本身想办法,咱们公司总部不在中国境内,因此咱们的办公网络通过注册,是能够合法访问外界的;关于网方面不在本篇中讨论,你们本身科学解决就能够了。微信
下面先给出本次咱们须要求解的线性规划问题,其实在Optaplanner相关的文章中,详细介绍过关于NPC问题,普通线性规划问题不少并非NPC问题,由于对于线性规划模型,仍是有例如单纯形法等算法推算它的最优解的,而不是全部规划问题的时间复杂度都是O(a^n)或O(n!)的,你们要理解清楚二者的关系。网络
咱们要求解的问题跟不少运筹学教材或科普书籍上的例子同样,也是最简单的在肯定的条件约束下,求最大利润下的产品生产方案问题。例如一家工厂生产两种产品,产品A与产品B,均需使用到三种资源,资源一、资源2和资源3。其中生产一件产品A,须要5个单位的资源1,4个单位的资源2,3个单位的资源3。生产一件产品B须要3个单位的资源1,8个单位的资源2,5个单位的资源3。一个产品A的利润是20,一个产品B的利润是25。库存中三种资源的存量为:280单位的资源1,580单位的资源2,360单位的资源3.见下表:架构
求:两种产品分别生产多少件,才能令到总利润最大?此时的利润是多少?函数
以上问题是典型的线性规划问题,运筹学的同窗能够经过单纯形法进行求解,可是这种方法对于没有运筹学背景的普通工程师来讲,困难仍是不小。即便咱们学会这种办法,但遇到更复杂问题的时候,对咱们来讲其挑战仍是至关大。所以,目前市上,或开源世界里,提供了不少解决此类规划问题的开源软件。但对于非IT人员来讲,没有软件开发背景,很难利用这些开源软件工具写程序求解。所以,一些知名的办公软提供了相关的特性,让非IT专业人员直接使用其规划功能,输入数据便可快速求得答案。对各行业的生产、管理活动提供了极大的帮助。下面咱们就以Excel和Google Spreadsheet两种工具中的规划求解功能,尝试求解上述问题。 工具
要解决上述问题,就须要对问题进行线性规划建模,创建数学模型,以数学工具对问题的约束和目标进行概括、抽象,用数学语言表达问题的本质意义。对于上面的问题咱们的建模以下:假设产品A生产x件,产品B生产y件,才能让利润最大化。那么咱们经过对问题的约条件和规划目标的分析,能够得出如下数学模型。性能
该模型表示:生产产品A和产品B所需的三种资源的总量,均不能超过每种资源的库存量;而且产品件数量必须是大于等于0的整数。规划的目标函数是找出两种产品的利润之和的最大值,并计算出得到该利润时,两种产品的产量分别是多少。学习
对于线性规划问题,其实能够经过单纯形法、对模型进行求解,从而得出z最大时的x与y的值。但此方法须要必定的数学知识,此范围的知识不在本文的讨论范围内,之后如有机会,我再简单介绍一下经过单纯形法对此模型求解步骤。但本人也不是运筹专业出身,估计也只是班门弄斧;所以,你们能够上网寻找更专业的运筹学资源,了解规划模型的解法。本文经过Excel下的规划求解功能,以及Google下的Spreadsheet中的Linear Optimization插件,对该规划模型进行求解,从而取得该生产安排问题的解。优化
Excel提供了一个很是强大的组件用于解决此类规划问题,目前我还只尝试过线性规划问题,根据其资料显示,非线性规划也是能够解的。之后如有机会尝试一下其它规划问题再分享给你们。下面逐一展现这组件具体用法给你们。
由于规则求解功能默认不会出如今Excel的经常使用工具栏中,所以,须要从加载项目中把它加载出来才能使用。在Excel菜单栏中,选择【文件】->【选项】,在弹出的【Excel选项】窗口中,选择【加载项】页签,在列表中的【非活动应用程序加载项】(意思是说Excel目前有这些功能能够用,但尚未加载进去,因此不会显示在工具栏中)的其下方找到【规则求解加载项】,以下图.
在列表下方的【管理(A)】下拉框中选择【Excel加载项】,点击【“转到...】按钮,会弹加载项窗口,以下图。在【可用加载宏(A)】列表中,选中【规划求解加载项】,点击肯定,窗口关闭。
在Excel的【数据】工具栏的最右则,你会看到【规划求解】的图标,便是刚才咱们操做完成后加载进来的组件,以下图。
事实上它是Microsoft提供的一个求解器,该组件对应的文件在C:\Program Files (x86)\Microsoft Office\root\Office16\Library\SOLVER此文件夹下。该文件夹下有两个文件,分别是SOLVER.XLAM和SOLVER32.DLL, SOLVER.XLAM是一个Excel的宏文件,用于实现Excel对求解器核心SOLVER32.DLL的调用,所以SOLVER32.DLL应该就是这个求解器的核心程序动态链接库。
完成规划求解组件加载后,下面就能够将数学模型的各个常量、变量和约束关系填入Excel单元格中;先将两种产品和三种资源对应的使用数量创建一张二维表,以下表。
经过Excel及规划求解组件解答此问题步骤以下:
1.填入常量:上表中,产品A对资源一、资源2和资源3的要求量分别是5,4,3(即B2,B3,B4的值),其单件利润为20(B5)。 一样方法将产品B对应的数量填入C2- C5单元格中。另外,对于三种资源的库存量,将其值填 入D2 - D4中。自此,模型中涉及的常量已经所有填写时表格。
2.根据数学模型,定义运算关系:本模型中,咱们的目标是求得当z最大时变量x,y的值(x,y在运筹学的规划模型中被称为 决策变量;在Optaplanner中,它们被称做规划变量)。在Excel中每个决策变量须要肯定在一个单元格,以备参与接下来的规划计算,如上表的B6,C6单元格。在未启动规划的时候,这两个单元格直接填上0做为初始值便可。这两个表明决策变量的单元格在完成规划,找到答案后,运算结果值将会被填到对应的单元格中。
肯定好这两个变量后,下一步须要考虑规划目标,也就是总利润最大化的目标,也须要为此目标值肯定一个单元格,此单元格的值会在规划完成时,肯定了B6和C6两件单元格的值以后计算出来。根据目标函数z = 20x X 25y的定义,此单元格的公式应为 :B5 * B6 + C5 * C6,即两种产品的利润之和。咱们把存储利润之和的值定在D7单元格,为了直观美观,咱们把D7与E7合并。
肯定了目标函数值的单元格和计算公式后,下一步须要处理约束条件,也就是产品的资源使用量与库存的约束关系。对于资源1,咱们将E2肯定为其资源用量,它计算公式应该是:B2 * B6 + C2 * C6,即两种产品对该资源的使用量之和。按相同的规则,设置E3 = B3 * B6+ C3* C6, E4 = B4 * B6 + C4 * C6.
经过上述两个步骤设定后,各个单元格的常量值、决策变量和运算关系已设定好。接下来就能够启动【规划求解】插件进行逻辑设定。在【数据】菜单项目中,最右则的【分析】组里,有一个【规划求解】图标,点击它,便可打开【规划求解】窗口(以下图)
如下讲解这些参数意义及其设置。
1.【设置目标(T)】项:该项目咱们须要选定一个单元格,表示该单元格是本次规划活动须要计算的目标。经过问题描述和规划模型,咱们得知该问题目标是求利润的最大值及取得该利润时两种产品的产量。也即模型中的目标函数z的最大值,及此时的x,y的值。在上表中D7就是存放这个目标函数的单元格,所以这里选中D7便可。在参数设置时,都是使用单元格的绝对地址,所以单元格地址前面都有$符号。
2.目标值中【到】项:该项用于设置对于目标函数的取值要求,能够看到它有【最大值】,【最小值】和【目标值】三个选项。其中【最大值】和【最小值】,表示目标函数往最大或最小两个极值方向求解,即最优解中,D7单元格的值是在知足约束条件状况下取得的最大值。而【目标值】则表示取得最优解时,目标函数值最等于或最接近于此值。本问题中的目标是求利润最大,因此咱们选择【最大值】。
3.【经过更改可变单元格(B)】:该项表示在规划过程当中求解器,经过改变哪些单元格的值,来得到结果,直到【目标值】所指的单远格(本例中的D7)中的值达到极值。对应到模型中,也就是x与y两个决策变量,本例中对应的单元格是B6和C6,分别表示产品A和产品B的产量。所以,选择B6和C6便可。
4.【遵照约束】:该项内容表示本次规划须要符合的约束条件,也就是模型中的s.t.部分(s.t. 是subject to的缩写)和各个不等式和各变量的范围条件。点击右则的【添加(A)】按钮,弹出【添加约束】窗口(以下图),能够看到约束的表达方式很是简单,就是添加左右两则值的逻辑关系。
参照模型中的s.t.部分,和excel中的单元格位置关系,添加它们的关系便可。例如对于资源1,s.t.中的约束条件5x * 3y <= 280, 可参经过选择操做,添加如下关系: E2 <= D2,表示产品A所需资源量与产品B所需资源量之和,不能大于资源库存量。按相同的规则设置好资源2和资源3的约束条件。另外对于决策变量x,y,模型中有这两个变量应为整数,且大于等于0的约束。所以,分选选择B6和C6,并在条件表达关系选择int便可。完成后条件约束的内容如上图中的【遵照约束】列表中的内容。
5.【选择求解方法】:该栏列举了目前可选择的三种求解算法,分别是【单纯线性规划】,即单纯形解法,【非线性GRG】和【演化】。具体的求解方法在选择框下方有简单解释,咱们选择默认的【非线性GRG】或【单纯形法】便可。
6.【求解】:点击【求解】按钮,即会启动求解器进行规划求解。完成后会弹出【规划求解结果】窗口,供进一步操做(例如保存规划方案等)。与此同时,原来在未求解前,由于产量设置为0,因此所需资源(E列)的三个单格E2,E3,E4,以及总利润单元格D7的初始值是0。完成规划后,找到最大利润下两种产品的产量(B6,C6)以后,上述原值为0的单元格的值,也随即被更新为该利润最大方案时对应的值。以下图。
由结果可知,完规划求解后,获得的决策变量值:x=20, y=60, 目标函数z的值为1900,即表示:当产品A生产20个(B6单元格),产品B生产60(C6单元格)个时,其利润达到最大值1900(D7单元格)。上述规划问题获得完美解。下面咱们再使用另一个工具 - Google Spreadsheet中的线性优化插件,求解一样的问题。
对于规划问题,微软和Google通提供了很强大的套件,令到像我这种没有运筹学背景的普通用户,能够方便地求解一些规划问题。在此不得不感叹一下,在此方面国内相似软件与国外的差异。曾经有朋友跟我讨论过,公司使用的国内某个一线办公软件,功能直逼office,办公中绝大部分状况,这个软件都能处理,但遇到一些须要进行规划运算的问题,此软件则没有提供相似的功能,不得不求助于Microsoft Excel。
说到这种非专业人员用的规划求解工具,不得不延伸提一下规划引擎软件方面,也存同类问题。目前在国内,若是是针对某一大型公司或项目,只要资源到位,实现一个可用的规划引擎问题不算大。但涉及要求更高,可用性更强的通用规划引擎(不管是开源仍是商业)国内外的差距就体现出来了。商业求解器领域暂不深刻讨论,本人专一于开源规划引擎的应用 研究,近两三年项目应用或本身学习研究中,曾分析应用过一些开源规划引擎,除开优化性能和优化结果的质量上的比较;仅就在工程实践的可用性、易用性上,目前还很难在国内找到一款能跟Optaplanner及Google OR-Tools媲美的开源引擎。先不说能够知足建模要求的引擎软件包,就是求解器方面,国内开源项目也寥寥可数。
下面开始对Google Spreadsheet中的Linear Optimization插件的应用进行具体介绍。仍是在上面已经创建好的数学模型基础上,讨论经过Google的Linear Optimization求解此模型。在开始以前,须要完成如下准备工做:
完成上述前期工做后,便可开始Google Spreadsheet的配置和应用。
Linear Optimization是Google Spreadsheet的一个插件,能够实现对线性规划模型的求解。默认状态下,Google Spreadsheet是不包括此插件的,须要使用的话,则须要将期添加Spreadsheet中才能使用。下面将操做接步骤列出。
1.建立Spreedsheet文件
登陆Google账号,进入Google Sheets页面(http://sheets.google.com)。进入后Spreadsheet主页后,点击页面右下解的红色添加按钮,建立一个Google Spreadsheet文件。在建立好的文件中,能够将文件命名为“LP_Test”文件即会自动保存到你的Google账号。以下图。
添加Spreadsheet 重命名文件
2. 添加Linear Optimization插件
经过Spreadsheet页面的Add-ons菜单,将Linear Optimization插件添加到你的账号上,才能进一步使用该线性优化插件,能够看到还有更多规划功能的插入能够添加。这也是Google在运筹优化方面的系统架构与Optaplanner存在的差异。我将会有新的一篇文章对比两个开源规划引擎这方面的差别,敬请期待。点击Add-ons -> Get add-ons… 菜单项目,将会弹出【Add-ons】页面,在页面上的搜索框中输入”Linear Optimization”并回车,便可搜索出该插件,并点击【+FREE】按钮进行添加。以下图。
在添加过程当中,须要你登陆或选择一个已经登陆的账号,选择你已登陆的账号便可,以下图
选择或输入账号后,会转到一个Sign in页面,大概意思是说Linear Optimization将会被添加到指定页面,点击页面底部右则的【Allow】按钮便可。
3. 建立线性规划模板
添加完成后,在【Add-ons】菜下会出现【Linear Optimization】子菜单项,该子菜单下会有用于设置决策变量、约束和求解的子项。见下图。
选择【Linear Optimization】菜单下的【Set up optimization sheet】子项,便可在当前Sheet中生成求解模板,模板中包含f了决策变量定义区域、目标函数区域和约束区域。下图为新建立的线性规划模板刚建立好的状态.
4.填入决策变量、约束和目标函数
建立好线性规划模板后,须要将上面已经创建好的数学规划模型输入模板中对应的单元格,正确地反映数学模型的意义,才启动求解器(Google的在线规划服务,是用通WebAPI提供的,所以其求解器是部署在Google本身的服务器上)。初学者能够经过Linear Optimization菜单下的子项,来辅助输入决策变量和约束。选择Linear Optimization菜单下的【Add Variables...】子项,在页面的右则会显示【Describe data】 页面。该页面中点击【Variables】和【Constrains】页签分别能够提供定义决策变量(即模型中的x,y)和约束条件(即模型中s.t.部分中的不等式)的输入元素。如下是【Variables】的各个字段输入以下:
a. Variable Name: 该字段表示决策变量,输入第一个决策变量名x.
b. Type: 从咱们创建的规划模型中,知道决策变量x是一个整数,所以Type中选择Integer,(它默认是Continuous).
c. Lower bound, Upper bound:这两个字段分别表示约束变量的最大值与最小值(即决策变量的取值范围),从模型中能够看到它们的最小值是0, 且无最大值限制,所以,Lower bound填上0, Upper bound留空(它提示为Defaults to Infinity,你们应该懂了吧?)。
d. Objective coefficient:该字段表示该决策变量在目标函数中的系数,也就是目标函数表达式中,x前面的常数,从模型的目标函数上能够看到x前面的技术系数为20,所以填入20便可。点击【Add】按钮,x的相关值及其在目标函数上的体现将会被填入模板中。以相同的规则填入决策变量y相关的信息。
下面介绍约束的输入,点击【Constraints】页签,页面将会展现约束条件填入界面:
a. Constraint Name:由于如今咱们是新创建约束,所以在下拉框中选择【New Constraint】, 页面中将会出同【Constraint Name】、【Lower bound】和【 Upper bound】三个字段。【Constraint Name】字段中输入一个名称用于标识该约束便可,由于模型中每一个不等式是表示一种资源的限制,所以第一个不等式是针对资源1的库存限制的,咱们输入”Resource1”。
b. Lower bound,Lower bound:以模型的s.t.部分中的首个不等式 为例,其实咱们根据题意能够把它补充成
,也就是说,模型中少了产品A资源用量大于等于0这个限制;其实这样是不严谨的。但由于目标函数是求最大值,所以,大于等于0这个条件不表示出来,也不会影响模型的正确性。但须要在Google的Linear Optimization中表未这个不等式时,必然存此条件才能完整表示,包括之后咱们直接使用Google OR-Tools中的线性规划模块,不等式的必须有明确的范围才行。根据上面的不等式,咱们在【Lower bound】中填入0,【Upper bound】输入280(即少于等于280)。点【Add】按钮,首个约束就会被添加到模板中,并添加了范围限制见下图红框内.此时,Resource1这一行(第8行)仅仅表示了式子的值域,具体的式子并未完成。
c. Variable Name, Coefficient:一上步仅添加了约束Resource1的基本结构。本步骤将要完成不等式中的式子部分。点击【Add】后,页面将会出现【Variable name】下拉框,其中有当前模型的全部决策变量(即本例中的x与y)供选择。在右则还会出现【Variable coefficient】输入框,表示你选择的决策变量在不等式中前面的常数(即技术系数),经过模型咱们看到Resource1不等式中x前面的常数是5,所以填入5,并点击【Add】,此时常数5就会被填入当前约束,x对应列的单元格(即D8单元格)。一样地,不等式中决策变量y前面的常是3,所以咱们在【Variable name】中选择y,并在【Variable coefficient】中填入3。点击【Add】便可完成约束Resource1的输入。一样的方法输入资源2和资源3的约束,完成后以下图
5.求解
完成上述步骤以后,咱们创建的规划模型已经所有表达到Linear Optimization模板中,选中【Linear Optimization】菜单下的【Solve】子项,程序将会启用Google的线性规划Web服务,对刚才输入的模型进行求解,并把结果填回表格中,见下图.
上图是模型的规划结果,能够看到,经过这个模型计算出来的最大的利润是1900(B6单元格),得到此利润时,产品A的产量是20(D6单元格),产品B的产量是60(E6单元格).
本文经过对一个简单的线性规划问题,创建线性规划模型;并分别经过Excel的规划求解组件,和Google Spreadsheet下的Linear Optimization插件对模型进行求解,从而得出最优结果。非IT专业人员在实际生产活动中,遇到此类线性规划问题时,能够经过此方法对问题进行求解。而专业的IT人员,遇到的问题会比本文中的状况复杂得多,经过现成的软件功能极可能是没法解决,须要经过软件开发技术,结合规划引擎进行求解。你们能够参考我以前的Optaplanner系列文章 .
本人近段时间也在研究Google OR-Tools,发现本文用到的Linear Optimization实际上是经过将Google OR-Tools的多个运筹求解器,创建在Google自身的服务器上;再以Web服务方式提供给的。在实际软件项目开发过程当中,咱们能够绕开Google Spreadsheet服务程序,经过本身的程序调用其运筹优化服务进行求解。固然现目前国内的状况来看,经过对它的开源项目Google OR-Tools的引用,直接将其求解器归入咱们本身开发的系统中更现实。
我正在撰写一篇关于Optaplanner与Google OR-Tools的对比文章,经过对比两个引擎的用法,有针对性的引出对Google OR-Tools的应用,敬请期待,谢谢!
如需了解更多关于Optaplanner的应用,请发电邮致:kentbill@gmail.com
或到讨论组发表你的意见:https://groups.google.com/forum/#!forum/optaplanner-cn
如有须要可添加本人微信(13631823503)或QQ(12977379)实时沟通,但因本人平常工做繁忙,经过微信,QQ等工具可能没法深刻沟通,较复杂的问题,建议以邮件或讨论组方式提出。(讨论组属于google邮件列表,国内网络可能较难访问,需自行解决)