应是天仙狂醉,乱把白云揉碎|

逆世混沌

园龄:3年2个月粉丝:6关注:5

学点数模-2——遗传算法

今天来学习一下遗传算法,其实相关的代码已经找到了,但是想先学一下,因为我发现我有些地方不能纯看代码看懂。还是得辅佐一下。

说白了就是模拟生物进化的,那么我们先构建一个模拟生物进化的模型,

首先,我们可以想象一下,

1.有三十只兔子在某一块地皮上,这就是初始种群。

2.这三十只兔子会相互繁育下一代,这之中会产生基因的交叉,即父母的染色体各取一条。还会产生染色体变异

3.产生的下一代还会不断的产生基因的交换与变异

4.物竞天择——因为某一个特定的规则,这个兔子活了下来,这里会复杂一点

  

我们可以简单思考一下,即使是物竞天择了、也不止是强壮的兔子活了下来,还有一些兔子侥幸活了下来。所以我们如果在模型里进行的话,简单来说,就是这个兔子的强壮程度决定了他活下去的概率。并且,这个兔子的强壮程度还会决定它的染色体会更优先被选中,即更容易发生交换(变异是无时无刻的,没有选择的)

在解释了一下遗传算法的基础思想之后,我们还要提一嘴

遗传算法,本质上还是在寻找最优解,它也是模拟的种群遗传去寻找最优解的。跟上次的模拟退火是一样的,目的上并没有区别。

1,相关的函数及解释

适应度函数(fitness function)

这个函数是基于你所添加的判断去计算适应度的。比方说,你想计算一个完全没有规律的函数的最优解,那么所有兔子越偏向优解的,越具有适应度。适应度函数就取决于你想要计算最优解的函数

 选择函数(selection)

选择函数指的是种群选择度,是来源于适应度的,适应度越高,其越会被选择,当然这是概率层面更高,并非适应度低就完全不行。

染色体交叉与变异

理论上,将染色体转为二进制是最正规的,但是其本身是“像”而非好用(个人理解),我们正常使用,用浮点数就完全ok,当然,浮点数是有弊端的,不像二进制那种随意交换,我们可以选择把重点放在变异

染色体变异则是我们可想而知的东西。比方说,这个染色体的浮点数编码是1.1,2.5,4.6,之后发生变异,这个变异可以大也可以小,可以增也可以减,这些都可以,但是由于刚开始计算为了尽快到达尽量优解,而后期想要更为精确的到达最优解,我们可以动态规划变异,即刚开始变异步幅大,后期变异步幅小,可以在种群繁衍几十次之后修改,动态就好。

 main.m

复制代码
function main()
clear;
clc;
%种群大小
popsize=100;
%二进制编码长度
chromlength=10;
%交叉概率
pc = 0.6;
%变异概率
pm = 0.001;
%初始种群
pop = initpop(popsize,chromlength);
objvalue = cal_objvalue(pop);
fitvalue = objvalue;

for i = 1:100
    %选择操作
    newpop = selection(pop,fitvalue);
    %交叉操作
    newpop = crossover(newpop,pc);
    %变异操作
    newpop = mutation(newpop,pm);
    %更新种群
    pop = newpop;
    %计算适应度值(函数值)
    objvalue = cal_objvalue(pop);
    fitvalue = objvalue;
    %寻找最优解
    [bestindividual,bestfit] = best(pop,fitvalue);
    x2 = binary2decimal(bestindividual);
    x1 = binary2decimal(newpop);
    y1 = cal_objvalue(newpop);
    if mod(i,10) == 0
        figure;
        fplot('10*sin(5*x)+7*abs(x-5)+10',[0 10]);
        hold on;
        plot(x1,y1,'*');
        size(x1)
        title(['iteration times n=' num2str(i)]);
        %plot(x1,y1,'*');
    end
end
fprintf('The best X is --->>%5.2f\n',x2);
fprintf('The best Y is --->>%5.2f\n',bestfit);
复制代码

initpop.m

复制代码
%初始化种群大小
%输入变量:
%popsize:种群大小
%chromlength:染色体长度-->>转化的二进制长度
%输出变量:
%pop:种群
function pop=initpop(popsize,chromlength)
pop = round(rand(popsize,chromlength));
%rand(3,4)生成3行4列的0-1之间的随机数
% rand(3,4)
% 
% ans =
% 
%     0.8147    0.9134    0.2785    0.9649
%     0.9058    0.6324    0.5469    0.1576
%     0.1270    0.0975    0.9575    0.9706
%round就是四舍五入
% round(rand(3,4))=
% 1 1 0 1
% 1 1 1 0
% 0 0 1 1
%所以返回的种群就是每行是一个个体,列数是染色体长度
复制代码

二进制转十进制binary2decimal.m(我认为浮点数也是够的,不过找的源码懒得改了.)

 
复制代码
%二进制转化成十进制函数
%输入变量:
%二进制种群
%输出变量
%十进制数值
function pop2 = binary2decimal(pop)
[px,py]=size(pop);
for i = 1:py
    pop1(:,i) = 2.^(py-i).*pop(:,i);
end
%sum(.,2)对行求和,得到列向量
temp = sum(pop1,2);
pop2 = temp*10/1023;
复制代码

计算适应度函数cal_objvalue.m

%计算函数目标值
%输入变量:二进制数值
%输出变量:目标函数值
function [objvalue] = cal_objvalue(pop)
x = binary2decimal(pop);
%转化二进制数为x变量的变化域范围的数值
objvalue=10*sin(5*x)+7*abs(x-5)+10;

选择新个体selection.m

复制代码
%如何选择新的个体
%输入变量:pop二进制种群,fitvalue:适应度值
%输出变量:newpop选择以后的二进制种群
function [newpop] = selection(pop,fitvalue)
%构造轮盘
[px,py] = size(pop);
totalfit = sum(fitvalue);
p_fitvalue = fitvalue/totalfit;
p_fitvalue = cumsum(p_fitvalue);%概率求和排序
ms = sort(rand(px,1));%从小到大排列
fitin = 1;
newin = 1;
while newin<=px
    if(ms(newin))<p_fitvalue(fitin)
        newpop(newin,:)=pop(fitin,:);
        newin = newin+1;
    else
        fitin=fitin+1;
    end
end
复制代码

交叉crossover.m

复制代码
%交叉变换
%输入变量:pop:二进制的父代种群数,pc:交叉的概率
%输出变量:newpop:交叉后的种群数
function [newpop] = crossover(pop,pc)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:2:px-1
    if(rand<pc)
        cpoint = round(rand*py);
        newpop(i,:) = [pop(i,1:cpoint),pop(i+1,cpoint+1:py)];
        newpop(i+1,:) = [pop(i+1,1:cpoint),pop(i,cpoint+1:py)];
    else
        newpop(i,:) = pop(i,:);
        newpop(i+1,:) = pop(i+1,:);
    end
end
复制代码

变异mutation.m

复制代码
%关于编译
%函数说明
%输入变量:pop:二进制种群,pm:变异概率
%输出变量:newpop变异以后的种群
function [newpop] = mutation(pop,pm)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:px
    if(rand<pm)
        mpoint = round(rand*py);
        if mpoint <= 0;
            mpoint = 1;
        end
        newpop(i,:) = pop(i,:);
        if newpop(i,mpoint) == 0
            newpop(i,mpoint) = 1;
        elseif newpop(i,mpoint) == 1
            newpop(i,mpoint) = 0;
        end
    else newpop(i,:) = pop(i,:);
    end
end
复制代码

选择最优个体best.m

复制代码
%求最优适应度函数
%输入变量:pop:种群,fitvalue:种群适应度
%输出变量:bestindividual:最佳个体,bestfit:最佳适应度值
function [bestindividual bestfit] = best(pop,fitvalue)
[px,py] = size(pop);
bestindividual = pop(1,:);
bestfit = fitvalue(1);
for i = 2:px
    if fitvalue(i)>bestfit
        bestindividual = pop(i,:);
        bestfit = fitvalue(i);
    end
end
复制代码
以上源码来自遗传算法介绍并附上Matlab代码 - 知乎 (zhihu.com)
这篇文章源码注释写的非常非常好,给我自己也学习一下。
posted @   逆世混沌  阅读(63)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 狂迪 卢广仲
狂迪 - 卢广仲
00:00 / 00:00
An audio error has occurred.

作词 : 卢广仲/討海人/黄少雍

作曲 : 卢广仲

在我眼前消失不见

今天的什么都不对

楼下的店听见熟悉的音乐

谁离开我谁爱着我

剩下一半的小火锅

别乱牵拖直到你出现

满天星光月亮出来了

神魂颠倒这是真的吗

管不住我自己的步伐

戒不掉你致命的魔法

谁教我蜿蜒的弹跳

谁教我崎岖的舞蹈

我爱你你知不知道

OH Dónde estás Bongria

想要见面有点抱歉

下午才跟你晚上约

请放轻松看着公园的落叶

摇摇晃晃我的形状

一边海洋一边天堂

你拉着我这一步叫做永远

满天星光月亮出来了

神魂颠倒这是真的吗

管不住我自己的步伐

戒不掉你致命的魔法

谁教我蜿蜒的弹跳

谁教我崎岖的舞蹈

我爱你你知不知道

OH Dónde estás Bongria

我丢掉太多的不必要

朝着有你的方向跑

跑到你眼前逗你笑

听到电影里的配乐响起

全场只为了等你说一句

说欸你要不要跟我一起

去教堂

Yes I do希望你也一样

先说好一起永保安康

每一天蜿蜒的弹跳

每一天崎岖的舞蹈

我爱你你知不知道 OH

如果爱我让我看见你

的脚