人工鱼群算法超详细解析附带JAVA代码

01 前言

本着学习的心态,还是想把这个算法写一写,给大家科普一下的吧。

02 人工鱼群算法

2.1 定义

人工鱼群算法为山东大学副教授李晓磊2002年从鱼找寻食物的现象中表现的种种移动寻觅特点中得到启发而阐述的仿生学优化方案。在一片水域中,鱼往往能自行或尾随其他鱼找到营养物质多的地方,因而鱼生存数目最多的地方一般就是本水域中营养物质最多的地方,人工鱼群算法就是根据这一特点,通过构造人工鱼来模仿鱼群的觅食、聚群及追尾行为,从而实现寻优。人工鱼拥有以下几种典型行为:

(1)觅食行为:一般情况下鱼在水中随机地自由游动,当发现食物时,则会向食物逐渐增多的方向快速游去。

(2)聚群行为:鱼在游动过程中为了保证自身的生存和躲避危害会自然地聚集成群,鱼聚群时所遵守的规则有三条:分隔规则:尽量避免与临近伙伴过于拥挤;对准规则:尽量与临近伙伴的平均方向一致;内聚规则:尽量朝临近伙伴的中心移动。

(3)追尾行为:当鱼群中的一条或几条鱼发现食物时,其临近的伙伴会尾随其快速到达食物点。

(4)随机行为:单独的鱼在水中通常都是随机游动的,这是为了更大范围地寻找食物点或身边的伙伴。

2.2 算法具体过程

人工鱼群算法实现的步骤:

  1. 初始化设置,包括种群规模N、每条人工鱼的初始位置、人工鱼的视野Visual、步长step、拥挤度因子δ、重复次数Trynumber;
  2. 计算初始鱼群各个体的适应值,取最优人工鱼状态及其值赋予给公告牌;
  3. 对每个个体进行评价,对其要执行的行为进行选择,包括觅食Pray、聚群Swarm、追尾Follow和评价行为bulletin;
  4. 执行人工鱼的行为,更新自己,生成新鱼群;
  5. 评价所有个体。若某个体优于公告牌,则将公告牌更新为该个体;
  6. 当公告牌上最优解达到满意误差界内或者达到迭代次数上限时算法结束,否则转步骤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。

  1. 视野Visual:
    动物的观察力是及其深奥的,它可以很快的洞察到周边的物体,鱼类的视野中分为连续型视野和离散型视野两类,应用如下方法实现虚拟人工鱼的视觉:图2.1(a)表示具有连续型视野的一条假设的人工鱼个体,它能看到的区域 Visual 为以现在位置 Xi为圆心一定距离为半径的圆形区域,地点 Xj为它在一个时候巡视到的视点种另一地方,如果这个地点的食物量比之前地方的多,就决定去这个地方前进步长的随机数达到地点 Xnext;人工鱼的离散型视野为与节点位置 Xi 相邻且相通的所有节点,如图 2.1(b)所示,根据判断边的代价来选择下一步位置 Xnext。

由于视野对算法中个行为都有较大影响,因此,它的变化对收敛性能影响也比较复杂。当视野范围较小时,人工鱼的觅食行为和随机行为比较突出;视野范围较大时,人工鱼的追尾行为和聚群行为将变得比较突出,相应的算法的复杂度也会有所上升。总的来说:视野越大,越容易使人工鱼发现全局最优解并收敛。

  1. 步长Step:对于固定步长,随着步长的增加,收敛的速度得到了一定的加速,但在超过一定的范围后,有使得收敛速度减缓,步长过大时会出现震荡现象而大大影响收敛速度。采用随机步长的方式在一定程度上防止了震荡现象的发生,并使得该参数的敏感度大大降低了,但最快的收敛速度还是最优固定步长的收敛速度,所以,对于特定的优化问题,我们可以考虑采用合适的固定步长或者变尺度方法来提高收敛速度。
  2. 群规模N:人工鱼的数目越多,跳出局部最优解的能力越强,同时,收敛的速度也越快。当然,付出的代价就是算法每次迭代的计算量也越大,因此,在使用过程中,满足稳定收敛的前提下,应当尽可能的减少个体数目。
  3. 尝试次数Trynumber:尝试次数越多,人工鱼的觅食行为能力越强,收敛的效率也越高。在局部极值突出的情况下,应该适当的减少以增加人工鱼随机游动的概率,克服局部最优解。
  4. 拥挤度因子δ:在求极大值问题中,δ=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;
        }
}

原文地址:https://blog.51cto.com/14328065/2393219

时间: 2024-08-30 08:31:29

人工鱼群算法超详细解析附带JAVA代码的相关文章

YOLO3算法超详细代码分享(二):手撕测试代码(test)

我看了很多博客,也看了一些github大神的源码,很多基于一个版本改写而成.会将代码分成很多小.py文件,如建立YOLO3网络模块就会用一个.py文件, 如建立共用iou计算就会放在utils.py文件里,这让很多学习者,无从适应.我也为此困惑过,因此我将自己写的代码贡献在博客中,希望给你们有一些帮助. 而鉴于已有很多博客对YOLO3理论有很多的详细解说,为此,我将不再赘述,借用网上下图,一笔带过理论. 我声明,我的训练代码只有一个.py文件,训练文件可以单独运行,若需要运行我test文件代码,

【优化算法】Greedy Randomized Adaptive Search算法 超详细解析,附代码实现TSP问题求解

01 概述 Greedy Randomized Adaptive Search,贪婪随机自适应搜索(GRAS),是组合优化问题中的多起点元启发式算法,在算法的每次迭代中,主要由两个阶段组成:构造(construction)和局部搜索( local search). 构造(construction)阶段主要用于生成一个可行解,而后该初始可行解会被放进局部搜索进行邻域搜索,直到找到一个局部最优解为止. 02 整体框架 如上面所说,其实整一个算法的框架相对于其他算法来说还算比较简单明了,大家可以先看以

微信公众平台开发详细步骤与java代码

1.微信公众平台设置 首先在https://mp.weixin.qq.com/注册一个公众平台账号(服务号.订阅号.企业号的区别) 微信公众平台地址:https://mp.weixin.qq.com 登录微信公众平台后台,在左侧列表中最下方,找到“ 基本配置 ”,点击进入 进入服务器配置填写框. 点击“修改配置”按钮 这里url需要填以下申请好的地址,tocken需要填写代码中指定好的. 2.申请服务器资源 创建新浪云计算应用 申请账号 我们使用SAE新浪云计算平台作为服务器资源,申请地址为:

DES加密算法详细原理以及Java代码实现

本周的密码学实验要求使用任意编程语言来实现des加密算法,于是我在查阅了相关资料后有了以下成果. 首先,DES算法作为经典的分块密码(block cipher),其主要的实现过程由两部分组成,分别是密钥的生成以及明文的处理. 加密的大致流程如图所示 作为分块密码,密钥的输入以及明文的输入均为64位2进制数. 下面首先来说密钥的生成过程. 密钥处理部分如图所示 密钥的输入为64位,例如00010011 00110100 01010111 01111001 10011011 10111100 110

最全排序算法原理解析、java代码实现以及总结归纳

算法分类 十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序. 详情如下: 算法评估 排序算法的性能依赖于以下三个标准: 稳定性:如果a原本在b前面,而a=b,排序之后a仍然在b的前面,则稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在

人工鱼群算法简介及应用

简介 定义 人工鱼群算法为山东大学副教授李晓磊2002年从鱼找寻食物的现象中表现的种种移动寻觅特点中得到启发而阐述的仿生学优化方案.在一片水域中,鱼往往能自行或尾随其他鱼找到营养物质多的地方,因而鱼生存数目最多的地方一般就是本水域中营养物质最多的地方,人工鱼群算法就是根据这一特点,通过构造人工鱼来模仿鱼群的觅食.聚群及追尾行为,从而实现寻优.人工鱼拥有以下几种典型行为: /p> (1)觅食行为:一般情况下鱼在水中随机地自由游动,当发现食物时,则会向食物逐渐增多的方向快速游去. (2)聚群行为:鱼

java代码的初始化过程研究

刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻--)但是博主写的不够详细具体,我想在这详细谈一下java代码的具体初始化过程. 首先要清楚,初始化分为两个过程:类初始化.对象初始化. 类初始化是指类加载器将类加载到内存时,对类成员的初始化过程,也就是有static修饰的变量.对于加载完的类,它的类变量都会赋一个默认值,即使你定义时就赋值了.比如int类型就是0

Java当中的堆与栈详细解析

总结第一句话:Java语言使用内存的时候,栈内存主要保存以下内容:基本数据类型和对象的引用,而堆内存存储对象,栈内存的速度要快于堆内存.总结成一句话就是:引用在栈而对象在堆. Java疯狂讲义的一段对话作为开场白. 一个问题:为什么有栈内存和堆内存之分? 答:当一个方法执行时,每个方法都会简历自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁.因此,所有在方法中创建一个对象时,这个对象将被保存到运行时数据区中,以便利用(因为对象的创建成

java类生命周期详细解析

(一)详解java类的生命周期 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你“怎样做”,但至于“为什么这样做”却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正. 首先来了解一下jvm(java虚拟机)