用Matlab 2012a实现遗传算法

遗传算法是一种非线性最优化算法,适用于复杂系统优化。它以决策变量编码为运算对象,通过适应度函数、选择、交叉和变异算子进行全局和局部搜索。本文详细介绍了遗传算法的基本概念、特点、实现步骤,并提供了MATLAB程序的解析,包括初始化种群、适应度计算、选择、交叉和变异等关键步骤。程序展示了遗传算法如何在迭代中逐步逼近最优解。
摘要由CSDN通过智能技术生成

目录

1 什么是遗传算法,他能干什么?

2 遗传算法的主要特点是什么?

3 如何实现遗传算法,流程是什么?

3.1 遗传算法的基本流程

3.2 基本遗传算法的实现技术

3.2.1 编码

3,2,2 适应度函数

3.2.3 选择算子

3.2.4 交叉算子

3.2.5 变异算子

3.2.6 运行参数

4 程序解析

4.1主程序代码解析

4.2 初始化种群子程序解析

4.3 适应度子程序解析

4.4 种群“优胜略汰”选择子程序解析

4.5 染色体编码生成子程序解析

4.6 染色条杂交子程序解析

4.7 染色体变异子程序解析

4.8 染色体解码为种群子程序解析

4.9 生成新一代的种群解析


1 什么是遗传算法,他能干什么?

遗传算法(Genetic Algorithm,GA)简单理解就是一种非线性的最优化算法。最优化干的事他都能干。

2 遗传算法的主要特点是什么?

遗传算法可用于复杂系统的最优化问题,而且很稳定。与传统的最优化算法相比,具有以下特点:

(1). 以决策变量的编码作为运算对象。

(2). 直接以适应度作为搜索信息。

(3). 使用多个点的搜索信息,具有隐含并行性。

(4). 使用概率搜索而非确定性规则。

上述4个特征看不懂也没关系,在实际测试的时候就自然可以理解了。

3 如何实现遗传算法,流程是什么?

首先看基本的遗传算法(Simple Genetic Algorithms,SGA),基本遗传算法只使用选择算子、交叉算子和变异算子这三种遗传算子,进化过程简单。其他遗传算法都是以这个为基础发展而来的。

3.1 遗传算法的基本流程

首先,通过随机方式产生若干由确定长度(长度与待求解问题的精度有关)编码的初始群体;
其次,通过适应度函数对每个个体进行评价,选择适应度值高的个体参与遗传操作,适应度低的个体被淘汰;
之后,经遗传操作(复制、交叉、变异)的个体集合形成新一代种群,直到满足停止准则(进化代数GEN>=?);
最后,将后代中变现最好的个体作为遗传算法的执行结果。

3.2 基本遗传算法的实现技术

基本遗传算法(SGA)由编码、适应度函数、遗传算子(选择、交叉、变异)及运行参数组成。

3.2.1 编码

(1)二进制编码

二进制编码的字符串长度与问题所求解的精度有关。需要保证所求解空间内的每一个个体都可以被编码。

优点:编、解码操作简单,遗传、交叉便于实现

缺点:长度大

(2)其他编码方法

格雷码、浮点数编码、符号编码、多参数编码等

3,2,2 适应度函数

适应度函数要有效反映每一个染色体与问题的最优解染色体之间的差距。

3.2.3 选择算子

通过选择算子模拟“优胜劣汰”,适应度高的个体被遗传到下一代的概率较大,适应度低的算子被遗传到下一代的概率较小。

常用的选择算法:轮盘赌选择法,即令表示群体的适应度函数值的总和,表示群体中第i个染色体的适应度值,则它产生后代的能力刚好为其适应度值所占的份额

3.2.4 交叉算子

交叉运算是指对两个相互配对的染色体按某种方式相互交换其部分基因,从而形成两个新的个体;
交叉运算是遗传算法区别于其他进化算法的重要特征,是产生新个体的主要方法。
在交叉之前需要将群体中的个体进行配对,一般采取随机配对原则。

常用的交叉方式:

单点交叉
双点交叉(多点交叉,交叉点数越多,个体的结构被破坏的可能性越大,一般不采用多点交叉的方式)
均匀交叉
算术交叉

3.2.5 变异算子

遗传算法中的变异运算是指将个体染色体编码串中的某些基因座上的基因值用该基因座的其他等位基因来替换,从而形成一个新的个体。

就遗传算法运算过程中产生新个体的能力方面来说,交叉运算是产生新个体的主要方法,它决定了遗传算法的全局搜索能力;而变异运算只是产生新个体的辅助方法,但也是必不可少的一个运算步骤,它决定了遗传算法的局部搜索能力。交叉算子与变异算子的共同配合完成了其对搜索空间的全局搜索和局部搜索,从而使遗传算法能以良好的搜索性能完成最优化问题的寻优过程。

3.2.6 运行参数

编码长度。编码长度取决于问题解的精度,精度越高,编码越长;
种群规模。规模小,收敛快但降低了种群的多样性,;
交叉概率。较大的交叉概率容易破坏种群中已形成的优良结构,使搜索具有太大随机性;较小的交叉概率发现新个体的速度太慢,一般取值为
变异概率。变异概率太小,则变异操作产生新个体的能力和抑制早熟现象的能力会较差;变异概率过高随机性过大,一般建议取值范围为0.005~0.01
终止进化代数。算法运行结束的条件之一,一般取100~1000

4 程序解析

本程序下载自Github: GitHub - strawberry-magic-pocket/Genetic-Algorithm: 基本遗传算法MATLAB程序

4.1主程序代码解析

clear;clc;close all;

%%遗传参数设置
NUMPOP=100;%初始种群大小
irange_l=-1; %问题解区间
irange_r=2;
LENGTH=22; %二进制编码长度
ITERATION = 10000;%迭代次数
CROSSOVERRATE = 0.7;%杂交率
SELECTRATE = 0.5;%选择率
VARIATIONRATE = 0.001;%变异率

%初始化种群
pop=m_InitPop(NUMPOP,irange_l,irange_r);
pop_save=pop;
%绘制初始种群分布
x=linspace(-1,2,1000);
y=m_Fx(x);
plot(x,y);
hold on
for i=1:size(pop,2)
    plot(pop(i),m_Fx(pop(i)),'ro');
end
hold off
title('初始种群');

%开始迭代
for time=1:ITERATION
    %计算初始种群的适应度
    fitness=m_Fitness(pop);
    %选择
    pop=m_Select(fitness,pop,SELECTRATE);
    %编码
    binpop=m_Coding(pop,LENGTH,irange_l);
    %交叉
    kidsPop = crossover(binpop,NUMPOP,CROSSOVERRATE);
    %变异
    kidsPop = Variation(kidsPop,VARIATIONRATE);
    %解码
    kidsPop=m_Incoding(kidsPop,irange_l);
    %更新种群
    pop=[pop kidsPop];
end
figure
x=linspace(-1,2,1000);
y=m_Fx(x);
plot(x,y);
hold on
for i=1:size(pop,2)
    plot(pop(i),m_Fx(pop(i)),'ro');
end
hold off
title('终止种群');

disp(['最优解:' num2str(max(m_Fx(pop)))]);
disp(['最大适应度:' num2str(max(m_Fitness(pop)))]);   
    
    


主程序的实现流程:

  • 设置参数
  • 初始化种群
  • 种群可视化(对算法没影响,只是看看)
  • 进入迭代
    • 计算初始种群的适应度
    • 选择
    • 编码
    • 交叉
    • 变异
    • 解码
    • 更新种群
  • 循环
  • 绘制最后得到的种群结果及相应的适应度。

4.2 初始化种群子程序解析

function pop=m_InitPop(numpop,irange_l,irange_r)
%% 初始化种群
%  输入:numpop--种群大小;
%       [irange_l,irange_r]--初始种群所在的区间
pop=[];
for i=1:numpop
    pop(:,i)=irange_l+(irange_r-irange_l)*rand;
end
end

这段代码较为简单,就是利用随机函数生成初始的种群。这里就只是给个初值,函数值还是需要用自定义函数来计算得。这个自定义函数实际上就是正演。

function y=m_Fx(x)
%% 要求解的函数
    y=x.*sin(3*pi.*x);
end

红色点就是初始种群,其中横坐标位置就是初始化函数随机出来的,在-1到2之间,函数时用fx计算出来的。蓝色线条是理论值,用来对比的。

计算出初始种群后就可以进入遗传算法的循环了,这里直接规定ITERATION = 10000;%迭代次数

进入循环后,首先要计算种群的适应度,目前的种群没有经过修改,还是初始的,那就是初始种群的适应度的。

4.3 适应度子程序解析

function fitness=m_Fitness(pop)
%% Fitness Function
%y=xsin(3x)在[-1,2]上,最大值也不会超过2
%所以计算函数值到2的距离,距离最小时,即为最优解
%适应度函数为1/距离
for n=1:size(pop,2)
    fitness(n)=1/(2-m_Fx(pop(:,n)));
end

end

输出的fitness也是个数组,就是适应度了。这个怎么计算得值得关注。主要是这个给定函数y=xsin(3x)在-1到2的区间上,最大值不会超过2,那么就可以计算种群到2的距离,距离最小时为最优解。距离怎么最小呢,就是倒数最小就可以了。

4.4 种群“优胜略汰”选择子程序解析

接下来就是种群的选择了。如上述所说,选择算子用来模拟“优胜劣汰”,适应度高的个体被遗传到下一代的概率较大,适应度低的算子被遗传到下一代的概率较小。怎么实现呢,看程序:

function parentPop=m_Select(matrixFitness,pop,SELECTRATE)
%% 选择
% 输入:matrixFitness--适应度矩阵
%      pop--初始种群
%      SELECTRATE--选择率

sumFitness=sum(matrixFitness(:));%计算所有种群的适应度

accP=cumsum(matrixFitness/sumFitness);%累积概率
%轮盘赌选择算法
for n=1:round(SELECTRATE*size(pop,2))
    matrix=find(accP>rand); %找到比随机数大的累积概率
    if isempty(matrix)
        continue
    end
    parentPop(:,n)=pop(:,matrix(1));%将首个比随机数大的累积概率的位置的个体遗传下去
end
end

这个函数的输入参数有3个,1是适应度向量,2是当前种群,3是选择率。输出为父辈种群,也就是能遗传下去的种群。

现将每个个体的适应度累加,得到总的适应度,在平均分给每个个体,得到每个个体的归一化适应度。然后采用轮盘赌的方式,设置一个随机的阈值,将不满足阈值的适应度的个体淘汰,就是直接置空。这时候种群的个体数为总数×选择率。

4.5 染色体编码生成子程序解析

接下来是编码:

function binPop=m_Coding(pop,pop_length,irange_l)
%% 二进制编码(生成染色体)
% 输入:pop--种群
%      pop_length--编码长度
pop=round((pop-irange_l)*10^6);
for n=1:size(pop,2) %列循环
    for k=1:size(pop,1) %行循环
        dec2binpop{k,n}=dec2bin(pop(k,n));%dec2bin的输出为字符向量;
                                          %dec2binpop是cell数组
        lengthpop=length(dec2binpop{k,n});
        for s=1:pop_length-lengthpop %补零
            dec2binpop{k,n}=['0' dec2binpop{k,n}];
        end
    end
    binPop{n}=dec2binpop{k,n};   %取dec2binpop的第k行
end

    

这段代码采用了二进制编码。输入选择过得种群,编码长度,以及左侧边界。

首先减去左侧边界,这类似于归零的办法。然后乘以1000000,得到较大的数。然后十进制数转二进制数,不够的位数用0补齐。得到二进制编码,也就是染色体。

本例中,种群是100个,淘汰率50%,经过选择后就剩下50个数,然后对这50个数都转为二进制,一个二进制数是22位。这样就得到50个二进制数。

之后是交叉。交叉运算是指对两个相互配对的染色体按某种方式相互交换其部分基因,从而形成两个新的个体;交叉运算是遗传算法区别于其他进化算法的重要特征,是产生新个体的主要方法。
在交叉之前需要将群体中的个体进行配对,一般采取随机配对原则。

4.6 染色条杂交子程序解析

下面看交叉的算法:

function kidsPop = Crossover(parentsPop,NUMPOP,CROSSOVERRATE)
kidsPop = {[]};n = 1;
while size(kidsPop,2)<NUMPOP-size(parentsPop,2)
    %选择出交叉的父代和母代
    father = parentsPop{1,ceil((size(parentsPop,2)-1)*rand)+1};
    mother = parentsPop{1,ceil((size(parentsPop,2)-1)*rand)+1};
    %随机产生交叉位置
    crossLocation = ceil((length(father)-1)*rand)+1;
    %如果随即数比交叉率低,就杂交
    if rand<CROSSOVERRATE
        father(1,crossLocation:end) = mother(1,crossLocation:end);
        kidsPop{n} = father;
        n = n+1;
    end
end

交叉函数的输入有3个:1是刚才生成的二进制编码数组,2是初始种群大小,3是杂交率。

杂交的过程为:先从二进制编码组中随机选择出父母,然后随机选择杂交的位置,再生成一个随机数,如果这个随机数比杂交率低,就将杂交位置的信息在父母上对换。再把父亲值赋予儿子。

看起来儿子的个数正好是刚才被淘汰的个数。后面将儿子补齐到新种群,所得的种群就又是原来的个数了。这个种群人口保持不变。

4.7 染色体变异子程序解析

杂交以后,还得变异。如果说杂交让遗传算法能进行全局处理,那么变异就是让他能局部处理。

%% 
function kidsPop = Variation(kidsPop,VARIATIONRATE)
for n=1:size(kidsPop,2)
    if rand<VARIATIONRATE
        temp = kidsPop{n};
        %找到变异位置
        location = ceil(length(temp)*rand);
        temp = [temp(1:location-1) num2str(~temp(location))...
            temp(location+1:end)];
       kidsPop{n} = temp;
    end
end

变异有2个输入参数,1是刚生产的儿子,也就是只对儿子做变异;2是变异率。这里变异率取0.001,也就是变异的个体是很少的。

具体的变异方法:对儿子循环,当随机数小于变异率时,对这个儿子开始变异,找一个随机位置,然后对这个位置进行变异,之后还是赋予这个儿子。

4.8 染色体解码为种群子程序解析

杂交,变异结束后,将对儿子进行解码。

function pop=m_Incoding(binPop,irange_l)
%% 解码
popNum=1;
popNum = 1;%染色体包含的参数数量
for n=1:size(binPop,2)
    Matrix = binPop{1,n};
    for num=1:popNum
        pop(num,n) = bin2dec(Matrix);
    end
end
pop = pop./10^6+irange_l;

解码比较简单,就是讲二进制数组改为十进制的,然后在除以100000,加上左边界,就行了。

4.9 生成新一代的种群解析

解码之后,将儿子加到种群后面的空位,就行了。这样如此往复循环,就得到了一个新的种群。这个种群是经过杂交,变异后的种群。

这是迭代10次之后的结果,可以看到,遗传算法收敛的很快,种群已经迅速向预定值靠拢了。只有这里的适应度是最高的。 

 本文是对该博文的学习: 详解遗传算法(含MATLAB代码)_草莓酱土司的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Intimes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值