基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)

 

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

 

我们来看一个很简单的小问题f=x1+x2+x3+x4,x1、x2、x3、x4是大于等于10小于等于100的实数,求f的最大值。

这个小学生就能解决的问题我今天打算用遗传算法来解决,你可能说这不是智障吗?但是其实这只是一个小例子,因为用同样的方法,你可以解决f=x1^x2*x3^x4/x2^x1*x4^x3甚至是更复杂的问题,下面就来详细讲一讲。

基于对遗传算法的一般性了解,我就不再赘述详细过程(其实是因为上一篇写过了懒得再写一遍),只谈谈实数编码和线性排名选择策略。

实数编码顾名思义就是用实数进行编码,实数来做染色体的基因,实数构成染色体,他的本质其实是用问题的一个解空间来做一个染色体,比如{20.5658.15.2385,89.0000,56.4400},就是上面小问题的一个解空间,就可以把它作为一个染色体用于进化,其中的每一个x1,x2都是一个基因,那些交叉,变异都是基于这样的设定的。

在这里插一句,实数编码和整数编码的思想是极为类似的,但是实数编码的解空间更大更复杂。

现在来讲讲实数编码的交叉和变异

1、交叉

实数编码的杂交方式有离散杂交,算数杂交等等,本例只讲解离散杂交。

离散杂交和二进制的杂交是十分类似的,(可以)选定一个基因位,然后将选定的两个染色体在这个位置之后的基因进行交换(注意基因的定义区间是不变的)。

注意,在实数编码中,交叉的作用不是很大。

2、变异

实数编码的变异包括均匀性变异、正态性变异、非一致性变异、自适应变异、多级变异等,本例只讲解自适应变异和非一致性变异。

(1)非一致性变异

在传统的遗传算法中,突变的情况是与代数无关的。但是进化刚开始时,就是需要向各个方向大步发展进行尝试,进化到了后期,解已经相对较优了,进行局部搜索可能更有利于找到更好的解。显然传统的方法是不行的,必须找到一种将变异幅度和代数相联系的策略。

所以给出如下方法:s={v1,v2,v3,v4……},vk被选中进行变异,它的定义区间为{ak,bk},

vk1=vk+h(t,bk-vk);  vk2=vk-h(t,vk-ak);

(t为代数,h(t,y)=y*(1-r^(1-t/T)^p),r是0~1的随机数,T为最大代数,p式一个参数,一般取值为2~5)

新的vk随机在vk1和vk2中进行选取,这样就实现了之前提出要求。

(2)自适应性变异

非一致性变异加强了局部搜索能力,但是与解的好坏无关,但是我们可能希望的是好的解搜索范围较小,坏的解搜索范围较大这样,所以在非一致性变异上进行一些修正。

我们只需要将h(t,y)中的t换为T,T是一个与解的质量有关的数,

T=1-f(s)/fmax

f(s)是某个体的适应值,fmax是所解问题的最优结果,当然fmax不太好确定,所以找一个近似替代就可以了,比如当代最优解或是历史最优解。

3、线性排名选择策略

基于适应值比例的算法(轮盘赌、繁殖池)比较容易陷入过早收敛和停滞现象,排名选择策略可以避免这个问题。

我们只介绍线性排名选择策略。

顾名思义,排名策略嘛,就是要所有的解按照适应值进行排排坐,各自都有一个排名,然后我们按照大家的排名制定一个被选中的概率(然后根据这个概率进行轮盘赌),这就避免了某些个体很多就可以在轮盘赌中获得很大优势,变成了强的更有机会,但是弱者的生存机会也没被剥夺。

被选中的概率为pi=(a-b/(n+1))/n,n为排名,a,b有个一般取值,1≤a≤2,一般取1.1,b=2a-2.

 

接下来是代码部分。

  1 #include <iostream>
  2 #include <string>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <math.h>
  6 using namespace std;
  7 
  8 
  9 //种群总数
 10 const int popSize=1000;
 11 //执行代数
 12 const int maxGen=200; 
 13 //染色体长度
 14 const int chromSize=4;
 15 //交叉概率
 16 const double Pc=0.7;
 17 //变异概率
 18 const double Pm=0.3;
 19 //线性排名选择参数1
 20 const double Pa=1.1;
 21 //线性排名选择参数2
 22 const double Pb=0.2;
 23 //变量定义上限
 24 const double up=100;
 25 //变量定义下限
 26 const double down=10;
 27 
 28 
 29 
 30 //遗传个体类
 31 class indivadual
 32 {
 33 public:
 34     //构造函数
 35     void indivadula(){};
 36     //染色体
 37     vector<double> chrom;
 38     //目标值
 39     double objectValue;
 40     //适应值
 41     double fitValue;
 42 };
 43 
 44 
 45 //进化处理类
 46 class Evalution
 47 {
 48 private:
 49     //种群
 50     vector <indivadual> Population;
 51     //最好个体
 52     indivadual Best;
 53     //最好个体下标
 54     int BestIndex;
 55     //最坏个体
 56     indivadual Worst;
 57     //最坏个体下标
 58     int WorstIndex;
 59     //历史最佳
 60     indivadual HistoryBest;
 61     //平均适应值
 62     double Avg;
 63     //初始化种群
 64     void Initialization();
 65     //选择算子
 66     void SeletPop();
 67     //交叉算子
 68     void CrossPop();
 69     //变异算子
 70     void VaryPop();
 71     //优化
 72     void OptimizePop();
 73     //排序辅助函数
 74     //bool compare(indivadual a,indivadual b);
 75 public:
 76     //构造函数,调用初始化函数
 77      Evalution();
 78     //评价函数
 79      void Evaluate();
 80     //生成下一代函数
 81     void NextPopulation();
 82     //输出
 83     void OutPut();
 84     //代数
 85     int gen;
 86 };
 87 
 88 Evalution::Evalution()
 89 {
 90     Initialization();
 91 }
 92 
 93 //初始化种群
 94 void Evalution::Initialization()
 95 {
 96     int i=0,j=0;
 97     Population.resize(popSize);
 98     for(i=0;i<popSize;i++)
 99     {
100         Population[i].chrom.resize(chromSize);
101         for(j=0;j<chromSize;j++)
102         {
103             //随机值范围为10-100
104             double r=(rand()%9000)/100.0+10.01;
105             Population[i].chrom[j]=r;
106         }
107     }
108     Best=Population[0];
109     Best.fitValue=0;
110     Worst=Population[0];
111     Worst.fitValue=1000;
112     BestIndex=0;
113     WorstIndex=0;
114     gen=0;
115     Avg=0;
116 }
117 
118 //评价适应值,目标值,最好个体,最坏个体,历史最佳个体 
119 void Evalution::Evaluate()
120 {
121     
122     int i=0,j=0;
123     vector<double> value;
124     value.resize(chromSize);
125     for(i=0;i<popSize;i++)
126     {
127         for (j=0;j<chromSize;j++)
128         {
129             value[j]=Population[i].chrom[j];
130         }
131         //评估函数为f=(a/b+c/d)/(b/a+d/c);
132         //Population[i].objectValue=Population[i].fitValue=(value[0]/value[1]+value[2]/value[3])/(value[1]/value[0]+value[3]/value[2]);
133         //评估函数为f=a+b+c+d
134         Population[i].objectValue=Population[i].fitValue=value[0]+value[1]+value[2]+value[3];
135         if (Population[i].fitValue>Best.fitValue)
136         {
137             Best=Population[i];
138             BestIndex=i;
139         }
140         if (Population[i].fitValue<Worst.fitValue)
141         {
142             Worst=Population[i];
143             WorstIndex=i;
144         }
145     }
146     if (Best.fitValue>HistoryBest.fitValue)
147     {
148         HistoryBest=Best;
149     }
150     for (i=0;i<popSize;i++)
151     {
152         Avg+=Population[i].fitValue;
153     }
154     Avg/=popSize;
155 }
156 
157 
158 //生成新一代个体
159 void Evalution::NextPopulation()
160 {
161     SeletPop();
162     CrossPop();
163     VaryPop();
164     Evaluate();
165     OptimizePop();
166 }
167 
168 //输出
169 void Evalution::OutPut()
170 {
171     cout<<"当前代数"<<++gen<<"   平均值"<<Avg<<"   最好个体适应值"<<Best.fitValue<<"最好个体基因";
172     int i=0;
173     for (i=0;i<chromSize;i++)
174     {
175         cout<<Best.chrom[i]<<"  ";
176     }
177     cout<<endl;
178 }
179 
180 //sort函数的辅助函数
181 bool compare(indivadual a,indivadual b)
182 {
183     if (a.fitValue>b.fitValue)
184     {
185         return true;
186     }
187     if (a.fitValue>b.fitValue)
188     {
189         return false;
190     }
191     return false;
192 }
193 
194 //线性排名选择
195 void Evalution::SeletPop()
196 {
197     sort(Population.begin(),Population.end(),compare);
198     double p[popSize],selection[popSize];
199     indivadual newPopulation[popSize];
200     double FitSum=0;
201     int i=0,j=0,index=0,popindex=0;
202     //计算分配概率
203     for (i=0;i<popSize;i++)
204     {
205         j=i+1;
206         p[i]=(Pa-Pb/(j+1))/j;
207     }
208     //求分配概率的总和
209     for(index=0;index<popSize;index++)
210     {
211         FitSum+=p[index];
212     }
213 
214     //确定轮盘分布
215     for(index=0;index<popSize;index++)
216     {
217         selection[index]=p[index]/FitSum;
218     }
219     for(index=1;index<popSize;index++)
220     {
221         selection[index]=selection[index]+selection[index-1];
222     }
223     //用轮盘进行随机选取,形成新的种群
224     for(popindex=0;popindex<popSize;popindex++)
225     {
226         double n=  (rand()%100)/100.0;
227         index=0;
228         while(n>selection[index])
229             index++;
230         newPopulation[popindex]=Population[index];
231     }
232     //将刚产生的群体替换为系统的群体
233     for(index=0;index<popSize;index++)
234     {
235         Population[index]=newPopulation[index];
236     }
237 }
238 
239 
240 
241 
242 //杂交算子,离散杂交
243 void Evalution::CrossPop()
244 {
245     int index=0,position=0,i=0,temp=0,t=0;
246     for(;index<popSize;index++)
247     {
248         indivadual temp;
249         int r=rand()%popSize;
250         temp=Population[index];
251         Population[index]=Population[r];
252         Population[r]=temp;
253     }
254     for(index=0;index<popSize;index+=2)
255     {
256         t=rand()%1000/1000.0;
257         if (t<Pc)
258         {
259              position=rand()%chromSize;
260              for (i=position+1;i<chromSize;i++)
261              {
262                  temp=Population[index+1].chrom[i];
263                  Population[index+1].chrom[i]=Population[index].chrom[i];
264                  Population[index].chrom[i]=temp;
265 
266              }
267 
268         }
269 
270     }
271 }
272 
273 
274 //变异算子,自适应性变异
275 void Evalution::VaryPop()
276 {
277     int i=0,j=0;
278     for (i=0;i<popSize;i++)
279     {
280         for (j=0;j<chromSize;j++)
281         {
282             double r=rand()%1000/1000.0;
283             if (r<Pm)
284             {
285                 double t=1-Population[i].fitValue*0.9999/Best.fitValue;
286                 //突变区间
287                 double u=(1-pow(r,pow(t,2)))*(up-Population[i].chrom[j]);
288                 if (u>up)
289                 {
290                     u=up;
291                 }
292                 if (u<down)
293                 {
294                     u=down;
295                 }
296                 double l=(1-pow(r,pow(t,2)))*(Population[i].chrom[j]-down);
297                 if (l>up)
298                 {
299                     l=up;
300                 }
301                 if (l<down)
302                 {
303                     l=down;
304                 }
305 
306                 int p=rand()%2;
307                 if (p==0)
308                 {
309                     Population[i].chrom[j]=u;
310                 }
311                 else
312                     Population[i].chrom[j]=l;
313             }
314         }
315     }
316 }
317 
318 //优化
319 void Evalution::OptimizePop()
320 {
321      Population[WorstIndex] = HistoryBest;  
322 }
323 
324 int main()
325 {
326     Evalution eva;
327     eva.Evaluate();
328     eva.OutPut();
329     while(eva.gen<maxGen)
330     {
331         eva.NextPopulation();
332         eva.Evaluate();
333         eva.OutPut();
334     }
335 }

这个代码中是有个问题的,就是优化函数的策略是把历史最佳替代当代最差,这个可能会容易陷入局部最优。目前想到的更好的策略是如果连续三代的历史最佳都不变,就对历史最佳以一个很小的概率进行突变。

附上这个代码的结果:

《基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)》

是不是觉得有点问题?这个结果不是最优结果啊,最优的结果明明是100,100,100,100,这个结果和最终的结果差距还是比较大的。

这个结果其实某种程度的体现了遗传算法的根本目的:遗传算法的目的通过一系列操作最终得到在适应值上更高的群体,而不是为了求最优而存在的,它是一种近似最优的算法,而这个近似的程度和种群的规模,进化的代数,进化的策略都是有关的,所以不能强求通过遗传算法非要得到最优解。对于实数编码来讲,解空间的范围实在是非常大,也就是说进化的方向是非常多的,在这个情况下,突变可能已经很难产生新的有利基因了,也就是说算法收敛了,当然这是可以通过算法进行调节的,但是收敛到了什么程度,也是比较难以判断。

附上不同规模的结果(大规模的遗传算法非常耗时):

popsize=100

《基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)》

popsize=500

《基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)》

popsize=1000

《基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)》

popsize=5000

《基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)》

popsize=10000

《基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)》

可以看出种群数量对于最终结果的影响是比较大的。

ps.然后说点vector,如果想不初始化就用,就用resize函数定义一个大小,那么会初始化这个大小的空间,然后就可以随便使用了。

    原文作者:darkmoon233
    原文地址: https://www.cnblogs.com/liyuwang/p/6012712.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞