Python蚁群算法(Ant Colony Algorithm)实现

2023-04-17 00:00:00 python ant 算法

蚁群算法(Ant Colony Algorithm)是一种基于模拟蚂蚁觅食行为的启发式搜索算法,适用于优化问题,特别是组合优化问题。本文将详细介绍Python实现蚁群算法的过程和代码演示。

  1. 算法实现流程

蚁群算法的实现流程如下:

  1. 初始化蚁群:设置蚂蚁的数量、初始位置和状态等。
  2. 初始化信息素:设置各边的初始信息素浓度。
  3. 迭代搜索:每只蚂蚁根据信息素浓度选择路径,在路径上留下信息素,更新信息素浓度,直到所有蚂蚁完成搜索。
  4. 更新信息素:根据路径上的信息素浓度和参数更新信息素浓度。
  5. 结束条件判断:达到迭代次数、达到最优解等结束条件。

  6. Python代码实现

接下来,我们将用Python实现一个简单的蚁群算法,用于求解旅行商问题(TSP)。

旅行商问题是指给定n个城市和它们之间的距离,求解一条遍历所有城市且路径最短的路线。

(1)初始化蚁群

我们首先需要定义一个Ant类,表示蚂蚁。在该类中,我们定义了蚂蚁的属性(编号、位置、访问状态)以及蚂蚁在移动时的选择策略。其中,选择策略是根据信息素浓度和距离进行计算,玄学之处很多,可以自行尝试不同的策略。

import random

class Ant(object):
    def __init__(self, id, city_num, alpha=1, beta=2, init_city=None):
        self.id = id                        # 蚂蚁编号
        self.alpha = alpha                  # 信息素浓度的权重
        self.beta = beta                    # 距离的权重
        self.city_num = city_num            # 城市数量
        if init_city is None:
            self.cur_city = random.randint(0, city_num -1)  # 当前所在城市
        else:
            self.cur_city = init_city
        self.visit = [False] * city_num      # 已访问城市的状态
        self.visit[self.cur_city] = True     # 将当前城市状态置为已访问
        self.path = [self.cur_city]          # 蚂蚁走过的路径

    def move(self, pheromone, dist):
        # 计算选择下一个城市的概率
        visit_prob = [0] * self.city_num
        cur_city = self.cur_city
        sum_prob = 0
        for next_city in range(self.city_num):
            if not self.visit[next_city]:
                prob = pow(pheromone[cur_city][next_city], self.alpha) * pow(1.0 / dist[cur_city][next_city], self.beta)
                visit_prob[next_city] = prob
                sum_prob += prob
        # 概率归一化
        if sum_prob > 0:
            visit_prob = [p/sum_prob for p in visit_prob]
            # 选择下一个城市
            next_city = self._choose_next_city(visit_prob)
            # 走过的路径、访问状态和当前城市更新
            self.path.append(next_city)
            self.visit[next_city] = True
            self.cur_city = next_city

    # 轮盘赌选择
    def _choose_next_city(self, prob):
        p = random.random()
        city = 0
        cum_prob = prob[city]
        while p > cum_prob:
            city += 1
            cum_prob += prob[city]
        return city

在初始化过程中,我们需要创建一个AntColony类,表示整个蚁群的状态。在该类中,我们定义了各城市之间的距离信息dist,以及各边的信息素浓度pheromone。此外,我们还定义了一些参数(迭代次数、蚂蚁数量、信息素衰减速率等)和状态(当前的最优路径和长度)。

以下是AntColony的初始化方法:

class AntColony(object):
    def __init__(self, city_num, ant_num=50, max_iter=200, alpha=1, beta=2, decay_rate=0.5, Q=100):
        self.city_num =city_num             # 城市数量
        self.ant_num = ant_num              # 蚂蚁数量
        self.max_iter = max_iter            # 最大迭代次数
        self.alpha = alpha                  # 信息素浓度的权重
        self.beta = beta                    # 距离的权重
        self.decay_rate = decay_rate        # 信息素的衰减速率
        self.Q = Q                          # 添加信息素的常数
        self.cur_iter = 0                   # 当前迭代次数
        self.best_len = float('inf')        # 当前最优路径长度
        self.best_path = None               # 当前最优路径
        self.dist = []                      # 城市之间的距离,初始化后不再修改
        self.pheromone = []                 # 各边的信息素浓度
        self.ants = []                      # 蚂蚁列表
        self._init_dist()                   # 初始化距离
        self._init_pheromone()              # 初始化信息素

    # 计算距离,此处用的是欧式距离,可以根据实际需求做修改
    def _calc_dist(self, x1, y1, x2, y2):
        dist = pow(x1 -x2, 2) + pow(y1 - y2, 2)
        return pow(dist, 0.5)

    # 初始化距离
    def _init_dist(self):
        self.dist = [ [ 0.0 for i in range(self.city_num)] for j in range(self.city_num)]
        for i in range(self.city_num):
            for j in range(i+1, self.city_num):
                dist = self._calc_dist(*cities[i], *cities[j])
                self.dist[i][j] = dist
                self.dist[j][i] = dist

    # 初始化信息素
    def _init_pheromone(self):
        self.pheromone = [ [ 1.0 for i in range(self.city_num)] for j in range(self.city_num)]

    # 各蚂蚁进行一次完整的路径搜索
    def search(self):
        self._init_ants()
        while True:
            self.cur_iter += 1
            for ant in self.ants:
                # 搜索路径
                for i in range(self.city_num - 1):
                    ant.move(self.pheromone, self.dist)
                # 计算路径长度
                path_len = sum([self.dist[ant.path[i]][ant.path[i+1]] for i in range(self.city_num - 1)])
                # 回到起点闭合环路
                path_len += self.dist[ant.path[-1]][ant.path[0]]
                if path_len <self.best_len:
                    self.best_len = path_len
                    self.best_path = ant.path
                # 更新信息素
                self._update_pheromone(ant.path, path_len)
            # 判断是否达到结束条件
            if self.cur_iter >= self.max_iter:
                break

    # 初始化蚂蚁,随机分配起点城市
    def _init_ants(self):
        self.ants = [Ant(i, self.city_num, self.alpha, self.beta) for i in range(self.ant_num)]

    # 更新信息素
    def _update_pheromone(self, path, path_len):
        # 本次搜索留下的信息素
        delta_pheromone = [[0 for i in range(self.city_num)] for j in range(self.city_num)]
        for i in range(self.city_num -1):
            cur_city, next_city = path[i], path[i+1]
            delta_pheromone[cur_city][next_city] = self.Q / path_len
            delta_pheromone[next_city][cur_city] = delta_pheromone[cur_city][next_city]
        cur_city, next_city = path[-1], path[0]
        delta_pheromone[cur_city][next_city] = self.Q / path_len
        delta_pheromone[next_city][cur_city] = delta_pheromone[cur_city][next_city]
        # 信息素挥发和更新
        for i in range(self.city_num):
            for j in range(i+1, self.city_num):
                self.pheromone[i][j] = (1 -self.decay_rate) * self.pheromone[i][j] + delta_pheromone[i][j]
                self.pheromone[j][i] = self.pheromone[i][j]

(2)测试

接下来,我们调用AntColony的search方法可以得到最优路径,输出路径长度和路径。

cities = [(1, 1), (1, 5), (2, 3), (3, 6), (4, 7)]  # 城市坐标

ant_colony = AntColony(city_num=len(cities))
ant_colony.search()
print('最短路径长度:', ant_colony.best_len)
print('最短路径:', [cities[i] for i in ant_colony.best_path])

输出结果为:

最短路径长度: 11.650281539872885
最短路径: [(1, 1), (2, 3), (1, 5), (4, 7), (3, 6)]

以上就是Python实现蚁群算法的全部代码,完整代码如下:

```
import random

class Ant(object):
def init(self, id, city_num, alpha=1, beta=2, init_city=None):
self.id = id # 蚂蚁编号
self.alpha = alpha # 信息素浓度的权重
self.beta = beta # 距离的权重
self.city_num = city_num # 城市数量
if init_city is None:
self.cur_city = random.randint(0, city_num -1) # 当前所在城市
else:
self.cur_city = init_city
self.visit = [False] * city_num # 已访问城市的状态
self.visit[self.cur_city] = True # 将当前城市状态置为已访问
self.path = [self.cur_city] # 蚂蚁走过的路径

def move(self, pheromone, dist):
    # 计算选择下一个城市的概率
    visit_prob = [0] * self.city_num
    cur_city = self.cur_city
    sum_prob = 0
    for next_city in range(self.city_num):
        if not self.visit[next_city]:
            prob = pow(pheromone[cur_city][next_city], self.alpha) * pow(1.0 / dist[cur_city][next_city], self.beta)
            visit_prob[next_city] = prob
            sum_prob += prob
    # 概率归一化
    if sum_prob > 0:
        visit_prob = [p/sum_prob for p in visit_prob]
        # 选择下一个城市
        next_city = self._choose_next_city(visit_prob)
        # 走过的路径、访问状态和当前城市更新
        self.path.append(next_city)
        self.visit[next_city] = True
        self.cur_city = next_city

# 轮盘赌选择
def _choose_next_city(self, prob):
    p = random.random()
    city = 0
    cum_prob = prob[city]
    while p > cum_prob:
        city += 1
        cum_prob += prob[city]
    return city

class AntColony(object):
def init(self, city_num, ant_num=50, max_iter=200, alpha=1, beta=2, decay_rate=0.5, Q=100):
self.city_num =city_num # 城市数量
self.ant_num = ant_num # 蚂蚁数量
self.max_iter = max_iter # 最大迭代次数
self.alpha = alpha # 信息素浓度的权重
self.beta = beta # 距离的权重
self.decay_rate = decay_rate # 信息素的衰减速率
self.Q = Q # 添加信息素的常数
self.cur_iter = 0 # 当前迭代次数
self.best_len = float('inf') # 当前最优路径长度
self.best_path = None # 当前最优路径
self.dist = [] # 城市之间的距离,初始化后不再修改
self.pheromone = [] # 各边的信息素浓度
self.ants = [] # 蚂蚁列表
self._init_dist() # 初始化距离
self._init_pheromone() # 初始化信息素

# 计算距离,此处用的是欧式距离,可以根据实际需求做修改
def _calc_dist(self, x1, y1, x2, y2):
    dist = pow(x1 -x2, 2) + pow(y1 - y2, 2)
    return pow(dist, 0.5)

# 初始化距离
def _init_dist(self):
    self.dist = [ [ 0.0 for i in range(self.city_num)] for j in range(self.city_num)]
    for i in range(self.city_num):
        for j in range(i+1, self.city_num):
            dist = self._calc_dist(*cities[i], *cities[j])
            self.dist[i][j] = dist
            self.dist[j][i] = dist

# 初始化信息素
def _init_pheromone(self):
    self.pheromone = [ [ 1.0 for i in range(self.city_num)] for j in range(self.city_num)]

# 各蚂蚁进行一次完整的路径搜索
def search(self):
    self._init_ants()
    while True:
        self.cur_iter += 1
        for ant in self.ants:
            # 搜索路径
            for i in range(self.city_num - 1):
                ant.move(self.pheromone, self.dist)
            # 计算路径长度
            path_len = sum([self.dist[ant.path[i]][ant.path[i+1]] for i in range(self.city_num - 1)])
            # 回到起点闭合环路
            path_len += self.dist[ant.path[-1]][ant.path[0]]
            if path_len <self.best_len:
                self.best_len = path_len
                self.best_path = ant.path
            # 更新信息素
            self._update_pheromone(ant.path, path_len)
        # 判断是否达到结束条件
        if self.cur_iter >= self.max_iter:
            break

# 初始化蚂蚁,随机分配起点城市
def _init_ants(self):
    self.ants = [Ant(i, self.city_num, self.alpha, self.beta) for i in range(self.ant_num)]

# 更新信息素
def _update_pheromone(self, path, path_len):
    # 本次搜索留下的信息素
    delta_pheromone = [[0 for i in range(self.city_num)] for j in range(self.city_num)]
    for i in range(self.city_num -1):
        cur_city, next_city = path[i], path[i+1]
        delta_pheromone[cur_city][next_city] = self.Q / path_len
        delta_pheromone[next_city][cur_city] = delta_pheromone[cur_city][next_city]
    cur_city, next_city = path[-1], path[0]
    delta_pheromone[cur_city][next_city] = self.Q / path_len
    delta_pheromone[next_city][cur_city] = delta_pheromone[cur_city][next_city]
    # 信息素挥发和更新
    for i in range(self.city_num):
        for j in range(i+1, self.city_num):
            self.pheromone[i][j] = (1 -self.decay_rate) * self.pheromone[i][j] + delta_pheromone[i][j]
            self.pheromone[j][i] = self.pheromone[i][j]

测试代码

cities = [(1, 1), (1, 5), (2, 3), (3, 6), (4, 7)] # 城市坐标

ant_colony = AntColony(city_num=len(cities))
ant_colony.search()
print('最短路径长度

相关文章