/**僅記錄自己的學習歷程**/
一、概述
在閱讀本文之前,可以先閱讀這兩篇文章(文章1,文章2),不需要理解理論部分,概覽全文,着重看一下原文舉的例子,有助於理解遺傳算法的實現原理。
前面的理論部分看不懂沒有關係,後面有很詳細的實例說明,把例子看懂並自己動手敲個代碼(源碼我會上傳,但一定要自己親自去實現一下,這樣才能對遺傳算法的每一步以及參數的意義有深刻的認識),再回過頭來看遺傳算法的理論部分,相信遺傳算法你就入門了。
標準遺傳算法的步驟如下:
(1)構造滿足約束條件的染色體。由於遺傳算法不能直接處理解空間中的解,所以必須通過編碼將解表示成適當的染色體。實際問題的染色體有多種編碼方式,染色體編碼方式的選取應儘可能的符合問題約束,否則將影響計算效率。
(2)隨機產生初始羣體。初始羣體是搜索開始的一組染色體,其數量應適當選擇。
(3)計算每個染色體的適應度。適應度是反應染色體優劣的唯一指標,遺傳算法就是要尋求適應度最大的染色體。
(4)使用複製、交叉和變異算子產生子羣體。這三個算子是遺傳算法的基本算子,其中複製體現了優勝劣汰的自然規律,交叉體現了有性繁殖的思想,變異體現了進化過程中基因突變。
(5)重複步驟,直到滿足終止條件爲止。
從生物學角度簡單來說,每一個染色體就代表一個個體,N個個體形成一個種羣,計算每一個個體的適應度大小,從種羣中挑選適應度大的個體,進行遺傳、交叉、變異操作生成下一代種羣。
從數學角度出發,上面的話翻譯下來的意思就是說對某個待解決的問題先生成N個初始解,形成一個解集。計算每一個解的好壞,留下好的解,對留下的解進行一番倒騰,再生成一組解,不斷循環,最後解集中的解趨近於理想值。
遺傳算法是一種複雜度爲O(1)的並行全局搜索算法。
與傳統方法相比,遺傳算法的優越性主要表現在首先,在遺傳算子的作用下,遺傳算法具有很強的搜索能力,能以很大的概率找到問題的全局最優解其次,由於它固有的並行性,能有效處理大規模的優化問題。
二、求解TSP問題
前面理論和優點說了一大堆,遺傳算法到底該怎麼用呢?下面通過解決TSP問題,我們來看看如何將問題轉化,進而使用遺傳算法求解(掌握思想最重要,用什麼語言無所謂,我這裏使用Matlab,不用擔心不會Matlab,我會很詳細的解釋每一行代碼的作用,然後你用自己會的語言實現一遍就可以了)。
旅行商問題(即TSP問題)指一個商人要經過且只經過一次指定的N座城市,即遍歷這N座不同的城市,求最短的遍歷路徑。這是一個NP-hard問題,隨着城市數量的增多,使用窮舉法計算的複雜度爲O(n!),想要求得精確解是不切合實際的。
遺傳算法求解思想:我給每一個城市一個特定編號行不行,1->2就代表從城市1到城市2,如果現在有5個城市,旅行商從城市0出發,那麼0-1-2-3-4-5-0就是旅行商的一條可選路線,也就是我們TSP問題的一個解,而路徑的長度就是對應的適應度值。使用遺傳算法的對應術語來說,0-1-2-3-4-5-0就是一個染色體,一個個體;一個染色體裏面的每一個數字就是一個基因,接下來的遺傳、交叉、變異就是針對基因進行操作。Matlab裏面randperm(n)函數可以生成1-n的隨機全排列,調用該函數10次,就會生成10個解(父代),根據適應度值我們按照一定的策略從父代中選擇10個作爲子代,對子代進行遺傳、交叉、變異操作,即變化染色體中基因點的位置,生成新的解,經過多次迭代,種羣中的解都會趨向於某個最優解。
第一步:編碼
這裏我們使用自然數編碼,代碼的14-19行是初始化種羣的過程,通過randperm生成需要城市數的隨機全排列,把出發城市放兩端,這樣一個解就構造出來了,循環指定的次數生成需要的種羣大小。
第二步:遺傳算法迭代
代碼20-28行是遺傳算法的迭代過程,第21行計算適應度,第22-24行分別進行選擇、交叉、變異操作。
% 單旅行商問題的遺傳算法
% 20個城市,1條線路
clear,clc
close all
load city_distance.mat %載入距離矩陣
load city_location.mat
City_Number=20; %城市數量
Race_Number=200; %種羣數量
Iteration=100; %迭代次數
P_Cross=0.8; %交叉概率
P_Mutation=0.2; %變異概率
race=zeros(Race_Number,City_Number+2);
%初始化種羣
for i=1:Race_Number
temp=randperm(City_Number);
route=[City_Number+1,temp,City_Number+1];
route=ga_hamilton(route); %使用改良圈算法優化初始種羣
race(i,:)=route;
end
for t=1:Iteration
adaptation=ga_adaptation(race); %計算適應度大小
race=ga_choose(race,adaptation); %進行選擇操作
race=ga_cross(race,P_Cross); %進行交叉操作
race=ga_mutation(race,P_Mutation); %進行變異操作
[path,val]=ga_plot(race);
pause(0.1);
fprintf('第%d代,最優解爲%d\n',t,val);
end
三、求解mTSP問題
回過頭來看看求解TSP的過程,是不是特別簡單,你完全不用考慮最終結果是怎麼計算出來的,你只要告訴遺傳算法怎麼進行下一步就行。
事實上,遺傳算法的難點在於:
(1)如何將複雜問題轉化成可用遺傳算法求解的問題;
(2)尋找合適的編碼方式;
(3)建立恰當的適應度值評價方法。
在學會求解TSP問題的基礎上,我們加大難度,現在依然有N座城市,要求M個旅行商遍歷N座城市,使總路程最短。這就是mTSP問題,不再是一條線路了,而是多條線路,而且總距離要最短。你可以先花幾分鐘自己思考一下,讓你用遺傳算法求解,你要怎麼做,如何轉化問題是關鍵。
遺傳算法求解思想:
(1)依然給每座城市一個編號,方便我們使用自然數編碼。假設現在有6座城市,旅行商從0點出發。那麼0-1-2-3-0-4-5-6-0就是我們的一個解,爲了更方便地表示,我們可以假設一個虛擬城市7,即假設兩個旅行商分別從兩個不同的城市出發,而這兩個城市位置座標一致,從而上面的解可表示爲0-1-2-3-7-4-5-6-0。這樣一來我們就把mTSP問題轉化成了一個TSP問題,不同的地方就是城市數量增加了1,由6座城市,增加爲7座。這樣轉換的便利性是顯而易見的,除去端點,中間數的序列又是一組1-n的全排列,我們只要做稍許變化,就可以繼續調用解決TSP問題的函數代碼;
(2)到這裏遺傳算法的三個難點我們已經解決了編碼和轉化這兩個難點,還剩最重要的計算適應度值。如果依舊按照求解TSP的方法把距離作爲計算適應度的指標,在求解mTSP問題時會出現0-7的情形,從出發點直接回到終點,即兩條線路一條特別長,另一條特別短,這明顯不是我們希望得到的結果,所以在計算適應度值時要綜合考慮距離和路線長度兩個指標。在ga_adaptation函數中,代碼16行我取兩段路線長度的最大值作爲另一個指標,總體適應度即兩個指標之和。如果你認爲兩條線路長度一致比較重要,你可以增大代碼16行中的係數,反之減小比例係數。
% 多旅行商問題的遺傳算法
% 20個城市,2條線路
clear,clc
close all
load city_distance.mat
load city_location.mat
City_Number=21; %城市數量
Race_Number=200; %種羣數量
Iteration=200; %迭代次數
P_Cross=0.6; %交叉概率
P_Mutation=0.2; %變異概率
race=zeros(Race_Number,City_Number+2);
%初始化種羣
for i=1:Race_Number
temp=randperm(City_Number);
route=[City_Number+1,temp,City_Number+1];
route=ga_hamilton(route); %使用改良圈算法優化初始種羣
race(i,:)=route;
end
for t=1:Iteration
adaptation=ga_adaptation(race);
race=ga_choose(race,adaptation);
race=ga_cross(race,P_Cross);
race=ga_mutation(race,P_Mutation);
race=ga_exchange(race,P_Cross); %新增操作
race=ga_invert(race,P_Cross); %新增操作
[path,val]=ga_plot(race);
best_path=path;
best_value=val;
pause(0.1);
end
function [ adaptation ] = ga_adaptation( race )
load city_distance.mat
k=race(1,1);
[m,n]=size(race);
adaptation=zeros(1,m);
adaptation_1=zeros(1,m);
adaptation_2=zeros(1,m);
for i=1:m
path=0;
for j=1:n-1
path=path+city_distance(race(i,j),race(i,j+1));
end
path=path+city_distance(race(i,n),race(i,1));
adaptation_1(i)=path;
index=find(race(i,:)==k-1);
adaptation_2(i)=max(index-1,n-index)*3000; %係數3000不是一個固定的值,需要根據實際情況取值
adaptation(i)=adaptation_1(i)+adaptation_2(i);
end
end
編碼方法:二進制編碼,浮點數編碼,自然數編碼,格雷碼。
選擇策略:賭輪盤法,精英策略,最優保存策略。
交叉操作:順序交叉,部分匹配交叉,循環交叉,單點交叉。
變異操作:均勻變異,邊界變異,高斯近似變異。
遺傳算法的特點:
(1)遺傳算法對問題參數的代碼集起作用,而不是對參數本身起作用。遺傳算法處理的對象是染色體,因而要求把所要優化問題的基本參數轉化爲定長的有限符號的染色體。
(2)遺傳算法是從初始羣體開始搜索的,而不是從單點開始搜索的。許多傳統優化方法都是從搜索空間的單點出發,通過某些轉換規則確定下一點。這種點到點的搜索方法在多峯值優化問題中,首先找到的可能不是最優峯值,遺傳算法是以點集開始的尋優過程,初始羣體是隨機在搜索空間中選取的,這樣在搜索過程中達到最優峯值的概率大於點到點的概率。
(3)遺傳算法在搜索過程中只使用適應度函數,而不用導數及其他輔助信息。對於不同類型的優化問題具有廣泛適應性。
(4)遺傳算法使用概率轉換規則而不用確定性規則。遺傳算法使用概率轉換規則來調整其搜索方向,各代羣體間沒有統一的聯繫規律。但使用概率轉換規則並不意味着這種方法屬於隨機算法範疇,它只是使用隨機轉換作爲工具來調整搜索過程趨向於目標函數不斷改進的區域。