人工蜂群算法(源码)

本文介绍了人工蜂群算法在数值优化中的应用,算法的核心由雇佣蜂、旁观蜂和侦察蜂三种行为决定。适应度值修正确保最小值问题的解决,并利于轮盘赌选择。雇佣蜂在附近搜索,旁观蜂采用贪心策略选择最佳解,而侦察蜂则负责替换长时间无改进的解。整个过程通过不断迭代,寻找最优解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

人工蜂群算法(源码)

AN IDEA BASED ON HONEY BEE SWARM FOR NUMERICAL OPTIMIZATION

这篇论文没有讲到具体如何实现,但是大家可以通过去官网学习一下这个算法。

算法主要的变化,由三种蜜蜂的行为决定。

适应度值修正

 fitness  ( X m → ) = { 1 / ( 1 + f ( X m → ) )  if  f ( X m → ) ≥ 0 1 + a b s ( f ( X m → ) )  if  f ( X m → ) < 0 } \text { fitness }\left(\overrightarrow{X_m}\right)=\left\{\begin{array}{cl}1 /\left(1+f\left(\overrightarrow{X_m}\right)\right) & \text { if } f\left(\overrightarrow{X_m}\right) \geq 0 \\1+a b s\left(f\left(\overrightarrow{X_m}\right)\right) & \text { if } f\left(\overrightarrow{X_m}\right)<0\end{array}\right\}  fitness (Xm )= 1/(1+f(Xm ))1+abs(f(Xm )) if f(Xm )0 if f(Xm )<0

首先,人工蜂群算法做的是求解最小值的问题,为了使得后面的轮盘赌算法能更好的运行,所以使用了这个修正函数,当原来的适应度值越小的时候,修正后的适应度值就会变得更大,并且修正过后的适应度值都为正数,同时,当适应度值为正数时候他修改后的适应度值小于等1,适应度值为负数的时候,适应度值大于1。

雇佣蜂(employed bee)

雇佣蜂负责在蜜源的附近搜索

public void employeeMove(){
        for(int i = 0;i<employeeBeeSize;i++){
            int j = (int)(Math.random()*employeeBeeSize);
            while(j==i){
                j = (int)(Math.random()*employeeBeeSize);//i!=j
            }//遍历所有的蜜源, 并且从里面挑出一个不是自己的蜜源的蜜源,i!=j
            int d = (int)(Math.random()*dimension);//随机挑一个维度进行变异
            Individual oldInd = honey.get(i);
            double xid = oldInd.getPosition().get(d);
            double xjd = honey.get(j).getPosition().get(d);
            double phi = Math.random()*2-1;//[-1,1)
            double vid = xid+phi*(xid-xjd);
            Position newPos = oldInd.getPosition().clone();
            newPos.set(d,vid);
            Individual newInd = new Individual(newPos);
            updateFitness(newInd);
            if(newInd.modifyFitness>oldInd.modifyFitness){//修正过以后越大越好
                honey.set(i,newInd);//贪婪交换
                trail[i]=0;
            }else {
                trail[i]++;
            }
        }
    }

这里是雇佣蜂的搜索

  • 遍历所有的雇佣蜂,由于直接将蜜源当成雇佣蜂来写比较方便,所以后面不管是雇佣蜂还是旁观蜂都用蜜源(honey表示)
  • 随机挑一个和自己不一样的蜜源,并且挑选一个维度使用公式 x i d = x i d + ϕ ∗ ( x i d − x k d ) x_{id} = x_{id}+\phi *(x_{id}-x_{kd}) xid=xid+ϕ(xidxkd)进行变异,其中i是当前的蜜源,k是随机挑出来的蜜源,d代表着要变异的维度, ϕ \phi ϕ为(-1,1)上面均匀分布的随机数。
  • 假如更新过后的蜜源比原来的蜜源要好,就替换,假如不是则 t r a i l trail trail增加, t r a i l trail trail是记录当前的蜜源有多久没有变化的。 t r a i l trail trail具有上限,当 t r a i l trail trail超过 l i m i t limit limit值的时候就会进行侦察峰的行为, l i m i t = d i m e n s i o n ∗ 10 limit = dimension * 10 limit=dimension10

旁观蜂(onlooker bee)

public void onlookerMove(){
        double sum = 0;
        for(int i = 0;i<employeeBeeSize;i++){
            sum+=honey.get(i).getModifyFitness();
        }
        for(int i = 0;i<onlookersSize;i++){
            double prob = Math.random()*sum;
            int select = 0;
            double curProb = 0;
            for(int j = 0;j<employeeBeeSize;j++){
                curProb+=honey.get(j).getModifyFitness();
                if(prob<curProb){
                    select = j;
                    break;
                }
            }
            int selectDimension = (int)(dimension*Math.random());
            Individual oldInd = honey.get(i);
            double xid = oldInd.getPosition().get(selectDimension);
            double xjd = honey.get(select).getPosition().get(selectDimension);
            double phi = Math.random()*2-1;//[-1,1)
            double vid = xid+phi*(xid-xjd);
            Position newPos = oldInd.getPosition().clone();
            newPos.set(selectDimension,vid);
            Individual newInd = new Individual(newPos);
            updateFitness(newInd);
            if(newInd.modifyFitness>oldInd.modifyFitness){//最大化修正过的适应度值,mini
                honey.set(i,newInd);//贪婪交换
                trail[i]=0;
            }else {
                trail[i]++;
            }
        }
    }

旁观蜂阶段大致是和雇佣蜂阶段相同的,最大的不同点就是,雇佣蜂阶段使用的是随机挑选一个雇佣蜂进行跟随,但是在旁观蜂阶段使用的是贪心形选择,将修正过后的适应度值作为选取轮盘赌的依据

轮盘赌的公式为:

p m = f i t m ( X m → ) ∑ m = 1 ∣ P ∣ f i t m ( X m → ) p_m=\frac{f i t_m\left(\overrightarrow{X_m}\right)}{\sum_{m=1}^{|P|} f i t_m\left(\overrightarrow{X_m}\right)} pm=m=1Pfitm(Xm )fitm(Xm )

注意这里的fit为修改过后的适应度值,修改过后的适应度值越大,则在该轮被选取的概率越大。

同样的,这里变化的公式为 x i d = x i d + ϕ ∗ ( x i d − x k d ) x_{id} = x_{id}+\phi *(x_{id}-x_{kd}) xid=xid+ϕ(xidxkd),k为根据轮盘赌选出的蜜蜂。

侦察峰(scout bee)

侦察峰

public void scoutMove(){
        int selectMaxTrail = 0;
        int limit = dimension*10;
        for(int i = 0;i<employeeBeeSize;i++){//find max trail bee
            if(trail[i]>limit&&trail[selectMaxTrail]< trail[i]){
                selectMaxTrail = i;
            }
        }
        if(trail[selectMaxTrail]>limit){
            Individual scout = new Individual(positionFactory.initRandomPosition());
            updateFitness(scout);
            trail[selectMaxTrail] = 0;
            honey.set(selectMaxTrail,scout);
        }
    }

这里就是每一轮都挑出最大的trail的蜜源出来,假如蜜源超过上限的话,就重新初始化这个蜜源。

总体流程就是这样↓

将侦察蜂送到初始化的食物源
重复
	雇佣蜂行为
	旁观蜂行为
	侦察峰行为
	记录下最优解
直到(需求被满足)

总体流程代码

import java.util.*;

//人工蜂群优化算法
public class ABC{
    int populationSize = 40;
    int onlookersSize = populationSize/2;//跟随蜂
    int employeeBeeSize = populationSize/2;//雇佣蜂
    Individual scout;
    List<Individual> honey;
    PositionFactory positionFactory;

    Individual bestBee;
    int dimension;
    int trail[];//记录迭代次数
    public ABC(int dimension,int ub,int lb){
        this.dimension = dimension;
        positionFactory = new PositionFactory(dimension,ub,lb);
        init();
        int iterTime = 0;
        int maxIterTime = 1000;
        while(iterTime<maxIterTime){
            employeeMove();
            onlookerMove();
            recordBest();
            scoutMove();
            recordBest();
            iterTime++;
            System.out.println(bestBee.fitness+"   "+bestBee.modifyFitness);
        }
    }

    public static void main(String[] args) {
        new ABC(2,4,-2);
    }
    public void init(){
        scout = new Individual(positionFactory.initRandomPosition());
        updateFitness(scout);
        honey = new ArrayList<>(onlookersSize);
        for (int i = 0; i < onlookersSize; i++) {
            Position p = positionFactory.initRandomPosition();
            Individual individual = new Individual(p);
            updateFitness(individual);
            honey.add(individual);
        }
        trail = new int[onlookersSize];
        Arrays.fill(trail,0);

    }
    public void employeeMove(){
        for(int i = 0;i<employeeBeeSize;i++){
            int j = (int)(Math.random()*employeeBeeSize);
            while(j==i){
                j = (int)(Math.random()*employeeBeeSize);//i!=j
            }
            int d = (int)(Math.random()*dimension);
            Individual oldInd = honey.get(i);
            double xid = oldInd.getPosition().get(d);
            double xjd = honey.get(j).getPosition().get(d);
            double phi = Math.random()*2-1;//[-1,1)
            double vid = xid+phi*(xid-xjd);
            Position newPos = oldInd.getPosition().clone();
            newPos.set(d,vid);
            Individual newInd = new Individual(newPos);
            updateFitness(newInd);
            if(newInd.modifyFitness>oldInd.modifyFitness){//修正过以后越大越好
                honey.set(i,newInd);//贪婪交换
                trail[i]=0;
            }else {
                trail[i]++;
            }
        }
    }
    public void onlookerMove(){
        double sum = 0;
        for(int i = 0;i<employeeBeeSize;i++){
            sum+=honey.get(i).getModifyFitness();
        }
        for(int i = 0;i<onlookersSize;i++){
            double prob = Math.random()*sum;
            int select = 0;
            double curProb = 0;
            for(int j = 0;j<employeeBeeSize;j++){
                curProb+=honey.get(j).getModifyFitness();
                if(prob<curProb){
                    select = j;
                    break;
                }
            }
            int selectDimension = (int)(dimension*Math.random());
            Individual oldInd = honey.get(i);
            double xid = oldInd.getPosition().get(selectDimension);
            double xjd = honey.get(select).getPosition().get(selectDimension);
            double phi = Math.random()*2-1;//[-1,1)
            double vid = xid+phi*(xid-xjd);
            Position newPos = oldInd.getPosition().clone();
            newPos.set(selectDimension,vid);
            Individual newInd = new Individual(newPos);
            updateFitness(newInd);
            if(newInd.modifyFitness>oldInd.modifyFitness){//最大化修正过的适应度值,mini
                honey.set(i,newInd);//贪婪交换
                trail[i]=0;
            }else {
                trail[i]++;
            }
        }
    }
    public void scoutMove(){
        int selectMaxTrail = 0;
        int limit = dimension*10;
        for(int i = 0;i<employeeBeeSize;i++){//find max trail bee
            if(trail[i]>limit&&trail[selectMaxTrail]< trail[i]){
                selectMaxTrail = i;
            }
        }
        if(trail[selectMaxTrail]>limit){
            Individual scout = new Individual(positionFactory.initRandomPosition());
            updateFitness(scout);
            trail[selectMaxTrail] = 0;
            honey.set(selectMaxTrail,scout);
        }
    }
    //求解最小值问题
    public void recordBest(){
        Individual curBestBee = Collections.min(honey, new Comparator<Individual>() {
            @Override
            public int compare(Individual o1, Individual o2) {
                return new Double(o1.getFitness()).compareTo(new Double(o2.getFitness()));
            }
        });

        if(bestBee==null){
            bestBee = curBestBee;
        }else if(bestBee.fitness>curBestBee.fitness){
            bestBee = curBestBee;
        }
    }
    public void updateFitness(Individual individual){
        individual.fitness = sinsin(individual.getPosition());
        individual.modifyFitness = modifyFitness(individual.fitness);
    }
    public static double Michalewicz(Position position){
        double res = 0;
        double m = 10;
        for (int i = 0; i < position.size(); i++) {
            double x = position.get(i);
            res+=-Math.sin(x)*Math.pow(Math.sin((i+1)*x*x/Math.PI),2*m);
        }
        return res;
    }
    public static double sinsin(Position position){
        double res = 0;
        for(int i = 0;i<position.size();i++){
            double x = position.get(i);
            res+=Math.sin(x);
        }
        return res;
    }
    public static double modifyFitness(double value){
        if(value>=0){
            return 1.0/(1.0+value);
        }else {
            return 1+Math.abs(value);
        }
    }
}

总结

这篇算法有粒子群算法的影子,在旁观蜂阶段使用轮盘赌算法,同时也有差分进化算法的影子:雇佣蜂阶段搜索猎物。而且这个算法没有什么需要调参的地方,感觉还行,这篇算法要注意的地方是适应度修正的地方然后就没有了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值