版权声明:本文为博主原创文章,转载请注明出处。

本周的任务一个是搞JavaWeb的学习,一个是搞演化计算的学习,可惜的是JavaWeb的东西没搞出来,现在还是一团乱麻,演化计算终于是写出个小程序,但是也算是对演化计算有了初步的了解,所以这次就把演化计算的心得拿出来说说,用以本周总结和搞日后的回顾。

一、演化计算的基本步骤

  1. 根据需求制定编码方案,我的理解中编码其实就是确定染色体的形式,这个编码方案是整个计算的基础,变异杂交都是基于编码(染色体)之上的,所以首先就应该制定合理的编码方案。

   编码方案有很多种,最简单的是二进制编码,也是目前我唯一能理解的编码形式。所谓二进制编码就是用一串01的序列作为染色体,这种编码某种意义上讲和自然界真实的染色体是很想相似的,可以看做01是染色体颗粒,非常方便进行变异和交叉。二进制编码是一种很自然的编码方式。

   还有gray编码,实数编码,有序位串编码结构式编码等等其他形式,编码会影响到之后的效率,其他的编码形式日后再讲。

  2.确定适应函数。适应函数就是描述一个个体的好坏,用以进行选择,适应函数也分原始适应函数和标准适应函数。

  3.确定选择策略。选择策略是重中之重,因为这决定了进化的方向,选择函数就是自然界中的各种灾难和竞争,只有实力强大的和幸运的(?)才能存留下来,看来果然运气也是实力的一部分。

  选择策略也是多种多样的,但是关注的点不太一样,包括进化的速度,是否会陷入局部最优,群体的数目大小等等,具体的策略有繁殖池选择,转轮盘选择,线性排名选择,非线性排名选择锦标赛选择等等。

  4.控制参数的选择。就是根据具体问题决定算法中种群的规模,最大代数,一些遗传操作的概率和辅助性的参数的设置,看起来是比较微小的东西,但是像秤砣一样左右着整个计算的结果。

  5.遗传算子的设计。遗传算子主要包括繁殖,杂交,变异,是对于自然的进一步模拟,能够优化算法的性能,通过引入随机性来克服程序化的问题。

  6.确定终止的准则。

二、一个简单的实例

    f(x1,x2)=x1^2+x2^2,x1和x2是属于0~7的正整数,求f的最大值。

这种弱智问题当然一眼就可以看出答案,但是就是要用遗传算法来实现,用以熟悉相关的操作和步骤,下面开始介绍我的想法。(哦,这是用C++写的)

1.编码:这个0~7简直就是为了二进制编码设计的,对x1,x2分别用三位二进制数来表示就可以了

2.适应函数:由于是求f的最大值,就是说f越大越好,所以就直接拿f来做适应函数来评价x1,x2.

3.选择策略:本例中我用的是轮盘赌的策略,所谓轮盘赌就是让每一个个体根据某种和为1的概率被挑选,挑中了就留下,否则就淘汰,这个概率就是该个体适应值占总适应值的比例。也就是说适应值越高的越有可能被选中(当然,个体越多的也越容易被选中),但是够幸运的个体即使概率很低也有机会存留下来。被挑中存留的个体才有机会参加之后的繁殖杂交突变等等,其实就相当于自然界中的种群越是厉害的越有机会留下来,但是厉害的也可能阴差阳错就被淘汰了(比如因为站得太高被雷劈死的头狼?),比较差的也可能碰巧没被淘汰。

4.控制参数:我设置的是最多一百代,0.6的概率会交叉,0.006的概率会突变,这个突变必须控制在较低的范围,否则是无法完成进化的,因为选择了半天,留下了适应度很高的染色体,但是染色体突变率很高,执行突变时又全都给你变没了,又恢复到随机的一种情况之下,进化就相当于没有发生。

5.遗传算子:我这里有突变和交叉两个算子,突变是每一条染色体的每一个基因都有Pm的概率取反,交叉是随机设置交叉点,两个染色体有一定的概率发生交叉(单点交叉)。

  1 #include<iostream>
  2 #include<string>
  3 #include<time.h>
  4 #include<sstream>
  5 using namespace std;
  6
  7
  8 //种群总数
  9 const int popSize=100;
 10 //染色体长度
 11 const int chromosomeSize=6;
 12 //变异概率
 13 const double Pm=0.001;
 14 //最多代数
 15 const int MaxGen=100;
 16 //变异概率
 17 const double Pc=0.1;
 18
 19
 20
 21
 22
 23 //遗传个体类
 24 class individual
 25 {
 26 public:
 27     //个体目标值
 28     double ObjectValue;
 29     //个体适应值
 30     double FitValue;
 31     //染色体编码
 32     string Chromosome;
 33     //构造函数
 34     individual()
 35     {
 36         ObjectValue=0;
 37         FitValue=0;
 38         Chromosome="000000";
 39     }
 40 };
 41
 42 //进化处理类
 43 class Evaluation
 44 {
 45 private:
 46
 47     //种群
 48     individual Population[popSize];
 49     //进行选择
 50     void SelectPop();
 51     //进行变异
 52     void VaryPop();
 53     //进行杂交
 54     void CrossPop();
 55     //优化
 56     void OptimizePop();
 57     //初始化种群,随机构造一个群体
 58     void Initialization();
 59     //找出最优和最差及平均值
 60     void Statistics();
 61     //评价种群
 62     void EvaluatePop();
 63     //最好个体
 64     individual Best;
 65     //最坏个体
 66     individual Worst;
 67     //最坏个体下标
 68     int WorstIndex;
 69     //历史最佳
 70     individual HistoryBest;
 71     //平均值
 72     double avg;
 73
 74 public:
 75     //构造函数,调用初始化函数
 76     Evaluation();
 77     //产生下一代
 78     void NextPopulation();
 79     //打印
 80     void output();
 81     //代数
 82     int generation;
 83 };
 84
 85 //构造函数,调用初始化函数
 86 Evaluation::Evaluation()
 87 {
 88     Initialization();
 89     generation=0;
 90
 91 }
 92
 93 //初始化构造初始种群
 94 void Evaluation::Initialization()
 95 {
 96     //对染色体进行初始化设置,逐颗粒随机赋值
 97     char temp;
 98     int Index=0,bitIndex=0;
 99     for(;Index<popSize;Index++)
100     {
101         for(bitIndex=0;bitIndex<chromosomeSize;bitIndex++)
102         {
103             int r=rand()%2;
104             if (r==0)
105                 temp='0';
106             else
107                 temp='1';
108             Population[Index].Chromosome[bitIndex]=temp;
109         }
110     }
111     //初始化时设置历史最佳为第一个
112     HistoryBest=Population[0];
113     //调用目标值和适应值的初始化函数,评价种群
114     EvaluatePop();
115     Statistics();
116 }
117
118 //评价函数,就是用函数f(x1,x2)=x1^2+x2^2,因为是数值函数,所以适应值和目标值是一致的
119 void Evaluation::EvaluatePop()
120 {
121     string num1,num2;
122     int value1,value2;
123     int Index=0;
124     for(;Index<popSize;Index++)
125     {
126             num1=Population[Index].Chromosome.substr(0,3);
127             num2=Population[Index].Chromosome.substr(3,3);
128             //二进制转化为十进制
129             stringstream ss;
130             ss<<num1;
131             ss>>value1;
132             //清空缓冲区
133             ss.clear();
134             ss.str("");
135             ss<<num2;
136             ss>>value2;
137
138             int a,b,c;
139             a=value1/100;
140             b=(value1-a*100)/10;
141             c=value1-a*100-b*10;
142             value1=a*4+b*2+c;
143             a=value2/100;
144             b=(value2-a*100)/10;
145             c=value2-a*100-b*10;
146             value2=a*4+b*2+c;
147             //计算适应值和目标值
148             Population[Index].FitValue=value1*value1+value2*value2;
149             Population[Index].ObjectValue=value1*value1+value2*value2;
150     }
151 }
152
153 //生成下一代
154 void Evaluation::NextPopulation()
155 {
156     SelectPop();
157     VaryPop();
158     CrossPop();
159     EvaluatePop();
160     Statistics();
161     OptimizePop();
162     EvaluatePop();
163     Statistics();
164     generation++;
165 }
166
167 //选择算子,轮盘赌
168 void Evaluation::SelectPop()
169 {
170     double FitSum=0,selection[popSize];
171     individual newPopulation[popSize];
172     int index=0,popindex=0;
173     //求适应值的总和
174     for(;index<popSize;index++)
175     {
176         FitSum+=Population[index].FitValue;
177     }
178
179     //确定轮盘分布
180     for(index=0;index<popSize;index++)
181     {
182         selection[index]=Population[index].FitValue/FitSum;
183     }
184     for(index=1;index<popSize;index++)
185     {
186         selection[index]=selection[index]+selection[index-1];
187     }
188     //用轮盘进行随机选取,形成新的种群
189     for(popindex=0;popindex<popSize;popindex++)
190     {
191         double p=  (rand()%100);
192         p/=100;
193         index=0;
194         while(p>selection[index])
195             index++;
196         newPopulation[popindex]=Population[index];
197     }
198     //将刚产生的群体替换为系统的群体
199     for(index=0;index<popSize;index++)
200     {
201         Population[index]=newPopulation[index];
202     }
203
204 }
205
206 //杂交算子,随机选取交叉点
207 void Evaluation::CrossPop()
208 {
209     int Localtion;
210     int index=0;
211     string str1,str2,str3,str4;
212     //打乱顺序
213     for(;index<popSize;index++)
214     {
215         individual temp;
216         int r=rand()%popSize;
217         temp=Population[index];
218         Population[index]=Population[r];
219         Population[r]=temp;
220     }
221     //随机选取交叉点,将染色体分裂,然后交叉,得到新的染色体
222     for(index=0;index<popSize;index+=2)
223     {
224         double temp=rand()%1000/1000.0;
225         if(temp<Pc)
226         {
227             Localtion=rand()%chromosomeSize;
228             str1=Population[index].Chromosome.substr(0,Localtion);
229             str2=Population[index].Chromosome.substr(Localtion);
230             str3=Population[index+1].Chromosome.substr(0,Localtion);
231             str4=Population[index+1].Chromosome.substr(Localtion);
232             Population[index].Chromosome=str1+str4;
233             Population[index+1].Chromosome=str3+str2;
234         }
235     }
236 }
237
238 //变异算子,对所有染色体每一位的随机位置以变异概率进行变异
239 void Evaluation::VaryPop()
240 {
241     int index=0,bitindex=0;
242     string str1="0";
243     string str2="1";
244
245     for(;index<popSize;index++)
246     {
247         for(bitindex=0;bitindex<chromosomeSize;bitindex++)
248         {
249             double r=rand()%1000;
250             r/=1000;
251             if(r<Pm)
252             {
253                 if(Population[index].Chromosome[bitindex]==str1[0])
254                     Population[index].Chromosome[bitindex]=str2[0];
255                 else
256                     Population[index].Chromosome[bitindex]=str1[0];
257             }
258         }
259     }
260 }
261
262 //优化
263 void Evaluation::OptimizePop()
264 {
265         Population[WorstIndex] = HistoryBest;
266 }
267
268 //统计
269 void Evaluation::Statistics()
270 {
271     Best=Population[0];
272     Worst=Population[0];
273     int index=0;
274     double sum=0;
275     for(;index<popSize;index++)
276     {
277         if(Best.FitValue<Population[index].FitValue)
278             Best=Population[index];
279         if(Worst.FitValue>Population[index].FitValue)
280         {
281             Worst=Population[index];
282             WorstIndex=index;
283         }
284         sum+=Population[index].FitValue;
285     }
286     if(HistoryBest.FitValue<Best.FitValue)
287         HistoryBest=Best;
288     avg=sum/popSize;
289
290 }
291
292
293 //输出文本
294 void Evaluation::output()
295 {
296     cout<<"Generation:"<<generation<<"   Average:"<<avg<<"   Best:"<<Best.FitValue<<"  Chromosome"<<Best.Chromosome<<endl;
297 }
298
299
300 int main()
301 {
302     Evaluation eva;
303     eva.output();
304     while(eva.generation<MaxGen)
305     {
306         eva.NextPopulation();
307         eva.output();
308     }
309
310
311 }

结果:

    写完这个小程序之后我就在思考选择,交叉,突变的意义是什么,目前的想法是这样:选择的目的是在当前种群中寻求当前最优的,只考虑现状,留下来的趋向于当前群体的最优,但是是不是整体最优是未知的,所以又引入了交叉和突变。

    交叉可以让优质基因和劣质基因在种群中变得更加均匀,方便于选择(就是留下好的去除坏的,因为好的和坏的都可能因此显得更加突出了,而平庸的在选择中并没有优势),同时也会产生新的个体。

    而变异就是为了产生新个体才引入的,事实上我觉得他会降低选择的速度,因为选择出的好的个体经过突变很可能就没有之前那么好了,但是引入新的个体的意义是显然的,这可以避免局部最优。

为了更好的说明,我们走两个极端,一是只选择不变异不交叉,很快这个种群就会被目前最好的个体占据,二是选择交叉,百分百变异,那么得到的群体几乎就是一个全新的群体了,选择已经失去了留下优质基因淘汰劣质基因的能力因为很快又会到原点,选了半天和没选一样。所以我目前认为选择是为了获得局部最优,交叉和变异是为了一定程度上扩充这个群体的基因库,努力向全局最优靠近,交叉和突变都会降低选择的速度,因为被选择留下的个体发生了变化。

附上不同变异概率的进化结果:

Pm=0

Pm=0.001

Pm=0.01

Pm=0.1

Pm=0.3

0.01以下的还算是进化了,但是随着Pm的增大,进化到最优的状态需要的代数也越来越多(即进化速度变慢了),0.1之后的基本上已经陷入无序的状态,选择已经没有用了。

改变了Pc(交叉概率),没有什么太大的影响。

下周的话尽量了解其他的编码方式,并尝试不同的选择策略,本次总结就到此为止。

时间:2016/10/22

转载于:https://www.cnblogs.com/liyuwang/p/5988358.html

演化计算简单实例(附代码)相关推荐

  1. VC++6.0 win32 控制台应用程序 简单应用 附代码

    **VC++6.0 win32 控制台应用程序 简单应用 附代码 ** .cpp 文件名 注意:在源文件添加如下声明: #include //没有.h using namespace std;//使用 ...

  2. Python科学绘图实例附代码

    Python绘图精简实例附代码 作者:金良(golden1314521@gmail.com) csdn博客:http://blog.csdn.net/u012176591 Python绘图精简实例附代 ...

  3. 从实例一步一步入门学习SpringCloud的Eureka、Ribbon、Feign、熔断器、Zuul的简单使用(附代码下载)

    场景 SpringCloud -创建统一的依赖管理: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/102530574 Sprin ...

  4. OpenCV Lucas-Kanade光流计算的实例(附完整代码)

    OpenCV Lucas-Kanade光流计算的实例 OpenCV Lucas-Kanade光流计算的实例 OpenCV Lucas-Kanade光流计算的实例 #include <iostre ...

  5. matlab watershed函数简单实现_函数指针方法实现简单状态机(附代码)

    之前写过一篇状态机的实用文章,很多朋友说有几个地方有点难度不易理解,今天给大家换种简单写法,使用函数指针的方法实现状态机. 状态机简介 有限状态机FSM是有限个状态及在这些状态之间的转移和动作等行为的 ...

  6. 用浏览器做人脸检测,竟然这么简单?(附代码)

    1.背景与场景 人脸检测(Face Detection)算是老生常谈的课题了,在诸多行业应用广泛,例如金融.安防.电子商务.智能手机.娱乐图片等行业.其中涉及的技术也在不断的演变,下面简要介绍几种思路 ...

  7. 神秘指标一出现,市场立马就变天 | 用Python计算成交量集中度(附代码)【邢不行】

    引言: 邢不行的系列帖子"量化小讲堂",通过实际案例教初学者使用python进行量化投资,了解行业研究方向,希望能对大家有帮助 01 某神秘指标 有这么一个神秘指标,虽然15年来只 ...

  8. 基于c++的马氏距离算法代码_监控警戒区基于掩码算法的简单实现(附代码)

    视频地址:https://www.ixigua.com/6870543177913205251/ 这是利用图片掩码实现的一个视频监控区域警戒功能代码,当人进出警戒区域时,自动记录一张图片到本地,效果视 ...

  9. PHP字符串运算结果,PHP 实现后缀表达式(接受四则运算字符串,输出计算结果,附代码)...

    最近接触了一个有趣的需求:给定变量a.b.c.d等若干,要求由用户输入的普通四则运算字符串(包含加减乘除括号),算出具体的值. 例如,a=1,b=2,c=3,d=4,给出 a+b/(d-c),应计算出 ...

最新文章

  1. (C++)A+B 输入输出练习VII 输入包含若干行,每行输入两个整数a和b,由空格分隔。 对于每组输入,输出a和b的和,每行输出后接一个空行。
  2. php项目从本地apache移到linux的nginx上,遇到的一些访问权限和报错的问题。
  3. 通过简单的Linux命令,编译一个C语言代码
  4. [log4j]log4j简单配置
  5. [转]状态压缩dp(状压dp)
  6. shell自定义数组元素分隔符
  7. Android单元测试(七):Robolectric,在JVM上调用安卓的类
  8. linux下proc文件的读写(部分转载)
  9. 使用 Iperf 测试软路由性能
  10. 阿里架构师墙裂推荐Java岗实战文档:Spring全家桶+Docker+Redis
  11. linux 目录配额,详细讲解linux磁盘配额之Quota命令
  12. 【我是老中医】codeblocks无法编译的问题解决方法
  13. 汇总病毒样本的常用反调试技术、反分析技巧(持续更新)
  14. 黑客电影《我是谁:没有绝对安全的系统》正片(含下载)
  15. oracle linux下开放1521端口
  16. 【python】-- paramiko、跳板机(堡垒机)
  17. 仓储管理之计价方法——毛利率法、零售价法【售价金额核算法】、计划成本法
  18. OpenCV图像处理(十一)---图像梯度
  19. 计算机专业英语 unit 5 fundamentals,计算机专业英语Unit 5
  20. IPguard服务器无法启动排查

热门文章

  1. WPF 提供了以下关键帧动画类[msdn]
  2. 通过SQL存储过程删除过期的数据库Bak备份文件
  3. 无法安装或运行应用程序。该应用程序要求首先在“全局程序集缓存(gac)”中安装程序集system.data.entity...
  4. Git命令家底儿及Git数据通信原理详解
  5. 《电子基础与维修工具核心教程》——1.3 弱电、强电、高压电
  6. java多线程实现方法
  7. Linux程序包管理,YUM命令使用解析。
  8. union-find算法分析(2)
  9. 暴汗,今天遇到个奇事
  10. 洛谷1020导弹拦截