蚁群算法(ACO)

目录

ACO简介

基本原理

算法步骤

 流程图  

 参数意义 

 构建路径

 更新信息素

 实例演示(TSP问题)


ACO简介

        蚁群是自然界中常见的一种生物,人们对蚂蚁的关注大都是因为“蚁群搬家,天要下雨”之类的民谚。然而随着近代仿生学的发展,这种似乎微不足道的小东西越来越多地受到学者们地关注。1991年意大利学者M. Dorigo等人首先提出了蚁群算法,人们开始了对蚁群的研究:相对弱小,功能并不强大的个体是如何完成复杂的工作的(如寻找到食物的最佳路径并返回等)。在此基础上就诞生了蚁群算法(ant colony optimization, ACO),一种用来在图中寻找优化路径的机率型算法。该算法最初用来求解旅行商(Traveling Saleman Problem,TSP)问题。即求出某个商人从某一个点出发(原点),经过若干个给定的需求点,最终返回到原点所经过的最短路径。

基本原理

        蚂蚁在行走过的路上留下一种挥发性的激素(信息素),蚂蚁就是通过这种激素进行信息交流。蚂蚁趋向于走激素积累较多的路径。找到最短路径的蚂蚁总是最早返回巢穴,从而在路上留下了较多的激素。由于最短路径上积累了较多的激素,选择这条路径的蚂蚁就会越来越多,到最后所有的蚂蚁都会趋向于选择这条最短路径,但信息素会随着时间的推移而逐渐挥发。基于蚂蚁这种行为而提出的蚁群算法具有群体合作,正反馈选择,并行计算等三大特点。

算法步骤

       

  1. 初始化(各个参数): 在计算之初需要对相关的参数进行初始化,如蚂蚁数量m、信息素因子α、启发函数因子β、信息素挥发因子ρ、信息素常数Q、最大迭代次数t等等。
  2. 构建解空间: 将各个蚂蚁随机地放置于不同的出发点,对每个蚂蚁k(k=1,2,……,m),计算其下一个待访问的城市,直到所有蚂蚁访问完所有的城市。
  3. 更新信息素: 计算各个蚂蚁经过的路径长度L,记录当前迭代次数中的最优解(最短路径)。同时,对各个城市连接路径上的信息素浓度进行更新。
  4. 判断是否终止: 若迭代次数小于最大迭代次数则迭代次数加一,清空蚂蚁经过路径的记录表,并返回步骤二;否则终止计算,输出最优解。
     

 流程图  

 参数意义 

参数名称参数意义参数设置过大参数设置过小
蚂蚁数量m蚂蚁数量一般设置为目标数的1.5倍较为稳妥每条路径上信息素趋于平均,正反馈作用减弱,从而导致收敛速度减慢可能导致一些从未搜索过的路径信息素浓度减小为0,导致过早收敛,解的全局最优性降低
信息素常量Q信息素常量根据经验一般取值在[10,1000]会使蚁群的搜索范围减小容易过早的收敛,使种群陷入局部最优每条路径上信息含量差别较小,容易陷入混沌状态
信息素因子ɑ反映了蚂蚁运动过程中路径上积累的信息素的量在指导蚁群搜索中的相对重要程度。取值范围通常在[1, 4]之间。蚂蚁选择以前已经走过的路可能性较大,容易使随机搜索性减弱蚁群易陷入纯粹的随机搜索,使种群陷入局部最优
启发函数因子𝛽反映了启发式信息在指导蚁群搜索中的相对重要程度,蚁群寻优过程中先验性、确定性因素作用的强度取值范围在[0, 5]之间虽然收敛速度加快,但是易陷入局部最优蚁群易陷入纯粹的随机搜索,很难找到最优解
信息素挥发因子𝜌反映了信息素的消失水平,相反的1-𝜌反映了信息素的保持水平。取值范围通常在[0.2, 0.5]之间信息素挥发较快,容易导致较优路径被排除各路径上信息素含量差别较小,收敛速度降低
最大迭代次数t最大迭代次数一般取[100,500],建议取200运算时间过长可选路径较少,使种群陷入局部最优。

 构建路径

我们知道蚂蚁是根据信息素的浓度来判断所走的路线的,但是事实上,不是说哪条路的信息素浓度高蚂蚁就一定走哪条路,而是走信息素浓度高的路线的概率比较高。那么首先我们就需要知道蚂蚁选择走每个城市的概率,然后通过轮盘赌法(相当于转盘)确定蚂蚁所选择的城市。

概率公式 :

 更新信息素

根据不同的规则我们可以将蚁群算法分为三种模型——蚁周模型(Ant-Cycle)、蚁量模型(Ant-Quantity)和蚁密模型(Ant-Density)。蚁周模型是完成一次路径循环后,蚂蚁才释放信息素,其利用的是全局信息。蚁量模型和蚁密模型蚂蚁完成一步后就更新路径上的信息素,其利用的是局部信息。本文章使用的是最常见的蚁周模型。

 实例演示(TSP问题)

 旅行商问题(TSP问题)。假设有一个旅行商人要拜访全国31个省会城市,他需要选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择要求是:所选路径的路程为所有路径之中的最小值。全国31个省会城市的坐标为[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;3238 1229;4196 1044;4312 790;4386 570;3007 1970;2562 1756;2788 1491;2381 1676;1332 695;3715 1678;3918 2179;4061 2370;3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2376;3394 2643;3439 3201;2935 3240;3140 3550;2545 2357;2778 2826;2370 2975]。

import numpy as np
import math
import matplotlib.pyplot as plt


class TSP():
    def __init__(self):
        # 初始化参数
        self.antcount = 50  # 蚂蚁数量
        self.alpha = 1  # 信息素重要程度因子
        self.beta = 5  # 启发函数重要程度因子
        self.rho = 0.1  # 信息素挥发因子
        self.Q = 100  # 信息素常量
        self.max_iter = 200  # 最大迭代次数
        self.iter = 1  # 迭代计数器
        self.city_location = np.array([[1304, 2312], [3639, 1315], [4177, 2244], [3712, 1399], [3488, 1535],
                                       [3326, 1556], [3238, 1229], [4196, 1044], [4312, 790], [4386, 570],
                                       [3007, 1970], [2562, 1756], [2788, 1491], [2381, 1676], [1332, 695],
                                       [3715, 1678], [3918, 2179], [4061, 2370], [3780, 2212], [3676, 2578],
                                       [4029, 2838], [4263, 2931], [3429, 1908], [3507, 2376], [3394, 2643],
                                       [3439, 3201], [2935, 3240], [3140, 3550], [2545, 2357], [2778, 2826],
                                       [2370, 2975]])
        self.city_num = len(self.city_location)  # 城市数量
        self.distance = np.zeros((self.city_num, self.city_num))  # 城市距离矩阵
        self.eta = np.zeros((self.city_num, self.city_num))  # 启发因子(距离的倒数)
        self.information = np.ones((self.city_num, self.city_num))  # 信息素矩阵
        self.path = np.zeros((self.antcount, self.city_num)).astype(int)  # 路径矩阵
        self.r_best = np.zeros((self.max_iter, self.city_num)).astype(int)  # 每次迭代的最优路径
        self.d_best = np.zeros(self.max_iter)  # 每次迭代的最短距离

    def get_dictance(self):
        for i in range(self.city_num):
            for j in range(self.city_num):
                if i != j:
                    self.distance[i][j] = math.sqrt(np.power((self.city_location[i][0] - self.city_location[j][0]), 2) + \
                                                    np.power((self.city_location[i][1] - self.city_location[j][1]), 2))
                else:
                    self.distance[i][j] = 100000
        self.eta = 1.0 / self.distance  # 启发因子(距离的倒数)

    def get_firstplace(self):  # 将antcount只蚂蚁放到city_num个城市上
        if self.antcount <= self.city_num:
            self.path[:, 0] = np.random.permutation(range(self.city_num))[:self.antcount]
        else:
            leave = self.antcount - self.city_num  # 剩下几个蚂蚁
            n = 1
            self.path[:self.city_num, 0] = np.random.permutation(range(self.city_num))
            while leave > self.city_num:
                self.path[self.city_num * n:self.city_num * (n + 1), 0] = np.random.permutation(range(self.city_num))
                leave = leave - self.city_num
                n += 1
            self.path[self.city_num * n:self.antcount, 0] = np.random.permutation(range(self.city_num))[:leave]

    def get_nextplace(self):  # 选择下一步走哪个城市
        self.length = np.zeros(self.antcount)  # 每次迭代每只蚂蚁走过的总路程
        for i in range(self.antcount):
            unvisit = list(range(self.city_num))  # 创建每只蚂蚁未走过的城市列表
            visit = self.path[i, 0]  # 每只蚂蚁走过的城市
            unvisit.remove(visit)  # 删除走过的城市
            for j in range(1, self.city_num):
                probability = np.zeros(len(unvisit))
                for k in range(len(unvisit)):  # 下一个城市的概率
                    probability[k] = np.power(self.information[visit][unvisit[k]], self.alpha) * \
                                     np.power(self.eta[visit][unvisit[k]], self.beta)
                # 累积概率 轮盘赌选择
                cousumprobability = (probability / sum(probability)).cumsum()
                cousumprobability -= np.random.rand()
                # 下一步该走的城市
                next = unvisit[list(cousumprobability > 0).index(True)]
                self.path[i, j] = next
                unvisit.remove(next)
                self.length[i] += self.distance[visit][next]  # 第i只蚂蚁走过的路程
                visit = next
            self.length[i] += self.distance[visit][self.path[i, 0]]  # 回到开始的城市

    def get_best(self):  # 得到最优路径和最短距离
        if self.iter == 1:
            self.r_best[self.iter - 1] = self.path[self.length.argmin()].copy()
            self.d_best[self.iter - 1] = self.length.min()
        else:
            if self.length.min() > self.d_best[self.iter- 2]:
                self.r_best[self.iter - 1] = self.r_best[self.iter - 2]
                self.d_best[self.iter - 1] = self.d_best[self.iter - 2]
            else:
                self.r_best[self.iter - 1] = self.path[self.length.argmin()].copy()
                self.d_best[self.iter - 1] = self.length.min()

    def update_infor(self):  # 更新信息素
        j=0
        information_increase = np.zeros((self.city_num, self.city_num))  # 信息素增加矩阵
        for i in range(self.antcount):
            for j in range(self.city_num - 1):
                information_increase[self.path[i, j]][self.path[i][j + 1]] += self.Q / self.length[i]
            information_increase[self.path[i][j+1]][self.path[i,0]]+= self.Q / self.length[i]
        # 信息素矩阵更新
        self.information = (1 - self.rho) * self.information + information_increase
        self.iter += 1

    def paint(self):
        # 绘图
        x = []
        y = []
        road = []
        for i in range(len(self.r_best[-1])):
            x.append(self.city_location[self.r_best[-1][i]][0])
            y.append(self.city_location[self.r_best[-1][i]][1])
            road.append(self.r_best[-1][i])
        x.append(x[0])  #回到开始城市
        y.append(y[0])
        road.append(road[0])
        plt.figure(figsize=(30, 30))
        plt.rcParams['font.family'] = ['Fangsong'] #设置字体
        for i in range(len(x)):
            #注释
            plt.annotate(str(road[i]) + ':' + '(' + str(x[i]) + ',' + str(x[i]) + ')',
                         xy=(x[i], y[i]), xytext=(x[i] + 0.5, y[i] + 0.5), color='r')
        plt.plot(x, y, 'g-o')
        plt.title('最短距离:' + str(self.d_best[-1]), fontsize=40)
        plt.xlabel('x', fontsize=40)
        plt.ylabel('y', fontsize=40, rotation='horizontal')
        plt.show()

        plt.figure()
        plt.title("迭代距离变化")  # 距离迭代图
        plt.plot([i for i in range(1, len(self.d_best) + 1)], self.d_best)
        plt.xlabel("迭代次数")  # 迭代次数
        plt.ylabel("距离")  # 距离值
        plt.show()

    def run(self):
        self.get_dictance()
        while self.iter<=self.max_iter:
            self.get_firstplace()
            self.get_nextplace()
            self.get_best()
            self.update_infor()
        print('蚁群最优路径', self.r_best[-1])
        print('最优解', self.d_best[-1])
        self.paint()

if __name__ == '__main__':
    tsp=TSP()
    tsp.run()


 

  • 31
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
蚁群算法(Ant Colony Optimization,ACO)是一种模拟蚂蚁寻找食物的行为进行优化的算法。下面是一个在C#中实现蚁群算法的示例代码: ```csharp using System; using System.Collections.Generic; class AntColonyOptimization { private int numAnts; // 蚂蚁数量 private int numCities; // 城市数量 private double[,] distanceMatrix; // 城市间距离矩阵 private double[,] pheromoneMatrix; // 信息素矩阵 private double alpha; // 信息素重要程度因子 private double beta; // 启发式因子 private double evaporationRate; // 信息素挥发率 private double initialPheromone; // 初始信息素浓度 private int maxIterations; // 最大迭代次数 public AntColonyOptimization(int numAnts, int numCities, double[,] distanceMatrix, double alpha, double beta, double evaporationRate, double initialPheromone, int maxIterations) { this.numAnts = numAnts; this.numCities = numCities; this.distanceMatrix = distanceMatrix; this.alpha = alpha; this.beta = beta; this.evaporationRate = evaporationRate; this.initialPheromone = initialPheromone; this.maxIterations = maxIterations; InitializePheromoneMatrix(); } private void InitializePheromoneMatrix() { pheromoneMatrix = new double[numCities, numCities]; for (int i = 0; i < numCities; i++) { for (int j = 0; j < numCities; j++) { pheromoneMatrix[i, j] = initialPheromone; } } } public List<int> FindShortestPath() { List<int> shortestPath = null; double shortestDistance = double.MaxValue; for (int iteration = 0; iteration < maxIterations; iteration++) { List<List<int>> antPaths = ConstructAntPaths(); UpdatePheromoneMatrix(antPaths); foreach (var path in antPaths) { double distance = CalculatePathDistance(path); if (distance < shortestDistance) { shortestDistance = distance; shortestPath = path; } } EvaporatePheromoneMatrix(); } return shortestPath; } private List<List<int>> ConstructAntPaths() { List<List<int>> antPaths = new List<List<int>>(); for (int ant = 0; ant < numAnts; ant++) { List<int> path = new List<int>(); bool[] visited = new bool[numCities]; int currentCity = new Random().Next(numCities); path.Add(currentCity); visited[currentCity] = true; while (path.Count < numCities) { int nextCity = ChooseNextCity(currentCity, visited); path.Add(nextCity); visited[nextCity] = true; currentCity = nextCity; } antPaths.Add(path); } return antPaths; } private int ChooseNextCity(int currentCity, bool[] visited) { double[] probabilities = new double[numCities]; double totalProbability = 0; for (int city = 0; city < numCities; city++) { if (!visited[city]) { probabilities[city] = Math.Pow(pheromoneMatrix[currentCity, city], alpha) * Math.Pow(1.0 / distanceMatrix[currentCity, city], beta); totalProbability += probabilities[city]; } } double randomValue = new Random().NextDouble(); for (int city = 0; city < numCities; city++) { if (!visited[city]) { probabilities[city] /= totalProbability; if (randomValue <= probabilities[city]) { return city; } randomValue -= probabilities[city]; } } return -1; } private void UpdatePheromoneMatrix(List<List<int>> antPaths) { for (int i = 0; i < numCities; i++) { for (int j = 0; j < numCities; j++) { if (i != j) { pheromoneMatrix[i, j] *= (1 - evaporationRate); foreach (var path in antPaths) { if (path.Contains(i) && path.Contains(j)) { pheromoneMatrix[i, j] += 1.0 / CalculatePathDistance(path); } } } } } } private void EvaporatePheromoneMatrix() { for (int i = 0; i < numCities; i++) { for (int j = 0; j < numCities; j++) { pheromoneMatrix[i, j] *= (1 - evaporationRate); } } } private double CalculatePathDistance(List<int> path) { double distance = 0; for (int i = 0; i < path.Count - 1; i++) { distance += distanceMatrix[path[i], path[i + 1]]; } return distance; } } ``` 上述代码实现了一个AntColonyOptimization类,可以用于解决旅行商问题。其中numAnts表示蚂蚁数量,numCities表示城市数量,distanceMatrix表示城市间距离矩阵,alpha和beta分别表示信息素重要程度因子和启发式因子,evaporationRate表示信息素挥发率,initialPheromone表示初始信息素浓度,maxIterations表示最大迭代次数。 你可以根据需要修改以上代码,并使用以下示例进行测试: ```csharp class Program { static void Main(string[] args) { int numAnts = 10; int numCities = 5; double[,] distanceMatrix = new double[,] { { 0, 2, 1, 3, 4 }, { 2, 0, 4, 1, 2 }, { 1, 4, 0, 5, 2 }, { 3, 1, 5, 0, 3 }, { 4, 2, 2, 3, 0 } }; double alpha = 1.0; double beta = 2.0; double evaporationRate = 0.5; double initialPheromone = 1.0; int maxIterations = 100; AntColonyOptimization aco = new AntColonyOptimization(numAnts, numCities, distanceMatrix, alpha, beta, evaporationRate, initialPheromone, maxIterations); List<int> shortestPath = aco.FindShortestPath(); Console.WriteLine("Shortest Path: " + string.Join(" -> ", shortestPath)); Console.WriteLine("Shortest Distance: " + aco.CalculatePathDistance(shortestPath)); } } ``` 希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星辰境末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值