概念
是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型。
本质:物竞天择,适者生存。
下面我们从生物学的角度来分析一下:
假如有一只猫和一种花有两种性状,一种是深色的,一种是浅色的,而猫只喜欢吃深色的花。
那么在经过很多代后,深色的花由于经常被猫吃,则花会更多的变为浅色。
<1>在遗传算法中,染色体对应的是数据或数组。
<2>串上各个位置对应基因的取值。
<3>基因组成的串就是染色体,或者称为基因型个体。
<4>一定数量的个体组成了群体。
<5>个体对环境的适应程度叫适应度。
算法步骤
核心操作:
<1>选择操作:从旧个体中以一定概率选择优良个体组成新的种群,以繁殖得到下一代。
通过图可以看出适应度越大,占的扇面就越大,遗传到下一代的概率也就越大。
<2>交叉操作:从种群中随机选择两个个体,通过两个染色体的交换组合,把父串的优秀特征遗传给子串,从而产生新的优秀个体。
<3>变异操作:从种群中随机选择一个个体,选择个体中的一点进行变异以产生更优秀的个体。
代码
主函数
%% 清空环境
clc
clear
%% 遗传算法参数
maxgen=50; %进化代数
sizepop=100; %种群规模
pcross=0.6; %交叉概率
pmutation=0.01; %变异概率
lenchrom=5; %变量字串长度
bound=[0 0.9*pi;0 0.9*pi;0 0.9*pi;0 0.9*pi;0 0.9*pi]; %变量范围
%% 个体初始化
individuals=struct('fitness',zeros(1,sizepop), 'chrom',[]); %种群结构体
% avgfitness=[]; %种群平均适应度
% bestfitness=[]; %种群最佳适应度
% bestchrom=[]; %适应度最好染色体
% 初始化种群
for i=1:sizepop
individuals.chrom(i,:)=Code(lenchrom,bound); %随机产生个体
x=individuals.chrom(i,:);
individuals.fitness(i)=fun(x); %个体适应度
end
%找最好的染色体
[bestfitness,bestindex]=min(individuals.fitness);
bestchrom=individuals.chrom(bestindex,:); %最好的染色体
avgfitness=sum(individuals.fitness)/sizepop; %染色体的平均适应度
% 记录每一代进化中最好的适应度和平均适应度
trace=[];
%% 进化开始
for i=1:maxgen
% 选择操作
individuals=Select(individuals,sizepop);
% 交叉操作
individuals.chrom=Cross(pcross,lenchrom,individuals.chrom,sizepop,bound);
% 变异操作
individuals.chrom=Mutation(pmutation,lenchrom,individuals.chrom,sizepop,[i maxgen],bound);
% 计算适应度
for j=1:sizepop
x=individuals.chrom(j,:);
individuals.fitness(j)=fun(x);
end
%找到最小和最大适应度的染色体及它们在种群中的位置
[newbestfitness,newbestindex]=min(individuals.fitness);
[worestfitness,worestindex]=max(individuals.fitness);
% 代替上一次进化中最好的染色体
if bestfitness>newbestfitness
bestfitness=newbestfitness;
bestchrom=individuals.chrom(newbestindex,:);
end
individuals.chrom(worestindex,:)=bestchrom;
individuals.fitness(worestindex)=bestfitness;
avgfitness=sum(individuals.fitness)/sizepop;
trace=[trace;avgfitness bestfitness]; %记录每一代进化中最好的适应度和平均适应度
end
%进化结束
%% 结果显示
[r,~]=size(trace);
figure
plot(1:r,trace(:,1),'r-',1:r,trace(:,2),'b--');
title(['函数值曲线 ' '终止代数=' num2str(maxgen)],'fontsize',12);
xlabel('进化代数','fontsize',12);ylabel('函数值','fontsize',12);
legend('各代平均值','各代最佳值');
grid on
Code函数(用来将变量编码成染色体)
function ret=Code(lenchrom,bound)
%本函数将变量编码成染色体,用于随机初始化一个种群
% lenchrom input : 染色体长度
% bound input : 变量的取值范围
% ret output: 染色体的编码值
flag=0;
while flag==0
pick=rand(1,lenchrom);
ret=bound(:,1)'+(bound(:,2)-bound(:,1))'.*pick; %线性插值
flag=test(bound,ret); %检验染色体的可行性
end
fun函数(所求问题的表达式)
function y = fun(x)
y=-5*sin(x(1))*sin(x(2))*sin(x(3))*sin(x(4))*sin(x(5))-sin(5*x(1))*sin(5*x(2))*sin(5*x(3))*sin(5*x(4))*sin(5*x(5))+8;
test函数(测试范围)
function flag=test(bound,code)
% lenchrom input : 染色体长度
% bound input : 变量的取值范围
% code output: 染色体的编码值
flag=1;
[n,m]=size(code);
for i=1:n
if code(i)<bound(i,1) || code(i)>bound(i,2)
flag=0;
end
end
Select函数(选择操作)
function ret=Select(individuals,sizepop)
% 本函数对每一代种群中的染色体进行选择,以进行后面的交叉和变异
% individuals input : 种群信息
% sizepop input : 种群规模
% opts input : 选择方法的选择
% ret output : 经过选择后的种群
individuals.fitness= 1./(individuals.fitness);
sumfitness=sum(individuals.fitness);
sumf=individuals.fitness./sumfitness;
index=[];
for i=1:sizepop %转sizepop次轮盘
pick=rand;
while pick==0
pick=rand;
end
for j=1:sizepop
pick=pick-sumf(j);
if pick<0
index=[index j];
break; %寻找落入的区间,此次转轮盘选中了染色体i,注意:在转sizepop次轮盘的过程中,有可能会重复选择某些染色体
end
end
end
individuals.chrom=individuals.chrom(index,:);
individuals.fitness=individuals.fitness(index);
ret=individuals;
Cross函数(交叉操作)
function ret=Cross(pcross,lenchrom,chrom,sizepop,bound)
%本函数完成交叉操作
% pcorss input : 交叉概率
% lenchrom input : 染色体的长度
% chrom input : 染色体群
% sizepop input : 种群规模
% ret output : 交叉后的染色体
for i=1:sizepop
% 随机选择两个染色体进行交叉
index=randi(sizepop,2,1);
% 交叉概率决定是否进行交叉
pick=rand;
while pick==0
pick=rand;
end
if pick>pcross
flag=0;
while flag==0
% 随机选择交叉位置
pos=randi(lenchrom); %随机选择进行交叉的位置,即选择第几个变量进行交叉,注意:两个染色体交叉的位置相同
pick=rand; %交叉开始
v1=chrom(index(1),pos);
v2=chrom(index(2),pos);
chrom(index(1),pos)=pick*v2+(1-pick)*v1;
chrom(index(2),pos)=pick*v1+(1-pick)*v2; %交叉结束
flag1=test(bound,chrom(index(1),:)); %检验染色体1的可行性
flag2=test(bound,chrom(index(2),:)); %检验染色体2的可行性
if flag1*flag2==0
flag=0;
else flag=1;
end %如果两个染色体不是都可行,则重新交叉
end
end
end
ret=chrom;
Mutation(变异操作)
function ret=Mutation(pmutation,lenchrom,chrom,sizepop,pop,bound)
% 本函数完成变异操作
% pmutation input : 变异概率
% lenchrom input : 染色体长度
% chrom input : 染色体群
% sizepop input : 种群规模
% pop input : 当前种群的进化代数和最大的进化代数信息
% ret output : 变异后的染色体
for i=1:sizepop
% 随机选择一个染色体进行变异
index=randi(sizepop);
% 变异概率决定该轮循环是否进行变异
pick=rand;
if pick>pmutation
flag=0;
while flag==0
% 变异位置
pos=randi(lenchrom); %随机选择了染色体变异的位置,即选择了第pos个变量进行变异
v=chrom(index,pos);
v1=v-bound(pos,1);
v2=bound(pos,2)-v;
pick=rand; %变异开始
if pick>0.5
delta=v2*(1-pick^((1-pop(1)/pop(2))^2));
chrom(index,pos)=v+delta;
else
delta=v1*(1-pick^((1-pop(1)/pop(2))^2));
chrom(index,pos)=v-delta;
end %变异结束
flag=test(bound,chrom(index,:)); %检验染色体的可行性
end
end
end
ret=chrom;