English Русский Deutsch Português
preview
イーグル戦略最適化(ES)

イーグル戦略最適化(ES)

MetaTrader 5トレーディング |
10 0
Andrey Dik
Andrey Dik

内容

  1. はじめに
  2. アルゴリズムの実装
  3. テスト結果


はじめに

プログラミングの世界、とりわけ取引用エキスパートアドバイザー(EA)の開発においては、効率的な最適化が極めて重要な役割を果たします。膨大な候補空間の中から最適解を探索する高度な問題では、従来の最適化手法が十分な性能を発揮できないことが少なくありません。こうした手法は局所最適解に陥りやすく、より優れた大域的最適解を見つけられない場合があります。

そのため近年では、自然界に着想を得たメタヒューリスティクスや自然進化の過程に着想を得た手法への関心が高まっています。これらのアルゴリズムは、計算速度が重要視される問題においても、良好な解、さらには最適解に近い解を効率的に発見できる能力を備えています。

タスクがますます複雑化し、計算コストも増大する中で、今回は有望なアプローチの一つであるイーグル戦略最適化(ES)を取り上げます。本アルゴリズムは鷲の狩猟行動に着想を得た新しいメタヒューリスティック手法であり、獲物を視認して探索し、動的に追跡する戦略を模倣することで、最適化問題の解決を目指します。


アルゴリズムの実装

上空を旋回しながら獲物を探すイヌワシを想像してみてください。その狩猟戦略は非常に効率的であり、明確に異なる2つの段階から構成されています。まず、高高度を飛行しながらジグザグに移動して広大な範囲を探索し、その後、標的を発見すると急降下して特定の獲物へ全力を集中します。この狩猟行動に着想を得て、2010年に複雑な最適化問題を解くためのイーグル戦略最適化(ES)アルゴリズムが開発されました。

第1段階では、アルゴリズムはレヴィ飛行と呼ばれる空間移動の数学モデルを利用します。一般的なランダムウォークでは移動距離がほぼ均一であるのに対し、レヴィ飛行では多数の短い移動の間に、ごくまれに非常に長いジャンプが発生します。 

アルゴリズムが有望な領域を発見すると(鷲が獲物を見つけた状況に相当します)、第2段階が開始されます。この段階ではホタルアルゴリズムを用いた集中的な局所探索が実行されます。このよく知られたアルゴリズムについては、すでに過去の記事で取り上げました。複数の探索エージェントは、夜空を飛ぶホタルのように、より高い適応度を持つ近傍エージェントへ引き寄せられます。ホタルの明るさは発見した解の品質に対応しており、その引力は距離に応じて指数関数的に減衰します。これにより、局所的な探索と有望解への収束との間でバランスが保たれます。

ESの重要な革新点は、これら2つのモードを周期的に切り替えることにあります。集中的な局所探索を終えると、アルゴリズムは再び大域探索へ戻り、探索空間内の未踏領域へ向けて長距離ジャンプを実行します。この仕組みにより早期収束を防ぎ、多数の局所最適解が存在する非常に複雑な探索空間においても、大域最適解を発見できる可能性を高めています。

アルゴリズムのパラメータは直感的で理解しやすく、設定も容易です。集団サイズは同時に探索をおこなうエージェント数を決定し、Levyパラメータは短距離移動と長距離ジャンプの比率を制御します。超球半径は集中的な局所探索をおこなう範囲を定義し、ランダム化係数は局所最適解の罠を回避するためのランダム性を付与します。この柔軟性により、高度な数学理論を深く理解していなくても、対象となる問題に応じてアルゴリズムを適切に調整できます。

ESアルゴリズムの基本思想はシンプルかつ洗練されています。すなわち、広い視野と局所的な精密さの両立です。鷲が広域の観察飛行と狙いを定めた急襲を組み合わせるように、このアルゴリズムも未知領域の探索と有望な領域の重点的探索との間でバランスを取ります。

本アルゴリズムの主な特徴は、解が改善された際にフェーズを自動的に切り替える機構、 適応的なパラメータ制御(停滞時にはλを減少させ、ステップサイズは時間とともに縮小)、 新たな探索領域の開拓と有望領域の重点的探索とのバランスです。

eagle_strategy

図1:ESアルゴリズムの動作概念図

図には、アルゴリズムの2つの動作フェーズ、レヴィ飛行の軌跡(赤色の点線)、局所探索をおこなう超球領域(青色の円)、超球近傍で移動するホタル群(緑色のハロー付きの点)、および最適化関数の等高線が示されています。

それでは、アルゴリズムの擬似コードを作成してみましょう。

初期化
1. エージェント集団をランダムな位置で生成する
2. 大域探索フラグを設定する(phase = global)
3.停滞カウンタおよび進捗カウンタを初期化する

メインループ(終了条件を満たすまで繰り返す)
  
  phase = globalの場合
    各エージェントについて:
      - マンテーニャアルゴリズムを使用してレヴィステップを生成する
      - 適応型ステップスケールを計算する(探索初期は大きく、終盤は小さくする)
      - 位置を更新する:new_position = current + Levy_step × scale
      - 境界制約を適用する
    
    大域最良解の改善が見つかった場合
      - 局所探索フェーズへ切り替える
      - 最良エージェントを局所探索の中心として選択する
      - 停滞カウンタをリセットする
    改善が見つからなかった場合
      - 停滞カウンタを増加させる
      - 停滞が5反復を超えた場合
        - より積極的なレヴィ飛行を実行するためλパラメータを減少させる
  
  それ以外の場合(phase = local)
    80%の確率で:
      - 最良エージェントを中心とする半径0.1の超球内に存在するエージェントを抽出する
      - エージェント数が5未満の場合
        - 最も近い5個、または集団の約30%に相当する近傍エージェントを選択する
      
      局所グループ内の各エージェントについて:
        グループ内の他の各エージェントについて:
          他のエージェントがより優れている場合
            - 魅力度を計算する:β = β₀ × exp(-γ × distance²)
            - エージェントを移動させる:position += β × (best - current) + random_noise
    
    20%の確率で:
      - 大域最良解の座標値を、各個体の一部座標へコピーする
    
    - 局所探索反復カウンタを増加させる
    - 局所探索を20反復実行した場合
       - 大域探索フェーズへ戻る
       - λパラメータを初期値へ復元する

  更新処理
    各エージェントについて:
      - 適応度を計算する
      - 自個体最良解を更新する
      - 大域最良解を更新

本実装のESアルゴリズムでは、レヴィ分布に従う乱数を生成するためにマンテーニャアルゴリズムを採用しています。この手法は1994年にロザリオ・N・マンテーニャ(R. N. Mantegna)によって提案され、その後、最適化アルゴリズムにおけるレヴィ飛行シミュレーションの標準的な手法として広く利用されるようになりました。マンテーニャは、適切にスケーリングされた2つのガウス乱数の比を用いることで、実用上重要な値の範囲においてレヴィ分布に非常に近い分布が得られることを数学的に証明しました。その基本的な考え方は次のとおりです。

// Calculating sigma for Mantegna algorithm
double numerator   = Gamma(1.0 + lambda) * MathSin(M_PI * lambda / 2.0);
double denominator = Gamma((1.0 + lambda) / 2.0) * lambda * MathPow(2.0, (lambda - 1.0) / 2.0);
double sigma = MathPow(numerator / denominator, 1.0 / lambda);

// Generate u and v from normal distributions
double u_val = GenerateGaussian() * sigma;
double v_val = MathAbs(GenerateGaussian());

// Calculate Levy step
levyStep[c] = u_val / MathPow(v_val, 1.0 / lambda);

2つの乱数変数を用います。

  • u:正規分布N(0, σ²)に従う乱数
  • v:正規分布N(0, 1)に従う乱数
σの特別な式
σ = [Γ(1+λ) × sin(πλ/2) / (Γ((1+λ)/2) × λ × 2^((λ-1)/2))]^(1/λ)

ここで、Γはガンマ関数、λはレヴィ分布のパラメータ(1 < λ ≤ 3)です。

なお、ガンマ関数の計算(マンテーニャ法におけるσパラメータの算出)には、Lanczos近似が用いられています。これはガンマ関数を高精度に数値計算するための手法であり、Γ(z)を求める方法として最も効率的なものの1つです。本コードでは独立した関数として実装されており、その詳細については最後に説明します。

基本式は次のとおりです。

Γ(z+1) = √(2π) × ((z+g+0.5)^(z+0.5)) × e^(-(z+g+0.5)) × Ag(z)

ここで、gはパラメータ(通常は7)であり、Ag(z)は事前に計算された係数を持つ数列です。g=7かつ9個の係数を使用した場合、およそ15桁の有効数字精度が得られます。

また、z < 0.5の場合には反射公式を利用します。この関係式により、ガンマ関数をすべての実数に対して計算できます。

Γ(z) × Γ(1-z) = π / sin(πz)

ガンマ関数を効率的に計算できなければ、レヴィ飛行の生成コストは非常に高くなり、最適化アルゴリズム全体の実行速度を大きく低下させることになります。

レヴィの最終ステップ

step = u / |v|^(1/λ)

この手法によって生成されるステップ列は、レヴィ飛行特有の挙動を示します。すなわち、多数の小さなステップによる局所探索、まれに発生する非常に大きなジャンプによる大域探索、そしてステップ長がべき乗則に従う分布という特徴を備えています。

この手法は、正規乱数生成器だけで実装できる簡潔さと、数値的な安定性と頑健性を兼ね備えています。まさにこの特性こそが、レヴィ飛行を最適化問題において効果的なものにしています。レヴィ飛行は、局所領域の詳細な探索と探索空間内の新しい領域への迅速な移動との間で、優れたバランスを実現するためです。

ESアルゴリズムで使用される手法について詳しく検討したところで、いよいよ鷲の狩猟戦略に基づく最適化手法を実装したC_AO_ESクラスの作成に移ります。このクラスはC_AO基底クラスから継承されます。本手法は2段階のアプローチを採用しています。まず有望な領域を特定するための大域探索を実行し、その後、選択された探索領域内で局所探索をおこない、解をさらに洗練させます。

集団サイズを表すpopSizeは、探索に参加する「候補解」の数を指定します。レヴィパラメータlambdaはランダムステップの分布特性を制御します。超球半径sphereRadiusは局所探索をおこなう領域を定義します。局所探索反復回数localIterationsは、超球内で解を何回改良するかを指定します。また、ランダム化パラメータalphaと魅力度パラメータbeta0は、ランダム移動や「光」の影響(比喩的表現)といった探索モデルの構成要素を制御します。 

大域探索フェーズ (GlobalExploration)は、レヴィ分布によって生成されたランダムステップを用いて、探索空間全体から「有望な」領域を発見することに重点を置いています。このアプローチにより、広範囲の探索が可能となり、大規模な探索空間に対しても高い適応性を示します。

局所探索フェーズ(LocalExploitation)では、現在の最良解を中心とする超球近傍のエージェントを対象に、より詳細な探索を実行します。この段階では、局所最適化に対応する小さく精密なステップが使用されます。

レヴィステップ生成(GenerateLevyStep)は、レヴィ分布に基づくランダムな移動量を生成します。これにより探索空間内で小さな移動と大きなジャンプの両方が実現され、探索と活用のバランスが保たれます。

このクラスには探索の進行状況を追跡するための仕組みも含まれています。具体的には、発見済みの最良解の保持、解の改善が見られない場合の停滞カウンタ、アルゴリズムの実行時間や反復回数を制限するためのエポックループ、ランダムステップ生成に必要な分布パラメータの計算、特にガウス分布およびレヴィ分布の生成処理などが実装されています。また、探索フェーズ管理機構によって大域探索と局所探索の切り替えおよびその動作制御がおこなわれます。

総じて、本手法はまず探索空間を広範囲に調査して有望な領域を特定し、その後に慎重な局所最適化をおこなうことで高精度な解を得る探索戦略です。また、さまざまなパラメータや制御機構によって、その挙動を対象となる問題や条件に合わせて柔軟に適応させることができます。

//————————————————————————————————————————————————————————————————————
class C_AO_ES : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_ES () { }
  C_AO_ES ()
  {
    ao_name = "ES";
    ao_desc = "Eagle Strategy";
    ao_link = "https://www.mql5.com/ja/articles/18460";

    popSize         = 100;   // population size
    lambda          = 1.0;  // Levy distribution parameter (1 < λ ≤ 3)
    sphereRadius    = 0.1;  // hypersphere radius for local search
    localIterations = 20;   // number of local search iterations
    alpha           = 0.1;  // randomization parameter for Firefly
    beta0           = 1.2;  // initial attractiveness

    ArrayResize (params, 6);

    params [0].name = "popSize";         params [0].val = popSize;
    params [1].name = "lambda";          params [1].val = lambda;
    params [2].name = "sphereRadius";    params [2].val = sphereRadius;
    params [3].name = "localIterations"; params [3].val = localIterations;
    params [4].name = "alpha";           params [4].val = alpha;
    params [5].name = "beta0";           params [5].val = beta0;
  }

  void SetParams ()
  {
    popSize         = (int)params [0].val;
    lambda          = params      [1].val;
    sphereRadius    = params      [2].val;
    localIterations = (int)params [3].val;
    alpha           = params      [4].val;
    beta0           = params      [5].val;
  }

  bool Init (const double &rangeMinP  [],  // minimum values
             const double &rangeMaxP  [],  // maximum values
             const double &rangeStepP [],  // step change
             const int     epochsP = 0);   // number of epochs

  void Moving   ();
  void Revision ();

  //------------------------------------------------------------------
  double lambda;          // Levy distribution parameter (1 < λ ≤ 3)
  double sphereRadius;    // hypersphere radius for local search
  int    localIterations; // number of local search iterations
  double alpha;           // randomization parameter
  double beta0;           // initial attractiveness

  private: //---------------------------------------------------------
  double gamma_es;           // light absorption coefficient
  double levyStep [];        // array for Levy steps

  // Phase tracking
  bool   inLocalSearchPhase; // local search flag
  int    localSearchCenter;  // local search center
  int    localSearchCounter; // local search iteration counter

  // Monitoring convergence
  double prevBestFitness;    // previous best value
  int    stagnationCounter;  // stagnation counter

  // Tracking epochs
  int    epochCurrent;       // current epoch
  int    epochMax;           // maximum number of epochs

  // Auxiliary methods
  void   GlobalExploration  ();
  void   LocalExploitation  ();
  void   GenerateLevyStep   ();
  double GenerateGaussian   ();
  double Gamma              (double z);
};
//————————————————————————————————————————————————————————————————————

C_AO_ESクラスのInitメソッドは、探索開始前に最適化アルゴリズムを初期化します。まず、アルゴリズムの標準的な初期化処理を担当するStandardInitメソッドが呼び出されます。このメソッドでは、共通パラメータおよびデータ構造が設定されます。StandardInitが失敗した場合、Initメソッドは直ちにfalseを返し、初期化が正常に完了しなかったことを通知します。

次に、coords座標数と同じサイズでlevyStep配列のメモリを確保します。この配列は、レヴィ分布に従って生成されたステップを格納するために使用されます。その後、inLocalSearchPhaseフラグをfalseに設定します。これは、アルゴリズムが初期状態では大域探索フェーズにあることを意味します。また、localSearchCenterおよびlocalSearchCounter変数を0に設定し、局所探索用のカウンタを初期化します。

収束パラメータの初期化

  • prevBestFitnessには取り得る最小値を設定します。これにより、最初に発見された解は必ず以前の解より優れていると判定されます。
  • stagnationCounterには0を設定し、最良解の改善が発生しなかった反復回数を追跡できるようにします。

エポックパラメータの初期化

  • epochMaxには入力パラメータepochsPの値を代入し、アルゴリズムの最大エポック数(反復回数)を設定します。
  • epochCurrentには0を設定し、現在のエポック番号を管理します。

続いて固定パラメータを設定します。gamma_es変数には1.0を代入します。このパラメータは、アルゴリズム全体の一部として利用されるホタルアルゴリズムで使用されます。

最後に、解集団aの初期個体群を生成します。集団内の各解に対して、次の処理を実行します。

  • 解ベクトルの各座標a[i].c[c]を、区間[rangeMin[c], rangeMax[c]]から取得したランダム値で初期化します。
  • 各座標値は、u.SeInDiSpメソッドを使用して、rangeStep[c]で指定された刻み幅を考慮した最も近い有効値へ丸められます。
  • 各解の目的関数値(a[i].fおよびa[i].fB)は、-DBL_MAXに設定されます。
//————————————————————————————————————————————————————————————————————
bool C_AO_ES::Init (const double &rangeMinP  [],
                    const double &rangeMaxP  [],
                    const double &rangeStepP [],
                    const int     epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  // Initialize arrays
  ArrayResize (levyStep, coords);

  // Initialize phase tracking
  inLocalSearchPhase = false;
  localSearchCenter  = 0;
  localSearchCounter = 0;

  // Initialize convergence tracking
  prevBestFitness   = -DBL_MAX;
  stagnationCounter = 0;

  // Initialize epoch tracking
  epochMax     = epochsP;
  epochCurrent = 0;

  // Fixed Firefly parameter
  gamma_es = 1.0;

  // Initialize the population randomly
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      a [i].c [c] = u.SeInDiSp  (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }

    a [i].f  = -DBL_MAX;
    a [i].fB = -DBL_MAX;
  }

  return true;
}
//————————————————————————————————————————————————————————————————————

Movingメソッドは、大域探索と局所探索を交互に実行する反復型最適化の基本ロジックを実装しています。メソッドが呼び出されるたびにエポックカウンタが増加し、アルゴリズムの進行状況を追跡します。

探索フェーズの処理
  • 現在のフェーズが大域探索の場合、レヴィ分布に基づくステップを用いて探索空間全体を探索します。これにより、新たな有望領域を発見することを目的として、探索空間全体にわたって新しい解が生成されます。

  • 大域探索後に解の改善が確認された場合、アルゴリズムは局所探索フェーズへ移行します。この際、最も有望な解(エージェント)が選択され、その周辺で探索することで解のさらなる改善を図ります。

  • 一方、複数回の反復にわたって改善が見られず停滞が蓄積した場合には、新しい解を探索する活動を強化します。具体的には、探索空間をより広範囲に探索できるよう、lambdaパラメータを減少させてレヴィ飛行をよりアグレッシブなものにします。

  • アルゴリズムが局所探索フェーズにある場合、80%の確率でホタルアルゴリズムを模倣した手法による局所最適化が実行されます。この過程で選択された解はさらに洗練され、局所探索反復カウンタが増加します。そして、あらかじめ設定された局所探索反復回数に達すると、アルゴリズムは再び大域探索フェーズへ戻ります。 

さらに、集団内の解を一定確率で変更する追加のランダム摂動も導入されています。この仕組みは多様性を維持し、局所最適解の「罠」に陥ることを防ぐことを目的としています。

    このように、本メソッドは大域的な探索と集中的な局所最適化を柔軟に切り替えながら進める探索戦略を実装しています。これにより、新しい領域の探索と既存の有望な解の改善とのバランスが実現されます。

    //————————————————————————————————————————————————————————————————————
    void C_AO_ES::Moving ()
    {
      epochCurrent++;
    
      // PHASE DECISION: Alternating between global and local search
      if (!inLocalSearchPhase)
      {
        // PHASE 1: GLOBAL EXPLORATION using Levy flights
        GlobalExploration ();
    
        // Check whether it is necessary to switch to local search
        // Switch if we find a promising area (improving the best fitness)
        if (fB > prevBestFitness)
        {
          inLocalSearchPhase = true;
          localSearchCounter = 0;
          prevBestFitness    = fB;
          stagnationCounter  = 0;
    
          // Find the best agent to center local search
          localSearchCenter = 0;
          double bestFit = -DBL_MAX;
    
          for (int i = 0; i < popSize; i++)
          {
            if (a [i].f > bestFit)
            {
              bestFit = a [i].f;
              localSearchCenter = i;
            }
          }
        }
        else
        {
          stagnationCounter++;
    
          // In case of stagnation, increase exploration
          if (stagnationCounter > 5)
          {
            lambda = MathMax (1.0, lambda - 0.1); // Make Levy flights more aggressive
          }
        }
      }
      else
      {
        if (u.RNDprobab () < 0.8)
        {
          // PHASE 2: LOCAL EXPLOITATION using the Firefly algorithm
          LocalExploitation ();
    
          localSearchCounter++;
    
          // Return to global search after local iterations are complete
          if (localSearchCounter >= localIterations)
          {
            inLocalSearchPhase = false;
            lambda = params [1].val; // Reset lambda to its original value
          }
        }
        else
        {
          for (int i = 0; i < popSize; i++)
          {
            for (int c = 0; c < coords; c++)
            {
              if (u.RNDprobab () < 0.5)
              {
                a [i].c [c] = cB [c];
              }
            }
          }
        }
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Revisionメソッドは、アルゴリズムの実行中に最良解に関する情報を更新するために設計されています。このメソッドは現在の解集団の全要素を走査し、各解について現在の適応度と、その解の個体最良結果として保存されている適応度を比較します。現在の適応度のほうが優れている場合は、個体最良結果および対応する解を更新します。つまり、現在の反復で得られた最良の解が保存されます。

    続いて、各解の適応度を、集団全体でこれまでに発見された大域最良値と比較します。現在の結果がより優れている場合は、大域最良結果を更新するとともに、対応する解を保存します。このように、Revisionメソッドはアルゴリズムの現在の状態における局所的な最良解および大域的な最良解に関する情報を常に最新の状態に維持します。これにより、探索の各ステップで発見された最良の解が確実に保持されます。

    //————————————————————————————————————————————————————————————————————
    void C_AO_ES::Revision ()
    {
      for (int i = 0; i < popSize; i++)
      {
        // Updating the personal best one
        if (a [i].f > a [i].fB)
        {
          a [i].fB = a [i].f;
          ArrayCopy (a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY);
        }
    
        // Update the global best one
        if (a [i].f > fB)
        {
          fB = a [i].f;
          ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY);
        }
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    GlobalExplorationメソッドは、レヴィ飛行を用いて解空間を探索する大域探索フェーズを実装しています。この処理では、集団内の各解に対してレヴィ分布に基づくランダムステップを生成し、そのステップによって解空間内での移動方向および移動距離を決定します。

    レヴィ分布は裾の重い特性を持つため、局所的な微調整に適した小さなステップと、遠方の領域を探索するためのまれな大ジャンプの両方を実現できます。ループ内では、各解の座標に対して以下が計算されます。

    • 探索範囲:座標の最大値と最小値の差
    • 適応型スケーリング係数stepScale:探索の進行に伴って減少します。探索の終盤に近づくほどステップは小さくなり、有望な解の周辺に探索を集中できるようになります。一方、探索開始直後はステップが大きく設定されるため、より広範囲の探索が可能です。
    • レヴィステップの適用:現在の解の座標は、レヴィステップ、探索範囲、およびスケーリング係数に比例した量だけ更新されます。
    • 境界補正:更新後の座標が許容範囲外に出ていないかを確認し、範囲外であれば指定された範囲内に収まるよう補正します。
    最終的に、このメソッドはレヴィ分布から生成されたステップを用いて集団内の各解の位置を更新します。これにより、最適化の進行状況に応じてステップサイズを適応的に制御しながら、解空間全体に対する大域的な探索を実現します。このアプローチにより、探索の初期段階では広範囲の探索をおこない、その後は最適解に近づくにつれて探索範囲を徐々に絞り込みながら解を洗練していくことができます。
    //————————————————————————————————————————————————————————————————————
    // PHASE 1: GLOBAL EXPLORATION using Levy flights
    void C_AO_ES::GlobalExploration ()
    {
      for (int i = 0; i < popSize; i++)
      {
        // Generate Levy step
        GenerateLevyStep ();
    
        // Update position using Levy flight
        for (int c = 0; c < coords; c++)
        {
          double range = rangeMax [c] - rangeMin [c];
    
          // Adaptive step size depending on search progress
          double progress = (epochMax > 0) ? (double)epochCurrent / (double)epochMax : 0.5;
          double stepScale = 0.01 + 0.2 * (1.0 - progress); // Start with big steps
    
          // Apply the Levy step
          a [i].c [c] += levyStep [c] * range * stepScale;
    
          // Boundary restrictions
          a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    LocalExploitationメソッドは、ホタルアルゴリズムを用いた解の局所改善フェーズを実装しています。初期段階では、最良解の周囲に定義された超球内部に存在するエージェントを特定します。そのために各エージェントと超球中心との距離を計算し、その距離が半径より小さい場合、またはエージェントが探索中心そのものである場合に、そのエージェントを選択グループに含めます。

    超球内部のエージェント数が少なすぎる場合には、近傍探索を拡張し、より多くのエージェントを含めます。この処理では、全エージェントについて中心からの距離を計算し、距離が小さい順に近いエージェントを選択します。選択方法は、固定数(例:5個)または全体の割合(例:30%)に基づいておこなわれ、これらのエージェントが局所探索グループに追加されます。

    ホタルアルゴリズムの適用範囲では、選択されたエージェント同士がアルゴリズムのルールに従って相互作用します。
    • 各エージェントについて、同一グループ内により良い適応度を持つ別のエージェントが存在するかどうかを確認します。
    • 存在する場合、現在のエージェントはより優れたエージェントへ向かって移動し、その際に両者間の距離が計算されます。
    • 他のエージェントがより良い解であるほど、その「輝度」は高くなり、この輝度は距離およびアルゴリズムパラメータに依存して決定されます。
    • エージェントの移動は、より良い解への引力と、探索多様性を維持するためのランダム摂動を組み合わせて構成されます。
    • 移動処理の後には、すべての解が許容範囲内に収まるよう座標境界が確認されます。

      このように本メソッドは、ホタルアルゴリズムの相互作用モデルに基づき、最良点付近における局所的な解の改善を可能にします。すなわち、より優れた解が他の解を引き寄せることで、解空間の局所的な最適化が促進されます。

      //————————————————————————————————————————————————————————————————————
      // PHASE 2: Local exploitation using the Firefly algorithm
      void C_AO_ES::LocalExploitation ()
      {
        // Identification of agents inside the hypersphere around the best solution
        double agents_in_sphere [];
        ArrayResize (agents_in_sphere, 0);
      
        for (int i = 0; i < popSize; i++)
        {
          double normalized_dist = 0.0;
      
          for (int c = 0; c < coords; c++)
          {
            double diff = (a [i].c [c] - a [localSearchCenter].c [c]) / (rangeMax [c] - rangeMin [c]);
            normalized_dist += diff * diff;
          }
          normalized_dist = MathSqrt (normalized_dist);
      
          // Include agents inside the sphere or the center itself
          if (normalized_dist <= sphereRadius || i == localSearchCenter)
          {
            int size = ArraySize (agents_in_sphere);
            ArrayResize (agents_in_sphere, size + 1);
            agents_in_sphere [size] = i;
          }
        }
      
        // If there are too few agents, expand to the nearest neighbors
        if (ArraySize (agents_in_sphere) < 5)
        {
          ArrayResize (agents_in_sphere, 0);
      
          // Calculate distances for all agents
          double distances [];
          ArrayResize (distances, popSize);
      
          for (int i = 0; i < popSize; i++)
          {
            if (i == localSearchCenter)
            {
              distances [i] = 0.0;
            }
            else
            {
              double dist = 0.0;
              for (int c = 0; c < coords; c++)
              {
                double diff = (a [i].c [c] - a [localSearchCenter].c [c]) / (rangeMax [c] - rangeMin [c]);
                dist += diff * diff;
              }
              distances [i] = MathSqrt (dist);
            }
          }
      
          // Take the closest 5 agents or 30% of the population
          int numAgents = MathMin (popSize, MathMax (5, popSize / 3));
          ArrayResize (agents_in_sphere, numAgents);
      
          // Simple selection of nearby agents
          for (int k = 0; k < numAgents; k++)
          {
            double minDist = DBL_MAX;
            int minIdx = -1;
      
            for (int i = 0; i < popSize; i++)
            {
              bool already_selected = false;
      
              for (int j = 0; j < k; j++)
              {
                if (agents_in_sphere [j] == i)
                {
                  already_selected = true;
                  break;
                }
              }
      
              if (!already_selected && distances [i] < minDist)
              {
                minDist = distances [i];
                minIdx = i;
              }
            }
      
            agents_in_sphere [k] = minIdx;
          }
        }
      
        // Execute the Firefly algorithm on the selected agents
        int numLocalAgents = ArraySize (agents_in_sphere);
      
        for (int i = 0; i < numLocalAgents; i++)
        {
          int idx_i = (int)agents_in_sphere [i];
      
          for (int j = 0; j < numLocalAgents; j++)
          {
            if (i == j) continue;
      
            int idx_j = (int)agents_in_sphere [j];
      
            // If agent j is better than agent i, move i to j
            if (a [idx_j].f > a [idx_i].f)
            {
              // Calculate the distance
              double r_squared = 0.0;
      
              for (int c = 0; c < coords; c++)
              {
                double diff = (a [idx_j].c [c] - a [idx_i].c [c]) / (rangeMax [c] - rangeMin [c]);
                r_squared += diff * diff;
              }
      
              // Calculate attractiveness
              double beta = beta0 * MathExp (-gamma_es * r_squared);
      
              // Move agent i to agent j
              for (int c = 0; c < coords; c++)
              {
                double range = rangeMax [c] - rangeMin [c];
      
                // Firefly motion equation
                a [idx_i].c [c] += beta * (a [idx_j].c [c] - a [idx_i].c [c]) +
                                   alpha * (u.RNDfromCI (-0.5, 0.5)) * range * 0.1;
      
                // Apply borders
                a [idx_i].c [c] = u.SeInDiSp (a [idx_i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
              }
            }
          }
        }
      }
      //————————————————————————————————————————————————————————————————————
      

      GenerateLevyStepメソッドは、最適化アルゴリズムにおける大域探索戦略を実装するために必要なレヴィステップを生成する役割を担っています。本メソッドでは、前述のマンテーニャアルゴリズムを用いてレヴィステップを生成します。

      σの計算

      コード内の式はσパラメータを算出するものであり、このパラメータはレヴィ分布のスケールに関連しています。またλに依存しており、λはレヴィ分布の形状を決定するパラメータです(分布の裾の重さを制御します)。Gamma()はガンマ関数であり、実数に対する階乗の一般化です(このメソッドの実装は後述されます)。このσパラメータは、マンテーニャアルゴリズムにおいて正規分布乱数を生成するために必要となります。

      レヴィステップは、解の各座標ごとに独立して生成されます。各次元に対して正規分布に従う乱数u_valとv_valが生成され、v_valの絶対値が使用されます。その後、マンテーニャアルゴリズムの式に従いレヴィステップは「u_val / Math.pow(v_val, 1.0 / lambda).」として計算されます。ここでゼロ除算を防ぐため、v_valが非常に小さい場合にはチェックがおこなわれます。また、レヴィステップは異常に大きな値を取らないよう絶対値で制限されます。これは過度に大きなジャンプによる探索の不安定化を防ぐためです。

      最終的に、本メソッドは各座標に対応するレヴィステップ値を格納したlevyStep配列を生成します。これらのステップは、その後GlobalExplorationメソッドにおいて使用され、解空間内での各解の位置更新に利用されます。

      //————————————————————————————————————————————————————————————————————
      // Generate Levy step using Mantegna algorithm
      void C_AO_ES::GenerateLevyStep ()
      {
        // Calculate sigma for Mantegna algorithm
        double numerator   = Gamma (1.0 + lambda) * MathSin (M_PI * lambda / 2.0);
        double denominator = Gamma ((1.0 + lambda) / 2.0) * lambda * MathPow (2.0, (lambda - 1.0) / 2.0);
        double sigma = MathPow (numerator / denominator, 1.0 / lambda);
      
        for (int c = 0; c < coords; c++)
        {
          // Generate u and v from normal distributions
          double u_val = GenerateGaussian () * sigma;
          double v_val = MathAbs (GenerateGaussian ());
      
          // Calculate the Levy step
          if (v_val > 1e-10)
          {
            levyStep [c] = u_val / MathPow (v_val, 1.0 / lambda);
          }
          else
          {
            levyStep [c] = 0.0;
          }
      
          // Limit extreme values
          if (MathAbs (levyStep [c]) > 10.0)
          {
            levyStep [c] = 10.0 * (levyStep [c] > 0 ? 1.0 : -1.0);
          }
        }
      }
      //————————————————————————————————————————————————————————————————————
      

      GenerateGaussianメソッドは、平均0、標準偏差1に従う正規分布(ガウス分布)の乱数を生成する処理を実装しています。本メソッドでは、一般的に広く用いられるボックス=ミュラー法を利用しており、この手法は過去の記事でも使用されています。

      本実装では静的変数hasSpareおよびspareが使用されます。Box-Muller変換では一度の計算で2つの独立した正規分布乱数が生成されるため、hasSpareは生成済みのもう一方の値が保存されているかどうかを示す論理変数として機能し、spareは次回の呼び出し時に使用するための「余りの乱数」を保持します。

        必要に応じて、新しい乱数を生成します。

        新しい乱数の生成が必要な場合(spareが存在しない場合)、まず(0,1)区間の一様分布に従う2つの独立した乱数u_valおよびv_valが生成されます。ここでu.RNDfromCI関数が一様乱数の生成に使用されます。次に、ボックス=ミュラー法が適用されます。

        • まず正規分布のスケールを表すmagは「mag = √(-2.0 × Math.log(u_val + 1e-10))」で計算されます。ここでu_valに微小値1e-10を加えている目的は、未定義であるlog(0)の回避です。
        • spare = mag × cos(2.0 × π × v_val)として求められます。
        • 関数の戻り値としてmag * Math.sin(2.0 * M_PI * v_val)が返されます。

        このように本メソッドは、一度のボックス=ミュラー変換で得られる2つの正規分布乱数のうち1つを返し、もう1つをspareとして保存することで、計算効率を向上させています。
        //————————————————————————————————————————————————————————————————————
        // Generate a Gaussian random number using the Box-Muller transform
        double C_AO_ES::GenerateGaussian ()
        {
          static bool hasSpare = false;
          static double spare;
        
          if (hasSpare)
          {
            hasSpare = false;
            return spare;
          }
        
          hasSpare = true;
          double u_val = u.RNDfromCI (0.0, 1.0);
          double v_val = u.RNDfromCI (0.0, 1.0);
        
          double mag = MathSqrt (-2.0 * MathLog (u_val + 1e-10));
          spare = mag * MathCos (2.0 * M_PI * v_val);
        
          return mag * MathSin (2.0 * M_PI * v_val);
        }
        //————————————————————————————————————————————————————————————————————
        

        Gammaメソッドは、与えられた引数zに対するガンマ関数の近似計算をおこなう関数です。ガンマ関数は統計学や最適化分野において非常に重要な数学関数ですが、厳密計算は複雑で計算コストも高いため、実用上は近似手法が用いられることが一般的です。本実装では、比較的少ない計算量で高い精度が得られるLanczos近似を使用しています。主なポイントを見ていきましょう。

        まず、引数zが0.5より小さい場合にはオイラーの反射公式が適用されます。これにより、0に近い領域においてもガンマ関数の計算が可能になります。反射公式は、ガンマ関数Γ(z)とΓ(1-z)を関係づけるものであり、小さな引数領域での数値的不安定性を回避する役割を持ちます。その後、あらかじめ定義された固定のLanczos係数が使用されます。これらの係数は高精度な近似結果が得られるよう慎重に設計されており、冪乗や指数関数を含む式と組み合わせて計算されます。本メソッドは、与えられたzに対してガンマ関数の近似値を返します。

        Lanczos近似は、実用上十分な精度を提供する手法です。必要となる演算は主に少数の算術計算と係数の参照で構成されており、計算効率にも優れています。また反射公式と組み合わせることで広い引数範囲に対応できる点も特徴です。総じてGammaメソッドは、ガンマ関数を実用的かつ高精度に近似する手法として有効です。

        //————————————————————————————————————————————————————————————————————
        // Approximation of the gamma function using Lanczos approximation
        double C_AO_ES::Gamma (double z)
        {
          if (z < 0.5)
          {
            // Reflection formula for z < 0.5
            return M_PI / (MathSin (M_PI * z) * Gamma (1.0 - z));
          }
        
          // Lanczos coefficients
          const double g = 7.0;
          double coef [] =
          {
            0.99999999999980993,
            676.5203681218851,
            -1259.1392167224028,
            771.32342877765313,
            -176.61502916214059,
            12.507343278686905,
            -0.13857109526572012,
            9.9843695780195716e-6,
            1.5056327351493116e-7
          };
        
          z -= 1.0;
          double x = coef [0];
        
          for (int i = 1; i < 9; i++)
          {
            x += coef [i] / (z + i);
          }
        
          double t = z + g + 0.5;
          double sqrt2pi = MathSqrt (2.0 * M_PI);
        
          return sqrt2pi * MathPow (t, z + 0.5) * MathExp (-t) * x;
        }
        //————————————————————————————————————————————————————————————————————
        


        テスト結果

        このアルゴリズムはランキング表には入りませんでしたが、その結果は注目に値します。

        ES|Eagle Strategy|100.0|1.0|0.1|20.0|0.1|1.2|
        =============================
        5 Hilly's; Func runs:10000; result:0.7077570016043803
        25 Hilly's; Func runs:10000; result:0.4307775904381953
        500 Hilly's; Func runs:10000; result:0.2747545259235643
        =============================
        5 Forest's; Func runs:10000; result:0.7173720280531499
        25 Forest's; Func runs:10000; result:0.3448423301485268
        500 Forest's; Func runs:10000; result:0.1597390810339928
        =============================
        5 Megacity's; Func runs:10000; result:0.5184615384615384
        25 Megacity's; Func runs:10000; result:0.2775384615384615
        500 Megacity's; Func runs:10000; result:0.11063076923077016
        =============================
        All score:3.54187 (39.35%)

        この可視化は、探索フェーズが戦略に従って明確に分割されている様子を示しており、長距離のジャンプ(大域探索)と短い改良的な移動(局所探索)がどのように発生するかを直感的に確認できます。

        Hilly

        Hillyテスト関数のES

        Forest

        Forestテスト関数のES

        Megacity

        Megacityテスト関数のES

        ESアルゴリズムは参考としてランキング表に記載されています。

        # AO 詳細 Hilly Hilly
        ファイナル
        Forest Forest
        ファイナル
        Megacity(離散) Megacity
        ファイナル
        ファイナル
        結果

        MAX
        10p(5F) 50p(25F) 1000p(500F) 10p(5F) 50p(25F) 1000p(500F) 10p(5F) 50p(25F) 1000p(500F)
        1 ANS across neighbourhood search 0.94948 0.84776 0.43857 2.23581 1.00000 0.92334 0.39988 2.32323 0.70923 0.63477 0.23091 1.57491 6.134 68.15
        2 CLA コードロックアルゴリズム(joo) 0.95345 0.87107 0.37590 2.20042 0.98942 0.91709 0.31642 2.22294 0.79692 0.69385 0.19303 1.68380 6.107 67.86
        3 AMOm 動物移動最適化m 0.90358 0.84317 0.46284 2.20959 0.99001 0.92436 0.46598 2.38034 0.56769 0.59132 0.23773 1.39675 5.987 66.52
        4 (P+O)ES (P+O)進化戦略 0.92256 0.88101 0.40021 2.20379 0.97750 0.87490 0.31945 2.17185 0.67385 0.62985 0.18634 1.49003 5.866 65.17
        5 CTA 彗星の尾アルゴリズム(joo) 0.95346 0.86319 0.27770 2.09435 0.99794 0.85740 0.33949 2.19484 0.88769 0.56431 0.10512 1.55712 5.846 64.96
        6 TETA 時間進化移動アルゴリズム(joo) 0.91362 0.82349 0.31990 2.05701 0.97096 0.89532 0.29324 2.15952 0.73462 0.68569 0.16021 1.58052 5.797 64.41
        7 SDSm 確率的拡散探索M 0.93066 0.85445 0.39476 2.17988 0.99983 0.89244 0.19619 2.08846 0.72333 0.61100 0.10670 1.44103 5.709 63.44
        8 BOAm ビリヤード最適化アルゴリズムM 0.95757 0.82599 0.25235 2.03590 1.00000 0.90036 0.30502 2.20538 0.73538 0.52523 0.09563 1.35625 5.598 62.19
        9 AAm アーチェリーアルゴリズムM 0.91744 0.70876 0.42160 2.04780 0.92527 0.75802 0.35328 2.03657 0.67385 0.55200 0.23738 1.46323 5.548 61.64
        10 ESG 社会集団の進化(joo) 0.99906 0.79654 0.35056 2.14616 1.00000 0.82863 0.13102 1.95965 0.82333 0.55300 0.04725 1.42358 5.529 61.44
        11 SIA 等方的焼きなまし(joo) 0.95784 0.84264 0.41465 2.21513 0.98239 0.79586 0.20507 1.98332 0.68667 0.49300 0.09053 1.27020 5.469 60.76
        12 BBO 生物地理学に基づく最適化 0.94912 0.69456 0.35031 1.99399 0.93820 0.67365 0.25682 1.86867 0.74615 0.48277 0.17369 1.40261 5.265 58.50
        13 ACS 人工協調探索 0.75547 0.74744 0.30407 1.80698 1.00000 0.88861 0.22413 2.11274 0.69077 0.48185 0.13322 1.30583 5.226 58.06
        14 DA 弁証法的アルゴリズム 0.86183 0.70033 0.33724 1.89940 0.98163 0.72772 0.28718 1.99653 0.70308 0.45292 0.16367 1.31967 5.216 57.95
        15 BHAm ブラックホールアルゴリズムM 0.75236 0.76675 0.34583 1.86493 0.93593 0.80152 0.27177 2.00923 0.65077 0.51646 0.15472 1.32195 5.196 57.73
        16 ASO 無政府社会最適化 0.84872 0.74646 0.31465 1.90983 0.96148 0.79150 0.23803 1.99101 0.57077 0.54062 0.16614 1.27752 5.178 57.54
        17 RFO ロイヤルフラッシュ最適化(joo) 0.83361 0.73742 0.34629 1.91733 0.89424 0.73824 0.24098 1.87346 0.63154 0.50292 0.16421 1.29867 5.089 56.55
        18 AOSm 原子軌道探索M 0.80232 0.70449 0.31021 1.81702 0.85660 0.69451 0.21996 1.77107 0.74615 0.52862 0.14358 1.41835 5.006 55.63
        19 TSEA 亀甲進化アルゴリズム(joo) 0.96798 0.64480 0.29672 1.90949 0.99449 0.61981 0.22708 1.84139 0.69077 0.42646 0.13598 1.25322 5.004 55.60
        20 DE 差分進化 0.95044 0.61674 0.30308 1.87026 0.95317 0.78896 0.16652 1.90865 0.78667 0.36033 0.02953 1.17653 4.955 55.06
        21 SRA レストラン経営達人アルゴリズム(joo) 0.96883 0.63455 0.29217 1.89555 0.94637 0.55506 0.19124 1.69267 0.74923 0.44031 0.12526 1.31480 4.903 54.48
        22 CRO 化学反応の最適化 0.94629 0.66112 0.29853 1.90593 0.87906 0.58422 0.21146 1.67473 0.75846 0.42646 0.12686 1.31178 4.892 54.36
        23 BIO 血液型遺伝最適化(joo) 0.81568 0.65336 0.30877 1.77781 0.89937 0.65319 0.21760 1.77016 0.67846 0.47631 0.13902 1.29378 4.842 53.80
        24 BSA 鳥群アルゴリズム 0.89306 0.64900 0.26250 1.80455 0.92420 0.71121 0.24939 1.88479 0.69385 0.32615 0.10012 1.12012 4.809 53.44
        25 HS ハーモニー検索 0.86509 0.68782 0.32527 1.87818 0.99999 0.68002 0.09590 1.77592 0.62000 0.42267 0.05458 1.09725 4.751 52.79
        26 SSG 苗木の播種と育成 0.77839 0.64925 0.39543 1.82308 0.85973 0.62467 0.17429 1.65869 0.64667 0.44133 0.10598 1.19398 4.676 51.95
        27 BCOm 細菌走化性最適化M 0.75953 0.62268 0.31483 1.69704 0.89378 0.61339 0.22542 1.73259 0.65385 0.42092 0.14435 1.21912 4.649 51.65
        28 ABO アフリカ水牛の最適化 0.83337 0.62247 0.29964 1.75548 0.92170 0.58618 0.19723 1.70511 0.61000 0.43154 0.13225 1.17378 4.634 51.49
        29 (PO)ES (PO)進化戦略 0.79025 0.62647 0.42935 1.84606 0.87616 0.60943 0.19591 1.68151 0.59000 0.37933 0.11322 1.08255 4.610 51.22
        30 FBA フラクタルベースのアルゴリズム 0.79000 0.65134 0.28965 1.73099 0.87158 0.56823 0.18877 1.62858 0.61077 0.46062 0.12398 1.19537 4.555 50.61
        31 TSm タブーサーチM 0.87795 0.61431 0.29104 1.78330 0.92885 0.51844 0.19054 1.63783 0.61077 0.38215 0.12157 1.11449 4.536 50.40
        32 BSO ブレインストーム最適化 0.93736 0.57616 0.29688 1.81041 0.93131 0.55866 0.23537 1.72534 0.55231 0.29077 0.11914 0.96222 4.498 49.98
        33 WOAm 鯨最適化アルゴリズムM 0.84521 0.56298 0.26263 1.67081 0.93100 0.52278 0.16365 1.61743 0.66308 0.41138 0.11357 1.18803 4.476 49.74
        34 AEFA 人工電界アルゴリズム 0.87700 0.61753 0.25235 1.74688 0.92729 0.72698 0.18064 1.83490 0.66615 0.11631 0.09508 0.87754 4.459 49.55
        35 AEO 人工生態系ベースの最適化アルゴリズム 0.91380 0.46713 0.26470 1.64563 0.90223 0.43705 0.21400 1.55327 0.66154 0.30800 0.28563 1.25517 4.454 49.49
        36 CAm ラクダアルゴリズムM 0.78684 0.56042 0.35133 1.69859 0.82772 0.56041 0.24336 1.63149 0.64846 0.33092 0.13418 1.11356 4.444 49.37
        37 ACOm 蟻コロニー最適化M 0.88190 0.66127 0.30377 1.84693 0.85873 0.58680 0.15051 1.59604 0.59667 0.37333 0.02472 0.99472 4.438 49.31
        38 BFO-GA 細菌採食の最適化:Ga 0.89150 0.55111 0.31529 1.75790 0.96982 0.39612 0.06305 1.42899 0.72667 0.27500 0.03525 1.03692 4.224 46.93
        39 SOA シンプル最適化アルゴリズム 0.91520 0.46976 0.27089 1.65585 0.89675 0.37401 0.16984 1.44060 0.69538 0.28031 0.10852 1.08422 4.181 46.45
        40 ABHA 人工蜂の巣アルゴリズム 0.84131 0.54227 0.26304 1.64663 0.87858 0.47779 0.17181 1.52818 0.50923 0.33877 0.10397 0.95197 4.127 45.85
        41 ACMO 大気雲モデルの最適化 0.90321 0.48546 0.30403 1.69270 0.80268 0.37857 0.19178 1.37303 0.62308 0.24400 0.10795 0.97503 4.041 44.90
        42 ADAMm 適応モーメント推定M 0.88635 0.44766 0.26613 1.60014 0.84497 0.38493 0.16889 1.39880 0.66154 0.27046 0.10594 1.03794 4.037 44.85
        43 CGO カオスゲーム最適化 0.57256 0.37158 0.32018 1.26432 0.61176 0.61931 0.62161 1.85267 0.37538 0.21923 0.19028 0.78490 3.902 43.35
        44 CROm サンゴ礁最適化M 0.78512 0.46032 0.25958 1.50502 0.86688 0.35297 0.16267 1.38252 0.63231 0.26738 0.10734 1.00703 3.895 43.27
        45 ATAm 人工部族アルゴリズムM 0.71771 0.55304 0.25235 1.52310 0.82491 0.55904 0.20473 1.58867 0.44000 0.18615 0.09411 0.72026 3.832 42.58
        ES イーグル戦略最適化 0.70776 0.43078 0.27475 1.41328 0.71737 0.34484 0.15973 1.22194 0.51846 0.27754 0.11063 0.90663 3.542 39.35
        RW ニューロボイド最適化アルゴリズム2(joo) 0.48754 0.32159 0.25781 1.06694 0.37554 0.21944 0.15877 0.75375 0.27969 0.14917 0.09847 0.52734 2.348 26.09


        まとめ

        ESアルゴリズムは、集団最適化ベンチマークにおいて平均的な成績にとどまり、最大可能スコアの39%を獲得しました。この結果により、上位45アルゴリズムへのランクインには至りませんでした。

        一方で、本アルゴリズムは依然として検討に値する手法です。その理由は、鷲の狩猟行動をモデル化した生物学的に着想を得た2段階探索という独自のコンセプトにあります。大域探索にレヴィ飛行を用いる手法は、ランダム探索問題に対して理論的な有効性と最適性が論じられている、数学的に美しいアプローチです。また、フェーズ間の動的切り替えや停滞時のパラメータ自動調整といった適応的メカニズムは、基本概念を改善する可能性を示しています。

        本アルゴリズムは、多峰性最適化問題やノイズの多いデータの存在下など、大域探索と局所探索のバランスが重要となる特定の問題領域において、有用性を持つ可能性があります。局所探索にホタルアルゴリズムを統合している点は、2つの自然由来メタヒューリスティックの興味深いシナジーを生み出していますが、全体性能としてはさらなるパラメータ最適化および内部機構の改良が必要であることを示しています。

        ESアルゴリズムは、異なるメタヒューリスティックを組み合わせたハイブリッド最適化手法の一例として、また将来的により高度な手法を設計するための基礎として位置づけることができます。その比較的シンプルな実装と直感的なロジックにより、進化計算分野の研究実験にも適しています。

        tab

        図2:対応するテストに応じたアルゴリズムのカラーグラデーション

        チャート

        図3:アルゴリズムテスト結果のヒストグラム(0から100のスケール、高いほど良い)100は理論上の最大値であり、アーカイブには評価表を計算するためのスクリプトがあります。

        ESの長所と短所

        長所

        1. 高速

        短所

        1. パラメータ数が多い

        この記事には、最新版のアルゴリズムコードを含むアーカイブが添付されています。記事の著者は、正統的なアルゴリズムの説明の絶対的な正確さについて責任を負いません。探索性能を向上させるために、それらの多くに変更が加えられています。記事に示された結論と判断は、実験結果に基づいています。


        記事で使用されているプログラム

        # 名前 種類 詳細
        1 #C_AO.mqh
        インクルード
        集団最適化アルゴリズムの親クラス
        2 #C_AO_enum.mqh
        インクルード
        集団最適化アルゴリズムの列挙
        3 TestFunctions.mqh
        インクルード
        テスト関数のライブラリ
        4
        TestStandFunctions.mqh
        インクルード
        テストスタンド関数ライブラリ
        5
        Utilities.mqh
        インクルード
        補助関数のライブラリ
        6
        CalculationTestResults.mqh
        インクルード
        比較表の結果を計算するスクリプト
        7
        Testing AOs.mq5
        スクリプト すべての集団最適化アルゴリズムの統一テストスタンド
        8
        Simple use of population optimization algorithms.mq5
        スクリプト
        可視化せずに集団最適化アルゴリズムを使用する簡単な例
        9
        Test_AO_ES.mq5
        スクリプト ESテストスタンド

        MetaQuotes Ltdによってロシア語から翻訳されました。
        元の記事: https://www.mql5.com/ru/articles/18460

        添付されたファイル |
        ES.zip (224.37 KB)
        MetaTrader 5における季節性に基づくFXスプレッド取引の有効性評価 MetaTrader 5における季節性に基づくFXスプレッド取引の有効性評価
        日足における季節性取引アプローチの有効性を検証します。対象は個別の金融商品およびスプレッドの両方であり、特に繰り返し現れる月次サイクルの特定と、それを現行年の取引へ応用する可能性に重点を置いています。
        PPPとIMFデータを用いた公正な為替レートの算出 PPPとIMFデータを用いた公正な為替レートの算出
        Pythonを用いた購買力平価(PPP)ベースの為替レート分析システムの構築。IMFデータを用いて、5つの方法によって理論為替レートを計算するアルゴリズムを開発しました。本記事は、ファンダメンタルな通貨分析、経済データの処理、トレードシステムとの統合に関する実践的なガイドです。完全なコードはオープンソースとして公開されています。
        初級から中級まで:関数ポインタ 初級から中級まで:関数ポインタ
        プログラミングにおいて「ポインタ」という概念について聞いたことがある方は多いと思います。しかし、MQL5でもこの種のデータを利用できることをご存じでしょうか。もちろん、これは実行時の挙動を適切に制御し、不可解な動作を回避できるよう慎重に扱う必要があります。ただし、この機能は非常に限定的な用途に向けたものであり、特定のタスクに特化しているため、MQL5におけるポインタの概念や使用方法について語られる機会はあまり多くありません。
        Pythonを用いたIMFデータの取得 Pythonを用いたIMFデータの取得
        PythonでIMFデータを取得する:マクロ経済に基づく通貨戦略に活用するためのIMF(国際通貨基金)データマイニング。マクロ経済は、一般のトレーダーおよびアルゴリズムトレーダーにどのように役立つのでしょうか。