优化算法の粒子群算法、遗传算法、禁忌算法对比

0、优化算法

优化算法是一种根据概率按照固定步骤寻求问题的最优解的过程。常见的优化算法有最传统的梯度下降法(Gradient Descent),在自然特性的基础上模拟个体种群的适应性的遗传算法(Genetic Algorithm,GA)和粒子群算法(Particle Swarm Optimization,PSO),收敛速度较快的牛顿法(Newton’s method)及其在牛顿法的基础上使用正定矩阵来近似Hessian矩阵逆的拟牛顿法(Quasi Newton method),还有以亚启发式随机搜索的禁忌算法(Tabu Search)。

1、粒子群算法

粒子群中的每一个粒子都代表一个问题的可能解,通过粒子个体的简单行为,群体内的信息交互实现问题求解的智能性。算法那中每个粒子可视为N维搜索空间中的一个搜索个体,粒子的当前位置即为对应优化问题的一个候选解,粒子的飞行过程即为该个体的搜索过程。粒子的飞行速度可根据粒子历史最优位置和种群历史最优位置进行动态调整。粒子仅具有两个属性:速度和位置,速度代表移动的快慢,位置代表移动的方向,每个粒子单独搜寻的最优解叫做个体极值,粒子群中最优的个体极值作为当前全局最优解。不断迭代,更新速度和位置。最终得到满足终止条件的最优解。
在这里插入图片描述
目标函数z=ysin(2pix)+xcos(2piy)

%% I. 清空环境%二元函数
%https://blog.csdn.net/weixin_44897776/article/details/113686831
clc
clear 
 
%% II. 绘制目标函数曲线图
rand('state',3);
figure(1);
lbx=-3;ubx=3; %函数自变量x范围【-3,3】
lby=-3;uby=3; %函数自变量y范围【-3,3ezmesh('y*sin(2*pi*x)+x*cos(2*pi*y)',[lbx,ubx,lby,uby],100);   %画出函数曲线
hold on;


%% III. 参数初始化
c1 = 1.49445;%c1和c2:是学习因子,通常c1=c2=2
c2 = 1.49445;

ws=0.9;%w惯性权重,体现粒子继承先前的速度的能力
we=0.4;%一般start=0.9 end=0.4时算法性能最好,迭代初期惯性大有利于全局搜索,迭代后期惯性小有利于局部搜索

 
maxgen = 50;   % 进化次数  
sizepop = 80;   %种群规模
 
Vmax = 1;   %速度的范围,超过则用边界值。
Vmin = -1;  
popmax = 3;   %个体的变化范围
popmin = -3;
%定义适应度函数
%% IV. 产生初始粒子和速度

for i = 1:sizepop
    % 随机产生一个种群
    pop(i,:) = 3*rands(1,2);    %初始种群粒子位置
    V(i,:) = rands(1,2);  %初始化速度
    % 计算适应度
    fitness(i) = fun1(pop(i,:));   
end
 
%% V. 个体极值和群体极值
[bestfitness,bestindex] = max(fitness);
gbest = pop(bestindex,:);   %全局最佳
fitnessgbest = bestfitness;   %全局最佳适应度值
pbest = pop;    %个体最佳
fitnesspbest = fitness;   %个体最佳适应度值

 
%% VI. 迭代寻优
tic
for i = 1:maxgen
%     tic
    w=ws-(ws-we)*(i/maxgen);
    for j = 1:sizepop
        % 速度更新
        V(j,:) = w*V(j,:) + c1*rand*(pbest(j,:) - pop(j,:)) + c2*rand*(gbest - pop(j,:));
        V(j,find(V(j,:)>Vmax)) = Vmax;
        V(j,find(V(j,:)<Vmin)) = Vmin;
        
        % 种群更新
        pop(j,:) = pop(j,:) + V(j,:);
        pop(j,find(pop(j,:)>popmax)) = popmax;
        pop(j,find(pop(j,:)<popmin)) = popmin;
        
        % 适应度值更新
        fitness(j) = fun1(pop(j,:)); 
    end
    
    for j = 1:sizepop    
        % 个体最优更新
        if fitness(j) > fitnesspbest(j)
            pbest(j,:) = pop(j,:);
            fitnesspbest(j) = fitness(j);
        end
        
        % 群体最优更新
        if fitness(j) > fitnessgbest
            gbest = pop(j,:);
            fitnessgbest = fitness(j);
        end
    end 
    Q(i) = fitnessgbest;        
%     toc
end
toc
%% VII. 输出结果并绘图

[gbest fitnessgbest];
plot3(gbest(1),gbest(2),fitnessgbest,'r*')
fprintf(['最优解:\nX=',num2str(gbest(1)),'\nY=',num2str(gbest(2)),'\nZ=',num2str(fitnessgbest),'\n'])
figure(2)
plot(Q)
title('最优个体适应度','fontsize',12);
xlabel('迭代次数','fontsize',12);ylabel('适应度','fontsize',12);
function z = fun1(x) 
        z=x(2)*sin(2*pi*x(1))+x(1)*cos(2*pi*x(2));
end

算法迭代曲线
在这里插入图片描述

2、遗传算法

遗传算法是从代表问题可能潜在的解集的一个种群开始的,而一个种群则由经过基因编码的一定数目的个体组成,每个个体实际上是染色体带有特征的实体。在初代种群产生之后,遗传算法按照适者生存和优胜劣汰的原理,逐代演化产生出越来越好的近似解,根据问题域中个体的适应度大小选择个体,并借助于自然遗传学的遗传算子进行组合交叉和变异,产生出代表新的解集的种群。
在这里插入图片描述
目标函数z=ysin(2pix)+xcos(2piy)

%%二维GA matlab智能算法第二章example2
clc
clear all
close all
rand('state',2);
%% 画出函数图
figure(1);
lbx=-3;ubx=3; %函数自变量x范围【-2,2】
lby=-3;uby=3; %函数自变量y范围【-2,2ezmesh('y*sin(2*pi*x)+x*cos(2*pi*y)',[lbx,ubx,lby,uby],100);   %画出函数曲线
hold on;
%% 定义遗传算法参数
NIND=40;        %个体数目
MAXGEN=50;      %最大遗传代数
PRECI=20;       %变量的二进制位数
GGAP=0.95;      %代沟
px=0.7;         %交叉概率
pm=0.01;        %变异概率
trace=zeros(3,MAXGEN);                        %寻优结果的初始值
FieldD=[PRECI PRECI;lbx lby;ubx uby;1 1;0 0;1 1;1 1];                      %区域描述器
Chrom=crtbp(NIND,PRECI*2);                      %初始种群
%% 优化
gen=0;                                  %代计数器
XY=bs2rv(Chrom,FieldD);                 %计算初始种群的十进制转换
X=XY(:,1);Y=XY(:,2);
ObjV=Y.*sin(2*pi*X)+X.*cos(2*pi*Y);        %计算目标函数值
tic
while gen<MAXGEN
%     tic
   FitnV=ranking(-ObjV);                              %分配适应度值
   SelCh=select('sus',Chrom,FitnV,GGAP);              %选择
   SelCh=recombin('xovsp',SelCh,px);                  %重组
   SelCh=mut(SelCh,pm);                               %变异
   XY=bs2rv(SelCh,FieldD);               %子代个体的十进制转换
   X=XY(:,1);Y=XY(:,2);
   ObjVSel=Y.*sin(2*pi*X)+X.*cos(2*pi*Y);             %计算子代的目标函数值
   [Chrom,ObjV]=reins(Chrom,SelCh,1,1,ObjV,ObjVSel); %重插入子代到父代,得到新种群
   XY=bs2rv(Chrom,FieldD);
   gen=gen+1;                                             %代计数器增加
   %获取每代的最优解及其序号,Y为最优解,I为个体的序号
   [Y,I]=max(ObjV);
   trace(1:2,gen)=XY(I,:);                       %记下每代的最优值
   trace(3,gen)=Y;                               %记下每代的最优值
%    toc
end
toc
plot3(trace(1,:),trace(2,:),trace(3,:),'bo');                            %画出每代的最优点
grid on;
plot3(XY(:,1),XY(:,2),ObjV,'bo');  %画出最后一代的种群
hold off
%% 画进化图
figure(2);
plot(1:MAXGEN,trace(3,:));
grid on
xlabel('遗传代数')
ylabel('解的变化')
title('收敛过程')
bestZ=trace(3,end);
bestX=trace(1,end);
bestY=trace(2,end);
fprintf(['最优解:\nX=',num2str(bestX),'\nY=',num2str(bestY),'\nZ=',num2str(bestZ),'\n'])

算法迭代曲线
在这里插入图片描述

3、禁忌算法

禁忌搜索算法首先确定一个初始可行解,确定初始可行解后,定义可行解的领域移动集,然后从领域移动集中挑选一个能改进当前解得移动集,再从新的解开始,反复搜索。如果领域移动中只接受比当前解好的解,搜索就可能陷入循环的危险。为了避免陷入循环和局部最优,构造一个短期循环记忆表,即禁忌表,禁忌表中存放刚刚进行过的领域移动,这些移动被称为禁忌移动。对于当前的移动,在以后的T次循环中都是禁止的,以避免回到原先的解,T次以后释放该移动。禁忌表是一个循环表,搜索过程中被循环的修改,使禁忌表始终保持这T个移动。
在这里插入图片描述
目标函数z=ysin(2pix)+xcos(2piy)

%%%%%%%%%%%%%%%%禁忌搜索算法求函数极值问题%%%%%%%%%%%%%%%%%%%
clear all;                        %清除所有变量
close all;                        %清图
clc;                              %清屏
xu=3;                             %上界
xl=-3;                            %下界
rand("state",3);
% L=randint(1,1,[5 11]);            %禁忌长度取5,11之间的随机数
L=randi([5 11],1,1);            %禁忌长度取5,11之间的随机数
Ca=5;                             %邻域解个数
Gmax=50;                         %禁忌算法的最大迭代次数;
w=1;                              %自适应权重系数
tabu=[];                          %禁忌表
x0=rand(1,2)*(xu-xl)+xl;          %随机产生初始解
bestsofar.key=x0;                 %最优解
xnow(1).key=x0;                   %当前解
%%%%%%%%%%%%%%%%最优解函数值,当前解函数值%%%%%%%%%%%%%%%%%
bestsofar.value=func2(bestsofar.key);  
xnow(1).value=func2(xnow(1).key);
g=1;
while g<Gmax
    x_near=[];                     %邻域解
    w=w*0.998;
    for i=1:Ca
        %%%%%%%%%%%%%%%%%%%%%产生邻域解%%%%%%%%%%%%%%%%%%%%
        x_temp=xnow(g).key;
        x1=x_temp(1);
        x2=x_temp(2);
        x_near(i,1)=x1+(2*rand-1)*w*(xu-xl);
           %%%%%%%%%%%%%%%%%边界条件处理%%%%%%%%%%%%%%%%%%%
           %%%%%%%%%%%%%%%%%%%边界吸收%%%%%%%%%%%%%%%%%%%%%
        if x_near(i,1)<xl
            x_near(i,1)=xl;
        end
        if x_near(i,1)>xu
            x_near(i,1)=xu;
        end
        x_near(i,2)=x2+(2*rand-1)*w*(xu-xl);
           %%%%%%%%%%%%%%%%%边界条件处理%%%%%%%%%%%%%%%%%%%
           %%%%%%%%%%%%%%%%%%%边界吸收%%%%%%%%%%%%%%%%%%%%%
        if x_near(i,2)<xl
            x_near(i,2)=xl;
        end
        if x_near(i,2)>xu
            x_near(i,2)=xu;
        end
        %%%%%%%%%%%%%%计算邻域解点的函数值%%%%%%%%%%%%%%%%%%%
        fitvalue_near(i)=func2(x_near(i,:)); 
    end
    %%%%%%%%%%%%%%%%%%%%最优邻域解为候选解%%%%%%%%%%%%%%%%%%%
    temp=find(fitvalue_near==max(fitvalue_near));
    candidate(g).key=x_near(temp,:);
    candidate(g).value=func2(candidate(g).key);
    %%%%%%%%%%%%%%候选解和当前解的评价函数差%%%%%%%%%%%%%%%%%%
    delta1=candidate(g).value-xnow(g).value; 
    %%%%%%%%%%%%%%候选解和目前最优解的评价函数差%%%%%%%%%%%%%%%
    delta2=candidate(g).value-bestsofar.value;    
    %%%%%候选解并没有改进解,把候选解赋给下一次迭代的当前解%%%%%%
    if delta1<=0   
        xnow(g+1).key=candidate(g).key;
        xnow(g+1).value=func2(xnow(g).key);
        %%%%%%%%%%%%%%%%%%%%%更新禁忌表%%%%%%%%%%%%%%%%%%%%%%%
        tabu=[tabu;xnow(g+1).key];
        if size(tabu,1)>L  
            tabu(1,:)=[];
        end
        g=g+1;                 %更新禁忌表后,迭代次数自增1
    %%%%%%%如果相对于当前解有改进,则应与目前最优解比较%%%%%%%%%%
    else
        if delta2>0            %候选解比目前最优解优
            %%%%%%%%%%把改进解赋给下一次迭代的当前解%%%%%%%%%%%%
            xnow(g+1).key=candidate(g).key;
            xnow(g+1).value=func2(xnow(g+1).key);
            %%%%%%%%%%%%%%%%%%%%更新禁忌表%%%%%%%%%%%%%%%%%%%%%
            tabu=[tabu;xnow(g+1).key];
            if size(tabu,1)>L 
                tabu(1,:)=[];
            end 
            %%%%%%%%把改进解赋给下一次迭代的目前最优解%%%%%%%%%%%%
            %%%%%%%%%%%%%%%%%包含藐视准则%%%%%%%%%%%%%%%%%%%%%%%
            bestsofar.key=candidate(g).key;
            bestsofar.value=func2(bestsofar.key);
            g=g+1;                %更新禁忌表后,迭代次数自增1
        else
            %%%%%%%%%%%%%%%判断改进解时候在禁忌表里%%%%%%%%%%%%%%%
            [M,N]=size(tabu);
            r=0;
            for m=1:M
                if candidate(g).key(1)==tabu(m,1)...
                   & candidate(g).key(2) == tabu(m,1)
                    r=1;
                end
            end
            if  r==0
                %%改进解不在禁忌表里,把改进解赋给下一次迭代的当前解
                xnow(g+1).key=candidate(g).key;
                xnow(g+1).value=func2(xnow(g+1).key);
                %%%%%%%%%%%%%%%%%%%%%更新禁忌表%%%%%%%%%%%%%%%%%%
                tabu=[tabu;xnow(g).key];
                if size(tabu,1)>L
                    tabu(1,:)=[];
                end
                g=g+1;               %更新禁忌表后,迭代次数自增1
            else
                %%%如果改进解在禁忌表里,用当前解重新产生邻域解%%%%%
                xnow(g).key=xnow(g).key;
                xnow(g).value=func2(xnow(g).key);
            end
        end
    end
    trace(g)=func2(bestsofar.key);
end
bestsofar          %最优变量及最优值
figure
plot(trace);
xlabel('迭代次数')
ylabel('目标函数值')
title('搜索过程最优值曲线')
%该脚本应命名为func2.m

function y=func2(x)
    y = x(2)*sin(2*pi*x(1))+x(1)*cos(2*pi*x(2));
end

迭代曲线
在这里插入图片描述

以上三种算法的优劣分析

以下分别对粒子群算法、遗传算法、禁忌算法的特征进行分析。
粒子群算法是一类非确定算法,其优点在于有更多的机会得到全局最优解,且粒子群算法具有自组织和进化性以及记忆功能,所有粒子都保存优解得相关信息。且粒子群算法还具备稳健性,即在不同条件和环境下都实用有效。但粒子群算法的数学理论基础还不够牢固,算法收敛性还有待斟酌。
遗传算法直接以目标函数作为搜索信息,仅仅使用适应度函数值来度量个体的优劣程度。因此遗传算法有着高度的优越性。另一方面由于遗传算法的群体搜索特性,可以避免在多峰分布搜索空间进行搜索易陷入单峰极值的问题。但遗传算法的效率通常低于其它优化算法,且容易出现过早收敛的现象。
禁忌算法主要特点是在搜索开始阶段解的质量提高很快,随着搜索过程的继续,解得质量提高速度逐渐放缓,甚至在很长的搜索阶段内解得质量没有太大的提高,适合中小规模的NP问题求解,整体效率比较均衡。

  • 3
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
本框架提供了有关粒子群算法(PSO)和遗传算法(GA)的完整实现,以及一套关于改进、应用、测试、结果输出的完整框架。 本框架对粒子群算法遗传算法进行逻辑解耦,对其中的改进点予以封装,进行模块化,使用者可以采取自己对该模块的改进替换默认实现组成新的改进算法与已有算法进行对比试验。试验结果基于Excel文件输出,并可通过设定不同的迭代结束方式选择试验数据的输出方式,包括: 1. 输出随迭代次数变化的平均达优率数据(设定终止条件区间大于0)。 2. 输出随迭代次数变化的平均最优值数据(设定终止条件区间等于0)。 本框架了包含了常用基准函数的实现以及遗传算法粒子群算法对其的求解方案实现和对比,如TSP,01背包,Banana函数,Griewank函数等。并提供大量工具方法,如KMeans,随机序列生成与无效序列修补方法等等。 对遗传算法的二进制编码,整数编码,实数编码,整数序列编码(用于求解TSP等),粒子群算法的各种拓扑结构,以及两种算法的参数各种更新方式均有实现,并提供接口供使用者实现新的改进方式并整合入框架进行试验。 其中还包括对PSO进行离散化的支持接口,和自己的设计一种离散PSO方法及其用以求解01背包问题的实现样例。 欢迎参考并提出宝贵意见,特别欢迎愿意协同更新修补代码的朋友(邮箱starffly@foxmail.com)。 代码已作为lakeast项目托管在Google Code: http://code.google.com/p/lakeast http://code.google.com/p/lakeast/downloads/list 某些类的功能说明: org.lakest.common中: BoundaryType定义了一个枚举,表示变量超出约束范围时为恢复到约束范围所采用的处理方式,分别是NONE(不处理),WRAP(加减若干整数个区间长度),BOUNCE(超出部分向区间内部折叠),STICK(取超出方向的最大限定值)。 Constraint定义了一个代表变量约束范围的类。 Functions定义了一系列基准函数的具体实现以供其他类统一调用。 InitializeException定义了一个代表程序初始化出现错误的异常类。 Randoms类的各个静态方法用以产生各种类型的随机数以及随机序列的快速产生。 Range类的实现了用以判断变量是否超出约束范围以及将超出约束范围的变量根据一定原则修补到约束范围的方法。 ToStringBuffer是一个将数组转换为其字符串表示的类。 org.lakeast.ga.skeleton中: AbstractChromosome定义了染色体的公共方法。 AbstractDomain是定义问题域有关的计算与参数的抽象类。 AbstractFactorGenerator定义产生交叉概率和变异概率的共同方法。 BinaryChromosome是采用二进制编码的染色体的具体实现类。 ConstantFactorGenerator是一个把交叉概率和变异概率定义为常量的参数产生器。 ConstraintSet用于在计算过程中保存和获取应用问题的各个维度的约束。 Domain是遗传算法求解中所有问题域必须实现的接口。 EncodingType是一个表明染色体编码类型的枚举,包括BINARY(二进制),REAL(实数),INTEGER(整型)。 Factor是交叉概率和变异概率的封装。 IFactorGenerator参数产生器的公共接口。 Population定义了染色体种群的行为,包括种群的迭代,轮盘赌选择和交叉以及最优个体的保存。 org.lakeast.ga.chromosome中: BinaryChromosome二进制编码染色体实现。 IntegerChromosome整数编码染色体实现。 RealChromosome实数编码染色体实现。 SequenceIntegerChromosome整数序列染色体实现。 org.lakeast.pso.skeleton中: AbstractDomain提供一个接口,将粒子的位置向量解释到离散空间,同时不干扰粒子的更新方式。 AbstractFactorGenerator是PSO中参数产生器的公共抽象类。 AbstractParticle定义了PSO种群中粒子的基本行为,最主要是实现了如何根据现有位置计算得到下一代粒子的位置的合法值。 ConstraintSet用于在粒子迭代过程中保存和获取应用问题的各个维度的约束。 AbstractSwarm.java各种拓扑结构的PSO种群的抽象父类,主要实现了种群迭代过程中计算流程的定义以及中间数据被如何输出到测试工具类。 Domain是PSO算法求解中所有问题域必须实现的接口。 DynamicFatorGenerator若种群在迭代过程中,w,c1,c2随迭代次数发生变化,那么它们的产生器需要继承这个抽象类。 Factor封装了w,c1,c2三个参数的字面值。 Location用于保存和获取迭代中粒子的位置和速度向量的数值。 NeighborhoodBestParticle定义了采用邻域版本的PSO算法的具体实现。主要是实现了如何根据邻域版本的PSO算法计算下一迭代中的粒子速度。 RingTopoSwarm定义环拓扑结构的具体实现,主要是定义了如何获取粒子的邻域粒子的方法。 StaticTopoSwarm静态拓扑结构的PSO算法的抽象父类。 org.lakeast.pso.swarm中包含粒子群拓扑结构的各种实现,基本见名知意。 对各种问题的求解样例位于org.lakeast.main包中,以...TaskTest结尾,基本见名知意。 以ShafferF6DomainTaskTes对ShafferF6函数进行求解(采用的是PSO,遗传算法样例参见TSPValueTaskTest)为例说明求解过程如下: 1. 入口函数位于org.lakeast.main.ShafferF6DomainTaskTest中,go函数执行。 2. 在go函数中,首先指定迭代次数(numberOfIterations),测试多少轮(testCount,多次运行以得到平均达优值),种群大小(popSize),邻域大小(neighborhoodSize),迭代结束条件(exitCondition,由于制定了迭代次数,所以设定为[0,0],也就是只有达到指定迭代次数才退出)。 3. 以testCount,numberOfIterations以及迭代结束条件exitCondition为参数构建TestBatch类的实例batch。这个类用来进行管理参与测试的各种具体算法,且把数据结果按指定的格式输出为Excel文件。 4. 指定PSO中的因子产生方法,采用ExponentFactorGenerator和ConstrictFactorGenerator两种方式(实现位于org.lakeast.pso.gen包)。 5. Y表示参与测试的算法数目。 6. Testable是所有可以被TestBatch测试的类需要实现的接口,以提供TestBatch生成结果Excel文件所需要的数据。 7. Domain接口是所有可以被算法解决的问题所需要实现的接口,比如说明该问题所需要的粒子位置约束范围,速度约束范围,以及适值评估的公司等。这里的Domain被实例化为ShafferF6Domain,也就是按照ShafferF6函数评估适值。 8. RingTopoSwarm是用来封装环拓扑邻域结构的类,NeighboordBestParticle是配合该类来实现按邻域最优更新速度而不是全局最优来更新。 9. 各个测试算法都被加入到TestBatch以后,batch.run()开始执行算法比较过程并输出结果Excel文件到C盘根目录(输出路径可在Testable接口中配置,除了生成Excel文件外,还可以通过修改log4j.properties在制定的位置产生运行结果日志)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值