柔性作业车间调度
1 问题描述
1.1 传统作业车间调度
工件 | 工序 | 可选择的加工机器 | ||||
---|---|---|---|---|---|---|
M1 | M2 | M3 | M4 | M5 | ||
J1 | O11 | -- | -- | 5 | -- | -- |
O12 | 11 | -- | -- | -- | -- | |
O13 | -- | -- | -- | -- | 8 | |
J2 | O21 | -- | 6 | -- | -- | -- |
O22 | 9 | -- | -- | -- | -- | |
O23 | -- | -- | -- | 7 | -- |
有若干工件,每个工件有若干工序,有多个加工机器,但是每道工序只能在一台机器上加工。对应到上面表格中的实例就是,两个工件,工件J1有三道工序,工序Q11只能在M3上加工,加工时间是5小时。
约束是对于一个工件来说,工序的相对顺序不能变。O11->O12->O13。每时刻,每个工件只能在一台机器上加工;每个机器上只能有一个工件。
调度的任务则是安排出工序的加工顺序,加工顺序确定了,因为每道工序只有一台机器可用,加工的机器也就确定了。
调度的目的是总的完工时间最短(也可以是其他目标)。举个例子,比如确定了O21->O22->O11->O23->O12->O13的加工顺序之后,我们就可以根据加工机器的约束,计算出总的加工时间。
M2加工O21消耗6小时,工件J2当前加工时间6小时。
M1加工O22消耗9小时,工件J2当前加工时间6+9=15小时。
M3加工O11消耗5小时,工件J1当前加工时间5小时。
M4加工O23消耗7小时,工件J2加工时间15+7=22小时。
M1加工O12消耗11小时,但是要等M1加工完O22之后才开始加工O12,所以工件J1的当前加工时间为max(5,9)+11=20小时。
M5加工O13消耗8小时,工件J2加工时间20+8=28小时。
总的完工时间就是max(22,28)=28小时。
1.2 柔性作业车间调度
工件 | 工序 | 可选择的加工机器 | ||||
---|---|---|---|---|---|---|
M1 | M2 | M3 | M4 | M5 | ||
J1 | O11 | 2 | 6 | 5 | 3 | 4 |
O12 | -- | 8 | -- | 4 | -- | |
O13 | 4 | -- | 3 | 6 | 2 | |
J2 | O21 | 3 | -- | 6 | -- | 5 |
O22 | 4 | 6 | 5 | -- | -- | |
O23 | -- | 7 | 11 | 5 | 8 |
相比于传统作业车间调度,柔性作业车间调度放宽了对加工机器的约束,更符合现实生产情况,每个工序可选加工机器变成了多个,可以由多个加工机器中的一个加工。比如上表中的实例,J1的O12工序可以选择M2和M4加工,加工时间分别是8小时和4小时,但是并不一定选择M4加工,最后得出来的总的完工时间就更短,所以,需要调度算法求解优化。
相比于传统作业车间,柔性车间作业调度的调度任务不仅要确定工序的加工顺序,而且需要确定每道工序的机器分配。比如,确定了O21->O22->O11->O23->O12->O13的加工顺序,我们并不能相应工序的加工机器,所以还应该确定对应的[M1、M3、M5]->[M1、M2、M3]->[M1、M2、M3、M4、M5]->[M2、M3、M4、M5]->[M2、M4]->[M1、M3、M4、M5]的机器组合。调度的目的还是总的完工时间最短(也可以是其他目标,比如机器最大负荷最短、总的机器负荷最短)
2 数据处理
2.1 数据集
引自博文“【标准算例数据源】作业车间、流水车间、柔性作业车间、其它”:https://blog.csdn.net/weixin_40775077/article/details/108762117
2.2 数据解释
上面的图片是Mk数据的一个例子,第一行6 6 1表示6个工件6个机器,平均每道工序有1个可选加工机器。第2-7行为工件1-6的信息。以第2行为例,6表示工件J1有6道工序;后面的1 3 1表示工序O11有1台机器可选,可选机器为M3,加工时间为1小时;后面的1 1 3表示工序O12有1台机器可选,可选机器为M1,加工时间为3小时。依此类推。
2.3 处理为适合自己的格式
上面的数据格式其实是不方便计算的(可行解不容易设计,调度目标如完工时长不容易计算)。所以需要读取为适合自己的格式。
下面是我的处理方式:
变量 | 类型 | 解释 |
---|---|---|
num_job | 1*1大小的整数 | 工件个数 |
num_machine | 1*1大小的整数 | 机器个数 |
num_op | 1*num_job大小的数组 | num_op[i]表示工件i的工序个数 |
operation_time | 1*num_job大小的cell,其中每个cell存储的是num_op[i]*num_machine大小的数组 | operation_time[i]存储的是工件i所有工序的可选加工机器以及加工时间,0表示不可加工 |
对应到上面图中的例子:
num_job = 6;
num_machine = 6;
num_op = [6 6 6 6 6 6];
operation_time{1} = [
0 0 1 0 0 0;
3 0 0 0 0 0;
0 6 0 0 0 0;
0 0 0 7 0 0;
0 0 0 0 0 3;
0 0 0 0 6 0;
];
operation_time{2-6}不再列出。operation_time{1}[i][j]表示工件1的第i道工序在第j台机器上的加工时间,0表示不可加工。
3 优化算法求解
3.1 编码方案
参考高亮老师论文改进遗传算法求解柔性作业车间调度问题——机械工程学报的编码方案。可行解分成两部分,第一部分为机器分配编码,第二部分为工序加工顺序编码。编码长度为2*工序总数。
机器分配编码按照工序的顺序来,第一个表示工序O11的机器分配,第二个数表示工序O12的机器分配,依此类推,如1.2节表格的一个可行解的机器分配可以从“[M1、M3、M5]->[M1、M2、M3]->[M1、M2、M3、M4、M5]->[M2、M3、M4、M5]->[M2、M4]->[M1、M3、M4、M5]”随机选为M3->M1->M2->M4->M2->M5,机器编码可以表示为3 1 2 4 2 5。这样编码的优势就是可以很容易设计出交叉变异操作方案,使得执行交叉变异操作之后得到的新解的机器编码是可行的。
工序加工顺序编码使用工件表示,工件i第j次出现表示工序Oij。比如1.2节表格的一个可行解的工序加工顺序可以为O21->O22->O11->O23->O12->O13,工序编码可以表示2 2 1 2 1 1。这样编码的优势是把工件对加工顺序的约束隐含到了编码里面。
3.2 适应度计算(目标函数)
对于一个可行解,要计算总的完工时间,需要计算每个工件的当前加工时间,每个机器的当前加工时间。然后根据可行解,解码出工件加工顺序和机器安排,根据2.3小节获得的数据格式计算完工时间。
主要的思路如下(细节不再给出):
- 初始化,每个工件的当前加工时间 = 0;每个机器的当前加工时间 = 0;
- 工件的当前工序完工时间 = max(工件上一道工序完工时间,当前工序对应加工机器的上一个任务完工时间)+对应机器对当前工序的加工时间;
- 机器的当前加工时间 = 工件的当前工序完工时间;
3.3 可行解更新策略
参考高亮老师论文改进遗传算法求解柔性作业车间调度问题——机械工程学报的更新策略。主要实现了GA(遗传算法)的选择、交叉和变异。
3.3.1 选择
采用锦标赛选择,K元锦标赛:从大小为N的种群中随机选取K个个体,将适应度最好的个体加入下一代。重复执行N次,获得N个个体。
3.3.2 交叉
当满足交叉概率时,执行交叉,重复N次判断。随机选择两个个体,具体交叉策略如下:
对于机器编码,采用两点交叉,随机生成两个交叉点,交换两个个体位于交叉点内的基因。
对于1.2节表格的两个可行解的机器编码,比如p1 = [3 1 2 5 4 1];p2 = [1 3 2 4 2 5];选取交叉点为2-4的话,交换p1和p2位于2-4之内的基因,得到两个子代s1 = [3 3 2 4 4 1];s2 = [1 1 2 5 2 5]。
对于工序编码,采用基于工件的POX交叉,将工件分成两个互补的集合J1和J2,P1中在J1中的工件保留,在J2中的工件使用P2中在J2中的工件按顺序对应填充。
1.2节的表格不适合解释这个交叉方案,我们提出一个新的问题:有4个工件待加工,工序数目为[2 2 2 1]。对应的两个可行解的工序编码,比如p1 = [3 1 2 4 2 1 3];p2 = [2 3 1 2 4 3 1]。J1={1,4},J2={2,3}。首先s1继承p1的J1编码,s2继承p2的J2编码,s1 = [- 1 - 4 - 1 -];s2 = [2 3 - 2 - 3 -]。用p2的J2编码填充s1的空位,同样方法