English Русский 中文 Español Português
preview
Chaos Game Optimization (CGO)

Chaos Game Optimization (CGO)

MetaTrader 5Tester |
15 0
Andrey Dik
Andrey Dik

Inhalt

  1. Einführung
  2. Implementierung des Algorithmus
  3. Testergebnisse


Einführung

Optimierungsalgorithmen spielen eine strategische Rolle bei der Lösung komplexer Probleme nicht nur in verschiedenen Bereichen der modernen Wissenschaft, sondern auch im Handel. Mit der rasanten Entwicklung der Technik werden diese Aufgaben immer komplexer, und die Suche nach der besten Lösung wird immer energieaufwändiger. Daher steigen die Anforderungen an Optimierungsalgorithmen, ihre Effektivität und hohe betriebliche Effizienz. Eine der neuesten und vielversprechendsten Methoden ist der Chaos Game Optimization (CGO) Algorithmus, der von Siamak Talatahari und Mehdi Azizi im Jahr 2020 entwickelt wurde. Dieser Algorithmus basiert auf den Prinzipien der Chaostheorie und verwendet chaotische Sequenzen, um Lösungen zu erzeugen und zu verbessern.

Die Hauptidee des Algorithmus besteht darin, chaotische Sequenzen zu verwenden, um globale Optima in komplexen, mehrdimensionalen Räumen zu finden. Chaotische Sequenzen verfügen über bestimmte Eigenschaften, die es ihnen theoretisch ermöglichen, lokale Fallstricke zu vermeiden und qualitativ hochwertige Lösungen zu finden. In diesem Artikel werden wir die grundlegenden Prinzipien und Stufen des Chaos Game Optimization Algorithmus untersuchen, ihn in Code implementieren, Standardtests mit Testfunktionen durchführen und Schlussfolgerungen über seine Leistung ziehen.


Implementierung des Algorithmus

Stellen Sie sich eine Gruppe von Forschern vor, von denen jeder versucht, ein Extremum in einem mehrdimensionalen Labyrinth zu finden. Zu Beginn der Reise sind die Suchenden wahllos im Labyrinth verstreut und finden ihre erste Zuflucht innerhalb streng definierter räumlicher Grenzen. Dies ist ihr Ausgangspunkt. Jeder Suchende handelt nicht allein – er beobachtet seine Mitmenschen und wählt zu einem bestimmten Zeitpunkt eine zufällige Gruppe von Mitmenschen aus, berechnet den Mittelpunkt ihres Standorts, als ob er einen Gleichgewichtspunkt zwischen ihren Positionen finden würde.

Es ist die kollektive Weisheit, die sich aus der Erfahrung der Gruppe ergibt. Und dann beginnt der wahre Zauber des Chaos. Der Suchende kann einen von vier Wegen für seinen nächsten Schritt wählen. Jeder Pfad ist eine spezielle Bewegungsgleichung, bei der drei Schlüsselpunkte miteinander verwoben sind: die aktuelle Position des Suchenden, der beste von der gesamten Gruppe gefundene Ort und das Zentrum der ausgewählten Untergruppe. Diese Punkte werden gemischt, und die Stärke ihres Einflusses auf die weitere Bewegung wird durch das Verhältnis α – den Leiter des Chaos – bestimmt.

Der Quotient α selbst nimmt verschiedene Inkarnationen an, und jeder Suchende kann, den Regeln folgend, entweder von seiner Position aus losstürmen und zur goldenen Mitte zwischen dem besten Ergebnis und dem Zentrum der Gruppe eilen oder vom besten Punkt aus starten und den Raum um ihn herum erkunden, und er kann auch vom Zentrum der Gruppe losstürmen oder einen völlig zufälligen Sprung ins Ungewisse machen.

Am Ende jeder dieser Aktionen findet ein Vergleich der Ergebnisse statt. Findet einer der Suchenden einen Ort, der besser ist als der bisherige Rekord, wird er zum neuen Leuchtturm für die gesamte Gruppe bei ihrer weiteren Suche.

Das ist die wahre Schönheit des Algorithmus – seine Fähigkeit, Chaos in Ordnung zu verwandeln, Zufälligkeit in zielgerichtete Bewegung, Ungewissheit in Fortschritt, und jeder Schritt, jede Bewegung ist der Suche nach Lösungen zwischen dem Bekannten und dem Unbekannten, zwischen Stabilität und Risiko, zwischen Ordnung und Chaos untergeordnet.

CGO-Veranschaulichung

Abbildung 1. Typische Aktionen eines Suchagenten im CGO-Algorithmus

In Abbildung 1 ist der rote Punkt der aktuelle Agent, für den die neue Position berechnet wird. Die blauen Punkte sind eine Gruppe von zufällig ausgewählten Agenten in der Population in einer zufällig ausgewählten Anzahl. Der lila gepunktete Kreis ist die mittlere Position der Gruppe. Der goldene Punkt ist die beste gefundene Lösung. Grüne Punkte sind mögliche neue Positionen des Agenten nach verschiedenen Formeln:
  • Formel 1: aktuell + α(β×beste - γ×Durchschnitt)
  • Formel 2: beste + α(β×Durchschnitt - γ×aktuell)
  • Formel 3: Durchschnitt + α(β×beste - γ×aktuell)
  • Random: zufällige Position

    Die gestrichelten Linien zeigen die Vektoren des Einflusses der besten Lösung und der durchschnittlichen Position der Gruppe auf die Bewegung des aktuellen Agenten. Das grau gestrichelte Rechteck zeigt die Grenzen des Suchgebiets.

    Beginnen wir mit dem Schreiben des Pseudocodes für den Algorithmus.

  1. INITIALISIERUNG DES ALGORITHMUS:
    • Populationsgröße festlegen (Standard ist 50 Agenten)
    • Definieren der Suchgrenzen für jede Koordinate:
      • Mindestwerte (rangeMin)
      • Höchstwerte (rangeMax)
      • Schrittweite (rangeStep)
    • Für jeden Agenten in der Population:
      • Erzeuge zufällige Anfangskoordinaten innerhalb der vorgegebenen Grenzen.
      • Runde die Koordinaten unter Berücksichtigung der Stufe.
      • Berechne die Werte der Zielfunktion.
    • Bestimme die beste Ausgangslösung unter allen Agenten.
  2. HAUPTOPTIMIERUNGSSCHLEIFE:
    • Für jeden Agenten in der Population: 
    a) Wähle eine zufällige Untergruppe von Agenten aus:
    • Untergruppengröße = Zufallszahl zwischen 1 und der Grundgesamtheit
    • Wähle eine zufällige Auswahl von Agenten in einer Untergruppe.
    b) Berechne die durchschnittlichen Position der ausgewählten Untergruppe:
    • für jede Koordinate: average_coordinate = sum_of_group_coordinates / group_size
    c) Erstelle die Verhältniszahlen für die Bewegungsformeln:
    • α (alpha) = Wählen eine der Methoden nach dem Zufallsprinzip:
      • Methode 1: Zufallszahl von 0 bis 1
      • Methode 2: 2 × random(0,1) - 1 [Abruf einer Zahl von -1 bis 1]
      • Methode 3: Ir × random(0,1) + 1
      • Methode 4: Ir × random(0,1) + (1-Ir) mit Ir = zufällig 0 oder 1
    • β (beta) = zufällig 1 oder 2
    • γ (gamma) = zufällig 1 oder 2
    d) Wähle zufällig eine der vier Bewegungsformeln aus:
    • Formel 1: new_position = aktuell + α(β×beste - γ×Durchschnitt)
    • Formel 2: new_position = beste + α(β×Durchschnitt - γ×aktuell)
    • Formel 3: new_position = Durchschnitt + α(β×beste - γ×aktuell)
    • Formel 4: new_position = zufällige Position innerhalb der Suchgrenzen
    e) Wenden Sie die ausgewählte Gleichung an:
    • für jede Koordinate:
      • Berechne einen neuen Wert anhand der Gleichung
      • Prüfe für eine Suche außerhalb der Grenzen
      • Passe bei seiner Überschreitung den jew. Grenzwert an den nächstliegenden Grenzwert an.
      • Runde den Wert unter Berücksichtigung des Schrittweite.
    f) Berechne den Wert der Zielfunktion an der neuen Position.
  3. AKTUALISIERUNG DER BESTEN LÖSUNG:
    • Für jeden Agenten:
      • wenn der Wert der Zielfunktion des Agenten besser ist als der derzeit beste Wert:
        • Aktualisiere den Bestwert.
        • Speichere die Koordinaten der neuen besten Lösung.
  4. WIEDERHOLUNG:
    • Wiederhole die Schritte 2-3, bis die Stoppbedingung erfüllt ist:
      • Erreichen der maximalen Anzahl von Iterationen
      • oder Finden einer Lösung mit der erforderlichen Qualität
      • oder eines anderen Haltbarkeitskriteriums
  5. Kommen wir nun zur Implementierung des Algorithmus selbst. Die Klasse C_AO_CGO implementiert den CGO-Algorithmus und ist von der Klasse C_AO abgeleitet, wobei sie die Eigenschaften und Methoden der Basisklasse erbt. 

    Methoden:

    • SetParams () – setzt den Wert popSize basierend auf den Daten des params-Arrays. Dies ist wichtig, um den Algorithmus vor seiner Verwendung abzustimmen.
    • Init () – Initialisierungsmethode, die die minimalen und maximalen Werte des Bereichs, die Schrittweite und die Anzahl der Epochen akzeptiert. Er dient dazu, den Algorithmus für den Start vorzubereiten, indem die Suchgrenzen und andere Parameter festgelegt werden.
    • Moving () beschreibt die Schritte, die mit der Bewegung von Individuen während der Optimierung verbunden sind. Seine Umsetzung liefert die Logik der alternativen Lösungen und deren Verbesserung.
    • Revision () ist für die Überarbeitung der aktuellen Lösungen für die aktuelle Population sowie für die global beste Lösung zuständig.

    Private Methoden:

    • GetAlpha (), um den Alpha-Parameter zu erhalten, der zur Steuerung der Suchstrategie verwendet wird, sowie seine „Intensität“ und „Vielfalt“.
    • GenerateNewSolution () zur Erzeugung einer neuen Lösung auf der Grundlage des Index (seedIndex) und des Gruppenmittelwertes (meanGroup). 
    class C_AO_CGO : public C_AO
    {
      public: //--------------------------------------------------------------------
      ~C_AO_CGO () { }
      C_AO_CGO ()
      {
        ao_name = "CGO";
        ao_desc = "Chaos Game Optimization";
        ao_link = "https://www.mql5.com/en/articles/17047";
    
        popSize = 25;
    
        ArrayResize (params, 1);
        params [0].name = "popSize"; params [0].val = popSize;
      }
    
      void SetParams ()
      {
        popSize = (int)params [0].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 ();
    
      private: //-------------------------------------------------------------------
      double GetAlpha ();
      void   GenerateNewSolution (int seedIndex, double &meanGroup []);
    };
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Methode Init der Klasse C_AO_CGO ist für die Initialisierung der Parameter des Optimierungsalgorithmus zuständig, bevor dieser gestartet wird. Er nimmt die folgenden Argumente entgegen: Arrays mit den Minimal- und Maximalwerten für jede Suchvariable, die Schrittgröße für jede Variable und die Anzahl der Epochen (Iterationen) des Algorithmus.

    //——————————————————————————————————————————————————————————————————————————————
    bool C_AO_CGO::Init (const double &rangeMinP  [], // minimum values
                         const double &rangeMaxP  [], // maximum values
                         const double &rangeStepP [], // step change
                         const int     epochsP = 0)   // number of epochs
    {
      if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
    
      return true;
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Moving-Methode implementiert die Hauptlogik der Bewegung von Individuen der Lösungspopulation im CGO-Algorithmus. Das Hauptziel dieser Methode ist die Aktualisierung von Entscheidungen in einer Population auf der Grundlage von Regeln, einschließlich der Generierung neuer Entscheidungen und der Mittelung der Ergebnisse. Schauen wir uns die wichtigsten Bestandteile genauer an.

    Der erste Teil, die Initialisierung beim ersten Aufruf (wenn „revision“ gleich „false“ ist):

    • Die äußere Schleife wird über alle Elemente der Grundgesamtheit (popSize) und für jedes Element (Individuum i) durchlaufen:
      • Es wird die innere Schleife durch Koordinaten (coords) gestartet:
      • Es wird ein Zufallswert für jede Koordinate mit der Methode u.RNDfromCI (), die einen Zufallswert innerhalb des angegebenen Bereichs liefert.
      • Dieser Wert wird dann mit u.SeInDiSp() angepasst, wodurch sichergestellt wird, dass der Wert innerhalb des Bereichs bleibt und auf die nächste Stufe gerundet wird.
      • Es wird das Flag „revision“ für den nächsten Methodenaufruf auf „true“ gesetzt und die Methode beendet.
      Zweiter Teil, Aktualisierung der Population (wenn „Revision“ auf „true“ gesetzt ist):
      • Für jedes Individuum der Population:
        • Erzeuge eine zufällige Gruppengröße randGroupSize von 1 bis popSize.
        • Erstelle das Array meanGroup, um den Mittelwert der Koordinaten zu speichern. Die Größe des Arrays entspricht der Anzahl der Koordinaten und wird auf coords gesetzt.
        • Fülle das Array randIndices mit zufälligen Indizes (Individuen), die zur Bildung der Gruppe verwendet werden sollen.
        • Bei jeder Iteration werden zufällige Indizes zu randIndices hinzugefügt, wobei die Indizes zufällig ausgewählt werden.
        • Dann werden für jede Gruppe die Koordinatenwerte für jedes Individuum aus zufällig ausgewählten Indizes summiert und das Ergebnis in meanGroup gespeichert.
        • Nach der Summierung wird der Wert in meanGroup durch die Anzahl der Personen in der Gruppe geteilt, um den Mittelwert zu erhalten.
        • Erzeugen einer neuen Lösung für „i“ Individuum auf der Grundlage des Gruppenmittelwerts unter Verwendung der Methode GenerateNewSolution().
      //——————————————————————————————————————————————————————————————————————————————
      void C_AO_CGO::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;
        }
      
        //----------------------------------------------------------------------------
        for (int i = 0; i < popSize; i++)
        {
          int randGroupSize = u.RNDminusOne (popSize) + 1;
          double meanGroup [];
          ArrayResize (meanGroup, coords);
          ArrayInitialize (meanGroup, 0);
      
          int randIndices [];
          ArrayResize (randIndices, randGroupSize);
      
          for (int j = 0; j < randGroupSize; j++) randIndices [j] = u.RNDminusOne (popSize);
      
          for (int j = 0; j < randGroupSize; j++)
          {
            for (int c = 0; c < coords; c++)
            {
              meanGroup [c] += a [randIndices [j]].c [c];
            }
          }
          for (int c = 0; c < coords; c++) meanGroup [c] /= randGroupSize;
      
          GenerateNewSolution (i, meanGroup);
        }
      }
      //——————————————————————————————————————————————————————————————————————————————
      

      Bei der Revisionsmethode werden die besten Lösungen in der Population aktualisiert. Es durchläuft alle Individuen in der Population in einer Schleife und prüft für jedes Individuum, ob sein Fitnessfunktionswert „f“ größer ist als der aktuell beste Wert fB. Wenn ja, wird fB mit dem neuen Wert von „f“ aktualisiert und die c-Koordinaten des aktuellen Individuums werden in das Array cB kopiert. So findet und aktualisiert die Revisionsmethode die beste bekannte Lösung in der Population auf der Grundlage der Werte der Fitnessfunktion.

      //——————————————————————————————————————————————————————————————————————————————
      void C_AO_CGO::Revision ()
      {
        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);
          }
        }
      }
      //——————————————————————————————————————————————————————————————————————————————
      

      Die Methode GetAlpha erzeugt einen zufälligen Alphawert auf der Grundlage zufälliger Auswahlbedingungen und gibt ihn zurück.

      • Ir – Zufallswert gleich 0 oder 1.
      • Es gibt vier mögliche Fälle (aufgeführt in „Fall“), von denen jeder einen Wert „alpha“ unter Verwendung der entsprechenden Gleichung erzeugt:
        • Fall 0: Erzeugt einen Wert zwischen 0 und 1.
        • Fall 1: Erzeugt einen Wert von -1 bis 1.
        • Fall 2: Erzeugt einen Wert von 1 bis 2 durch Multiplikation mit „Ir“ (0 oder 1).
        • Fall 3: Erzeugt einen Wert, der von „Ir“ abhängt und einen Bereich von 0 bis 1 oder 1 hat, je nach dem Wert von „Ir“.
      Man beachte, dass die Ausdrücke, die zur Erzeugung der „Alpha“-Zahl verwendet werden, auch in einer einfacheren Form hätten verwendet werden können, doch wird die ursprüngliche Form verwendet, die der Gleichung der Autoren des Algorithmus entspricht.
        //——————————————————————————————————————————————————————————————————————————————
        double C_AO_CGO::GetAlpha ()
        {
          int Ir = u.RNDminusOne (2);
        
          switch (u.RNDminusOne (4))
          {
            case 0: return u.RNDfromCI (0, 1);
            case 1: return 2 * u.RNDfromCI (0, 1) - 1;
            case 2: return Ir * u.RNDfromCI (0, 1) + 1;
            case 3: return Ir * u.RNDfromCI (0, 1) + (1 - Ir);
          }
          return 0;
        }
        //——————————————————————————————————————————————————————————————————————————————
        

        Die Methode GenerateNewSolution ist für die Generierung einer neuen Lösung für einen bestimmten Agenten in der Population verantwortlich, basierend auf verschiedenen Zufallsparametern.

        Initialisierung der Parameter:
        • alpha ist der Wert, den man durch den Aufruf der Methode GetAlpha () erhält, um die neue Position zu beeinflussen.
        • beta und gamma sind Zufallswerte (1 oder 2).
        Auswählen einer Gleichung:
        • Formel – eine von vier möglichen Gleichungen wird zufällig ausgewählt, nach der die neue Position berechnet wird.
        Schleife nach Koordinaten: für jede Koordinate (von 0 bis coords):
        • newPos – eine Variable zum Speichern der neuen Position unter Verwendung der gewählten Gleichung.
        • Das hängt von der Bedeutung des Begriffs „Formel“ ab:
          • Fall 0: Eine neue Position wird berechnet als die aktuelle Position des Agenten plus eine Kombination von Koordinaten aus cB (der besten Lösung in der Population) und meanGroup.
          • Fall 1: Eine neue Position wird anhand der Koordinate aus cB und dem Mittelwert von meanGroup berechnet.
          • Fall 2: Eine neue Position wird durch den Durchschnittswert und die Koordinate des aktuellen Agenten bestimmt.
          • Fall 3: Eine neue Position wird zufällig innerhalb des angegebenen Bereichs (rangeMin [c] und rangeMax [c]) festgelegt.
        Berichtigung der neuen Position:
        • a [seedIndex].c [c] – die entsprechende Agentenkoordinate wird mit der Methode u.SeInDiSp() aktualisiert, die die Mindest- und Höchstwerte sowie die Schritte berücksichtigt, um sicherzustellen, dass der neue Wert innerhalb der zulässigen Grenzen liegt.
        //——————————————————————————————————————————————————————————————————————————————
        void C_AO_CGO::GenerateNewSolution (int seedIndex, double &meanGroup [])
        {
          double alpha = GetAlpha ();
          int    beta  = u.RNDminusOne (2) + 1;
          int    gamma = u.RNDminusOne (2) + 1;
        
          int formula = u.RNDminusOne (4);
        
          for (int c = 0; c < coords; c++)
          {
            double newPos = 0;
        
            switch (formula)
            {
              case 0:
                newPos = a [seedIndex].c [c] + alpha * (beta * cB [c] - gamma * meanGroup [c]);
                break;
        
              case 1:
                newPos = cB [c] + alpha * (beta * meanGroup [c] - gamma * a [seedIndex].c [c]);
                break;
        
              case 2:
                newPos = meanGroup [c] + alpha * (beta * cB [c] - gamma * a [seedIndex].c [c]);
                break;
        
              case 3:
                newPos = u.RNDfromCI (rangeMin [c], rangeMax [c]);
                break;
            }
        
            a [seedIndex].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
          }
        }
        //——————————————————————————————————————————————————————————————————————————————
        

        Nach der Durchführung von Tests habe ich versucht, die Konvergenz des Algorithmus zu verbessern, und beschlossen, einen Zusatz zur Grundversion des CGO-Algorithmus zu machen. Der Hauptunterschied besteht zu Beginn der Bearbeitung jeder Koordinate, bevor die grundlegenden Bewegungsgleichungen angewendet werden:

        double rnd = u.RNDprobab();                             // Get a random number from 0.0 to 1.0
        rnd *= rnd;                                             // Squate it
        int ind = (int)u.Scale(rnd, 0.0, 1.0, 0, popSize - 1);  // Scale to index
        a[seedIndex].c [c] = a[ind].c [c];                      // Copy the coordinate from another agent with the received index
        

        Die Koordinate wird von einem zufällig ausgewählten Agenten kopiert, und der Agent wird nicht gleichmäßig, sondern mit einer quadratischen Wahrscheinlichkeitsverteilung (rnd *= rnd) ausgewählt. Dies führt zu einer Verzerrung, einem „bias“ bei der Auswahl von Agenten mit kleineren Indizes (bessere Lösungen haben eine höhere Wahrscheinlichkeit, ausgewählt zu werden). Wir quadrieren die Zufallszahl, wodurch eine ungleichmäßige Verteilung entsteht, skalieren sie auf den Bereich der Populationsindizes und kopieren sie dann, bevor wir die grundlegenden Bewegungsgleichungen anwenden. Meine Bemühungen, die Konvergenz in vielversprechenden Bereichen zu beschleunigen, haben leider nicht die erwartete Wirkung gezeigt.

        Wahrscheinlich nimmt die Diversität in der Population infolge der vorzeitigen Konvergenz durch den Verstärkungseffekt schnell ab, was bei diesem Algorithmus dazu führt, dass er in einem noch größeren Ausmaß stecken bleibt; es ist möglich, dass die Logik des Algorithmus selbst dies verhindert. Nachstehend finden Sie den Abschnitt des Codes, an dem die Änderungen vorgenommen wurden. Darüber hinaus unternahm ich mehrere weitere Versuche, ihn zu verbessern, doch es wurden keine nennenswerten Fortschritte erzielt, und ich beschloss, bei der ursprünglichen Version des Algorithmus zu bleiben.

        //——————————————————————————————————————————————————————————————————————————————
        void C_AO_CGO::GenerateNewSolution (int seedIndex, double &meanGroup [])
        {
          double alpha = GetAlpha ();
          int    beta  = u.RNDminusOne (2) + 1;
          int    gamma = u.RNDminusOne (2) + 1;
        
          int formula = u.RNDminusOne (4);
        
          for (int c = 0; c < coords; c++)
          {
            double rnd = u.RNDprobab ();
            rnd *= rnd;
            int ind = (int)u.Scale (rnd, 0.0, 1.0, 0, popSize - 1);
            a [seedIndex].c [c] = a [ind].c [c];
        
            double newPos = 0;
        
            switch (formula)
            {
              case 0:
                newPos = a [seedIndex].c [c] + alpha * (beta * cB [c] - gamma * meanGroup [c]);
                break;
        
              case 1:
                newPos = cB [c] + alpha * (beta * meanGroup [c] - gamma * a [seedIndex].c [c]);
                break;
        
              case 2:
                newPos = meanGroup [c] + alpha * (beta * cB [c] - gamma * a [seedIndex].c [c]);
                break;
        
              case 3:
                newPos = u.RNDfromCI (rangeMin [c], rangeMax [c]);
                break;
            }
        
            a [seedIndex].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
          }
        }
        //——————————————————————————————————————————————————————————————————————————————
        


        Testergebnisse

        Wie Sie aus den nachstehenden Testergebnissen ersehen können, ist der Gesamtprozentsatz, den der Algorithmus erzielt, recht bescheiden. Wenn Sie jedoch genau hinsehen, können Sie eine interessante Eigenschaft dieses Algorithmus feststellen, die ich im Folgenden beschreiben werde.

        CGO|Chaos Game Optimization|50.0|
        =============================
        5 Hilly's; Func runs: 10000; result: 0.5725597668122144
        25 Hilly's; Func runs: 10000; result: 0.3715760642098293
        500 Hilly's; Func runs: 10000; result: 0.32017971142744234
        =============================
        5 Forest's; Func runs: 10000; result: 0.6117551660766816
        25 Forest's; Func runs: 10000; result: 0.619308424855028
        500 Forest's; Func runs: 10000; result: 0.6216109945434442
        =============================
        5 Megacity's; Func runs: 10000; result: 0.3753846153846153
        25 Megacity's; Func runs: 10000; result: 0.2192307692307692
        500 Megacity's; Func runs: 10000; result: 0.19028461538461647
        =============================
        All score: 3.90189 (43.35%)

        Die Visualisierung der Funktionsweise des Algorithmus auf Testfunktionen zeigt deutlich die Bildung von Strukturen bei der Gruppierung von Agenten, und diese Strukturen sind für verschiedene Aufgaben unterschiedlich. Aber die allgemeine Natur des Algorithmusbetriebs ist die riesige Bandbreite der Optimierungsergebnisse.

        Hilly

        CGO mit der Testfunktion Hilly

        Forest

        CGO mit der Testfunktion Forest

        Megacity

        CGO mit der Testfunktion Megacity

        Aufgrund der Testergebnisse belegt der CGO-Algorithmus Platz 38 in der Rangliste der populationsbasierten Optimierungsalgorithmen.

        # AO Beschreibung Hilly Hilly final Forest Forest final Megacity (discrete) Megacity final Final result % of MAX
        10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F)
        1 ANS Suche über die gesamte Nachbarschaft 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 Code-Sperr-Algorithmus (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 Optimierung der Tiermigration 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) Entwicklungsstrategien 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 Kometenschweif-Algorithmus (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 Zeit-Evolutions-Reise-Algorithmus (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 stochastische Diffusionssuche 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 AAm Algorithmus für das Bogenschießen 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
        9 ESG Entwicklung sozialer Gruppen (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
        10 SIA Simuliertes isotropes Glühen (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
        11 ACS künstliche, kooperative Suche 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
        12 DA dialektischer Algorithmus 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
        13 BHAm Algorithmus für schwarze Löcher 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
        14 ASO Anarchische Gesellschaftsoptimierung 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
        15 RFO Optimierung des Royal Flush (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
        16 AOSm Suche nach atomaren Orbitalen 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
        17 TSEA Schildkrötenpanzer-Evolutionsalgorithmus (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
        18 DE differentielle Evolution 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
        19 CRO Optimierung chemischer Reaktionen 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
        20 BIO Optimierung der Blutvererbung (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
        21 BSA Vogelschwarm-Algorithmus 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
        22 HS Harmoniesuche 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
        23 SSG Setzen, Säen und Wachsen 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
        24 BCOm Optimierung mit der bakteriellen Chemotaxis 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
        25 ABO Optimierung des afrikanischen Büffels 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
        26 (PO)ES (PO) Entwicklungsstrategien 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
        27 TSm Tabu-Suche 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
        28 BSO Brainstorming-Optimierung 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
        29 WOAm Wal-Optimierungsalgorithmus 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
        30 AEFA Algorithmus für künstliche elektrische Felder 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
        31 AEO Algorithmus zur Optimierung auf der Grundlage künstlicher Ökosysteme 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
        32 ACOm Ameisen-Kolonie-Optimierung 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
        33 BFO-GA Optimierung der bakteriellen Futtersuche — 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
        34 SOA einfacher Optimierungsalgorithmus 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
        35 ABHA Algorithmus für künstliche Bienenstöcke 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
        36 ACMO Optimierung atmosphärischer Wolkenmodelle 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
        37 ADAMm adaptive Momentabschätzung 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
        38 CGO Chaos Game Optimization 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
        39 ATAm Algorithmus für künstliche Stämme 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
        40 ASHA Algorithmus für künstliches Duschen 0.89686 0.40433 0.25617 1.55737 0.80360 0.35526 0.19160 1.35046 0.47692 0.18123 0.09774 0.75589 3.664 40.71
        41 ASBO Optimierung des adaptiven Sozialverhaltens 0.76331 0.49253 0.32619 1.58202 0.79546 0.40035 0.26097 1.45677 0.26462 0.17169 0.18200 0.61831 3.657 40.63
        42 MEC Evolutionäre Berechnung des Geistes 0.69533 0.53376 0.32661 1.55569 0.72464 0.33036 0.07198 1.12698 0.52500 0.22000 0.04198 0.78698 3.470 38.55
        43 CSA Kreis-Such-Algorithmus 0.66560 0.45317 0.29126 1.41003 0.68797 0.41397 0.20525 1.30719 0.37538 0.23631 0.10646 0.71815 3.435 38.17
        44 IWO Optimierung mit invasiven Unkräutern 0.72679 0.52256 0.33123 1.58058 0.70756 0.33955 0.07484 1.12196 0.42333 0.23067 0.04617 0.70017 3.403 37.81
        45 Micro-AIS Künstliches Mikro-Immunsystem 0.79547 0.51922 0.30861 1.62330 0.72956 0.36879 0.09398 1.19233 0.37667 0.15867 0.02802 0.56335 3.379 37.54

        RW Random Walk 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


        Zusammenfassung

        Nach der Analyse der Ergebnisse des CGO-Algorithmus bin ich zu einigen wichtigen Schlussfolgerungen gekommen. Der Algorithmus der Chaos Game Optimization zeigt ein sehr interessantes Verhalten. Insgesamt ist seine Effizienz als unterdurchschnittlich einzustufen, was durch das Gesamtergebnis von 43,35 % bestätigt wird. Am bemerkenswertesten ist jedoch sein Verhalten bei der Skalierung des Problems; CGO zeigt gerade bei mehrdimensionalen Problemen – Tests mit einer Dimension von 1000 Variablen – eine hohe Effizienz. Dies ist eine untypische Eigenschaft für die meisten metaheuristischen Algorithmen, die in der Regel unter dem „Fluch der Dimensionen“ leiden und mit zunehmender Anzahl von Variablen an Effizienz verlieren. Im Gegenteil, CGO übertrifft seine Ergebnisse bei 10- und 50-dimensionalen Problemen manchmal sogar, wenn es mit 1000-dimensionalen Problemen arbeitet. Besonders deutlich wird dies bei der Forest-Testfunktion, die ein globales Extremum an einem „scharfen“ Punkt aufweist.

        Ich glaube, dass dieses Phänomen auf die Natur des Algorithmus selbst zurückzuführen ist. Die chaotische Natur von CGO und die Vielfalt der Bewegungsgleichungen schaffen einen effizienten Mechanismus zur Erkundung hochdimensionaler Räume. Vier verschiedene Positionsaktualisierungsstrategien, eine zufällige Auswahl zwischen ihnen und ein unvorhersehbares α-Verhältnis ermöglichen es dem Algorithmus, Probleme in komplexen mehrdimensionalen Landschaften zu lösen. Besonders gut schnitt der Algorithmus bei Funktionen vom Typ Forest ab, mit Ergebnissen von 0,61-0,62, die deutlich über seinem Durchschnitt liegen.

        Wenn ich den Entwurf des Algorithmus analysiere, sehe ich, dass seine Stärke in hohen Dimensionen mit der koordinatenweisen Verarbeitung zusammenhängt. Anstatt mit dem gesamten Lösungsvektor zu arbeiten, aktualisiert CGO jede Koordinate unabhängig, was bei zunehmender Dimensionalität von Vorteil ist. Darüber hinaus gewährleistet die Verwendung von Zufallsgruppen und deren Durchschnittspositionen einen effizienten Informationsaustausch zwischen den Agenten auch in hochdimensionalen Räumen.

        Ich habe versucht, die Oberfläche der Funktion Forrest in verschiedenen Winkeln zu drehen, um sicherzugehen, dass die interessanten Ergebnisse, die ich erhielt, nicht nur auf die spezifischen Merkmale der Algorithmuslogik und der entsprechenden Testfunktion zurückzuführen sind. Dies war notwendig, um die Möglichkeit auszuschließen, versehentlich auf ein globales Extremum zu stoßen. Experimente mit Funktionsrotation haben nur bestätigt, dass solche Ergebnisse nicht zufällig sind. In Anbetracht dieser Besonderheit im Umgang von CGO mit Funktionen mit scharfen Extremen empfehle ich, bei Verwendung dieses Algorithmus mehrere Optimierungsläufe durchzuführen. Diese Empfehlung ist für diesen Algorithmus besonders wichtig.

        Insgesamt ist CGO trotz seiner durchschnittlichen Gesamtleistung aufgrund seiner einzigartigen Fähigkeit, die Effizienz bei zunehmender Problemgröße beizubehalten und sogar zu verbessern, ein außerordentlich interessanter Algorithmus für weitere Untersuchungen und Anwendungen auf komplexe Optimierungsprobleme.

        Tabelle

        Abbildung 2. Farbabstufung der Algorithmen nach den entsprechenden Tests

        Histogramm

        Abbildung 3. Histogramm der Algorithmus-Testergebnisse (Skala von 0 bis 100, je höher, desto besser, wobei 100 das maximal mögliche theoretische Ergebnis ist; im Archiv befindet sich ein Skript zur Berechnung der Bewertungstabelle)

        Vor- und Nachteile von CGO:

        Vorteile:

        1. Keine externen Parameter
        2. Gute Konvergenz bei hoch- und mitteldimensionalen Funktionen

        Nachteile:

        1. Bleibt bei niedrigdimensionalen Problemen an lokalen Extremen hängen.

        Der Artikel wird von einem Archiv mit den aktuellen Versionen der Codes der Algorithmen begleitet. Der Autor des Artikels übernimmt keine Verantwortung für die absolute Richtigkeit der Beschreibung der kanonischen Algorithmen. An vielen von ihnen wurden Änderungen vorgenommen, um die Suchmöglichkeiten zu verbessern. Die in den Artikeln dargelegten Schlussfolgerungen und Urteile beruhen auf den Ergebnissen der Versuche.


        Programme, die im diesem Artikel verwendet werden

        # Name Typ Beschreibung
        1 #C_AO.mqh
        Include
        Elternklasse der Populationsoptimierung
        Algorithmen
        2 #C_AO_enum.mqh
        Include
        Enumeration der Algorithmen zur Populationsoptimierung
        3 TestFunctions.mqh
        Include
        Bibliothek mit Testfunktionen
        4
        TestStandFunctions.mqh
        Include
        Bibliothek mit Funktionen für den Prüfstand
        5
        Utilities.mqh
        Include
        Bibliothek mit Hilfsfunktionen
        6
        CalculationTestResults.mqh
        Include
        Skript zur Berechnung der Ergebnisse in der Vergleichstabelle
        7
        Testing AOs.mq5
        Skript Der einheitliche Prüfstand für alle Algorithmen zur Populationsoptimierung
        8
        Simple use of population optimization algorithms.mq5
        Skript
        Ein einfaches Beispiel für die Verwendung von Algorithmen zur Populationsoptimierung ohne Visualisierung
        9
        Test_AO_CGO.mq5
        Skript CGO-Prüfstand

        Übersetzt aus dem Russischen von MetaQuotes Ltd.
        Originalartikel: https://www.mql5.com/ru/articles/17047

        Beigefügte Dateien |
        CGO.zip (168.66 KB)
        Von der Grundstufe bis zur Mittelstufe: Structs (II) Von der Grundstufe bis zur Mittelstufe: Structs (II)
        In diesem Artikel werden wir versuchen zu verstehen, warum Programmiersprachen wie MQL5 Strukturen haben und warum in einigen Fällen Strukturen der ideale Weg sind, um Werte zwischen Funktionen und Prozeduren zu übergeben, während sie in anderen Fällen vielleicht nicht der beste Weg sind, dies zu tun.
        Marktsimulation (Teil 07): Sockets (I) Marktsimulation (Teil 07): Sockets (I)
        Sockets. Wissen Sie, wofür sie da sind oder wie man sie in MetaTrader 5 verwendet? Wenn die Antwort nein lautet, sollten wir sie zunächst studieren. Im heutigen Artikel werden wir die Grundlagen behandeln. Da es mehrere Möglichkeiten gibt, das Gleiche zu tun, und wir immer am Ergebnis interessiert sind, möchte ich zeigen, dass es tatsächlich eine einfache Möglichkeit gibt, Daten aus MetaTrader 5 in andere Programme, wie z. B. Excel, zu übertragen. Die Hauptidee ist jedoch nicht, Daten von MetaTrader 5 nach Excel zu übertragen, sondern umgekehrt, d.h. Daten von Excel oder einem anderen Programm nach MetaTrader 5 zu übertragen.
        Marktsimulation (Teil 08): Sockets (II) Marktsimulation (Teil 08): Sockets (II)
        Wie wäre es, etwas Praktisches mit Sockets zu schaffen? Im heutigen Artikel werden wir mit der Erstellung eines Mini-Chats beginnen. Schauen wir uns gemeinsam an, wie das gemacht wird – es wird sehr interessant sein. Bitte beachten Sie, dass der hier zur Verfügung gestellte Code nur für Lehrzwecke gedacht ist. Es sollte nicht für kommerzielle Zwecke oder in vorgefertigten Anwendungen verwendet werden, da es keine Sicherheit bei der Datenübertragung bietet und die über den Socket übertragenen Inhalte eingesehen werden können.
        Biologisches Neuron zur Vorhersage von Finanzzeitreihen Biologisches Neuron zur Vorhersage von Finanzzeitreihen
        Wir werden ein biologisch korrektes System von Neuronen für die Vorhersage von Zeitreihen aufbauen. Die Einführung einer plasmaähnlichen Umgebung in die Architektur des neuronalen Netzes schafft eine Art „kollektive Intelligenz“, bei der jedes Neuron den Betrieb des Systems nicht nur durch direkte Verbindungen, sondern auch durch weitreichende elektromagnetische Wechselwirkungen beeinflusst. Mal sehen, wie sich das neuronale Gehirnmodellierungssystem auf dem Markt schlagen wird.