计算智能——基于遗传算法的TSP问题

1. 遗传算法

1.1 遗传算法简介

遗传算法是通过模拟自然界中生物的遗传进化过程,对优化问题的最优解进行搜索。算法维护一个代表问题潜在解的群体,对于群体的进化,算法引入了类似自然进化中选择、交配以及变异等算子。
遗传算法搜索全局最优解的过程是一个不断迭代的过程(每一次迭代相当于生物进化中的一次循环),直到满足算法的终止条件为止。

1.2 遗传算法原理

在利用遗传算法求解问题时,问题的每一个可能解都被编码成一个“染色体”,即个体,若干个个体构成了群体(所有可能解)。在遗传算法开始时,总是随机的产生一些个体(即初始解),根据预定的目标函数对每一个个体进行评估,给出一个适应度值,基于此适应度值,选择一些个体用来产生下一代,选择操作体现了“适者生存”的原理,“好”的个体被用来产生下一代,“坏”的个体则被淘汰,然后选择出来的个体,经过交叉和变异算子进行再组合生成新的一代,这一代的个体由于继承了上一代的一些优良性状,因而在性能上要优于上一代,这样逐步朝着最优解的方向进化。

遗传算法的基本思想是从初始种群出发,采用优胜劣汰、 适者生存的自然法则选择个体,并通过杂交、变异来产生新 一代种群,如此逐代进化,直到满足目标为止。
遗传算法所 涉及到的基本概念主要有以下几个:
• 种群(Population):种群是指用遗传算法求解问题时, 初始给定的多个解的集合。遗传算法的求解过程是从这个子 集开始的。
•个体(Individual):个体是指种群中的单个元素,它通常 由一个用于描述其基本遗传结构的数据结构来表示。例如, 可以用0、1组成的长度为l的串来表示个体。
• 染色体(Chromosome):染色体是指对个体进行编码后 所得到的编码串。染色体中的每1位称为基因,染色体上由 若干个基因构成的一个有效信息段称为基因组。
• 适应度(Fitness)函数:适应度函数是一种用来对种群中 各个个体的环境适应性进行度量的函数。其函数值是遗传 算法实现优胜劣汰的主要依据 • 遗传操作(Genetic Operator):遗传操作是指作用于种 群而产生新的种群的操作。标准的遗传操作包括以下3种基本形式:
– 选择(Selection)
– 杂交(Crosssover)
– 变异(Mutation)

1.3 遗传算法的基本流程

遗传算法的基本步骤:

Step1. 初始化规模为N的群体,其中染色体每个基因的值采用随机数产生器生成并满足问题定义的范围。当前进化代数Generation=0。
Step2. 采用评估函数对群体中所有染色体进行评价,分别计算每个染色体的适应值,保存适应值最大的染色体Best。
Step3. 采用轮盘赌选择算法对群体的染色体进行选择操作,产生规模同样为N的种群。
Step4. 按照概率Pc从种群中选择染色体进行交配。每两个进行交配的父代染色体,交换部分基因,产生两个新的子代染色体,子代染色体取代父代染色体进入新种群。没有进行交配的染色体直接复制进人新种群。
Step5. 按照概率 Pm对新种群中染色体的基因进行变异操作。发生变异的基因数值发生改变。变异后的染色体取代原有染色体进人新群体,未发生变异的染色体直接进人新群体。
Step6. 变异后的新群体取代原有群体,重新计算群体中各个染色体的适应值。倘若群体的最大适应值大于Best 的适应值,则以该最大适应值对应的染色体替代Best。
Step7. 当前进入代数Generation加1.如果Generation超过规定的最大进化代数或Best达到规定的误差要求,算法结束。否则返回Step3.

遗传算法流程图:
在这里插入图片描述
遗传算法伪代码:

/*  P(t)表示某一代的群体,t为当前进化代数
Best表示目前已找到的最优解  */
Procedure GA
begin
  t←0;
  initialize(P(t));
  evaluate(P(t));
  keep_best(P(t));
  while(不满足终止条件) do
  begin
  	P(t)←selection(P(t));
  	P(t)←crossover(P(t));
  	P(t)←mutation(P(t));
  	t←t+1;
  	P(t)←P(t-1);
  	evaluate(P(t));
  	if (P(t)的最优适应值大于Best的适应值)
  		//以P(t)的最优染色体替代Best
  		replace(Best);
  		end if
  	end
 end

2. 基于遗传算法的TSP问题

2.1 准备数据

  1. 设置当前N的值为25,使用如下命令:
 save city_25 pos;

保存随机生成的25个城市序列的位置信息在city_25.mat文件中,在下一次使用此城市序列信息时只需执行load命令即可。

  1. 设置当前N的值为50,使用如下命令:
 save city_50 pos;

保存随机生成的50个城市序列的位置信息在city_50.mat文件中,在下一次使用此城市序列信息时只需执行load命令即可。

  1. 设置当前N的值为75,使用如下命令:
 save city_75 pos;

保存随机生成的75个城市序列的位置信息在city_75.mat文件中,在下一次使用此城市序列信息时只需执行load命令即可。

2.2 代码实现

2.2.1 画图函数(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

2.2.2 适应度函数(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

2.2.3 染色体的路程代价函数(mylength.m)

function len=myLength(D,p)%p是一个排列
[N,NN]=size(D);
len=D(p(1,N),p(1,1));
for i=1:(N-1)
    len=len+D(p(1,i),p(1,i+1));
end
end

2.2.4 交叉操作函数(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

2.2.5 变异函数(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

2.2.6 对调函数I(exchange.m)

function [x,y]=exchange(x,y)
temp=x;
x=y;
y=temp;
end

2.2.7 主函数(main.m)

clear;
clc;
N=25;              
M=100;              
ITER=2000;              
%C_old=C;
m=6;               
Pc=0.8;             
Pmutation=0.05;     
load city_25;
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);
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);
R=popm(rr(1,1),:);
for i=1:N
    fprintf('%d ',R(i));
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);
    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(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
figure(3)
plot_route(pos,R);
axis([-3 3 -3 3]);
figure(4)
plot(distance_min);

2.3 调整参数并分析运行结果

2.3.1 不同种群个数对算法的影响

对于city_25.mat文件中的城市序列,参数ITER=2000,m=2,Pc=0.8,Pm=0.05保持不变,调整种群个数M的值,观测其对于算法性能的影响,运行结果如下:

  1. M=50
minlen=2.206565e+01

在这里插入图片描述
2. M=100

minlen=1.740894e+01

在这里插入图片描述
3. M=200

minlen=1.874265e+01

在这里插入图片描述
对于遗传算法中的群体个数参数的设置,由运行结果可知当M=100时得到TSP的最短路径长度都小于M=50和M=200运行得出的最短路径长度。
根据运行结果可知:群体个数M参数设置的时候不宜过大也不宜过小。
若M设置较大,一次进化所覆盖的模式较多,可以保证群体的多样性,从而提高算法的搜索能力,但是由于群体中染色体的个数较多,势必增加算法的计算量,降低了算法的运行效率。
若M设置较小,虽然降低了计算量,但是同时降低了每次进化中群体包含更多较好染色体的能力。

2.3.2 不同迭代次数对算法的影响

对于city_25.mat文件中的城市序列,参数M=100,m=2,Pc=0.8,Pm=0.05保持不变,调整迭代次数TER的值,观测其对于算法性能的影响,运行结果如下:

  1. ITER=1000
minlen=1.960677e+01

在这里插入图片描述
2. ITER=2000

minlen=1.851282e+01

在这里插入图片描述
3. ITER=3000

minlen=1.823384e+01

在这里插入图片描述
算法迭代次数由运行结果可知自然是越大越好,但也有计算量较大或无法得出最优解的弊端,应当选取适合当前数据量的迭代次数即可,无需太大或太小。
若迭代次数过多,势必会降低算法的运行效率,会陷入已经求解到最优值,但因为迭代次数还未达到设置的值,因此继续进行迭代,降低了算法的运行效率。
若迭代次数过少,会直接导致算法的失败,当算法还未查找到最优值时,已经到达了迭代次数的最大值,退出迭代过程。
因此,在实现遗传算法的时候应根据实际情况选定合适的迭代次数,不应一味选取较大的值。

2.3.3 适应值归一化淘汰加速指数对算法的影响

对于city_25.mat文件中的城市序列,参数M=100,ITER=2000,Pc=0.8,Pm=0.05保持不变,调整适应值归一化淘汰加速指数m的值,观测其对于算法性能的影响,运行结果如下:

  1. m=2
minlen=1.841556e+01

在这里插入图片描述
2. m=4

minlen=2.153948e+01

在这里插入图片描述
4. m=6

minlen=2.040191e+01

在这里插入图片描述
由运行结果可得:当m=2时得到的TSP最短路径比m=4和m=6时得到的最短路径都要小,即m=2为当前情况下的较好的参数值。但对比迭代曲线可以发现当m=2时的迭代过程不够稳定,当m=4,m=6时迭代曲线较为平滑,且较快地趋于稳定,可以发现算法运行效率和迭代过程的稳定性不能只通过m而达到兼得的效果。
经查阅资料可得:m为适应值归一化淘汰加速指数 ,最好取为1,2,3,4 ,不宜太大。

2.3.4 不同交叉概率对算法的影响

对于city_25.mat文件中的城市序列,参数M=100,ITER=2000,m=2,Pm=0.05保持不变,调整交叉概率Pc的值,观测其对于算法性能的影响,运行结果如下:

  1. Pc=0.4
minlen=2.144176e+01

在这里插入图片描述
2. Pc=0.8

minlen=1.903893e+01

在这里插入图片描述
3. Pc=1.2

minlen=2.107957e+01

在这里插入图片描述
由运行结果可得当Pc的值为0.8时,得到的最短路径比Pc=0.4和Pc=1.2时都要小。但当Pc为1.2时,算法的收敛速度很快,可以得出较差概率影响着算法的运行效率,但对得出的最优值不能保证其最优性。
经查阅资料可得:
Pc的取值一般为0.4~0.99。
也可采用自适应的方法调整算法运行过程中的Pc值.

2.3.5 不同变异概率对算法的影响

  1. Pm=0.001
minlen=2.209860e+01

在这里插入图片描述
2. Pm=0.05

minlen=1.949286e+01

在这里插入图片描述
3. Pm=0.20

minlen=1.954383e+01

在这里插入图片描述
Pm的值不宜过大。因为变异对已找到的较优解具有一定的破坏作用,如果Pm的值太大,可能会导致算法目前所处的较好的搜索状态倒退回原来较差的情况。
Pm的取值一般为0. 001~0.1。
也可采用自适应的方法调整算法运行过程中的Pm值。

发布了13 篇原创文章 · 获赞 5 · 访问量 2188

猜你喜欢

转载自blog.csdn.net/weixin_45617915/article/details/103142816
今日推荐