人工鱼群算法Matlab实现
人工鱼群算法是一种基于模拟鱼群行为的优化算法,是由李晓磊等在2002年提出的一种新型的寻优算法。在一片水域中,鱼生存的数目最多的地方就是本水域中富含营养物质最多的地方,依据这一特点来模仿鱼群的觅食等行为,从而实现全局寻优,这就是鱼群算法的基本思想。
在鱼类的活动中,可以分为觅食行为、聚群行为、追尾行为和随机行为这四种行为,如何利用简单有效的方式来构造实现这些行为将是算法实施的主要问题。
觅食行为主要就是循着食物多的方向游动的一种行为,在寻优中则是向较优方向进行的迭代方式,如鱼群模式中的视觉概念;
在聚群行为中,借鉴的思想对每条人工鱼规定了这样两个规则:
1)尽量向邻近伙伴的中心移动;
2)避免过分拥挤,这样就能基本实现人工鱼的聚群能力;
追尾行为就是一种向临近的最活跃者追逐的行为,在寻优算法中可以理解为是向附近的最优化伙伴前进的过程;
随机行为就是人工鱼在其视野内随机移动的行为,在寻优算法中这种行为有助于解跳出局部最优。
假设在一个n维的目标搜索空间中,有N条组成一个群体的人工鱼,每天人工鱼个体的状态可表示为向量 X = ( x 1 , x 2 , … , x n ) X=(x_1,x_2,…,x_n) X=(x1,x2,…,xn),其中 x i ( i = 1 , … … n ) x_i(i=1,……n) xi(i=1,……n)为欲寻优的变量:人工鱼当前所在位置的食物浓度表示为 Y = f ( X ) Y=f(X) Y=f(X),其中 f ( ) f() f()为目标函数;人工鱼个体间距离表示为 d = ∣ ∣ x i − x j ∣ ∣ d=||x_i-x_j|| d=∣∣xi−xj∣∣(这是二范数); v i s u a l visual visual表示人工鱼的感知范围, s t e p step step为人工鱼移动步长, δ δ δ为拥挤度因子; t r y n u m b e r trynumber trynumber表示人工鱼每次觅食最大试探次数。
指鱼循着食物多的方向游动的一种行为,人工鱼 X i X_i Xi在其视野内随机选择一个状态 X j X_j Xj,分别计算它们的目标函数值进行比较,如果发现 Y j Y_j Yj比 Y i Y_i Yi优( Y j Y_j Yj和 Y i Y_i Yi分别为 X j X_j Xj和 X i X_i Xi的适应度值),则Xi向Xj的方向移动一步;否则, X i X_i Xi继续在其视野内选择状态 X j X_j Xj,判断是否满足前进条件,反复尝试 t r y n u m b e r trynumber trynumber次后,仍没有满足前进条件,则随机移动一步使 X i X_i Xi到达一个新的状态。表达式如下:
X j = X i + r a n d ( ) ∗ v i s u a l X_j=X_i+rand()*visual Xj=Xi+rand()∗visual (1)
X n e x t = X i + r a n d ( ) ∗ s t e p ∗ X j − X i ∣ ∣ X j − X i ∣ ∣ X_{next}=X_i+rand()*step*\frac{X_j-X_i}{\left | \left | X_j-X_i \right | \right |} Xnext=Xi+rand()∗step∗∣∣Xj−Xi∣∣Xj−Xi (2)
X n e x t = X i + r a n d ( ) ∗ s t e p X_{next}=X_i+rand()*step Xnext=Xi+rand()∗step (3)
其中rand()是介于-1和1之间的随机数。
人 工 鱼 的 视 觉 描 述 人工鱼的视觉描述 人工鱼的视觉描述
框架图如下所示:
伪代码段如下:
for i = 1:N
for j = 1:Try_number
Xj=x(i)+Visual.*rand();%人工鱼Xi按式(1)在其视野内随机选择一个状态Xj
if f(Xj)<f(x(i)) %比较Xj和Xi的适应度
X_next= x(i)+rand()*step*(Xj-x(i))/norm(Xj-x(i)); %人工鱼Xi按式(2)朝着Xj方向移动一步,norm()函数表示二范数
break;
else
X_next=x(i)+step*rand();
end
end
end
鱼在游动过程中为了保证自身的生存和躲避危害会自然地聚集成群 。人工鱼 X i X_i Xi搜索其视野内( d i j < v i s u a l d_{ij}<visual dij<visual)的伙伴数目 n f n_f nf及中心位置 X c X_c Xc,若 Y c / n f < δ Y i Y_c/n_f< δY_i Yc/nf<δYi(求极小值时使用小于号,在求极大值时则相反; Y c Y_c Yc和 Y i Y_i Yi分别为 X c X_c Xc和 X i X_i Xi的适应度值),表明伙伴中心位置状态较优且不太拥挤,则 X i X_i Xi朝伙伴的中心位置移动一步,否则执行觅食行为;
框架图如下所示:
伪代码段如下:
nf=0;X_inside=0;
for i = 1:N
for j = 1:N
if norm(x(j)-x(i))<Visual % 求人工鱼Xi与其他人工鱼之间的距离
nf = nf+1; %统计在视野范围内的鱼数量
X_inside= X_inside+x(i); %将视野范围内的鱼进行累加
end
X_inside=X_inside-x(i); %需要去除Xi本身;因为在 一开始计算时,i=j,把中心的鱼也进行了一次计算
nf=nf-1;
Xc = X_inside/nf; %此时Xc表示Xi感知范围其他伙伴的中心位置;
if f(Xc)/nf < δ*f(x(i))
x_next=x(i)+rand*Step*(Xc-x(i))/norm(Xc-x(i));
else
进行觅食行动
end
end
end
指鱼向其视野区域内的最优方向移动的一种行为。人工鱼 X i X_i Xi搜索其视野内( d i j < v i s u a l d_{ij}<visual dij<visual)适应度最高的个体 X j X_j Xj,其适应度值为 Y j Y_j Yj,并探索人工鱼 X j X_j Xj视野内的伙伴数目 n f n_f nf,若 Y j / n f < δ Y i Y_j/n_f< δY_i Yj/nf<δYi,表明 X j X_j Xj状态较优且不太拥挤,则 X i X_i Xi朝 X j X_j Xj位置移动一步,否则执行觅食行为;
框架图如下所示:
伪代码段如下:
Y_max=inf;nf=0;
for i = 1:N
%搜索人工鱼Xi视野范围内的最高适应度个体Xj
for j = 1:N
if norm(x(j)-x(i))<Visual && f(x(j))<Y_max % 求人工鱼Xi与其他人工鱼之间的距离
X_max=x(j);
Y_max=f(x(j));
end
end
%搜索人工鱼Xj视野范围内的伙伴数量
for j = 1:N
if(norm(x(j)-X_max)<Visual)
nf=nf+1;
end
end
nf=nf-1;%去掉他本身
if Y_max/nf<delta*f(x(i))
x_next= x(i,:)+rand*Step.*(temp_maxX-x(i,:))./norm(temp_maxX-x(i,:));
else
进行觅食行为;
end
end
综上所述,算法在运算过程中,会同时进行聚群和追尾行为。而觅食行为属于这两种行为中发现聚群对象或者追尾对象附近拥挤度过大时,人工鱼选择的行为方式,若在觅食过程中,未发现比自身适应度高的人工鱼,则按步长step随机移动。最后对聚群行为和追尾行为得到的适应度值进行比较,选择优秀的人工鱼作为下一代的个体。其总框架图如下:
在求极小值问题中: δ = α n m a x , α ∈ ( 0 , 1 ] δ=αn_{max}, α∈(0,1] δ=αnmax,α∈(0,1]
在求极大值问题中: δ = 1 α n m a x , α ∈ ( 0 , 1 ] δ=\frac{1}{αn_{max}},α∈(0,1] δ=αnmax1,α∈(0,1]
其中 α α α为极值接近水平, n m a x n_{max} nmax为期望在该邻域内聚集的最大人工鱼数目。
对追尾行为的描述
图中af0为人工鱼af1-5在各自视野内的最优人工鱼,其实物浓度为 Y j Y_j Yj,C1为以af0为圆心,以视野范围为半径的圆,即能探知af0的最远距离,人工鱼越靠近af0,状态越优。
求极大值情况下:当 δ n f ≤ 1 δn_f\leq 1 δnf≤1时,所有人工鱼af1-5都执行追尾行为,向af0游动;
δ = 1 α n m a x δ=\frac{1}{αn_{max}} δ=αnmax1
δ n f = n f α n m a x ≤ 1 δn_f =\frac{n_f}{αn_{max}}\leq 1 δnf=αnmaxnf≤1
当 α α α=1的时候,可以明显看出来 n f ≤ n m a x n_f \leq n_{max} nf≤nmax,即说明人工鱼视野范围内不拥挤。
当 δ n f > 1 δn_f >1 δnf>1时,若C2的食物浓度为 Y j δ n f \frac{Y_j}{δn_f } δnfYj的等浓度食物圈,则C2与C1间的人工鱼af1、af2、af3执行追尾行动,向af0游动,人工鱼af4、af5执行觅食行为。此时δnf 越大执行追尾行动的人工鱼越少,反之越多。
以极大值为例(极小值的情况正好和极大值相反), δ δ δ越大,表明允许的拥挤程度越小,人工鱼摆脱局部最优的能力越强;但是收敛的速度会有所减缓,这主要因为人工鱼在逼近极值的同时,会因避免过分拥挤而随机走开或者受其它人工鱼的排斥作用,不能精确逼近极值点。可见, δ δ δ的引入避免了人工鱼过度拥挤而陷入局部极值,另一方面,该参数会使得位于极值点附近的人工鱼之间存在相互排斥的影响,而难以向极值点精确逼近,所以,对于某些局部极值不是很严重的具体问题,可以忽略拥挤的因素,从而在简化算法的同时也加快了算法的收敛速度和提高结果的精确程度。
%sum(sin(x)./x) 极小值
clear all;
close all;
clc;
Visual = 25; %人工鱼的感知距离
Step = 3; %人工鱼的移动最大步长
N = 30; %人工鱼的数量
dim=10; %人工鱼维度
Try_number = 50;%迭代的最大次数
delta=27; %拥挤度因子
%测试函数
f=@(x) sum(x.^2);
ub=100;%边界上限
lb=-100;%边界下限
d = [];%存储50个状态下的目标函数值;
Iteration = 1; %
Max_iteration = 500;%迭代次数
%初始化人工鱼种群
x=lb+rand(N,dim).*(ub-lb);
%计算10个初始状态下的适应度值;
for i = 1:N
fitness_fish(i) = f(x(i,:));
end
[best_fitness,I] = min(fitness_fish); % 求出初始状态下的最优适应度;
best_x = x(I); % 最优人工鱼;
while Iteration<=Max_iteration
for i = 1:N
%% 聚群行为
nf_swarm=0;
Xc=0;
label_swarm =0; %群聚行为发生标志
%确定视野范围内的伙伴数目与中心位置
for j = 1:N
if norm(x(j,:)-x(i,:))<Visual
nf_swarm = nf_swarm+1; %统计在感知范围内的鱼数量
Xc = Xc+x(j,:); %将感知范围内的鱼进行累加
end
end
Xc=Xc-x(i,:); %需要去除本身;因为在 一开始计算时,i=j,把中心的鱼也进行了一次计算
nf_swarm=nf_swarm-1;
Xc = Xc/nf_swarm; %此时Xc表示视野范围其他伙伴的中心位置;
%判断中心位置是否拥挤
if (f(Xc)/nf_swarm < delta*f(x(i,:))) && (f(Xc)<f(x(i,:)))
x_swarm=x(i,:)+rand*Step.*(Xc-x(i,:))./norm(Xc-x(i,:));
%边界处理
ub_flag=x_swarm>ub;
lb_flag=x_swarm<lb;
x_swarm=(x_swarm.*(~(ub_flag+lb_flag)))+ub.*ub_flag+lb.*lb_flag;
x_swarm_fitness=f(x_swarm);
else
%觅食行为
label_prey =0; %判断觅食行为是否找到优于当前的状态
for j = 1:Try_number
%随机搜索一个状态
x_prey_rand = x(i,:)+Visual.*(-1+2.*rand(1,dim));
ub_flag2=x_prey_rand>ub;
lb_flag2=x_prey_rand<lb;
x_prey_rand=(x_prey_rand.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
%判断搜索到的状态是否比原来的好
if f(x(i,:))>f(x_prey_rand)
x_swarm = x(i,:)+rand*Step.*(x_prey_rand-x(i,:))./norm(x_prey_rand-x(i,:));
ub_flag2=x_swarm>ub;
lb_flag2=x_swarm<lb;
x_swarm=(x_swarm.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
x_swarm_fitness=f(x_swarm);
label_prey =1;
break;
end
end
%随机行为
if label_prey==0
x_swarm = x(i,:)+Step*(-1+2*rand(1,dim));
ub_flag2=x_swarm>ub;
lb_flag2=x_swarm<lb;
x_swarm=(x_swarm.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
x_swarm_fitness=f(x_swarm);
end
end
%% 追尾行为
fitness_follow = inf;
label_follow =0;%追尾行为发生标记
%搜索人工鱼Xi视野范围内的最高适应度个体Xj
for j = 1:N
if (norm(x(j,:)-x(i,:))<Visual) && (f(x(j,:))<fitness_follow)
best_pos = x(j,:);
fitness_follow = f(x(j,:));
end
end
%搜索人工鱼Xj视野范围内的伙伴数量
nf_follow=0;
for j = 1:N
if norm(x(j,:)-best_pos)<Visual
nf_follow=nf_follow+1;
end
end
nf_follow=nf_follow-1;%去掉他本身
%判断人工鱼Xj位置是否拥挤
if (fitness_follow/nf_follow)<delta*f(x(i,:)) && (fitness_follow<f(x(i,:)))
x_follow = x(i,:)+rand*Step.*(best_pos-x(i,:))./norm(best_pos-x(i,:));
%边界判定
ub_flag2=x_follow>ub;
lb_flag2=x_follow<lb;
x_follow=(x_follow.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
label_follow =1;
x_follow_fitness=f(x_follow);
else
%觅食行为
label_prey =0; %判断觅食行为是否找到优于当前的状态
for j = 1:Try_number
%随机搜索一个状态
x_prey_rand = x(i,:)+Visual.*(-1+2.*rand(1,dim));
ub_flag2=x_prey_rand>ub;
lb_flag2=x_prey_rand<lb;
x_prey_rand=(x_prey_rand.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
%判断搜索到的状态是否比原来的好
if f(x(i,:))>f(x_prey_rand)
x_follow = x(i,:)+rand*Step.*(x_prey_rand-x(i,:))./norm(x_prey_rand-x(i,:));
ub_flag2=x_follow>ub;
lb_flag2=x_follow<lb;
x_follow=(x_follow.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
x_follow_fitness=f(x_follow);
label_prey =1;
break;
end
end
%随机行为
if label_prey==0
x_follow = x(i,:)+Step*(-1+2*rand(1,dim));
ub_flag2=x_follow>ub;
lb_flag2=x_follow<lb;
x_follow=(x_follow.*(~(ub_flag2+lb_flag2)))+ub.*ub_flag2+lb.*lb_flag2;
x_follow_fitness=f(x_follow);
end
end
% 两种行为找最优
if x_follow_fitness<x_swarm_fitness
x(i,:)=x_follow;
else
x(i,:)=x_swarm;
end
end
%% 更新信息
for i = 1:N
if (f(x(i,:))<best_fitness)
best_fitness = f(x(i,:));
best_x = x(i,:);
end
end
Convergence_curve(Iteration)=best_fitness;
Iteration = Iteration+1;
if mod(Iteration,50)==0
display(['迭代次数:',num2str(Iteration),'最优适应度:',num2str(best_fitness)]);
display(['最优人工鱼:',num2str(best_x)]);
end
end
figure('Position',[284 214 660 290])
subplot(1,2,1);
x=-100:1:100; y=x;
L=length(x);
for i=1:L
for j=1:L
F(i,j)=x(i).^2+y(j).^2;
end
end
surfc(x,y,F,'LineStyle','none');
title('Test function')
xlabel('x_1');
ylabel('x_2');
zlabel(['sum','( x_1 , x_2 )'])
grid off
subplot(1,2,2);
semilogy(Convergence_curve,'Color','b')
title('Convergence curve')
xlabel('Iteration');
ylabel('Best fitness');
axis tight
grid off
box on