轮盘赌算法详细批注《游戏编程中人工智能》

来源:互联网 发布:java principal 编辑:程序博客网 时间:2024/05/20 07:34

注:本文含有大量原著内容。本文目的仅在于对程序进行更详细的批注或解释,阅读过该著作的可直接转至标题<2>查看详细注释。


    <1>原文介绍:

       轮盘赌选择是从染色体群体中选择一些成员的方法,被选中的机率和它们的适应性分数成比例,染色体的适应性分数愈高,被选中的概率也愈多。这不保证适应性分数最高的成员一定能选入下一代,仅仅说明它有最大的概率被选中。其工作过程是这样的:

    设想群体全体成员的适当性分数由一张饼图来代表 (见图3.4),这一饼图就和用于赌博的转轮形状一样。我们要为群体中每一染色体指定饼图中一个小块。块的大小与染色体的适应性分数成比例,适应性分数愈高,它在饼图中对应的小块所占面积也愈大。为了选取一个染色体,你要做的,就是旋转这个轮子,并把一个小球抛入其中,让它翻来翻去地跳动,直到轮盘停止时,看小球停止在哪一块上,就选中与它对应的那个染色体。


<2>轮盘赌算法详解(原:指原文。注:本文作者批注。)

    原:让我们从轮盘赌选择算法开始。请记住,这一个函数的功能是从群体中选择一个基因组,选中的几率正比于基因组的适应性分数。

 SGenome& CgaBob::RouletteWheelSelection()//轮盘赌函数的构建

 { 

     double fSlice = RandFloat()*m_dTotalFitnessScore;//阀值的计算

     原:我们从零到整个适应分范围内随机选取了一实数fSlice 。我喜欢把此数看作整个适应性分数饼图中的一块,如早先在图3.4中所示。 [但并不是其中一块,译注]

     注:双整型变量fSlice为某种意义上的阀值,一旦cfTotal大于该阀值(cfTotal > fSlice),从某种角度可以理解为:作为赌徒玩家的你摇起的轮盘停止了!这时候小球停止在i区域(对应的基因组数组元素为m_vecGenomes[i]m_vecGenomes[SelectedGenome])

    函数RandFloat()的原型为

    inline double RandFloat()   

    {

        return (rand())/(RAND_MAX+1.0);

    }

    另,源码中有

        #define RAND_MAX 0x7fff

    这意味着rand()返回的值将在0到2147483647之间产生,实际就是某个介于0-99.99%之间的百分比。至于m_dTotalFitnessScore,是每个基因组内各个基因适应分(请区别于下述“各个基因组适应分总和”这是两个不同的概念)叠加的结果(适应分的计算步骤详见源代码,本文主要解释轮盘赌思想,对其他不作过多解释),可看做是整个轮盘的数值大小(如果你的思维能够将轮盘数字化的话)。那么double fSlice = RandFloat()*m_dTotalFitnessScore;这个式子就很好理解了。喜欢钻牛角尖的童鞋可以根据源代码实际计算一下,看是不是这样的。

    我们可以将圆形的轮盘想象为一把长形的游标卡尺,这把尺子又分为很多段(基因组的适应分区域,适应分越大,该基因组占有的区域越大),箭头(即随机产生的阀值)在尺子的长度范围内随机移动,很明显便有了下述判断:

    if (cfTotal > fSlice)

    { 

         SelectedGenome = i; 

         break; 

    }


原:

    double cfTotal = O; 

    int SelectedGenome = 0;

    for (int i=O; i<m_iPopSize; ++i)//m_iPopSize为群体大小,或者说基因组的数量

    {

//依次叠加各个基因组的适应分

        cfTotal += m_vecGenomes[i].dFitness;//m_vecGenomes[i]为第i个基因组,m_vecGenomes[i].dFitness为第i个基因组的适应分数。

       

//上一次未跳出循环说明适应分总和还未达到阀值,如果本次分数总和超过阀值,说明该阀值处于该基因组的区域内,可以形象理解为游标卡尺的游动指针滑动到了某个刻度区域块内

if (cfTotal > fSlice)

        {

            SelectedGenome = i;

            break;

        }

    }

    return m_vecGenomes[SelectedGenome];

} 。。

    原:现在,程序通过循环来考察各基因组,把它们相应的适应性分数一个一个累加起来,直到这一部分累加和大于fSlice值时,就返回该基因组。就是这样简单。

    

    总结:第一次看这个算法的时候并不是太懂,而且原著的程序怎么也不符合我脑袋中想象的圆形轮盘跟跳动的小球,直到……我将那个轮盘线性化(就像求圆的面积一样将圆沿中心向四周剖开再将圆周直线化,拉直)。就是这样简单,终于明白了原作者的话,恩,这个算法根据源代码直译过来的思想就是酱紫的,你懂了没?


0 0