python闭环最短路径_深度学习经典算法 | 蚁群算法解析
蟻群算法基本思想
蟻群算法的基本原理來源于自然界中螞蟻覓食的最短路徑問題。根據(jù)昆蟲學(xué)家的觀察,發(fā)現(xiàn)自然界的螞蟻雖然視覺不發(fā)達(dá),但它可以在沒有任何提示的情況下找到從食物源到巢穴的最短路徑,并且能在環(huán)境發(fā)生變化(如原有路徑上有了障礙物)后,自適應(yīng)地搜索新的最佳路徑。螞蟻是如何做到這一點(diǎn)的呢?
原來,螞蟻在尋找食物源時(shí),能在其走過的路徑上釋放一種螞蟻特有的分泌物一信息激素一也可稱之為信息素,使得一定范圍內(nèi)的其他螞蟻能夠察覺到并由此影響它們以后的行為。當(dāng)一些路徑上通過的螞蟻越來越多時(shí),其留下的信息素也越來越多,以致信息素強(qiáng)度增大(當(dāng)然,隨時(shí)間的推移會(huì)逐漸減弱),所以螞蟻選擇該路徑的概率也越高,從而更增加了該路徑的信息素強(qiáng)度,這種選擇過程被稱之為螞蟻的自催化行為。由于其原理是一種正反饋機(jī)制.因此,也可將螞蟻王國(guó)理解為所謂的增強(qiáng)型學(xué)習(xí)系統(tǒng)。
在自然界中,蟻群的這種尋找路徑的過程表現(xiàn)為一種正反饋過程,“蟻群算法”就是模仿生物學(xué)螞蟻群覓食尋找最優(yōu)路徑原理衍生出來的。
蟻群算法數(shù)學(xué)模型
應(yīng)該說前面介紹的蟻群算法只是一種算法思想,要是想真正應(yīng)用該算法,還需要針對(duì)一個(gè)特定問題, 建立相應(yīng)的數(shù)學(xué)模型。現(xiàn)仍以經(jīng)典的TSP問題為例,來進(jìn)一步闡述如何基于蟻群算法來求解實(shí)際問題。
對(duì)于TSP問題,為不失一般性,設(shè)整個(gè)螞蟻群體中螞蟻的數(shù)量為m,城市的數(shù)量為n,城市i與城市j之間的距離為
(i,j=1,2,…,n),t時(shí)刻城市i與城市j連接路徑上的信息素濃度為
(t)。初始時(shí)刻,螞蟻被放置在不同的城市里,且各城市間連接路徑上的信息素濃度相同,不妨設(shè)
(0)=
(0)。然后螞蟻將按一定概率選擇線路,不妨設(shè)
為t時(shí)刻螞蟻k從城市i轉(zhuǎn)移到城市j的概率。我們知道,“螞蟻TSP”策略會(huì)受到兩方面的左右,首先是訪問某城市的期望,另外便是其他螞蟻釋放的信息素濃度,所以定義:
其中,
為啟發(fā)函數(shù),表示螞蟻從城市i轉(zhuǎn)移到城市j的期望程度:
(k=1, 2, …, m)為螞蟻k待訪問城市集合,開始時(shí),
中有n一1個(gè)元素,即包括除了螞蟻k出發(fā)城市的其他多有城市, 隨著時(shí)間的推移,
中的元素越來越少,直至為空;a為信息素重要程度因子,簡(jiǎn)稱信息度因子。其值越大,表示信息影響強(qiáng)度越大;
為啟發(fā)函數(shù)重要程度因子,簡(jiǎn)稱啟發(fā)函數(shù)因子,其值越大,表明啟發(fā)函數(shù)影響越大。
在螞蟻遍歷城市的過程中,與實(shí)際情況相似的是,在螞蟻釋放信息素的同時(shí),各個(gè)城市間連接路徑上的信息素的強(qiáng)度也在通過揮發(fā)等方式逐漸消失。為了描述這一特征,不妨令p(0
其中,
為第k只螞蟻在城市i與城市j連接路徑上釋放信息素而增加的信息素濃度;
為所有螞蟻在城市i與城市j連接路徑上釋放信息素而增加的信息素濃度。
一般
的值可由ant cycle system模型進(jìn)行計(jì)算:
其中,Q為信息素常數(shù),表示螞蟻循環(huán)一次所釋放的信息素總量;
為第k只螞蟻經(jīng)過路徑的總長(zhǎng)度。
蟻群算法流程
用蟻群算法求解TSP問題的算法流程如下圖所示,具體每步的含義如下:步驟1:對(duì)相關(guān)參數(shù)進(jìn)行初始化,包括蟻初始化群規(guī)模、信息素因子、啟發(fā)函數(shù)因子、信息素、揮發(fā)因子、信息素常數(shù)、最大迭代次數(shù)等,以及將數(shù)據(jù)讀人程序,并對(duì)數(shù)據(jù)進(jìn)行基本的處理,如將城市的坐標(biāo)位置,轉(zhuǎn)為城市間的矩陣。
步驟2:隨機(jī)將螞蟻放于不同的出發(fā)點(diǎn),對(duì)每個(gè)螞蟻計(jì)算其下一個(gè)訪問城市,直至所更新信息素表有螞蟻訪問完所有城市。
步驟3:計(jì)算各個(gè)螞蟻經(jīng)過的路徑長(zhǎng)度
,記錄當(dāng)前迭代次數(shù)中的最優(yōu)解,同時(shí)對(duì)各個(gè)城市連接路徑上的信息素濃度進(jìn)行更新。
步驟4:判斷是否達(dá)到最大迭代次數(shù),若否,則返回步驟2,否則終止程序。
步驟5:輸出程序結(jié)果,并根據(jù)需要輸出程序?qū)?yōu)過程中的相關(guān)指標(biāo),如運(yùn)行時(shí)間、收斂迭代次數(shù)等。
python簡(jiǎn)單實(shí)現(xiàn)
import numpy as np
import matplotlib.pyplot as plt
# 建立“螞蟻”類
class Ant(object):
def __init__(self, path):
self.path = path # 螞蟻當(dāng)前迭代整體路徑
self.length = self.calc_length(path) # 螞蟻當(dāng)前迭代整體路徑長(zhǎng)度
def calc_length(self, path_): # path=[A, B, C, D, A]注意路徑閉環(huán)
length_ = 0
for i in range(len(path_)-1):
delta = (path_[i].x - path_[i+1].x, path_[i].y - path_[i+1].y)
length_ += np.linalg.norm(delta)
return length_
@staticmethod
def calc_len(A, B): # 靜態(tài)方法,計(jì)算城市A與城市B之間的距離
return np.linalg.norm((A.x - B.x, A.y - B.y))
# 建立“城市”類
class City(object):
def __init__(self, x, y):
self.x = x
self.y = y
# 建立“路徑”類
class Path(object):
def __init__(self, A): # A為起始城市
self.path = [A, A]
def add_path(self, B): # 追加路徑信息,方便計(jì)算整體路徑長(zhǎng)度
self.path.append(B)
self.path[-1], self.path[-2] = self.path[-2], self.path[-1]
# 構(gòu)建“蟻群算法”的主體
class ACO(object):
def __init__(self, ant_num=50, maxIter=300, alpha=1, beta=5, rho=0.1, Q=1):
self.ants_num = ant_num # 螞蟻個(gè)數(shù)
self.maxIter = maxIter # 蟻群最大迭代次數(shù)
self.alpha = alpha # 信息啟發(fā)式因子
self.beta = beta # 期望啟發(fā)式因子
self.rho = rho # 信息素?fù)]發(fā)速度
self.Q = Q # 信息素強(qiáng)度
###########################
self.deal_data('coordinates.dat') # 提取所有城市的坐標(biāo)信息
###########################
self.path_seed = np.zeros(self.ants_num).astype(int) # 記錄一次迭代過程中每個(gè)螞蟻的初始城市下標(biāo)
self.ants_info = np.zeros((self.maxIter, self.ants_num)) # 記錄每次迭代后所有螞蟻的路徑長(zhǎng)度信息
self.best_path = np.zeros(self.maxIter) # 記錄每次迭代后整個(gè)蟻群的“歷史”最短路徑長(zhǎng)度
###########################
self.solve() # 完成算法的迭代更新
self.display() # 數(shù)據(jù)可視化展示
def deal_data(self, filename):
with open(filename, 'rt') as f:
temp_list = list(line.split() for line in f) # 臨時(shí)存儲(chǔ)提取出來的坐標(biāo)信息
self.cities_num = len(temp_list) # 1. 獲取城市個(gè)數(shù)
self.cities = list(City(float(item[0]), float(item[1])) for item in temp_list) # 2. 構(gòu)建城市列表
self.city_dist_mat = np.zeros((self.cities_num, self.cities_num)) # 3. 構(gòu)建城市距離矩陣
for i in range(self.cities_num):
A = self.cities[i]
for j in range(i, self.cities_num):
B = self.cities[j]
self.city_dist_mat[i][j] = self.city_dist_mat[j][i] = Ant.calc_len(A, B)
self.phero_mat = np.ones((self.cities_num, self.cities_num)) # 4. 初始化信息素矩陣
# self.phero_upper_bound = self.phero_mat.max() * 1.2 ###信息素濃度上限
self.eta_mat = 1/(self.city_dist_mat + np.diag([np.inf]*self.cities_num)) # 5. 初始化啟發(fā)函數(shù)矩陣
def solve(self):
iterNum = 0 # 當(dāng)前迭代次數(shù)
while iterNum < self.maxIter:
self.random_seed() # 使整個(gè)蟻群產(chǎn)生隨機(jī)的起始點(diǎn)
delta_phero_mat = np.zeros((self.cities_num, self.cities_num)) # 初始化每次迭代后信息素矩陣的增量
##########################################################################
for i in range(self.ants_num):
city_index1 = self.path_seed[i] # 每只螞蟻訪問的第一個(gè)城市下標(biāo)
ant_path = Path(self.cities[city_index1]) # 記錄每只螞蟻訪問過的城市
tabu = [city_index1] # 記錄每只螞蟻訪問過的城市下標(biāo),禁忌城市下標(biāo)列表
non_tabu = list(set(range(self.cities_num)) - set(tabu))
for j in range(self.cities_num-1): # 對(duì)余下的城市進(jìn)行訪問
up_proba = np.zeros(self.cities_num-len(tabu)) # 初始化狀態(tài)遷移概率的分子
for k in range(self.cities_num-len(tabu)):
up_proba[k] = np.power(self.phero_mat[city_index1][non_tabu[k]], self.alpha) * \
np.power(self.eta_mat[city_index1][non_tabu[k]], self.beta)
proba = up_proba/sum(up_proba) # 每條可能子路徑上的狀態(tài)遷移概率
while True: # 提取出下一個(gè)城市的下標(biāo)
random_num = np.random.rand()
index_need = np.where(proba > random_num)[0]
if len(index_need) > 0:
city_index2 = non_tabu[index_need[0]]
break
ant_path.add_path(self.cities[city_index2])
tabu.append(city_index2)
non_tabu = list(set(range(self.cities_num)) - set(tabu))
city_index1 = city_index2
self.ants_info[iterNum][i] = Ant(ant_path.path).length
if iterNum == 0 and i == 0: # 完成對(duì)最佳路徑城市的記錄
self.best_cities = ant_path.path
else:
if self.ants_info[iterNum][i] < Ant(self.best_cities).length: self.best_cities = ant_path.path
tabu.append(tabu[0]) # 每次迭代完成后,使禁忌城市下標(biāo)列表形成完整閉環(huán)
for l in range(self.cities_num):
delta_phero_mat[tabu[l]][tabu[l+1]] += self.Q/self.ants_info[iterNum][i]
self.best_path[iterNum] = Ant(self.best_cities).length
self.update_phero_mat(delta_phero_mat) # 更新信息素矩陣
iterNum += 1
def update_phero_mat(self, delta):
self.phero_mat = (1 - self.rho) * self.phero_mat + delta
# self.phero_mat = np.where(self.phero_mat > self.phero_upper_bound, self.phero_upper_bound, self.phero_mat) # 判斷是否超過濃度上限
def random_seed(self): # 產(chǎn)生隨機(jī)的起始點(diǎn)下表,盡量保證所有螞蟻的起始點(diǎn)不同
if self.ants_num <= self.cities_num: # 螞蟻數(shù) <= 城市數(shù)
self.path_seed[:] = np.random.permutation(range(self.cities_num))[:self.ants_num]
else: # 螞蟻數(shù) > 城市數(shù)
self.path_seed[:self.cities_num] = np.random.permutation(range(self.cities_num))
temp_index = self.cities_num
while temp_index + self.cities_num <= self.ants_num:
self.path_seed[temp_index:temp_index + self.cities_num] = np.random.permutation(range(self.cities_num))
temp_index += self.cities_num
temp_left = self.ants_num % self.cities_num
if temp_left != 0:
self.path_seed[temp_index:] = np.random.permutation(range(self.cities_num))[:temp_left]
def display(self): # 數(shù)據(jù)可視化展示
plt.figure(figsize=(6, 10))
plt.subplot(211)
plt.plot(self.ants_info, 'g.')
plt.plot(self.best_path, 'r-', label='history_best')
plt.xlabel('Iteration')
plt.ylabel('length')
plt.legend()
plt.subplot(212)
plt.plot(list(city.x for city in self.best_cities), list(city.y for city in self.best_cities), 'g-')
plt.plot(list(city.x for city in self.best_cities), list(city.y for city in self.best_cities), 'r.')
plt.xlabel('x')
plt.ylabel('y')
plt.savefig('ACO.png', dpi=500)
plt.show()
plt.close()
ACO()
輸出:
參考文獻(xiàn)
[2]《matlab在數(shù)學(xué)建模中的應(yīng)用》
總結(jié)
以上是生活随笔為你收集整理的python闭环最短路径_深度学习经典算法 | 蚁群算法解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何隐藏地址栏中的真实地址_Firefo
- 下一篇: python字符串前面去两位_在Pyth