import numpy as np
import matplotlib.pyplot as plt
import pylab
coordinates = np.array([[565.0, 575.0], [25.0, 185.0], [345.0, 750.0], [945.0, 685.0], [845.0, 655.0],
[880.0, 660.0], [25.0, 230.0], [525.0, 1000.0], [580.0, 1175.0], [650.0, 1130.0],
[1605.0, 620.0], [1220.0, 580.0], [1465.0, 200.0], [1530.0, 5.0], [845.0, 680.0],
[725.0, 370.0], [145.0, 665.0], [415.0, 635.0], [510.0, 875.0], [560.0, 365.0],
[300.0, 465.0], [520.0, 585.0], [480.0, 415.0], [835.0, 625.0], [975.0, 580.0],
[1215.0, 245.0], [1320.0, 315.0], [1250.0, 400.0], [660.0, 180.0], [410.0, 250.0],
[420.0, 555.0], [575.0, 665.0], [1150.0, 1160.0], [700.0, 580.0], [685.0, 595.0],
[685.0, 610.0], [770.0, 610.0], [795.0, 645.0], [720.0, 635.0], [760.0, 650.0],
[475.0, 960.0], [95.0, 260.0], [875.0, 920.0], [700.0, 500.0], [555.0, 815.0],
[830.0, 485.0], [1170.0, 65.0], [830.0, 610.0], [605.0, 625.0], [595.0, 360.0],
[1340.0, 725.0], [1740.0, 245.0]])
def getdistmat(coordinates):
num = coordinates.shape[0]
distmat = np.zeros((52, 52))
for i in range(num):
for j in range(i, num):
distmat[i][j] = distmat[j][i] = np.linalg.norm(coordinates[i] - coordinates[j])
return distmat
distmat = getdistmat(coordinates)
numant = 40
numcity = coordinates.shape[0]
alpha = 1
beta = 5
rho = 0.1
Q = 1
iter = 0
itermax = 250
etatable = 1.0 / (distmat + np.diag([1e10] * numcity))
pheromonetable = np.ones((numcity, numcity))
pathtable = np.zeros((numant, numcity)).astype(int)
distmat = getdistmat(coordinates)
lengthaver = np.zeros(itermax)
lengthbest = np.zeros(itermax)
pathbest = np.zeros((itermax, numcity))
while iter < itermax:
if numant <= numcity:
pathtable[:, 0] = np.random.permutation(range(0, numcity))[:numant]
else:
pathtable[:numcity, 0] = np.random.permutation(range(0, numcity))[:]
pathtable[numcity:, 0] = np.random.permutation(range(0, numcity))[:numant - numcity]
length = np.zeros(numant)
for i in range(numant):
visiting = pathtable[i, 0]
unvisited = set(range(numcity))
unvisited.remove(visiting)
for j in range(1, numcity):
listunvisited = list(unvisited)
probtrans = np.zeros(len(listunvisited))
for k in range(len(listunvisited)):
probtrans[k] = np.power(pheromonetable[visiting][listunvisited[k]], alpha) \
* np.power(etatable[visiting][listunvisited[k]], alpha)
cumsumprobtrans = (probtrans / sum(probtrans)).cumsum()
cumsumprobtrans -= np.random.rand()
k = listunvisited[(np.where(cumsumprobtrans > 0)[0])[0]]
pathtable[i, j] = k
unvisited.remove(k)
length[i] += distmat[visiting][k]
visiting = k
length[i] += distmat[visiting][pathtable[i, 0]]
lengthaver[iter] = length.mean()
if iter == 0:
lengthbest[iter] = length.min()
pathbest[iter] = pathtable[length.argmin()].copy()
else:
if length.min() > lengthbest[iter - 1]:
lengthbest[iter] = lengthbest[iter - 1]
pathbest[iter] = pathbest[iter - 1].copy()
else:
lengthbest[iter] = length.min()
pathbest[iter] = pathtable[length.argmin()].copy()
changepheromonetable = np.zeros((numcity, numcity))
for i in range(numant):
for j in range(numcity - 1):
changepheromonetable[pathtable[i, j]][pathtable[i, j + 1]] += Q / distmat[pathtable[i, j]][
pathtable[i, j + 1]]
changepheromonetable[pathtable[i, j + 1]][pathtable[i, 0]] += Q / distmat[pathtable[i, j + 1]][pathtable[i, 0]]
pheromonetable = (1 - rho) * pheromonetable + changepheromonetable
iter += 1
print("iter:", iter)
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12, 10))
axes[0].plot(lengthaver, 'k', marker=u'')
axes[0].set_title('Average Length')
axes[0].set_xlabel(u'iteration')
axes[1].plot(lengthbest, 'k', marker=u'')
axes[1].set_title('Best Length')
axes[1].set_xlabel(u'iteration')
fig.savefig('average_best.png', dpi=500, bbox_inches='tight')
plt.show()
bestpath = pathbest[-1]
plt.plot(coordinates[:, 0], coordinates[:, 1], 'r.', marker=u'$\cdot$')
plt.xlim([-100, 2000])
plt.ylim([-100, 1500])
for i in range(numcity - 1):
m = int(bestpath[i])
n = int(bestpath[i + 1])
plt.plot([coordinates[m][0], coordinates[n][0]], [coordinates[m][1], coordinates[n][1]], 'k')
plt.plot([coordinates[int(bestpath[0])][0],coordinates[int(n)][0]],[coordinates[int(bestpath[0])][1],coordinates[int(n)][1]],'b')
ax = plt.gca()
ax.set_title("Best Path")
ax.set_xlabel('X axis')
ax.set_ylabel('Y_axis')
plt.savefig('best path.png', dpi=500, bbox_inches='tight')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
coordinates = np.array([[880.0,660.0],[25.0,230.0],[525.0,1000.0],[580.0,1175.0],[650.0,1130.0],
[1605.0,620.0],[1220.0,580.0],[1465.0,200.0],[1530.0,5.0],[845.0,680.0],
[725.0,370.0],[145.0,665.0],[415.0,635.0],[510.0,875.0],[560.0,365.0],
[300.0,465.0],[520.0,585.0],[480.0,415.0],[835.0,625.0],[975.0,580.0],
[420.0,555.0],[575.0,665.0],[1150.0,1160.0],[700.0,580.0],[685.0,595.0],
[685.0,610.0],[770.0,610.0],[795.0,645.0],[720.0,635.0],[760.0,650.0],
[475.0,960.0],[95.0,260.0],[875.0,920.0],[700.0,500.0],[555.0,815.0],
[830.0,485.0],[1170.0, 65.0],[830.0,610.0],[605.0,625.0],[595.0,360.0],
])
"""
得到各个城市间的距离
由于距离是两点之间的,因此,会返回一个对称矩阵
"""
def getdistmat(coordinates):
num = coordinates.shape[0]
distmat = np.zeros((num,num))
for i in range(num):
for j in range(i, num):
distmat[i][j] = distmat[j][i] = np.linalg.norm(coordinates[i] - coordinates[j])
return distmat
def draw_graphics(save_path,new_coordinates):
global coordinates
x=[]
y=[]
for i in range(len(new_coordinates)):
x.append(new_coordinates[i][0])
y.append(new_coordinates[i][1])
x.append(new_coordinates[0][0])
y.append(new_coordinates[0][1])
fig=plt.figure()
plt.scatter(x,y,c='b',s=5)
plt.plot(x,y)
for i in save_path:
plt.text(coordinates[int(i)][0],coordinates[int(i)][1],r'%s'%int(i),fontdict={'size':7,'color':'r'})
plt.show()
numant = 30
numcity = coordinates.shape[0]
alpha = 1
beta=1
rho = 0.1
Q =1
iter = 0
itermax =300
distmat = getdistmat(coordinates)
etatable = 1.0 / (distmat + np.diag([1e10] * numcity))
pheromonetable = np.ones((numcity, numcity))
pathtable = np.zeros((numant, numcity)).astype(int)
lengthaver = np.zeros(itermax)
lengthbest = np.zeros(itermax)
pathbest = np.zeros((itermax, numcity))
while iter < itermax:
if numant <= numcity:
pathtable[:, 0] = np.random.permutation(range(0, numcity))[:numant]
else:
pathtable[:numcity, 0] = np.random.permutation(range(0, numcity))[:]
pathtable[numcity:, 0] = np.random.permutation(range(0, numcity))[:numant - numcity]
length = np.zeros(numant)
for i in range(numant):
visiting = pathtable[i, 0]
unvisited = set(range(numcity))
unvisited.remove(visiting)
for j in range(1, numcity):
listunvisited = list(unvisited)
probtrans = np.zeros(len(listunvisited))
for k in range(len(listunvisited)):
probtrans[k] = np.power(pheromonetable[visiting][listunvisited[k]], alpha) * np.power(
etatable[visiting][listunvisited[k]], beta)
cumsumprobtrans = (probtrans / sum(probtrans)).cumsum()
cumsumprobtrans -= np.random.rand()
next_index = 0
for value in cumsumprobtrans:
if value > 0:
break
else:
next_index += 1
k = listunvisited[next_index]
pathtable[i, j] = k
unvisited.remove(k)
length[i] += distmat[visiting][k]
visiting = k
length[i] += distmat[visiting][pathtable[i, 0]]
lengthaver[iter] = length.mean()
if iter == 0:
lengthbest[iter] = length.min()
pathbest[iter] = pathtable[length.argmin()].copy()
else:
if length.min() > lengthbest[iter - 1]:
lengthbest[iter] = lengthbest[iter - 1]
else:
lengthbest[iter] = length.min()
pathbest[iter] = pathtable[length.argmin()].copy()
changepheromonetable = np.zeros((numcity, numcity))
for i in range(numant):
for j in range(numcity - 1):
changepheromonetable[pathtable[i, j]][pathtable[i, j + 1]] += Q / distmat[pathtable[i, j]][
pathtable[i, j + 1]]
changepheromonetable[pathtable[i, j + 1]][pathtable[i, 0]] += Q / distmat[pathtable[i, j + 1]][pathtable[i, 0]]
pheromonetable = (1 - rho) * pheromonetable + changepheromonetable
iter += 1
print(lengthbest)
save_path=[]
new_coordinates=[]
for i in pathbest:
if i[0]!=i[1]:
save_path=i.copy()
print(save_path)
for i in range(coordinates.shape[0]):
new_coordinates.append(coordinates[int(save_path[i])])
draw_graphics(save_path,new_coordinates)
import numpy as np
import matplotlib.pyplot as plt
565.0 575.0
25.0 185.0
345.0 750.0
945.0 685.0
845.0 655.0
880.0 660.0
25.0 230.0
525.0 1000.0
580.0 1175.0
650.0 1130.0
1605.0 620.0
1220.0 580.0
1465.0 200.0
1530.0 5.0
845.0 680.0
725.0 370.0
145.0 665.0
415.0 635.0
510.0 875.0
560.0 365.0
300.0 465.0
520.0 585.0
480.0 415.0
835.0 625.0
975.0 580.0
1215.0 245.0
1320.0 315.0
1250.0 400.0
660.0 180.0
410.0 250.0
420.0 555.0
575.0 665.0
1150.0 1160.0
700.0 580.0
685.0 595.0
685.0 610.0
770.0 610.0
795.0 645.0
720.0 635.0
760.0 650.0
475.0 960.0
95.0 260.0
875.0 920.0
700.0 500.0
555.0 815.0
830.0 485.0
1170.0 65.0
830.0 610.0
605.0 625.0
595.0 360.0
1340.0 725.0
1740.0 245.0
View coordinates.dat
class Ant(object):
def __init__(self, path):
self.path = path
self.length = self.calc_length(path)
def calc_length(self, path_):
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):
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):
self.path = [A, A]
def add_path(self, B):
self.path.append(B)
self.path[-1], self.path[-2] = self.path[-2], self.path[-1]
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
self.maxIter = maxIter
self.alpha = alpha
self.beta = beta
self.rho = rho
self.Q = Q
self.deal_data('coordinates.dat')
self.path_seed = np.zeros(self.ants_num).astype(int)
self.ants_info = np.zeros((self.maxIter, self.ants_num))
self.best_path = np.zeros(self.maxIter)
self.solve()
self.display()
def deal_data(self, filename):
with open(filename, 'rt') as f:
temp_list = list(line.split() for line in f)
self.cities_num = len(temp_list)
self.cities = list(City(float(item[0]), float(item[1])) for item in temp_list)
self.city_dist_mat = np.zeros((self.cities_num, self.cities_num))
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))
self.eta_mat = 1/(self.city_dist_mat + np.diag([np.inf]*self.cities_num))
def solve(self):
iterNum = 0
while iterNum < self.maxIter:
self.random_seed()
delta_phero_mat = np.zeros((self.cities_num, self.cities_num))
for i in range(self.ants_num):
city_index1 = self.path_seed[i]
ant_path = Path(self.cities[city_index1])
tabu = [city_index1]
non_tabu = list(set(range(self.cities_num)) - set(tabu))
for j in range(self.cities_num-1):
up_proba = np.zeros(self.cities_num-len(tabu))
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)
while True:
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:
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])
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
def random_seed(self):
if self.ants_num <= self.cities_num:
self.path_seed[:] = np.random.permutation(range(self.cities_num))[:self.ants_num]
else:
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):
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()