English Русский Deutsch Português
preview
母集団最適化アルゴリズム:人工多社会的検索オブジェクト(MSO)

母集団最適化アルゴリズム:人工多社会的検索オブジェクト(MSO)

MetaTrader 5テスター | 25 6月 2024, 11:28
54 0
Andrey Dik
Andrey Dik

内容

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


1.はじめに

前回は、探索空間を自由に移動する社会集団の進化について考えました。しかし、ここで私は、この概念を変え、集団はセクター間を移動し、セクターからセクターへと飛び移ることを仮定することを提案します。すべての集団はそれぞれの中心を持ち、アルゴリズムの各反復で更新されます。さらに、集団全体と集団内の個々の粒子の両方に記憶の概念を導入します。これらの変更により、私たちのアルゴリズムでは、集団が最適解に関する情報に基づいてセクターからセクターへと移動できるようになりました。

この新たな修正は、社会集団の進化を研究するための新たな可能性を開くものです。セクターを移動することで、各集団は各セクター内で情報や経験を共有し、より効果的な検索や適応につなげることができます。記憶を導入することで、集団は以前の動きに関する情報を保持し、それを将来の動きに関する判断に用いることができます。

この記事では、これらの新しい概念がアルゴリズムの検索パフォーマンスにどのような影響を与えるかを探るため、一連の実験をおこないます。私たちは、集団間の相互作用、協力調整能力、学習適応能力を分析します。今回の発見は、社会システムの進化に光を当て、集団がどのように形成され、進化し、環境の変化に適応していくのかをよりよく理解する一助となるでしょう。

最後に、改良されたアルゴリズムの更なる改良の可能性と、様々な分野への応用について議論します。本研究で導入した修正により、より効率的に解空間を探索し、最適値を見つけることができるようになりました。これは、最適化と解探索の分野で働く研究者や実務家にとって有益でしょう。


2.アルゴリズム

社会集団の原理を統合したアルゴリズムの最終的な目標は、集団メンバー間の調整と協力の効果的なシステムを構築することです。このようなアルゴリズムに組み込むことができる一般的な原則を紹介します。

  • 移動アルゴリズムによって、関係者は異なるセクターやエリア間を移動することができます。これにより、集団はさまざまなリソースや経験を探求し、個々の座標に関する情報だけでなく、セクターという形のメタデータを他の集団と交換することができるようになります。
  • 役割分担と専門化によって、集団のメンバーは特定の分野を選択し、専門化することができます。これにより、集団のリソースとスキルを効果的に活用し、共通の目標を達成することができます。これは、異なる性質(平滑と離散の両方)を持つ関数の曲面が同時に存在するような多次元空間の問題を解くときに特に役立ちます。
  • 協力と相互作用によって、集団のメンバーは互いに協力し、相互作用することができます。これには、情報を共有し、アイデアを議論し、未知の領域への推定や推定をおこなうことが含まれます。
  • 対立と紛争解決は、集団内の対立を解決するメカニズムです。これには、規則や手続きの確立、意見の相違や紛争を解決するための調停や対話が含まれます。例えば、粒子が同じエリアを奪い合うのを防ぎ、アルゴリズムの貴重な反復を節約できるようにすることです。
  • リーダーシップと組織は、組織化、調整、意思決定をおこなうリーダーが集団にいる可能性です。リーダーは、集団のモチベーションを高め、目標達成に導くことができなければなりません。
  • 知識や経験を交換することで、参加者間で知識や経験を積極的に交換することができます。そうすることで、集団は他者から学び、新しい状況に適応し、より多くの情報に基づいた決断を下すことができます。単なる確率的な空間探索ではなく、座標間の複雑な論理的つながりを構築する能力。
  • 集団の記憶会計によって、集団は以前の動き、役割、専門化、協力、紛争解決に関する情報を保持することができます。これによって集団は、その経験を活かして、今後の動きや交流について、より多くの情報に基づいた決断を下すことができるようになります。

これらの一般原則をアルゴリズムに組み込むことで、協力、協調、情報交換、変化する環境への適応が可能な、より効率的な社会システムが生まれます。

アルゴリズムの文脈で理解を深めるために、セクターの意味を説明しましょう。セクターは、最適化されたパラメータの定義領域(多次元空間の座標軸)の一部です。軸のセクター分けは全集団共通です。2つの集団G0とG1は、例えばこのように、対応する座標のセクターに配置することができます。

G0 (X) |---V---|-------|-------|-------|-------|

G0 (Y) |-------|---V---|-------|-------|-------|

G0 (Z) |-------|-------|-------|-------|---V---|

-----------------------------------------------------

G1 (X) |-------|-------|---V---|-------|-------|

G1 (Y) |---V---|-------|-------|-------|-------|

G1 (Z) |-------|-------|-------|---V---|-------|

アルゴリズムの主なアイデアの1つは、セクター選択の自由度においてある程度の確率性を維持しつつ、成功したセクターに関する知識を集団間で交換できるようにすることです。

では、アルゴリズムの最初の概念の説明に移りましょう。まず、最適解の記憶を考慮に入れずに、セクターをまたいで集団をランダムに移動させるアルゴリズムを考えてみましょう。

アルゴリズムの擬似コードは以下の通りです。

1.集団のセクターを無作為に選択します。
2.セクター間で均等にポイントを作成します。
3.適応度関数を計算します。
4.大域的な解を更新します(最適の集団粒子)。
5.現在のイテレーションで、集団内の最適な粒子の値を取得します。
6.各集団のセクターの最適解の記憶を更新します。
7.各粒子のセクターの最適解の記憶を更新します。
8.集団別に最適解を更新します。
9.ある集団について、その解が各座標に対してより良いかどうかを他の集団に尋ねます。
9. a) 「はい」の場合:そのセクターを選択します。
9. b) そうでない場合:ある確率で他のセクターを選択します。
10.確率で粒子を作成します。
10. a)はいの場合:セクター全体に均等に。
10. b) そうでない場合:集団の決定を明確にします。
11.4から繰り返します。

集団内部のアーキテクチャと、セクターごとの座標の表示は以下のようになります。

Group  [groups]|
                        |-----------------------------------------
                        |fB
                        |-----------------------------------------
                        |fBLast
                        |-----------------------------------------
                        |cB              [coords]
                        |-----------------------------------------
                        |cLast         [coords]
                        |-----------------------------------------
                        |centre       [coords]
                        |-----------------------------------------
                        |secInd       [coords]
                        |-----------------------------------------
                        |secIndLast [coords]
                        |-----------------------------------------
                        |p                [groupSize]|
                        |                                    |-------------------
                        |                                    |c   [coords]
                        |                                    |f   

m [coords]|
                 |--------------
                 |min [sectNumb]
                 |max [sectNumb]

コードの説明に移りましょう。

探索空間をセクターにマークするには、セクターの境界を指定する必要があります。これを実現するために、S_Min_Max構造体を書きます。ひとつひとつ分解してみましょう。

S_Min_Max構造体には2つのデータフィールドがあります。minとmaxは、左側のセクター境界を表し、maxは右側のセクター境界を表します。両方の配列のサイズは、sectNumbパラメータで指定されるセクター数に等しいです。

この構造体はまた、min配列とmax配列を初期化するInit関数も定義しています。セクター数を指定する sectNumbというパラメータを1つ受け付けます。Init関数内部では、渡された sectNumbパラメータに従って、min配列およびmax配列のサイズが変更されます。したがって、この構造体はセクター境界を保存し、Init関数を使用して初期化する方法を提供します。

//——————————————————————————————————————————————————————————————————————————————
struct S_Min_Max
{
  void Init (int sectNumb)
  {
    ArrayResize (min, sectNumb);
    ArrayResize (max, sectNumb);
  }
  double min []; //sector border on the left, size - number of sectors
  double max []; //sector border on the right, size - number of sectors
};
//——————————————————————————————————————————————————————————————————————————————

集団のメンバーである粒子を記述するために、S_Particle構造体を記述します。

  • c:粒子座標を格納する配列。配列のサイズは、Init関数に渡される coordsパラメータによって決定されます。
  • fはInit関数で-DBL_MAX 値で初期化された粒子適応度関数の値です。

したがって、この構造体は、粒子の座標と関連する関数値を格納するコンテナを提供します。

//——————————————————————————————————————————————————————————————————————————————
struct S_Particle
{
  void Init (int coords, int sectNumb)
  {
    ArrayResize (c, coords);

    f = -DBL_MAX;
  }

  double c  [];
  double f;
};
//——————————————————————————————————————————————————————————————————————————————

粒子の集団をS_Groupデータ構造体にまとめます。S_Group構造体にはいくつかのデータフィールドがあります。

  • pは集団粒子を格納するためのS_Particle構造体の配列を表します。p配列のサイズは、Init関数に渡される groupSizeパラメータによって決定されます。forループの中で、各粒子はS_Particle構造体のInit関数を使用して初期化されます。
  • secIndとsecIndLast:各座標のセクターインデックスを格納する配列。secInd配列とsecIndLast配列のサイズは、coordsパラメータによって決定されます。
  • cBとcBLast:この配列には、それぞれ集団内のベスト座標と直前のベスト座標が格納されます。cB配列とcBLast配列のサイズもcoordsパラメータによって決定されます。
  • fBとfBLast:変数には、それぞれ集団内の最適の結果と直前の最適の結果が格納されます。
  • center:中心を格納する配列。centre配列のサイズも coordsパラメータによって決定され、集団全体の最適なセクター座標を決定するために使用されます。

Init関数は、S_Group構造体のすべての配列と変数を初期化します。coords:座標の数、groupSize:集団のサイズ、sectNumb:セクター数の3つのパラメータを取ります。

したがって、この構造は、粒子群に関する情報を保存するためのコンテナを提供します。粒子は集団の規則に従い、他の集団の粒子とは相互作用しません。交流は、集団レベルのセクターを通じた間接的な情報伝達を通じておこなわれます。

//——————————————————————————————————————————————————————————————————————————————
struct S_Group
{
  void Init (int coords, int groupSize, int sectNumb)
  {
    ArrayResize     (p,             groupSize);
    ArrayResize     (secInd,        coords);
    ArrayResize     (cB,            coords);
    ArrayResize     (cBLast,        coords);
    ArrayResize     (secIndLast,    coords);
    ArrayResize     (centre,        coords);
    for (int i = 0; i < groupSize; i++)  p [i].Init (coords, sectNumb);

    fB     = -DBL_MAX;
    fBLast = -DBL_MAX;
  }

  S_Particle p          [];
  int        secInd     []; //sector index on the coordinate, size is the number of coordinates
  int        secIndLast []; //previous index of the sector on the coordinate, the size is the number of coordinates

  double     cB         []; //the best coord's in the group
  double     cBLast     []; //the previous best coord's in the group
  double     fB;            //the best result in the group
  double     fBLast;        //the previous best result in the group
  double     centre [];
};
//——————————————————————————————————————————————————————————————————————————————

最適化エージェントをS_Agent構造体で説明します。この構造体を通して、集団粒子から適応度関数の計算に情報が伝達されます。S_Agent構造体には2つのフィールドがあります。

  • c:エージェント座標を格納する配列
  • f:エージェントの適応度関数を格納する

Init関数は、S_Agent構造体のc配列とf変数を初期化します。これは、c配列のサイズを指定する coordsというパラメータを1つ取ります。

//——————————————————————————————————————————————————————————————————————————————
struct S_Agent
{
  void Init (const int coords)
  {
    ArrayResize (c, coords);
    f = -DBL_MAX;
  }

  double c []; //coordinates
  double f;    //fitness
};
//——————————————————————————————————————————————————————————————————————————————

C_AO_MSOクラスを使用して多社会的アルゴリズムを説明しましょう。このクラスにはいくつかのデータフィールドとメソッドがあります。

  • cB:ベスト座標を格納する配列
  • fB:この変数には、最適の座標の適応度が格納される
  • a:エージェントを格納するS_Agent構造体の配列
  • rangeMax、rangeMin、rangeStep:それぞれ検索範囲の最大値と最小値、ステップを格納する配列

このクラスにはいくつかのメソッドもあります。

  • Initはクラスのすべてのデータメンバーを初期化します。coordinatesNumberP:座標の数、opulationSizeP:母集団のサイズ、groupsP:座標の数、sectsNumberP:座標ごとのセクター数、probRNSectorP:セクターのランダム確率、probUniformSectorP:粒子の一様分布確率、probClgroupP:集団の結果を絞り込む確率、powerP:冪乗分布関数の冪乗を受け取ります。
  • MovingおよびRevision:集団と集団粒子で基本的な操作をおこなうメソッド

一般に、C_AO_MSOクラスは、エージェントの最適分布による多重探索を用いた最適化アルゴリズムの実装です。エージェント、集団、セクターを管理し、検索操作を実行し、結果を絞り込むためのデータとメソッドが含まれています。

//——————————————————————————————————————————————————————————————————————————————
class C_AO_MSO
{
  //----------------------------------------------------------------------------
  public: double cB [];         //best coordinates
  public: double fB;            //FF of the best coordinates
  public: S_Agent a [];         //agents

  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search

  public: void Init (const int    coordinatesNumberP,  //coordinates number
                     const int    populationSizeP,     //population size
                     const int    groupsP,             //number of groups
                     const int    sectorsNumberP,      //sectors number
                     const double probRNSsectorP,      //probability random sector
                     const double probUniformSectorP,  //probability uniform distribution
                     const double probClgroupP,        //probability of clarifying the group's result
                     const double powerP);             //power

  public: void Moving   ();
  public: void Revision ();

  //----------------------------------------------------------------------------
  private: int    coords;                //coordinates number
  private: int    popSize;               //population size

  private: int    sectNumb;              //sectors number
  private: double sectorSpace [];        //sector space

  private: S_Group    gr [];             //groups
  private: S_Min_Max  min_max_Sector []; //sector boundary by coordinates

  private: int    groups;                //number of groups
  private: int    sectorsNumber;         //sectors number
  private: double probRNSsector;         //probability random sector
  private: double probUniformSector;     //probability uniform distribution
  private: double probClgroup;           //probability of clarifying the group's result
  private: double power;                 //power

  private: bool   revision;

  private: double SeInDiSp  (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI (double min, double max);
  private: double Scale     (double In, double InMIN, double InMAX, double OutMIN, double OutMAX,  bool revers);
  private: double PowerDistribution (const double In, const double outMin, const double outMax, const double power);
};
//——————————————————————————————————————————————————————————————————————————————

Initメソッドは、与えられたパラメータでC_AO_MSOクラスのオブジェクトを初期化します。このコードをひとつひとつ分解してみましょう。

関数の最初に、クラスの変数とデータメンバーが初期化されます。乱数発生器は、マイクロ秒単位の現在時刻を使用してリセットされます。そして、fB変数には可能な限り最小のダブル値-DBL_MAXが設定され、revision変数にはfalseが設定されます。

そして、関数に渡されたパラメータは、クラスの対応するフィールドに代入されます。

母集団粒子を集団に分配するために、partInSwarms配列が作成されます。各集団の粒子の数が格納されます。配列のサイズは集団の数に等しく設定されます。次に、particles変数は、popSize総母集団サイズをgroupsの数で割ることによって、各集団の粒子の数を計算します。

もし「失われた」余剰があれば、それは集団ごとに分配されます。ループは余剰分が0になるまで実行されます。

次に、配列のサイズが変更され、オブジェクトが初期化されます。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Init (const int    coordinatesNumberP,  //coordinates number
                     const int    populationSizeP,     //population size
                     const int    groupsP,             //number of groups
                     const int    sectorsNumberP,      //sectors number
                     const double probRNSsectorP,      //probability random sector
                     const double probUniformSectorP,  //probability uniform distribution
                     const double probClgroupP,        //probability of clarifying the group's result
                     const double powerP)              //power
{
  MathSrand ((int)GetMicrosecondCount ()); // reset of the generator
  fB       = -DBL_MAX;
  revision = false;

  coords            = coordinatesNumberP;
  popSize           = populationSizeP;
  groups            = groupsP;
  sectNumb          = sectorsNumberP;
  probRNSsector     = probRNSsectorP;
  probUniformSector = probUniformSectorP;
  probUniformSector = probClgroupP;
  power             = powerP;

  //----------------------------------------------------------------------------
  int partInSwarms [];
  ArrayResize (partInSwarms, groups);

  int particles = popSize / groups;
  ArrayInitialize (partInSwarms, particles);

  int lost = popSize - particles * groups;

  if (lost > 0)
  {
    int pos = 0;

    while (true)
    {
      partInSwarms [pos]++;
      lost--;
      pos++;
      if (pos >= groups) pos = 0;
      if (lost == 0) break;
    }
  }

  //----------------------------------------------------------------------------
  ArrayResize (rangeMax,  coords);
  ArrayResize (rangeMin,  coords);
  ArrayResize (rangeStep, coords);
  ArrayResize (cB,        coords);

  ArrayResize (gr,        groups);
  for (int s = 0; s < groups; s++) gr [s].Init (coords, partInSwarms [s], sectNumb);

  ArrayResize (sectorSpace, coords);

  ArrayResize (a, popSize);
  for (int i = 0; i < popSize; i++) a [i].Init (coords);
}
//——————————————————————————————————————————————————————————————————————————————

Movingメソッドは、最初の反復で粒子を移動させる役割を担い、集団とその粒子を初期位置で初期化する機能を実行します。

関数の冒頭で、変数 revisionの値が確認され、一度しか実行されないこと、そしてfalseかどうかが確認されます。

コードの最初の部分は、空間をセクターに分割し、min_max_Sector配列を初期化します。各c座標について、sectorSpace[c]のセクターサイズは、rangeMax[c]とrangeMin[c]の差をセクター数 sectNumbで割ったものとして計算されます。そして、minとmaxの値が、各座標とセクターのmin_max_Sector配列に初期化されます。

次に、粒子を探索空間に配置します。各s集団に対して、各座標に対してランダムなセクターが選択されます。セクターインデックス値は、集団ごとにsecInd配列に格納されます。その後、集団の粒子が選択されたセクター内にランダムに分散されます。各p粒子とc座標について、セクターの最小値と最大値の範囲内でランダムな値cdが選択され、この値が粒子座標に格納されます。

最後のブロックは、エージェントに粒子を送信するコードです。cntカウンタが作成され、エージェントの列挙に使用されます。次に、各s集団と各p粒子について、粒子座標値がa[cnt].c配列にコピーされます。ここで、cntは​​コピーごとに増加します。

そこで、このメソッドは最適化アルゴリズムにおける粒子のランダムな初期配置を担当し、空間をセクターに分割し、各集団のセクターをランダムに選択し、選択したセクター内に粒子を分散させます。その後、粒子はさらに加工するためにエージェントに送られます。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Moving ()
{
  if (!revision)
  {
    //marking up sectors--------------------------------------------------------
    ArrayResize (min_max_Sector, coords);

    for (int c = 0; c < coords; c++)
    {
      sectorSpace [c] = (rangeMax [c] - rangeMin [c]) / sectNumb;
      min_max_Sector [c].Init (sectNumb);

      for (int sec = 0; sec < sectNumb; sec++)
      {
        min_max_Sector [c].min [sec] = rangeMin [c] + sectorSpace [c] * sec;
        min_max_Sector [c].max [sec] = min_max_Sector [c].min [sec] + sectorSpace [c];
      }
    }

    //--------------------------------------------------------------------------
    int    sect    = 0;   //sector
    double sectMin = 0.0; //sector's min
    double sectMax = 0.0; //sector's max
    int    ind     = 0;   //index
    double cd      = 0.0; //coordinate

    for (int s = 0; s < groups; s++)
    {
      //select random sectors for the group-------------------------------------
      for (int c = 0; c < coords; c++)
      {
        ind = (int)(RNDfromCI (0, sectNumb));
        if (ind >= sectNumb) ind = sectNumb - 1;

        gr [s].secInd     [c] = ind;
        gr [s].secIndLast [c] = ind;
      }

      //random distribute the particles of the group within the sectors---------
      for (int p = 0; p < ArraySize (gr [s].p); p++)
      {
        for (int c = 0; c < coords; c++)
        {
          sect               = gr [s].secInd [c];
          cd                 = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
          gr [s].p [p].c [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    }

    //--------------------------------------------------------------------------
    //send particles to agents
    int cnt = 0;

    for (int s = 0; s < groups; s++)
    {
      for (int p = 0; p < ArraySize (gr [s].p); p++)
      {
        ArrayCopy (a [cnt].c, gr [s].p [p].c, 0, 0, WHOLE_ARRAY);
        cnt++;
      }
    }

    revision = true;
  }
}
//——————————————————————————————————————————————————————————————————————————————

集団とその粒子を探索空間内で移動させるための主な操作は、Revisionメソッドによっておこなわれます。

  • 各粒子の適合度関数値を現在の最適値と比較することにより、大域的最適解を更新します。現在の粒子の目標関数値が現在の最適値より大きければ、それが新しい最適値となり、その座標が変数cBにコピーされます。
  • エージェントから粒子に結果を移動し、各集団で最適の粒子を決定します。各粒子の適応度関数の値は、この粒子に対応するエージェントのゴール関数の値に等しく設定されます。粒子の適応度関数の値が集団内の現在の最適値より大きい場合、その値が新しい最適値となり、その座標が集団cB変数にコピーされます。
  • 各集団の最適解を更新します。集団内の新しい最適値が前の値より大きければ、それが現在の最適値となり、その座標が集団のcBLast変数とsecIndLast変数にコピーされます。
  • 各集団の各座標について、より良い解を持つ別の集団が存在するかどうかが確認されます。そのような集団が存在する場合、現在の集団のセクターと中心は、最適解を持つ集団のセクターと中心の値で更新されます。そうでなければ、セクターと中央に変更はありません。
  • 確率に基づいて新しい粒子を作成します。各集団と集団内の各粒子について、確率に基づいて新しい座標値が生成されます。一様分布またはPowerDistribution関数を使用した分布を選択する確率は、probUniformSectorとpowerパラメータによって決定されます。
  • 最適化アルゴリズムの次の反復でさらに使用するために、作成された粒子をエージェントに移動します。

この方法は、各反復で解を更新し、集団内の最適解と確率に関する情報を使用して新しい粒子を作成します。

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

  //----------------------------------------------------------------------------
  //Transfer the results from the agents to the particles
  //and get the value of the best particle in the group at the current iteration
  int cnt = 0;
  for (int s = 0; s < groups; s++)
  {
    gr [s].fB = -DBL_MAX;

    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      gr [s].p [p].f = a [cnt].f;

      if (a [cnt].f > gr [s].fB)
      {
        gr [s].fB = a [cnt].f;
        ArrayCopy (gr [s].cB, a [cnt].c, 0, 0, WHOLE_ARRAY);
      }

      cnt++;
    }
  }

  int sector = 0;

  //----------------------------------------------------------------------------
  //Update the best solution for the group
  for (int s = 0; s < groups; s++)
  {
    if (gr [s].fB > gr [s].fBLast)
    {
      gr [s].fBLast = gr [s].fB;
      ArrayCopy (gr [s].cBLast, gr [s].cB, 0, 0, WHOLE_ARRAY);
      ArrayCopy (gr [s].secIndLast, gr [s].secInd, 0, 0, WHOLE_ARRAY);
    }

    ArrayCopy (gr [s].centre, gr [s].cBLast);
  }


  //----------------------------------------------------------------------------
  int    sect    = 0;     //sector
  double sectMin = 0.0;   //sector's min
  double sectMax = 0.0;   //sector's max
  int    ind     = 0;     //index
  double cd      = 0.0;   //coordinate

  for (int s = 0; s < groups; s++)
  {
    for (int c = 0; c < coords; c++)
    {
      if (RNDfromCI (0.0, 1.0) < 0.6)
      {
        ind = (int)(RNDfromCI (0, groups));
        if (ind >= groups) ind = groups - 1;

        if (ind == s) ind++;
        if (ind > groups - 1) ind = 0;

        if (gr [ind].fBLast > gr [s].fBLast)
        {
          gr [s].secInd [c] = gr [ind].secIndLast [c];
          gr [s].centre [c] = gr [ind].cBLast [c];
        }
      }
      else
      {
        if (RNDfromCI (0.0, 1.0) < probRNSsector)
        {
          ind = (int)(RNDfromCI (0, sectNumb));
          if (ind >= sectNumb) ind = sectNumb - 1;

          gr [s].secInd [c] = ind;
          sect = gr [s].secInd [c];

          cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
          gr [s].centre [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
        }
        else gr [s].secInd [c] = gr [s].secIndLast [c];
      }
    }
  }

  //----------------------------------------------------------------------------
  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      for (int c = 0; c < coords; c++)
      {
        sect = gr [s].secInd [c];

        if (RNDfromCI (0.0, 1.0) < probUniformSector)
        {
          cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
        }
        else
        {
           cd = PowerDistribution (gr [s].centre [c], min_max_Sector [c].min [sect], min_max_Sector [c].max [sect], power);
        }

        gr [s].p [p].c [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
  }
  //----------------------------------------------------------------------------
  cnt = 0;

  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      ArrayCopy (a [cnt].c, gr [s].p [p].c, 0, 0, WHOLE_ARRAY);
      cnt++;
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

次に、同じアルゴリズムを考えますが、集団とその粒子の記憶を追加し、探索戦略のロジックに他の変更を加えます。

集団と粒子の記憶の空き状況を考慮して、アルゴリズムの擬似コードを変更します。

  • 1.集団のセクターを無作為に選択します。
  • 2.セクター間で均等にポイントを作成します。
  • 4.FFを計算します。
  • 5.大域的な解を更新します(最適の集団粒子)。
  • 6.現在のイテレーションで、集団内の最適な粒子の値を取得します。
  • 7.各集団のセクターの最適解の記憶を更新します。
  • 8.各粒子のセクターの最適解の記憶を更新します。
  • 9.集団別に最適解を更新します。
  • 10.ある集団について、その解が各座標に対してより良いかどうかを他の集団に尋ねます。
  • 10. a) 「はい」の場合:そのセクターを選択します。
  • 10. b) そうでない場合:ある確率で他のセクターを選択します。
  • 11.確率で粒子を作成します。
  • 11. a)はいの場合:セクター全体に均等に。
  • 11. b) そうでない場合:確率 ? (集団の決定を明確に) : (自分の決定を明確に)。
  • 12.4から繰り返します。

記憶を追加することで、理論的には、以前の動きに関する情報を保持し、それを今後の動きの判断に役立てることができます。これは、集団が環境の変化にうまく適応し、より効果的に解を探るのに役立ちます。

集団の内部アーキテクチャを以下のように変更してみましょう。

Swarm [groups]|
                        |-----------------------------------------
                        |fB
                        |-----------------------------------------
                        |fBLast
                        |-----------------------------------------
                        |cB               [coords]
                        |-----------------------------------------
                        |cBLast        [coords]
                        |-----------------------------------------
                        |secInd        [coords]
                        |-----------------------------------------
                        |secIndLast [coords]
                        |-----------------------------------------
                        |sMemory    [coords]|
                        |                               |---------------
                        |                               |cB      [sectNumb]
                        |                               |fB      [sectNumb]
                        |-----------------------------------------
                        |p         [groupSize] |
                        |                              |-------------------
                        |                              |c       [coords]
                        |                              |f
                        |                              |pMemory [coords]|
                        |                                                            |--------
                        |                                                            |cB [sectNumb]
                        |                                                            |fB [sectNumb]

記憶を記述するS_Memory構造体を追加します。集団と粒子の場合、記憶は同じように見え、2つのcBとfB配列を含み、最適な座標とその座標に対する適応度関数に関する情報を格納します。

//——————————————————————————————————————————————————————————————————————————————
struct S_Memory
{
  void Init (int sectNumb)
  {
    ArrayResize     (cB, sectNumb);
    ArrayResize     (fB, sectNumb);
    ArrayInitialize (fB, -DBL_MAX);
  }
  double cB []; //the best sector coordinate, size is the number of sectors
  double fB []; //FF is the best coordinate on a sector, size is the number of sectors
};
//——————————————————————————————————————————————————————————————————————————————

従って、粒子と集団の構造体に記憶宣言を追加します。

//——————————————————————————————————————————————————————————————————————————————
struct S_Particle
{
  <..............code is hidden.................>

  S_Memory pMemory []; //particle memory, size - the number of coordinates
};
//——————————————————————————————————————————————————————————————————————————————

//——————————————————————————————————————————————————————————————————————————————
struct S_Group
{
  <..............code is hidden.................>

  S_Memory sMemory []; //group memory, size - number of coordinates 
}; 
//——————————————————————————————————————————————————————————————————————————————

この変更はRevisionメソッドにも影響しました。

  • 群記憶内の最適なセクター座標を更新します。全セクターが各集団、各座標ごとに列挙されています。セクター上の集団のfB値がセクター記憶のfB値より大きい場合、fBとcBが記憶内で更新されます。
  • 粒子記憶内の最適のポジションを更新します。粒子の適応度関数の値が粒子記憶の値より大きい場合、fBとcBが記憶内で更新されます。
//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Revision ()
{
  //----------------------------------------------------------------------------
  //Update the best global solution
  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }

  //----------------------------------------------------------------------------
  //Transfer the results from the agents to the particles
  //and get the value of the best particle in the group at the current iteration
  int cnt = 0;
  for (int s = 0; s < groups; s++)
  {
    gr [s].fB = -DBL_MAX;

    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      gr [s].p [p].f = a [cnt].f;

      if (a [cnt].f > gr [s].fB)
      {
        gr [s].fB = a [cnt].f;
        ArrayCopy (gr [s].cB, a [cnt].c, 0, 0, WHOLE_ARRAY);
      }

      cnt++;
    }
  }

  //----------------------------------------------------------------------------
  //Update the best sector coordinates in the swarm's memory
  int sector = 0;
  for (int s = 0; s < groups; s++)
  {
    for (int c = 0; c < coords; c++)
    {
      sector = gr [s].secInd [c];

      if (gr [s].fB > gr [s].sMemory [c].fB [sector])
      {
        gr [s].sMemory [c].fB [sector] = gr [s].fB;
        gr [s].sMemory [c].cB [sector] = gr [s].cB [c];
      }
    }
  }

  //----------------------------------------------------------------------------
  //Update in the memory of the particles their best positions by sector
  sector  = 0;
  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      for (int c = 0; c < coords; c++)
      {
        sector = gr [s].secInd [c];

        if (gr [s].p [p].f > gr [s].p [p].pMemory [c].fB [sector])
        {
          gr [s].p [p].pMemory [c].fB [sector] = gr [s].p [p].f;
          gr [s].p [p].pMemory [c].cB [sector] = gr [s].p [p].c [c];
        }
      }
    }
  }

  //----------------------------------------------------------------------------
  //Update the best solution for the group
  for (int s = 0; s < groups; s++)
  {
    if (gr [s].fB > gr [s].fBLast)
    {
      gr [s].fBLast = gr [s].fB;
      ArrayCopy (gr [s].cBLast, gr [s].cB, 0, 0, WHOLE_ARRAY);
      ArrayCopy (gr [s].secIndLast, gr [s].secInd, 0, 0, WHOLE_ARRAY);
    }
  }

  //----------------------------------------------------------------------------
  int    sect    = 0;     //sector
  double sectMin = 0.0;   //sector's min
  double sectMax = 0.0;   //sector's max
  int    ind     = 0;     //index
  double cd      = 0.0;   //coordinate

  for (int s = 0; s < groups; s++)
  {
    for (int c = 0; c < coords; c++)
    {
      ind = (int)(RNDfromCI (0, groups));
      if (ind >= groups) ind = groups - 1;

      if (ind == s) ind++;
      if (ind > groups - 1) ind = 0;

      if (RNDfromCI (0.0, 1.0) < 0.6)
      {
        if (gr [ind].fBLast > gr [s].fBLast)                                       
        {
          gr [s].secInd [c] = gr [ind].secIndLast [c];
        }
      }
      else                                                                      
      {
        if (RNDfromCI (0.0, 1.0) < probRNSsector)
        {
          ind = (int)(RNDfromCI (0, sectNumb));
          if (ind >= sectNumb) ind = sectNumb - 1;

          gr [s].secInd [c] = ind;
          sect = gr [s].secInd [c];

          if (gr [s].sMemory [c].fB [sect] == -DBL_MAX)
          {
            cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
            gr [s].sMemory [c].cB [sect] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
          }
        }
        else gr [s].secInd [c] = gr [s].secIndLast [c];
      }
    }
  }

  //----------------------------------------------------------------------------
  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      for (int c = 0; c < coords; c++)
      {
        sect = gr [s].secInd [c];

        if (RNDfromCI (0.0, 1.0) < probUniformSector)
        {
          cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
        }
        else
        {
          if (RNDfromCI (0.0, 1.0) < probClgroup)
          {
            cd = PowerDistribution (gr [s].sMemory [c].cB [sect], min_max_Sector [c].min [sect], min_max_Sector [c].max [sect], power);
          }
          else
          {
            cd = PowerDistribution (gr [s].p [p].pMemory [c].cB [sect], min_max_Sector [c].min [sect], min_max_Sector [c].max [sect], power);
          }
        }

        gr [s].p [p].c [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
  }

  //----------------------------------------------------------------------------
  //send the particles to the agents
  cnt = 0;

  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      ArrayCopy (a [cnt].c, gr [s].p [p].c, 0, 0, WHOLE_ARRAY);
      cnt++;
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————


3.テスト結果

粒子の記憶を考慮しないアルゴリズムテストでは、かなり良好な結果が得られました。このアルゴリズムは評価表でトップ10に入ります。重要なのは、このアルゴリズムはあくまでロジックの一例であり、卓越した結果を示したのであれば、それを表に入れたであろうということです。また、このアルゴリズムをさらに実装し、修正する機会も多いです。

結果は傑出しているわけではありませんが、このアルゴリズムは探索空間の様々な領域を探索する上で優れた探索能力を示しています。

C_AO_MSO|60|30|9|0.05|0.05|10.0
=============================
5 Hilly's; Func runs:10000; result:0.9313358190790157
25 Hilly's; Func runs:10000; result:0.6649184286250989
500 Hilly's; Func runs:10000; result:0.3282041522365852
=============================
5 Forest's; Func runs:10000; result:0.9522099605531393
25 Forest's; Func runs:10000; result:0.5542256622730999
500 Forest's; Func runs:10000; result:0.08984352753493675
=============================
5 Megacity's; Func runs:10000; result:0.7899999999999998
25 Megacity's; Func runs:10000; result:0.33533333333333326
500 Megacity's; Func runs:10000; result:0.042983333333333325
=============================
All score:4.68905 (52.1%)

これらの結果は、記憶を持つ社会的集団についてのものです。アルゴリズム全体の結果が少し悪化しているのがわかります。とはいえ、このアルゴリズムは正当に評価表のトップの座を占めています。これは、このアルゴリズムの可能性と、満足のいく結果を得る能力を示しています。集団間だけでなく、その粒子間でも記憶を共有するという概念を考慮するというアイデアは、アルゴリズムを改善するための論理的なステップです。このような新たな相互作用を導入することで、新たなアイデアや戦略が生まれる可能性があります。前述したように、社会集団間の相互作用についてはさまざまなシナリオが描かれていますが、ここではその一部のみを紹介しました。つまり、アルゴリズムの修正や改良の余地が十分にあるということです。

C_AO_MSOm|60|30|9|0.1|0.9|0.1|10.0
=============================
5 Hilly's; Func runs:10000; result:0.9468984351872132
25 Hilly's; Func runs:10000; result:0.5865441453580522
500 Hilly's; Func runs:10000; result:0.3186653673403949
=============================
5 Forest's; Func runs:10000; result:0.9064162754293653
25 Forest's; Func runs:10000; result:0.43175851113448455
500 Forest's; Func runs:10000; result:0.06865408175918558
=============================
5 Megacity's; Func runs:10000; result:0.6783333333333333
25 Megacity's; Func runs:10000; result:0.213
500 Megacity's; Func runs:10000; result:0.03310000000000002
=============================
All score:4.18337 (46.4%)

Hilly

  Hillyテスト関数のMSO

Forest

  Forestテスト関数のMSO

Megacity

  Megacityテスト関数のMSO


まとめ

これまでの推論と結果を考慮して、次のように付け加えることができます。

実験中、記憶を使用したアルゴリズムは、記憶を使用しないアルゴリズムに比べ、若干結果が劣ることがわかりました。しかし、これは記憶ベースのアルゴリズムがあまり有望ではないということを意味するものではありません。おそらく、その結果を改善するためには、集団と粒子間の記憶交換の概念を修正する必要があるでしょう。

加えて、社会集団間の相互作用の他の原理を取り入れることで、記憶アルゴリズムの効率を大幅に改善できることも注目に値します。集団間の協力、調整、学習のメカニズムを導入することで、パフォーマンスが大幅に向上し、アルゴリズムが評価表の上位に入ることができます。

結論として、本研究は、セクター間の移動と記憶の使用に基づく社会集団の進化に関する新しい概念を提案しています。これらの概念は、社会システムとその協力、調整、適応能力を研究するための新たな可能性を開くものです。この結果が、複雑な社会環境において社会集団がどのように機能し、進化していくのかをよりよく理解する助けとなり、この分野のさらなる研究の契機となることを願っています。

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

添付されたファイル |
ニューラルネットワークが簡単に(第75回):軌道予測モデルのパフォーマンス向上 ニューラルネットワークが簡単に(第75回):軌道予測モデルのパフォーマンス向上
私たちが作成するモデルはより大きく、より複雑になっています。そのため、訓練だけでなく、運用にもコストがかかります。しかし、決断に要する時間はしばしば重要です。この観点から、品質を損なうことなくモデルのパフォーマンスを最適化する手法を考えてみましょう。
母集団最適化アルゴリズム:社会集団の進化(ESG) 母集団最適化アルゴリズム:社会集団の進化(ESG)
多母集団アルゴリズムの構成原理を考えます。この種のアルゴリズムの一例として、新しいカスタムアルゴリズムであるESG (Evolution of Social Groups)を見てみましょう。このアルゴリズムの基本概念、母集団相互作用メカニズム、利点を分析し、最適化問題におけるパフォーマンスを検証します。
多通貨エキスパートアドバイザーの開発(第2回):取引戦略の仮想ポジションへの移行 多通貨エキスパートアドバイザーの開発(第2回):取引戦略の仮想ポジションへの移行
複数の戦略を並行して動作させる多通貨エキスパートアドバイザー(EA)の開発を続けましょう。マーケットポジションを建てることに関連するすべての作業を、戦略レベルから、戦略を管理するEAのレベルに移してみましょう。戦略自体は、マーケットポジションを持つことなく、仮想の取引のみをおこないます。
最適化アルゴリズムを使用してEAパラメータをオンザフライで設定する 最適化アルゴリズムを使用してEAパラメータをオンザフライで設定する
この記事では、最適化アルゴリズムを使用して最適なEAパラメータをオンザフライで見つけることや、取引操作とEAロジックの仮想化について、実践的な側面から論じています。この記事は、最適化アルゴリズムをEAに実装するためのインストラクションとして使用できます。