縮水版遺傳算法 學習筆記

遺傳算法是在隨機的初始數據下,經過一段時間的變化,最後收斂得到針對某類特定問題的一個或者多個解。

主要步驟有編碼 選擇 交叉 變異

這裏以一個極其簡單的探索迷宮出路的代碼爲例 增加對遺傳算法的感性認識。

 

編碼 
2,3,4,1,1,1,1,1,1,1,1,1,1,1,1, 
1,8,1,0,0,0,0,0,0,0,1,0,0,1,1,
1,0,1,0,1,0,1,1,1,0,0,0,0,0,1,
1,0,1,0,1,0,1,1,1,1,0,1,0,1,1,
1,0,0,0,1,0,0,0,0,0,0,1,0,5,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

我們定義這樣一個迷宮 
1表示爲不可到達地點 
0表示可通過區域
5是起點 8是終點
我們再定義一系列行走出迷宮的行走方向數組 walk[TestStep](walk[50]).這個數組記錄了走50步的方向
方向使用0-3來代替 0 表示向上走,1表示向下走,2表示向左走,3表示向右走。然後測試這一系列走法在迷宮能達到的座標,以達到的位置和終點的X\Y的差值的倒數作爲這個走法的評分
price = 1/(1.0+(abs(exitIndex.x-vMethods[i].currentPosIndex.x)+abs(exitIndex.y-vMethods[i].currentPosIndex.y)));

考慮到X\Y的差值可能爲零,所以額外加了一個1.0;以上就是編碼的步驟;

 


選擇

作爲進化演變下一代的元素,我們需要選擇評分比較高的走法

通常的辦法是輪盤賭選擇 根據評分的高低 決定其被選中的機率

 

各個個體被選中的概率與其適應度函數值大小成正比。設羣體大小爲n ,個體i 的適應度爲 Fi,則個體i 被選中遺傳到下一代羣體的概率爲:

比如說

走法A 評分0.5

走法B 評分0.2

走法C 評分0.3

那麼根據一個隨機範圍爲0-99的隨機數

如果數目在0-49之間 則選擇走法A

如果數目在50-69之間則選擇走法B

如果數目在70-99之間則選擇走法C

我的代碼中 寫的比較簡單 直接選擇評分在前一半的作爲進化演變的元素

int index1 = rand()%(TrySize/2);

int index2 = rand()%(TrySize/2);

缺點是可能逐步演化中 族羣的走法都慢慢接近 甚至編程一樣 從未導致沒有變化 得不到正確結果

優點是 代碼簡單

 

 

交叉

2個元素交換部分結構,來構造下一代新的元素

例如

走法A 01230123 0123

走法B 12301230 1230

構造下一代走法

01230123 1230

代碼中爲

Method m = CrossOver(vMethods[index1],vMethods[index2]);

 

 

突變

對元素數據進行小概率的調整 以調整進化的集中性 避免所有元素同一化

代碼中是以25%的概率 對某一步的走法進行調整

if((rand()%100)>75)

{

int index = rand()%TestStep;

 m.walk[index] = direction(rand()%4);

}

本節代碼屬於實驗性代碼 對具體參數和一些算法都做了簡化 只是加深對算法的理解 方便入門

至於算法的選擇 參數優化調整的理論依據 均未涉及 需要學習理論教程書籍

代碼如下

複製代碼
  1 #include <iostream>
  2 #include <ctime>
  3 #include <cstdlib>
  4 #include <vector>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 int mapArray[6][15] = { 2,3,4,1,1,1,1,1,1,1,1,1,1,1,1,
 10                         1,8,1,0,0,0,0,0,0,0,1,0,0,1,1,
 11                         1,0,1,0,1,0,1,1,1,0,0,0,0,0,1,
 12                         1,0,1,0,1,0,1,1,1,1,0,1,0,1,1,
 13                         1,0,0,0,1,0,0,0,0,0,0,1,0,5,1,
 14                         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 15 struct Point{
 16     int x;
 17     int y;
 18 };
 19 
 20 Point startIndex = {4,13};
 21 Point exitIndex = {1,1};
 22 
 23 enum direction{
 24     Mup =0,
 25     Mdown ,
 26     Mleft ,
 27     Mright };
 28 
 29 #define TestStep    50
 30 #define TrySize     50
 31 
 32 
 33 struct Method{
 34     direction walk[TestStep];
 35     Point   currentPosIndex;
 36     double price;
 37 };
 38 
 39 vector<Method> vMethods;
 40 vector<Method> vNewMethods;
 41 
 42 
 43 bool SortByPrice(const Method& obj1,const Method& obj2)
 44 {
 45     return obj1.price>obj2.price;
 46 }
 47 
 48 void InitRandomWalk(direction walk[]){
 49     for(int i = 0;i< TestStep;++i){
 50         walk[i] = direction(rand()%4);
 51     }
 52 }
 53 
 54 bool Walk(Point& currentPosIndex,direction walk[],int length){
 55     for(int i = 0;i< TestStep;++i){
 56         if(walk[i] == Mup){
 57             if( (currentPosIndex.x-1)>=0 &&
 58                mapArray[currentPosIndex.x-1][currentPosIndex.y] != 1){
 59                 currentPosIndex.x -= 1;
 60             }
 61         }else if(walk[i] == Mdown){
 62             if( (currentPosIndex.x+1)<=5 &&
 63                mapArray[currentPosIndex.x+1][currentPosIndex.y] != 1){
 64                 currentPosIndex.x += 1;
 65             }
 66         }else if(walk[i] == Mleft){
 67             if( (currentPosIndex.y-1)>=0 &&
 68                mapArray[currentPosIndex.x][currentPosIndex.y-1] != 1){
 69                 currentPosIndex.y -= 1;
 70             }
 71         }else if(walk[i] == Mright){
 72             if( (currentPosIndex.y+1)<=14 &&
 73                mapArray[currentPosIndex.x][currentPosIndex.y+1] != 1){
 74                 currentPosIndex.y += 1;
 75             }
 76         }
 77         if(currentPosIndex.x == exitIndex.x && currentPosIndex.y == exitIndex.y){
 78             return true;
 79         }
 80     }
 81 
 82     return false;
 83 }
 84 
 85 Method CrossOver(const Method& m1,const Method& m2){
 86     int i = rand()%TestStep;
 87     Method m;
 88 
 89     for(int j = 0; j <= i ;++j){
 90         m.walk[j] = m1.walk[j];
 91     }
 92 
 93     for(int k =i;k < TestStep;++k){
 94         m.walk[k] = m2.walk[k];
 95     }
 96     return m;
 97 }
 98 
 99 bool run(){
100 
101     for(int i = 0;i < TrySize;++i){
102        vMethods[i].currentPosIndex.x = startIndex.x;
103        vMethods[i].currentPosIndex.y = startIndex.y;
104        if(Walk(vMethods[i].currentPosIndex, vMethods[i].walk,TestStep)){
105            cout << "walk to exit!!!" << endl;
106            return true;
107        }
108        vMethods[i].price = 1/(1.0+(abs(exitIndex.x-vMethods[i].currentPosIndex.x)+abs(exitIndex.y-vMethods[i].currentPosIndex.y)));
109        cout << "current pos:\t" << vMethods[i].currentPosIndex.x <<" " << vMethods[i].currentPosIndex.y <<"\tprice:"<< vMethods[i].price<< endl;
110     }
111 
112     sort(vMethods.begin(),vMethods.end(),SortByPrice);
113     for(int i = 0 ; i <TrySize;i++){
114         int index1 = rand()%(TrySize/2);
115         int index2 = rand()%(TrySize/2);
116 
117 //        for(int k = 0 ;k<TestStep;++k){
118 //            cout << vMethods[index1].walk[k];
119 //        }
120 //        cout << endl;
121 
122       Method m = CrossOver(vMethods[index1],vMethods[index2]);
123        if((rand()%100)>75)
124        {
125            int index = rand()%TestStep;
126            m.walk[index] = direction(rand()%4);
127 
128        }
129        vNewMethods.push_back(m);
130 //        for(int k = 0 ;k<TestStep;++k){
131 //            cout << vMethods[index1].walk[k];
132 //        }
133 //        cout << endl;
134     }
135     vMethods = vNewMethods;
136     vNewMethods.clear();
137     return false;
138 }
139 
140 
141 
142 
143 
144 int main(int argc, char *argv[])
145 {
146     vMethods.clear();
147     srand( (unsigned)time( NULL ) );
148     for(int i = 0;i < TrySize;++i){
149         Method m;
150         InitRandomWalk( m.walk);
151         vMethods.push_back(m);
152     }
153 
154     int64_t count = 0;
155     while(!run()){
156         count++;
157     }
158     cout << "run " << count << " times." << endl;
159 
160 
161     return 0;
162 }
複製代碼

 

 

 

 

 

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章