蚁群算法python代码
蚁群算法是一种模拟蚂蚁觅食行为的优化算法,常用于解决组合优化问题,如旅行商问题。
pythonimport random
class AntColony:
def __init__(self, distances, n_ants, decay, alpha=1, beta=1):
"""
Args:
distances (2D numpy.array): Square matrix of distances. Diagonal is assumed to be np.inf.
n_ants (int): Number of ants running per iteration
decay (float): Rate it which pheromone decays. The pheromone value is multiplied by decay, so 0.95 will lead to decay,
whereas 1.0 will keep the values constant.
alpha (int or float): exponenet on pheromone, higher alpha gives pheromone more weight. Default=1
beta (int or float): exponent on distance, higher beta give distance more weight. Default=1
"""
self.distances = distances
self.pheromone = 1 / (len(distances)**2) * np.ones(distances.shape)
self.all_inds = range(len(distances))
self.n_ants = n_ants
self.decay = decay
self.alpha = alpha
self.beta = beta
def run(self, n):
"""
Args:
n (int): Number of iterations
"""
best_path = None
all_time_best_path = ("placeholder", np.inf)
for i in range(n):
all_paths = self.gen_all_paths()
self.spread_pheronome(all_paths, self.pheromone, self.distances)
self.pheromone * self.decay
self.intensify_pheromone(self.best_path(all_paths), self.pheromone, self.distances)
if self.best_path(all_paths) == all_time_best_path:
best_path = self.best_path(all_paths)
if self.best_path(all_paths)[1] < all_time_best_path[1]:
all_time_best_path = self.best_path(all_paths)
return all_time_best_path
def spread_pheronome(self, all_paths, pheromone, distances):
"""
Args:
all_paths (list): all the paths of the ants
pheromone (2D numpy.array): pheromone matrix
distances (2D numpy.array): distance matrix
"""
pheromone * self.decay
for path in all_paths:
for move in path:
pheromone[move] += 1 / distances[move]
def intensify_pheromone(self, best_path, pheromone, distances):
"""
Args:
best_path (tuple): the best path and its length
pheromone (2D numpy.array): pheromone matrix
distances (2D numpy.array): distance matrix
"""
for move in best_path[0]:
pheromone[move] += 1 / distances[move]
def gen_path_dist(self, path):
"""
Args:
path (list): list of moves ant has made
"""
total_dist = 0
for move in path:
total_dist += self.distances[move]
return total_dist
def best_path(self, all_paths):
"""
Args:
all_paths (list): all the paths of the ants
"""
all_paths = all_paths
all_paths_dist = []
for path in all_paths:
all_paths_dist.append((path, self.gen_path_dist(path)))
return min(all_paths_dist, key=lambda x: x[1])
def gen_all_paths(self):
"""
Returns:
all_paths (list): all the paths of the ants
"""
all_paths = []
for i in range(self.n_ants):
path = self.gen_path(0)
while set(path) != set(self.all_inds):
path = self.gen_path(0)
all_paths.append(path)
return all_paths
def gen_path(self, start):
"""
Args:
start (int): starting location of the ant
Returns:
path (list): the path of the ant
"""
path = []
visited = set()
visited.add(start)
prev = start
for i in range(len(self.distances)-1):
move = self.pick_move(self.pheromone[prev], self.distances[prev], visited)
path.append((prev, move))
prev = move
visited.add(move)
path.append((prev, start)) # going back to where we started
return path
def pick_move(self, pheromone, dist, visited):
"""
Args:
pheromone (1D numpy.array): pheromone of the current node
dist (1D numpy.array): distance matrix of the current node
visited (set): set of visited nodes
Returns:
move (int): the next move
"""
row = pheromone ** self.alpha * (( 1.0 / dist) ** self.beta)
row[list(visited)] = 0
norm_row = row / row.sum()
move = np_choice(self.all_inds, 1, p=norm_row)[0]
return move
这是一个简单的ACO算法实现。这个实现中使用了NumPy库,你可能需要安装它,你可以使用
bashpip install numpy
要使用这个算法,你需要创建一个包含节点之间距离的距离矩阵。例如,如果有3个节点,你的距离矩阵可能是这样的:
pythonimport numpy as np
distances = np.array([
[0, 1, 2],
[1, 0, 3],
[2, 3, 0]
])
然后,你可以创建AntColony对象并运行算法:
pythonaco = AntColony(distances, n_ants=3, decay=0.95, alpha=1, beta=2)
best_path = aco.run(100)
print("Best Path:", best_path[0])
print("Best Distance:", best_path[1])
pythonimport numpy as np
from numpy.random import choice as np_choice
class AntColony:
def __init__(self, distances, n_ants, decay, alpha=1, beta=1):
self.distances = distances
self.pheromone = np.ones(self.distances.shape) / len(distances)
self.all_inds = range(len(distances))
self.n_ants = n_ants
self.decay = decay
self.alpha = alpha
self.beta = beta
def run(self, n):
all_time_best_path = None
for i in range(n):
all_paths = self.gen_all_paths()
self.spread_pheromone(all_paths, self.pheromone, self.distances)
self.pheromone * self.decay
self.intensify_pheromone(self.best_path(all_paths), self.pheromone, self.distances)
if all_time_best_path is None or self.best_path(all_paths)[1] < all_time_best_path[1]:
all_time_best_path = self.best_path(all_paths)
return all_time_best_path
def spread_pheromone(self, all_paths, pheromone, distances):
for path in all_paths:
for move in path:
pheromone[move] += 1 / distances[move]
def intensify_pheromone(self, best_path, pheromone, distances):
for move in best_path[0]:
pheromone[move] += 1 / distances[move]
def gen_path_dist(self, path):
total_dist = 0
for move in path:
total_dist += self.distances[move]
return total_dist
def best_path(self, all_paths):
all_paths = all_paths
all_paths_dist = []
for path in all_paths:
all_paths_dist.append((path, self.gen_path_dist(path)))
return min(all_paths_dist, key=lambda x: x[1])
def gen_all_paths(self):
all_paths = []
for i in range(self.n_ants):
path = self.gen_path(0)
while set(path) != set(self.all_inds):
path = self.gen_path(0)
all_paths.append(path)
return all_paths
def gen_path(self, start):
path = []
visited = set()
visited.add(start)
prev = start
for i in range(len(self.distances)-1):
move = self.pick_move(self.pheromone[prev], self.distances[prev], visited)
path.append((prev, move))
prev = move
visited.add(move)
path.append((prev, start)) # going back to where we started
return path
def pick_move(self, pheromone, dist, visited):
row = pheromone ** self.alpha * ((1.0 / dist) ** self.beta)
row[list(visited)] = 0
norm_row = row / row.sum()
move = np_choice(self.all_inds, 1, p=norm_row)[0]
return move
这个修复的版本应该更加稳定和准确。使用这个修复的版本,你可以按照上面的例子创建AntColony对象并运行算法。这个算法可能需要根据具体问题进行调整和优化。