English Русский 中文 Español Deutsch Português
preview
雲モデル最適化(ACMO):実践編

雲モデル最適化(ACMO):実践編

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

内容

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


はじめに

テクノロジーと自然が交差する科学の世界において、複雑な問題を最適化するためのメタヒューリスティック手法として、ACMO(大気雲モデル最適化)アルゴリズムというユニークな発想が登場しました。前回の記事では、さまざまな気象パラメータに基づいて、大気中における雲の形成と移動のプロセスをモデル化するアルゴリズムの実装を技術的に解析しました。初回は、雲シミュレーションを管理するクラスを作成し、初期化、雲の移動、領域プロパティの更新などの処理をおこなう各種メソッドを実装しました。

検索空間を複数の領域に分割し、それぞれの領域における初期の湿度と気圧を設定しました。また、初期エントロピー、ハイパーエントロピー、雲形成に必要な湿度の閾値など、モデルの各種パラメータを定義しました。次のステップとして、湿度の高い領域を選択して雲を生成し、雲の中心、エントロピー、およびハイパーエントロピーを計算しました。さらに、雲生成後の領域における湿度と気圧の気象パラメータを更新し、雲が低気圧領域へ移動する処理や、領域間の移動・拡散に応じて雲の特性を動的に更新する仕組みも実装しました。 

次にやるべきことは何でしょうか。今後の実装としては、水滴のランダムな配置や、それらを雲に分配する関数の実装、降雨プロセスの完了、および大域解の更新が必要です。また、さまざまなパラメータを用いてテスト関数上で本モデルを評価し、その性能と精度を検証することも求められます。さらに、集団内の有望な領域に関する情報をより完全に交換できるようにするため、雨と水滴生成のプロセスに変更を加えていく予定です。


アルゴリズムの実装

気象プロセス全体を擬似コードの形式で記述し、それに基づいてアルゴリズムの最終バージョンを組み立てられるようにします。

1. 最初のエポックでは、雲はランダムに配置されます。
   EnCk = EnM0;
   HeCk = HeM0;
//--------------------------------------------------------------------------------
1.1 低気圧領域に向かう雲の移動
   β = deltaP / normP
   d = Tck.x - Cck.c
   VC = β * d;
   Ck = Ck + VC

   移動後の水滴数の変化
   nk = nk × (1 - γ)

   エントロピーとハイパーエントロピーの変化
   α = ΔP / ΔPmax;
   EnCk = EnCk * (1 + α)
   HeCk = HeCk * (1 - α)
//--------------------------------------------------------------------------------
2. 雨が降る過程、雨滴が落ちる過程:
   雲間の水滴の分布はその領域の湿度に比例
   雲中に存在する水滴の数は増加
//--------------------------------------------------------------------------------
3. 水滴の適応度関数を計算します。
//--------------------------------------------------------------------------------
4. 降水量が降った領域における大域解と最低気圧を更新します。
//--------------------------------------------------------------------------------
5. 閾値を超える領域で、雲の減衰と、減衰した雲を置き換える新しい雲の生成を確認します。
   許容値を超える膨張による崩壊の規則(雲の破裂):
   En > 5 * EnM0_t
   臨界値以下の水分含有量での減衰則(雲の乾燥):
   dCk < dMin

   雲の形成が可能になる領域のための湿度閾値:
   HT = H_min + λ * (H_max - H_min);
//--------------------------------------------------------------------------------
6. 新しい雲のエントロピーとハイパーエントロピーを計算します。
   En = EnM0 / (1 + 2.72 ^ (-(8 - 16 * (t / maxT))))
   He = HeM0 / (1 + 2.72 ^ ((8 - 16 * (t / maxT))))

それでは続きを見ていきましょう。ここでは、C_AO_ACMOクラスのMovingメソッドについて取り上げます。このメソッドは2つの操作を実行します。MoveClouds (revision)は雲の動きを担当し、RainProcess (revision)は雲の状態とrevisionパラメータに基づいて降雨処理を行います。Movingメソッドは、雲の動きと降雨に関する2つの主要な処理を統括しており、雲の移動および雨プロセスとの相互作用に関するロジックをカプセル化しています。したがって、Movingメソッドは気象シミュレーションにおいて、雲と雨の状態を更新するために使用されます。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::Moving ()
{
  MoveClouds       (revision);
  RainProcess      (revision);
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスのMoveCloudsメソッドを詳しく見てみましょう。

1. 最初のブロック(revfalseの場合):ランダムな中心を持つ雲を作成します。各雲と座標について

  • 指定された範囲内で雲中心のランダム値が生成されます(RNDfromCI関数)。
  • 中心はSeInDiSpを使用して調整され、値が正規化されます。
  • 雲が配置されている領域のインデックスは、GetRegionIndexを使用して決定されます。
  • 雲のエントロピーと初期エントロピー値が設定されます。
  • ハイパーエントロピーの初期値は、hyperEntropyに設定されます。
実行を終了します。

2. 2番目のブロック(revtrueの場合)

  • revtrueに等しい場合、最も気圧が低い領域の検索を開始します。
  • 湿度lHindが最も低い領域のインデックスを格納し、気圧normPを正規化するための配列が作成されます。

3. 気圧が最も低い領域を見つけるためにループします。

  • c座標について、すべての領域における最小気圧と最大気圧が決定されます。
  • 気圧が最も低い領域のインデックスがlHind配列に格納されます。
  • 各座標の正規化された気圧がnormPに格納されます。

4. 各雲の動きと座標

  • 雲がすでに気圧が最も低い領域にある場合、反復はスキップされます。
  • 気圧の低いターゲット領域がランダムに選択されます。
  • 現在の領域とターゲット領域間の気圧差が計算されます。
  • 気圧値を正規化し、VC雲の移動速度が計算されます。
  • 雲の中心は移動速度に基づいて更新されます。
  • 領域インデックスが更新されます。
  • 雲のエントロピーは、気圧の変化を考慮して更新されます。
  • 雲内の水分量が減少し、ハイパーエントロピーが更新され、その値は最大8に制限されます。

MoveCloudsメソッドは、雲をより低圧の領域に移動し、エントロピーやハイパーエントロピーなどのパラメータを更新します。このメソッドは、大気の変化を反映した動的モデルを実装します。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::MoveClouds (bool &rev)
{
  //----------------------------------------------------------------------------
  if (!rev)
  {
    //creating clouds with random centers---------------------------------------
    for (int i = 0; i < cloudsNumber; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        clouds [i].center [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        clouds [i].center [c] = u.SeInDiSp  (clouds [i].center [c], rangeMin [c], rangeMax [c], rangeStep [c]);

        clouds [i].regionIndex [c] = GetRegionIndex (clouds [i].center [c], c);

        clouds [i].entropy      [c] = entropy [c] * EnM0;
        clouds [i].entropyStart [c] = clouds [i].entropy [c];
      }

      clouds [i].hyperEntropy = HeM0;
    }

    return;
  }

  //search for the region with the lowest pressure------------------------------
  int targetRegion = 0;

  int lHind []; //lowest humidity index
  ArrayResize     (lHind, coords);
  ArrayInitialize (lHind, 0);

  double normP [];
  ArrayResize (normP, coords);
  double minP;
  double maxP;

  for (int c = 0; c < coords; c++)
  {
    minP =  DBL_MAX;
    maxP = -DBL_MAX;

    for (int r = 0; r < regionsNumber; r++)
    {
      if (areas [c].regions [r].pressure < areas [c].regions [lHind [c]].pressure)
      {
        lHind [c] = r;
      }

      if (areas [c].regions [r].pressure < minP) minP = areas [c].regions [r].pressure;
      if (areas [c].regions [r].pressure > maxP) maxP = areas [c].regions [r].pressure;
    }

    normP [c] = maxP - minP;
  }

  //moving the cloud to a region with less pressure-----------------------------
  int    clRegIND = 0;
  double deltaP   = 0.0;
  double α        = 0.0; // Entropy factor
  double β        = 0.0; // Atmospheric pressure factor
  double VC       = 0.0; // Cloud velocity
  double d        = 0.0; // Cloud direction

  for (int i = 0; i < cloudsNumber; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      //find a region with lower pressure---------------------------------------
      if (clouds [i].regionIndex [c] == lHind [c]) continue;

      clRegIND = clouds [i].regionIndex [c];

      do targetRegion = u.RNDminusOne (regionsNumber);
      while (areas [c].regions [clRegIND].pressure < areas [c].regions [targetRegion].pressure);

      //------------------------------------------------------------------------
      deltaP = areas [c].regions [clRegIND].pressure - areas [c].regions [targetRegion].pressure;

      β = deltaP / normP [c];
      d = areas [c].regions [targetRegion].x - areas [c].regions [clRegIND].centre;

      VC = β * d;

      clouds [i].center      [c] += VC;
      clouds [i].center      [c] = u.SeInDiSp (clouds [i].center [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      clouds [i].regionIndex [c] = GetRegionIndex (clouds [i].center [c], c);

      α = β;
      clouds [i].entropy [c] *=(1 + α);
    }

    clouds [i].droplets     *=(1 - γ);
    clouds [i].hyperEntropy *=(1 + α);
    if (clouds [i].hyperEntropy > 8) clouds [i].hyperEntropy = 8;
  }
}
//——————————————————————————————————————————————————————————————————————————————

次に、C_AO_ACMOクラスのGetRegionIndexメソッドを分析してみましょう。以下がメソッドの説明です。

1. 領域の位置を計算します。指定されたpointregPos領域インデックスが計算され、floor関数を使用して最も近い整数に切り捨てられます。
2. 境界を確認します。このブロックは、regPosの計算されたインデックスが許容値を超えているかどうかを確認します(許容される領域の数を超えることはできません)。
3. このメソッドは、点が配置されている領域のインデックスを返します。

GetRegionIndexメソッドは、特定の範囲内で特定の点が配置されている領域のインデックスを決定することを目的としています。領域の数を考慮し、点が範囲の境界上にある場合も正しく処理します。 

//——————————————————————————————————————————————————————————————————————————————
int C_AO_ACMO::GetRegionIndex (double point, int ind)
{
  int regPos = (int)floor ((point - rangeMin [ind]) / ((rangeMax [ind] - rangeMin [ind]) / regionsNumber));

  if (regPos >= regionsNumber) regPos = regionsNumber - 1;

  return regPos;
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスの次のメソッドRainProcessについて説明します。

2. 配列の初期化

  • 雲の値を格納するためのcloudと、各雲の雨滴の数を格納するためのdropsの2つの配列を作成します。
  • 両配列のサイズは、雲の量(cloudsNumber)に応じて異なります。

3. cloud配列の初期化

  • revfalseに等しい場合、すべてのcloud配列要素は1.0の値を使用して初期化されます。
  • それ以外の場合、cloud配列は0.0の値を使用して初期化され、各雲の湿度が計算されます。

4. 湿度計算

  • 各雲と座標ごとに、領域に応じて湿度が計算されます。
  • 湿度が-DBL_MAXと等しくない場合は、cloud配列の対応する要素に追加されます。それ以外の場合は、minGp(最小水滴量)が追加されます。

5. 水滴分布

  • DropletsDistributionメソッドを呼び出して、cloud配列の値に基づいて水滴量を配布します。

6. 各雲および各水滴の主な水滴処理ループ

  • distcenterxMinxMaxの値が計算されます。
  • x値は正規分布を使用して生成されます。
  • xが範囲外の場合は、RNDfromCIメソッドを使用して修正されます。
  • x値はSeInDiSpメソッドを使用して正規化され、a配列に保存されます。

雲のすべての水滴が処理された後、雲内の水滴の合計数が更新されます。したがって、RainProcessメソッドは、湿度と雨滴の分布を考慮して、雲から降る雨をシミュレートします。配列を初期化し、各雲の湿度を計算し、雨滴を分布させ、正規分布を仮定して各雨滴の値を生成します。 

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::RainProcess (bool &rev)
{
  //to shed drops from every cloud----------------------------------------------
  double cloud [];
  int    drops [];
  ArrayResize (cloud, cloudsNumber);
  ArrayResize (drops, cloudsNumber);

  if (!rev)
  {
    ArrayInitialize (cloud, 1.0);
  }
  else
  {
    ArrayInitialize (cloud, 0.0);

    double humidity;

    for (int i = 0; i < cloudsNumber; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        for (int r = 0; r < regionsNumber; r++)
        {
          humidity = areas [c].regions [clouds [i].regionIndex [r]].humidity;
          if (humidity != -DBL_MAX) cloud [i] += humidity;
          else                      cloud [i] += minGp;
        }
      }
    }
  }

  DropletsDistribution (cloud, drops);

  double dist   = 0.0;
  double centre = 0.0;
  double xMin   = 0.0;
  double xMax   = 0.0;
  double x      = 0.0;
  int    dCNT   = 0;

  for (int i = 0; i < cloudsNumber; i++)
  {
    for (int dr = 0; dr < drops [i]; dr++)
    {
      for (int c = 0; c < coords; c++)
      {
        dist   = clouds [i].entropy [c];
        centre = clouds [i].center  [c];
        xMin   = centre - dist;
        xMax   = centre + dist;

        x = u.GaussDistribution (centre, xMin, xMax, clouds [i].hyperEntropy);

        if (x < rangeMin [c]) x = u.RNDfromCI (rangeMin [c], centre);
        if (x > rangeMax [c]) x = u.RNDfromCI (centre, rangeMax [c]);

        x = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);

        a [dCNT].c [c] = x;
      }

      dCNT++;
    }

    clouds [i].droplets += drops [i];
  }
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスの次のメソッドであるDropletsDistributionは、湿度に基づいて雲間に雨滴を分配するように設計されています。詳しく見てみましょう。

2. 変数の初期化

  • minHumidityは、最小湿度を見つけられるように最大値に初期化されます。
  • indMinHumidityは、湿度が最小の雲インデックスを格納します。
  • totalHumidityは、すべての雲の湿度の合計を保存するために使用されます。

3. 湿度の合計は、すべての雲の湿度を合計し、湿度が最も低い雲を決定します。

4. 水滴の比例配分:各雲について、水滴の数は湿度の合計に対する割合で計算されます。この値は、droplet配列に保存されます。

5. 残りの水滴の分配

  • まず、分散された水滴の総数(totalDrops)が計算されます。
  • 残りの水滴数(remainingDrops)が計算されます。
  • 残っている水滴があれば、最小限の湿度で雲に追加されます。

DropletsDistributionメソッドは、水滴の水分含有量に基づいて雲の間に水滴を効果的に分散させます。まず水滴を比例配分し、残りの水滴を湿度の最も低い雲に追加することで配分を調整します。これにより、アルゴリズムの外部パラメータの集団サイズに対応する一定数の雨滴を維持しながら、より現実的な水滴のシミュレーションが可能になります。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::DropletsDistribution (double &cloud [], int &droplets [])
{
  double minHumidity    = DBL_MAX;
  int    indMinHumidity = -1;
  double totalHumidity  = 0; //total amount of humidity in all clouds

  for (int i = 0; i < ArraySize (cloud); i++)
  {
    totalHumidity += cloud [i];

    if (cloud [i] < minHumidity)
    {
      minHumidity = cloud [i];
      indMinHumidity = i;
    }
  }

  // Filling the droplets array in proportion to the value in clouds
  for (int i = 0; i < ArraySize (clouds); i++)
  {
    droplets [i] = int((cloud [i] / totalHumidity)*popSize); //proportional distribution of droplets
  }

  // Distribute the remaining drops, if any
  int totalDrops = 0;

  for (int i = 0; i < ArraySize (droplets); i++)
  {
    totalDrops += droplets [i];
  }

  // If not all drops are distributed, add the remaining drops to the element with the lowest humidity
  int remainingDrops = popSize - totalDrops;

  if (remainingDrops > 0)
  {
    droplets [indMinHumidity] += remainingDrops; //add the remaining drops to the lightest cloud
  }
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスのRevisionメソッドは、システム状態の更新を実行します。もう少し詳しく見てみましょう。

1. a配列の要素(最適化エージェントの集合)をループします。このループは、popSizeサイズのa配列のすべての要素を反復処理します。

  • 現在の要素の適合度値fが現在の最大適合度値fBより大きい場合、fBが更新され、indインデックスが現在のインデックスに設定されます。
  • 最小適合値fの検索も配列のすべての要素間で実行され、現在の値がminGpより小さい場合はminGpが更新されます。

2. データのコピー:最大適合度値fを持つ要素が見つかった場合(indが-1ではない場合)、データ(つまりa [ind])がc配列からcB配列へコピーされます。

3. 領域プロパティの更新:UpdateRegionPropertiesメソッドが呼び出されます。さまざまな領域の湿度と気圧のパラメータを更新します。

4. 雲の生成:古い雲を消去し、新しい雲を作成するGenerateCloudsメソッドが呼び出されます。

5. ステータスの更新

  • revisionフラグはtrueに設定されており、これはシステムの初期状態が合格したことを示します。
  • エポックの数を追跡するために、epochNowカウンタが増加されます。

Revisionメソッドは、雲に関連するシステムの状態を更新する役割を担います。最大のf適合値を見つけ、関連するパラメータを更新し、新しい雲を初期化し、領域のプロパティを更新します。このメソッドは、モデル内のデータを最新の状態に保ち、システムが変更に適応できるようにするための鍵となります。

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

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

    if (a [i].f < minGp) minGp = a [i].f;
  }

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

  //----------------------------------------------------------------------------
  UpdateRegionProperties (); //updating humidity and pressure in the regions
  GenerateClouds         (); //disappearance of clouds and the creation of new ones

  revision = true;
  epochNow++;
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスのGenerateCloudsメソッドは、湿度やエントロピーなどのさまざまな要因に応じて雲を作成し、その状態を管理する役割を担います。以下がメソッドの説明です。

1. 湿度閾値の計算:CalculateHumidityThreshold関数が呼び出され、雲の形成に必要な湿度閾値が返されます。

2. 領域インデックスを格納するための構造体

  • S_Areas構造体が定義されています。この構造体には、雲を形成できる領域のインデックスの配列が含まれています。 
  • arメソッドは、座標のcoords数に等しいサイズで初期化されます。

3. 領域情報の収集:この二重ループは、各領域が湿度の閾値を満たしているかどうかをテストします。領域の湿度が閾値より大きい場合、その領域のインデックスが適切なS_Areas構造体のregsIND配列に追加されます。

4. 雲の減衰条件の確認

  • 各雲について、エントロピーが特定の制限(初期エントロピーの5倍)を超えているかどうかが確認されます。超えている場合、雲は崩壊したと考えられます。
  • 次に、雲内の水分量がdMinの最小値より少ないかどうかが確認されます。これも雲の崩壊につながる可能性があります。

5. 最も雨の多い領域に新しい雲を作成する

  • 雲が崩壊すると、最も湿潤な領域のひとつに新たな雲が生成されます。各座標に対して、領域インデックスがランダムに選択され、雲は新しい中心座標と領域インデックスを受け取ります。
  • 次に、CalculateNewEntropy関数が呼び出されます。この関数は、現在のエポックに応じて新しい雲のエントロピーを再計算します。

GenerateCloudsメソッドは、湿度とエントロピーに基づいて雲の生成と崩壊を管理します。雲を形成できる領域に関する情報を収集し、既存の雲の減衰をチェックし、適切な領域に新しい雲を作成します。このメソッドは、モデル内の雲の状態を動的に制御するための鍵となります。                                                                                                                                                    

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::GenerateClouds ()
{
  //Collecting statistics of regions capable of creating clouds-----------------
  double Ht = CalculateHumidityThreshold ();

  struct S_Areas
  {
      int regsIND []; //index of the potential region
  };

  S_Areas ar [];
  ArrayResize (ar, coords);

  int sizePr = 0;

  for (int i = 0; i < coords; i++)
  {
    for (int r = 0; r < regionsNumber; r++)
    {
      if (areas [i].regions [r].humidity > Ht)
      {
        sizePr = ArraySize (ar [i].regsIND);
        sizePr++;
        ArrayResize (ar [i].regsIND, sizePr, coords);
        ar [i].regsIND [sizePr - 1] = r;
      }
    }
  }

  //Check the conditions for cloud decay----------------------------------------
  bool   cloudDecay = false;

  for (int i = 0; i < cloudsNumber; i++)
  {
    cloudDecay = false;

    //checking the cloud for too much entropy-----------------------------------
    for (int c = 0; c < coords; c++)
    {
      if (clouds [i].entropy [c] > 5.0 * clouds [i].entropyStart [c])
      {
        //Print ("Disintegration of cloud #", i, " - tore at epoch ", epochNow);
        cloudDecay = true;
        break;
      }
    }

    //checking the cloud for decay----------------------------------------------
    if (!cloudDecay)
    {
      if (clouds [i].droplets < dMin)
      {
        //Print ("Disintegration of cloud #", i, " - dried up at epoch ", epochNow);
        cloudDecay = true;
      }
    }

    //if the cloud has decayed--------------------------------------------------
    int regIND = 0;

    if (cloudDecay)
    {
      //creating a cloud in a very humid region---------------------------------
      for (int c = 0; c < coords; c++)
      {
        regIND = u.RNDminusOne (ArraySize (ar [c].regsIND));
        regIND = ar [c].regsIND [regIND];

        clouds [i].center      [c] = areas [c].regions [regIND].x;
        clouds [i].regionIndex [c] = regIND;
      }

      CalculateNewEntropy (clouds [i], epochNow);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスのCalculateHumidityThresholdメソッドは、雲の形成に必要な湿度の閾値を計算する役割を担います。詳細な手順は次のとおりです。

1. 最低湿度を見つけるために二重ループを実行します。外側のループはすべてのcoords座標を処理し、内側のループは各座標のすべてのregionsNumber領域を反復処理します。領域の湿度が-DBL_MAXと等しくない場合は、チェックが実行されます。現在の湿度が現在のH_minより小さい場合は、H_minが更新されます。

2. 雲が形成されるために必要な湿度の閾値を表す値として、H_minλH_maxH_minの差の積を加えた値を返します。

CalculateHumidityThresholdメソッドは、すべての領域の中での最小湿度に基づいて湿度閾値を計算し、最大湿度とλ比に基づいてそれを調整します。これにより、環境の状態に基づいて、どのような条件下で雲が形成されるかを判断することが可能になります。

//——————————————————————————————————————————————————————————————————————————————
double C_AO_ACMO::CalculateHumidityThreshold ()
{
  double H_max = fB;
  double H_min = DBL_MAX;

  for (int c = 0; c < coords; c++)
  {
    for (int r = 0; r < regionsNumber; r++)
    {
      if (areas [c].regions [r].humidity != -DBL_MAX)
      {
        if (areas [c].regions [r].humidity < H_min)
        {
          H_min = areas [c].regions [r].humidity;
        }
      }
    }
  }

  return H_min + λ * (H_max - H_min);
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_ACMOクラスのCalculateNewEntropyメソッドは、S_ACMO_Cloud構造体によって表される雲の新しいエントロピーとハイパーエントロピーを計算します。詳しく見てみましょう。

1. エントロピーの計算

  • すべてのcoords座標をループします。
  • 各座標について、次の式を使用して新しいエントロピー値cl.entropy [c]が計算されます: En = (entropy [c] * EnM0) / (1 + e ^ (-(8 - 16 * (t / epochs))))
  • cl.entropyStart [c]cl.entropy [c]entropy [c]の値で初期化され、エントロピーの初期値を保持します。

2. ハイパーエントロピーの計算: He = 1 / (1 + e ^ (8 - 16 * (t / epochs)))

3. ハイパーエントロピーは、uオブジェクトのScaleメソッドを使用してスケーリングされます。これにより、HeM0パラメータと8.0を使用して、ハイパーエントロピー値を特定の範囲(0から8)にスケーリングできます。

CalculateNewEntropyメソッドは、現在の時刻tと指定されたパラメータに基づいて、雲のエントロピーとハイパーエントロピーの値を更新します。 

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::CalculateNewEntropy (S_ACMO_Cloud &cl, int t)
{
  //----------------------------------------------------------------------------
  //En: 1/(1+2.72^(-(8-16*(t/maxT))))
  for (int c = 0; c < coords; c++)
  {
    cl.entropy      [c] = entropy [c] * EnM0 / (1.0 + pow (M_E, (-(8.0 - 16.0 * (t / epochs)))));
    cl.entropyStart [c] = cl.entropy [c] = entropy [c];
  }

  //----------------------------------------------------------------------------
  //He: 1/(1+2.72^((8-16*(t/maxT))))
  cl.hyperEntropy = 1.0 / (1.0 + pow (M_E, ((8.0 - 16.0 * (t / epochs)))));

  cl.hyperEntropy = u.Scale (cl.hyperEntropy, 0.0, 8.0, HeM0, 8.0);
}
//——————————————————————————————————————————————————————————————————————————————

En and He 2

図1:現在のエポックに応じてζ比を計算するための方程式の変形方程式を選択し、それぞれのアルゴリズムを試すことができる(コード文字列はコメントアウトされている)


テスト結果

アルゴリズムのテストに移りましょう。著者らが考案した雲形成の気象モデルは次のように機能します。

//オリジナル版
ACMO|Atmospheric Cloud Model Optimization|50.0|5.0|10.0|0.2|5.0|5.0|0.9|0.2|
=============================
5 Hilly's; Func runs:10000; result:0.6017884495404766
25 Hilly's; Func runs:10000; result:0.3426222382089618
500 Hilly's; Func runs:10000; result:0.2526410178225118
=============================
5 Forest's; Func runs:10000; result:0.4780554376190664
25 Forest's; Func runs:10000; result:0.261057831391174
500 Forest's; Func runs:10000; result:0.17318135866144563
=============================
5 Megacity's; Func runs:10000; result:0.3507692307692307
25 Megacity's; Func runs:10000; result:0.16153846153846158
500 Megacity's; Func runs:10000; result:0.09632307692307775
=============================
All score:2.71798 (30.20%)

残念ながら、得られた結果は予想を大きく下回るものでした。多数の異なる方程式や、極端な解に陥るのを回避するための論理的な処理を備えた、雲形成の美しいモデルにもかかわらず、アルゴリズムの収束性は低いと考えられます。このアルゴリズムには、エージェント間での直接的なやり取りや、最適解に関する情報交換の仕組みが欠けています。こうした仕組みは、通常、あらゆるアルゴリズムの探索能力を高める効果があります。そのため、最良の水滴から最悪の水滴へ情報を確率的に伝達することで、情報交換を実現する仕組みを新たに追加しました。次に、この変更によって何が得られたのか、見ていきましょう。

ACMOm|Atmospheric Cloud Model Optimization|50.0|4.0|10.0|0.2|0.2|2.0|0.9|0.9|
=============================
5 Hilly's; Func runs:10000; result:0.9032099148349984
25 Hilly's; Func runs:10000; result:0.48545807643133143
500 Hilly's; Func runs:10000; result:0.30403284557071203
=============================
5 Forest's; Func runs:10000; result:0.8026793420899985
25 Forest's; Func runs:10000; result:0.3785708322859447
500 Forest's; Func runs:10000; result:0.1917777390119122
=============================
5 Megacity's; Func runs:10000; result:0.6230769230769231
25 Megacity's; Func runs:10000; result:0.244
500 Megacity's; Func runs:10000; result:0.10795384615384714
=============================
All score:4.04076 (44.90%)

結果は大幅に改善されました。このアイデアは成功だったと言えます。その内容は、湿度(アルゴリズムにおける適応度)が高い場合に、他の水滴からある確率で最適解に関する情報を伝達するというものです。 

最後に、各雲に対して、その雲から落下した水滴の総数(湿度の指標)が、drops配列の対応する値を加算することで更新されます。RainProcessメソッドは、湿度、水滴の分布、および個体群との相互作用を考慮しながら降雨をモデル化するメカニズムを実装しています。なお、コードに変更が加えられた箇所は緑色で強調表示されています。

生成された各x値に対して、集団からランダムにpインデックスが選ばれます。その後、確率(95%)に基づいて、a配列内の値が更新されます。この値は、集団(あるいは解集合)を表しています。最後に、各雲について、drops配列の対応する値を加算することで、その雲から落下した水滴の総数が再度更新されます。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::RainProcess (bool &rev)
{
  //to shed drops from every cloud----------------------------------------------
  double cloud [];
  int    drops [];
  ArrayResize (cloud, cloudsNumber);
  ArrayResize (drops, cloudsNumber);

  if (!rev)
  {
    ArrayInitialize (cloud, 1.0);
  }
  else
  {
    ArrayInitialize (cloud, 0.0);

    double humidity;

    for (int i = 0; i < cloudsNumber; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        humidity = areas [c].regions [clouds [i].regionIndex [c]].humidity;
       
        if (humidity != -DBL_MAX) cloud [i] += humidity;

        else                      cloud [i] += minGp;
      }
    }
  }

  DropletsDistribution (cloud, drops);
  //ArrayPrint (drops);

  double dist   = 0.0;
  double centre = 0.0;
  double xMin   = 0.0;
  double xMax   = 0.0;
  double x      = 0.0;

  int    dCNT   = 0;


  for (int i = 0; i < cloudsNumber; i++)
  {
    for (int dr = 0; dr < drops [i]; dr++)
    {
      for (int c = 0; c < coords; c++)
      {
        dist   = clouds [i].entropy [c];
        centre = clouds [i].center  [c];
        xMin   = centre - dist;
        xMax   = centre + dist;

        x = u.GaussDistribution (centre, xMin, xMax, clouds [i].hyperEntropy);

        if (x < rangeMin [c]) x = u.RNDfromCI (rangeMin [c], centre);
        
        if (x > rangeMax [c]) x = u.RNDfromCI (centre, rangeMax [c]);

        x = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);

        int p = u.RNDminusOne (popSize);

        if (a [p].f > a [dCNT].f)
        {
          if (u.RNDprobab () < 0.95) a [dCNT].c [c] = a [p].c [c];
        }

        else
        {
          a [dCNT].c [c] = x;
        }
      }
      dCNT++;
    }

    clouds [i].droplets += drops [i];
  }
}
//——————————————————————————————————————————————————————————————————————————————

アルゴリズムの動作を可視化すると、収束性が良好であることが確認できます。ただし、最適化パラメータの数が少ない場合、収束グラフ上に長く平坦な区間が現れる傾向があり、これはアルゴリズムが局所的な極値に陥りやすいことを示しています。一方で、パラメータ数を増やすことでこの欠点は解消されることがわかりました。

可視化においては、雲は密集したクラスタとして表示されますが、外部パラメータ(領域数、雲数、初期エントロピー、乾燥閾値)を適切に設定することで、自然界のように空に浮かぶ雲の外観をシミュレートすることも可能です。

Hilly

Hillyテスト関数のAСMO

Forest

Forestテスト関数のACMO

Megacity

Megacityテスト関数のACMO

修正版のテスト結果によると、アルゴリズムの順位は27位で、これは比較的安定した指標といえます。ここで強調しておきたいのは、現在この表には常に45種類のアルゴリズムが含まれており、新しいアルゴリズムが追加されるたびに、それ以前のものとの差は徐々に小さくなっていくという点です。つまり、この表は現在知られている最良のアルゴリズム上位群を示しているといえるでしょう。 

# 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)
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
7AAmアーチェリーアルゴリズムM0.917440.708760.421602.047800.925270.758020.353282.036570.673850.552000.237381.463235.54861.64
8ESG社会母集団の進化0.999060.796540.350562.146161.000000.828630.131021.959650.823330.553000.047251.423585.52961.44
9SIA等方的焼きなまし0.957840.842640.414652.215130.982390.795860.205071.983320.686670.493000.090531.270205.46960.76
10ACS人工協調探索0.755470.747440.304071.806981.000000.888610.224132.112740.690770.481850.133221.305835.22658.06
11ASO無政府社会最適化0.848720.746460.314651.909830.961480.791500.238031.991010.570770.540620.166141.277525.17857.54
12TSEA亀甲進化アルゴリズム0.967980.644800.296721.909490.994490.619810.227081.841390.690770.426460.135981.253225.00455.60
13DE差分進化0.950440.616740.303081.870260.953170.788960.166521.908650.786670.360330.029531.176534.95555.06
14CRO化学反応の最適化0.946290.661120.298531.905930.879060.584220.211461.674730.758460.426460.126861.311784.89254.36
15BSA鳥群アルゴリズム0.893060.649000.262501.804550.924200.711210.249391.884790.693850.326150.100121.120124.80953.44
16HSハーモニー検索0.865090.687820.325271.878180.999990.680020.095901.775920.620000.422670.054581.097254.75152.79
17SSG苗木の播種と育成0.778390.649250.395431.823080.859730.624670.174291.658690.646670.441330.105981.193984.67651.95
18BCOm細菌走化性最適化M0.759530.622680.314831.697040.893780.613390.225421.732590.653850.420920.144351.219124.64951.65
19(PO)ES(PO)進化戦略0.790250.626470.429351.846060.876160.609430.195911.681510.590000.379330.113221.082554.61051.22
20TSmタブーサーチM0.877950.614310.291041.783300.928850.518440.190541.637830.610770.382150.121571.114494.53650.40
21BSOブレインストーム最適化0.937360.576160.296881.810410.931310.558660.235371.725340.552310.290770.119140.962224.49849.98
22WOAm鯨最適化アルゴリズムM0.845210.562980.262631.670810.931000.522780.163651.617430.663080.411380.113571.188034.47649.74
23AEFA人工電界アルゴリズム0.877000.617530.252351.746880.927290.726980.180641.834900.666150.116310.095080.877544.45949.55
24ACOm蟻コロニー最適化M0.881900.661270.303771.846930.858730.586800.150511.596040.596670.373330.024720.994724.43849.31
25BFO-GA細菌採食の最適化:Ga0.891500.551110.315291.757900.969820.396120.063051.428990.726670.275000.035251.036924.22446.93
26ABHA人工蜂の巣アルゴリズム0.841310.542270.263041.646630.878580.477790.171811.528180.509230.338770.103970.951974.12745.85
27ACMO雲モデル最適化0.903210.485460.304031.692700.802680.378570.191781.373030.623080.244000.107950.975034.04144.90
28ASBO適応型社会行動最適化(ASBO)0.763310.492530.326191.582020.795460.400350.260971.456770.264620.171690.182000.618313.65740.63
29MECmind evolutionary computation0.695330.533760.326611.555690.724640.330360.071981.126980.525000.220000.041980.786983.47038.55
30IWO侵入雑草最適化0.726790.522560.331231.580580.707560.339550.074841.121960.423330.230670.046170.700173.40337.81
31Micro-AIS微小人工免疫系0.795470.519220.308611.623300.729560.368790.093981.192330.376670.158670.028020.563353.37937.54
32COAmカッコウ最適化アルゴリズムM0.758200.486520.313691.558410.740540.280510.055991.077040.505000.174670.033800.713473.34937.21
33SDOm螺旋ダイナミクス最適化M0.746010.446230.296871.489120.702040.346780.109441.158260.428330.167670.036630.632633.28036.44
34NMmネルダー=ミード法M0.738070.505980.313421.557470.636740.283020.082211.001970.446670.186670.040280.673623.23335.92
35FAmホタルアルゴリズムM0.586340.472280.322761.381380.684670.374390.109081.168140.286670.164670.047220.498553.04833.87
36GSA重力探索法0.647570.491970.300621.440160.539620.363530.099451.002600.326670.122000.019170.467832.91132.34
37BFO細菌採餌最適化0.611710.432700.313181.357590.544100.215110.056760.815970.421670.138000.031950.591622.76530.72
38ABC人工蜂コロニー0.633770.424020.308921.366710.551030.218740.056230.826000.340000.142000.031020.513022.70630.06
39BAコウモリアルゴリズム0.597610.459110.352421.409150.403210.193130.071750.668100.210000.101000.035170.346172.42326.93
40AAA藻類適応アルゴリズム0.500070.320400.255251.075720.370210.222840.167850.760890.278460.148000.097550.524022.36126.23
41SA焼きなまし0.557870.421770.315491.295130.349980.152590.050230.552800.311670.100330.028830.440832.28925.43
42IWDmintelligent water drops M0.545010.378970.301241.225220.461040.147040.043690.651770.258330.097000.023080.378422.25525.06
43PSO粒子群最適化0.597260.369230.299281.265770.372370.163240.070100.605720.256670.080000.021570.358232.23024.77
44ボイドボイドアルゴリズム0.433400.305810.254250.993460.357180.201600.157080.715860.278460.142770.098340.519572.22924.77
45MAモンキーアルゴリズム0.591070.426810.318161.336040.311380.140690.066120.518190.228330.085670.027900.341902.19624.40


まとめ

本稿では、ACMOアルゴリズムのオリジナル版と修正版の2つのバージョンを提示しました。修正版ではわずかな改良が加えられているだけですが、集団内での情報交換を導入することにより、性能が大幅に向上しました。これは、アルゴリズムのロジックにごく小さな調整を加えるだけでも、さまざまな課題に対する効率を大きく改善できることを示しています。

このアルゴリズムの着想は非常に興味深く、局所的な極値に陥るのを回避することを主な目的としています。雲を高気圧領域から低気圧領域へと移動させ、降水を起こすという複雑かつ多段階のロジックを用いています。しかし、それだけでは高い収束性能を得るには不十分でした。そこで私は、個体間で情報をやりとりする仕組みを導入することでアルゴリズムを改良し、最適化手法にとって極めて重要な要素である収束性の向上を実現しました。

このアルゴリズムの特筆すべき点は、どの雲も同じ場所に長く留まらないということです。時間の経過とともに領域内の気圧が上昇し、結果的に雲は新しい未知の領域へと押し出されていきます。このメカニズムは、局所解への停滞を防ぐために設計されたものです。しかし、収束性の向上を図ることで逆に極値に陥る確率が高まり、このアプローチの魅力だった特徴が部分的に損なわれてしまうという結果になりました。最適化アルゴリズムの設計には常に、探索性能(局所最適に陥らない力)と解の精度のバランスというトレードオフがつきまといます。なお、情報交換の確率(現在は95%)はコード上で調整可能であり、これを下げることで安定性を高めることも可能です。

このアルゴリズムは、最適化のための素晴らしい土台であり、さまざまな応用が可能な興味深い技術の集合でもあります。たとえば、領域ごとの湿度形成ルール、気圧分布、雲の質量に応じた加速度と慣性の物理法則など、多くの革新的なアイデアが含まれており、研究者にとって非常に有益な資源となるでしょう。

Tab

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

チャート

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

ACMOの長所と短所

長所

  1. スタックを防止するメカニズムが組み込まれている
  2. 比較的良好な収束
  3. 比較的優れたスケーラビリティ

短所

  1. 膨大な数の外部パラメータ
  2. 実装が複雑
  3. 行き詰まりと収束の間の適切なバランスを見つけるのが難しい

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

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

添付されたファイル |
ACMO.zip (39.7 KB)
最後のコメント | ディスカッションに移動 (2)
Arda Kaya
Arda Kaya | 24 4月 2025 において 16:13
本当に興味深いトピックだ!
Andrey Dik
Andrey Dik | 28 4月 2025 において 18:02
Arda Kaya #:
本当に興味深いトピックだ!

ありがとう。

取引におけるニューラルネットワーク:価格変動予測におけるマスクアテンションフリーアプローチ 取引におけるニューラルネットワーク:価格変動予測におけるマスクアテンションフリーアプローチ
この記事では、Mask-Attention-Free Transformer (MAFT)法と、それを取引分野に応用する可能性について説明します。従来のTransformerはシーケンスを処理する際にマスキングを必要としますが、MAFTはこのマスキングを不要にすることでアテンション処理を最適化し、計算効率を大幅に向上させています。
初級から中級へ:配列と文字列(II) 初級から中級へ:配列と文字列(II)
この記事では、プログラミングがまだ非常に初歩的な段階にあるにもかかわらず、すでにいくつかの興味深いアプリケーションを実装できることを示します。今回は、比較的シンプルなパスワードジェネレーターを作成します。このようにして、これまでに説明してきたいくつかの概念を実際に適用することができます。加えて、特定の問題に対する解決策をどのように構築できるかについても考察していきます。
DoEasy - サービス関数(第3回):アウトサイドバーパターン DoEasy - サービス関数(第3回):アウトサイドバーパターン
本記事では、DoEasyライブラリにおけるアウトサイドバーのプライスアクションパターンを開発し、価格パターン管理へのアクセス手法を最適化します。あわせて、ライブラリのテスト中に判明したエラーや不具合の修正もおこないます。
リプレイシステムの開発(第67回):コントロールインジケーターの改良 リプレイシステムの開発(第67回):コントロールインジケーターの改良
この記事では、コードを少し手直しすることで、どのような改善が得られるかを見ていきます。今回の改良は、コードの簡素化を図り、MQL5ライブラリの呼び出しをより活用し、そして何よりも、将来的に開発する可能性のある他のプロジェクトでも、より安定して安全かつ使いやすくなることを目的としています。