蚁群算法

蚁群算法

AntColonyAlgorithm.png

一、背景

在蚂蚁觅食的过程中,单个蚂蚁的行为比较简单,但蚁群整体却可以体现一些智能的行为。
这是因为蚁群内的蚂蚁可以通过某种信息机制实现信息的传递。这种信息机制就是“信息素”。
蚂蚁会在其经过的路径上释放一种称之为“信息素”的物质,蚁群内的蚂蚁对“信息素”具有感知能力,它们会沿着“信息素”浓度较高的路径行走,而每只路过的蚂蚁都会在路上留下“信息素”,这就形成了一种类似正反馈的机制,这样经过一段时间后,整个蚁群就会沿着最短路径到达食物源了。

二、思想

将蚁群算法应用于解决优化问题的基本思路为:

  1. 解的表示:用蚂蚁的行走路径表示待优化问题的可行解,整个蚂蚁群体的所有路径构成待优化问题的解空间。
  2. 寻找最优解的过程:路径较短的蚂蚁释放的信息素量较多,随着时间的推进,较短的路径上累积的信息素浓度逐渐增高,选择该路径的蚂蚁个数也愈来愈多。(怎么表示解的偏向性?)
  3. 最优解:最终,整个蚂蚁会在正反馈的作用下集中到最佳的路径上,此时对应的便是待优化问题的最优解。

三、实现

蚂蚁找到最短路径要归功于信息素环境,假设有两条路可从蚁窝通向食物,开始时两条路上的蚂蚁数量差不多:当蚂蚁到达终点之后会立即返回,距离短的路上的蚂蚁往返一次时间短,重复频率快,在单位时间里往返蚂蚁的数目就多,留下的信息素也多,会吸引更多蚂蚁过来,会留下更多信息素。而距离长的路正相反,因此越来越多的蚂蚁聚集到最短路径上来。
蚂蚁具有的智能行为得益于其简单行为规则,该规则让其具有多样性正反馈。在觅食时,多样性使蚂蚁不会走进死胡同而无限循环,是一种创新能力;正反馈使优良信息保存下来,是一种学习强化能力。两者的巧妙结合使智能行为涌现,如果多样性过剩,系统过于活跃,会导致过多的随机运动,陷入混沌状态;如果多样性不够,正反馈过强,会导致僵化,当环境变化时蚁群不能相应调整。

四、规则

1. 感知范围
蚂蚁观察到的范围是一个方格世界,相关参数为速度半径,一般为3,可观察和移动的范围为3x3方格。
2. 环境信息
蚂蚁所在环境中有障碍物、其他蚂蚁、信息素,其中信息素包括食物信息素(找到食物的蚂蚁留下的)、窝信息素(找到窝的蚂蚁留下的),信息素以一定速率消失。
3. 觅食规则
蚂蚁在感知范围内寻找食物,如果感知到就会过去;否则朝信息素多的地方走,每只蚂蚁会以小概率犯错误,并非都往信息素最多的方向移动。蚂蚁找窝的规则类似,仅对窝信息素有反应。
4. 移动规则
蚂蚁朝信息素最多的方向移动,当周围没有信息素指引时,会按照原来运动方向惯性移动。而且会记住最近走过的点,防止原地转圈。
5. 避障规则
当蚂蚁待移动方向有障碍物时,将随机选择其他方向;当有信息素指引时,将按照觅食规则移动。
6. 散发信息素规则
在刚找到食物或者窝时,蚂蚁散发的信息素最多;当随着走远时,散发的信息素将逐渐减少。

五、特点

与其他优化算法相比,蚁群算法具有以下几个特点:
(1)采用正反馈机制,使得搜索过程不断收敛,最终逼近最优解。
(2)每个个体可以通过释放信息素来改变周围的环境,且每个个体能够感知周围环境的实时变化,个体间通过环境进行间接地通讯
(3)搜索过程采用分布式计算方式,多个个体同时进行并行计算,大大提高了算法的计算能力和运行效率。
(4)启发式的概率搜索方式不容易陷入局部最优,易于寻找到全局最优解。

六、应用

6.1 TSP(旅行商问题)

6.1.1 分析

  1. 解空间:不同起点的闭合路径
  2. 寻找最优解的过程:尝试不同的路径
  3. 最优解:总长度最小的路径

运用人工蚁群算法求解TSP问题时的基本原理是:

  1. 将m个蚂蚁随机地放在多个城市
  2. 让这些蚂蚁从所在城市出发,n步(一个蚂蚁从一个城市到另外一个城市为1步)之后返回到出发城市。
  3. 如果m个蚂蚁所走出的m条路径中的最短者不是TSP问题的最短路程,则重复这一过程,直至寻找到满意的TSP问题的最短路径为止,流程图如下:


    AntColonyAlgorithmTSP.png

6.1.2 建立数学模型

(一)算法相关参数
\tau _{ij}:城市i和城市j之间边e_{ij}上信息素的残留强度;

\Delta\tau _{ij}:一次循环后边e_{ij}上信息素的增量

\Delta \tau_{ij}^{k}:一次循环之后蚂蚁k对边e_{ij}上信息素的贡献量

\eta _{ij}:城市ij之间的能见度,反映了由城市i转移到城市j的启发程度

d_{ij}:城市i到城市j之间的距离

p_{ij}^{k}:蚂蚁k从当前所在的城市到下一个城市去的概率

tabu(k):禁忌表,用于存放第k只蚂蚁已经走过的城市

Q:信息素总量,信息素总信息量为蚂蚁循环一周后向经过路径释放信息素的总量

\rho:信息素残留系数,由于蚂蚁释放的信息量回随着时间的转移而逐渐挥发,以至于路径上的信息素不能无限递增,该系数太小时会降低算法的全局搜素能力,过大时容易使算法陷入局部最优,影响全局搜素能力。

m:蚂蚁总数,在TSP问题中,每次循环当中,每只蚂蚁所走出的每条路径为TSP问题的候选解,m只蚂蚁一次循环所走出来的m条路经为TSP问题的一个解子集,所以这个解子集越大则算法的全局搜索能力越强,但是过大会使算法的收敛速度降低。如果m太小的话,算法也很容易就陷入局部最优,过早的出现停滞现象,(ps:王老师讲过曾经见到一个学生在论文中让一个蚂蚁去跑路径,老师开玩笑说,估计把这只蚂蚁就给累死了)所以选择合理的蚂蚁总数是非常重要的。

\alpha:信息启发因子,反应了蚂蚁在进行城市选择时,信息素会起多大的作用,即蚁群在路径搜素中随即性因素作用的强度。(反映了蚂蚁在从城市i向城市j移动时,这两个城市之间道路上所累积的信息素在指导蚂蚁选择城市j的程度。)

\beta:期望值启发式因子,反映了蚂蚁在从城市i向城市j转移时候期望值\eta _{ij}在指导蚁群搜素中的相对重要程度。其大小反映了蚁群在道路搜素中的先验性、确定性等因素的强弱,\alpha\beta的大小也会影响算法的收敛性。

参数影响分析:

AntColonyAlgorithmParameterEffect.png

常用参数取值:

AntColonyAlgorithmParameterSelect.png

(二)算法过程中的关键步骤

1、蚂蚁在选择下一个要转移的城市时候是基于概率选择的,这个概率并不是随机概率,而是其中的一些参数(由两个城市之间的信息素(信息素残留+信息启发因子)和城市能见度(城市能见度+能见度启发因子)共同决定)来决定。
假定在t时刻,蚂蚁从目前所在的i城市要选择转移去的下一个j城市,概率大小为p_{ij}^{k}:

p_{ij}^{k}= \begin{cases} {\tau_{ij}^{\alpha}*\eta _{ij}^\beta\over {\sum^{}_{s \in allowed_k}{\tau_{is}^{k}*\eta _{is}^\beta}}}, &if\ j \in \ allowed_k\\ 0, &otherwise \end{cases}

其中allowed_{k}表示允许蚂蚁k下一步可容许去的城市的集合(也就是不在禁忌表中的城市),\tau_{ij}^{\alpha}为边e_{ij}上的信息素因数,\eta_{ij}^{\beta}为城市ij间能见度因数。

2、对任意两个城市ij之间道路对应的边e_{ij}信息素增量按照下式进行:
\left \{ \begin{array}{c} \tau_{ij}(t+1) = \rho \tau_{ij}(t) + \Delta\tau _{ij}(t,t+1)\\ \Delta\tau _{ij}(t,t+1) = \sum_{k=1}^m \Delta\tau _{ij}^k(t,t+1) \end{array} \right.

其中,\Delta\tau_{ij}^{k}(t,t+1)为蚂蚁k对边e_{ij}上所贡献的信息素增量,\Delta\tau_{ij}(t,t+1) 是经过边e_{ij}的所有蚂蚁对边e_{ij}的信息素量贡献,\rho为信息素残留系数。对于\Delta\tau_{ij}^{k}(t,t+1)的调整方式不同,可以将蚁群算法分为三种模型:蚁密模型、蚁量模型和蚁周模型。

2.1 蚁密模型(Ant-Density模型)

在蚁密模型当中,每一只蚂蚁在经过城市i,j时,对该边e_{ij}所贡献的信息素增量为常量,每个单位长度是Q
\Delta\tau_{ij}^{k}(t,t+1)= \begin{cases} {Q}, &e_{ij}\\ 0, &otherwise \end{cases}

2.2 蚁量模型(Ant-Quantity模型)

在蚁量模型中,一只蚂蚁k在经过城市i,j之间边e_{ij}时,对该边所贡献的信息素增量为变量,为Q/d_{ij},它与城市i,j之间的路径长度d_{ij}有关,具体为:
\Delta\tau_{ij}^{k}(t,t+1)= \begin{cases} {Q\over {d_{ij}}}, &e_{ij}\\ 0, &otherwise \end{cases}

2.3 蚁周模型(Ant-Cycle模型)
上述两种模型,对两城市之间边e_{ij}上信息素贡献的增量在蚂蚁k经过边的同时完成,而蚁周模型对边e_{ij}信息素的增量是在本次循环结束时才进行更新调整。一只蚂蚁在经过城市ij时,对边e_{ij}上贡献的增量为每单位长度Q/L_{k}L_{k}为蚂蚁在本次循环走出路径的长度。
\Delta\tau_{ij}^{k}(t,t+1)= \begin{cases} {Q\over {L_{k}}}, &e_{ij}\\ 0, &otherwise \end{cases}

区别:
1.蚁周模型利用的是全局信息,即蚂蚁完成一个循环后更新所有路径上的信息素;
2.蚁量和蚁密模型利用的是局部信息,即蚂蚁完成一步后更新路径上的信息素。

AntColonyAlgorithmPheromoneUpdateClassify.png

(三)Java编程实现
编程分析:

  1. 初始化

    \tau _{ij}:二维数组,初始化值为0。 城市i和城市j之间边e_{ij}上信息素的残留强度;

    \eta _{ij}:随机数初始化。 城市ij之间的能见度,反映了由城市i转移到城市j的启发程度

    d_{ij}:初始化城市坐标,然后再初始化距离。 城市i到城市j之间的距离
    tabu(k):二维数组,蚂蚁数*城市数,初始化为空。 禁忌表,用于存放第k只蚂蚁已经走过的城市

    Q:信息素总量,信息素总信息量为蚂蚁循环一周后向经过路径释放信息素的总量

    \rho:信息素残留系数。

    m:蚂蚁总数。

    \alpha:信息启发因子。

    \beta:期望值启发式因子。

  2. 代码部分
    终于把错误改正了,觉得主要有一下两点需要注意:

  3. 使用的是“蚁周模型”(全局更新),而不是“蚁量模型”(局部更新),目前还没有找到两者主要的区别

  4. 一定要注意在蚂蚁没走过的路径上的信息素的挥发,否则结果很难收敛(但是目前还没分析出原因
    结果不收敛,找不到原因,望指教!!

import java.util.*;

public class AntColonyAlgorithm2 {
    public static final int n=50;//城市数
    public static final int m=50;//蚂蚁数
    public static final double alpha=1.0,beta=2.0;//信息启发因子+期望值启发因子
    public static final double rho=0.5,Q=100;//信息素挥发因子+信息素增量

    public static void main(String[] args) {
        Random random=new Random();
        int[] distance_x = {
        178,272,176,171,650,499,267,703,408,437,491,74,532,
                416,626,42,271,359,163,508,229,576,147,560,35,714,
                757,517,64,314,675,690,391,628,87,240,705,699,258,
                428,614,36,360,482,666,597,209,201,492,294};
        int[] distance_y = {
        170,395,198,151,242,556,57,401,305,421,267,105,525,
                381,244,330,395,169,141,380,153,442,528,329,232,48,
                498,265,343,120,165,50,433,63,491,275,348,222,288,
                490,213,524,244,114,104,552,70,425,227,331};
        //随机初始化城市的位置坐标
        City[] city=new City[AntColonyAlgorithm2.n];
        for(int i=0;i<AntColonyAlgorithm2.n;i++){
            city[i]=new City(distance_x[i],distance_y[i]);
//            city[i]=new City(random.nextInt(800),random.nextInt(600));
        }
        //初始化城市间的距离、信息素残留、能见度
        for(int i=0;i<AntColonyAlgorithm2.n;i++){
            for(int j=0;j<i;j++){
                //距离
//                city[i].d[j]=Math.sqrt(Math.pow((city[i].x-city[j].x),2)+Math.pow((city[i].y-city[j].y),2));
                city[i].d[j]=(double)(int)(Math.sqrt(Math.pow((city[i].x-city[j].x),2)+Math.pow((city[i].y-city[j].y),2))+0.5);
                city[j].d[i]=city[i].d[j];
                //信息素残留
                city[i].tau[j]=1.0;
                city[j].tau[i]=1.0;
                //能见度
//                city[i].eta[j]=1;
//                city[j].eta[i]=city[i].eta[j];
            }
            city[i].d[i]=0;
//            city[i].eta[i]=1;
            city[i].tau[i]=1;
//            System.out.println();
        }
        double min=1000000000;
        int NC_max=100;//定义最大循环次数
        for(int i=0;i<NC_max;i++){
            Ant[] ants=new Ant[AntColonyAlgorithm2.m];
            //每只蚂蚁都要走一条回路,然后进行比较
            for(int k=0;k<AntColonyAlgorithm2.m;k++){
                ants[k]=new Ant(random.nextInt(AntColonyAlgorithm2.n));
                ants[k].searchPath(city);
                if(ants[k].length<min){
                    min=ants[k].length;
                }
            }
            //更新路径信息素含量,这种跟新方法,那些没有蚂蚁经过的路径的信息素不会挥发
//            for(int j=0;j<AntColonyAlgorithm2.m;j++){
//                double incre=AntColonyAlgorithm2.Q/ants[j].length;
//                for(int k=0;k<AntColonyAlgorithm2.n;k++){
//                    city[ants[j].path[k]].tau[ants[j].path[k+1]]=city[ants[j].path[k]].tau[ants[j].path[k+1]]*AntColonyAlgorithm2.rho+incre;
//                    city[ants[j].path[k+1]].tau[ants[j].path[k]]=city[ants[j].path[k]].tau[ants[j].path[k+1]];
//                }
//            }

            double[][] incre=new double[AntColonyAlgorithm2.n][AntColonyAlgorithm2.n];
            for(int j=0;j< AntColonyAlgorithm2.n;j++){
                for (int k=0;k<AntColonyAlgorithm2.n;k++){
                    incre[j][k]=0.0;
                }
            }

            for(int j=0;j<AntColonyAlgorithm2.m;j++){
                for(int k=0;k<AntColonyAlgorithm2.n;k++){
                    incre[ants[j].path[k]][ants[j].path[k+1]]+=AntColonyAlgorithm2.Q/ants[j].length;
                    incre[ants[j].path[k+1]][ants[j].path[k]]=incre[ants[j].path[k]][ants[j].path[k+1]];
                }
            }

            for(int j=0;j< AntColonyAlgorithm2.n;j++){
                for (int k=0;k<AntColonyAlgorithm2.n;k++){
                    city[j].tau[k]=city[j].tau[k]*AntColonyAlgorithm2.rho+incre[j][k];
                }
            }

            //选出本轮的最佳路径
//            for(int a=0;a<AntColonyAlgorithm2.m;a++){
////                System.out.print(String.format("%1$.3f", ants[a].start));
////                System.out.print(ants[a].start);
////                System.out.print(' ');
//                if(ants[a].length<min){
//                    min=ants[a].length;
//                }
//            }
            System.out.println();
            System.out.println("第"+i+"轮,最短距离为:"+min);
        }
    }
}
class City{

    double x,y;
    //该城市到达其他城市的距离
    double[] d=new double[AntColonyAlgorithm2.n];
    //该城市与其他城市的边之间的信息素残留
    double[] tau=new double[AntColonyAlgorithm2.n];
    //能见度
    double[] eta=new double[AntColonyAlgorithm2.n];

    public City(){
        this.x=0;
        this.y=0;
    }
    public City(double x,double y){
        this.x=x;
        this.y=y;
    }
}

class AntCity{
    boolean unvisited;//该城市是否被访问
    double p;//该城市被访问的概率

    public AntCity(){
        this.unvisited=true;
    }
    public AntCity(boolean unvisited){
        this.unvisited=unvisited;
    }
}

class Ant{
    int start=0;//出发城市
    int cindex;//蚂蚁当前位置,城市标号
    int count;//记录该蚂蚁走过的城市数
    double length=0;//记录蚂蚁到目前为止走过的总长度

    int[] path=new int[AntColonyAlgorithm2.n+1];
    //未访问过的城市列表
    AntCity[] antCities=new AntCity[AntColonyAlgorithm2.n];

    //初始化
    public Ant(int cindex){
        this.start=cindex;
        this.cindex=cindex;

        for(int i=0;i<AntColonyAlgorithm2.n;i++){
            this.antCities[i]=new AntCity();
        }
        this.antCities[cindex].unvisited=false;
        this.count=0;
        this.path[this.count++]=cindex;
    }

    //选择要移动的城市
    public int chooseNextCity (City[] cities) {
        int to = -1;
        double sum = 0;
        //计算概率

        for (int i = 0; i < AntColonyAlgorithm2.n; i++) {
            //目前经过的城市到下一个所有城市的概率大小
            if (this.antCities[i].unvisited) {

                try {
                    this.antCities[i].p = Math.pow(( cities[cindex].tau[i]), AntColonyAlgorithm2.alpha) * Math.pow(1.0 / cities[cindex].d[i], AntColonyAlgorithm2.beta);
                    sum += this.antCities[i].p;
                } catch (Exception e) {

                    System.out.println("current city: " + this.cindex + "target city:" + to);
                    System.exit(-1);
                }
            } else {
                this.antCities[i].p = 0.0;
            }
        }

        //轮盘选择城市
        Random random = new Random();
        double rand = random.nextDouble() * sum;
//        System.out.println(rand+" "+sum);
        if (sum > 0.0) {
            for (int i = 0; i < AntColonyAlgorithm2.n; i++) {
                if (antCities[i].unvisited) {
                    rand -= this.antCities[i].p;
                    if (rand < 0.0) {
                        to = i;
                        break;
                    }
                }
            }
        }
        if (to == -1) {
            to = random.nextInt(AntColonyAlgorithm2.n);
            while (this.antCities[to].unvisited == false) {
                to = random.nextInt(AntColonyAlgorithm2.n);
            }
        }
        return to;
    }

    public void move(City[] cities,int to){
        //蚂蚁本次移动的距离
        double lengtht=cities[this.cindex].d[to];

        //蚂蚁做出移动
        if(this.cindex!=to) {
            //做出移动
            this.cindex = to;
            //更新禁忌表
            this.antCities[cindex].unvisited = false;
            this.antCities[cindex].p = 0;
            //更新路程总长度
            this.length += lengtht;
            this.path[this.count++]=this.cindex;
        }
    }

    public void searchPath(City[] cities){
        while (this.count<AntColonyAlgorithm2.n){
            int to=this.chooseNextCity(cities);
            this.move(cities,to);

        }
        //计算路径总长度
        this.length+=cities[this.path[this.count-1]].d[this.path[0]];
        this.path[this.count]=this.start;
    }
}


参考资料:
[1] https://baike.baidu.com/item/%E8%9A%81%E7%BE%A4%E7%AE%97%E6%B3%95
[2] https://www.cnblogs.com/yhgao96/articles/10887569.html
[3] https://blog.csdn.net/peachhhh/article/details/109501256

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容