人工鱼群算法超详细解析附带JAVA代码
01 前言
本着学习的心态,还是想把这个算法写一写,给大家科普一下的吧。
02 人工鱼群算法
2.1 定义
人工鱼群算法为山东大学副教授李晓磊2002年从鱼找寻食物的现象中表现的种种移动寻觅特点中得到启发而阐述的仿生学优化方案。在一片水域中,鱼往往能自行或尾随其他鱼找到营养物质多的地方,因而鱼生存数目最多的地方一般就是本水域中营养物质最多的地方,人工鱼群算法就是根据这一特点,通过构造人工鱼来模仿鱼群的觅食、聚群及追尾行为,从而实现寻优。人工鱼拥有以下几种典型行为:
(1)觅食行为:一般情况下鱼在水中随机地自由游动,当发现食物时,则会向食物逐渐增多的方向快速游去。
(2)聚群行为:鱼在游动过程中为了保证自身的生存和躲避危害会自然地聚集成群,鱼聚群时所遵守的规则有三条:分隔规则:尽量避免与临近伙伴过于拥挤;对准规则:尽量与临近伙伴的平均方向一致;内聚规则:尽量朝临近伙伴的中心移动。
(3)追尾行为:当鱼群中的一条或几条鱼发现食物时,其临近的伙伴会尾随其快速到达食物点。
(4)随机行为:单独的鱼在水中通常都是随机游动的,这是为了更大范围地寻找食物点或身边的伙伴。
2.2 算法具体过程
人工鱼群算法实现的步骤:
初始化设置,包括种群规模N、每条人工鱼的初始位置、人工鱼的视野Visual、步长step、拥挤度因子δ、重复次数Trynumber;
计算初始鱼群各个体的适应值,取最优人工鱼状态及其值赋予给公告牌;
对每个个体进行评价,对其要执行的行为进行选择,包括觅食Pray、聚群Swarm、追尾Follow和评价行为bulletin;
执行人工鱼的行为,更新自己,生成新鱼群;
评价所有个体。若某个体优于公告牌,则将公告牌更新为该个体;
当公告牌上最优解达到满意误差界内或者达到迭代次数上限时算法结束,否则转步骤3。
2.3 算法流程图
2.4 算法伪代码
procedure code :
Artificial_Fishswarm_Algorithm
::AF_init();
while the result isnot satisfied do
switch(::AF_evaluate())
case value1:
::AF_follow();
case value2:
::AF_swarm();
default:
::AF_prey();
end switch
::AF_move();
get_result();
end while
end Artificial_FFishswarm_Algorithm
03 参数解析
人工鱼群算法有5个基本参数:群规模N、人工鱼的视野Visual、步长Step、拥挤度因子δ、重复次数Trynumber。
- 视野Visual:
动物的观察力是及其深奥的,它可以很快的洞察到周边的物体,鱼类的视野中分为连续型视野和离散型视野两类,应用如下方法实现虚拟人工鱼的视觉:图2.1(a)表示具有连续型视野的一条假设的人工鱼个体,它能看到的区域 Visual 为以现在位置 Xi为圆心一定距离为半径的圆形区域,地点 Xj为它在一个时候巡视到的视点种另一地方,如果这个地点的食物量比之前地方的多,就决定去这个地方前进步长的随机数达到地点 Xnext;人工鱼的离散型视野为与节点位置 Xi 相邻且相通的所有节点,如图 2.1(b)所示,根据判断边的代价来选择下一步位置 Xnext。
由于视野对算法中个行为都有较大影响,因此,它的变化对收敛性能影响也比较复杂。当视野范围较小时,人工鱼的觅食行为和随机行为比较突出;视野范围较大时,人工鱼的追尾行为和聚群行为将变得比较突出,相应的算法的复杂度也会有所上升。总的来说:视野越大,越容易使人工鱼发现全局最优解并收敛。
步长Step:对于固定步长,随着步长的增加,收敛的速度得到了一定的加速,但在超过一定的范围后,有使得收敛速度减缓,步长过大时会出现震荡现象而大大影响收敛速度。采用随机步长的方式在一定程度上防止了震荡现象的发生,并使得该参数的敏感度大大降低了,但最快的收敛速度还是最优固定步长的收敛速度,所以,对于特定的优化问题,我们可以考虑采用合适的固定步长或者变尺度方法来提高收敛速度。
群规模N:人工鱼的数目越多,跳出局部最优解的能力越强,同时,收敛的速度也越快。当然,付出的代价就是算法每次迭代的计算量也越大,因此,在使用过程中,满足稳定收敛的前提下,应当尽可能的减少个体数目。
尝试次数Trynumber:尝试次数越多,人工鱼的觅食行为能力越强,收敛的效率也越高。在局部极值突出的情况下,应该适当的减少以增加人工鱼随机游动的概率,克服局部最优解。
拥挤度因子δ:在求极大值问题中,δ=1/(αnmax),α∈(0,1]δ=1/(αnmax),α∈(0,1];在求极小值问题中,δ=αnmax,α∈(0,1]δ=αnmax,α∈(0,1]。其中α为极值接近水平, nmax为期望在该邻域内聚集的最大人工鱼数目。拥挤度因子与nf相结合,通过人工鱼是否执行追尾和聚群行为对优化结果产生影响。以极大值为例(极小值的情况正好与极大值相反),δ越大,表明允许的拥挤程度越小,人工鱼摆脱局部最优解的能力越强;但是收敛速度会有所减缓,这主要因为人工鱼在逼近最优解的同时,会因避免过分拥挤而随机走开或者受其他人工鱼的排斥作用,不能精确逼近极值点。可见,虽然δ的引入避免了人工鱼过度拥挤而陷入局部最优解,但是另一方面,该参数会使得位于极值点附件的人工鱼之间存在相互排斥的影响,而难以想极值点精确逼近。所以,对于某些局部极值不是很严重的具体问题,可以忽略拥挤的因素,从而在简化算法的同时也加快算法的收敛速度和提高结果的精确程度。
小结起来就是:
1.群规模:N越大收敛越快,越容易寻得全局最优解,但是计算量越大;
2.感知范围:视野越大,越易发现全局最优解;
3.步长:决定收敛速度;
4.拥挤因子:适当选择可避免局部最优
5.重复次数:越大收敛越快,可调整随机游走概率,克服局部最优解。
04 四种基本行为
4.1 觅食行为
这是鱼趋向食物的一种活动,一般认为它是通过视觉或味觉来感知水中的食物量或食物浓度来选择行动的方向。设置人工鱼当前状态,并在其感知范围内随机选择另一个状态,如果得到的状态的目标函数大于当前的状态,则向新选择得到的状态靠近一步,反之,重新选取新状态,判断是否满足条件,选择次数达到一定数量后,如果仍然不满足条件,则随机移动一步。
4.2 聚群行为
大量或少量的鱼聚集成群,进行集体觅食和躲避敌害,这是它们在进化过程中形成的一种生存方式。人工鱼探索当前邻居内的伙伴数量,并计算伙伴的中心位置,然后把新得到的中心位置的目标函数与当前位置的目标函数相比较,如果中心位置的目标函数优于当前位置的目标函数并且不是很拥挤,则当前位置向中心位置移动一步,否则执行觅食行为。鱼聚群时会遵守两条规则:一是尽量向邻近伙伴的中心移动,二是避免过分拥挤。
4.3 追尾行为
当某一条鱼或几条鱼发现食物时,它们附近的鱼会尾随而来,导致更远处的鱼也会尾随过来。人工鱼探索周围邻居鱼的最优位置,当最优位置的目标函数值大于当前位置的目标函数值并且不是很拥挤,则当前位置向最优邻居鱼移动一步,否则执行觅食行为。
4.4 随机行为
它是觅食行为的一个缺省行为,指人工鱼在视野内随机移动。当发现食物时,会向食物逐渐增多的方向快速的移动。
05 行为选择
公告牌是记录最优人工鱼个体状态的地方。每条人工鱼在执行完一次迭代后将自身当前状态与公告牌中记录的状态进行比较,如果优于公告牌中的状态则用自身状态更新公告牌中的状态,否则公告牌的状态不变。当整个算法的迭代结束后,公告牌的值就是最优解。
行为评价是用来反映鱼自主行为的一种方式,在解决优化问题时选用两种方式评价:一种是选择最优行为执行;另一种是选择较优方向。对于解决极大值问题,可以使用试探法,即模拟执行群聚、追尾等行为,然后评价行动后的值选择最优的来执行,缺省的行为为觅食行为。
一般通过试探法,模拟执行上述几种行为,评价后选择最大者实行;
06 终止条件
迭代终止条件:通常的方法是判断连续多次所得值得均方差小鱼允许的误差;或判断聚集于某个区域的人工鱼的数目达到某个比例;或连续多次所得的均值不超过已寻找的极值;或限制最大迭代次数。若满足终止条件,则输出公告牌的最优记录;否则继续迭代。
07 实现代码
7.1 主函数
package AFAS_PACK;
import java.io.IOException;
public class mainTest {
/**
* @param args
* @throws IOException
* @author sun
*/
public static void main(String[] args) throws IOException {
//int fishNum, int tryTime, int dim, double step, double delta, double visual
System.out.println("begin");
AFAS run = new AFAS(10,5,2,5,0.2,10);
run.doAFAS(40 );//括号内为迭代次数
}
}
7.2 人工鱼
package AFAS_PACK;
import java.io.IOException;
public class Fish {
public int dim; //每条鱼的维度
public int[] x; //每条鱼的具体多维坐标
public double fit; //鱼的适应值,浓度
public int visaul; //每条鱼的视野
public final double[] H = new double[256];
public final double[] W = new double[256];
public Fish(int dim, int visaul) throws IOException {
super();
this.dim = dim;
this.visaul = visaul;
x = new int[dim];
for(int i=0;i<dim;i++)
x[i] = (int) Math.floor(256*Math.random());
fit = 0;
//init();
}
/*getfit = newfunction(this.x[0],this.x[1]);*/
public double distance(Fish f)
{
double a = 0;
for(int i=0;i<dim;i++)
{
if(this.x[i]-f.x[i]==0)
a = 0.00001;
else
a += (this.x[i]-f.x[i])*(this.x[i]-f.x[i]);
}
return Math.sqrt(a);
}
public double newfunction(int[] w) throws IOException {
return -(w[0]*w[0]-160*w[0]+640+w[1]*w[1]-260*w[1]+16900);
}
}
7.3 AFAS算法部分
package AFAS_PACK;
import java.io.IOException;
import java.util.Date;
public class AFAS {
//鱼群数目
private int fishNum;
//尝试次数
private int tryTime;
//维度
private int dim;
//人工鱼移动步长
private int step;
//拥挤度因子
private double delta;
//视野范围
private int visual;
//人工鱼群、范围内最佳鱼,遍历时的下一条鱼
Fish[] fish;
Fish bestfish;
Fish[] nextfish;
//遍历索引
int index;
double[][] vector;
private int[] choosed;
//范围内鱼群数目 fishCount
public int scopelength;
public AFAS(){
}
public AFAS(int fishNum, int tryTime, int dim, int step, double delta, int visual) throws IOException
{
super();
this.fishNum = fishNum;
this.tryTime = tryTime;
this.dim = dim;
this.step = step;
this.delta = delta;
this.visual = visual;
fish = new Fish[fishNum];
nextfish = new Fish[3];
vector = new double[fishNum][dim];
choosed = new int[fishNum];
index = 0;
init();
}
public void doAFAS(int num) throws IOException
{
long startTime = new Date().getTime();
double a = 0.0;
int count = 1; //计算查找次数
int len = 0;
while(count<=num)
{
for(int i=0; i<fishNum; i++)
{
prey(i);
swarm(i);
follow(i);
bulletin(i);
System.out.println("第"+count+"遍第"+i+"条鱼结束");
}
System.out.println(count+"当前最优值:"+bestfish.fit);
for(int i=0; i<dim; i++)
{
System.out.print("位置"+(i+1)+": "+bestfish.x[i]);
}
System.out.println();
count++;
System.out.println("step:"+step+" visaul:"+visual);
}
System.out.println("最优值:"+bestfish.fit);
for(int i=0; i<dim; i++)
{
System.out.print("位置"+(i+1)+": "+bestfish.x[i]);
}
long endTime = new Date().getTime();
System.out.println("本程序运行计时: "+(endTime-startTime)+" 毫秒。");
}
private void bulletin(int i) throws IOException {
Fish maxfish = new Fish(dim,visual);
maxfish = nextfish[0];
for(int j=0;j<3;j++)
{
if(nextfish[j].fit>maxfish.fit && nextfish[j].x[0]!=0 && nextfish[j].x[1]!=0)
{
maxfish = nextfish[j];
}
}
if(maxfish.fit<fish[i].fit)
{
return ;
}
fish[i] = maxfish;
if(maxfish.fit>bestfish.fit)
bestfish = maxfish;
}
private void follow(int i) throws IOException {
nextfish[2] = new Fish(dim,visual);
Fish minfish = new Fish(dim,visual); // 中心位置
minfish = fish[i];
Fish[] scope = getScopefish(i);
int key = i;
if(scope!=null)
{
for(int j=0;j<scope.length;j++)
{
if(scope[j].fit<minfish.fit)
{
minfish = scope[j];
key = j;
}
}
if(minfish.fit>=fish[i].fit)
prey(i);
else{
Fish[] newScope = getScopefish(key);
if(newScope!=null)
{
if(newScope.length*minfish.fit<delta*fish[i].fit)
{
double dis = fish[i].distance(minfish);
for(int k=0;k<dim;k++)
{
nextfish[2].x[k] = (int) (fish[i].x[k]+(minfish.x[k]-fish[i].x[k])*step*Math.random()/dis);
}
nextfish[2].fit = nextfish[2].newfunction(nextfish[2].x);
}
else prey(i);
}
else prey(i);
}
}
else prey(i);
}
private void swarm(int i) throws IOException { //swam start
nextfish[1] = new Fish(dim,visual);
int[] center = new int[dim]; // 中心位置
for(int j=0;j<dim;j++)
center[j] = 0;
Fish[] scope = getScopefish(i);
if(scope!=null)
{
for(int j=0;j<scope.length;j++) // 计算人工鱼的中心位置
{
for( i=0; i<dim; ++i )
center[i] += scope[j].x[i];
}
for( i=0; i<dim; i++ )
center[i] /= scope.length; // 人工鱼的中心位置
//满足条件
double dis=0.0;
Fish centerfish = new Fish(dim,visual);
centerfish.x = center;
centerfish.fit = centerfish.newfunction(centerfish.x);
dis = fish[i].distance(centerfish);
if(centerfish.fit>fish[i].fit && scope.length*centerfish.fit<delta*fish[i].fit)
{
for(int j=0;j<dim;j++)
{
nextfish[1].x[j] = (int) (fish[i].x[j]+(centerfish.x[j]-fish[i].x[j])*step*Math.random()/dis);
}
nextfish[1].fit = nextfish[1].newfunction(nextfish[1].x);
}
else prey(i);
}
else prey(i);
} //swam end
private void prey(int i) throws IOException { //prey start
Fish newfish = new Fish(dim,visual);
newfish.fit = 0;
nextfish[0] = new Fish(dim,visual);
for(int k=0; k<tryTime; k++ ) // 进行try_number次尝试
{
for(int j=0; j<dim; j++ )
{
newfish.x[j] = (int) ((2*(Math.random())-1)*visual);
}
newfish.fit = newfish.newfunction(newfish.x);
if( newfish.fit > fish[i].fit )
{
double dis = fish[i].distance(newfish);
for(int j=0; j<dim; j++ )
{
nextfish[0].x[j] = (int) (fish[i].x[j]+(newfish.x[j]-fish[i].x[j])*step*Math.random()/dis);
}
nextfish[0].fit =nextfish[0].newfunction(nextfish[0].x);
}
else
{
for(int j=0; j<dim; j++)
{
nextfish[0].x[j] = (int) (fish[i].x[j]+visual*(2*(Math.random())-1));
nextfish[0].fit = nextfish[0].newfunction(nextfish[0].x);
}
}
}
}
private Fish[] getScopefish(int i) {
int num = 0;
for(int j=0;j<fishNum;j++)
{
choosed[j] = -1;
if(fish[i].distance(fish[j])<visual)
{
choosed[j] = i;
num++;
}
}
if(num!=0)
{
Fish[] scope = new Fish[num];
int k = 0;
for(int j=0;j<fishNum;j++)
{
if(choosed[j]!=-1)
scope[k++] = fish[choosed[j]];
}
return scope;
}
return null;
} //prey end
private void init() throws IOException {
for(int i=0;i<fishNum;i++)
{
fish[i] = new Fish(dim,visual);
fish[i].fit = fish[i].newfunction(fish[i].x);
}
bestfish = new Fish(dim,visual);
bestfish.fit = -999999;
}
}
人工鱼群算法超详细解析附带JAVA代码的更多相关文章
- GeoHash核心原理解析及java代码实现(转)
原文链接:http://blog.jobbole.com/80633/ 引子 机机是个好动又好学的孩子,平日里就喜欢拿着手机地图点点按按来查询一些好玩的东西.某一天机机到北海公园游玩,肚肚饿了,于是乎 ...
- mongoDB 分组并对分组结果筛选类似于SQL中的(group by xxx having ) 附带Java代码
今天需要做一个筛选程序,因为数据放在mongodb中,没写过分组的查询语句,查了一些资料,终于写出来了,分享给各位小伙伴 需求是 查询 学员 在2019-07-29之后未同步的数据(同一个学员需要2条 ...
- 干货 | 10分钟带你掌握branch and price(分支定价)算法超详细原理解析
00 前言 相信大家对branch and price的神秘之处也非常好奇了.今天我们一起来揭秘该算法原理过程.不过,在此之前,请大家确保自己的branch and bound和column gene ...
- Elasticsearch BM25相关度算法超详细解释
Photo by Pixabay from Pexels 前言:日常在使用Elasticsearch的搜索业务中多少会出现几次 "为什么这个Doc分数要比那个要稍微低一点?".&q ...
- 【优化算法】Greedy Randomized Adaptive Search算法 超详细解析,附代码实现TSP问题求解
01 概述 Greedy Randomized Adaptive Search,贪婪随机自适应搜索(GRAS),是组合优化问题中的多起点元启发式算法,在算法的每次迭代中,主要由两个阶段组成:构造(co ...
- 微信公众平台开发详细步骤与java代码
1.微信公众平台设置 首先在https://mp.weixin.qq.com/注册一个公众平台账号(服务号.订阅号.企业号的区别) 微信公众平台地址:https://mp.weixin.qq.com ...
- 干货 | 10分钟搞懂branch and bound(分支定界)算法的代码实现附带java代码
Outline 前言 Example-1 Example-2 运行说明 00 前言 前面一篇文章我们讲了branch and bound算法的相关概念.可能大家对精确算法实现的印象大概只有一个,调用求 ...
- 【智能算法】变邻域搜索算法(Variable Neighborhood Search,VNS)超详细解析和TSP代码实例以及01背包代码实例
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 00 目录 局部搜索再次科普 变邻域搜索 造轮子写代码 01 局部搜索科普三连 虽然之前做的很多篇启发式的算法都有跟大家提过局部 ...
- 最全排序算法原理解析、java代码实现以及总结归纳
算法分类 十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间非比较类排序:不通过 ...
随机推荐
- mybatis逆向工程的注意事项:mapper文件内容不是覆盖而是追加
XXXMapper.xml文件已经存在时,如果进行重新生成则mapper.xml文件内容不被覆盖而是进行内容追加,结果导致mybatis解析失败. 解决方法:删除原来已经生成的mapper xml文件 ...
- Java语句
Java的条件语句,循环语句 /* switch语句格式: switch(表达式) { case 值1: 语句体1; break; case 值2: 语句体2; break; ... default: ...
- Win10正式版怎么关闭windows defender
分步阅读 如何关闭Win10正式版系统所自带的"Windows Defender"程序呢?"Windows Defender"程序是Win10正式版系统所自带的 ...
- jquery的理解
1.jquery的好处 简化js的复杂操作 不再需要关心兼容性 提供大量使用方法 2.jquery的设计思想 选择网页元素 -模拟css选择元素 -独有的表达式选择 -多种筛选方法 写法 -方法函数化 ...
- appium镜像设置
npm --registry http://registry.cnpmjs.org install -g appium 使用npm的国内镜像可以安装,速度很不错. 以后不想输入ip的话可以输入以下命令 ...
- HDU1863 畅通工程 2017-04-12 19:25 59人阅读 评论(0) 收藏
畅通工程 Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submissi ...
- linux网络管理员
1. 查看当前开启的所有网络服务 命令:netstat -a (all)显示所有选项,默认不显示LISTEN相关-t (tcp)仅显示tcp相关选项-u (udp)仅显示udp相关选项-n 拒绝显示别 ...
- jsp中路径的写法
在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况 代码” ${pageContext.request.context ...
- 两段 PHP 代码比较优劣
// 代码一 public function getPCA($level = false) { $results = array(); $where = $level ? " where f ...
- 凭借对KMP算法的了解,用java实现了一下,结果和java自带的字符串indexOf比,性能差了十倍。。。
public class KMP { private char[] source = {'a','b','c','b','c','a','b','a','b','d','d','e','f','g', ...