获取更多资讯,赶快关注上面的公众号吧!
文章目录
第一章 单机调度问题研究
1.1 单机案例描述
单机总加权拖期问题可以描述为:一共有n个作业,每个作业(1,…,n)需要在同一台机床上加工,加工过程不能中断,且机床在同一时间只能加工一项作业。作业j(j=1,…,n)在0时刻准备就绪,加工时间为p(j),权重为w(j),交货期为d(j)。给定这些作业的加工顺序,可以很容易地得到作业j(j=1,…,n)的最早完成时间C(j)和拖期T(j)=max{C(j)-d(j),0}。问题的目标是确定一个加工顺序使得所有作业的总加权拖期SUM{j=1,…,n}w(j)T{j}最小。
OR-Library中提供了三种问题规模(n=40,50,100)的数据文件,每种规模都有125(对于RDD和TF每个取值各生成5个案例,5x5x5=125)个测试案例。这些案例可以在链接:https://pan.baidu.com/s/1SXl8TZCKs1D2uNca80RjmA 提取码:ux3k 下载。
案例按照如下方式随机生成:
属性 | 数据类型 | 分布 | 分布参数 |
---|---|---|---|
加工时间p(j) | 整型 | 均匀分布 | [1,100] |
权重w(j) | 整型 | 均匀分布 | [1,10] |
交货期范围RDD | 浮点型 | 离散取值 | [0.2,0.4,0.6,0.8,1.0] |
平均拖期因子TF | 浮点型 | 离散取值 | [0.2,0.4,0.6,0.8,1.0] |
交货期d(j) | 整型 | 均匀分布 | [P(1-TF-RDD/2),P(1-TF+RDD/2)],P=SUM{j=1,…,n}p(j) |
文件wt40,wt50和wt100分别包含了规模为40,50和100的案例,每个文件包含了125个实例的数据,这些数据是针对每个案例依次给出的,首先是n个加工时间,接着是n个权重,最后是n个交货期。例如,在wt40中前40个整数是第一个案例的40个作业的加工时间,接下来的40个整数为第一个案例的权重,再接下来的40个整数为第一个案例的交货期,再后面的40个整数为第二个案例的加工时间,以此类推。
规模大小为40和50的案例中,分别有124和115个案例时已知最优值的,规模40中未被解决的问题是19,50中未被解决的是11,12,14,19,36,44,66,87,88和111。
wtopt40和wtopt50文件中给出了目前已知的最优值。Crauwels, Potts & Van Wassenhove (1996)。这些值一直到现在也没有得到改进,所以很可能就是最优的。
在文件wtbest100a中给出了规模为100问题的最优值(Crauwels, Potts & Van Wassenhove (1998)),这些值在Crauwels, Potts和Van Wassenhove (1998) and Congram, Potts & van de Velde (1998)中也被当做是已知最优值。因此使用这些已知的最优解值Crauwels, Potts & Van Wassenhove(1998)允许未来启发式算法的结果直接与这些论文中的表格数据进行比较。
针对规模为100的问题,局部搜索启发式动态搜索(Congram, Potts & van de Velde 1998)已经在某些情况下找到了比Crauwels, Potts & van Wassenhove(1998)更好的解决方案。wtbest100b文件给出了到目前为止已知的最优值。
1.2 启发式规则设计
一共设置了34种启发式规则,详细见下表。
规则序号 | 规则名称 | 描述 |
---|---|---|
1 | FOPNR | 剩余工序数越少越优先 |
2 | MOPNR | 剩余工序数越多越优先 |
3 | SPT | 工时越短越优先 |
4 | LPT | 工时越长越优先 |
5 | SRPT | 剩余工时越少越优先 |
6 | LRPT | 剩余工时越多越优先 |
7 | MINSEQ | 准备时间越少越优先 |
8 | EDD | 工件交货期越早越优先 |
9 | SPT/TWK | 选择工序加工时间与总加工时间比值最小的工件 |
10 | LPT/TWK | 选择工序加工时间与总加工时间比值最大的工件 |
11 | SPT/TWKR | 选择工序加工时间与剩余加工时间比值最小的工件 |
12 | LPT/TWKR | 选择工序加工时间与剩余加工时间比值最大的工件 |
13 | SPTxTWK | 选择工序加工时间与总加工时间乘积最小的工件 |
14 | LPTxTWK | 选择工序加工时间与总加工时间乘积最大的工件 |
15 | SPTxTWKR | 选择工序加工时间与剩余加工时间乘积最小的工件 |
16 | LPTxTWKR | 选择工序加工时间与剩余加工时间乘积最大的工件 |
17 | SRM | 选择除当前考虑工序外剩余加工时间最短的工件 |
18 | LRM | 选择除当前考虑工序外剩余加工时间最长的工件 |
19 | SSO | 选择后继工序加工时间最短的工件 |
20 | LSO | 选择后继工序加工时间最长的工件 |
21 | SPT+SSO | 选择当前工序加工时间与后继工序加工时间最短的工件 |
22 | LPT+LSO | 选择当前工序加工时间与后继工序加工时间最长的工件 |
23 | S-1 | 工件剩余交货时间越少越优先(ALL) |
24 | S-2 | 工件松弛率越小越优先(CR) |
25 | S-3 | 工件待加工部分松弛率越小越优先(SL) |
26 | S-4 | 工序松弛时间越小越优先(OSL) |
27 | S-5 | 工序松弛率越小越优先(OCR) |
28 | S-6 | 每一剩余工序可用时间越小越优先(ALL/OPN) |
29 | S-7 | 每一剩余工序松弛时间越小越优先(SL/OPN) |
30 | S-8 | 每单位剩余工作量松弛时间越小越优先(SL/WKR) |
31 | GW | 工件权重越大越优先 |
32 | LW | 工件权重越小越优先 |
33 | WSPT | 加权最短加工时间(权重/工时越大)优先 |
34 | WLPT | 加权最长加工时间(权重/工时越小)优先 |
1.3 调度案例求解过程
1.3.1 案例格式化
对于不同调度类型(单机、并行机、流水、作业车间、柔性作业车间),以及不同机构和论文中给出的benchmark往往具有不同的数据定义格式,为了能够灵活地处理这些数据,在调度平台中加入了一个Instance类,所有的benchmark数据最终转换成Instance类型并保存成JSON格式至本地,所以用户在使用时就不用再关心和调度无直接关系的事情了。同时用户也还可以自行运行程序,根据给定的参数(工件数、机床数、工序数等)生成自己想要的案例,同样也以JSON形式保存到本地。
案例格式化的目的在于三方面。第一,就是将不同的调度定义进行转换,使得调度平台的输入只有一种格式,从而简化维护过程;第二,JSON格式具有很强的可读性,“属性:值”这样的表达远远要比一堆纯数字要清晰得多;第三,Instance采用面向对象的思想,可以让其具有更通用的表达能力。
1.3.2 案例初始化与重置
通过FileHandle类中的相关方法就可以将本地JSON读取到内存中,但是此时调度案例中各个对象间的关系是独立的,比如某一工序的前置和后置工序为空,工序对应的工件为空,因此在执行调度前一般需要对案例进行初始化,具体的初始化内容加表表2。初始化过程仅仅在算法整个生命周期中执行一次。
初始化项 | 初始化值 |
---|---|
调度目标objective | 默认为ObjectiveCmax,即制造期 |
工序任务map | 遍历各个工件的各道工序,以工序名称为key,以工序为value存入map |
工序剩余工时 | 当前工序工时+其后所有工序总工时 |
工序剩余工序数 | 最后一道工序为1,倒数第二道工序为2,以此类推 |
工序对应工件 | 设置为当前正在处理的工件 |
工序的前置工序 | 工件的工序列表中前一道工序 |
工序的后置工序 | 工件的工序列表中后一道工序 |
工件总工时 | 工件的工序任务列表工时总和 |
机床已分派任务队列 | 新建一个TreeSet,设置一个按照工序开始时间升序排列的比较器 |
调度案例重置的目的是在使用迭代优化算法时,每一次迭代开始前先清除上一代的调度结果,具体的重置内容见表表3。重置过程需要在每次迭代时执行。
重置项 | 重置值 |
---|---|
调度目标objective | 0 |
已调度总工时 | 0 |
就绪任务集合 | 设置为默认的任务比较器,添加所有工件的首工序至该集合 |
工件当前工序 | 工件的首工序 |
工序调度开始和结束 | 0 |
工序已分派机床 | ID为-1, 名称为空,表示未分派 |
工序状态 | Operation.Unassigned_state表示待分派 |
工序固定分配机床 | -1 |
机床已分派任务队列 | 清空 |
机床已分派任务工时 | 0 |
机床负荷率和利用率 | 0 |
工件调度开始和结束 | 0 |
1.3.3 案例工序分派
任务调度是基于析取图模型(后面再单独讲)的,如图2所示,大致就是确定需要相同机床上加工的工件顺序,然后再通过拓扑排序得到调度结果,整个调度流程如图3所示。
调度分派过程中采用了插空法,这样就能得到活跃调度,因为已经证明最优解存在于活跃调度中。
1.3.4 案例调度后处理
后处理主要是计算调度结果并进行输出。
1.4 单机调度案例启发式求解
1.4.1 案例格式化
在InstanceGenManagerTest中给出了单机调度案例格式化的测试,方法genSingleMachineInstance需要三个参数,分别为:标准案例文件路径,案例个数和工件数量。
InstanceGenManager instanceGenManager = new InstanceGenManager();
instanceGenManager.genSingleMachineInstance("D:\\Personal\\Desktop\\单机调度案例\\wt40.txt", 125, 40);
instanceGenManager.genSingleMachineInstance("D:\\Personal\\Desktop\\单机调度案例\\wt50.txt", 125, 50);
instanceGenManager.genSingleMachineInstance("D:\\Personal\\Desktop\\单机调度案例\\wt100.txt", 125, 100);
格式化后的案例默认存放于系统盘用户目录(我的是C:\Users\Administrator\instance)下,如图4所示。其中“0”表示单机调度类型,40/50/100表示工件数量,1表示机床数量。在该三个文件夹下各有125个调度案例,以“.ins”为后缀名,可以用NotePad打开,同时需要在插件管理中安装JSON Viewer,这样看起来就舒服多了,但这并不是必要的。所有这些文件都已经准备好,无需运行以上代码。
1.4.2 读取格式化后的案例
读取案例也很方便,只要调用相应的方法即可,如读取单机案例则执行FileHandle的readSingleMachineInstance方法即可,输入参数为案例所在文件夹名称,如图4中的“0_40x1sample”。
1.4.3 创建启发式管理器
调度管理器采用接口(ScheduleManagerIface)的形式对调度使用的主要过程进行了定义,然后在实现类ScheduleManager中实现了一般的调度过程,其实大部分调度过程离不开这个范围,如果有特殊的调度过程,可以继承ScheduleManager,对相应的方法进行重写(override)即可。这里的启发式调度管理器HeuristicScheduleManager直接继承了ScheduleManager而没有重写。
package mm_scheduler.instanceScheduler.algorithm.heuristic;
import mm_scheduler.instanceScheduler.instance.manager.ScheduleManager;
/**
* @author: hba
* @description:启发式调度器,完全继承了ScheduleManager
* @date: 2019年12月18日
*
*/
public class HeuristicScheduleManager extends ScheduleManager {
/**
* @author hba
*
* 下午5:25:38
*/
}
1.4.4 创建启发式调度器
调度器是用户进行调度的交互入口,在新建启发式调度器时需要指定所使用的启发式规则,可以有两种指定方式:启发式规则对象和启发式规则编号。
目前在rules路径下指定了34中启发式规则,这些规则均继承于OperationRule类,自定义的规则也需要继承该类,然后根据规则属性重写compare方法。创建调度器时只需要传入规则对象即可。
HeuristicScheduler heuristicScheduler = new HeuristicScheduler(new OperationEDD());
当需要一次运行多个规则时,平台里还提供了一种通过编号确定规则的方式,创建调度器时只需要传入规则对应的编号,同时该编号对应的规则一定要在InstanceUtil的setInstanceOperationComparator方法中进行注册。
HeuristicScheduler heuristicScheduler = new HeuristicScheduler(ruleID);
1.4.5 执行调度
创建完调度器后,直接调用其schedule方法即可。
heuristicScheduler.schedule(instance, 0);
1.4.6 调度结果
这里以40x1的第一个单机案例为研究对象(其加权拖期最优解为913),使用34种规则进行调度,得到的结果如表4。通过以下结果可以发现,很多规则得到的调度结果是相同的,这是因为在按某一属性进行排序时得到的调度结果是相同的,同时不同规则间调度性能差别也很大,所以不同的规则组合搭配成复合规则往往取长补短,更加有效。
规则名称 | 加权拖期 | 执行时间(秒) |
---|---|---|
FOPNR | 7755 | 0.048 |
MOPNR | 27509 | 0.002 |
SPT | 7755 | 0.001 |
LPT | 27509 | 0.001 |
SRPT | 7755 | 0.001 |
LRPT | 27509 | 0.001 |
MINSEQ | 7755 | 0.001 |
EDD | 1588 | 0.001 |
SPT/TWK | 7755 | 0.0 |
LPT/TWK | 27509 | 0.001 |
SPT/TWKR | 7755 | 0.0 |
LPT/TWKR | 27509 | 0.0 |
SPTxTWK | 7755 | 0.001 |
LPTxTWK | 27509 | 0.0 |
SPTxTWKR | 7755 | 0.0 |
LPTxTWKR | 27509 | 0.001 |
SRM | 7755 | 0.0 |
LRM | 27509 | 0.001 |
SSO | 7755 | 0.0 |
LSO | 27509 | 0.0 |
SPT+SSO | 7755 | 0.0 |
LPT+LSO | 27509 | 0.0 |
S-1 | 1588 | 0.001 |
S-2 | 27493 | 0.001 |
S-3 | 1588 | 0.0 |
S-4 | 1588 | 0.001 |
S-5 | 27493 | 0.001 |
S-6 | 1588 | 0.0 |
S-7 | 1588 | 0.001 |
S-8 | 27493 | 0.001 |
GW | 3354 | 0.0 |
LW | 23831 | 0.0 |
WSPT | 3066 | 0.001 |
WLPT | 30647 | 0.001 |
参考文献
H.A.J. Crauwels, C.N. Potts and L.N. Van Wassenhove (1998). Local search heuristics for the single machine total weighted tardiness scheduling problem, Informs Journal on Computing 10, 341-350.
R.K. Congram, C.N. Potts and S.L. van de Velde (1998). An iterated dynasearch algorithm for the single-machine total weighted tardiness scheduling problem. In preparation.