本文用经典人工蜂群算法框架模板,对matlab新手友好,快速上手看懂matlab代码,快速应用实践,源代码在文末给出。
基本原理:
人工蜂群算法(Artificial Bee Colony Algorithm,ABC)是一种启发式算法,受到蜜蜂觅食行为的启发而提出的一种优化算法。它模拟了蜜蜂在寻找花朵采集花粉的过程中的行为,通过不断地调整蜜蜂的搜索策略来寻找最优解。
人工蜂群算法的基本思想是将候选解空间中的点看作花朵,并将搜索过程看作蜜蜂在不同花朵之间搜索的过程。在算法的执行过程中,蜜蜂分为三类:雇佣蜜蜂、观察蜜蜂和侦查蜜蜂。
-
雇佣蜜蜂:雇佣蜜蜂负责在当前位置附近的解空间中搜索,并评估候选解的质量。它们根据花粉量的多少(即解的适应度)来选择候选解,并将信息传递给其他蜜蜂。
-
观察蜜蜂:观察蜜蜂根据雇佣蜜蜂的信息进行选择,并尝试在当前位置附近进行搜索。它们通过观察雇佣蜜蜂找到的解来确定自己的搜索方向。
-
侦查蜜蜂:侦查蜜蜂负责在整个解空间中进行全局搜索,以寻找可能的新解。它们以一定的概率选择随机位置进行探索,并在搜索过程中更新最优解。
通过不断地雇佣、观察和侦查过程,人工蜂群算法能够在解空间中搜索到较优解。该算法具有较好的全局搜索能力和较快的收敛速度,适用于解决各种复杂的优化问题,如函数优化、参数优化等。
本文编程思想:
本编程将观察蜂于侦察蜂统一,称为侦察蜂,将雇佣蜜蜂称为采蜜蜂。
编程思想为:采蜜蜂进行随机采蜜,侦察蜂根据采蜜蜂的适应度大小进行跟随,适应度越高证明蜜源越好,越接近正确解,侦察蜂在采蜜蜂周围进行随机侦察,侦察到更好的蜜源后(也就是适应度越好的个体),那么将采蜜蜂更新到此位置,进而吸引更多的侦察蜂侦察,实现快速收敛。
开始编程:
参数与子函数定义:
%---------------------------------- 程序正文 -------------------------------
function ABC
%---------------------------------- 参数设置 -------------------------------
NP1=20; %种群规模
NP2=20; %种群规模
D=10; %变量个数
MinX=-D^2; %范围下限
MaxX=D^2; %范围上限
Limit=50; %次数阈值
Search=zeros(1,NP1); %采蜜搜次
Error=1.0; %限定精度
Max_N=1000; %限定代数
flagc=[0,Max_N]; %收敛标志
%---------------------- 粒子位置初始化 ----------------------
for i=1:1:D
X(:,i)=MinX+(MaxX-MinX)*rand(NP1+NP2,1);
end
%----------------------- 计算函数值 -------------------------
F=fun(X);
%---------------------------- 子函数1:目标函数 ----------------------------
function F=fun(X)
[M,N]=size(X);
for i=1:1:M
for j=1:1:N
x(j)=X(i,j);
end
F(i)=N*(N+4)*(N-1)/6+sum((x-1).^2)-sum(x(2:N).*x(1:N-1));
end
%----------------------- 建采蜜蜂群 -------------------------
[Bestf,Indexf]=sort(F,2);
for i=1:1:NP1
X1(i,:)=X(Indexf(i),:);
F1(i)=F(Indexf(i));
end
CX1=X1;CF1=F1;
参数定义:
NP1和NP2分别为采蜜蜂和侦察蜂。D为变量个数
X矩阵为D列,NP1+NP2行的矩阵,也就是40行,10列的矩阵。每一行代表一个蜜蜂个体,元素范围为(-100,100)
子函数定义
fun(x)为子函数,子函数中,M,N分别代表为X的行数和列数,这里的子函数也是目标函数,具体的数学函数如下,最终算法目标也就是求这个数学函数值小于1的解。
建立采蜜蜂群:
如上述代码所示,sort(F,2)表示按F的第二维度进行排序,也就是按列排序,也就是对F的每一行进行排序,由于F只有1行,那么也可以去掉这个参数,F一行的第i个参数也就是第i个蜜蜂的适应度,这里的排序就相当于按照每个蜜蜂的适应度进行排序,然后根据for循环挑选出NP1个蜜蜂作为采蜜蜂,CX1,CF1表示复制一份值。
开始主循环:
%--------------------- 程序主循环开始 ----------------------
for gen=1:1:Max_N
time(gen)=gen;
%----------------- 作采蜜蜂群搜索 ----------------------
for i=1:1:NP1
flag1=ceil(rand*NP1);
while(flag1==i)
flag1=ceil(rand*NP1);
end
flag2=ceil(rand*D);
X1(i,flag2)=X1(i,flag2)+rands(1)*(X1(i,flag2)-X1(flag1,flag2));
end
%----------------- 计算采蜜函数值 ----------------------
F1=fun(X1);
%----------------- 采蜜蜂贪婪搜索 ----------------------
for i=1:1:NP1
if F1(i)>=CF1(i)
Search(i)=Search(i)+1;
X1(i,:)=CX1(i,:);
F1(i)=CF1(i);
else
Search(i)=0;
end
end
%----------------- 跟踪蜂选择概率 ----------------------
temp=(1./(1+F1))/sum(1./(1+F1));
%P=cumsum((1./(1+F1))/sum(1./(1+F1)));
for i=1:1:NP1
P(i)=sum(temp(1:i));
end
%----------------- 跟踪蜂蜜源搜索 ----------------------
for i=1:1:NP2
%------------- 跟踪蜂选择蜜源 ----------------------
rnd=rand;
for flag=1:1:NP1
if rnd<P(flag)
Genzong(i)=flag;
break;
end
end
X2(i,:)=X1(flag,:);
%------------- 跟踪蜂搜索蜜源 ----------------------
flag1=ceil(rand*NP1);
while(flag1==flag)
flag1=ceil(rand*NP1);
end
flag2=ceil(rand*D);
X2(i,flag2)=X1(flag,flag2)+rands(1)*(X1(flag,flag2)-X1(flag1,flag2));
end
%----------------- 计算跟踪函数值 ----------------------
F2=fun(X2);
%----------------- 跟踪蜂蜜源计数 ----------------------
for i=1:1:NP2
if F2(i)>=F1(Genzong(i))
Search(Genzong(i))=Search(Genzong(i))+1;
else
Search(Genzong(i))=0;
X1(Genzong(i),:)=X2(i,:);
F1(Genzong(i))=F2(i);
end
end
%----------------- 检验采蜜蜂蜜源 ----------------------
for i=1:1:NP1
if Search(i)>Limit
Search(i)=0;
if i~=Indexf(1)
X1(i,:)=MinX+(MaxX-MinX)*rand(1,D);
F1=fun(X1);
end
end
end
%----------------- 迭代更新 ---------------------------
CF1=F1;CX1=X1;
%----------------- 求最优解 ---------------------------
[Bestf,Indexf]=sort(F1,2); %对NP1个函数值排序
gBestf=Bestf(1);
gX=X1(Indexf(1),:);
%----------------------------- 记录结果 --------------------------------
result(gen)=gBestf;
if mod(gen,10)==0
disp(sprintf('代数:%d -------- 结果:%f',gen,gBestf));
plot(time,result,'r');axis([1,Max_N,0,10000]);
xlabel('迭代步数');ylabel('优化结果');drawnow;pause(0.1);
end
if gBestf<Error break;end
end
%disp(' ');
disp(sprintf('迭代步数:%d -------- 优化结果:%f',gen,gBestf));
外层循环:
最外层循环表示迭代次数,表示进行Max_N次迭代,time记录迭代到第几次,做采蜜蜂群搜索代码中,ceil表示向上取整,表示[1,NP1]范围的随机整数。while循环内表示此整数不能等于当前迭代次数,也就是防止下一段代码中X1的参数未被修改。
F1 = fun(X1)表示计算采蜜蜂群的适应度并存储在F1矩阵中。
采蜜蜂贪婪搜索:
当更新后F1的适应度比之前差,那么把对应的个体记录到search中,并把没更新之前的值赋值给X1和F1。
跟踪蜂选择概率:
这个选择方法是轮盘赌选择,具体原理和流程见主页遗传算法中。这里Genzong数组里记录了每个跟踪蜂跟踪第几个采蜜蜂,X2矩阵中存储跟踪蜂选择的采蜜蜂个体。蜜源越大也就是适应度越好,跟踪蜂越多。
跟踪蜂搜索蜜源:
flag1表示[1,NP1]的随机值,与上面的采蜜蜂搜索蜜源相似,做随机搜索,随机改变10个变量中的一个,循环结束使用F2进行跟踪蜂适应度计算。
跟踪蜜源计数:
这个for循环中,遍历每个跟踪蜂的适应度,如果跟踪蜂的适应度比它跟踪的采蜜蜂的适应度差,那么将对应采蜜蜂的search中的值+1,也就是search越大,这个采蜜蜂的适应度越好,如果跟踪蜂的适应度好,将跟踪蜂的值赋值给它跟踪的采蜜蜂,并更新采蜜蜂的对应适应度的值。
检验采蜜蜂蜜源:
这个代码是防止陷入局部最优解的过程,当search超过limit时,表示此采蜜蜂周围没有比他更好的蜜源了,将search设置为0,如果这个采蜜蜂还不是全局最优解,那么将这个采蜜蜂重新分配一个随机蜜源,这就是避免陷入局部最优的过程,如果这个蜜蜂是全局最优解,那么不分配随机蜜源,继续让跟踪蜂寻找。
迭代更新:
迭代更新的CF1记录上一次的采蜜蜂的适应度,CX1记录上一次采蜜蜂的值,计算最优解将适应度排序,寻找最佳的采蜜蜂。
源代码:
%---------------------------------- 程序说明 -------------------------------
% 该程序实现了基本蜂群算法
%---------------------------------- 程序正文 -------------------------------
function ABC
%---------------------------------- 参数设置 -------------------------------
NP1=20; %种群规模
NP2=20; %种群规模
D=10; %变量个数
MinX=-D^2; %范围下限
MaxX=D^2; %范围上限
Limit=50; %次数阈值
Search=zeros(1,NP1); %采蜜搜次
Error=1.0; %限定精度
Max_N=1000; %限定代数
flagc=[0,Max_N]; %收敛标志
%---------------------- 粒子位置初始化 ----------------------
for i=1:1:D
X(:,i)=MinX+(MaxX-MinX)*rand(NP1+NP2,1);
end
%X=MinX+(MaxX-MinX)*rand(NP1+NP2,D);
disp(X);
%----------------------- 计算函数值 -------------------------
F=fun(X);
%----------------------- 建采蜜蜂群 -------------------------
[Bestf,Indexf]=sort(F,2);
for i=1:1:NP1
X1(i,:)=X(Indexf(i),:);
F1(i)=F(Indexf(i));
end
CX1=X1;CF1=F1;
%--------------------- 程序主循环开始 ----------------------
for gen=1:1:Max_N
time(gen)=gen;
%----------------- 作采蜜蜂群搜索 ----------------------
for i=1:1:NP1
flag1=ceil(rand*NP1);
while(flag1==i)
flag1=ceil(rand*NP1);
end
flag2=ceil(rand*D);
X1(i,flag2)=X1(i,flag2)+rands(1)*(X1(i,flag2)-X1(flag1,flag2));
end
%----------------- 计算采蜜函数值 ----------------------
F1=fun(X1);
%----------------- 采蜜蜂贪婪搜索 ----------------------
for i=1:1:NP1
if F1(i)>=CF1(i)
Search(i)=Search(i)+1;
X1(i,:)=CX1(i,:);
F1(i)=CF1(i);
else
Search(i)=0;
end
end
%----------------- 跟踪蜂选择概率 ----------------------
temp=(1./(2+F1))/sum(1./(2+F1));
%P=cumsum((1./(1+F1))/sum(1./(1+F1)));
for i=1:1:NP1
P(i)=sum(temp(1:i));
end
%----------------- 跟踪蜂蜜源搜索 ----------------------
for i=1:1:NP2
%------------- 跟踪蜂选择蜜源 ----------------------
rnd=rand;
for flag=1:1:NP1
if rnd<P(flag)
Genzong(i)=flag;
break;
end
end
X2(i,:)=X1(flag,:);
%------------- 跟踪蜂搜索蜜源 ----------------------
flag1=ceil(rand*NP1);
while(flag1==flag)
flag1=ceil(rand*NP1);
end
flag2=ceil(rand*D);
X2(i,flag2)=X1(flag,flag2)+rands(1)*(X1(flag,flag2)-X1(flag1,flag2));
end
%----------------- 计算跟踪函数值 ----------------------
F2=fun(X2);
%----------------- 跟踪蜂蜜源计数 ----------------------
for i=1:1:NP2
if F2(i)>=F1(Genzong(i))
Search(Genzong(i))=Search(Genzong(i))+1;
else
Search(Genzong(i))=0;
X1(Genzong(i),:)=X2(i,:);
F1(Genzong(i))=F2(i);
end
end
%----------------- 检验采蜜蜂蜜源 ----------------------
for i=1:1:NP1
if Search(i)>Limit
Search(i)=0;
if i~=Indexf(1)
X1(i,:)=MinX+(MaxX-MinX)*rand(1,D);
disp("reSearch");
F1=fun(X1);
end
end
end
%----------------- 迭代更新 ---------------------------
CF1=F1;CX1=X1;
%----------------- 求最优解 ---------------------------
[Bestf,Indexf]=sort(F1,2); %对NP1个函数值排序
gBestf=Bestf(1);
gX=X1(Indexf(1),:);
%----------------------------- 记录结果 --------------------------------
result(gen)=gBestf;
if mod(gen,10)==0
disp(sprintf('代数:%d -------- 结果:%f',gen,gBestf));
plot(time,result,'r');axis([1,Max_N,0,10000]);
xlabel('迭代步数');ylabel('优化结果');drawnow;pause(0.1);
end
if gBestf<Error break;end
end
%disp(' ');
disp(sprintf('迭代步数:%d -------- 优化结果:%f',gen,gBestf));
disp(X1(Indexf(1),:));
%---------------------------- 子函数1:目标函数 ----------------------------
function F=fun(X)
[M,N]=size(X);
for i=1:1:M
for j=1:1:N
x(j)=X(i,j);
end
F(i)=N*(N+4)*(N-1)/6+sum((x-1).^2)-sum(x(2:N).*x(1:N-1));
end