English Русский 中文 Español Deutsch Português
preview
アーチェリーアルゴリズム(AA)

アーチェリーアルゴリズム(AA)

MetaTrader 5テスター |
126 2
Andrey Dik
Andrey Dik

内容

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


はじめに

タスクがますます複雑化し、利用可能なリソースが限られる中で、最適化は現代において単なる必要性を超え、真のアルゴリズム的芸術とも言える領域に達しています。数ある可能な解の中から最適解をどう導き出すか?コストを抑えつつ効率を高め、利益を最大化するにはどうすればよいか?こうした問いは、経済学から工学、社会システムから生態学に至るまで、さまざまな分野の専門家に共通する課題です。最適化問題を解くためには、まず現実を適切に再現できるよう、重要な変数や数学的関係を明確にして問題を正しくモデル化することが重要です。最適化は金融や取引の分野でも広く利用されており、新たな投資戦略の開発だけでなく、既存戦略の改善にも貢献しています。最適化手法は一般的に、「決定論的手法」と「確率論的手法」の2つに大別されます。

たとえば、勾配降下法のような決定論的手法は、数学的導関数を用いて最適解を厳密かつ予測可能に導き出すことが可能で、さまざまなシナリオを効率的にモデル化できます。しかし、問題が非線形であったり、多変数を含む場合には、その効果が大きく低下することもあります。そうした状況で活躍するのが確率論的手法です。これらはランダム性を利用して複雑な状況下でも妥当な解を見つけ出すことができ、特に市場のような不安定な環境では非常に有効です。

近年では、決定論的手法と確率論的手法を組み合わせるアプローチが主流となっています。この2つを融合することで、変化に柔軟に対応しつつも安定性を保てるモデルが構築でき、予測精度を向上させるだけでなく、リスクを最小限に抑えることも可能になります。これは、成功する投資管理にとって極めて重要です。

本稿では、最適化問題に対する新たなアプローチであるアーチェリーアルゴリズム(AA)を紹介します。このアルゴリズムは、Fatemeh Ahmadi Zeidabadiらによって開発され、2022年2月に発表されました。アーチェリーに着想を得たこの手法では、探索空間内における集団メンバーの位置を、ランダムに選ばれた要素に基づいて更新し、準最適な解を生成します。本記事では、AAの性能を標準的な目的関数を用いて検証し、既存のアルゴリズムと比較します。詳細な検討を通じて、この革新的なアプローチが最適化の概念にどのような変革をもたらすか、そして複雑な問題解決においてどのような可能性を切り開くかを探ります。


アルゴリズムの実装

アーチェリーアルゴリズム(AA)は、最適化問題に対して最適解を見つけることを目的として設計された、全く新しい確率的最適化手法です。このアルゴリズムは、的を狙って矢を放つ射手の行動に着想を得ており、矢を射るプロセスをシミュレートします。集団内の各メンバーは、最適化問題に対する潜在的な解を表しており、それぞれの探索空間内での位置は、ランダムに選ばれた「的」となるメンバーの性能に基づいて更新されます。これは、射手が狙いたい場所に応じて照準を調整するのと似ています。

集団は行列として表現され、各行がメンバー(解)に、各列が問題の次元に対応します。これにより、目的関数に基づいて解を体系的に評価・更新することが可能となります。各メンバーの性能は、解の良否を定量的に評価する目的関数によって評価され、その結果はベクトルとして格納されます。この評価により、異なる解の効率性を比較できるようになります。

的は、集団メンバーの生産性に応じた幅を持つセクションに分割されます。そして、各メンバーが選ばれる確率は目的関数値に基づいて計算され、性能の高いメンバーほど選ばれる確率が高くなります。選択は累積確率に基づいてランダムにおこなわれ、これにより射手がどの的を狙うかを模倣します。この選択結果が、他のメンバーの位置更新に影響を与えます。各射手(エージェント)の位置は、一定の更新式を用いて探索空間内で調整されます。この更新は、選択された射手の目的関数値が現在のものよりも優れているか否かによって異なり、ランダム性を伴うことで探索空間の幅広い範囲をカバーします。AAは反復的に動作し、最大反復数などの停止条件に達するまで集団の状態を更新し続けます。その過程で、アルゴリズムは最良解を常に記録し保持します。

アルゴリズムは、特定の方程式を使用して、検索空間内の各射手の位置を更新します。このAAアルゴリズムのオリジナルバージョンでは、集団を行列として、各メンバーをベクトルとして記述していますが、行列特有の操作が明示されているわけではありません。実際には、これまで紹介した多くのアルゴリズムと同様に、検索エージェントによる標準的な操作が用いられています。

また、「的は、生産性に応じた幅で区分される」という表現は、ルーレット選択法(ルーレット方式)を使用していることを意味しています。この方式では、セクション(扇形)の幅に比例して選ばれる確率が決まります。

このように、複雑な概念を簡素化しながらも本質を保った形で説明することで、アルゴリズムの実装がより容易になります。

つまり、アーチェリーアルゴリズムは、射撃の原理を取り入れた集団ベースの最適化手法であり、ランダム性と正規分布を組み合わせて探索空間を「探索」と「活用」の両面から効率的に探索します。アルゴリズムの主な構成要素:

1. エージェント(射手)の集団
2. 確率のベクトルと累積確率
3. 継承メカニズム(オリジナルバージョンには存在しない)
4. 位置更新メカニズム
5. 訓練強度パラメータ(I)

まず、アルゴリズムの疑似コードを示します。

初期化
    popSizeエージェントの集団を作成する
    各エージェントについて:
        検索範囲内でランダムな位置を初期化する
        以前の位置と適応度を初期化する

メインループ
    停止条件に達するまで:
        集団内の各iエージェントについて:
            確率Pと累積確率Cのベクトルを計算する
            
            各c座標について:
                累積確率を使用してk射手を選択する
                
                (乱数<継承確率)の場合:
                    new_position [c] = k_archer_position [c]
                そうでない場合:
                    I = rounding (1 + random_number_from_0_to_1)  // 訓練強度パラメータ
                    random_gaussian = generate_gaussian_number (mean = 0, min =-1, max = 1)
                    
                    (k_archer_fitness>i_agent_fitness)の場合:
                        new_position [c] = previous_position [c] + random_gaussian * (k_archer_position [c] - I * previous_position [c])
                    そうでない場合:
                        new_position [c] = previous_position [c] + random_gaussian * (previous_position [c] - I * k_archer_position [c])
                
                検索範囲内でnew_position[c]を制限する
            
            エージェントiのポジションを更新する
        
        すべてのエージェントの適応度を評価する
        大域的最適解を更新する
        各エージェントについて:
            新しい適応度が以前のものより優れている場合:
                以前の位置と適応度を更新する

見つかった最適解を返す

コード内の実装機能

1. アルゴリズムは、学習対象となる射手(アーチャー)を確率的に選択します。
2. 継承メカニズムにより、エージェントは成功した射手の位置をある確率で直接コピーすることができます。
3. 位置の更新時には、ガウス分布を用いてランダム性を導入し、射手の学習プロセスに多様性をもたらします。
4. アルゴリズムはエージェントの過去の最良位置を記憶し、有効な意思決定の「記憶」として活用します。
5. 新しい位置が許容された探索範囲内に収まるよう制限をかけるメカニズムが実装されています。
6. 著者によって提案された「訓練強度」パラメータ(I)は、新しい位置に対する現在位置の影響度を調整するために用いられます。

Iパラメータ(訓練強度)は、1または2のいずれかの値をとるランダム変数であり、以下のように定義されます。I = 1 + [0~1のランダムな値] を最も近い整数に丸めたもの。つまり、Iは0.5の確率で1、同じく0.5の確率で2になります。アルゴリズムにおける I の役割:

1. I = 1のとき、アルゴリズムは位置を小さく調整します。
2. I = 2のとき、位置により大きな変化を与えることができます。

アルゴリズムのコードに移りましょう。射手構造体S_AA_Agentについて説明します。アルゴリズムのエージェントを表しており、適応度関数に基づくパフォーマンスに関する情報も含まれます。 

  • cPrev[]配列には前のエージェントの座標が格納される
  • fPrev変数にはエージェントの適応度の前の値が格納される   

Initメソッドは、エージェントの座標および適応度の初期値を設定して、アルゴリズム実行の準備をおこないます。このとき、fPrevには適応度がまだ評価されていないため、double型で取りうる最小値が設定されます。

//——————————————————————————————————————————————————————————————————————————————
struct S_AA_Agent
{
    double cPrev []; // previous coordinates
    double fPrev;    // previous fitness

    void Init (int coords)
    {
      ArrayResize (cPrev, coords);
      fPrev = -DBL_MAX;
    }
};
//——————————————————————————————————————————————————————————————————————————————

アルゴリズム自体を実装し、C_AOクラスから継承されたC_AO_AAmクラスを見てみましょう。 

  • popSize:集団のサイズ
  • inhProbab:別の射手から特徴量を継承する確率

次に、params配列がサイズ2で初期化され、そこにアルゴリズムパラメータ(集団サイズと継承確率)が格納されます。

  • SetParamsメソッドは、params配列に格納されている値に基づいてパラメータを設定します。popSizeinhProbabの値を抽出し、適切な型に変換します。
  • Initメソッドは、最小および最大の検索境界、検索ステップ、およびエポック数を受け入れることでアルゴリズムを初期化します。
  • MovingメソッドとRevisionメソッドは、解空間内でエージェントを移動するロジックと、エージェントを修正(更新)するロジックを担当します。 

S_AA_Agent agent []:最適化を実行するために使用されるエージェントの配列

C_AO_AAmクラスは最適化アルゴリズムを実装し、SetParamsInitMovingRevisionは操作中のアルゴリズムの構成と動作を管理します。 

//——————————————————————————————————————————————————————————————————————————————
class C_AO_AAm : public C_AO
{
  public: //--------------------------------------------------------------------
  ~C_AO_AAm () { }
  C_AO_AAm ()
  {
    ao_name = "AAm";
    ao_desc = "Archery Algorithm M";
    ao_link = "https://www.mql5.com/ja/articles/15782";

    popSize   = 50;    // population size
    inhProbab = 0.3;

    ArrayResize (params, 2);

    params [0].name = "popSize";   params [0].val = popSize;
    params [1].name = "inhProbab"; params [1].val = inhProbab;
  }

  void SetParams ()
  {
    popSize   = (int)params [0].val;
    inhProbab = params      [1].val;
  }

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

  void Moving ();
  void Revision ();

  //----------------------------------------------------------------------------
  double  inhProbab; //probability of inheritance

  S_AA_Agent agent [];

  private: //-------------------------------------------------------------------
};
//——————————————————————————————————————————————————————————————————————————————

C_AO_AAmクラスのInitメソッドは、最適化アルゴリズムの初期化を担当します。このメソッドは、探索範囲の最小値と最大値を格納した配列、探索ステップ幅、エポック数(デフォルトでは0)の4つのパラメータを受け取ります。

  • 標準的な初期化が成功すると、agentの配列が指定されたpopSize(個体数)に応じてリサイズされます。これにより、アルゴリズムで使用する必要な数のエージェントを生成することが可能になります。
  • forループでは、配列の各エージェントがInitメソッドを使用して初期化され、各エージェントの初期座標が指定されます。

最後に、メソッドはtrueを返し、アルゴリズムの初期化が正常に完了したことを示します。したがって、Initメソッドは、必要なパラメータを設定し、最適化に参加するエージェントを作成することによって、アルゴリズムが操作の準備が整っていることを確認します。

//——————————————————————————————————————————————————————————————————————————————
bool C_AO_AAm::Init (const double &rangeMinP  [],
                     const double &rangeMaxP  [],
                     const double &rangeStepP [],
                     const int     epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //----------------------------------------------------------------------------
  ArrayResize (agent, popSize);
  for (int i = 0; i < popSize; i++) agent [i].Init (coords);

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

C_AO_AAmクラスのMovingメソッドは、エージェントの現在の位置と最適化している関数の値に基づいて、エージェントを解空間内で移動させます。それをいくつかの部分に分解してみましょう。

  • メソッドが初めて呼び出された場合(revisionfalseに等しい場合)、各エージェントおよび各座標に対して、指定されたrangeMinおよびrangeMaxの境界内でランダム値が初期化されます。
  • 次に、この値はSeInDiSpメソッドを使用して調整され、値が指定されたステップと一致することが保証されます。

その後、revisionフラグがtrueに設定され、メソッドは作業を完了します。

  • 次に2つの配列が作成されます。Pは確率、Cは累積確率を表します。
  • 関数の最悪値であるF_worstは、エージェントの適応度関数の値を正規化するために求められます。
  • 次に、各エージェントの確率が計算され、合計が1になるように正規化されます。
  • C累積確率はP確率に基づいて計算されます。
  • 各エージェントおよび各座標に対して、累積確率に基づいてパートナー射手(エージェント)が選択されます。
  • ランダム値が指定されたinhProbab継承確率より小さい場合、エージェントは選択されたエージェントの座標を受け入れます(指定された確率で機能の継承が保証されます)。
  • それ以外の場合、エージェントは現在の位置、ランダム値、およびパートナーの射手の位置を考慮した方程式に基づいて位置を更新します。
  • 最後に、SeInDiSpメソッドを使用して新しい座標値も調整されます。

Movingメソッドは、エージェントの現在の位置と関数値を考慮して解空間内でのエージェントの移動を実装し、確率的手法を使用して移動方向を選択し、位置を更新します。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_AAm::Moving ()
{
  //----------------------------------------------------------------------------
  if (!revision)
  {
    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]);
      }
    }
    revision = true;
    return;
  }

  //-------------------------------------------------------------------------
  // Calculate probability vector P and cumulative probability C
  double P [], C [];
  ArrayResize (P, popSize);
  ArrayResize (C, popSize);
  double F_worst = DBL_MAX;
  double sum = 0;

  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f < F_worst) F_worst = a [i].f;
  }

  for (int i = 0; i < popSize; i++)
  {
    P [i] =  a [i].f - F_worst;
    sum += P [i];
  }

  for (int i = 0; i < popSize; i++)
  {
    P [i] /= sum;
    C [i] = (i == 0) ? P [i] : C [i - 1] + P [i];
  }

  double x;

  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Select archer (k) using cumulative probability
      int k = 0;
      double r = u.RNDprobab ();
      while (k < popSize - 1 && C [k] < r) k++;

      if (u.RNDbool () < inhProbab)
      {
        x = a [k].c [c];
      }
      else
      {
        // Update position using Eq. (5) and (6)
        double I   = MathRound (1 + u.RNDprobab ());
        double rnd = u.GaussDistribution (0, -1, 1, 8);

        if (a [k].f > a [i].f)
        {
          x = agent [i].cPrev [c] + rnd * (a [k].c [c] - I * agent [i].cPrev [c]);
        }
        else
        {
          x = agent [i].cPrev [c] + rnd * (agent [i].cPrev [c] - I * a [k].c [c]);
        }
      }

      a [i].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_AAmクラスのRevisionメソッドは、集団内の最適なエージェントに関する情報を更新する役割を担います。このメソッドでは次をおこないます。

  • ind変数は-1で初期化されます。これは、最高の関数値を持つエージェントのインデックスを格納するために使用されます。
  • forループはpopSize集団内のすべてのエージェントを反復処理し、現在のエージェント関数a[i].fの値がfB関数の現在の最適値を超えている場合は次のようになります。
    • fBa[i].fの新しいより良い値に更新されます。
    • このエージェントのインデックスはind変数に格納されます。
ループが完了した後、indが-1と等しくない場合は、ArrayCopy関数が呼び出され、最適なエージェントの座標をa配列からcB配列にコピーします。2番目のforループも、集団内のすべてのエージェントを反復処理します。

  • 現在のエージェント関数a[i].fの値が、以前のエージェント[i].fPrevの適応度関数値を超えた場合
    • エージェントの以前のfPrevの値が更新されます。
    • エージェントの現在の座標は、ArrayCopyを使用してcPrev配列にコピーされます。

Revisionメソッドは、最適な大域解に関する情報を更新し、エージェントの最適な位置を更新するために役立ちます。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_AAm::Revision ()
{
  //----------------------------------------------------------------------------
  int ind = -1;

  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ind = i;
    }
  }

  if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY);

  //----------------------------------------------------------------------------
  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > agent [i].fPrev)
    {
      agent [i].fPrev = a [i].f;
      ArrayCopy (agent [i].cPrev, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————


テスト結果

アルゴリズムにいくつかの改良を加えました。元のアルゴリズムでは、射手同士が直接情報を交換する仕組みはありません。情報のやり取りは、正規分布を介した座標の相互作用によって間接的におこなわれます。このため、射手間での直接的な情報交換を導入する必要があると考えました。その目的で、特定の確率で情報交換を実行するためのinhProbabアルゴリズムを追加しました。

if (u.RNDbool () < inhProbab)
{
  x = a [k].c [c];
}

以下に示す結果は、著者が意図したアルゴリズムのオリジナルバージョンに対応しています。

AA|Archery Algorithm|50.0|
=============================
5 Hilly's; Func runs:10000; result:0.6699547926310098
25 Hilly's; Func runs:10000; result:0.37356238340164605
500 Hilly's; Func runs:10000; result:0.257542163368952
=============================
5 Forest's; Func runs:10000; result:0.38166669771790607
25 Forest's; Func runs:10000; result:0.199300365268835
500 Forest's; Func runs:10000; result:0.15337954055780398
=============================
5 Megacity's; Func runs:10000; result:0.4076923076923077
25 Megacity's; Func runs:10000; result:0.17907692307692308
500 Megacity's; Func runs:10000; result:0.10004615384615476
=============================
All score:2.72222 (30.25%)

このアルゴリズムはテストで30.25%のスコアを獲得しましたが、私が変更を加えると、アルゴリズムのパフォーマンスは13%以上向上しました。以下は、修正版の結果です。

AAm|Archery Algorithm M|50.0|0.3|
=============================
5 Hilly's; Func runs:10000; result:0.9353194829441194
25 Hilly's; Func runs:10000; result:0.6798262991897616
500 Hilly's; Func runs:10000; result:0.2596620178276653
=============================
5 Forest's; Func runs:10000; result:0.5735062785421186
25 Forest's; Func runs:10000; result:0.22007188891556378
500 Forest's; Func runs:10000; result:0.1486980566819649
=============================
5 Megacity's; Func runs:10000; result:0.6307692307692309
25 Megacity's; Func runs:10000; result:0.344
500 Megacity's; Func runs:10000; result:0.10193846153846249
=============================
All score:3.89379 (43.26%)

そこで、修正を加えたアルゴリズムを選択し、評価表に追加しました。以下にアルゴリズムの視覚化を示します。かなり良いと思います。もちろん、結果にはばらつきがありますが、それは重大なものではなく、座標数が少ない関数の場合にのみ発生します。

Hilly

Hillyテスト関数のAAm

Forest

Forestテスト関数のAAm

Megacity

Megacityテスト関数のAAm

動作結果によると、アルゴリズムの修正バージョンは26位を占めています。

# AO 詳細 HillyHilly最終 ForestForest最終 Megacity(離散)Megacity最終 最終結果 MAXの%
10p(5F)50p(25F)1000p(500F)10p(5F)50p(25F)1000p(500F)10p(5F)50p(25F)1000p(500F)
1ANSacross neighbourhood search0.949480.847760.438572.235811.000000.923340.399882.323230.709230.634770.230911.574916.13468.15
2CLAコードロックアルゴリズム0.953450.871070.375902.200420.989420.917090.316422.222940.796920.693850.193031.683806.10767.86
3AMOm動物移動最適化m0.903580.843170.462842.209590.990010.924360.465982.380340.567690.591320.237731.396755.98766.52
4(P+O)ES(P+O)進化戦略0.922560.881010.400212.203790.977500.874900.319452.171850.673850.629850.186341.490035.86665.17
5CTA彗尾アルゴリズム0.953460.863190.277702.094350.997940.857400.339492.194840.887690.564310.105121.557125.84664.96
6SDSm確率的拡散探索M0.930660.854450.394762.179880.999830.892440.196192.088460.723330.611000.106701.441035.70963.44
7ESG社会母集団の進化0.999060.796540.350562.146161.000000.828630.131021.959650.823330.553000.047251.423585.52961.44
8SIA等方的焼きなまし0.957840.842640.414652.215130.982390.795860.205071.983320.686670.493000.090531.270205.46960.76
9ACS人工協調探索0.755470.747440.304071.806981.000000.888610.224132.112740.690770.481850.133221.305835.22658.06
10ASO無政府社会最適化0.848720.746460.314651.909830.961480.791500.238031.991010.570770.540620.166141.277525.17857.54
11TSEA亀甲進化アルゴリズム0.967980.644800.296721.909490.994490.619810.227081.841390.690770.426460.135981.253225.00455.60
12DE差分進化0.950440.616740.303081.870260.953170.788960.166521.908650.786670.360330.029531.176534.95555.06
13CRO化学反応の最適化0.946290.661120.298531.905930.879060.584220.211461.674730.758460.426460.126861.311784.89254.36
14BSA鳥群アルゴリズム0.893060.649000.262501.804550.924200.711210.249391.884790.693850.326150.100121.120124.80953.44
15HSハーモニー検索0.865090.687820.325271.878180.999990.680020.095901.775920.620000.422670.054581.097254.75152.79
16SSG苗木の播種と育成0.778390.649250.395431.823080.859730.624670.174291.658690.646670.441330.105981.193984.67651.95
17BCOm細菌走化性最適化M0.759530.622680.314831.697040.893780.613390.225421.732590.653850.420920.144351.219124.64951.65
18(PO)ES(PO)進化戦略0.790250.626470.429351.846060.876160.609430.195911.681510.590000.379330.113221.082554.61051.22
19TSmタブーサーチM0.877950.614310.291041.783300.928850.518440.190541.637830.610770.382150.121571.114494.53650.40
20BSOブレインストーム最適化0.937360.576160.296881.810410.931310.558660.235371.725340.552310.290770.119140.962224.49849.98
21WOAm鯨最適化アルゴリズムM0.845210.562980.262631.670810.931000.522780.163651.617430.663080.411380.113571.188034.47649.74
22AEFA人工電界アルゴリズム0.877000.617530.252351.746880.927290.726980.180641.834900.666150.116310.095080.877544.45949.55
23ACOm蟻コロニー最適化M0.881900.661270.303771.846930.858730.586800.150511.596040.596670.373330.024720.994724.43849.31
24BFO-GA細菌採食の最適化:Ga0.891500.551110.315291.757900.969820.396120.063051.428990.726670.275000.035251.036924.22446.93
25ABHA人工蜂の巣アルゴリズム0.841310.542270.263041.646630.878580.477790.171811.528180.509230.338770.103970.951974.12745.85
26AAmアーチェリーアルゴリズムM0.935320.679830.259661.874810.573510.220070.148700.942280.630770.344000.101941.076713.89443.26
27ASBO適応型社会行動最適化(ASBO)0.763310.492530.326191.582020.795460.400350.260971.456770.264620.171690.182000.618313.65740.63
28MECmind evolutionary computation0.695330.533760.326611.555690.724640.330360.071981.126980.525000.220000.041980.786983.47038.55
29IWO侵入雑草最適化0.726790.522560.331231.580580.707560.339550.074841.121960.423330.230670.046170.700173.40337.81
30Micro-AIS微小人工免疫系0.795470.519220.308611.623300.729560.368790.093981.192330.376670.158670.028020.563353.37937.54
31COAmカッコウ最適化アルゴリズムM0.758200.486520.313691.558410.740540.280510.055991.077040.505000.174670.033800.713473.34937.21
32SDOm螺旋ダイナミクス最適化M0.746010.446230.296871.489120.702040.346780.109441.158260.428330.167670.036630.632633.28036.44
33NMmネルダー=ミード法M0.738070.505980.313421.557470.636740.283020.082211.001970.446670.186670.040280.673623.23335.92
34FAmホタルアルゴリズムM0.586340.472280.322761.381380.684670.374390.109081.168140.286670.164670.047220.498553.04833.87
35GSA重力探索法0.647570.491970.300621.440160.539620.363530.099451.002600.326670.122000.019170.467832.91132.34
36BFO細菌採餌最適化0.611710.432700.313181.357590.544100.215110.056760.815970.421670.138000.031950.591622.76530.72
37ABC人工蜂コロニー0.633770.424020.308921.366710.551030.218740.056230.826000.340000.142000.031020.513022.70630.06
38BAコウモリアルゴリズム0.597610.459110.352421.409150.403210.193130.071750.668100.210000.101000.035170.346172.42326.93
39AAA藻類適応アルゴリズム0.500070.320400.255251.075720.370210.222840.167850.760890.278460.148000.097550.524022.36126.23
40SA焼きなまし0.557870.421770.315491.295130.349980.152590.050230.552800.311670.100330.028830.440832.28925.43
41IWDmintelligent water drops M0.545010.378970.301241.225220.461040.147040.043690.651770.258330.097000.023080.378422.25525.06
42PSO粒子群最適化0.597260.369230.299281.265770.372370.163240.070100.605720.256670.080000.021570.358232.23024.77
43ボイドボイドアルゴリズム0.433400.305810.254250.993460.357180.201600.157080.715860.278460.142770.098340.519572.22924.77
44MAモンキーアルゴリズム0.591070.426810.318161.336040.311380.140690.066120.518190.228330.085670.027900.341902.19624.40
45SFLshuffled frog-leaping0.539250.358160.298091.195510.371410.114270.040510.526180.271670.086670.024020.382352.10423.38



まとめ

本稿では、アルゴリズムの2つのバージョン、すなわちオリジナル版と、若干の変更を加えた修正版を提示しました。修正版はわずかな改良でありながら、パフォーマンスの大幅な向上を実現しています。この記事を通じて、アルゴリズムのロジックに小さな調整を加えるだけでも、さまざまなタスクにおいて効率性が著しく向上する可能性があることを明確に示しました。また、アルゴリズムの説明が過度に複雑であると、仕組みの理解が困難になり、それが改善の妨げとなることも浮き彫りになりました。これに対し、複雑な概念を平易な言葉で表現することにより、より効率的で実用的な解決策への道が開かれることが確認されました。

Tab

図1:関連するテストに応じたアルゴリズムの色勾配結果は0.99は白で強調表示されます

チャート

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


記事の出版準備がほぼ整った段階で、私はあるアイデアを思いつき、試してみることにしました。著者が「ルーレット方式」を用いて的と射手を選択するという論理に基づき、見つかった解の品質に反比例して的のサイズ自体を変化させるという手法です。解の質が高ければ、その周辺を重点的に探索して改善を図るべきです。一方、得られた結果があまり有望でない場合は、探索範囲を広げて新たな可能性のある領域を見つける必要があります。

目標

図3:標的に命中する矢の数は標的自体の質に正比例し、標的の大きさはその質に反比例する 

的の品質に反比例して的を増やすというアイデアを採用したコードを見てみましょう。

void C_AO_AAm::Moving ()
{
  //----------------------------------------------------------------------------
  if (!revision)
  {
    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]);
      }
    }
    revision = true;
    return;
  }

  //-------------------------------------------------------------------------
  // Calculate probability vector P and cumulative probability C
  double P [], C [];
  ArrayResize (P, popSize);
  ArrayResize (C, popSize);
  double F_worst = DBL_MAX; // a[ArrayMaximum(a, WHOLE_ARRAY, 0, popSize)].f;
  double sum = 0;

  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f < F_worst) F_worst = a [i].f;
  }

  for (int i = 0; i < popSize; i++)
  {
    P [i] =  a [i].f - F_worst; ////F_worst - a[i].f;
    sum += P [i];
  }

  for (int i = 0; i < popSize; i++)
  {
    P [i] /= sum;
    C [i] = (i == 0) ? P [i] : C [i - 1] + P [i];
  }

  double x;
  
  double maxFF = fB;
  double minFF = DBL_MAX;
  double prob1;
  double prob2;
  
  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f < minFF) minFF = a [i].f;
  } 

  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Select archer (k) using cumulative probability
      int k = 0;
      double r = u.RNDprobab ();
      while (k < popSize - 1 && C [k] < r) k++;

      if (u.RNDbool () < inhProbab)
      {
        x = a [k].c [c];
      }
      else
      {
        
        // Update position using Eq. (5) and (6)
        //double I   = MathRound (1 + u.RNDprobab ());
        double rnd = u.GaussDistribution (0, -1, 1, 8);
        /*
        if (a [k].f > a [i].f)
        {
          x = agent [i].cPrev [c] + rnd * (a [k].c [c] - I * agent [i].cPrev [c]);
        }
        else
        {
          x = agent [i].cPrev [c] + rnd * (agent [i].cPrev [c] - I * a [k].c [c]);
        }
        */
        
        prob1 = u.Scale (a [i].f, minFF, maxFF, 0, 1);
        prob2 = u.Scale (a [k].f, minFF, maxFF, 0, 1);
        
        x = agent [i].cPrev [c] + rnd * (a [k].c [c] - agent [i].cPrev [c]) * (1 - prob1 - prob2);  
        
      }

      a [i].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//—

1. 元のバージョンのコメントセクションでは、条件構文if-elseを使用して、エージェントの位置を更新する方法を決定していました。このロジックは削除され、新しい計算に置き換えられました。

2. 3行の新しいコード:

prob1 = u.Scale(a[i].f, minFF, maxFF, 0, 1);
prob2 = u.Scale(a[k].f, minFF, maxFF, 0, 1);

x = agent[i].cPrev[c] + rnd * (a[k].c[c] - agent[i].cPrev[c]) * (1 - prob1 - prob2);

これらの行は、更新された位置を計算するための新しいアプローチを導入します。

a) 2つの確率値(prob1prob2)は、Scale関数を使用して計算されます。この関数は、minFFmaxFFの最小および最大適合度値に基づいて、iおよびkエージェントの適合度値を0から1の範囲で正規化します。

b) 次に、これらの確率を使用して新しいx位置が計算されます。エージェントのi番目の前の位置[i].cPrev[c]、エージェントのk番目の位置[k].c[c]、選択された射手およびrndランダム係数を使用します。

c) ここで、動きは、両方のエージェントの適応度値の合計から1を引いた値によって影響を受けます。この係数はスケーリング係数として機能し、選択した射手の適応度に反比例して的を拡大または縮小することができます。射手の経験が少ないほど、矢の広がりは大きくなりますが、標的に命中する確率の分布は依然として正規分布に従います。

それでは結果を見てみましょう。

AAm|Archery Algorithm M|50.0|0.3|
=============================
5 Hilly's; Func runs:10000; result:0.9174358826544864
25 Hilly's; Func runs:10000; result:0.7087620527831496
500 Hilly's; Func runs:10000; result:0.42160091427958263
=============================
5 Forest's; Func runs:10000; result:0.9252690259821034
25 Forest's; Func runs:10000; result:0.7580206359203926
500 Forest's; Func runs:10000; result:0.353277934084795
=============================
5 Megacity's; Func runs:10000; result:0.6738461538461538
25 Megacity's; Func runs:10000; result:0.552
500 Megacity's; Func runs:10000; result:0.23738461538461658
=============================
All score:5.54760 (61.64%)

アルゴリズムのパフォーマンスが大幅に向上しました。以下の視覚化では、アルゴリズムの確実な収束と関数表面の重要な領域の識別を確認できます。

Hilly2

Hillyテスト関数のAAm

もう1つ小さな実験をしてみましょう。上記の結果は、射手の確率の合計を1から引くことによって得られます。

//x = agent [i].cPrev [c] + rnd * (a [k].c [c] - agent [i].cPrev [c]) * (1 - prob1 - prob2); 
 x = agent [i].cPrev [c] + rnd * (a [k].c [c] - agent [i].cPrev [c]) * (2 - prob1 - prob2);  

主な変更点は、合計が1からではなく2から引かれることです。このような単純なアクションがアルゴリズムの動作にどのような影響を与えるかを見てみましょう。

  • 以前のバージョンでは、両方の射手の適応度が高かった場合、この操作の結果がマイナスになる可能性があり、新しい射手の結果の座標に「突然変異」効果が生じていました。
  • 新しいバージョンでは、乗数は0から2までの値を提供します。

この変更により、エージェントは位置の更新ごとにより大きなステップを踏むため、より広範囲に移動し、解空間をより積極的に探索することになります。

したがって、アルゴリズムの結果のプリントアウトからわかるように、この変更により、中次元関数でのアルゴリズムの収束は改善されましたが、高次元関数(黄色でマーク)では収束が悪化しました。ただし、全体としては、アルゴリズムの最終スコアは高くなりました。

AAm|Archery Algorithm M|50.0|0.3|
=============================
5 Hilly's; Func runs:10000; result:0.9053229410164233
25 Hilly's; Func runs:10000; result:0.8259118221071665
500 Hilly's; Func runs:10000; result:0.2631661675236262
=============================
5 Forest's; Func runs:10000; result:0.9714247249319152
25 Forest's; Func runs:10000; result:0.9091052022399436
500 Forest's; Func runs:10000;結果:0.2847632249786224
=============================
5 Megacity's; Func runs:10000; result:0.7169230769230768
25 Megacity's; Func runs:10000; result:0.6378461538461538
500 Megacity's; Func runs:10000; result:0.10473846153846252
=============================
All score:5.61920(62.44%)

以前の結果はより実用的であるように思われ、AAmアルゴリズムの修正バージョンの主なバリエーションとして残ります。もう一度、温度グラデーションによる評価表を紹介します。AAmは現在、立派な7位を占めています。このアルゴリズムは非常にバランスが取れている(異なる次元の関数に対する収束が良好)という特徴があり、さまざまな問題を解決するために推奨できます。

タブ2

図4:関連するテストに応じたアルゴリズムの色勾配結果は0.99は白で強調表示されます

AAmの長所と短所:

長所

  1. かなり早い
  2. 自己適応性
  3. 外部パラメータは1つだけ
  4. 優れた収束
  5. 優れたスケーラビリティ
  6. シンプルな実装(著者による複雑な説明にもかかわらず)

短所

  1. 低次元関数で行き詰まる傾向がややある

評価表にさらに新しいアルゴリズムを追加していくと、可読性が低下する恐れがあります。そのため、評価対象のアルゴリズム数は最大45個に制限し、現在は「ノックアウト方式」でコンテストを実施しています。読者が視覚的にわかりやすく、すべての記事へ簡単にアクセスできるよう、これまでにレビューされたアルゴリズムを評価順に並べたHTMLファイルを用意しました。このファイルは、記事アーカイブ内にすでに含まれており、初めて開く方にはちょっとした「お楽しみ」も用意されています。

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

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

添付されたファイル |
AAm.zip (35.89 KB)
最後のコメント | ディスカッションに移動 (2)
Ilya Melamed
Ilya Melamed | 13 9月 2024 において 18:11
ご研究ありがとうございます。しかし、私はmql5のExpert Advisorの単純なプログラマーとして非常に単純な質問があります(私は数学者ではありません)。くだらないと思われるかもしれませんが、あらかじめお詫びします。それでも、あなたの研究はEAの最適 化にどのように役立つのでしょうか?例を挙げてください。例えば、新しいEAがあり、それを最適化したいとします。ありがとうございます。
Andrey Dik
Andrey Dik | 14 9月 2024 において 18:23
Ilya Melamed EAの最適 化にどのように役立つのでしょうか?例を挙げてください。例えば、新しいEAがあり、それを最適化したいとします。ありがとうございます。

私の研究に興味を持っていただき、ありがとうございます。

最適化アルゴリズムを適用するシナリオはたくさんあります。

例えば、ここに 書かれているように、EAの自己最適化に適用することができます。

また、ここで 説明されているように、社内テスターの最適化管理の一部として使用することもできます。

PythonとMQL5における局所的特徴量選択の適用 PythonとMQL5における局所的特徴量選択の適用
この記事では、Narges Armanfardらの論文「Local Feature Selection for Data Classification」で提案された特徴量選択アルゴリズムを紹介します。このアルゴリズムはPythonで実装されており、MetaTrader 5アプリケーションに統合可能なバイナリ分類モデルの構築に使用されます。
インジケーターを便利に扱うためのシンプルなソリューション インジケーターを便利に扱うためのシンプルなソリューション
この記事では、チャート上からインジケーターの設定を直接変更できるシンプルなパネルの作成方法と、そのパネルをインジケーターに接続するために必要な変更点について解説します。この記事はMQL5初心者向けに書かれています。
初級から中級へ:SWITCH文 初級から中級へ:SWITCH文
この記事では、SWITCH文の最も基本的かつシンプルな使い方について学びます。ここで提示されるコンテンツは、教育目的のみを目的としています。いかなる状況においても、提示された概念を学習し習得する以外の目的でアプリケーションを閲覧することは避けてください。
取引におけるニューラルネットワーク:点群用Transformer (Pointformer) 取引におけるニューラルネットワーク:点群用Transformer (Pointformer)
この記事では、点群におけるオブジェクト検出問題を解決するためのアテンションを用いたアルゴリズムについて解説します。点群におけるオブジェクト検出は、多くの現実世界の応用において極めて重要です。