遗传算法解决柔性作业车间调度问题之解码

前面已经写了编码及种群初始化(14条消息) 遗传算法解决柔性作业车间调度问题(附初始化代码)_Yzboyfriend1106的博客-CSDN博客

接下来要讲一下解码

FJSP染色体MS、OS由两部分组成,分别对它们进行解码,关键是需要将工序排序部分解码成对应于机器选择部分的活动调度,具体的解码步骤如下。

步骤1:

对机器选择部分进行解码,从左到右依次读取并转换成机器顺序矩阵J_M{}和时间顺序矩阵T。其中J_M{}(j,h)表示工件J的工序O的机器号J_M{}(j,·)表示工件J的所有工序按优先顺序加工的各个机器号的排列;T(j,h)表示工件J的工序O的加工时间。J_M{}(j,h)与T(j,h)的关系是一一对应的。
以上篇文章图3表示的P-FJSP为例,如上篇文章图5所示的一个染色体编码,其中机器选择部分[4 1 2 2 4]转换为机器顺序矩阵和时间顺序矩阵后为

J_M{}(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()

  • 7
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值