本文仅是个人观点,用于记录学习所得,有问题还请提出。
前言
生产调度优化是一种将有限的车间加工资源合理分配给车间内各生产任务的问题,其具有复杂性、动态随机性、多目标、多约束的特点,是一类经典的NP难问题。过去的研究中以近似算法与精确算法求解为主,其中精确方法能保证得到全局最优解,但只能求解较小规模的问题,而近似算法能够求解大规模调度问题,可以较快得到问题的较优解,并满足解决实际问题的需要,但容易陷入局部最优解。
科学制定并执行优化调度方法能够缩短生产周期、提高成品率、降低企业生产成本并使装配过程更科学、有效、柔性。
一、MiniZinc介绍
Minizinc是一种免费的开源约束规划建模语言,是Zinc语言的一个子集,其能够非常简单方便地表示大多数约束,同时可以与大多数求解器进行融合,可以认为MiniZinc对模型进行描述,再利用求解器对模型进行求解(个人理解,有错误请指出)。与MiniZinc兼容的求解器包括:Chuffed、CBC、findMUS、Gecode、CPLEX等,不同求解器针对的场景不同,比如一般使用Gecode,但其不适合求解混合整数规划问题,这时使用CBC求解器就可以正常求解啦,具体可以看一下官方文档中的实数求解那一部分。
MiniZinc支持定义谓词和函数,用户可以以此构建自己的模型,其一个最强大的建模特征是建模者可以定义属于他们自己的高级约束,这就使得用户可以对模型进行抽象化和模块化。除此之外Minizinc有十分全面的官方文档,很适合新手入门学习调度优化。
MiniZinc官方网站:迷你锌 (minizinc.org)
二、问题建模及代码
调度优化问题的建模是一个稍显复杂的过程,一般的生产调度问题可以定义为:假定目前存在n个工件{W1,W2,...Wn}需要在m个机器{M1,M2,...,Mm}上进行相应的加工过程,具体需要考虑到不同工件、不同工序、加工时间、等待时间、加工顺序、资源约束、空间约束等问题。
为对问题进行简化并更易于理解MiniZinc代码,针对其官方文档中提供的源代码jobshop(2.2.5复杂约束)进行建模。
2.1 问题模型假设
(1)作业一旦开始就必须完成,不能中途停止;
(2)各资源不发生变化且只具备一种功能;
(3)装配工艺明确,装配时间、资源数量等不随装配过程发生改变;
(4)不考虑作业空间、物料运输、人员移动等因素,仅考虑装配作业时间。
2.2 问题参数定义
JOB:作业集合;
i:作业任务序号;
k:作业任务序号且大于i;
TASK:任务;
j:不同任务对应的机器序号;
total:总持续时间;
last:TASK的最大数量
end:最终结束时间
d[i,j]:整型数组,表示第i个作业中运行在第j个机器上的工时;
s[i,j]:整形数组,表示第i个作业在第j台机器上开始工作的起始时间;
约束条件
(1)作业任务顺序固定
具体代码如下:
constraint %% ensure the tasks occur in sequence
forall(i in JOB) (
forall(j in TASK where j < last)
(s[i,j] + d[i,j] <= s[i,enum_next(TASK,j)]) /\
s[i,last] + d[i,last] <= end
);
对于每一个作业中在任何机器上运行的任务来说,一个任务的开始时间加上持续时间要小于下一个任务的开始时间,并且最后一个任务的开始时间加上持续时间要小于总结束时间。
forall:聚合函数,接收一个布尔型表达式数组,返回单个布尔型表达式;
enum_next(X,x):返回枚举类型X中x值的后一个值。
(2)不同作业的任务之间不互相重叠
constraint %% ensure no overlap of tasks
forall(j in TASK) (
forall(i,k in JOB where i < k) (
s[i,j] + d[i,j] <= s[k,j] \/
s[k,j] + d[k,j] <= s[i,j]
)
);
根据假设2,同一台机器上不能同时运行两个作业的任务,当两个作业都需要在第j台机器执行任务时,只有一个任务结束后该机器才能运行另一个作业的相应任务,这一约束与作业序号无关。
目标函数
solve minimize end;
目标函数为最小化最终结束时间。
三、问题求解
利用官方文档中所提供的.dzn文件对相应数据进行输入,具体求解结果如下:
这表明最终找到了该问题的最优解,最优解的结束时间为30,下面数据为各作业在各机器上执行任务的开始时间。
总结
该问题代码为官方文档所提供,无法完全表示实际生产过程的现场情况,故可以对该问题进行进一步地完善。如加入资源约束,定义一个代表资源的枚举类型RESOURCE,表示运行每一种任务的机器数量,在任务运行过程中可以根据作业数量进行调度;可以对每个时间节点的资源数量进行约束,定义一个资源最大供应量,每个任务运行过程中资源的使用量不得大于供应量;此外还可以考虑每个作业任务之间的空间距离问题以及运输时间的问题或者定义作业最早开始与最迟开始时间等。官方文档中一共提供了三个车间作业调度代码,后两个主要是针对代码进行优化,如jobshop2定义了谓词no_overlap,jobshop3利用全局约束cumulative引入了disjunctive谓词约束,分别对不重叠代码进行了优化,但两者都没有对模型进行优化。