遗传算法例子(转)

来源:互联网 发布:php msgpack pack 编辑:程序博客网 时间:2024/06/05 21:51
遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法可以解决多种优化问题,如:TSP问题、生产调度问题、轨道优化问题等,在现代优化算法中占据了重要的地位,本文简要地介绍了遗传算法。

    在此之前我们通过一个小故事来通俗地讲解遗传算法:

    从前有一群快乐的袋鼠(初代),生活在某某不知名的山上,有的袋鼠喜欢生活在高处,有的袋鼠喜欢生活在山脚,如图:


    可是天有不测风云,袋鼠有祸兮旦福。随着全球气候变暖,生活在山脚的袋鼠被热死了(所以说保护环境、减少排放很重要)。但是,生活在山麓和山顶的袋鼠生存了下来,他(她)们互相啪啪啪,生下了下一代(第二代)。


    第二代袋鼠继承了父母的好奇心和勇气,有部分袋鼠继续向山顶跑,当然也有一小部分去探索山脚的世界去了。但是,可恶的人类不知道节制,温室效应继续增强,山麓的袋鼠也相继死去,当然,山脚的袋鼠也死了。

    值得开心的是,接近山顶的袋鼠还活着诶!!!这群勇敢的袋鼠快乐地生活、繁衍、生活……繁衍,气候也不停地变热。就这样过了很久很久,终于有一只袋鼠跑到了山顶!!!到了山顶!!!到了山顶!!!(重要的事情说三遍)跑到山顶的他也得到了一块巧克力作为奖励,然后,故事快乐的结束了。



    故事虽然结束了,但是,我们学习遗传算法的脚步不能停歇。回顾整个故事,每只袋鼠就是个体,最开始袋鼠是随机地分布在整座山上的。但随之气候变暖,有的袋鼠死去(选择)。同时,活下来的袋鼠繁衍,产生新的一代袋鼠,他们大部分生活在更高处,小部分去低处生活(交叉、变异)。同时,气候又变暖了,活在山麓的袋鼠也死了,只有生活在更高处的袋鼠活了下来。就这样周而复始地过了很久(迭代),终于有一只袋鼠到了山顶,吃到了巧克力,故事结束(跳出迭代)。

    所以,遗传算法有几个部分:

例题:

    寻找函数f(x)=x*sin(3*pi*x)的最大值,搜索范围[-1,2]。

    初始化种群

    随机产生一定数量的个体,组成一个种群。代码如下:

[plain] view plain copy
  1. function pop = IntPop(numPop)  
  2. pop = [];%初始化种群矩阵  
  3. for n=1:numPop  
  4.     pop(:,n) = 3*rand-1;%个体范围[-1,2]  
  5.     %产生初始种群  
  6. end  

      


    计算适应度

    计算适应度需要个人找到合适的目标函数,适应度函数的优化目标是适应度越大越好。所以,如果你的目标是min,请使用它的倒数,即max=1/min。本题中,在已知最大值的条件下,使用个体与目标的欧式距离的倒数作为适应度函数。当然,也可以将函数本身作为适应度函数。

[plain] view plain copy
  1. function fitness = Fitness(pop)  
  2. for n = 1:size(pop,2)  
  3.     fitness(n) = 1/abs(2-Fx(pop(n)));  
  4. end  

    选择

     选择是为了将适应度小的个体淘汰的,模拟了自然环境中的优胜劣汰。选择的算法一般选择轮盘赌算法。轮盘赌算法是指,所有个体的适应度组成圆盘,适应度越大的扇形面积越大。


程序如下:

[plain] view plain copy
  1. function parentsPop = Select(matrixFitness,pop,SELECTRATE)  
  2. sumFitness = sum(matrixFitness);%计算所有个体的适应度之和  
  3. accP = [];%积累概率  
  4. for n=1:size(pop,2)  
  5.     accP(n) = sum(matrixFitness(1:n))./sumFitness;  
  6.     %计算从1到n的积累概率  
  7. end  
  8. %轮盘赌选择法  
  9. for n=1:round(SELECTRATE*size(pop,2))  
  10.     matrix = find(accP>rand);%找到比随机数小的积累概率位置  
  11.     if isempty(matrix)  
  12.         continue  
  13.     end  
  14.     parentsPop(:,n) = pop(:,matrix(1));  
  15.     %将首个比随机数小的积累概率小的位置的个体遗传下去  
  16. end  

    编码

    编码是为了产生一个2进制染色体,方便进行交叉和变异。当然,编码规则具体问题需要具体规定。

[plain] view plain copy
  1. function binPop = Codeing(pop)  
  2. codeLength = 35;%编码长度  
  3. pop = round((pop+1)*10^10);%[-1,2]浮点数  
  4. for n=1:size(pop,2)  
  5.     for k=1:size(pop,1)  
  6.         dec2binPop{k,n} = dec2bin(pop(k,n));          
  7.         lengthPop = length(dec2binPop{k,n});          
  8.         for s=1:codeLength-lengthPop  
  9.             dec2binPop{k,n} = ['0' dec2binPop{k,n}];  
  10.         end  
  11.     end  
  12.     binPop{n} = dec2binPop{k,n};  
  13. end  

    解码

    有编码,当然也要解码。

[plain] view plain copy
  1. function pop = Incodeing(binPop)  
  2. popNum = 1;%染色体包含的参数数量  
  3. for n=1:size(binPop,2)  
  4.     Matrix = binPop{1,n};  
  5.     for num=1:popNum  
  6.         pop(num,n) = bin2dec(Matrix);  
  7.     end  
  8. end  
  9. pop = pop./10^10-1;  

    交叉

    交叉互换是生物遗传变异的主要形式,正是因为交叉互换,带给了我们一些和父母都不相同的生理特征。

    同样,交叉算子是遗传算法中非常重要的一部分。机器从种群中随机选择一对“父母亲”,随机产生交叉位置,交换染色体的剩下部分。如图


    发生交叉之后的染色体:


    可以看到,一次交叉就可以产生两个新个体。当时,考虑种群的多样性,我们可以只取一条个体。

    程序如下:

[plain] view plain copy
  1. function kidsPop = Crossover(parentsPop,NUMPOP,CROSSOVERRATE)  
  2. kidsPop = {[]};n = 1;  
  3. while size(kidsPop,2)<NUMPOP-size(parentsPop,2)  
  4.     %选择出交叉的父代和母代  
  5.     father = parentsPop{1,ceil((size(parentsPop,2)-1)*rand)+1};  
  6.     mother = parentsPop{1,ceil((size(parentsPop,2)-1)*rand)+1};  
  7.     %随机产生交叉位置  
  8.     crossLocation = ceil((length(father)-1)*rand)+1;  
  9.     %如果随即数比交叉率低,就杂交  
  10.     if rand<CROSSOVERRATE  
  11.         father(1,crossLocation:end) = mother(1,crossLocation:end);  
  12.         kidsPop{n} = father;  
  13.         n = n+1;  
  14.     end  
  15. end  

    变异

    在遗传变异过程中,另一个重要的过程就是变异。

    我们通过随机某位取反,完成变异操作

    程序如下:    

[plain] view plain copy
  1. function kidsPop = Variation(kidsPop,VARIATIONRATE)  
  2. for n=1:size(kidsPop,2)  
  3.     if rand<VARIATIONRATE  
  4.         temp = kidsPop{n};  
  5.         %找到变异位置  
  6.         location = ceil(length(temp)*rand);  
  7.         temp = [temp(1:location-1) num2str(~temp(location))...  
  8.             temp(location+1:end)];  
  9.        kidsPop{n} = temp;  
  10.     end  
  11. end  

最后的优化结果:


完整程序下载地址:http://download.csdn.net/detail/treasure_c_j_l/9059215