《Matlab在数学建模中的应用》笔记4-遗传算法(GA)(1)

刚接触遗传算法,感觉还是不是很懂。。。个人认为是一种求解最优化问题的算法。先引入具体实现过程:

  • 1.编码
    GA包括浮点编码以及二进制编码,这里介绍后者,因为既符合计算机二进制工作原理又能方便表示染色体变异、基因突变等概念。设某一参数取值范围为(L,U),使用长度为k的二进制编码该参数,有
    2k
    2^k种不同编码。有对应关系:

00000000000=0−→L

00000000000=0 \xrightarrow{}L

00000000001=1−→L+δ

00000000001=1 \xrightarrow{}L +\delta

00000000010=2−→L+2δ

00000000010=2 \xrightarrow{}L+2\delta

11111111111=2k−1−→U=L+(2k−1)∗δ

11111111111=2^k-1 \xrightarrow{}U=L+(2^k-1 )*\delta 因此,
δ=(U−L)/(2k−1)
\delta=(U-L)/(2^{k}-1)

  • 2.解码
    解码就是把二进制数化为10进制,转换公式为

x=L+(∑i=1kbi2i−1)∗(U−L)/(2k−1−1)

x=L+(\sum_{i=1}{k}b_{i}2{i-1})*(U-L)/(2^{k-1}-1)

  • 3.个体适应度评估(即目标函数值)
    先随机产生(L,U)范围内的二进制数串(需初始种群数量),再解码为对应的10进制数,代入y=(x1,x2,…),求出对应的多组适应度值,即y值,对所有y值求和并求出每个y所占比例(适应度所占概率)以及每一个一个下来的累积概率
  • 4.复制与剔除(进化与自然选择)
    根据6求得的适应度所占概率表格,先产生一组随机数(数量和初始化种群数一致),判定每个随机数在累积概率的哪个区间,例如:第一个随机数是0.1,累积概率序列为(对应染色体序列)0.02,0.05,0.2,1,则0.05<0.1<0.2,落在第2、3个区间中,3对应的染色体被选中。对所有产生的随机数如此操作。
  • 5.新种群交配
    对7筛选出来的新的染色体交配(交叉互换)产生新个体
  • 6.基因突变
    先定下突变概率。如概率为0.01,有10个个体,染色体对应的二进制数串有33位,则新一代(即8产生后代)有33*10*0.01=3.3个突变基因。由于,突变几率对于每个染色体概率均等,先产生330个0-1之间的随机数(对应330个基因序列),挑出<0.01的对应染色体,并找出对应的基因所在染色体序列位置以及基因的位数。
  • 7.循环
    然后,把突变后的新种群染色体(二进制数串)再转为10进制代入目标函数求得适应度。返回4,不断循环(可设置循环次数,即代数),最后如果都是同一个体(即均为同一个染色体二进制数串)或到达最大迭代代数时,跳出循环,得到对应染色体数串时的目标函数值为最优值。
  • 伪代码
%Matlab & GA
%遗传算法伪代码(GA's pseudocode)
BEGINdd
    t=0;                %遗传代数
    初始化P(t);            %初始化种群或染色体
    计算P(t)的适应值;
    while(不满足停止法则)do
        begin
        t=t+1;
        从P(t-1)中选择P(t); %选择
        重组P(t);         %交叉&变异
        计算P(t)的适应值;
        end
END
  • Attention
    建议:初始化种群数量为0-100;变异概率为0.0001-0.2;
    交配概率为0.4-0.99;进化代数为100-500.

个人认为,简单看来,遗传算法的目的是:求解特定约束下,目标函数的最优值(max or min)。以下为例子代码,一切尽在代码中。

  1. 求解

maxf(x)=200e−0.05xsin(x),x∈[−2,2]

max f(x)=200e^{-0.05x}sin(x),x\in[-2,2]

(1)在求解之前,先用Matlab画出该函数在[-2,2]中的图像,代码如下:

%matlab画图
x=[-2:0.1:2];
y=200.*exp(-0.05.*x).*sin(x);
plot(x,y);
grid on;
xlabel('x');ylabel('f(x)');
title('函数图像');

下图为结果输出:
函数图像

由上图估计,max f(x)大概在(1.543,185.1)的坐标位置。

(2)以下为matlab代码(待更)
由于代码过长,分为几个函数po出,需要慢慢看懂代码才是关键啊。。。打码时,把子函数存为M文件,主程序main.m为代码调用子函数。

以下为主程序:

%主程序main:用遗传算法求解y=200\*exp(-0.05\*x).\*sin(x)在[-2,2]区间上的最大值
clc;
clear all;
close all;
global BitLength
global BitLength2
global BitLength3
global boundsbegin
global boundsend
global bounds2begin
global bounds2end
global bounds3begin
global bounds3end
bounds=[-2 2];%一维自变量的取值范围
precision=0.0001; %运算精度
boundsbegin=bounds(:,1);
boundsend=bounds(:,2);
bounds2begin=bounds2(:,1);
bounds2end=bounds2(:,2);
bounds3begin=bounds3(:,1);
bounds3end=bounds3(:,2);
%计算如果满足求解精度至少需要多长的染色体
BitLength=ceil(log2((boundsend-boundsbegin)' ./ precision));
BitLength2=ceil(log2((bounds2end-bounds2begin)' ./ precision));
BitLength3=ceil(log2((bounds3end-bounds3begin)' ./ precision));
popsize=300; %初始种群大小
Generationnmax=500; %最大代数
pcrossover=0.90; %交配概率
pmutation=0.09; %变异概率
%产生初始种群
population=round(rand(popsize,BitLength+BitLength2+BitLength3));
%计算适应度,返回适应度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,:),BitLength);
 x2=transform2to10\_2(population(nmax,:),BitLength,BitLength2);
 x3=transform2to10\_3(population(nmax,:),BitLength,BitLength2,BitLength3);
 %根据自变量取值范围,需要把经过遗传运算的最佳染色体整合到取值范围的区间
 xx=boundsbegin+x\*(boundsend-boundsbegin)/(power(2,BitLength)-1);
 xx2=bounds2begin+x2\*(bounds2end-bounds2begin)/(power(2,BitLength2)-1);
 xx3=bounds3begin+x3\*(bounds3end-bounds3begin)/(power(2,BitLength3)-1);
 %求解出变量的十进制结果
 xmax(Generation,:)=[xx,xx2,xx3];
 Generation=Generation+1
end 

Generation=Generation-1;
Bestpopulation=[xx,xx2,xx3]
Besttargetfunvalue=targetfun(xx,xx2,xx3)

%绘制经过遗传运算后的适应度曲线。一般地,如果进化过程中种群的平均适应度与最大适
%应度在曲线上有相互趋同的形态,表示算法收敛进行得很顺利,没有出现震荡;在这种前
%提下,最大适应度个体连续若干代都没有发生进化表明种群已经成熟。
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
%子程序:新种群交叉操作,函数名称存储为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.m
%子程序:计算适应度函数, 函数名称存储为fitnessfun
function [Fitvalue,cumsump]=fitnessfun(population);
global BitLength
global BitLength2
global BitLength3
global boundsbegin
global boundsend
global bounds2begin
global bounds2end
global bounds3begin
global bounds3end
popsize=size(population,1);   %有popsize个个体
for i=1:popsize
   x=transform2to10(population(i,:),BitLength);  %将二进制转换为十进制
   x2=transform2to10_2(population(i,:),BitLength,BitLength2);
   x3=transform2to10_3(population(i,:),BitLength,BitLength2,BitLength3);
    %转化为[-2,2]区间的实数
xx=boundsbegin+x*(boundsend-boundsbegin)/(power(2,BitLength)-1);
xx2=bounds2begin+x2*(bounds2end-bounds2begin)/(power(2,BitLength2)-1);


## 学习路线:

这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7a04c5d629f1415a9e35662316578e07.png#pic_center)



  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值