1 批处理(Batch Scheduling)
1.1 问题描述
车间有一系列零部件需要在数量有限的烤箱内进行加温处理,每个零部件需要经过一系列相互独立的烘烤流程。另外,烤箱从当前烘烤温度转为另一烘烤温度时,需要一定的转换时间。同一工单进行相邻两个步骤时,也需要一定的加工准备时间。如何合理组合不同零件为一批次和合理的安排加工顺序来最大化烤箱利用率同时最小化烤箱转换所花的等待时间最早缩短总工时就显得尤其重要。
1.2 CP模型
1.2.1 输入参数
preparationTime:同一空单进行相邻两步骤时的,所需的准备时间;
products:零部件种类集合;
steps[products]各零部件所需加工工序集合;
orders[p in products]各零部件订单数量;
{taskT} allTasks = {<p, s.stepNumber, o,
s.duration, s.temperatureCode>
| p in products, s in steps[p], o in 1..orders[p]};调度任务集合 包含零件种类、步骤编号、订单编号、加工时间;
maxTime = sum(t in allTasks)(t.duration + preparationTime)引入所有任务结束时间的一个上限参数;这里构造为所有任务串行总时间。
range ovens = 1..numberOvens可用烤箱集合
ovenCapacity[ovens]各烤箱的容量;
transitionTimes烤箱从一个烘烤温度过渡到另一烘烤温度所需的转换时间(该过渡矩阵需满足三角不等式)
1.2.1 决策变量
(1)tasks[t in allTasks]1) 区间决策变量(intervalvariable),表示任务 由任何烤箱执行的所需时间。CP模型中决策变量的域很重要,直接关系到搜索空间的大小,如下 下届为该烘烤任务准备完成时间,下届为所有烘烤任务完成的最迟时间,该区间变量的长度即为该工序所需的烘烤时间。
dvar interval tasks[t in allTasks] in preparationTime..maxTime size t.duration;
(2) taskOvenAlts定义为可选(optional)区间决策变量,表示任务 由烤箱 烘烤。“可选”意味着这类区间变量中有些并不会出现在最终解中(即不会被执行)。设计这个区间变量的目的是为了进行任务分配,即对任务 的操作任务可能会被分配给任意烤箱上,但最终通过 约束会限制仅有一个烤箱能够执行任务 ,其它烤箱都不会出现在最终解中(即不会执行)。如果定义区间变量时未加optional关键词,则默认该区间变量必定会出现在解中(即必定执行)。定义如下:
dvar interval taskOvenAlts[t in allTasks][o in ovens] optional;
(3) ovenUsage累积函数变量(cumuFunction),表示任一时刻所有任务消耗烤箱总数。本模型中,表示在任一时刻所有任务消耗的机器总数不得超过烤箱总个数。累积约束是全局约束(globalconstraint),非常有助于CP引擎进行全局推理,进而提升求解效率。
cumulFunction ovenUsage[o in ovens] = sum(t in allTasks) pulse(taskOvenAlts[t][o], 1);
定义中 函数是OPL中的基本累积函数,其第一个参数表示消耗资源的区间变量,第二个参数表示区间变量在其执行过程中消耗的资源数。基本累积函数求和后成为汇总累积函数,它代表了所有基本累积函数执行过程中消耗的资源总量,对汇总累积函数施加约束即为资源约束。
图1表示了汇总累积函数表示的资源消耗曲线,其中H是资源量限制,各个a是区间变量。可以看出,每个区间变量执行时,使得汇总累积函数曲线增加,区间变量执行完后,使得汇总累积函数减少。对汇总累积函数上限施加的限制就是累积约束,也就是资源消耗约束。
图1 汇总累积函数
(4) ovenTemperature状态转变函数(stateFunction)表示烤箱从一个温度状态转到另一个温度状态所需的转换时间。
stateFunction ovenTemperature[o in ovens] with transitionTimes;
1.2.2任务优先关系约束
forall(t1,t2 in allTasks : t1.productId == t2.productId &&
t1.stepNumber + 1 == t2.stepNumber &&
t1.orderId == t2.orderId) {
endBeforeStart(tasks[t1], tasks[t2], preparationTime);
} (1-1)
约束(1)确保所有的零部件按照规定的加温工序,依次处理。
1.2.3 任务分配约束
forall(t in allTasks)
alternative(tasks[t], all (o in ovens) taskOvenAlts[t][o]); (1-2)
约束(2)将烘烤任务分配到烤箱上。该约束意思有且仅有一个变量 出现在解中,且其起止时间与 完全相同。
任务 可能会分配到任意烤箱上操作,这些操作可用区间变量集合 表示。但通过 (选择)约束,会限制在可用烤箱中仅有一个能够执行任务 ( 状态为1),且该任务的起止时间与 完全相同,同时使得其他烤箱操作任务 的 状态为0。这样,就相当于将任务 分配给唯一一台烤箱。
1.2.4 烤箱资源有限约束
forall(o in ovens)
ovenUsage[o] <= ovenCapacity[o]; (1-3)
约束(3)确保任意时刻被分配的烤箱总数不得超过该类型的可用烤箱总数。
1.2.5 烤箱转换时间约束
forall(t in allTasks, o in ovens)
alwaysEqual(ovenTemperature[o], taskOvenAlts[t][o], t.temperatureCode); (1-4)
约束(4)中的 确保在 这段时段内,烤箱 的温度保持在任务 所需的温度。烤箱的温度随着任务 的变化,处理相邻不同的温度时,烤箱需要转换时间。
1.3 目标函数
目标函数(5)是最小化最晚完工任务的完成时间,也就是整体完工时间。
minimize max(t in allTasks) endOf(tasks[t]);(1-5)