[python 那些事儿]流水车间调度问题(理论待更新)

问题描述与算法设计

问题背景

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(1)参数值:

  • 初始化种群数目:NP=自定
  • 最大进化代数:G=自定
  • 交叉概率:Pc =0.8
  • 变异概率:Pm =0.2

(2)编程中的关键问题:

  • (a) 编码。每个染色体编码成工件号序列,比如5个工件的一个编码为序列:[5 1 3 4 2]。
  • (b) 初始种群。初始种群随机产生,种群规模自定。
  • © 解码。将编码按照从左到右的次序进行加工。比如编码[5 1 3 4 2],可以解码为:工件加工次序为:工件5、工件1、工件3、工件4、工件2
  • (d)适应度值。因为是流水线调度问题最小值问题,所以适应度值取目标值的倒数。
  • (e) 选择。采用轮盘赌选择。
  • (f)交叉。交叉采用单点交叉,由于交叉后的个体可能是不可行的,注意需要修复。
  • (g)变异。每次变异,从交换、插入、逆序中随机选择一个执行。
  • (h)测试算例。使用如下6组(n是工件数,m是机器数,Tm,n是加工时间表,从1到99整数中随机产生):
  • 第一组:n=8, m=6, Tm,n
  • 第二组:n=10, m=8, Tm,n
  • 第三组:n=12, m=10, Tm,n
  • 第四组:n=20, m=6, Tm,n
  • 第五组:n=25, m=8, Tm,n
  • 第六组:n=30, m=10, Tm,n

基本遗传算法的一般步骤

  1. 第一步:使用随机方法产生一个有NP个染色体的初始种群;
  2. 第二步:计算种群中每一个染色体的适应度值,即函数值;
  3. 第三步:若达到最大迭代次数G,则算法终止;否则,继续迭代;
  4. 第四步:按照轮盘赌选择。
  5. 第五步:按照概率执行单点交叉操作,注意需要修复;
  6. 第六步:从交换、插入、逆序中随机选择一个执行变异;
  7. 第七步:返回第三步。

简单实现

import copy
import numpy as np
import random
class Node:
    def __init__(self,data,fitness):
        self.data = data
        self.fitness = fitness

#种群条件数据
init_data = [[1,31,41,25,30],
[2,19,55,3,34],
[3,23,42,27,6],
[4,13,22,14,13],
[5,33,5,57,19]]
init_data = np.array(init_data)

#基本数据
source_data = {'1':[1,31,41,25,30],
             '2':[2,19,55,3,34],
             '3':[3,23,42,27,6],
             '4':[4,13,22,14,13],
             '5':[5,33,5,57,19]
            }

#初始化种群
#order_list:初始化种群时的顺序,后期可以调为随机。
order_list1 = [4,2,5,1,3]


class GA_FSP:
    def __init__(self,pc=0.6,pm=0.1,N=20,T=50,n=5,machine=4):
        '''
        N = 20  #群体大小
        T = 50  #Ga终止进化代数
        Pc = 0.6 #交叉概率
        Pm=0.1 #变异概率
        n = 5 #工件个数
        machine = 4 #机器个数
        '''
#         self.data = data
        self.pc = pc
        self.pm = pm
        self.N = N
        self.T = T
        self.n = n
        self.machine = machine
        
       
    def fitness(self,order_list):
        '''
        输入状态数据,即可输出适应度和加工时间
        '''
        def init_group(order_list):
            '''
            根据列表顺序调整整体数据。
            '''
            three_init_data = copy.deepcopy(order_list)
#             print(three_init_data)
            for j in range(len(order_list)):
                i = order_list[j]
                order_i = str(i)
                init_i = i-1
                three_init_data[j] = source_data[order_i]
            init_group = np.array(three_init_data)
            return init_group

        init_data = init_group(order_list)
        # k为加工工件数量
        # j为机器数量
        k = init_data.shape[0]
        j = init_data.shape[1]-1
        
        def find_time(k,j):
            if k==1 and j==1:
                return init_data[0,1]
            elif k>=2 and j==1:
                return find_time(k-1,1)+init_data[k-1,1]
            elif k == 1 and j>=2:
                return find_time(1,j-1)+init_data[0,j]
            else:
                time = max(find_time(k-1,j),find_time(k,j-1))+init_data[k-1,j]
            return time
        time = find_time(k,j)
        fitness = 1/time
        
        return fitness,time

    def init_list(self,N):
        N_group = []
        for i in range(N):
            order_list = [p for p in range(1,self.n+1)]
            random.shuffle(order_list)
#             node = Node(order_list,fitness(order_list))
            N_group.append(order_list)
        return N_group
    
    def where_change(self,three_change_list):
        for i in range(len(three_change_list)):
            if three_change_list[i]<=0:
                return i
            continue
            
    
    def cross_change(self,choice_three):
        changed_list = []

        '''
        函数:两点交叉 传入数据为node列表 长度20
        '''
        def change_main(a1,a2):
            '''
            两点交叉
            传入数据为两个个体
            '''
#             print("两个父类")
#             print(a1.data)
#             print(a2.data)
            a1_copy = copy.deepcopy(a1)
            a2_copy = copy.deepcopy(a2)
            
            random_1=random.randint(0,self.n-1)
            random_2=random.randint(0,self.n-1)
            
            while random_1 > random_2 or random_1 == random_2:
                random_1 = random.randint(0,self.n-1)
                random_2 = random.randint(0,self.n-1)
            a1_copy.data[random_1:random_2],a2_copy.data[random_1:random_2]=a2_copy.data[random_1:random_2],a1_copy.data[random_1:random_2]
            
            intermediate1 = a1.data[random_1:random_2]
            intermediate2 = a2.data[random_1:random_2]
            
#             print("两个随机数")
#             print(random_1)
#             print(random_2)

            head1 = []
            head2 = []
            tail1 = []
            tail2 = []
            
            # 子代1头
#             print("head1")
            for i in a1_copy.data[:random_1]:
#                 print(i)
                while i in intermediate2:
                    i = intermediate1[intermediate2.index(i)]
                head1.append(i)
            # 子代1尾
#             print("tail1")
            for i in a1_copy.data[random_2:]:
                while i in intermediate2:
                    i = intermediate1[intermediate2.index(i)]
                tail1.append(i)
            # 子代2头
#             print("head2")
            for i in a2_copy.data[:random_1]:
                while i in intermediate1:
                    i = intermediate2[intermediate1.index(i)]
                head2.append(i)
            # 子代2尾
#             print("tail2")
            for i in a2_copy.data[random_2:]:
                while i in intermediate1:
                    i = intermediate2[intermediate1.index(i)]
                tail2.append(i)
            
            result1 = head1 + intermediate2 + tail1
            result2 = head2 + intermediate1 + tail2
#             print("两个子类")
#             print(result1)
#             print(result2)

            result1 =  Node(result1,self.fitness(result1))
            result2 =  Node(result2,self.fitness(result2))

            return result1,result2
        
        male = choice_three[0:len(choice_three):2]
        female = choice_three[1:len(choice_three):2]
        if len(male) != len(female):
            minmale = min(len(male),len(female))
        else:
            minmale = len(male)
            
        for j in range(minmale):
            cross_rand = random.random()
            if cross_rand<self.pc:
                a1,a2 = change_main(male[j],female[j])
                changed_list.append(a1)
                changed_list.append(a2)
            else:
                changed_list.append(male[j])
                changed_list.append(female[j])
#         print(changed_list)    
        return changed_list
    
    def variation_change(self,cross_change_three):
        changed_variation=[]
        for j in range(len(cross_change_three)):
            variation_rand = random.random()
            if variation_rand<self.pm:
                random_1=random.randint(0,self.n-1)
                random_2=random.randint(0,self.n-1)
#                 print("变异之前的数据",cross_change_three[j].data)
                cross_change_three[j].data[random_1],cross_change_three[j].data[random_2]=cross_change_three[j].data[random_2],cross_change_three[j].data[random_1]
                changed_variation.append(cross_change_three[j])
#                 print("变异之后的数据",cross_change_three[j].data)
            else:
                changed_variation.append(cross_change_three[j])

        return changed_variation
    
    
    def __sort_threelist(self,arr):
        '''
        冒泡排序
        '''
        n = len(arr)
        for i in range(n):
            for j in range(0,n-i-1):
                if arr[j].fitness[1]>arr[j+1].fitness[1]:
                    arr[j],arr[j+1] = arr[j+1] ,arr[j]
        return arr

    
    def pro_go(self):
        #初始化种群
        N_group = self.init_list(self.N)
        for j in range(len(N_group)):
            N_group[j] = Node(N_group[j],self.fitness(N_group[j]))
        #开始迭代
        draw_x = []
        draw_y = [] 
        for num in range(self.T+1):
            #计算适应度
            for j in range(len(N_group)):
                N_group[j].fitness = self.fitness(N_group[j].data)
#                 print(N_group[j].fitness[0])
#                 print(N_group)

            if num>self.T:
                break
            
            
            #选择操作
            choiceList = [N_group[i].fitness[1] for i in range(len(N_group))]
#             print(choiceList)
            '''
            求出个体i被选中的概率
            '''
            choice = copy.deepcopy(choiceList)
            choice = [choiceList[j]/sum(choiceList) for j in range(len(choiceList))]
#             print(choice)
            sum_choice = []
            for p in range(len(choice)):
                if p == 0 :
                    sum_choice.append(choice[p])
                else:
                    sum_choice.append(choice[p] + sum_choice[p-1])
            
#             print(sum_choice)
#             print(rand_num)
            
            
            '''
            选数 原先列表有几行就要选出几个
            '''
            choice_three = []
            for i in range(self.N):
                rand_num = random.random()
                three_change_list = [rand_num-sum_choice[i] for i in range(len(sum_choice))]
                change_index = self.where_change(three_change_list)
                choice_three.append(N_group[change_index])
            '''
            交叉
            传入种群节点即可
            '''

            cross_choice_three = self.cross_change(choice_three)
#             print(choice_three)
            '''
            变异
            '''
            variation_three = self.variation_change(cross_choice_three)
            sort_group= N_group+variation_three
            
            print("第"+str(num)+"次迭代",end=" ")
            N_group = self.__sort_threelist(sort_group)[0:self.N]
            print(N_group[0].fitness[1],end='--')
            print(N_group[-1].fitness[1])
#             print()
            draw_x.append(num)
            draw_y.append(N_group[0].fitness[1])

            random.shuffle(N_group)
            
        N_group = self.__sort_threelist(sort_group)[0:self.N]
        for i in range(len(N_group)):
            print(N_group[i].data)
            
        return N_group[i],draw_x,draw_y

Ga1 = GA_FSP()
best1,draw_x,draw_y = Ga1.pro_go()
final_data = best1.data

import matplotlib.pyplot as plt 
plt.plot(draw_x, draw_y)
plt.show()

加入测试算例(时间略长)

import copy
import numpy as np
import random
import matplotlib.pyplot as plt
import time
import eventlet

plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
plt.rcParams['axes.unicode_minus']=False   #这两行需要手动设置
class Node:
    def __init__(self,data,fitness):
        self.data = data
        self.fitness = fitness


#初始化种群
#order_list:初始化种群时的顺序,后期可以调为随机。



class GA_FSP:
    
    def __init__(self,pc=0.6,pm=0.1,N=20,T=50,n=8,machine=6):
        '''
        N = 20  #群体大小
        T = 50  #Ga终止进化代数
        Pc = 0.6 #交叉概率
        Pm=0.1 #变异概率
        n = 5 #工件个数
        machine = 4 #机器个数
        '''

        self.pc = pc
        self.pm = pm
        self.N = N
        self.T = T
        self.n = n
        self.machine = machine
       
        self.source_data = self.random_init_data(self.n,self.machine)
        self.order_list1 = [i for i in range(1,self.n+1)]
        random.shuffle(self.order_list1)
    
    def random_init_data(self,m,n):
        '''
        m 是工件数
        n 是机器数
        '''
        source_data_dict={}
        source_data = np.random.randint(1,99,size=[m,n])
        source_data_0 = [i for i in range(1,m+1)]
    #     source_data = np.insert(source_data, 0, values=np.array(source_data_0), axis=1)
        source_data = source_data.tolist()
        for p in range(len(source_data)):
            source_data_dict["{}".format(source_data_0[p])] = source_data[p]
        return source_data_dict
    
    
    def fitness(self,order_list):
        '''
        输入状态数据,即可输出适应度和加工时间
        '''
        def init_group(order_list):
            '''
            根据列表顺序调整整体数据。
            '''
            three_init_data = copy.deepcopy(order_list)
#             print(three_init_data)
#             print(order_list)
#             print(self.source_data)
            for j in range(len(order_list)):
                i = order_list[j]
                order_i = str(i)
                init_i = i-1
                three_init_data[j] = self.source_data[order_i]
            init_group = np.array(three_init_data)
            return init_group

        init_data = init_group(order_list)
        # k为加工工件数量
        # j为机器数量
        k = init_data.shape[0]
        j = init_data.shape[1]-1
        
        def find_time(k,j):
            if k==1 and j==1:
                return init_data[0,1]
            elif k>=2 and j==1:
                return find_time(k-1,1)+init_data[k-1,1]
            elif k == 1 and j>=2:
                return find_time(1,j-1)+init_data[0,j]
            else:
                time = max(find_time(k-1,j),find_time(k,j-1))+init_data[k-1,j]
            return time
        time = find_time(k,j)
        fitness = 1/time
        
        return fitness,time

    def init_list(self,N):
        N_group = []
        for i in range(N):
            order_list = [p for p in range(1,self.n+1)]
            random.shuffle(order_list)
#             node = Node(order_list,fitness(order_list))
            N_group.append(order_list)
        return N_group
    
    def where_change(self,three_change_list):
        for i in range(len(three_change_list)):
            if three_change_list[i]<=0:
                return i
            continue
            
    
    def cross_change(self,choice_three):
        changed_list = []

        '''
        函数:两点交叉 传入数据为node列表 长度20
        '''
        def change_main(a1,a2):
            '''
            两点交叉
            传入数据为两个个体
            '''
#             print("两个父类")
#             print(a1.data)
#             print(a2.data)
            a1_copy = copy.deepcopy(a1)
            a2_copy = copy.deepcopy(a2)
            
            random_1=random.randint(0,self.n-1)
            random_2=random.randint(0,self.n-1)
            
            while random_1 > random_2 or random_1 == random_2:
                random_1 = random.randint(0,self.n-1)
                random_2 = random.randint(0,self.n-1)
            a1_copy.data[random_1:random_2],a2_copy.data[random_1:random_2]=a2_copy.data[random_1:random_2],a1_copy.data[random_1:random_2]
            
            intermediate1 = a1.data[random_1:random_2]
            intermediate2 = a2.data[random_1:random_2]
            
#             print("两个随机数")
#             print(random_1)
#             print(random_2)

            head1 = []
            head2 = []
            tail1 = []
            tail2 = []
            
            # 子代1头
#             print("head1")
            for i in a1_copy.data[:random_1]:
#                 print(i)
                while i in intermediate2:
                    i = intermediate1[intermediate2.index(i)]
                head1.append(i)
            # 子代1尾
#             print("tail1")
            for i in a1_copy.data[random_2:]:
                while i in intermediate2:
                    i = intermediate1[intermediate2.index(i)]
                tail1.append(i)
            # 子代2头
#             print("head2")
            for i in a2_copy.data[:random_1]:
                while i in intermediate1:
                    i = intermediate2[intermediate1.index(i)]
                head2.append(i)
            # 子代2尾
#             print("tail2")
            for i in a2_copy.data[random_2:]:
                while i in intermediate1:
                    i = intermediate2[intermediate1.index(i)]
                tail2.append(i)
            
            result1 = head1 + intermediate2 + tail1
            result2 = head2 + intermediate1 + tail2
#             print("两个子类")
#             print(result1)
#             print(result2)

            result1 =  Node(result1,self.fitness(result1))
            result2 =  Node(result2,self.fitness(result2))

            return result1,result2
        
        male = choice_three[0:len(choice_three):2]
        female = choice_three[1:len(choice_three):2]
        if len(male) != len(female):
            minmale = min(len(male),len(female))
        else:
            minmale = len(male)
            
        for j in range(minmale):
            cross_rand = random.random()
            if cross_rand<self.pc:
                a1,a2 = change_main(male[j],female[j])
                changed_list.append(a1)
                changed_list.append(a2)
            else:
                changed_list.append(male[j])
                changed_list.append(female[j])
#         print(changed_list)    
        return changed_list
    
    def variation_change(self,cross_change_three):
        changed_variation=[]
        for j in range(len(cross_change_three)):
            variation_rand = random.random()
            if variation_rand<self.pm:
                random_1=random.randint(0,self.n-1)
                random_2=random.randint(0,self.n-1)
#                 print("变异之前的数据",cross_change_three[j].data)
                cross_change_three[j].data[random_1],cross_change_three[j].data[random_2]=cross_change_three[j].data[random_2],cross_change_three[j].data[random_1]
                changed_variation.append(cross_change_three[j])
#                 print("变异之后的数据",cross_change_three[j].data)
            else:
                changed_variation.append(cross_change_three[j])

        return changed_variation
    
    
    def __sort_threelist(self,arr):
        '''
        冒泡排序
        '''
        n = len(arr)
        for i in range(n):
            for j in range(0,n-i-1):
                if arr[j].fitness[1]>arr[j+1].fitness[1]:
                    arr[j],arr[j+1] = arr[j+1] ,arr[j]
        return arr

    
    def pro_go(self):
        #初始化种群
        N_group = self.init_list(self.N)
        for j in range(len(N_group)):
            N_group[j] = Node(N_group[j],self.fitness(N_group[j]))
        #开始迭代
        draw_x = []
        draw_y = [] 
        for num in range(self.T+1):
            #计算适应度
            for j in range(len(N_group)):
                N_group[j].fitness = self.fitness(N_group[j].data)
#                 print(N_group[j].fitness[0])
#                 print(N_group)

            if num>self.T:
                break
            
            
            #选择操作
            choiceList = [N_group[i].fitness[1] for i in range(len(N_group))]
#             print(choiceList)
            '''
            求出个体i被选中的概率
            '''
            choice = copy.deepcopy(choiceList)
            choice = [choiceList[j]/sum(choiceList) for j in range(len(choiceList))]
#             print(choice)
            sum_choice = []
            for p in range(len(choice)):
                if p == 0 :
                    sum_choice.append(choice[p])
                else:
                    sum_choice.append(choice[p] + sum_choice[p-1])
            
#             print(sum_choice)
#             print(rand_num)
            
            
            '''
            选数 原先列表有几行就要选出几个
            '''
            choice_three = []
            for i in range(self.N):
                rand_num = random.random()
                three_change_list = [rand_num-sum_choice[i] for i in range(len(sum_choice))]
                change_index = self.where_change(three_change_list)
                choice_three.append(N_group[change_index])
            '''
            交叉
            传入种群节点即可
            '''

            cross_choice_three = self.cross_change(choice_three)
#             print(choice_three)
            '''
            变异
            '''
            variation_three = self.variation_change(cross_choice_three)
            sort_group= N_group+variation_three
            
#             print("第"+str(num)+"次迭代",end=" ")
            N_group = self.__sort_threelist(sort_group)[0:self.N]
#             print(N_group[0].fitness[1],end='--')
#             print(N_group[-1].fitness[1])
#             print()
            draw_x.append(num)
            draw_y.append(N_group[0].fitness[1])
            random.shuffle(N_group)
            
        N_group = self.__sort_threelist(sort_group)[0:self.N]
#         for i in range(len(N_group)):
#             print(N_group[i].data)
            
        return N_group[i],draw_x,draw_y

    
    
    '''
    n为工件数
    m为机器数
    '''
testlist = [[8,6,200],[10,8,100],[12,10,60]]
for test in testlist:
    n = test[0]
    m = test[1]
    T = test[2]
    Ga1 = GA_FSP(n=n,machine=m,T=T)
    best1,draw_x,draw_y = Ga1.pro_go()
    final_data = best1.data
    plt.plot(draw_x, draw_y)
    plt.title('工件为{},机器数为{}'.format(n,m))
    plt.show()
  • 27
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小范今天学Java了嘛?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值