一、簡介
遺傳算法是基於達爾文的生物進化論,是人工智能算法的的重要分支,主要用於解決一類求最優解問題。如旅行商(TSP)問題。
遺傳算法是將狀態當成染色體,狀態里的每一個決策都是染色體上的一個基因。然后根據實際情況生成一個適應度函數,計算每一串染色體對環境的適應度。讓適應度高的遺傳到下一代,適應度低的淘汰掉,另外在實現的過程中也許會發生變異,導致一些決策改變。除此之外,遺傳算法是隨機性近似算法,所以當我們運用該算法時必須采取措施使其收斂到全局最優解,並且盡量提高達到最優解的概率。遺傳算法除了設計適應度函數以外,還有很重要的三個部分:選擇,交叉,變異。
二、遺傳算法實現步驟
1.評估每條染色體所對應個體的適應度。
2.遵照適應度越高,選擇概率越大的原則,從種群中選擇兩個個體作為父方和母方。
3.抽取父母雙方的染色體,進行交叉,產生子代。
4.對子代的染色體進行變異。
5.重復2,3,4步驟,直到新種群的產生。
三、遺傳算法求解TSP實現步驟
1.確定影響因素
城市序列、城市個數N、種群個數M、交叉概率Pc、變異概率Pmutation等;
2.初始化數據
2.1初始化影響因素:城市序列、城市個數N、種群個數M、交叉概率Pc、變異概率Pmutation
2.2 初始化數據:讀入數據源,將坐標轉換為距離矩陣(標准化歐式距離)
3.計算種群適應度
已知任意兩個城市之間的距離,每個染色體可計算出總距離,因此可以將一個隨機全排列的總距離的倒數作為適應度函數,即距離越短,適應度函數越好。
4.迭代
選擇算子:賭輪選擇策略挑選下一代個體。
交叉運算:在交叉概率的控制下,對群體中的個體兩兩進行交叉。
變異運算:在變異概率的控制下,對群體中的個體兩兩進行變異,即對某一個體的基因進行隨機調整。
計算新的種群適應度以及個體累積概率,並更新最優解。
將新種群復制到舊種群中,准備下一代進化(迭代)。
5.輸出
輸出迭代過程中產生的最短路徑長度以及最短路徑。
四、代碼實現
main.m(主函數):
%main clear; clc; %%%%%%%%%%%%%%%輸入參數%%%%%%%% N=25; %%城市的個數 M=100; %%種群的個數 ITER=2000; %%迭代次數 %C_old=C; m=2; %%適應值歸一化淘汰加速指數 Pc=0.8; %%交叉概率 Pmutation=0.05; %%變異概率 %%生成城市的坐標 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(交叉操作函數):
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(對調函數):
function [x,y]=exchange(x,y) temp=x; x=y; y=temp; end
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(變異函數):
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
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
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
五、實驗結果與分析
分別測試城市序列、城市個數N、種群個數M、交叉概率Pc、變異概率Pmutation等影響因素對實驗結果的影響
1、不同城市序列對實驗結果的影響:
分析:在本算法實現過程中,城市序列采用隨機生成,當城市序列不同時,算法運行時間和最短回路距離也會不同。
2、種群個數M(其他因素不變)對實驗結果的影響:
M=100,城市個數N=35,其坐標分別如下:(在后面的測試中各城市坐標均如下所示)
M=100(如圖顯示約迭代1100次得到最短回路距離為20.92):
M=80(如圖顯示約迭代1000次得到最短回路距離為23.25)
M=60(如圖顯示約迭代1400次得到最短回路距離為23.59)
M=40(如圖顯示約迭代1750次得到最短回路距離為24.06)
分析:如上4組數據所示,當種群規模增大時,算法收斂到最優解的可能性越大,全局搜索能力也有所增強;另外可以看出當種群規模增大后,在解空間中搜索時,可以在相對較少的代數中找到最優解,進化代數也隨着種群規模的增大而變小了。種群規模越大算法結果越精確,適應度越好。
3、交叉概率Pc對實驗結果的影響
Pc=0.8(如圖顯示約迭代1000次得到最短回路距離為22.21)
Pc=0.6(如圖顯示約迭代900次得到最短回路距離為23.08)
Pc=0.4(如圖顯示約迭代1100次得到最短回路距離為23.36)
Pc=0.2(如圖顯示約迭代1700次得到最短回路距離為22.23)
Pc=0.01(如圖顯示約迭代1800次得到最短回路距離為25.14)
分析:如以上五組測試數據和運行結果可以看出,當交叉概率越小,迭代次數越大且得不到最優解,當交叉概率越大時,迭代次數越是且得到的結果更優。所以交叉概率較大時,結果越優。
4、變異概率Pmutation對實驗結果的影響
Pmutation=0.05(如圖顯示約迭代1100次得到最短回路距離為22.57)
Pmutation=0.1(如圖顯示約迭代1600次得到最短回路距離為21.52)
Pmutation=0.3(如圖顯示約迭代1500次得到最短回路距離為23.20)
Pmutation=0.6(如圖顯示約迭代2000次得到最短回路距離為28.56)
Pmutation=0.005(如圖顯示約迭代1700次得到最短回路距離為24.38)
分析:如以上五組測試數據和運行結果可以看出,當變異概率大於0.1時,變異概率越大,迭代次數越大且最短回路距離也變得越大,得不到最優解。當變異概率小於0.1時,變異概率越小,迭代次數越大且最短回路距離也變得越大,也無法得到最優解!!所以當變異概率越接近0.1時,越能得到最優解。