【转载】遗传算法及其在作业车间调度问题中的实现

遗传算法及其在作业车间调度问题中的实现

目录

  • 前言
  • 一、遗传算法是什么?
  • 二、使用步骤
  • 总结

  • 前言

    简介:
    遗传算法被发明几十年来,应用已经较为成熟,广泛应用于各类复杂优化问题,但其中一个缺点是实现较为困难,本文以作业车间调度问题为研究对象,在matlab中实现了遗传算法。


    一、遗传算法是什么?

    遗传算法(Genetic Algorithms,简称GA)是一种借鉴生物界自然选择和自然遗传机制的高度并行、随机、自适应搜索算法。它是模仿自然界生物进化过程中“物竞天择,适者生存”的原理而进行的一种多参数、多群体同时优化的方法。经过20多年的发展,遗传算法已经在数据挖掘、生产调度、机器学习、图象处理等领域得到成功的应用,并显示出良好的性能。

    二、使用步骤

    1.流程示意

    基本的遗传算法的计算过程是一个迭代过程,基本步骤如下:
    步骤1:选择编码策略,将实际问题的参数集合X表示位串。
    步骤2:根据实际问题的优化目标,定义适应度值函数。
    步骤3:确定遗传策略,包括群体大小n、选择、交叉、变异操作的方法,确定交叉概率Pc,变异概率Pm等参数。
    步骤4:产生初始群体P。
    步骤5:计算群体中所有个体的适应度值。
    步骤6:按照遗传策略,对群体中的每一个个体选择、复制、交叉、变异操作,形成下一代群体。
    步骤6:判断群体性能是否满足终止条件,不满足则返回第6步,进行下一次迭代;满足条件则完成计算,输出结果。

    遗传算法基本流程

    2. 编码方案

    (1)编码
    设某一参数取值范围是[Umin,Umax],用长度为L的二进制编码符号串表示该参数。

    编码代表数值
    000…000=0Umin
    000…001=1Umin +σ
    000…010=2Umin +2σ
    …………
    111…111=2^L-1Umax

    编码精度如下:
    精度
    (2)解码方法
    解码
    例:设-3.0≤x≤12.1,精度要求1/1000 ,问:最少需要多少位二进制,才能达到编码精度?对求解的结果如何解码?
    示例

    代码如下(示例):

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    import warnings
    warnings.filterwarnings('ignore')
    import  ssl
    ssl._create_default_https_context = ssl._create_unverified_context

    3. 案例实现

    工件1包含4道工序(101,102,103,104),工件2包含3道工序(201,202,203,204),工件3包含5道工序(301,302,303,304,305),其中每一道工序与每台加工设备对应(如下图所示),每个工件只需完成自身所有工序即视为完成加工,所有工件第一道工序加工开始时间到加工结束时间视为整个调度的完成时间。
    三工件加工
    工序与设备的对应关系
    (1)程序设计
    ①数据处理:将案例中的数据输入矩阵中。
    数据整理
    其中Job1矩阵中第一行[11 1 6]代表工件1的第一道工序,此道工序加工位置为设备1,加工时间为6,矩阵其他位置同理。
    ②编码:本文采用机器序列和基于位置“列表” 相结合的组合编码方法 , 染色体被编码为可重复的自然数序列。其中, 染色体以工件为单位进行工件各工序的排列, 每个工件的工序排列顺序满足紧前关系。各位置 "列表 "的编码是各工序所使用的设备编号。染色体的长度为所有工件工序数量的总和。
    对于 n个工件 m台机器的分布式车间作业计划问题 ,假定每个工件的工序数均为k,一个染色体包含Σki个基因。一个染色体的位置“列表”为[ C11 ,C12 , …, C1k1 , C21 , C22 ,…, C2k2 ,…, Cn1 ,Cn2,…,Cnkn ] ,其中各位置 Cij表示工件 i第 j道工序所使用的机器编号。
    如排序[1 2 3 2 1 3 2 3 1 1 3 3]对应工序为:101 201 301 202 102 302 203 303 103 104 304 305。
    初始化种群:
    P1:[1,2,2,3,3,1,2,3,1,3,1,3]
    P2:[3,1,2,3,3,2,2,1,1,3,1,3]
    P3:[2,2,2,3,1,1,1,3,1,3,3,3]
    P4:[1,3,2,3,2,1,1,3,1,3,1,3]
    P5:[2,3,3,3,3,1,2,3,2,1,1,1]
    P6:[2,2,1,3,3,3,3,3,1,2,1,1]
    ………
    ………
    ③参数初始化,交叉概率,变异概率等;
    ④计算父代适应度,找出最优个体并保留;
    ⑤进行选择、交叉和变异,生成子代。交叉和变异的改进:
    1)交叉
    ->P1:[1,2,2,3,3,1,2,3,1,3,1,3]
    P2:[3,1,2,3,3,2,2,1,1,3,1,3]
    P3:[2,2,2,3,1,1,1,3,1,3,3,3]
    P4:[1,3,2,3,2,1,1,3,1,3,1,3]
    P5:[2,3,3,3,3,1,2,3,2,1,1,1]
    ->P6:[2,2,1,3,3,3,3,3,1,2,1,1]
    若选择交叉染色体为P1,P6,交叉点为8,则:
    P1:[1,2,2,3,3,1,2,3,1,3,1,3] -> O1:[1,2,2,3,3,1,2,3,1,2,1,1]
    P6:[2,2,1,3,3,3,3,3,1,2,1,1] -> O6:[2,2,1,3,3,3,3,3,1,3,1,3]
    发现P1与P6均产生了多余工序,因此上述交叉方式需要改进。
    改进:随机选择某一工件编号,分别在两条染色体中,保留该编号的位置,将除该编号以外的片段按先后排序依次交换复制到剩余的基因位。
    P1:[1,2,2,3,3,1,2,3,1,3,1,3] -> O1:[1,2,2,3,3,3,2,3,3,1,1,1]
    P6:[2,2,1,3,3,3,3,3,1,2,1,1] -> O6:[2,2,1,3,3,1,3,1,3,2,1,3]
    2)变异
    P1:[1,2,2,3,3,1,2,3,1,3,1,3] -> P1:[1,2,2,1,3,1,2,3,1,3,1,3]
    以上变异方式导致染色体第4位变异为1,则工件1多了一道工序,而工件3少了一道工序。
    改进:随机选择染色体,在染色体中随机选择两个基因位,首先判断这两个基因位上的值是否相等,如果相等,则随机重选,直到选到值不相等的两个基因位,然后将两个基因位上的值互换,得到变异后的新染色体。
    P1:[1,2,2,3,3,1,2,3,1,3,1,3] -> O1:[1,3,2,3,3,1,2,2,1,3,1,3]
    ⑥ 计算子代个体适应度;
    ⑦ 找到子代最优个体;
    ⑧ 比较父代最优个体和子代最优个体的适应度,当父代最优个体适应度大于子代最优个体适应度时,替换子代最优个体;
    ⑨ 检验终止条件,当种群中大部分个体,如95%的个体相同,则认为这些相同个体就是最优解,可以输出进行解码;否则转至③。
    运行程序得到以下结果:
    运行结果
    对应甘特图
    在迭代次数为1000时,最短时间46,最优排序是 301 302 101 303 102 103 201 304 104 202 203 305。

    4. 代码实现

    clear
    clc
    close all
    gongjian_1=[11 1 6;12 2 5;13 3 8;14 4 16];
    gongjian_2=[21 1 9;22 2 16;23 3 10];
    gongjian_3=[31 1 5;32 2 9;33 3 7;34 4 4;35 5 12];
    %--------------------------种群初始化------------------------------------%
    seed=[1 1 1 1 2 2 2 3 3 3 3 3 ];%种子
    seed_length=length(seed);
    Chrom=zeros(10,seed_length);%预定义零矩阵,用于存数20个染色体
     NIND=size(Chrom,1);%种群大小10
     WNumber=size(Chrom,2);%染色体长度为12
     XOVR=0.2;%交叉概率=0.2
     MUTR=0.03;
    for i=1:NIND
        Chrom(i,:)=seed(randperm(numel(seed)));%生成染色体并赋到矩阵各行
    end 
     time_opt=zeros(NIND,1000);% 预定义20*100的矩阵存储100代种群中的各个个体时间
     generations=1000;
     %% 迭代开始
    for generation=1:generations
    
      %% 以下进行解码、计算适应度、选择————————————
      %% 解码求适应度 计算最短时间
    P=zeros(WNumber,1);%工序
    M=zeros(WNumber,1);%机床
    T=zeros(WNumber,1);%时间
    t_bz=zeros(3,5);
    T_qunti=zeros(NIND,1);
    %该函数用来1 :计算种群中各个染色体的时间,最终结果为20*1的矩阵,代表各个染色体对应的时间
    %          2 :通过选择生成新的种群,其中,最优个体直接保留
    %  将该时间放到20行100矩阵中,每一列代表一代中的20个个体的时间
    for i=1:NIND         %% 群体中的20个个体分别求时间   
         a=1; b=1;c=1;%定义a b c 用于确定工序矩阵、机床矩阵以及时间矩阵
         t1=0;t2=0;t3=0;t4=0;t5=0;%初始化机床1 机床2 机床3 的值
        for j=1:WNumber%WNumber=9,所有工序数
            if Chrom(i,j)==1%在第一个工件
                P(j)=10+a;%加工序号
    %             if a==4
    %                a=3;
    %             end
                M(j)=gongjian_1(a,2);%加工位置
                T(j)=gongjian_1(a,3);%加工时间
                a=a+1;%下一道工序
            elseif Chrom(i,j)==2%第二个工件
                    P(j)=20+b;%工序号
    %                   if b==4
    %                      b=3;
    %                    end
                    M(j)=gongjian_2(b,2);%位置
                    T(j)=gongjian_2(b,3);%时间
                    b=b+1;%下一道工序
            elseif Chrom(i,j)==3
                     P(j)=30+c;
    %                    if c==4
    %                       c=3;
    %                     end
                     M(j)=gongjian_3(c,2);
                     T(j)=gongjian_3(c,3);
                     c=c+1;
            end
        end  %解码完成 求出P M T
        %% 以下计算每个个体的时间,即目标值(适应度值)计算
       
        for k=1:WNumber
            if M(k)==1%第一个机床
                x=floor(P(k)/10);% x为工件号
                y=rem(P(k),10);% y为工序号
                if y==1%显然,如果该工序为第一个工序,则M1机床时间t1直接为当前时间加上该工序的时间
                    t1=t1+T(k);%t1表示在设备1上加工总时间
                    t_bz(x,y)=t1;%第x工件的第y道工序结束时的时间。第32行,在程序初始化过程中已经预定义t_bz=zeros(3,3);
                    %t_bz即为3*3的零矩阵,用于存储各个工序在机床上对应的机床时间,行数代表工件号,列数代表工序
                else %如果该工序不是第一个工序:temp1为一个中间变量,元素为该机床当前的时间t1、以及该工件上一工序所在机床的对应机床时间
                    temp1=[ t1 t_bz(x,y-1)];
                    t1=max(temp1)+T(k);%选择两者之中的较大值,即为该工件在1机床上(2 3机床同理)上对应的机床时间
                    t_bz(x,y)=t1;%将该时间赋值到时间矩阵
                end
            elseif M(k)==2
                  x=floor(P(k)/10);% x为工件号
                  y=rem(P(k),10); % y为工序号
                if y==1   % 如果为该工件的第一个工序,则该机床时间为其前一时刻时间+该道工序的时间
                    t2=t2+T(k);
                    t_bz(x,y)=t2;
                else    %如果该工序不是第一道工序
                     temp2=[ t2 t_bz(x,y-1)];
                     t2=max(temp2)+T(k);
                     t_bz(x,y)=t2; 
                end
            elseif M(k)==3
                  x=floor(P(k)/10);% x为工件号
                  y=rem(P(k),10); % y为工序号
                if y==1
                    t3=t3+T(k);
                    t_bz(x,y)=t3;
                else 
                    temp3=[ t3 t_bz(x,y-1)];
                    t3=max(temp3)+T(k);
                    t_bz(x,y)=t3; 
                end
            elseif M(k)==4
                  x=floor(P(k)/10);% x为工件号
                  y=rem(P(k),10); % y为工序号
                if y==1
                    t4=t4+T(k);
                    t_bz(x,y)=t4;
                else 
                    temp3=[ t4 t_bz(x,y-1)];
                    t4=max(temp3)+T(k);
                    t_bz(x,y)=t4; 
                end
           elseif M(k)==5
                  x=floor(P(k)/10);% x为工件号
                  y=rem(P(k),10); % y为工序号
                if y==1
                    t5=t5+T(k);
                    t_bz(x,y)=t5;
                else 
                    temp3=[ t5 t_bz(x,y-1)];
                    t5=max(temp3)+T(k);
                    t_bz(x,y)=t5; 
                end
            end    
        end
           temp=[t1 t2 t3 t4 t5];%很显然,该染色体对应的加工时间就是三个机床时间的最大值
           t=max(temp);      %得出该染色体对应的加工时间
           T_qunti(i,1)=t;   %将该染色体对应的时间赋值给时间矩阵,种群中20个染色体的时间就欧了
    time_add=sum(T_qunti); %计算出种群中各个染色体总时间和
    time_indiv=T_qunti/time_add; %计算每一个个体与总时间的比值
    min_time=min(T_qunti);%该代种群中时间最短的个体时间
          
    end %截至该句,计算出每个染色体的时间
    
    
    %% 以下执行*选择*操作 ---.>稳态复制的方法
    next_pop=Chrom;%初始化群体
    best_flag=0;
      for tt=1:NIND
        if T_qunti(tt,1)==min_time %如果该个体为截止到当前代最好的个体,则保留
           best_flag=best_flag+1;
           next_pop(best_flag,:)=Chrom(tt,:);
           time_indiv(tt,:)=2;% 如果该个体为该代中最优,则将该个体直接复制到下一代,然后将time_indiv赋值为2,以避开交叉和变异
        end
      end
    
    flag=best_flag;
     for z=1:NIND %下一代群体的前flag个个体直接取上一带的最佳个体,剩下的个体用随即方法选择
            if flag<NIND
                sj=rand;
                if  time_indiv(z)<sj %如果随机数大于第i个染色体的概率,认为该染色体较好,保留
                    next_pop(flag+1,:)=Chrom(z,:);
                    flag=flag+1;
                end
            end
     end
    Chrom=next_pop;
    %% % %--------------------------------------------------------------------------
    % % % %截止到该行语句 实现了选择、计算适应度、解码,一下进行交叉和变异
    % % % %--------------------------------------------------------------------------
    %% % % % % % % % 交叉
    SelNum=randperm(NIND);%1-NIND的随机数矩阵,NIND是种群大小
     %交叉个体组个数
    %  Num=NIND/2;
    %  Num=2*fix(Num);
    ChromNew=Chrom; 
     for mm=(NIND-best_flag):NIND-1%选择非最优染色体进行交叉
         rd=rand;
         if XOVR>rd %交叉概率=0.2
             
                %取交换的个体;
                if best_flag==NIND% 如果该种群最优个体达到最大,跳出交叉
                    break
                end
                S1=Chrom(SelNum(mm),:);
                S2=Chrom(SelNum(mm+1),:);%mm+1开始的染色体
                A=S1;%A是Chrome中第mm个染色体
                B=S2;%AB代表了两个染色体
                 %交叉点--postion
                n=fix(WNumber*rand);%取较小值
                C=[A(1:n) B(n+1:WNumber)];%染色体长度为WNumber
                D=[B(1:n) A(n+1:WNumber)];%交叉后的初步染色体
    
                c1=sum(C(n+1:WNumber)==1);%工件1
                d1=sum(D(n+1:WNumber)==1);%
                c2=sum(C(n+1:WNumber)==2);%工件2
                d2=sum(D(n+1:WNumber)==2);
                c3=sum(C(n+1:WNumber)==3);%工件3
                d3=sum(D(n+1:WNumber)==3);
                
                E=[ones(1,4-c1) 2*ones(1,3-c2) 3*ones(1,5-c3) C(n+1:WNumber)];%重排C
                F=[ones(1,4-d1) 2*ones(1,3-d2) 3*ones(1,5-d3) D(n+1:WNumber)];%重排D
                ex1=E(1,1:(WNumber-c1-c2-c3));%取出交叉位及其之前的元素放到ex1和ex2中
                ex2=F(1,1:(WNumber-c1-c2-c3));
                ex1=ex1(randperm(numel(ex1)));
                ex2=ex2(randperm(numel(ex2)));
                E=[ex1 E(n+1:WNumber)];
                F=[ex2 F(n+1:WNumber)];
    %            %放入新群
                 ChromNew(SelNum(mm),:)=E;
                 ChromNew(SelNum(mm+1),:)=F;
    %              Chrom(SelNum(mm),:)=ChromNew(SelNum(mm),:);
    %              Chrom(SelNum(mm+1),:)=ChromNew(SelNum(mm+1),:);
    %             
         end
     end% % %截止到该行语句 实现了交叉,以下进行变异操作
    
    %% %--------------------------------------------------------------------------
    % % %截止到该行语句 实现了交叉,以下进行变异操作
    % % %--------------------------------------------------------------------------
    % %变异
    ChromNew=Chrom;
    
    for i=best_flag+1:NIND  %是否变异
        mt=rand;
      if MUTR>mt     
         Pos1=unidrnd(WNumber);%变异位置
         Pos2=unidrnd(WNumber);
    
     %变异位置不相同
      while Pos1==Pos2      
            Pos2=unidrnd(WNumber);
      end 
     
     %取数据
       S=Chrom(i,:);
        
       %交换
       temp=S(Pos1);
       S(Pos1)=S(Pos2);
       S(Pos2)=temp;
      
       ChromNew(i,:)=S;
     end
    end
    Chrom=ChromNew;
    
    time_opt(:,generation)=T_qunti;%时间矩阵,用来存储N代种群中各个染色体的时间
    
    % % %--------------------------------------------------------------------------
    % % %截止到该行语句 实现变异
    %% %--------------------------------------------------------------------------
    pp=T_qunti==min_time;%pp记录T_qunti中与最小时间个体相同的个体数量(为20*1的矩阵)
    min_Time(generation)=min_time;
    pingjun(generation)=mean(T_qunti);
    zonghe(generation)=sum(pp);
    %以下进行该代结果的输出
    end
    
    
    

    总结

    说明:
    串行是调度问题中较为简单的一种方式,本文中的调度问题很大程度上是一种较为普遍的模式,其中代码实现部分省略了绘图部分,希望大家自己实现。

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
柔性作业车间调度问题是指在一个具有多台机器和多种任务的车间,如何合理地安排任务的执行顺序和机器的使用,以最大化生产效率和降低生产成本。基于遗传算法的柔性作业车间调度问题解决方案,是一种优化算法,通过模拟生物进化过程,找到最优的调度方案。 遗传算法是一种优化算法,模拟自然界的进化过程,通过不断的交叉、变异、选择等操作,逐渐优化种群的个体,找到最优解。在柔性作业车间调度问题遗传算法可以通过将每个调度方案转化为一个染色体,每个染色体包含了所有任务的执行顺序和机器的使用情况。通过不断地进化操作,找到最优的调度方案,从而最大化生产效率和降低生产成本。 基于遗传算法的柔性作业车间调度问题解决方案需要考虑以下几个方面: 1. 确定适应度函数:适应度函数用于评估每个染色体的优劣程度,一般来说,适应度函数越高,表示染色体的质量越好。在柔性作业车间调度问题,适应度函数可以考虑任务的完成时间、机器的利用率等因素。 2. 交叉操作:交叉操作用于产生新的染色体,一般来说,是将两个父代染色体的基因组合在一起,形成新的染色体。在柔性作业车间调度问题,交叉操作可以将两个染色体的任务执行顺序进行交换,从而产生新的调度方案。 3. 变异操作:变异操作用于产生新的基因,一般来说,是在某个基因上进行随机变化。在柔性作业车间调度问题,变异操作可以将某个任务的执行顺序进行变化,从而产生新的调度方案。 4. 选择操作:选择操作用于选择优秀的染色体,一般来说,是根据适应度函数来进行选择。在柔性作业车间调度问题,选择操作可以选择适应度高的染色体,作为下一代染色体的父代。 基于遗传算法的柔性作业车间调度问题解决方案,可以通过不断地进化操作,找到最优的调度方案,从而最大化生产效率和降低生产成本。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

昔时扬尘处

你的鼓励会让技术更加具有价值!

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

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

打赏作者

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

抵扣说明:

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

余额充值