遺傳算法可視化項目(4):遺傳算法

昨天講了一下關於距離的計算,沒有看昨天或者以前的文章,點一下歷史消息或者這裏:html

遺傳算法可視化項目(1):概述
ios

遺傳算法可視化項目(2):獲取信息
git

遺傳算法可視化項目(3):建立圖的數據結構
github

遺傳算法可視化項目(插曲):關於距離的計算算法

今天首先介紹遺傳算法(genetic algorithm,GA)。數組

遺傳算法是一種進化算法,其基本原理是模仿天然界中的生物「物競天擇,適者生存」的進化法則,把問題參數編碼爲染色體,再利用迭代的方式進行選擇、交叉、變異等運算法則來交換種羣中染色體的信息,最終生成符合優化目標的染色體。微信

在遺傳算法中,染色體對應的是數據或者數組,一般是由一維的串結構數據來表示,串上各個位置對應基因的的取值。基因組成的串就是染色體,或者稱爲基因型個體。必定數量的個體組成了種羣,種羣中個體數目的大小稱爲種羣大小,也稱爲種羣規模,而各個個體對環境的適應程度稱爲適應度。數據結構

標準遺傳算法的步驟以下:機器學習

(1)編碼:遺傳算法在搜索解空間以前須要將解數據表示成遺傳空間的基因型串結構數據,這些串結構數據的不一樣組合構成了不一樣的染色體。函數

(2)初始化:即生成初始種羣。具體的作法是隨機生成N個初始的染色體(解空間的解),每個染色體其實就至關於一個個體,N個個體構成了一個初始種羣。遺傳算法以這N個個體做爲初始值開始進化。

(3)適應度評估:適應度代表個體或者解的優劣性。不一樣的問題,定義適應度函數的方式也不一樣。好比若是是求一個函數的最大值,那麼通常某個解對應的函數值越大,那麼這個個體(解)的適應度也就越高。

(4)選擇:選擇的目的是爲了從當前種羣中選出優良的個體,使它們有機會成爲父代繁殖下一代子孫。遺傳算法經過選擇過程體現這一思想,進行選擇的原則是適應性強的個體爲下一代貢獻一個或者多個後代的機率大。這體現了達爾文的適者生存原則。

(5)交叉:交叉操做是遺傳算法中最主要的遺傳操做。經過交叉能夠獲得新一代個體,新個體組合了其父代的個體特徵。交叉體現了信息交換的思想。

(6)變異:變異首先在羣體中隨機選擇一個個體,對於選中的個體以必定的機率(一般是比較小的機率,這與天然界一致,天然界的變異都是小几率事件)隨機改變染色體中某個基因的值。

有的時候除了選擇選擇、交叉、變異這三種操做以外,咱們還會針對具體的問題加入其它的操做(好比逆轉之類),可是選擇、交叉、變異是全部的遺傳算法都共同的擁有的遺傳操做。

其次介紹一下TSP問題。TSP(traveling salesman problem,旅行商問題)是典型的NP徹底問題,即其最壞狀況下的時間複雜度隨着問題規模的增大按指數方式增加,到目前爲止尚未找到一個多項式時間的有效算法。TSP問題能夠描述爲:已知n個城市之間的相互距離,某一旅行商從某一個城市出發,訪問每一個城市一次且僅一次,最後回到出發的城市,如何安排才能使其所走的路線最短。換言之,就是尋找一條遍歷n個城市的路徑,或者說搜索天然子集X={1,2,...,n}(X的元素表示對n個城市的編號)的一個排列P(X)={V1,V2,....,Vn},使得Td=∑d(Vi,Vi+1)+d(Vn,V1)取最小值,其中d(Vi,Vi+1)表示城市Vi到Vi+1的距離。TSP問題不只僅是旅行商問題,其餘許多NP徹底問題也能夠歸結爲TSP問題,如郵路問題,裝配線上的螺母問題和產品的生產安排問題等等,也使得TSP問題的求解具備更加普遍的實際意義。

  再來講針對TSP問題使用遺傳算法的步驟。

  (1)編碼問題:因爲這是一個離散型的問題,咱們採用整數編碼的方式,用1~n來表示n個城市,1~n的任意一個排列就構成了問題的一個解。能夠知道,對於n個城市的TSP問題,一共有n!種不一樣的路線。

  (2)種羣初始化:對於N個個體的種羣,隨機給出N個問題的解(至關因而染色體)做爲初始種羣。這裏具體採用的方法是:1,2,...,n做爲第一個個體,而後2,3,...,n分別與1交換位置獲得n-1個解,從2開始,3,4,...,n分別與2交換位置獲得n-2個解,依次類推。(若是這樣還不夠初始種羣的數量,能夠再考慮n,n-1,...,1這個序列,而後再按照相同的方法生成等等)

  (3)適應度函數:設一個解遍歷初始行走的總距離爲D,則適應度fitness=1/D,即總距離越高,適應度越低,總距離越低(解越好),適應度越高。

  (4)選擇操做:個體被選中的機率與適應度成正比,適應度越高,個體被選中的機率越大。這裏仍然採用輪盤賭法。

    (5)交叉操做:交叉操做是遺傳算法最重要的操做,是產生新個體的主要來源,直接關係到算法的全局尋優能力,這裏採用部分映射交叉。好比對於n=10的狀況,對於兩個路徑:

1 2 4 5 6  3  9 10 8 7

3 9 7 6 8 10 5  1  2 4

隨機產生兩個[1,10]之間的隨機數r1,r2,表明選擇交叉的位置,好比r1=2,r2=4,將第一個個體r1到r2之間的基因(即城市序號)與第二個個體r1到r2之間的基因交換,交換以後變爲:

1 9 7 6 6  3  9 10 8 7

3 2 4 5 8 10 5  1  2 4

這個時候會發現可能交叉過來的基因與原來其餘位置上的基因有重複,容易直到,第一個個體重複基因的數目與第二個個體重複基因的數目是相同的(這裏都是3個),只須要把第一個個體重複的基因與第二個個體重複的基因作交換,便可以消除衝突。消除衝突以後的解以下:

1 9 7 6 5  3  2 10 8 4

3 2 4 5 8 10 6  1  9 7

(6)變異操做:變異操做採起對於一個染色體(即個體)隨機選取兩個基因進行交換的策略。好比對於染色體:

2 4 6 10 3 1 9 7 8 5

隨機選取了兩個位置p1=3,p2=8,交換這兩個位置的基因,獲得新的染色體爲:

2 4 7 10 3 1 9 6 8 5

(7)進化逆轉操做:這個是標準的遺傳算法沒有的,是咱們爲了加速進化而加入的一個操做。這裏的進化是指逆轉操做具備單向性,即只有逆轉以後個體變得更優纔會執行逆轉操做,不然逆轉無效。具體的方法是,隨機產生[1,10](這裏仍然以10個城市爲例)之間的兩個隨機數r1和r2(其實也是容許相同的,只是r1,r2相同以後,逆轉天然無效,設置交叉變異都是無效的,可是這不會常常發生),而後將r1和r2之間的基因進行反向排序。好比對於染色體:

1 3 4 2 10 9 8 7 6 5

r1=3,r2=5,它們之間的基因反向排列以後獲得的染色體以下:

1 3 10 2 4 9 8 7 6 5

說了這麼多,接下來就是代碼實現了,仍是打開以前VS2017建立的項目:在解決方案資源管理器右擊頭文件→添加→新建項,而後在彈出的窗口點擊頭文件,取個名字(我這裏就叫GA.h了),最後肯定就行,首先是包含頭文件,宏定義(最大進化代數,種羣數目,交叉機率,變異機率大佬能夠隨便改,但小白菜鳥建議仍是用我給的數),定義全局變量和函數聲明,代碼以下:

接下來就是每個函數的實現,首先是init函數,實現代碼以下:

而後是距離函數和最小值函數,代碼以下:

接着是路徑總長度函數,代碼以下:

目前爲止,進入選擇,交叉,變異三大基本操做的實現了,首先是選擇操做,代碼以下:

而後就是最複雜的代碼最多(多到我連圖都不能一次截完的交叉操做,代碼以下:

而後是變異操做,代碼以下:

目前爲止三大基本操做結束了,還差一個逆轉操做,逆轉操做代碼以下:

最後還差一步計算並把結果傳給昨天建立的圖,代碼以下:

遺傳算法目前爲止理論和C語言實現講完了,今天的文章也就到此結束,文章最後附上項目地址:https://github.com/3480430977/DataVisualizationOfGA

最後歡迎你們掃碼關注

本文分享自微信公衆號 - Python機器學習算法說書人(Python-ML-Algorithm)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索