蚁群算法(ant colony optimization, ACO),又称蚂蚁算法,是一种用来在图中寻找优化路径的机率型算法。它由Marco Dorigo于1992年在他的博士论文中提出,其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。蚁群算法是一种模拟进化算法,初步的研究表明该算法具有许多优良的性质。针对PID控制器参数优化设计问题,将蚁群算法设计的结果与遗传算法设计的结果进行了比较,数值仿真结果表明,蚁群算法具有一种新的模拟进化优化方法的有效性和应用价值。
如果我们要为蚂蚁设计一个人工智能的程序,那么这个程序要多么复杂呢?首先,你要让蚂蚁能够避开障碍物,就必须根据适当的地形给它编进指令让他们能够巧妙的避开障碍物,其次,要让蚂蚁找到食物,就需要让他们遍历空间上的所有点;再次,如果要让蚂蚁找到最短的路径,那么需要计算所有可能的路径并且比较它们的大小,而且更重要的是,你要小心翼翼地编程,因为程序的错误也许会让你前功尽弃。这是多么不可思议的程序!太复杂了,恐怕没人能够完成这样繁琐冗余的程序。
然而,事实并没有你想得那么复杂,上面这个程序每个蚂蚁的核心程序编码不过100多行!为什么这么简单的程序会让蚂蚁干这样复杂的事情?答案是:简单规则的涌现。事实上,每只蚂蚁并不是像我们想象的需要知道整个世界的信息,他们其实只关心很小范围内的眼前信息,而且根据这些局部信息利用几条简单的规则进行决策,这样,在蚁群这个集体里,复杂性的行为就会凸现出来。这就是人工生命、复杂性科学解释的规律!那么,这些简单规则是什么呢?
1、范围
蚂蚁观察到的范围是一个方格世界,蚂蚁有一个参数为速度半径(一般是3),那么它能观察到的范围就是3*3个方格世界,并且能移动的距离也在这个范围之内。
2、环境
蚂蚁所在的环境是一个虚拟的世界,其中有障碍物,有别的蚂蚁,还有信息素,信息素有两种,一种是找到食物的蚂蚁洒下的食物信息素,一种是找到窝的蚂蚁洒下的窝的信息素。每个蚂蚁都仅仅能感知它范围内的环境信息。环境以一定的速率让信息素消失。
3、觅食规则
在每只蚂蚁能感知的范围内寻找是否有食物,如果有就直接过去。否则看是否有信息素,并且比较在能感知的范围内哪一点的信息素最多,这样,它就朝信息素多的地方走,并且每只蚂蚁都会以小概率犯错误,从而并不是往信息素最多的点移动。蚂蚁找窝的规则和上面一样,只不过它对窝的信息素做出反应,而对食物信息素没反应。
4、移动规则
每只蚂蚁都朝向信息素最多的方向移,并且,当周围没有信息素指引的时候,蚂蚁会按照自己原来运动的方向惯性的运动下去,并且,在运动的方向有一个随机的小的扰动。为了防止蚂蚁原地转圈,它会记住刚才走过了哪些点,如果发现要走的下一点已经在之前走过了,它就会尽量避开。
5、避障规则
如果蚂蚁要移动的方向有障碍物挡住,它会随机的选择另一个方向,并且有信息素指引的话,它会按照觅食的规则行为。
6、信息素规则
每只蚂蚁在刚找到食物或者窝的时候撒发的信息素最多,并随着它走远的距离,播撒的信息素越来越少。
根据这几条规则,蚂蚁之间并没有直接的关系,但是每只蚂蚁都和环境发生交互,而通过信息素这个纽带,实际上把各个蚂蚁之间关联起来了。比如,当一只蚂蚁找到了食物,它并没有直接告诉其它蚂蚁这儿有食物,而是向环境播撒信息素,当其它的蚂蚁经过它附近的时候,就会感觉到信息素的存在,进而根据信息素的指引找到了食物。
package com.heng; import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; public class Main { public static void main(String[] args) { ACO aco; aco = new ACO(); try { aco.init("MyFile//eil51.tsp", 50); long start = System.currentTimeMillis(); aco.run(2000); aco.ReportResult(); long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); } catch (FileNotFoundException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } } }
package com.heng; import java.io.*; /** *蚁群优化算法,用来求解TSP问题 */ public class ACO { // 定义蚂蚁群 Ant[] ants; int antcount;// 蚂蚁的数量 int[][] distance;// 表示城市间距离 double[][] tao;// 信息素矩阵 int citycount;// 城市数量 int[] besttour;// 求解的最佳路径 int bestlength;// 求的最优解的长度 /** * 初始化函数 * @param filename tsp数据文件 * @param antnum 系统用到蚂蚁的数量 * @throws 如果文件不存在则抛出异常 */ public void init(String filename, int antnum) throws FileNotFoundException, IOException { antcount = antnum;//系统用到的蚂蚁数目 ants = new Ant[antcount]; // 读取数据 int[] x; int[] y; String strbuff; BufferedReader tspdata = new BufferedReader(new InputStreamReader( new FileInputStream(filename))); strbuff = tspdata.readLine();//48 System.out.println("strbuff = "+strbuff); citycount = Integer.valueOf(strbuff); distance = new int[citycount][citycount]; x = new int[citycount]; y = new int[citycount]; for (int citys = 0; citys < citycount; citys++) { strbuff = tspdata.readLine(); String[] strcol = strbuff.split(" "); x[citys] = Integer.valueOf(strcol[1]); y[citys] = Integer.valueOf(strcol[2]); } // 计算距离矩阵 for (int city1 = 0; city1 < citycount - 1; city1++) { distance[city1][city1] = 0; for (int city2 = city1 + 1; city2 < citycount; city2++) { distance[city1][city2] = (int) (Math.sqrt((x[city1] - x[city2]) * (x[city1] - x[city2]) + (y[city1] - y[city2]) * (y[city1] - y[city2])) + 0.5); distance[city2][city1] = distance[city1][city2]; } } distance[citycount - 1][citycount - 1] = 0; // 初始化信息素矩阵 tao = new double[citycount][citycount]; for (int i = 0; i < citycount; i++) { for (int j = 0; j < citycount; j++) { tao[i][j] = 0.1; } } bestlength = Integer.MAX_VALUE; besttour = new int[citycount + 1]; // 随机放置蚂蚁 for (int i = 0; i < antcount; i++) { ants[i] = new Ant(); ants[i].RandomSelectCity(citycount); } tspdata.close(); } /** * ACO的运行过程 * @param maxgen ACO的最多循环次数 */ public void run(int maxgen) { for (int runtimes = 0; runtimes < maxgen; runtimes++) { // 每一只蚂蚁移动的过程 for (int i = 0; i < antcount; i++) { for (int j = 1; j < citycount; j++) { ants[i].SelectNextCity(j, tao, distance); } // 计算蚂蚁获得的路径长度 ants[i].CalTourLength(distance); if (ants[i].tourlength < bestlength) { // 保留最优路径 bestlength = ants[i].tourlength; System.out.println("第" + runtimes + "代,发现新的解" + bestlength); for (int j = 0; j < citycount + 1; j++) besttour[j] = ants[i].tour[j]; } } // 更新信息素矩阵 UpdateTao(); // 重新随机设置蚂蚁 for (int i = 0; i < antcount; i++) { ants[i].RandomSelectCity(citycount); } } } /** * 更新信息素矩阵 */ private void UpdateTao() { double rou = 0.5; // 信息素挥发 for (int i = 0; i < citycount; i++) for (int j = 0; j < citycount; j++) tao[i][j] = tao[i][j] * (1 - rou); // 信息素更新 for (int i = 0; i < antcount; i++) { for (int j = 0; j < citycount; j++) { tao[ants[i].tour[j]][ants[i].tour[j + 1]] += 1.0 / ants[i].tourlength; } } } /** * 输出程序运行结果 */ public void ReportResult() { System.out.println("最优路径长度是" + bestlength); } }
package com.heng; import java.util.Random; /** * 蚂蚁类 */ public class Ant { /** * 蚂蚁获得的路径 */ public int[] tour; // unvisitedcity 取值是0或1, // 1表示没有访问过,0表示访问过 int[] unvisitedcity; /** * 蚂蚁获得的路径长度 */ public int tourlength; int citys; /** * 随机分配蚂蚁到某个城市中 同时完成蚂蚁包含字段的初始化工作 * @param citycount 总的城市数量 */ public void RandomSelectCity(int citycount) { citys = citycount; unvisitedcity = new int[citycount]; tour = new int[citycount + 1]; tourlength = 0; for (int i = 0; i < citycount; i++) { tour[i] = -1; unvisitedcity[i] = 1; } long r1 = System.currentTimeMillis(); Random rnd = new Random(r1); int firstcity = rnd.nextInt(citycount); unvisitedcity[firstcity] = 0; tour[0] = firstcity; } /** * 选择下一个城市 * @param index 需要选择第index个城市了 * @param tao 全局的信息素信息 * @param distance 全局的距离矩阵信息 */ public void SelectNextCity(int index, double[][] tao, int[][] distance) { double[] p; p = new double[citys]; double alpha = 1.0; double beta = 2.0; double sum = 0; int currentcity = tour[index - 1]; // 计算公式中的分母部分 for (int i = 0; i < citys; i++) { if (unvisitedcity[i] == 1) sum += (Math.pow(tao[currentcity][i], alpha) * Math.pow( 1.0 / distance[currentcity][i], beta)); } // 计算每个城市被选中的概率 for (int i = 0; i < citys; i++) { if (unvisitedcity[i] == 0) p[i] = 0.0; else { p[i] = (Math.pow(tao[currentcity][i], alpha) * Math.pow( 1.0 / distance[currentcity][i], beta)) / sum; } } long r1 = System.currentTimeMillis(); Random rnd = new Random(r1); double selectp = rnd.nextDouble(); // 轮盘赌选择一个城市; double sumselect = 0; int selectcity = -1; for (int i = 0; i < citys; i++) { sumselect += p[i]; if (sumselect >= selectp) { selectcity = i; break; } } if (selectcity == -1) System.out.println(); tour[index] = selectcity; unvisitedcity[selectcity] = 0; } /** * 计算蚂蚁获得的路径的长度 * @param distance 全局的距离矩阵信息 */ public void CalTourLength(int[][] distance) { tourlength = 0; tour[citys] = tour[0]; for (int i = 0; i < citys; i++) { tourlength += distance[tour[i]][tour[i + 1]]; } } }
案例代码下载:http://download.csdn.net/detail/u013043346/9327251