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.