蚁群算法
- 推荐看b站的这个视频,蚁群算法简介
原理介绍
- 1,若蚂蚁从A点出发,速度相同,食物在D点,则它可能随机选择路线ABD或ACD。假设初始时每条路线分配一只蚂蚁,每个时间单位行走一步。图5.1所示为经过8个时间单位时的情形:走路线ABD的蚂蚁到达终点;而走路线ACD的蚂蚁刚好走到C点,为一半路程。如图所示:
- 2,图5.2表示从开始算起,经过16个时间单位时的情形:走路线ABD的蚂蚁到达终点后得到食物又返回了起点A,而走路线ACD的蚂蚁刚好走到D点。
- 3,假设蚂蚁每经过一处所留下的信息素为1个单位,则经过32个时间单位后,所有开始一起出发的蚂蚁都经过不同路径从D点取得了食物。此时ABD的路线往返了2趟,每一处的信息素为4个单位;而ACD的路线往返了一趟,每一处的信息素为2个单位,其比值为2∶1。
- 4,寻找食物的过程继续进行,则按信息素的指导,蚁群在ABD路线上增派一只蚂蚁(共2只),而ACD路线上仍然为一只蚂蚁。再经过32个时间单位后,两条线路上的信息素单位积累为12和4,比值为3∶1。
- 5,若按以上规则继续,蚁群在ABD路线上再增派一只蚂蚁(共3只),而ACD路线上仍然为一只蚂蚁。再经过32个时间单位后,两条线路上的信息素单位积累为24和6,比值为4∶1。
- 6,若继续进行,则按信息素的指导,最终所有的蚂蚁都会放弃ACD路线,而选择ABD路线。这也就是前面所提到的正反馈效应。
蚁群算法求解旅行商
我们的任务是找到一条线路遍历所有城市的路程最短,这就是旅行商问题,城市坐标数据如下:
蚁群算法流程图
Python重写
import numpy as np
import pandas as pd
from numpy import random
import matplotlib
import matplotlib.pyplot as plt
class ACO:
def __init__(self,m,alpha,beta,rho,G,Q,data):
'''
:param m: 蚂蚁个数
:param alpha: 信息素重要程度
:param beta: 启发式因子重要程度
:param rho: 信息素蒸发系数
:param G: 最大迭代次数
:param Q: 信息数增加强度系数
:param data: 坐标矩阵
'''
self.m = m
self.alpha = alpha
self.beta = beta
self.rho = rho
self.G = G
self.Q = Q
self.data = data
# 两点直接距离公式
def cd(self,x1, x2):
d = (sum((x1 - x2) ** 2)) ** 0.5
return d
def aco(self):
# 第一步:初始化变量
n = len(self.data) # 获取城市个数
D = np.zeros((n,n)) # 城市距离矩阵
for i in range(n): # 计算距离矩阵
for j in range(n):
if i == j:
D[i, j] = np.spacing(1)
elif i < j:
D[i, j] = self.cd(self.data[i], self.data[j])
else:
D[i, j] = D[j, i]
Eta = 1/D # 启发因子,距离倒数
Tau = np.ones((n,n)) # 信息素矩阵
Tabu = np.zeros((self.m,n),dtype=np.int32) # 存储并记录路径生成
R_best = np.zeros((self.G,n),dtype=np.int32) # 各代最佳路线
L_best = np.zeros(self.G) # 各代最佳路线长度
fig = plt.figure(figsize=(10, 5.5), dpi=100)
for nc in range(self.G):
# 第二步:将m只蚂蚁放到n个城市上
t1 = random.randint(0,31,(1,round(self.m/n)*n))[0,:self.m] # 初始化m只蚂蚁第一座城市
Tabu[:,0] = t1
# 第三步:m只蚂蚁按概率函数选择下一座城市
for j in range(1,n): # 下一座城市
for i in range(self.m): # 第m只蚂蚁的选择是?
t5 = Tabu[i,:j]
arrived = t5 # 取已经访问的城市
candidate = np.zeros((n-j),dtype=np.int32) # 待访问的城市
p = np.zeros((n-j)) # 待访问的城市的概率分布
jc = 0
# 对于第m只蚂蚁,找出其未去的城市
for k in range(n): # n座城
if sum(arrived==k) == 0: # 说明第k个城市没去过
candidate[jc] = k
jc = jc + 1
# 计算待选城市的概率分布
for k in range(len(candidate)):
a = arrived[-1] # 当前所在
b = candidate[k] # 尚未去的k
t2 = Tau[a][b] # 当前蚂蚁所在城市要去下一座未访问的城市k的路段信息素
t3 = Eta[a][b] # 当前蚂蚁所在城市要去下一座未访问的城市k的期望,距离倒数
p[k] = (t2**self.alpha)*(t3**self.beta) # 期望前往城市的概率公式
# 概率归一化
p = p/sum(p)
# 按概率原则选取下一座城市...??
pcum = np.cumsum(p) # 累计概率
t4 = random.rand()
select = np.where(pcum>t4)[0][0] # 概率选择???
to_visit = candidate[select]
Tabu[i,j] = to_visit
if nc > 0:
Tabu[0] = R_best[nc-1] # 把上一代最好的路径赋值给第一只蚂蚁,不然不收敛。
# 第四步:记录本次迭代最佳路线
L = np.zeros((self.m))
for i in range(self.m):
R = Tabu[i] # 第i只蚂蚁的周游路径
for j in range(n-1):
x0 = R[j] # 假设从x0城市去x1城市
x1 = R[j+1]
L[i] = L[i] + D[x0][x1] # 计算该条路径的总周长
xx = R[0]
xn = R[n-1]
L[i] = L[i] + D[xx][xn] # 回到出发点,累计闭合圈
L_best[nc] = min(L)
pos = np.where(L==min(L))[0][0] # 记录该轮最短路径的位置,即第几条路径?
R_best[nc] = Tabu[pos] # 记录该轮最短路径的位置,即第几条路径.
# 第五步:更新信息素
delta_tau = np.zeros((n,n))
for i in range(self.m):
for j in range(n-1):
x0 = Tabu[i][j] # 当前
x1 = Tabu[i][j+1] # 下一个
delta_tau[x0][x1] = delta_tau[x0][x1] + self.Q/L[i]
x00 = Tabu[i][0] # 第i只蚂蚁的第一个位置
x11 = Tabu[i][-1] # 最后一个位置
delta_tau[x11][x11] = delta_tau[x11][x00] + self.Q/L[i] # 回来的路径的信息素更新
Tau = (1-self.rho)*Tau + delta_tau # 信息素更新公式
# 第六步:禁忌表清零
Tabu = np.zeros((self.m,n),dtype=np.int32)
## 输出结果
self.move_city(R_best[nc],nc)
plt.show()
# return L_best,R_best
def move_city(self,p,nc):
matplotlib.rcParams['font.family'] = 'Kaiti'
plt.rc('legend', fontsize=16)
plt.ion() # 打开交互模式
# fig = plt.figure(figsize=(10, 5.5), dpi=100)
CK = ['b', 'y', 'g', 'r', 'k', 'c', 'm']
k = np.random.randint(0, len(CK), 1)
# p = np.random.permutation(31) # 从0-31的无序下标
data = self.data[p] # 重新打乱数组
x = data[:, 0] # x轴
y = data[:, 1] # y轴
start = p[0] # 起点
stop = p[-1] # 终点
x = np.append(x,data[stop][0])
y = np.append(y, data[stop][1])
x = np.append(x, data[start][0])
y = np.append(y, data[start][1])
plt.clf()
plt.plot(x, y, '%s:d' % CK[k.item()], markerfacecolor='red', markersize=5, linewidth=1.8,
label='蚁群算法解旅行商')
plt.xlabel('迭代次数', fontproperties='Kaiti', fontsize=14) # 坐标轴标签设置
plt.ylabel('旅行最短路径', fontproperties='Kaiti', fontsize=14)
plt.title('蚁群算法最优路径迭代%d'%(nc+1),
fontproperties='Kaiti', fontsize=14)
plt.annotate('起点:(%d,%d)'%(data[start][0],data[start][1]), xy=(data[start][0],data[start][1]),
xytext=(data[start][0]-400, data[start][1]+200),
fontproperties='Kaiti',
fontsize=12, arrowprops=dict(facecolor='green', shrink=1.5, width=1.5, headwidth=5))
plt.annotate('终点:(%d,%d)' % (data[stop][0], data[stop][1]), xy=(data[stop][0], data[stop][1]),
xytext=(data[stop][0]-400, data[stop][1]+200),
fontproperties='Kaiti',
fontsize=12, arrowprops=dict(facecolor='black', shrink=1.5, width=1.5, headwidth=5))
plt.grid(True) # 网格
plt.legend(loc='upper right')
plt.pause(0.05)
plt.ioff()
# plt.show()
data = pd.read_excel('城市坐标数据.xlsx')
data = np.array(data)
aco = ACO(50,1,5,0.1,50,50,data)
aco.aco()
实验结果
- 为了绘制实验动态图学习了matplotlib的动态图。非常满意的可视化结果。