目录
一、遗传算法的原理
遗传算法(GA)是一类借鉴生物界的进化规律(适者生存,优胜劣汰遗传机制)演化而来的随机化搜索方法,是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
首先,算法会随机生成一定数量的个体,也可以人为地设定,这样可以提高初始种群的质量。在每一代中,所有的个体都被评价,并通过计算适应度函数得到一个适应度数值,依照适应度,对种群中的个体进行排序。然后,产生一个新的个体种群,也就是选择和繁殖,繁殖包括交配和突变。初始的数据便可以通过这样的选择原则组成一个相对优化的群体。之后,被选择的个体进入交配过程。经过这一系列的过程(选择、交配和突变),产生的新一代个体不同于初始的一代,并一代一代向增加整体适应度的方向发展。过程不断重复,每个个体被评价,计算出适应度,两个个体交配,然后突变,产生第三代......直到满足终止条件为止。
二、遗传算法的算法流程
(1)初始化规模为 N的群体,其中染色体每个基因的值采用随机数产生器生成并满足问题定义的范围。当前进化代数Generation=0。
(2)采用评估函数对群体中所有染色体进行评价,分别计算每个染色体的适应值,保存适应值最大的染色体Best。
(3)采用轮盘赌选择算法对群体的染色体进行选择操作,产生规模同样为N的种群。
(4)按照概率Pc 从种群中选择染色体进行交配。每两个进行交配的父代染色体,交换部分基因,产生两个新的子代染色体,子代染色体取代父代染色体进入新种群。没有进行交配的染色体直接复制进入新种群。
(5)按照概率 Pm对新种群中染色体的基因进行变异操作。发生变异的基因数值发生改变。变异后的染色体取代原有染色体进入新群体,未发生变异的染色体直接讲入新群体。
(6)变异后的 新群体取代原有群体,重新计算群体中各个染色体的适应值。倘若群体的最大适应值大于Best的适应值,则以该最大适应值对应的染色体替代Best。
(7)当 前进化代数Generation加1。如果Generation超过规定的最大进化代数或Best达到规定的误差要求,算法结束;否则返回第(3)步。
三、代码实现及分析
1、城市个数改变,随机生成城市的坐标
(种群个数、交叉概率、变异概率都不变)
(1)第一次随机生成:城市个数N=25,种群个数M=100,交叉概率Pc=0.8,变异概率Pmutation=0.05
(2)城市个数N=50,种群个数M=100,交叉概率Pc=0.8,变异概率Pmutation=0.05
(3)结论
城市个数M可以影响算法的搜索能力和运行效率。当M较大时,曲线收敛的越快越平缓,说明此时算法的搜索能力较好,收敛的较快,反之M越小算法搜索能力越差,运行效率越低。
把城市个数为50的数据保存下来进行以下的实验
2、种群个数改变
(城市个数和城市的坐标、交叉概率、变异概率都不变)
(1)种群个数M=200,城市个数N=50,交叉概率Pc=0.8,变异概率Pmutation=0.05
(2)种群个数M=500,城市个数N=50,交叉概率Pc=0.8,变异概率Pmutation=0.05
(3)结论
比较发现,群体规模N可以影响算法的搜索能力和运行效率。当N较大时,保证了群体的多样性,可以提高算法的搜索能力,但是由于群体中染色体的个数较多,增加了算法的计算量,降低了算法的运行效率。当N较小时,降低了计算量,同时也降低了每次进化中群体包含更多较好染色体的能力。
3、交叉概率改变
(城市个数和城市的坐标、种群个数、变异概率都不变)
(1)交叉概率Pc=0.1,城市个数N=50,种群个数M=100,变异概率Pmutation=0.05
(2)交叉概率Pc=0.5,城市个数N=50,种群个数M=100,变异概率Pmutation=0.05
(3)结论
交配概率Pc决定了进化过程种群参加交配的染色体平均数目Pc*N,交叉概率越大进化过程中参加交配的染色体平均数目越多,Pc=0.5的比Pc=0.1的算法搜索能力和运行效率都比较好,Pc的取值一般为0.4-0.99比较好。
4、变异概率改变
(城市个数和城市的坐标、种群个数、交叉概率都不变)
(1)变异概率Pmutation=0.5,城市个数N=50,种群个数M=100,交叉概率Pc=0.8
(2)变异概率Pmutation=0.9,城市个数N=50,种群个数M=100,交叉概率Pc=0.8
(3)结论
由图可知变异概率过大的时候算法无法收敛,不存在最优解。变异概率Pmutation决定了进化过程种群参加交配的染色体平均数目。Pm的值不宜过大,因为变异对已找到的较优解具有一定的破坏作用,如果Pm的值太大,可能会导致算法目前所处的较好的搜索状态倒退回原来较差的情况。Pm的取值一般为0.001~0.1,也可采用自适应的方法调整算法运行过程中的Pm值。
四、代码附录
main.m
%main
clear;
clc;
%%%%%%%%%%%%%%%输入参数%%%%%%%%
%N=50; %%城市的个数
M=100; %%种群的个数
ITER=2000; %%迭代次数
%C_old=C;
m=2; %%适应值归一化淘汰加速指数
Pc=0.8; %%交叉概率
Pmutation=0.9; %%变异概率
% 导入数据
load citys_data.mat
% 计算城市间相互距离
fprintf('Computing Distance Matrix... \n');
N = size(citys,1);
%%生成城市的坐标
pos=randn(N,2);
%%生成城市之间距离矩阵
D=zeros(N,N);
for i=1:N
for j=i+1:N
dis=(pos(i,1)-pos(j,1)).^2+(pos(i,2)-pos(j,2)).^2;
D(i,j)=dis^(0.5);
D(j,i)=D(i,j);
end
end
%%生成初始群体
popm=zeros(M,N);
for i=1:M
popm(i,:)=randperm(N);%随机排列,比如[2 4 5 6 1 3]
end
%%随机选择一个种群
R=popm(1,:);
figure(1);
scatter(pos(:,1),pos(:,2),'rx');%画出所有城市坐标
axis([-3 3 -3 3]);
figure(2);
plot_route(pos,R); %%画出初始种群对应各城市之间的连线
axis([-3 3 -3 3]);
%%初始化种群及其适应函数
fitness=zeros(M,1);
len=zeros(M,1);
for i=1:M%计算每个染色体对应的总长度
len(i,1)=myLength(D,popm(i,:));
end
maxlen=max(len);%最大回路
minlen=min(len);%最小回路
fitness=fit(len,m,maxlen,minlen);
rr=find(len==minlen);%找到最小值的下标,赋值为rr
R=popm(rr(1,1),:);%提取该染色体,赋值为R
for i=1:N
fprintf('%d ',R(i));%把R顺序打印出来
end
fprintf('\n');
fitness=fitness/sum(fitness);
distance_min=zeros(ITER+1,1); %%各次迭代的最小的种群的路径总长
nn=M;
iter=0;
while iter<=ITER
fprintf('迭代第%d次\n',iter);
%%选择操作
p=fitness./sum(fitness);
q=cumsum(p);%累加
for i=1:(M-1)
len_1(i,1)=myLength(D,popm(i,:));
r=rand;
tmp=find(r<=q);
popm_sel(i,:)=popm(tmp(1),:);
end
[fmax,indmax]=max(fitness);%求当代最佳个体
popm_sel(M,:)=popm(indmax,:);
%%交叉操作
nnper=randperm(M);
% A=popm_sel(nnper(1),:);
% B=popm_sel(nnper(2),:);
%%
for i=1:M*Pc*0.5
A=popm_sel(nnper(i),:);
B=popm_sel(nnper(i+1),:);
[A,B]=cross(A,B);
% popm_sel(nnper(1),:)=A;
% popm_sel(nnper(2),:)=B;
popm_sel(nnper(i),:)=A;
popm_sel(nnper(i+1),:)=B;
end
%%变异操作
for i=1:M
pick=rand;
while pick==0
pick=rand;
end
if pick<=Pmutation
popm_sel(i,:)=Mutation(popm_sel(i,:));
end
end
%%求适应度函数
NN=size(popm_sel,1);
len=zeros(NN,1);
for i=1:NN
len(i,1)=myLength(D,popm_sel(i,:));
end
maxlen=max(len);
minlen=min(len);
distance_min(iter+1,1)=minlen;
fitness=fit(len,m,maxlen,minlen);
rr=find(len==minlen);
fprintf('minlen=%d\n',minlen);
R=popm_sel(rr(1,1),:);
for i=1:N
fprintf('%d ',R(i));
end
fprintf('\n');
popm=[];
popm=popm_sel;
iter=iter+1;
%pause(1);
end
%end of while
figure(3)
plot_route(pos,R);
axis([-3 3 -3 3]);
figure(4)
plot(distance_min);
cross.m
%交叉操作函数 cross.m
function [A,B]=cross(A,B)
L=length(A);
if L<10
W=L;
elseif ((L/10)-floor(L/10))>=rand&&L>10
W=ceil(L/10)+8;
else
W=floor(L/10)+8;
end
%%W为需要交叉的位数
p=unidrnd(L-W+1);%随机产生一个交叉位置
%fprintf('p=%d ',p);%交叉位置
for i=1:W
x=find(A==B(1,p+i-1));
y=find(B==A(1,p+i-1));
[A(1,p+i-1),B(1,p+i-1)]=exchange(A(1,p+i-1),B(1,p+i-1));
[A(1,x),B(1,y)]=exchange(A(1,x),B(1,y));
end
end
exchange.m
%对调函数 exchange.m
function [x,y]=exchange(x,y)
temp=x;
x=y;
y=temp;
end
fit.m
%适应度函数fit.m,每次迭代都要计算每个染色体在本种群内部的优先级别,类似归一化参数。越大约好!
function fitness=fit(len,m,maxlen,minlen)
fitness=len;
for i=1:length(len)
fitness(i,1)=(1-(len(i,1)-minlen)/(maxlen-minlen+0.0001)).^m;
end
Mutation.m
%变异函数 Mutation.m
function a=Mutation(A)
index1=0;index2=0;
nnper=randperm(size(A,2));
index1=nnper(1);
index2=nnper(2);
%fprintf('index1=%d ',index1);
%fprintf('index2=%d ',index2);
temp=0;
temp=A(index1);
A(index1)=A(index2);
A(index2)=temp;
a=A;
end
plot_route.m
%连点画图函数 plot_route.m
function plot_route(a,R)
scatter(a(:,1),a(:,2),'rx');
hold on;
plot([a(R(1),1),a(R(length(R)),1)],[a(R(1),2),a(R(length(R)),2)]);
hold on;
for i=2:length(R)
x0=a(R(i-1),1);
y0=a(R(i-1),2);
x1=a(R(i),1);
y1=a(R(i),2);
xx=[x0,x1];
yy=[y0,y1];
plot(xx,yy);
hold on;
end
end