matlab 遗传优化算法_转载 | 遗传算法解决TSP问题的MATLAB实现
問(wèn)題定義:
巡回旅行商問(wèn)題
給定一組n個(gè)城市和倆倆之間的直達(dá)距離,尋找一條閉合的旅程,使得每個(gè)城市剛好經(jīng)過(guò)一次且總的旅行距離最短。
TSP問(wèn)題也稱(chēng)為貨郎擔(dān)問(wèn)題,是一個(gè)古老的問(wèn)題。最早可以追溯到1759年Euler提出的騎士旅行的問(wèn)題。1948年,由美國(guó)蘭德公司推動(dòng),TSP成為近代組合優(yōu)化領(lǐng)域的典型難題。
TSP是一個(gè)具有廣泛的應(yīng)用背景和重要理論價(jià)值的組合優(yōu)化問(wèn)題。近年來(lái),有很多解決該問(wèn)題的較為有效的算法不斷被推出,例如Hopfield神經(jīng)網(wǎng)絡(luò)方法,模擬退火方法以及遺傳算法方法等。
TSP搜索空間隨著城市數(shù)n的增加而增大,所有的旅程路線組合數(shù)為(n-1)!/2。在如此龐大的搜索空間中尋求最優(yōu)解,對(duì)于常規(guī)方法和現(xiàn)有的計(jì)算工具而言,存在著諸多計(jì)算困難。借助遺傳算法的搜索能力解決TSP問(wèn)題,是很自然的想法。
基本遺傳算法可定義為一個(gè)8元組:
(SGA)=(C,E,P0,M,Φ,Г,Ψ,Τ)
C ——個(gè)體的編碼方法,SGA使用固定長(zhǎng)度二進(jìn)制符號(hào)串編碼方法;
E ——個(gè)體的適應(yīng)度評(píng)價(jià)函數(shù);
P0——初始群體;
M ——群體大小,一般取20—100;
Ф——選擇算子,SGA使用比例算子;
Г——交叉算子,SGA使用單點(diǎn)交叉算子;
Ψ——變異算子,SGA使用基本位變異算子;
Т——算法終止條件,一般終止進(jìn)化代數(shù)為100—500;
問(wèn)題的表示
對(duì)于一個(gè)實(shí)際的待優(yōu)化問(wèn)題,首先需要將其表示為適合于遺傳算法操作的形式。用遺傳算法解決TSP,一個(gè)旅程很自然的表示為n個(gè)城市的排列,但基于二進(jìn)制編碼的交叉和變異操作不能適用。
路徑表示是表示旅程對(duì)應(yīng)的基因編碼的最自然,最簡(jiǎn)單的表示方法。它在編碼,解碼,存儲(chǔ)過(guò)程中相對(duì)容易理解和實(shí)現(xiàn)。例如:旅程(5-1-7-8-9-4-6-2-3)可以直接表示為(5 1 7 8 9 4 6 2 3)。
產(chǎn)生初始種群
一是完全隨機(jī)產(chǎn)生,它適合于對(duì)問(wèn)題的解無(wú)任何先驗(yàn)知識(shí)的情況。隨機(jī)性較強(qiáng),因而也較公正。
二是某些先驗(yàn)知識(shí)可轉(zhuǎn)變?yōu)楸仨殱M(mǎn)足的一組要求,然后在滿(mǎn)足這些要求的解中在隨機(jī)地選取樣本。這樣選擇初始種群可使遺傳算法更快的達(dá)到最優(yōu)解。種群有一定的目標(biāo)性和代表性,但取例不如完全隨機(jī)的廣泛,而且先驗(yàn)知識(shí)是否可靠也是一個(gè)問(wèn)題。
適應(yīng)度函數(shù)
遺傳算法在進(jìn)化搜索中基本不利用外部信息,僅以適應(yīng)度函數(shù)為依據(jù),利用種群中每個(gè)個(gè)體的適應(yīng)度值來(lái)進(jìn)行搜索。TSP的目標(biāo)是路徑總長(zhǎng)度為最短,路徑總長(zhǎng)度的倒數(shù)就可以為T(mén)SP的適應(yīng)度函數(shù):
選擇
一般地說(shuō),選擇將使適應(yīng)度較大(優(yōu)良)個(gè)體有較大的存在機(jī)會(huì),而適應(yīng)度較小(低劣)的個(gè)體繼續(xù)存在的機(jī)會(huì)也較小。簡(jiǎn)單遺傳算法采用賭輪選擇機(jī)制,令Σfi表示群體的適應(yīng)度值之總和,fi表示種群中第i個(gè)染色體的適應(yīng)度值,它產(chǎn)生后代的能力正好為其適應(yīng)度值所占份額fi/Σfi。
交叉
基于路徑表示的編碼方法,要求一個(gè)個(gè)體的染色體編碼中不允許有重復(fù)的基因碼,也就是說(shuō)要滿(mǎn)足任意一個(gè)城市必須而且只能訪問(wèn)一次的約束。基本遺傳算法的交叉操作生成的個(gè)體一般不能滿(mǎn)足這一約束條件。
部分匹配交叉操作要求隨機(jī)選取兩個(gè)交叉點(diǎn),以便確定一個(gè)匹配段,根據(jù)兩個(gè)父?jìng)€(gè)體中兩個(gè)交叉點(diǎn)之間的中間段給出的映射關(guān)系生成兩個(gè)子個(gè)體。
變異
遺傳算法解決TSP 問(wèn)題基于二進(jìn)值編碼的變異操作不能適用,不能夠由簡(jiǎn)單的變量的翻轉(zhuǎn)來(lái)實(shí)現(xiàn)
在TSP問(wèn)題中個(gè)體的編碼是一批城市的序列,隨機(jī)的在這個(gè)序列抽取兩個(gè)城市,然后交換他們的位置。這樣就實(shí)現(xiàn)了個(gè)體編碼的變異,算法如下:
產(chǎn)生兩個(gè)0到1之間的隨機(jī)實(shí)數(shù);
將這兩個(gè)隨機(jī)實(shí)數(shù)轉(zhuǎn)化為0到n(城市數(shù))-1之間的隨機(jī)整數(shù);
將這兩個(gè)隨機(jī)整數(shù)指代的城市進(jìn)行交換;
流程圖
代碼
主函數(shù)代碼:
clear;
clc;
tStart= tic;% 算法計(jì)時(shí)器
%%%%%%%%%%%%自定義參數(shù)%%%%%%%%%%%%%
[cityNum,cities]= Read('dsj1000.tsp');
cities= cities';
%cityNum=100;
maxGEN = 1000;
popSize = 100; % 遺傳算法種群大小
crossoverProbabilty = 0.9; %交叉概率
mutationProbabilty = 0.1; %變異概率
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
gbest = Inf;
%隨機(jī)生成城市位置
%cities=rand(2,cityNum)*100;%100是最遠(yuǎn)距離
%計(jì)算上述生成的城市距離
distances = calculateDistance(cities);
%生成種群,每個(gè)個(gè)體代表一個(gè)路徑
pop = zeros(popSize, cityNum);
for i=1:popSize
????pop(i,:) = randperm(cityNum);
end
offspring = zeros(popSize,cityNum);
%保存每代的最小路勁便于畫(huà)圖
minPathes = zeros(maxGEN,1);
%GA算法
for??gen=1:maxGEN
????% 計(jì)算適應(yīng)度的值,即路徑總距離
????[fval, sumDistance, minPath, maxPath] = fitness(distances, pop);
????% 輪盤(pán)賭選擇
????tournamentSize=4; %設(shè)置大小
????for k=1:popSize
????????% 選擇父代進(jìn)行交叉
????????tourPopDistances=zeros( tournamentSize,1);
????????for i=1:tournamentSize
????????????randomRow = randi(popSize);
????????????tourPopDistances(i,1) = sumDistance(randomRow,1);
????????end
????????% 選擇最好的,即距離最小的
????????parent1??= min(tourPopDistances);
????????[parent1X,parent1Y] = find(sumDistance==parent1,1, 'first');
????????parent1Path = pop(parent1X(1,1),:);
????????for i=1:tournamentSize
????????????randomRow = randi(popSize);
????????????tourPopDistances(i,1) = sumDistance(randomRow,1);
????????end
????????parent2??= min(tourPopDistances);
????????[parent2X,parent2Y] = find(sumDistance==parent2,1, 'first');
????????parent2Path = pop(parent2X(1,1),:);
????????subPath = crossover(parent1Path, parent2Path, crossoverProbabilty);%交叉
????????subPath = mutate(subPath, mutationProbabilty);%變異
????????offspring(k,:) = subPath(1,:);
????????minPathes(gen,1) = minPath;
????end
????fprintf('代數(shù):%d?? 最短路徑:%.2fKM \n', gen,minPath);
????% 更新
????pop= offspring;
????% 畫(huà)出當(dāng)前狀態(tài)下的最短路徑
????ifminPath< gbest
????????gbest= minPath;
????????paint(cities,pop,gbest,sumDistance,gen);
????end
end
figure
plot(minPathes,'MarkerFaceColor','red','LineWidth',1);
title('收斂曲線圖(每一代的最短路徑)');
set(gca,'ytick',500:100:5000);
ylabel('路徑長(zhǎng)度');
xlabel('迭代次數(shù)');
gridon
tEnd= toc(tStart);
fprintf('時(shí)間:%d 分??%f 秒.\n',floor(tEnd/60),rem(tEnd,60));
function[distances]= calculateDistance(city)
%計(jì)算距離
????[~,col]= size(city);
????distances= zeros(col);
????fori=1:col
????????forj=1:col
????????????distances(i,j)= distances(i,j)+ sqrt((city(1,i)-city(1,j))^2+ (city(2,i)-city(2,j))^2??);??????????
????????end
????end
end
function[childPath]= crossover(parent1Path,parent2Path,prob)
%交叉
????random= rand();
????ifprob>= random
????????[l,length]= size(parent1Path);
????????childPath= zeros(l,length);
????????setSize= floor(length/2)-1;
????????offset= randi(setSize);
????????fori=offset:setSize+offset-1
????????????childPath(1,i)= parent1Path(1,i);
????????end
????????iterator= i+1;
????????j= iterator;
????????whileany(childPath== 0)
????????????ifj> length
????????????????j= 1;
????????????end
????????????ifiterator> length
????????????????iterator= 1;
????????????end
????????????if~any(childPath== parent2Path(1,j))
????????????????childPath(1,iterator)= parent2Path(1,j);
?????????????? iterator= iterator+ 1;
????????????end
????????????j= j+ 1;
????????end
????else
????????childPath= parent1Path;
????end
end
function[fitnessvar,sumDistances,minPath,maxPath]= fitness(distances,pop)
%計(jì)算整個(gè)種群的適應(yīng)度值
????[popSize,col]= size(pop);
????sumDistances= zeros(popSize,1);
????fitnessvar= zeros(popSize,1);
????fori=1:popSize
?????? forj=1:col-1
??????????sumDistances(i)= sumDistances(i)+ distances(pop(i,j),pop(i,j+1));
?????? end
????end
????minPath= min(sumDistances);
????maxPath= max(sumDistances);
????fori=1:length(sumDistances)
????????fitnessvar(i,1)=(maxPath- sumDistances(i,1)+0.000001)/ (maxPath-minPath+0.00000001);
????end
end
function[mutatedPath]= mutate(path,prob)
%對(duì)指定的路徑利用指定的概率進(jìn)行更新
????random= rand();
????ifrandom<= prob
????????[l,length]= size(path);
????????index1= randi(length);
????????index2= randi(length);
????????%交換
????????temp= path(l,index1);
????????path(l,index1)= path(l,index2);
????????path(l,index2)=temp;
????end
????????mutatedPath= path;
end
function[output_args]= paint(cities,pop,minPath,?totalDistances,?gen)
????gNumber=gen;
????[~,length]= size(cities);
????xDots= cities(1,:);
????yDots= cities(2,:);
????%figure(1);
????title('GA TSP');
????plot(xDots,yDots,'p','MarkerSize',14,'MarkerFaceColor','blue');
????xlabel('經(jīng)度');
????ylabel('緯度');
????axisequal
????holdon
????[minPathX,~]= find(totalDistances==minPath,1,'first');
????bestPopPath= pop(minPathX,:);
????bestX= zeros(1,length);
????bestY= zeros(1,length);
????forj=1:length
?????? bestX(1,j)= cities(1,bestPopPath(1,j));
?????? bestY(1,j)= cities(2,bestPopPath(1,j));
????end
????title('GA TSP');
????plot(bestX(1,:),bestY(1,:),'red','LineWidth',1.25);
????legend('城市','路徑');
????axisequal
????gridon
????%text(5,0,sprintf('迭代次數(shù): %d 總路徑長(zhǎng)度: %.2f',gNumber, minPath),'FontSize',10);
????drawnow
????holdoff
end
function[n_citys,city_position]= Read(filename)
fid= fopen(filename,'rt');
location=[];
A= [12];
tline= fgetl(fid);
whileischar(tline)
????if(strcmp(tline,'NODE_COORD_SECTION'))
????????while~isempty(A)
????????????A=fscanf(fid,'%f',[3,1]);
????????????ifisempty(A)
????????????????break;
????????????end
????????????location=[location;A(2:3)'];
????????end
????end
????tline = fgetl(fid);
????if strcmp(tline,'EOF')
????????break;
????end
end
[m,n]=size(location);
n_citys= m;
city_position=location;
fclose(fid);
end
結(jié)果
測(cè)試數(shù)據(jù):
初始態(tài):
終態(tài):
收斂曲線:
可以看到,當(dāng)城市數(shù)量適中時(shí),迭代500次最短路徑長(zhǎng)度有收斂的趨勢(shì)。
當(dāng)城市數(shù)目較多時(shí)
迭代500次,仍然不收斂,可能的問(wèn)題是陷入了局部最優(yōu)解。
總結(jié)與觀點(diǎn)
難點(diǎn)是交叉算法的設(shè)計(jì),由于TSP問(wèn)題和一般的NP問(wèn)題不一樣,每個(gè)個(gè)體的每個(gè)維度具有唯一性,因此在交叉的時(shí)候要注意不能有重復(fù)的值。本次實(shí)驗(yàn)采用的是部分匹配交叉,先從第一個(gè)父代選出一個(gè)偏移量,從偏移量后的部分點(diǎn)加入到子代,接下來(lái)從第二個(gè)父代選擇第一代沒(méi)有選擇的部分點(diǎn)移到子代中。
當(dāng)城市數(shù)量較多時(shí),大于50個(gè)城市,迭代多次,GA仍然不收斂,可能的問(wèn)題是陷入了局部最優(yōu)解,因此對(duì)GA算法進(jìn)行改進(jìn)怡跳出局部最優(yōu)解,可以采用類(lèi)似于PSO或者蟻群算法的思想。
數(shù)據(jù)集下載
https://github.com/xyjigsaw/Dataset
轉(zhuǎn)載自:
https://www.omegaxyz.com/2019/01/21/matlab-tsp-all/
作者:OmegaXYZ
https://www.omegaxyz.com
總結(jié)
以上是生活随笔為你收集整理的matlab 遗传优化算法_转载 | 遗传算法解决TSP问题的MATLAB实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 为什么苹果内购总是失败_IOS用户支付失
- 下一篇: matlab人脸追踪,求大神帮助我这个菜