遗传算法入门--连载7

               连载之七

             算法进化的时代
Epoch

3.4.2 Epoch(时代)

  遗传算法类中最烩灵人口的内容就是Epoch()方法。这就是我们前面3.3节讲过的遗传算法的那个循环。它是这个类的主要工作场所。这一方法与所有工作或多或少都有连系。下面就让我们来更近距离地考察它 ...
void CgaBob::epoch()
{
 UpdateFitnessScores();

  在每一个epoch循环内所要做的第一件事情,就是测试染色体群中每一个成员的适应性分数。 UpdateFitnessScores()是用来对每个基因组的二进制染色体编码进行译码的函数,而由它再把译码所得到的一系列结果,也就是由代表东、南、西、北四个方向的整数,发送给 CBobsMap::TestRoute。后者检查 Bob在地 图中游走了多远,并根据 Bob离开出口的最终距离,返回一个相应的适应性分数。让我通过很少几行源码来告诉你怎样计算 Bob的适应性分数:
 int DiffX = abs(posX - m_iEndX);
 int DiffY = abs(posY - m_iEndY);
  这里,DiffX和DiffY 就是 Bob所在格子相对于迷宫出口的水平和垂直偏离值。 试考察图 3.6 的例子。灰色小格代表 Bob通过迷宫的路程,上面写着B的小格是他 最终所到达的地方。在这一位置上,Diffx = 3,而 DiffY = 0。


图 3.6 Bob尝试寻找迷宫出口

 return 1/(double)(DiffX+DiffY+1);

  这最后一行式子就是计算 Bob 的适应性分数。它把 DiffX与DiffY 两个数字 加起来然后求倒数。DiffX与DiffY的和数中还加了一个1,这是为了确保除法不会 出现一个分母为零的错误,如果 Bob 到达出口,Diffx + DiffY = O。 UpdateFitnessScores 也保持对每一代里适应分最高的基因组、以及与所有基 因组相关的适应性分数的跟踪。这些数值在执行轮盘赌选择时需要使用。
到此,你已经知道了函数 UpdateFitnessScores() 所做的全部工作,让我们回到Epoch函数的讨论.由于在每一Epoch中都需要创建一个新的基因组群,因此,当它们在创建出来时(每次创建2个基因组),我们需要寻找一些地方来保存它们。
 //现在创建一个新的群体
 int NewBabies = 0; //为婴儿基因组创建存储器
 vector<SGenome> vecBabyGenomes;
 现在继续讨论遗传算法循环中所处理的各种事务。
 while (NewBabies < m_iPopSize)
 { //用轮盘赌法选择 2 个上辈(parents)
   SGenome mum = RouletteWheelSelection();
   SGenome dad = RouletteWheelSelection();
  在每次迭代过程中,我们需要选择2个基因组来作为2个新生婴儿的染色体的上辈。我今后常喜欢把这2个上辈分别称为dad(父亲)和mum(母亲),因为他们将来就是要生孩子的)。你应该回忆得起来,一个基因组的适应性愈强,则由轮盘赌方法选择作为父母的几率也愈大。
   //杂交操作
   SGenome baby1, baby2;
   Crossover(mum.vecBits ,dad.vecBits, baby1.vecBits,         baby2.vecBits);

  以上2行的工作是:创建2个空白基因组,这是2个婴儿;它们与所选的上辈一起传递给杂交函数Crossover() 。这一函数执行了杂交(需要依赖于所设杂交 率m_dCrossoverRate来进行),并把新的染色体的2进制位串存放到2个新生婴儿 baby1和baby2之中

   // 变异操作
   Mutate(baby1.vecBits);
   Mutate(baby2.vecBits);
  以上这2步是对婴儿实行突变!这听起来可怕,但这对他们是有利的。一个婴儿的位的突变概率依赖于所选的参数 m_dMutationRate(突变率)。
   // 把2个新生因个婴儿加入新群体
   vecBabyGenomes.push_back(baby1);
   vecBabyGenomes.push_back(baby2);
   NewBabies += 2;
   }

  这2个新生后代最终要加入到新的群体中,这样就完成了一次 Loop 的迭代过程。这一过程需要不断重复,直到创建出来的后代总量和初始群体的大小相同。
  // 把所有婴儿复制到初始群体
  m_vecGenomes = vecBabyGenomes; // 代的计数加1
  ++m_iGeneration;
 }
  这里,原有的那个群体由新生一代所组成的群体来代替,并把代的计数器加1, 以跟踪当前的代。就是这么一些了!呵呵,不难吧? 这一 Epoch函数将无止境地重复,直到染色体收敛到了一个解,或到用户要求 停止时为止。下面我将会向你显示上述各种操作(算子)的代码,但在此首先让我 们来聊聊,应该如何确定使用的参数值。

转载于:https://my.oschina.net/dake/blog/196713

猜你喜欢

转载自blog.csdn.net/weixin_34146410/article/details/91508248