1. 问题描述和数学规划模型
排产排程、原料采购、仓储存放等是制造业降本增效的关键问题。本节以香皂的制造为例,不同于上一篇问题01-生产多少,本例主要考虑原料采购的问题。以下数据只是用来示意如何使用MAPL建模和求解,实际的制造规划问题规模更大,建模更复杂。
集合
- 制作香皂的油脂集合
- 油脂分为两种,我们定义植物油脂集合为,动物油脂集合为
参数
- 油脂每吨的成本
- 油脂的硬度
- 植物油脂的购买量上限(单位: 吨)
- 动物油脂的购买上限(单位: 吨)
- 每卖出一吨香皂,盈利
- 香皂的硬度不得低于,也不得高于
变量
- 是某工厂要购买油脂的重量(单位: 吨)
- 是生产的香皂量(单位: 吨)
目标
- 工厂要最大化其利润:
约束
- 假设从油脂到香皂的转化过程中,油脂没有任何浪费,生产过程中重量守恒:
- 植物油脂的购买总量不得超过
- 动物油脂的购买总量不得超过
- 假设从油脂到香皂的制造过程中,硬度的转化满足线性关系:
2. 使用MindOpt APL进行建模和求解
MindOpt建模语言(MindOpt Algebra Programming Language, MindOpt APL,简称为MAPL)是一种高效且通用的代数建模语言。当前主要用于数学规划问题的建模,并支持调用多种求解器求解。下面将演示如何使用MAPL将上面的数学模型公式和数据输入,生成一个求解器可求解的问题,再调用求解器去进行求解。
方法1:cell中直接输入建模代码运行
我们可以将 MindOpt APL 建模代码直接在MindOpt云上平台Notebook中的cell里运行。请注意内核(kernel)需要选MAPL。代码如下:
clear model;#清除model,多次run的时候使用 option modelname model/manufacture_02_soap1;#方便与方法2的中间文件生成在同一个目录 #---------建模----------------- # manufacture_02_soap1.mapl # 声明集合 set O1 := { "VEG1", "VEG2" }; set O2 := {"OIL1", "OIL2", "OIL3"}; set O := O1 + O2; set F := {"cost", "hardness"}; # 声明参数 param data[O * F] := | "cost" , "hardness" | |"VEG1" | 100 , 2.0 | |"VEG2" | 90 , 4.5 | |"OIL1" | 110 , 5.3 | |"OIL2" | 105 , 7.8 | |"OIL3" | 95 , 5.0 |; param r := 180; param b1 := 200; param b2 := 150; param l := 4; param u := 6; # 声明变量 var x[O] >= 0; # 括号内室字母O, 并非数字0 var y >= 0; # 声明目标 maximize Reward: r * y - sum {<j> in O} (data[j, "cost"] * x[j]); # 声明约束 subto Weight: sum {<j> in O} x[j] == y; subto Hardness1: sum {<j> in O} (data[j, "hardness"] * x[j]) >= y * l; subto Hardness2: sum {<j> in O} (data[j, "hardness"] * x[j]) <= y * u; subto VEGBound: sum {<j> in O1} x[j] <= b1; subto OILBound: sum {<j> in O2} x[j] <= b2; #------------------------------ print "-----------------用MindOpt求解---------------"; option solver mindopt; # 指定求解用MindOpt求解器 solve; # 求解 display; print "-----------------结果---------------"; print "最大利润 = ",r * y - sum {<j> in O} data[j, "cost"] * x[j];
方法2:导入.mapl文件运行建模然后求解
上面时直接在cell中运行所有的脚本,我们也可以建立个新文档,将中间建模的代码保存为manufacture_02_soap1.mapl文件。然后运行如下code,结果同方法1。
clear model;#清除model,多次run的时候使用 #------------------------------ model model/manufacture_02_soap1.mapl; #通过导入建模脚本.mapl文件进行建模 #------------------------------ print "-----------------用MindOpt求解---------------"; option solver mindopt; # 指定求解用MindOpt求解器 solve; # 求解 display; print "-----------------结果---------------"; print "最大利润 = ", r * y - sum {<j> in O} data[j, "cost"] * x[j];
3. 结果
运行方法一、方法二代码结果一致,如下:
-----------------用MindOpt求解--------------- Running mindoptampl wantsol=1 MindOpt Version 0.25.1 (Build date: 20230816) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 24-AUG-2023 19:46:39). License validation terminated. Time : 0.006s Model summary. - Num. variables : 6 - Num. constraints : 5 - Num. nonzeros : 23 - Bound range : [1.5e+02,2.0e+02] - Objective range : [9.0e+01,1.8e+02] - Matrix range : [1.0e+00,7.8e+00] Presolver started. Presolver terminated. Time : 0.000s Simplex method started. Model fingerprint: =Y2dkV2dhdnY Iteration Objective Dual Inf. Primal Inf. Time 0 1.54802e+05 0.0000e+00 8.6001e+00 0.01s 4 3.07500e+04 0.0000e+00 0.0000e+00 0.01s Postsolver started. Simplex method terminated. Time : 0.001s OPTIMAL; objective 30750.00 4 simplex iterations Completed. Primal Solution: x@VEG1 = 0.00000000 x@VEG2 = 200.000000 x@OIL1 = 0.00000000 x@OIL2 = 0.00000000 x@OIL3 = 150.000000 y = 350.000000 -----------------结果--------------- 最大利润 = 30750
display指令运行时,会打印出很多求解的结果,x@name 和 y 是决策变量的取值,后面的dual solution是对偶解的值。示意如下:
Primal Solution: x@VEG1 = 0.00000000 x@VEG2 = 200.000000 x@OIL1 = 0.00000000 x@OIL2 = 0.00000000 x@OIL3 = 150.000000 y = 350.000000 -----------------结果--------------- 最大利润 = 30750
同时,在最近建模的文件所在目录或option modelname指定的位置,会生成对应的文件.nl
和.sol
。其中.nl
文件是建模的问题模型文件,可被多数求解器识别,.sol
文件中存储了求解结果solution。
从打印的结果,们可以得到采用如下的采购方案时,利润最大,为30750元,生产了350吨的香皂:
x@VEG2 = 200.000000 x@OIL3 = 150.000000