遗传算法

1.前言

遗传算法是一种基于生物界自然群体遗传进化机制的自适应全局优化概率搜索算法。它与传统算法不同,不依赖梯度信息,而是通过模拟自然进化过程来搜索最优解。

例子:兔子的遗传进化

有人说,现代医学阻碍了人类的进化?你怎么看?

2.发展历程

遗传算法由密歇根大学的约翰·霍兰德和他的同事于二十世纪六十年代在对细胞自动机(英文:cellular automata)进行研究时率先提出。在二十世纪八十年代中期之前,对于遗传算法的研究还仅仅限于理论方面,直到在匹兹堡召开了第一届世界遗传算法大会。随着计算机计算能力的发展和实际应用需求的增多,遗传算法逐渐进入实际应用阶段。1989年,纽约时报作者约翰·马科夫写了一篇文章描述第一个商业用途的遗传算法--进化者(英文:Evolver)。之后,越来越多种类的遗传算法出现并被用于许多领域中,财富杂志500强企业中大多数都用它进行时间表安排、数据分析、未来趋势预测、预算、以及解决很多其他组合优化问题。

3.应用领域

4.适用问题

全局最优化问题(用其他优化方法较难求解,通常选择GA和LINGO)

5.算法详解

刚才说到了遗传算法的来源与基础,下面我们来具体说一说生物进化与遗传算法名词的对应关系。

5.1 对应关系

生物进化

遗传算法

环境

适应函数

适者生存

适应函数值最大的解被保留的概率最大

个体

问题的一个解

染色体

解的编码

基因

编码的元素

种群

根据适应函数选择的一组解

交叉(交配)

以一定的方式由双亲产生后代的过程

变异

编码的某些分量发生变化的过程

了解了上面的对应关系之后,我们再一起来看遗传算法究竟是怎么实现的。

5.2 算法思想

遗传算法是从代表问题可能潜在解集的一个种群(population)

开始的,而一个种群则由经过基因编码(coding)的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。为了简化,往往采用二进制编码。对种群反复进行选择(selection)、交叉(crossover)、变异(mutation)操作,估计各个体的适应值(fitness),根据”适者生存、优胜劣汰”的进化规则,产生最好的种群,使适应性好的个体比适应性差的个体有更多的繁殖机会。最后把末代种群中的最优个体经过解码(decoding),可以获得满足要求的最优解。

5.3流程图描述

5.4 伪代码描述

(1) 随机产生初始种群;

(2) 计算种群体中每个个体的适应度值,判断是否满足停

止条件,若不满足,则转第(3)步,否则转第(7)步;

(3) 按由个体适应值所决定的某个规则选择将进入下一代

的个体;

(4) 按交叉概率Pc进行交叉操作,生产新的个体;

(5) 按变异概率Pm进行变异操作,生产新的个体;

(6) 输出种群中适应度值最优的染色体作为问题的满意解

或最优解。

  • Ø 具体讲解

遗传算法的具体实现

问题

如何进行编码?

如何产生初始种群?

如何定义适应函数?

如何进行遗传操作(复制、交叉、变异)?

如何产生下一代种群?

如何定义停止准则?

6.例题解析

6.1 例1:求解多变量多约束非线性规划问题

求解以下问题的解

函数图像:

解法:

      这题属于规划类问题,我们可以用LINGO来求解。

(1)  在LINGO中求解:

那么在遗传算法里面我们要怎么样去解决它呢?

(2)  在MATLAB中求解(GA工具箱求解):

这里使用到的是MATLAB自带的GA工具箱,即GADS工具箱。

遗传工具箱共有四大版本,分别是

英国Sheffield《genetic arithmetic toolbox》(GATBX遗传算法工具箱)

中国陈益《simple genetic algorithms laboratory》(SGALAB简单遗传算法实验室)

美国NCSU-IE《Genetic Algorithm Optimization Tool》(GAOT遗传算法优化工具箱)

美国MathWorks《Genetic Algorithm and Direct Search Toolbox 》(GADS遗传算法和直接搜索工具箱)

6.2 例2:求解最值问题

求解以下问题

函数图像为

最大值大约在x=1.5附近取得。

(1)   在LINGO中求解:

(2)  在MATLAB中求解:

第一种方法:使用GA工具箱

注意:GA工具箱默认求最小值!若要求最大值,需要加上负号!

代码实现如下:

%主程序代码,本程序采用遗传算法接力进化,
%将上次进化结束后得到的最终种群作为下次输入的初始种群
%主程序代码,
clc;
close all;
clear all;

% 进化的代数
T=50;
% 初始的种群
options=gaoptimset('Generations',T);
[x,fval,reason,output,final_pop]=ga(@fitnessfun,1,options);

%进行第二次接力进化
options1=gaoptimset('Generations',T,'InitialPopulation',final_pop,'PlotFcns',@gaplotbestf);
[x,fval,reason,output,final_pop]=ga(@fitnessfun,1,options1);

Bestx=x
BestFval=-fval

% 适应度函数
function f = fitnessfun(x)
    if(x<-2|x>2)
        f=100;
    else
        f=-200*exp(-0.05*x)*sin(x);
    end
end

生成结果如下:

要点:适应度函数的选取

第二种方法:使用GA工具箱GUI(有可能在将来的版本中移除)

这里我给大家实际演示一下。

要点

第三种方法:自定义实现遗传算法

接下来就步入正题了,因为工具箱提供的功能有限,很多时候不能很好地满足我们的需要,那我们怎么自己实现一个遗传算法呢?

代码实现如下:

%主程序代码,本程序采用遗传算法接力进化,
%将上次进化结束后得到的最终种群作为下次输入的初始种群
clc;
close all;
clear all;

%进化的代数
T=100;
optionsOrigin=gaoptimset('Generations',T);
[x,fval,reason,output,finnal_pop]=ga(@fitnessfun,2,optionsOrigin);

%进行第二次接力进化
options1=gaoptimset('Generations',T,'InitialPopulation',finnal_pop,'PlotFcns',@gaplotbestf);
[x,fval,reason,output,finnal_pop,trace]=ga(@fitnessfun,2,options1);

Bestx=x
BestFval=fval

% 适应度函数
function f = fun(x)
    g1=1.5+x(1)*x(2)-x(1)-x(2);
    g2=-x(1)*x(2)-10;
    if (g1>0|g2>0)
        f=100;
    else
        f=exp(x(1))*(4*x(1)^2+2*x(2)^2+4*x(1)*x(2)+2*x(2)+1);;
    end
end

%主程序:
%用遗传算法求解y=200*exp(-0.05*x).*sin(x)在[-2 2]区间上的最大值
clc;
clear all;
close all;

global BitLength
global boundsbegin
global boundsend
bounds=[-2 2];%一维自变量的取值范围
precision=0.0001; %运算精度
boundsbegin=bounds(:,1);
boundsend=bounds(:,2);
%计算如果满足求解精度至少需要多长的染色体
BitLength=ceil(log2((boundsend-boundsbegin)' ./ precision));
popsize=50; %初始种群大小

Generationnmax=100;  %最大代数
pcrossover=0.90; %交配概率
pmutation=0.09; %变异概率
%产生初始种群
population=round(rand(popsize,BitLength));
%计算适应度,返回适应度Fitvalue和累积概率cumsump
[Fitvalue,cumsump]=fitnessfun(population);
Generation=1;
while Generation<Generationnmax+1
   for j=1:2:popsize
      %选择操作
      seln=selection(population,cumsump);
      %交叉操作
      scro=crossover(population,seln,pcrossover);
      scnew(j,:)=scro(1,:);
      scnew(j+1,:)=scro(2,:);
      %变异操作
      smnew(j,:)=mutation(scnew(j,:),pmutation);
      smnew(j+1,:)=mutation(scnew(j+1,:),pmutation);
   end
   population=smnew;  %产生了新的种群
   %计算新种群的适应度
   [Fitvalue,cumsump]=fitnessfun(population);
   %记录当前代最好的适应度和平均适应度
   [fmax,nmax]=max(Fitvalue);
   fmean=mean(Fitvalue);
   ymax(Generation)=fmax;
   ymean(Generation)=fmean;
   %记录当前代的最佳染色体个体
   x=transform2to10(population(nmax,:));
   %自变量取值范围是[-2 2],需要把经过遗传运算的最佳染色体整合到[-2 2]区间
  xx=boundsbegin+x*(boundsend-boundsbegin)/(power((boundsend),BitLength)-1);
   xmax(Generation)=xx;
   Generation=Generation+1
end
Generation=Generation-1;
Bestpopulation=xx
Besttargetfunvalue=targetfun(xx)
%绘制经过遗传运算后的适应度曲线。一般地,如果进化过程中种群的平均适应度与最大适
%应度在曲线上有相互趋同的形态,表示算法收敛进行得很顺利,没有出现震荡;在这种前
%提下,最大适应度个体连续若干代都没有发生进化表明种群已经成熟。
figure(1);
hand1=plot(1:Generation,ymax);
set(hand1,'linestyle','-','linewidth',1.8,'marker','*','markersize',6)
hold on;

hand2=plot(1:Generation,ymean);
set(hand2,'color','r','linestyle','-','linewidth',1.8,...
'marker','h','markersize',6)
xlabel('进化代数');ylabel('最大/平均适应度');xlim([1 Generationnmax]);
legend('最大适应度','平均适应度');
box off;hold off;

%子程序:新种群交叉操作,函数名称存储为crossover.m
function scro=crossover(population,seln,pc);
BitLength=size(population,2);
pcc=IfCroIfMut(pc);  %根据交叉概率决定是否进行交叉操作,1则是,0则否
if pcc==1
   chb=round(rand*(BitLength-2))+1;  %在[1,BitLength-1]范围内随机产生一个交叉位
   scro(1,:)=[population(seln(1),1:chb) population(seln(2),chb+1:BitLength)];
   scro(2,:)=[population(seln(2),1:chb) population(seln(1),chb+1:BitLength)];
else
   scro(1,:)=population(seln(1),:);
   scro(2,:)=population(seln(2),:);
end  

%子程序:计算适应度函数, 函数名称存储为fitnessfun
function [Fitvalue,cumsump]=fitnessfun(population);
global BitLength
global boundsbegin
global boundsend
popsize=size(population,1);   %有popsize个个体
for i=1:popsize
   x=transform2to10(population(i,:));  %将二进制转换为十进制
    %转化为[-2,2]区间的实数
xx=boundsbegin+x*(boundsend-boundsbegin)/(power((boundsend),BitLength)-1);
   Fitvalue(i)=targetfun(xx);  %计算函数值,即适应度
end
%给适应度函数加上一个大小合理的数以便保证种群适应值为正数
Fitvalue=Fitvalue'+230;
%计算选择概率
fsum=sum(Fitvalue);
Pperpopulation=Fitvalue/fsum;
%计算累积概率
cumsump(1)=Pperpopulation(1);
for i=2:popsize
   cumsump(i)=cumsump(i-1)+Pperpopulation(i);
end
cumsump=cumsump';

%子程序:新种群变异操作,函数名称存储为mutation.m
function snnew=mutation(snew,pmutation);
BitLength=size(snew,2);
snnew=snew;
pmm=IfCroIfMut(pmutation);  %根据变异概率决定是否进行变异操作,1则是,0则否
if pmm==1
   chb=round(rand*(BitLength-1))+1;  %在[1,BitLength]范围内随机产生一个变异位
   snnew(chb)=abs(snew(chb)-1);
end   

%子程序:判断遗传运算是否需要进行交叉或变异, 函数名称存储为IfCroIfMut.m
function pcc=IfCroIfMut(mutORcro);
test(1:100)=0;
l=round(100*mutORcro);
test(1:l)=1;
n=round(rand*99)+1;
pcc=test(n);  

%子程序:新种群选择操作, 函数名称存储为selection.m
function seln=selection(population,cumsump);
%从种群中选择两个个体
for i=1:2
   r=rand;  %产生一个随机数
   prand=cumsump-r;
   j=1;
   while prand(j)<0
       j=j+1;
   end
   seln(i)=j; %选中个体的序号
end

%子程序:将2进制数转换为10进制数,函数名称存储为transform2to10.m
function x=transform2to10(Population);
BitLength=size(Population,2);
x=Population(BitLength);
for i=1:BitLength-1
   x=x+Population(BitLength-i)*power(2,i);
end

%子程序:对于优化最大值或极大值函数问题,目标函数可以作为适应度函数
%函数名称存储为targetfun.m
function y=targetfun(x); %目标函数
y=200*exp(-0.05*x).*sin(x);

生成结果如下:

遗传算法详解(LINGO及MatlabGA工具箱求解实现)的更多相关文章

  1. 遗传算法详解及c++实现

    1.什么是遗传算法? 遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法.遗传算法是从代表问题可能潜在的解集的一个种群开始的,而一 ...

  2. 用Advanced Installer制作DotNetBar for Windows Forms 12.0.0.1_冰河之刃重打包版详解

    关于 DotNetBar for Windows Forms 12.0.0.1_冰河之刃重打包版 --------------------11.8.0.8_冰河之刃重打包版-------------- ...

  3. JS逗号运算符的用法详解

    逗号运算符的用法详解 注意: 一.由于目前正在功读JavaScript技术,所以这里拿JavaScript为例.你可以自己在PHP中试试. 二.JavaScript语法比较复杂,因此拿JavaScri ...

  4. Dancing Link 详解(转载)

    Dancing Link详解: http://www.cnblogs.com/grenet/p/3145800.html Dancing Link求解数独: http://www.cnblogs.co ...

  5. ArcGIS中的北京54和西安80投影坐标系详解

    ArcGIS中的北京54和西安80投影坐标系详解 1.首先理解地理坐标系(Geographic coordinate system),Geographic coordinate system直译为地理 ...

  6. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  7. SIFT算法详解(转)

    http://blog.csdn.net/zddblog/article/details/7521424 目录(?)[-] 尺度不变特征变换匹配算法详解 Scale Invariant Feature ...

  8. 【转】 SIFT算法详解

    尺度不变特征变换匹配算法详解Scale Invariant Feature Transform(SIFT)Just For Fun zdd  zddmail@gmail.com 对于初学者,从Davi ...

  9. HS光流算法详解&lt;转载&gt;

    HS 光流法详解 前言 本文较为详细地介绍了一种经典的光流法 - HS 光流法. 光流法简介 当人的眼睛与被观察物体发生相对运动时,物体的影像在视网膜平面上形成一系列连续变化的图像,这一系列变化的图像 ...

随机推荐

  1. JavaScript高级程序设计学习笔记--引用类型

    Object类型 对象字面量表示法: var person={ name:"Nicholas", age:29, 5:true }; 这人例子会创建一个对象,包含三个属性:name ...

  2. CentOS搭建Redis集群

    集群原理-redis-cluster架构图 架构细节: (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽. (2)节点的fail是通过集群中超过半数的 ...

  3. Java 动态编译组件 &amp; 类动态加载

    1.JDK6 动态编译组件 Java SE 6 之后自身集成了运行时编译的组件:javax.tools,存放在 tools.jar 包里,可以实现 Java 源代码编译,帮助扩展静态应用程序.该包中提 ...

  4. Android Activity的切换动画

    Android的Activity切换有两种方法, 第一种是用代码方式实现: Activity A跳转到Activity B,要在startActivity(intent)后面加上overridePen ...

  5. 【Android实战开发】3G技术和Android发展简介

    随着移动设备的不断普及和发展,相关软件的开发也越来越受到人们的关注,其中要提及的就是Android开发.本系列博客主要为大家介绍Android的开发,可能会有人问:现在互联网上已经有很多的Androi ...

  6. zTree实现地市县三级级联报错(三)

    zTree实现地市县三级级联报错(三) 1.具体报错如下 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] ...

  7. 用windbg显示特定进程虚拟地址的方法

    1 必须使用Livekd.exe启动windbg 2 !process PID 3 找到PROCESS对象的地址:PROCADDR 4 找到进程的DirBase 5 r cr3 = DirBase 6 ...

  8. synchronized(this) 与synchronized(class) 之间的区别

    一.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...

  9. UI组件--element-ui--全部引入和按需引入

    主要就是一句话, 如果用到的组件少, 要按需引入, 如果用到的组件很多,就全部引入, 因为按需引入全部的, 和全部引入效果一样(我这是废话, 大家都知道...) 完整引入 在 main.js 中写入以 ...

  10. tp5.0 composer命令插件

    1.单元测试composer require topthink/think-testing 1.* (5.0) composer require topthink/think-testing 5.1官 ...