最近在學習有關遺傳算法和神經網絡方面的知識,網上查看了很多這方面的祕笈,只怪小生天生愚鈍、才疏學淺,不能很好的領悟祕笈中的真諦,往往被弄得暈頭轉向、不知所措。直到有一天無意中看到了博主zzwu寫的有關這方面的文章,初讀之,如溫舊習;漸深入,覺甚好;遂一氣呵成,猶如撥雲見日、茅塞頓開。餘甚怕在茫茫Internet中再無機會拜讀之,遂收藏於此,以便衆人觀之,絕無其他不良用途。在此對博主再次深表感謝。
博文轉自:http://blog.csdn.net/zzwu/article/details/561625
.
(連載之六)
.
扎自<遊戲編程中的人工智能技術>第三章
清華大學出版社
(本章由zzwu譯)
3.4.1爲染色體編碼
(Ecoding the Chromosome)
每個染色體必須把小人Bob 的每一個行動編入代碼中。Bob的行動僅限爲4個方向: 向東(East),向南(South),向西(West),向北(North) 故編碼後的染色體應該就是代表這4個方向信息的一個字符串。傳統的編碼方法就是把方 向變換成二進制的代碼。四個方向只要2位就夠了,例如下表所示的那樣:
二進制代碼 | 十進制譯碼 | 代表的方向 |
00 | 0 | 向北 |
01 | 1 | 向南 |
10 | 2 | 向東 |
11 | 3 | 向西 |
這樣,如果你得到了一個隨機的二進制字符串,你就能將它譯碼出Bob行動時所遵循的
一系列方向。例如染色體:
111110011011101110010101
代表的基因就是:
11,11,10,01,10,11,10,11,10,01,01,01
當把二進制代碼譯成十進制時,就成爲
3,3,2,1,2,3,2,3,2,1,1,1
再把這些放進一個表格中,就可以使你相信這是一樣的一些概念:
二進制代碼 | 十進制譯碼 | 代表的方向 |
11 | 3 | West |
11 | 3 | West |
10 | 2 | East |
01 | 1 | South |
10 | 2 | East |
11 | 3 | West |
10 | 2 | East |
11 | 3 | West |
10 | 2 | East |
01 | 1 | South |
01 | 1 | South |
01 | 1 | South |
到此,你要做的全部就是將Bob置於迷宮的起點,然後告訴他根據這張表所列的方向一步步地走。如果按某一個方向前進將使Bob碰到牆壁或障礙物,則只需忽略該方向並繼續按下一個方向去走就行了。這樣不斷下去,直到所有方向用光或Bob到達出口時爲止。
如果你想象有幾百個這樣的隨機的染色體,你就能看到它們中的某些可能爲Bob譯碼出到達出口的一套方向(問題的一個解),但它們中的大多數將是失敗的。
遺傳算法以隨機的2進制串(染色體)作爲初始羣體,測試它們每一個能讓Bob走到離開出口有多麼接近,然後讓其中最好的那些來孵化後代,期望它們的子孫中能有比Bob走得離出口更近一點。這樣繼續下去,直到找出一個解,或直到Bob絕望地在一個角落裏被粘住不動爲止(你將看到,這種情況是可能發生的)。
因此,我們應定義一種結構,其中包含一個2進制位串(染色體),以及一個與該染色體相聯繫的適應性分數。我把這個結構稱爲SGenome結構,它的定義如下:
並將其適應性分數初始化爲零,這樣就把基因組什麼都準備好了。
程序註釋
std::vector是STL(Standard Templete Library)標準模板庫的一部分, 這是一種爲處理動態數組而預先建立好的類。如果要把數據加入STL中,可使用
push_back()方法。
下面是一個簡單的例子:
MyFirstVector.clear();
你可利用size()方法來得到向量中元素的數目:
NyFirstVector.size()
就是這樣。
不需要你去考慮內存管理問題-std::vector能夠爲你來做所有這些!當需要時,我會在整個程序中使用它。
SGenome結構中不具備怎樣爲染色體(vecBits)進行譯碼的知識; 這是需要由遺傳算法類自己來完成的一項任務。現在讓我們來快速窺視一下這個類的定義。
我已把它稱作CgaBob類(有時我對我的原始創見自己也很喫驚,但我確實是這樣做的)。
由上你可看出,當這個類的一個實例被創建時,構造函數初始化所有的變量,並調用CreateStartPopulation()。這一短小函數創建了所需數量的基因組羣體。
每個基因組一開始包含的是一個由隨機2進制位串組成的染色體,其適應性分數則被設置爲零。
-連載6完-