基於實數編碼(離散雜交+自適應變異),線性排名選擇的遺傳算法(附代碼)


 

版權聲明:本文為博主原創文章,轉載請注明出處。

 

我們來看一個很簡單的小問題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函數定義一個大小,那么會初始化這個大小的空間,然后就可以隨便使用了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM