遗传算法求解函数优化及TSP问题
本文的pdf文件:link
???????遺傳算法是群智能算法中的一個分支,是一類基于種群搜索的優化算法,受自然界生物進化機制的啟發,通過自然選擇、變異、重組等操作,針對特定的問題取尋找出一個滿意的解。其遺傳進化過程簡單,容易理解,是其他一些遺傳算法的基礎。
???????遺傳算法的搜索特點是以編碼空間代替問題的參數空間,以適應度函數為評價依據;將編碼集作為遺傳的基礎,對個體進行遺傳操作,建立一個迭代過程。首先,算法從一個由個體組成的種群開始,對每個種群個體進行適應度評價;其次,利用個體的適應度選擇個體,并利用交叉和變異等遺傳算子作用其上,產生后代個體;最后,在原種群個體和后代個體中選擇個體生成下一代種群。
???????本文主要通過遺傳算法來求解函數優化和TSP兩個問題。函數優化是我們隨時都是遇到的問題,而傳統的求解方法更多的是基于數學理論來求解,通過求導等一系列數學計算來發掘函數本身的單調性等一系列性質并以此來尋找函數的極大極小值,但是普通的求解方法對問題本身要求很高,例如函數必須可導,或者必須是凸函數等,所以在面對一些非凸函數或者奇異函數時就不可以用傳統求解方法,而只能采用暴力搜索等算法。但是遺傳算法對于函數本身沒有要求,它可以看作是一種指導性搜索算法,利用前一代所遺留的信息來指導下一代的進化,這樣每一個計算得到的值都可以在此利用,不重復計算。所以遺傳算法在求解一些復雜函數最優值的問題中被廣泛使用。
???????TSP問題是一個典型的NP問題,暴力求解的復雜度非常高,但是遺傳算法的提出可以使得其在可接受迭代次數內達到收斂,本文利用遺傳算法來求解所給城市的最優路線。
一、問題重述
???????根據遺傳算法求解問題,分別運用遺傳算法求解低維單目標優化問題,高維單目標優化問題和TSP問題。
二、背景和發展
???????遺傳算法是近年來迅速發展起來的一種全新的隨機搜索與優化算法,其基本思想是基于達爾文的遺傳學說,該算法于1975年創建。
???????1971年,首次將遺傳算法用于函數優化。
???????1975年,出版了《自然系統和人工系統的自適應》,第一本系統的闡述了遺傳算法的著作。
???????1989年,《搜索,優化和機器學習中的遺傳算法》,總結了遺傳算法研究的主要成果,對遺傳算法及其應用做了全面而系統的闡述,同年并提出了基于自然選擇遠測創造性的提出了用層次化的計算機程序來表達問題的遺傳程序設計方法。
???????1991年,提出了基于鄰域交叉的交叉算子,并將其運用到TSP問題中。
???????目前,遺傳算法已經廣泛應用,主要有基于遺傳算法的機器學習,遺傳算法和神經網絡,并行處理人工生命等領域。
三、原理分析
3.1 定義
???????進化計算的基本思想來源于生物學中的基本知識:生物從簡單到復雜,從低級到高級的進化過程是一個自然的穩健的優化過程。這一進化過程的目的在于使生命個體更好的適應周邊環境。生物種群通過“優勝劣汰”及遺傳變異來達到進化的目的。
???????目前研究的進化算法主要有四種:遺傳算法,進化規劃,進化策略和遺傳編程。
???????遺傳算法(Genetic Algorithm)是模擬達爾文生物進化論的自然選擇和遺傳學機理的生物進化過程的計算模型,包括選擇、交叉和變異操作。
標準的遺傳算法主要有如下主要特點:
1,遺傳算法必須通過適當的方法對問題的可行解進行編碼。解空間中的可行解是個體的表現型,它在遺傳算法的搜索空間中對應的編碼形式是個體的基因型。
2,遺傳算法基于個體的適應度來進行概率選擇操作。
3,在遺傳算法中,個體的重組使用交叉算子。交叉算子是遺傳算法所強調的關鍵技術,它是遺傳算法中產生個體的主要方法,也是遺傳算法區別于其他進化算法的一個主要特點。
4,在遺傳算法中,編譯操作使用隨機變異技術。
5,遺傳算法擅長對離散空間的搜索,它較多地應用于組合優化問題。
???????直接對結構對象進行操作,不存在求導和函數連續性的限定;具有內在的隱并行性和更好的全局尋優能力;采用概率化的尋優方法,不需要確定的規則就能自動獲取和指導優化的搜索空間,自適應地調整搜索方向。
???????遺傳算法以一種群體中的所有個體為對象,并利用隨機化技術指導對一個被編碼的參數空間進行高效搜索。其中,選擇、交叉和變異構成了遺傳算法的遺傳操作;參數編碼、初始群體的設定、適應度函數的設計、遺傳操作設計、控制參數設定五個要素組成了遺傳算法的核心內容。
相關術語:
? 基因型(genotype):性狀染色體的內部表現;
? 表現型(phenotype):染色體決定的性狀的外部表現,或者說,根據基因型形成的個體的外部表現;
? 進化(evolution):種群逐漸適應生存環境,品質不斷得到改良。生物的進化是以種群的形式進行的。
? 適應度(fitness):度量某個物種對于生存環境的適應程度。
? 選擇(selection):以一定的概率從種群中選擇若干個個體。一般,選擇過程是一種基于適應度的優勝劣汰的過程。
? 復制(reproduction):細胞分裂時,遺傳物質DNA通過復制而轉移到新產生的細胞中,新細胞就繼承了舊細胞的基因。
? 交叉(crossover):兩個染色體的某一相同位置處DNA被切斷,前后兩串分別交叉組合形成兩個新的染色體。也稱基因重組或雜交;
? 變異(mutation):復制時可能(很小的概率)產生某些復制差錯,變異產生新的染色體,表現出新的性狀。
? 編碼(coding):DNA中遺傳信息在一個長鏈上按一定的模式排列。遺傳編碼可看作從表現型到基因型的映射。
? 解碼(decoding):基因型到表現型的映射。
? 個體(individual):指染色體帶有特征的實體;
? 種群(population):個體的集合,該集合內個體數稱為種群。
3.2 遺傳算法的基本流程
???????遺傳算法的搜索特點是以編碼空間代替問題的參數空間,以適應度函數為評價依據;將編碼集作為遺傳的基礎,對個體進行遺傳操作,建立一個迭代過程。首先,算法從一個由個體組成的種群開始,對每個種群個體進行適應度評價;其次,利用個體的適應度選擇個體,并利用交叉和變異等遺傳算子作用其上,產生后代個體;最后,在原種群個體和后代個體中選擇個體生成下一代種群。
3.3 編碼
???????染色體作為遺傳物質的主要載體,即多個基因的集合,其內部表現(即基因型)是某種基因組合,它決定了個體的形狀的外部表現,如黑頭發的特征是由染色體中控制這一特征的某種基因組合決定的。因此,在一開始需要實現從表現型到基因型的映射即編碼工作。
???????遺傳算法的編碼有浮點編碼、二進制編碼和符號編碼,這里只介紹二進制編碼規則。二進制編碼既符合計算機處理信息的原理,也方便了對染色體進行遺傳、編譯和突變等操作。設某一參數的取值范圍為(L,U),使用長度為k的二進制編碼表示該參數,則它共有2^k種不同的編碼。該參數編碼時的對應關系為
???????易知其取值精度δ滿足關系:
δ = ( U ? L ) / ( 2 k ? 1 ) δ=(U-L)/(2^k-1) δ=(U?L)/(2k?1)
???????假設用長度為k的二進制編碼表示該參數,編碼為 x : b k b ( k ? 1 ) b ( k ? 2 ) b ( k ? 3 ) … b 2 b 1 x:b_k b_(k-1) b_(k-2) b_(k-3)…b_2 b_1 x:bk?b(?k?1)b(?k?2)b(?k?3)…b2?b1?,對應的解碼公式為:
3.4 適應度函數
???????為了體現染色體的適應能力,區分種群中個體的好壞,遺傳算法引入了對問題中的每個染色體都能進行度量的函數,即適應度函數。通過適應度函數來決定染色體的優劣程度,它體現了自然進化中的優勝劣汰原則。在簡單問題的優化時,通常可以直接將目標函數換成適應度函數。在復雜問題的優化時,往往需要構造合適的評價函數,使其適應遺傳算法進行優化。好的適應度函數能夠真實反映優化的情況,找到問題真正的最優解,質量差的適應度函數可能是的優化后的解不可用。
3.5選擇算子
???????選擇算子體現了自然界中優勝劣汰的基本規律。個體的適應度值所度量的優劣程度決定了它在下一代是被淘汰還是被遺傳,從而提高全局收斂性和計算效率。一般來說,如果該個體適應度函數值比較大,則它存在的概率也比較大。
???????通常采用的選擇方法有:輪盤賭選擇,競爭選擇,隨機遍歷抽樣選擇,競標賽選擇等。其中最知名的為輪盤賭選擇,其基本原理是:首先計算種群中個體的適應度值,然后計算該個體的適應度值在該種群中所占的比例,該比例就為該個體的選擇概率或生存概率。
???????個體 x i x_i xi?的選擇概率如下:
???????其中, f ( x i ) f(x_i) f(xi?)為個體的適應度值,N為種群的規模大小。根據這個概率分布選取N個個體產生下一代種群。
3.6 交叉算子
???????遺傳算法的交叉操作,是指對兩個相互配對的染色體按某種方式相互交換其部分基因,從而形成兩個新的個體。
???????交叉算子體現了信息交換的思想。交叉又稱為重組,是按較大的概率從種群中選擇兩個個體,交換兩個個體的某個或某些位。其作用是組合出新的個體,在編碼串空間進行有效搜索,同時降低對有效模式的破壞概率。交叉算子的設計包括如何確定交叉點的位置和如何交換兩個方面,但在設計交叉算子時,需要保證前一代中有優秀個體的性狀能夠在后一代的新個體中盡可能得到遺傳和繼承。
???????個體采用二進制編碼時,常用的交叉算子有單點交叉,兩點交叉和均勻交叉。
???????1,單點交叉(One-point Crossover):指在個體編碼串中只隨機設置一個交叉點,然后再該點相互交換兩個配對個體的部分染色體。
??????? 2,兩點交叉與多點交叉:
???????兩點交叉(Two-point Crossover):在個體編碼串中隨機設置了兩個交叉點,然后再進行部分基因交換。
???????多點交叉(Multi-point Crossover)
???????3,均勻交叉(也稱一致交叉,Uniform Crossover):兩個配對個體的每個基因座上的基因都以相同的交叉概率進行交換,從而形成兩個新個體。
3.7 變異算子
???????變異算子是指從種群中隨機選擇一個個體,以變異概率對個體編碼串上的某個或某些位置進行改變,經過變異后形成一個新的染色體。在遺傳算法中,能夠保持種群多樣性的一個主要途徑就是通過個體變異。
???????? 基本位變異(Simple Mutation):對個體編碼串中以變異概率、隨機指定的某一位或某幾位僅因座上的值做變異運算。
???????? 均勻變異(Uniform Mutation):分別用符合某一范圍內均勻分布的隨機數,以某一較小的概率來替換個體編碼串中各個基因座上的原有基因值。(特別適用于在算法的初級運行階段)
???????? 邊界變異(Boundary Mutation):隨機的取基因座上的兩個對應邊界基因值之一去替代原有基因值。特別適用于最優點位于或接近于可行解的邊界時的一類問題。
???????? 非均勻變異:對原有的基因值做一隨機擾動,以擾動后的結果作為變異后的新基因值。對每個基因座都以相同的概率進行變異運算之后,相當于整個解向量在解空間中作了一次輕微的變動。
???????? 高斯近似變異:進行變異操作時用符號均值為P的平均值,方差為P**2的正態分布的一個隨機數來替換原有的基因值。
四、問題求解
4.1 低維單目標優化問題
4.1.1 凸函數
???????求解函數f(x)的最大值,設置函數為
f ( x , y ) = ? ( x 2 + y 2 ) f(x,y)=-(x^2+y^2) f(x,y)=?(x2+y2)
???????其函數圖像如圖所示,根據遺傳算法求解其最大值。
???????設置編碼長度為24,種群數量為200,交叉概率為0.8,變異概率為0.01。由于每一代都會產生一個最優得適應度值,迭代100代,得到其收斂曲線如圖:
???????最終得到其在(0,0)處得最優解為0 。
4.1.2 非凸函數
???????其圖像如圖所示
???????根據遺傳算法求解得:
???????最優的基因型: [1 1 0 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 0 1 0 0 0 0 0 0 1 0 0 1 0 1 1 1 1 1 1 1 0 1 1 1 1]
???????(x, y): (0.023550332996268963, 1.4934538896950418)
???????得到其最大值為:0.026285520703649645
4.2 高維單目標優化問題
f ( m , x , y , z ) = s i n ? ( √ ( m 2 + x 2 ) + √ ( y 2 + z 2 ) ) f(m,x,y,z)=sin?(√(m^2+x^2 )+√(y^2+z^2 )) f(m,x,y,z)=sin?(√(m2+x2)+√(y2+z2))
???????其收斂過程為:
???????得到其在(x, y, m, z): (4.184986900388413, -2.2360853693536145, 3.0514268905774884, -1.4670375863932121)取得最優解0.0728843932140556。
4.3 TSP問題
???????旅行商問題,給定N個城市得坐標,商人隨機選擇其中一個城市開始旅行,要求為通過隨給得所有城市且每個城市只能通過一次,求解如何安排才可以是的路徑得長度最小。
???????由于給出的只是經緯度的數據,理論上應該根據具體的換算公式計算出實際距離,但是本題只是為了使用遺傳算法,所以就直接根據經緯度的點來做的,并未做具體的轉化。根據給出每個城市得坐標,得到城市的分布散點圖如圖:
???????由于TSP問題與求解函數最優解不同,需要對各個城市進行編碼,我們選擇城市并對其進行順序排列,每個城市都有一個序號代表,并對其序號進行二進制編碼。
???????每兩個城市之間都可以互通,兩個城市之間的距離用兩點之間的距離直接衡量,最后的總距離為整個路徑總長,并以此為適應度值,由此問題轉化為求解最小路徑總和。
???????選擇種群數為100,迭代次數為500,變異概率為0.1。
???????得到其路徑為:[21, 20, 1, 2, 7, 3, 22, 0, 23, 24, 19, 26, 17, 25, 13, 18, 14, 12, 10, 4, 8, 5, 6, 9, 11, 16],路徑總長為:155.0823114848274
五、結果分析
???????由遺傳算法的原理及對三類問題的求解可以得知各個因素對結果的影響。
???????適應度函數是求解問題的關鍵,比如在求解TSP問題時,選擇路徑長度作為適應度函數,而在求解函數的最大值問題是則是直接以函數值作為適應度值,因此在求解實際問題時根據問題的特點設置適當的適應度函數可以使算法更快的收斂。
???????編碼長度決定了種群數量的大小,如果編碼長度為N,則這個種群的最大數量為2^N,而種群數量決定了之后的一系列遺傳變異等操作,只有保持了種群數量足夠多,才有可能產生交叉變異等操作,算法可以很快收斂,但是種群數量的增多會導致運算量上升。
???????交叉和變異是種群中個體更新的主要方式,由于很多問題的表示函數并不是簡單的凸函數只有一個極值點,而是非凸函數,所以可能存在多個極值點,而大多數算法根據起始點的不同,很大概率只能找到局部最優點,而無法找到全局最優點,但是遺傳算法根據交叉和變異,使得種群中隨時可能產生新的個體,所以往往可以找到較優的結果。
六、遺傳算法的拓展
???????雖然GA在許多優化問題中都有成功的應用 ,但其本身也存在一些不足 .例如局部搜索能力差、存在未成熟收斂和隨機漫游等現象 ,從而導致算法的收斂性能差 ,需要很長時間才能找到最優解 ,這些不足阻礙了遺傳算法的推廣應用。
6.1 關于編碼方式的改進
???????二進制編碼不能直接反映問題的固有結構 ,精度不高 ,個體長度大 ,占用計算機內存多。
???????Gray編碼是將二進制編碼通過一個變換進行轉換得到的編碼 ,其目的就是克服 Hamming懸崖的缺點。
???????動態編碼 (dynamic encoding)GA是當算法收斂到某局部最優時增加搜索的精度 ,從而使得在全局最優點附近可以進行更精確的搜索 ,增加精度的辦法是在保持串長不變的前提下減小搜索區域。
???????對于問題的變量是實向量的情形 ,可以直接采用實數進行編碼 ,這樣可以直接在解的表現型上進行遺傳操作 ,從而便于引入與問題領域相關的啟發式信息以增加算法的搜索能力。
???????復數編碼的GA是為了描述和解決二維問題 ,基因用 x+yi 表示 ;其還可以推廣到多維問題的描述中。
???????多維實數編碼,使無效交叉發生的可能性大大降低 ,同時其合理的編碼長度也有助于算法在短時間內獲得高精度的全局最優解。
???????在組合優化中 ,可以使用有序串編碼 ,例如VRP問題。
???????當問題的表示是樹和圖時 ,我們還可以使用結構式編碼。
6.2 關于選擇策略的改進
???????輪盤賭法是使用最多的選擇策略 ,但這種策略可能會產生較大的抽樣誤差 ,于是對此提出了很多的改進方法 ,如繁殖池選擇,Boltzmann選擇等等 .但是這幾種策略都是基于適應值比例的選擇 ,常常會出現早熟收斂現象和停滯現象。
???????非線性排名選擇,這種選擇不僅避免了上述問題 ,而且可以直接使用原始適應值進行排名選擇 ,而不需對適應值進行標準化 ;但這種選擇在群體規模很大時 ,其額外計算量 (如計算總體適應值和排序 )也相當可觀 ,甚至在進行并行實現時有時要帶來一些同步限制。
???????基于局部競爭機制的選擇如 ( λ + μ ) (λ+μ) (λ+μ)選擇,它使雙親和后代有同樣的生存競爭機會在一定程度上避免了這些問題。
七、python代碼
7.1 函數優化
import numpy as np import matplotlib.pyplot as plt DNA_SIZE = 24 POP_SIZE = 300 # 種群數量 CROSSOVER_RATE = 0.8 # 交叉概率 MUTATION_RATE = 0.01 # 變異概率 N_GENERATIONS = 200 # 迭代次數 X_BOUND = [-5, 5] # X的范圍 Y_BOUND = [-5, 5] # Y的范圍 # m_BOUND = [-5, 5] # z_BOUND = [-5, 5] # 定義函數 # def F(x, y, m, z): # # f = np.sin(np.sqrt(x**2 + y**2)) # # f = -(x**2+y**2) # f = np.sin(np.sqrt(m**2 + x**2)+np.sqrt(y**2 + z**2)) # return f def F(x, y):f = -(x**2+y**2)return f # 根據編碼翻譯為真實數據 def translateDNA(pop): x_pop = pop[:, 1::2] y_pop = pop[:, ::2] # m_pop = pop[:, 2::4]# z_pop = pop[:, 3::4]x = x_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(X_BOUND[1]-X_BOUND[0])+X_BOUND[0]y = y_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(Y_BOUND[1]-Y_BOUND[0])+Y_BOUND[0]# m = m_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(m_BOUND[1]-m_BOUND[0])+m_BOUND[0]# z = z_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(z_BOUND[1]-z_BOUND[0])+z_BOUND[0]return x, y, m, z# 計算適應度值 def get_fitness(pop):x, y = translateDNA(pop)# x, y, m, z =translateDNA(pop)pred = F(x, y)return (pred - np.min(pred)) # 交叉和變異 def crossover_and_mutation(pop, CROSSOVER_RATE = 0.8):new_pop = []for father in pop: # 遍歷種群中的每一個個體,將該個體作為父親child = father if np.random.rand() < CROSSOVER_RATE: mother = pop[np.random.randint(POP_SIZE)] cross_points = np.random.randint(low=0, high=DNA_SIZE*2) child[cross_points:] = mother[cross_points:] mutation(child) new_pop.append(child)return new_pop# 變異 def mutation(child, MUTATION_RATE=0.003):if np.random.rand() < MUTATION_RATE: mutate_point = np.random.randint(0, DNA_SIZE) child[mutate_point] = child[mutate_point]^1 # 選擇 def select(pop, fitness):idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=(fitness)/(fitness.sum()) )return pop[idx]def print_info(pop):fitness = get_fitness(pop)max_fitness_index = np.argmax(fitness)print("max_fitness:", fitness[max_fitness_index])x, y = translateDNA(pop)# x, y, m, z = translateDNA(pop)print("最優的基因型:", pop[max_fitness_index])print("(x, y):", (x[max_fitness_index], y[max_fitness_index]))# print("(x, y, m, z):", (x[max_fitness_index], y[max_fitness_index], m[max_fitness_index], z[max_fitness_index]))if __name__ == "__main__":pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE*2))fitness_record = []for _ in range(N_GENERATIONS): # 迭代N代x, y = translateDNA(pop)# x, y, m, z = translateDNA(pop)pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))fitness = get_fitness(pop)pop = select(pop, fitness) # 選擇生成新的種群fitness = get_fitness(pop)max_fitness_index = np.argmax(fitness)fitness_record.append(fitness[max_fitness_index]) # 記錄每一代的最優值print_info(pop)# 畫出適應度值得變化函數plt.figure(1)axis_x = [i for i in range(len(fitness_record))]plt.plot(axis_x, fitness_record)plt.grid()plt.xlabel('N_GENERATIONS')plt.ylabel('fitness')plt.show()# 畫出函數圖像,只能可視化低維函數# fig = plt.figure(2)# ax = fig.gca(projection='3d')# x = np.arange(-5, 5, 0.1)# y = np.arange(-5, 5, 0.1)# x, y =np.meshgrid(x, y)# # z = -(x**2+y**2)# z = np.sin(np.sqrt(x ** 2 + y ** 2))# surf = ax.plot_surface(x, y, z)# plt.show()7.2 TSP
import numpy as np import matplotlib.pyplot as plt import math import random# 載入數據 city_condition=[[106.54,29.59], [91.11,29.97], [87.68,43.77], [106.27,38.47], [123.38,41.8], [114.48,38.03], [112.53,37.87], [101.74,36.56], [117,36.65], [113.6,34.76], [118.78,32.04], [117.27,31.86], [120.19,30.26], [119.3,26.08], [115.89,28.68], [113,28.21], [114.31,30.52], [113.23,23.16], [121.5,25.05], [110.35,20.02], [103.73,36.03], [108.95,34.27], [104.06,30.67], [106.71,26.57], [102.73,25.04], [114.1,22.2], [113.33,22.13]] city_condition = np.array(city_condition)# 展示地圖 plt.figure(1) plt.scatter(city_condition[:, 0], city_condition[:, 1]) plt.grid() plt.show()# 距離矩陣 city_count = len(city_condition) Distance = np.zeros([city_count, city_count]) for i in range(city_count):for j in range(city_count):Distance[i][j] = math.sqrt((city_condition[i][0]-city_condition[j][0])**2+(city_condition[i][1]-city_condition[j][1])**2)count = 100 # 種群數 improve_count = 100 # 改良次數 itter_time = 500 # 進化次數 retain_rate = 0.3 # 設置強者的定義概率,即種群前30%為強者 random_select_rate = 0.5 # 設置弱者的存活概率 mutation_rate = 0.1 # 變異率 origin = 15 # 設置起點 index = [i for i in range(city_count)] index.remove(15)# 總距離 def get_total_distance(x):distance = 0distance += Distance[origin][x[0]]for i in range(len(x)):if i == len(x)-1:distance += Distance[origin][x[i]]else:distance += Distance[x[i]][x[i+1]]return distancedef improve(x):i = 0distance = get_total_distance(x)while i<improve_count:u=random.randint(0,len(x)-1)v = random.randint(0, len(x)-1)if u!=v:new_x=x.copy()t=new_x[u]new_x[u]=new_x[v]new_x[v]=tnew_distance=get_total_distance(new_x)if new_distance<distance:distance=new_distancex=new_x.copy()else:continuei+=1# 自然選擇 def selection(population):# 對總距離從小到大進行排序graded = [[get_total_distance(x), x] for x in population]graded = [x[1] for x in sorted(graded)]# 選出適應性強的染色體retain_length = int(len(graded) * retain_rate)parents = graded[:retain_length]# 選出適應性不強,但是幸存的染色體for chromosome in graded[retain_length:]:if random.random() < random_select_rate:parents.append(chromosome)return parents# 交叉繁殖 def crossover(parents):# 生成子代的個數,以此保證種群穩定target_count = count - len(parents)# 孩子列表children = []while len(children) < target_count:male_index = random.randint(0, len(parents) - 1)female_index = random.randint(0, len(parents) - 1)if male_index != female_index:male = parents[male_index]female = parents[female_index]left = random.randint(0, len(male) - 2)right = random.randint(left + 1, len(male) - 1)# 交叉片段gene1 = male[left:right]gene2 = female[left:right]child1_c = male[right:] + male[:right]child2_c = female[right:] + female[:right]child1 = child1_c.copy()child2 = child2_c.copy()for o in gene2:child1_c.remove(o)for o in gene1:child2_c.remove(o)child1[left:right] = gene2child2[left:right] = gene1child1[right:] = child1_c[0:len(child1) - right]child1[:left] = child1_c[len(child1) - right:]child2[right:] = child2_c[0:len(child1) - right]child2[:left] = child2_c[len(child1) - right:]children.append(child1)children.append(child2)return children# 變異 def mutation(children):for i in range(len(children)):if random.random() < mutation_rate:child = children[i]u = random.randint(1,len(child)-4)v = random.randint(u+1, len(child)-3)w = random.randint(v+1, len(child)-2)child = children[i]child = child[0:u]+child[v:w]+child[u:v]+child[w:]# 得到最佳純輸出結果 def get_result(population):graded = [[get_total_distance(x), x] for x in population]graded = sorted(graded)return graded[0][0], graded[0][1]#初始化種群 population = [] for i in range(count):# 隨機生成個體x = index.copy()random.shuffle(x)improve(x)population.append(x) register = [] i = 0 distance, result_path = get_result(population) while i < itter_time:parents = selection(population) # 選擇繁殖個體群children = crossover(parents) # 交叉繁殖mutation(children) # 變異操作population = parents + children # 更新種群distance, result_path = get_result(population)register.append(distance)i = i + 1 print(distance) print(result_path) result_path = [origin] + result_path + [origin] X = [] Y = [] for index in result_path:X.append(city_condition[index, 0])Y.append(city_condition[index, 1]) plt.figure(2) plt.plot(X, Y, '-o') plt.xlabel('Longitude') plt.ylabel('Latitude') plt.grid() plt.show() plt.figure(3) plt.plot(list(range(len(register))), register) plt.xlabel('Iterations') plt.ylabel('Path Length') plt.grid() plt.show()總結
以上是生活随笔為你收集整理的遗传算法求解函数优化及TSP问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 半入耳蓝牙耳机哪款好?音质好高性价比的半
- 下一篇: 纯属巧合,解决了一个困扰许久的问题,关于