ABC(artificial bee colony)法のソースコード | akusanのブログ

akusanのブログ

ゲーム、プログラミングなどなど種々雑多に興味あるものをのせております。プログラミングはたまにコード自体を載せております。

ABC法を実装して、それなりに動作しているようなので、ソースコードでも掲載します。

何かの参考にでもしていただければと思います。

言語はC++です。

なお、ソースコード中に掲載されているpflfObjectiveFunctionに関しては関数ポインタです。

コールバック関数として実装しているので、別のところでベンチマーク関数を定義しています。

ソースコード中のmrand及びrndは私の方で実装した疑似乱数です。C言語による最新アルゴリズム事典記載のM系列乱数を使用しています。

mrand  整数を返す疑似乱数

rnd   浮動小数点で返却する疑似乱数(0~1)

 

以下のソースは1巡のみなので、これを繰り返し実行し、最終的な最適解を求めます。

 

void CAbc::vAbc()
{
       int i,j,k,m,h,c;
       int iRankCount = 0;
       int iLocalMaxAbcLoc = 0;
       int iGlobalMaxAbcLoc = 0;
       int iMinLoc = 0;
       double lfTempAbcData = -DBL_MAX;
       double lfTempWeight = 0.0;
       double lfMin = 0.0;
       double lfObjFunc = 0.0;
       double lfRand = 0.0;
        double lfFunc1 = 0.0;
        double lfFunc2 = 0.0;
        double lfRes = 0.0;
        double lfPrevProb = 0.0;
        double lfProb = 0.0;
        double lfFitProb = 0.0;
        int icNonUpdateCount = 0;

 

        // employee bee の動作
        // 更新点候補を算出します。
        m = mrand() % ( iAbcSearchNum - 1 );
        h = mrand() % ( iAbcVectorDimNum - 1);
 
        for( i = 0;i < iAbcSearchNum; i++ )
        {
                lfRand = 2*rnd()-1;
                for( j = 0; j < iAbcVectorDimNum; j++ )
                {
                        pplfVelocityData[i][j] = pplfAbcData[i][j];
                }
                pplfVelocityData[i][h] = pplfAbcData[i][h] + lfRand*( pplfAbcData[i][h] - pplfAbcData[m][h] );
        }

        // 各探索点と更新しなかった回数を格納する変数を更新します。
        for( i = 0;i < iAbcSearchNum; i++ )
        {
                lfFunc1 = pflfObjectiveFunction( pplfVelocityData[i], iAbcVectorDimNum );
                lfFunc2 = pflfObjectiveFunction( pplfAbcData[i], iAbcVectorDimNum );

                if( lfFunc1 < lfFunc2 )
                {
                        for( j = 0;j < iAbcVectorDimNum; j++ )
                                pplfAbcData[i][j] = pplfVelocityData[i][j];
                        piNonUpdateCount[i] = 0;
                }
                else
                {
                        piNonUpdateCount[i] = piNonUpdateCount[i] + 1;
                }
        }

        // onlookers beeの動作

        for( i = 0;i < iAbcDataNum-iAbcSearchNum;  i++ )
        {
                lfRes = 0.0;
                for(j = 0;j < iAbcSearchNum; j++ )
                {
                        // 適応度の算出
                        lfObjFunc = pflfObjectiveFunction( pplfAbcData[j], iAbcVectorDimNum );
                        if( lfObjFunc >= 0.0 )
                        {
                                lfFitProb = 1.0/( 1.0+lfObjFunc );
                        }
                        else
                        {
                                lfFitProb = 1.0+fabs( lfObjFunc );
                        }
                        lfRes += lfFitProb;
                        plfFit[j] = lfFitProb;
                }
                // 適応度の正規化
                for( j = 0;j < iAbcSearchNum; j++ )
                {
                        plfFitProb[j] = plfFit[j]/lfRes;
                }
                // ルーレット戦略を実行
                lfPrevProb = 0.0;
                lfProb = 0.0;
                lfRand = rnd();
                c = 0;
                for( j = 0;j < iAbcSearchNum; j++ )
                {
                        lfProb += plfFitProb[j];
                        if( lfPrevProb <= lfRand && lfRand <= lfProb )
                        {
                                c = j;
                        }
                        lfPrevProb = lfProb;
                }

                // ルーレット選択した探索点に対して更新候補を求めます。

                // 更新点候補を算出する。
                // 更新点候補を乱数により決定する。
                m = mrand() % ( iAbcSearchNum-1 );
                h = mrand() % ( iAbcVectorDimNum - 1);

                lfRand = 2*rnd()-1;
                for( j = 0; j < iAbcVectorDimNum; j++ )
                {
                        pplfVelocityData[c][j] = pplfAbcData[c][j];
                }
                pplfVelocityData[c][h] = pplfAbcData[c][h] + lfRand*( pplfAbcData[c][h] - pplfAbcData[m][h] );
                // 更新点候補を次のように更新します。
                lfFunc1 = pflfObjectiveFunction( pplfVelocityData[c], iAbcVectorDimNum );
                lfFunc2 = pflfObjectiveFunction( pplfAbcData[c], iAbcVectorDimNum );

                if( lfFunc1 < lfFunc2 )
                {
                        for( j = 0;j < iAbcVectorDimNum; j++ )
                                pplfAbcData[c][j] = pplfVelocityData[c][j];
                        piNonUpdateCount[c] = 0;
                }
                else
                {
                        piNonUpdateCount[c] = piNonUpdateCount[c] + 1;
                }
        }

        // scout bee の実行
        // 新たな探索点を求めて探索を実行します。
        for( i = 0;i < iAbcSearchNum; i++ )
        {
                if( piNonUpdateCount[i] > iAbcLimitCount )
                {
                        for( k = 0;k < iAbcVectorDimNum; k++ )
                        {
                                lfRand = lfSolveRange*(2*rnd()-1.0);
                                pplfAbcData[i][k] = lfRand;
                        }
                }
                else
                {
                        for( k = 0;k < iAbcVectorDimNum; k++ )
                        {
                                pplfAbcData[i][k] = pplfAbcData[i][k];
                        }
                }
        }
 
        lfMin = pflfObjectiveFunction( plfGlobalMaxAbcData, iAbcVectorDimNum );
        // 更新します。
        for( i = 0;i < iAbcSearchNum; i++ )
        {
                lfObjFunc = pflfObjectiveFunction( pplfAbcData[i], iAbcVectorDimNum );
                if( lfMin >= lfObjFunc )
               {
                        iMinLoc = i;
                        lfMin = lfObjFunc;
                        for( j = 0; j < iAbcVectorDimNum; j++ )
                        {
                                plfGlobalMaxAbcData[j] = pplfAbcData[i][j];
                        }
                }
        }
}

 

ABC法をクラスとして定義しています。なので、関数中に定義されていない変数があるかと思いますが、それは以下の通りです。

 

 int iGenerationNumber;    // 計算回数
 int iAbcDataNum;     // コロニーの数
 int iAbcVectorDimNum;    // 蜂の特徴ベクトル
 int iAbcSearchNum;     // 探索点数
 int iAbcLimitCount;     // 更新しなかった回数
 double **pplfAbcData;    // ABCデータ配列
 double **pplfNAbcData;    // ABC更新用データ配列
 double lfGlobalMaxAbcData;   // 大域的最適値
 double *plfGlobalMaxAbcData;  // 大域的最適解を表す粒子のデータ
  double **pplfVelocityData;   // ABCデータ速度配列
 double **pplfNVelocityData;   // ABC更新用データ速度配列
 double *plfFitProb;     // 適合度相対確率
 double *plfFit;      // 適合度
 int *piNonUpdateCount;    // 更新しない回数
double lfSolveRange;    // 出力範囲

その他にも実数値GA、粒子群最適化法も作成しているので、そちらも今後掲載していこうと思います。

 

参考文献:奥村晴彦『C言語による最新アルゴリズム事典』技術評論社,1991年

       宇谷昭秀, 長島 淳也, 牛腸 隆太, 山本 尚生, Artificial Bee Colony (ABC)アルゴリズムの高次元問題に対する解探索性能強化, 電子情報通信学会論文誌, vol.94, no.2, pp.425-438, 2011.