人工蜂群算法(ABC算法)(Artificial Bee Colony)
Java实现测试函数Rastrigin,附上原型代码翻译后的注释。
题目:
待优化问题参数设置10个,运行一次,[-5.12,5.12]。
附上代码:
package ABCtest;
public class bee {
/* ABC算法的控制参数 */
int NP=20; /* 蜂群大小(雇佣蜂+观蜜蜂) (employed bees+onlooker bees)*/
int FoodNumber = NP/2; /*食物源的数量相当于蜂群数量的一半*/
int limit = 100; /*一种无法通过“限制”改善的食物源被其雇佣蜂抛弃*/
int maxCycle = 2500; /*觅食循环次数{一个停止条件}*/
/* 问题的特殊变量*/
int D = 10; /*待优化问题的参数个数*/
double lb = -5.12; /*参数的下界。*/
double ub = 5.12; /*参数的上界。对于参数有不同边界的问题,可以将lb和ub定义为数组*/
double Foods[][]=new double[FoodNumber][D]; /*foods是食物源的数组。每一行是一个包含D个待优化参数的向量。矩阵的行数等于食物源数*/
double f[]=new double[FoodNumber]; /*f是一个与食物源相关的目标函数值的数组*/
double fitness[]=new double[FoodNumber]; /*fitness是与食物源相关的质量值的数组*/
double trial[]=new double[FoodNumber]; /*trial is a vector holding trial numbers through which solutions can not be improved*/
double prob[]=new double[FoodNumber]; /*prob表示食物源被选择的概率的数组*/
double solution[]=new double[D];
double ObjValSol; /*Objective function value of new solution*/
double FitnessSol; /* Fitness value of new solution*/
int neighbour, param2change; /*param2change corrresponds to j, neighbour corresponds to k in equation v_{ij}=x_{ij}+\phi_{ij}*(x_{kj}-x_{ij})*/
double GlobalMin; /*ABC算法求得的最优解*/
double GlobalParams[]=new double[D]; /*最优解的参数Parameters of the optimum solution*/
double r; /* [0,1)的随机数 */
/*适应度函数*/
double CalculateFitness(double fun)
{
double result=0;
if(fun>=0)
{
result=1/(fun+1);
}
else
{
result=1+Math.abs(fun);
}
return result;
}
/*记录最优解*/
void MemorizeBestSource()
{
int i,j;
for(i=0;i<FoodNumber;i++)
{
if (f[i]<GlobalMin)
{
GlobalMin=f[i];
for(j=0;j<D;j++)
GlobalParams[j]=Foods[i][j];
}
}
}
/* 变量在[lb,ub]范围内初始化。如果每个参数的取值范围不同,使用lb[j]、ub[j]数组代替lb和ub */
/* 食物源的计数器也在这个函数中初始化*/
void init(int index)
{
int j;
for (j=0;j<D;j++)
{
r = ( (double)Math.random()*32767 / ((double)32767+(double)(1)) );
Foods[index][j]=r*(ub-lb)+lb;
solution[j]=Foods[index][j];
}
f[index]=calculateFunction(solution);
fitness[index]=CalculateFitness(f[index]);
trial[index]=0;
}
/*初始化所有食物源 */
void initial()
{
int i;
for(i=0;i<FoodNumber;i++)
{
init(i);
}
GlobalMin=f[0];
for(i=0;i<D;i++)
GlobalParams[i]=Foods[0][i];
}
void SendEmployedBees()
{
int i,j;
/*雇佣蜂阶段*/
for (i=0;i<FoodNumber;i++)
{
/*随机更改参数*/
r = ((double) Math.random()*32767 / ((double)(32767)+(double)(1)) );
param2change=(int)(r*D);
/*使用随机数产生不同的解*/
r = ( (double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
neighbour=(int)(r*FoodNumber);
for(j=0;j<D;j++)
solution[j]=Foods[i][j];
r = ( (double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
solution[param2change]=Foods[i][param2change]+(Foods[i][param2change]-Foods[neighbour][param2change])*(r-0.5)*2;
/*如果超出边界,则直接等于边界*/
if (solution[param2change]<lb)
solution[param2change]=lb;
if (solution[param2change]>ub)
solution[param2change]=ub;
ObjValSol=calculateFunction(solution);
FitnessSol=CalculateFitness(ObjValSol);
/*贪婪选择一下*/
if (FitnessSol>fitness[i])
{
/*如果变换后的解优于原解,则替换之,并重置计数器*/
trial[i]=0;
for(j=0;j<D;j++)
Foods[i][j]=solution[j];
f[i]=ObjValSol;
fitness[i]=FitnessSol;
}
else
{ /*如果解决方案没有改进,增加它的试验次数*/
trial[i]=trial[i]+1;
}
}
/*雇佣蜂阶段结束*/
}
/*选择食物源的概率与其质量成正比*/
/*可以采用多种方案来计算概率值*/
/*例如 prob(i)=fitness(i)/sum(fitness) */
/*或者 prob(i)=a*fitness(i)/max(fitness)+b*/
/*概率值由适应度值计算,并除以最大适应度值来标准化*/
void CalculateProbabilities()
{
int i;
double maxfit;
maxfit=fitness[0];
for (i=1;i<FoodNumber;i++)
{
if (fitness[i]>maxfit)
maxfit=fitness[i];
}
for (i=0;i<FoodNumber;i++)
{
prob[i]=(0.9*(fitness[i]/maxfit))+0.1;
}
}
void SendOnlookerBees()
{
int i,j,t;
i=0;
t=0;
/*观察蜂阶段*/
while(t<FoodNumber)
{
r = ( (double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
if(r<prob[i]) /*根据选择概率选择食物源*/
{
t++;
/*随机更改参数*/
r = ((double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
param2change=(int)(r*D);
/*使用随机数产生不同的解*/
r = ( (double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
neighbour=(int)(r*FoodNumber);
/*随机解必须不同于解i*/
while(neighbour == i)
{
r = ( (double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
neighbour=(int)(r*FoodNumber);
}
for(j=0;j<D;j++)
solution[j]=Foods[i][j];
r = ( (double)Math.random()*32767 / ((double)(32767)+(double)(1)) );
solution[param2change]=Foods[i][param2change]+(Foods[i][param2change]-Foods[neighbour][param2change])*(r-0.5)*2;
/*如果超出边界,则直接等于边界*/
if (solution[param2change]<lb)
solution[param2change]=lb;
if (solution[param2change]>ub)
solution[param2change]=ub;
ObjValSol=calculateFunction(solution);
FitnessSol=CalculateFitness(ObjValSol);
/*贪婪选择一下*/
if (FitnessSol>fitness[i])
{
trial[i]=0;
for(j=0;j<D;j++)
Foods[i][j]=solution[j];
f[i]=ObjValSol;
fitness[i]=FitnessSol;
}
else
{ /*如果解决方案没有改进,增加它的试验次数*/
trial[i]=trial[i]+1;
}
}
i++;
if (i==FoodNumber-1)
i=0;
}
/*观察蜂阶段结束 */
}
/*确定哪些食物源的试验计数器超过了“limit”值. 在基本的ABC算法中,每次循环只允许有一个侦察蜂*/
void SendScoutBees()
{
int maxtrialindex,i;
maxtrialindex=0;
for (i=1;i<FoodNumber;i++)
{
if (trial[i]>trial[maxtrialindex])
maxtrialindex=i;
}
if(trial[maxtrialindex]>=limit)
{
init(maxtrialindex);
}
}
double calculateFunction(double sol[])
{
return Rastrigin (sol);
}
double Rastrigin(double sol[])
{
int j;
double top=0;
for(j=0;j<D;j++)
{
top=top+(Math.pow(sol[j],(double)2)-10*Math.cos(2*Math.PI*sol[j])+10);
}
return top;
}
public static void main(String[] args) {
bee bee=new bee();
int iter=0;
int j=0;
bee.initial(); /*初始化所有食物源 */
bee.MemorizeBestSource(); /*记录最优解*/
for (iter=0;iter<bee.maxCycle;iter++)
{
bee.SendEmployedBees(); /*雇佣蜂阶段*/
bee.CalculateProbabilities(); /*计算食物源适应度*/
bee.SendOnlookerBees(); /*观察蜂阶段*/
bee.MemorizeBestSource(); /*记录最优解*/
bee.SendScoutBees(); /*侦查蜂阶段*/
}
for(j=0;j<bee.D;j++) /*循环打印10个最优解的参数*/
{
System.out.println("最优解的参数GlobalParam["+(j+1)+"]:"+bee.GlobalParams[j]);
}
System.out.println("最优解为:"+bee.GlobalMin); /*打印每次运行的最优解*/
}
}
运行截图: