遗传算法
前言
简介:
遗传算法被发明几十年来,应用已经较为成熟,广泛应用于各类复杂优化问题,但其中一个缺点是实现较为困难,本文以作业车间调度问题为研究对象,在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=0 | Umin |
000…001=1 | Umin +σ |
000…010=2 | Umin +2σ |
…… | …… |
111…111=2^L-1 | Umax |
编码精度如下:
(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