1.算法描述
人工鱼群优化算法,模仿鱼群的行为特点而设计的一种寻优策略。人工鱼群算法(Artificial Fish Swarm Algorithm,AFSA)是Li Xiao-lei在2002年提出的(Yazdani, Toosi, & Meybodi, 2010),目的是模仿鱼类捕食、群集、跟随、移动等行为。AFSA是基于鱼类集体向某个目标运动,并受到自然的启发,是一种并行和随机搜索算法。与狮子和猴子不同,在像鱼类这种动物物种中没有领导者,每个成员都有自我组织的行为。鱼对它们的群体和环境一无所知,通过相邻成员之间的数据交换在环境中随意移动,这种交互作用为鱼群优化带来了更多的复杂性。
在一片水域中,鱼往往能自行或尾随其他鱼找到营养物质多的地方,因而鱼生存数目最多的地方一般就是本水域中营养物质最多的地方,人工鱼群算法就是根据这一特点,通过构造人工鱼来模仿鱼群的觅食、聚群及追尾行为,从而实现寻优。
人工鱼拥有以下几种典型行为:
(1)觅食行为:一般情况下鱼在水中随机地自由游动,当发现食物时,则会向食物逐渐增多的方向快速游去。
(2)聚群行为: 鱼在游动过程中为了保证自身的生存和躲避危害会自然地聚集成群,鱼聚群时所遵守的规则有三条:
分隔规则:尽量避免与临近伙伴过于拥挤;
对准规则:尽量与临近伙伴的平均方向一致;
内聚规则:尽量朝临近伙伴的中心移动。
(3)追尾行为:当鱼群中的一条或几条鱼发现食物时,其临近的伙伴会尾随其快速到达食物点。
(4)随机行为:单独的鱼在水中通常都是随机游动的,这是为了更大范围地寻找食物点或身边的伙伴。
人工鱼有四种基本行为,包括觅食Pray、聚群Swarm、追尾Follow和评价行为bulletin。
3.1 觅食行为
这是鱼趋向食物的一种活动,一般认为它是通过视觉或味觉来感知水中的食物量或食物浓度来选择行动的方向。
设置人工鱼当前状态,并在其感知范围内随机选择另一个状态,如果得到的状态的目标函数大于当前的状态,则向新选择得到的状态靠近一步,反之,重新选取新状态,判断是否满足条件。
选择次数达到一定数量后,如果仍然不满足条件,则随机移动一步。
3.2 聚群行为
大量或少量的鱼聚集成群,进行集体觅食和躲避敌害,这是它们在进化过程中形成的一种生存方式。
人工鱼探索当前邻居内的伙伴数量,并计算伙伴的中心位置,然后把新得到的中心位置的目标函数与当前位置的目标函数相比较,如果中心位置的目标函数优于当前位置的目标函数并且不是很拥挤,则当前位置向中心位置移动一步,否则执行觅食行为。
鱼聚群时会遵守两条规则:一是尽量向邻近伙伴的中心移动,二是避免过分拥挤。
3.3 追尾行为
当某一条鱼或几条鱼发现食物时,它们附近的鱼会尾随而来,导致更远处的鱼也会尾随过来。
人工鱼探索周围邻居鱼的最优位置,当最优位置的目标函数值大于当前位置的目标函数值并且不是 很拥挤,则当前位置向最优邻居鱼移动一步,否则执行觅食行为。
3.4 随机行为
它是觅食行为的一个缺省行为,指人工鱼在视野内随机移动。当发现食物时,会向食物逐渐增多的方向快速的移动。
2.仿真效果预览
matlab2022a仿真结果如下:
3.MATLAB核心程序
for i = 1:length(nodes_id)
node = nodes_id(i);
people_waitting_in_current_node = cell2mat(p_in_node(node));
people_node_waitting = [people_node_waitting,people_waitting_in_current_node];
end
people_node_waitting = setdiff(people_node_waitting,people_prepare_moving);
%% 更新正在移动的队列
people_moving = [people_moving,people_prepare_moving];
%% 判断当前是否有边内等待的人,如果有,先遍历他们,让他们进入目标节点
people_side_index = []; %记录从边内等待状态转变为进入节点内的那些人在people_side_waitting中的索引
people_node_index = []; %记录进入某个节点的人在people_side_waitting中的索引
for i = 1:length(people_side_waitting)
p = people_side_waitting(i);
path = cell2mat(path_all(p));
% from_node = path(end-1);
% to_node = path(end);
if length(path)>1
from_node = path(end-1);
to_node = path(end);
else
from_node = path(end);
to_node = path(end);
end
%如果到达的是终点,则记录
if ismember(to_node,destination_nodes)
people_side_index = [people_side_index,i];
people_node_index = [people_node_index,i];
arrival_exit_people = [arrival_exit_people,p];
Sum_node(to_node) = Sum_node(to_node)+1;
diff = setdiff(p,cell2mat(p_in_node(to_node)));
p_in_node(to_node) = { [cell2mat(p_in_node(to_node)) , diff]};
people_in_side = cell2mat(p_in_side(from_node,to_node));
people_in_side = setdiff(people_in_side,p);
p_in_side(from_node,to_node) = {people_in_side};
p_in_side(to_node,from_node) = {people_in_side};
Sum_side(from_node,to_node) = Sum_side(from_node,to_node) -1;
Sum_side(to_node,from_node) = Sum_side(from_node,to_node);
t_left(p) = NaN;
t(p) = t(p) + t_move(p) + t_wait_node(p) + t_wait_side(p);
% 进入后,该人的移动时间、节点内等待时间、边内等待时间均置零
t_move(p) = 0;
t_wait_node(p) = 0;
t_wait_side(p) = 0;
exit_num = exit_num + 1;
elseif Sum_node(to_node)<nodes_capacity(to_node)
%% 如果所到达的节点没有超过容量限制,就进入
people_side_index = [people_side_index,i];
people_node_index = [people_node_index,i];
Sum_node(to_node) = Sum_node(to_node)+1;
diff = setdiff(p,cell2mat(p_in_node(to_node)));
p_in_node(to_node) = { [cell2mat(p_in_node(to_node)) , diff]};
people_in_side = cell2mat(p_in_side(from_node,to_node));
people_in_side = setdiff(people_in_side,p);
p_in_side(from_node,to_node) = {people_in_side};
p_in_side(to_node,from_node) = {people_in_side};
Sum_side(from_node,to_node) = Sum_side(from_node,to_node) -1;
Sum_side(to_node,from_node) = Sum_side(from_node,to_node);
if i>=length(first_people)
exit_num = exit_num + 1;
end
else
%% 如果超过了容量限制,则继续等待,不需要做任何操作
if i>=length(first_people)
exit_num = exit_num + 1;
end
end
end
if ~isempty(people_side_waitting)
%% 更新进入节点后,节点和人的属性
in_node_people = people_side_waitting(people_node_index);
t(in_node_people) = t(in_node_people) + t_move(in_node_people) + t_wait_node(in_node_people) + t_wait_side(in_node_people);
% 进入后,该人的移动时间、节点内等待时间、边内等待时间均置零
t_move(in_node_people) = 0;
t_wait_node(in_node_people) = 0;
t_wait_side(in_node_people) = 0;
%% 更新边内等待队列
people_side_waitting(people_side_index) = [];
end