前面已经写了编码及种群初始化(14条消息) 遗传算法解决柔性作业车间调度问题(附初始化代码)_Yzboyfriend1106的博客-CSDN博客
接下来要讲一下解码
FJSP染色体MS、OS由两部分组成,分别对它们进行解码,关键是需要将工序排序部分解码成对应于机器选择部分的活动调度,具体的解码步骤如下。
步骤1:
对机器选择部分进行解码,从左到右依次读取并转换成机器顺序矩阵和时间顺序矩阵T。其中(j,h)表示工件J的工序O的机器号(j,·)表示工件J的所有工序按优先顺序加工的各个机器号的排列;T(j,h)表示工件J的工序O的加工时间。(j,h)与T(j,h)的关系是一一对应的。
以上篇文章图3表示的P-FJSP为例,如上篇文章图5所示的一个染色体编码,其中机器选择部分[4 1 2 2 4]转换为机器顺序矩阵和时间顺序矩阵后为
(1,2)=2表示工件J的工序O2在机器M2上加工,T(1,2)=8表示工件J1的工序O2在机器M2上的加工时间为8。
步骤2:(公式太多了就贴图了)
到此染色体解码完毕,生成活动调度。可以得到每个机器上工序的加工顺序和对应的开始时间、结束时间,即可画出调度甘特图。对其进行操作可以得到相应的目标值。例如对每台机器最后一道工序的完工时间进行比较,可得到最大完工时间。
解码代码思路:
步骤一比较简单,且基本每一步在代码中都有注释
简单讲下步骤二:首先需要创建两个m行n列全为0的矩阵,m为机器数,n为工序的总长度
相当于每个机器都有对应的工序位,如果某工序在某机器上加工,开始加工时间的矩阵相应位置就
变为开始加工的时间,结束时间也是。以书中例子为例,矩阵如下
以此为主要思路,按步骤分情况讨论即可,具体见代码
解码代码如下:
#已以书上例子进行测试,与手算无差,下一步要做的是绘制甘特图
import numpy as np
class Decode:
def __init__(self,J,Processing_time,M_num):
self.J = J
self.Processing_time = Processing_time
self.M_num = M_num
self.Len_Chromo = 0
for i in J.values():
self.Len_Chromo += i # 计算工序长度(如第一个工件有五道工序,第二个工件有十道工序,则长度为15)
# 步骤一:对机器选择部分进行解码,从左到右依次读取并转换成机器顺序矩阵JM和时间矩阵T
def Order_Matrix(self,MS):#机器选择部分的染色体转换为机器顺序矩阵JM和时间顺序矩阵T,注意导入的染色体需要减1(因为本代码从0开始计数),生成的也是减1的
Ms = [] #Ms为变形后的染色体
site = 0 #起始位置
for i in self.J.values(): #为了生成变形的染色体 方便后续
Ms.append(MS[site:site+i])
site += i
JM = []
T = []
for g in range(len(Ms)):#提取第一个工件
JM_i = []
T_i = []
h = Ms[g]
for j in range(len(h)):#提取第一个工件的第一个工序
machine_time = self.Processing_time[g][j] #提取第g个工件第j道工序的加工机器时间矩阵
machine_location = []
T_location = []
for k in range(len(machine_time)): #可使用的机器编号 即mk
using_time = machine_time[k]
if using_time != 9999:
machine_location.append(k)
T_location.append(using_time) #可使用的机器对应的加工时间,即剔除了9999的加工时间矩阵
else:
continue
JM_i.append(machine_location[Ms[g][j]]) #第g个工件的第j道工序选择了第几个机器
T_i.append(T_location[Ms[g][j]]) #对应的时间
JM.append(JM_i) #生成完整的JM
T.append(T_i) #生成完整的T
return JM,T
def Site(self,Job, Operation):#确定第n个工件的第m道工序位于Chromo的哪个位置,解码需再次用到此函数,懒得调用了,从编码直接copy过来了
O_num = 0
for i in range(len(self.J)):
if i == Job:
return O_num + Operation
else:
O_num = O_num + self.J[i+1]
return O_num
#步骤二
def Chromosome_decoding(self,OS,MS):
JM,T = self.Order_Matrix(MS)
Start_Time = np.zeros((self.M_num,self.Len_Chromo),dtype = int)
End_Time = np.zeros((self.M_num,self.Len_Chromo),dtype = int)
Counter_list = []
for OS_i in OS:#OS_i为OS里的每个元素,数字即代表了为第几个工件,如数字2为第二个工件
Counter_list.append(OS_i)
O_j = Counter_list.count(OS_i) #count函数的作用是统计某list里某元素出现几次,在这里,O_j用于记作该工件的第几道工序,如2出现第二次则为第二个工件的第二道工序
M_i = JM[OS_i-1][O_j-1] #减1是因为OS_i和O_j都是从1开始计数的,而list则是从0开始的,工件OS_i的第O_j道工序选择了机器M_i,此处M_i已经是-1的状态
P_i = T[OS_i-1][O_j-1] #这道工序的加工时间
site = self.Site(OS_i-1,O_j-1) #确定工件OS_i的第O_j道工序的位置,site已经是-1的状态
End_Time_list_Mi = End_Time[M_i] #选择的机器对应的那行工序结束时间
Start_Time_list_Mi = Start_Time[M_i] #选择的机器对应的那行工序开始时间
M_i_j = len([i for i in End_Time_list_Mi if i >0]) #M_i_j统计工序Oij为机器Mi的第几道加工工序,此代码含义为统计Mi机器的End_time list中大于0的个数
#如果工序Ojh既是工件Jj的第一道工序,又是机器Mi第一道加工工序,那么直接从Mi的零时刻开始
if O_j == 1 and M_i_j == 0:
Start_Time[M_i][site] = 0
End_Time[M_i][site] += P_i
#如果工序Ojh不是工件Jj的第一道工序,但是是机器Mi的第一道加工工序,那么直接从它的上道工序Oj(h-1)的结束时间开始加工即可
elif O_j > 1 and M_i_j == 0:
M_j_h_1 = JM[OS_i-1][O_j-2] #M_j_h_1为Ojh上道工序选择的机器编号,此处已经是-1的状态
End_time_of_last_operation = End_Time[M_j_h_1][site-1] #在矩阵里找到上道工序的结束时间
Start_Time[M_i][site] = End_time_of_last_operation #上道工序的结束时间就是这道工序的开始时间
End_Time[M_i][site] = End_time_of_last_operation + P_i
#其他情况
else:
end_time_list = [] # end_time为机器Mi对应的那行End_Time里不为0的元素list
end_time_location = [] # 记下不为0的位置
for k in range(len(End_Time_list_Mi)):
a = End_Time_list_Mi[k]
if a != 0:
end_time_list.append(a)
end_time_location.append(k)
end_time_list.sort()
start_time_list = [] # start_time为end_time对应的位置的开始时间
for i in end_time_location:
start_time_list.append(Start_Time_list_Mi[i])
start_time_list.sort()
number = len(end_time_list)
busy_time = np.zeros((number, 2), dtype=int)
for j in range(len(start_time_list)):
start_time = start_time_list[j]
end_time = end_time_list[j]
busy_time[j][0] = start_time
busy_time[j][1] = end_time
if busy_time[0][0] == 0: #分情况讨论,第一种,此加工机器0时刻是忙碌的
free_time = np.zeros((number - 1, 2), dtype=int)
for l in range(number - 1):
free_start_time = end_time_list[l] # 空闲时间的起始时间
free_end_time = start_time_list[l + 1] # 空闲时间的结束时间
free_time[l][0] = free_start_time
free_time[l][1] = free_end_time
elif busy_time[0][0] != 0: #第二种,此加工机器0时刻空闲
free_time = np.zeros((number, 2), dtype=int)
free_time[0][0] = 0
free_time[0][1] = busy_time[0][0]
for l in range(number - 1):
free_start_time = end_time_list[l] # 空闲时间的起始时间
free_end_time = start_time_list[l + 1] # 空闲时间的结束时间
free_time[l + 1][0] = free_start_time
free_time[l + 1][1] = free_end_time
End_time_of_last_operation = End_Time[M_j_h_1][site-1] # 上道工序的结束时间
real_free_start_time = [End_time_of_last_operation] #由于这道工序需要晚于上道工序的结束时间,因此需要刷新空闲时间
for m in range(len(free_time)):
start_free_time = free_time[m][0]
real_free_start_time.append(start_free_time)
real_free_start_time.sort()
location_free_time = real_free_start_time.index(End_time_of_last_operation)
real_free_start_time_reduce_one = real_free_start_time[location_free_time - 1]
key_spot = free_time[location_free_time - 1][1] #关键比较点
if End_time_of_last_operation <= key_spot:
free_time[location_free_time - 1][0] = End_time_of_last_operation
for n in range(location_free_time - 1):
free_time[n][0] = 0
free_time[n][1] = 0
elif End_time_of_last_operation > key_spot:
for n in range(location_free_time):
free_time[n][0] = 0
free_time[n][1] = 0 #以上步骤将不可用的间隔时间设置为0
free_time_space = [] #计算空闲时间的间隔
for q in range(len(free_time)):
space = free_time[q][1] - free_time[q][0]
free_time_space.append(space)
for r in free_time_space: #将空闲时间间隔和加工时间进行比较
if P_i <= r: #加工时间小于空闲时间则插入,注意需要插入最早的那部分
r_location = free_time_space.index(r)
Start_Time[M_i][site] = free_time[r_location][0]
End_Time[M_i][site] = free_time[r_location][0] + P_i
break
else:#加工时间大于所有空闲时间则插到最后面
Start_Time[M_i][site] = busy_time[len(busy_time) - 1][1]
End_Time[M_i][site] = busy_time[len(busy_time) - 1][1] + P_i
Fitness = np.max(End_Time)
return Start_Time,End_Time,Fitness
def main():
Processing_time = [[[2, 6, 5, 3, 4],
[9999, 8, 9999, 4, 9999]],
[[3, 9999, 6, 9999, 5],
[4, 6, 5, 9999, 9999],
[9999, 7, 11, 5, 8]]]
J = {1: 2, 2: 3}
MS = [3,0,1,1,3]
OS = [2,2,1,1,2]
M_num = 5
t = Decode(J,Processing_time,M_num)
print(t.Chromosome_decoding(OS,MS))
if __name__ == '__main__':
main()