作者:zzwu 来源:CSDN博客   酷勤网收集 2007-09-20

摘要
  每个染色体必须把小人Bob 的每一个行动编入代码中。Bob的行动仅限为4个方向: 向东(East),向南(South),向西(West),向北(North) 故编码后的染色体应该就是代表这4个方向信息的一个字符串。传统的编码方法就是把方向变换成二进制的代码。

扎自<游戏编程中的人工智能技术>
第三章清华大学出版社(本章由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结构,它的定义如下:   

struct SGenome 
{    
 vector <int>  vecBits;    
 double   dFitness;    
 SGenome():dFitness(0){}    
 SGenome(const int num_bits):dFitness(0)    
 {//创造随机二进制位串      
  for (int i=0; i<num_bits; ++i)        
  {           
   vecBits.push_back(RandInt(0,1));        
  }    
 } 
}; 

正如你能见到的那样,如果你在创建Sgenome对象时把一个整型数作为参数传递给构造函数,则它就会自动创建一个以此整数为长度的随机2进制位串,并将其适应性分数初始化为零,这样就把基因组什么都准备好了。

程序注释   
  std::vector是STL(Standard Templete Library)标准模板库的一部分, 这是一种为处理动态数组而预先建立好的类。如果要把数据加入STL中,可使用push_back()方法。

下面是一个简单的例子:

#include <vector> 
for (int i=0; i<10; i++)   
{       
 MyFirstVector.push_back(i);
 cout << endl << MyFirstVector[i];   
}     

要清空一个向量,使用clear()方法:MyFirstVector.clear(); 
你可利用size()方法来得到向量中元素的数目: NyFirstVector.size()  就是这样。
不需要你去考虑内存管理问题-std::vector能够为你来做所有这些!

当需要时,我会在整个程序中使用它。
SGenome结构中不具备怎样为染色体(vecBits)进行译码的知识; 这是需要由遗传算法类自己来完成的一项任务。
现在让我们来快速窥视一下这个类的定义。我已把它称作CgaBob类(有时我对我的原始创见自己也很吃惊,但我确实是这样做的)。

class CgaBob 

 private:    
 vector<SGenome> m_vecGenomes    //基因组群体  
 int     m_iPopSize; //群体的大小
 double    m_dCrossoverRate;        
 double    m_dMutationRate;       
 int    m_iChromoLength;      //每个染色体含有多少bits
 int     m_iGeneLength;    //每个基因有多少bits
 int     m_iFittestGenome;        
 double    m_dBestFitnessScore;   
 double    m_dTotalFitnessScore;   
 int     m_iGeneration;   
 CBobsMap    m_BobsMap;  //为 map 类创建一个实例
 
    
 CBobsMap    m_BobsBrain;      //另一个CbobsMap对象用来保存每一代的最佳路径的一个记录,这是被访问小
 bool    m_bBusy;   
 void    Mutate(vector<int>&vecBits);  //格的一个数组,它仅仅是为了显示目的而使用的。//让你知道运行是否仍在进行中
 void  Crossover(const vector<int>&mum,            
 const vector<int>&dad, vector<int>&baby1, vector<int>&baby2); 
 SGenome& RouletteWheel Selection();   
 void   UpdateFitnessScores();   //用新的适应性分数来更新基因组原有的适应性分数,并计算群体的最高适应性分数和适应性分数最高的那个成员。
 vector<int>  Decode(const vector<int> &bits);  //把一个位向量译成为一个方向的(整数)向量 
 int    BinToInt(const vector<int> &v); //把一个位向量变换为十进制数。用于译码     

 void    CreateStartPopulation(); //创建一个随机的二进制位串的初始群体        
public:         
 CgaBob(double cross_rat, double mut_rat,int pop_size, int num_bits,int gene_len):m_dCrossoverRate(cross_rat),m_dMutationRate(mut_rat),m_iPopSize(pop_size),        m_iChromoLength(num_bits), m_dTotalFitnessScore(0.0), m_iGeneration(0), m_iGeneLength(gene_len), m_bBusy(false)
 {               
  CreateStartPopulation();            
 }          
 void  Run(HNND hwnd);               
 void  Epoch();          
 void  Render(int cxClient, int cyClient, HDC surface);            
 int   Generation(){return m_iGeneration;} //访问用的方法
 
 int   GetFittest(){return m_iFittestGenome;}  
 bool  Started(){return m_bBusy;}  
 void  Stop(){m_bBusy = false;}
};    

由上你可看出,当这个类的一个实例被创建时,构造函数初始化所有的变量,并调用CreateStartPopulation()。这一短小函数创建了所需数量的基因组群体。每个基因组一开始包含的是一个由随机2进制位串组成的染色体,其适应性分数则被设置为零。 

来自:http://blog.csdn.net/zzwu/archive/2005/12/25/561625.aspx

分类: 算法艺术 设计模式



关于酷勤 | 联系方式 | 免责声明 | 友情链接