English Русский 中文 Español 日本語 Português
preview
Algorithmus der Atomic Orbital Search (AOS)

Algorithmus der Atomic Orbital Search (AOS)

MetaTrader 5Beispiele |
21 1
Andrey Dik
Andrey Dik

Inhalt

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


Einführung

Moderne Ansätze zur Lösung komplexer Optimierungsprobleme lassen sich zunehmend von den Prinzipien der Physik, insbesondere der Quantenmechanik, inspirieren. In diesem Artikel betrachten wir den Algorithmus Atomic Orbital Search (AOS), der auf den Konzepten des atomaren Orbitalmodells basiert. Der Algorithmus wurde von Mahdi Azizi im Jahr 2021 vorgeschlagen. Dieser Algorithmus ist eine neue metaheuristische Methode. Das Modell beschreibt das Verhalten der Elektronen nicht als streng definierte Flugbahnen, sondern als Wellenfunktionen, die Wahrscheinlichkeitswolken um den Atomkern herum bilden, dank der wissenschaftlichen Entwicklungen des herausragenden Physikers Erwin Schroeder. 

Ein Atomorbital, das das Ergebnis einer Quantenbeschreibung ist, ist ein Bereich, in dem die Wahrscheinlichkeit, ein Elektron zu finden, maximal ist. In diesem Modell bewegen sich die Elektronen in imaginären Schichten, die durch Radien und Quantenzahlen definiert sind, die Energieniveaus widerspiegeln. Schichten mit höheren n-Werten entsprechen größeren Radien und dementsprechend höheren Energieniveaus. Dieses Verhalten der Elektronen, das durch die Wechselwirkung mit anderen Teilchen und den Einfluss von Photonen angeregt wird, schafft eine dynamische und sich verändernde Umgebung, in der Elektronen Energie abgeben oder aufnehmen können, wenn sie sich zwischen verschiedenen Orbitalen bewegen.

Der AOS-Algorithmus nutzt diese physikalischen Prinzipien, um den Prozess der Lösungsfindung für Optimierungsprobleme zu modellieren. Es berücksichtigt Wahrscheinlichkeitsverteilungen und Interaktionsdynamik, was eine effiziente Erkundung des Lösungsraums ermöglicht. Insbesondere berücksichtigt der Algorithmus Aktualisierungen der Positionen der Lösungsvorschläge (Elektronen) in Abhängigkeit von ihren Energien, was sich wiederum auf die Wahrscheinlichkeit auswirkt, sich in bestimmten Schichten zu befinden. Dadurch kann AOS nicht nur optimale Lösungen finden, sondern sich auch an Veränderungen in der Umgebung anpassen.

In diesem Beitrag werden wir das mathematische Modell von AOS im Detail untersuchen, einschließlich der Schritte zur Aktualisierung der Positionen der Lösungsvorschläge sowie der Mechanismen, die die Energieaufnahme und -abgabe regeln. AOS ist also nicht nur ein interessanter Ansatz für die Optimierung, sondern eröffnet auch neue Horizonte für die Anwendung von Quantenprinzipien auf Berechnungsprobleme.


Implementierung des Algorithmus

Der AOS-Algorithmus basiert auf den Prinzipien des Atomorbitalmodells, das die Emission und Absorption von Energie durch Atome sowie die Konfiguration der Elektronendichte berücksichtigt. Zu Beginn des Algorithmus werden mehrere Lösungsvorschläge mit der Bezeichnung X angegeben, die als Elektronen um den Kern eines Atoms betrachtet werden. Diese Kandidaten bilden eine Elektronenwolke, und der Suchraum wird als ein kugelförmiges Volumen dargestellt, das in konzentrische Schichten unterteilt ist. Die Lösungskandidaten können in allgemeiner Form wie folgt geschrieben werden:

X = [x1, x2 ..., xj ..., xm], wobei xi der i-te Lösungskandidat ist, während m die Gesamtzahl der Kandidaten ist.

Die Anfangspositionen der Lösungskandidaten werden nach dem Zufallsprinzip initialisiert. Jedes Elektron hat ein Energieniveau, das durch eine Zielfunktion bestimmt wird, die es zu minimieren gilt. So entsprechen Elektronen mit niedrigen Energieniveaus den Kandidaten mit den besten Zielfunktionswerten, und Elektronen mit hohen Energieniveaus entsprechen den Kandidaten mit den schlechtesten Werten. Der Vektor der Werte der Zielfunktion wird wie folgt geschrieben:

E = [E1, E2, ..., Ei, ..., Em], wobei Ei das Energieniveau des i-ten Kandidaten ist.

Die imaginären Schichten um den Kern herum werden mit einer zufälligen ganzen Zahl n modelliert, die von 1 bis zur Anzahl der Schichten L reichen kann. Die Schicht mit dem kleinsten Radius L0 stellt den Kern dar, und die übrigen Li-Schichten sind der Ort, an dem sich die Elektronen befinden (bei AOS kann die „Kern“-Schicht auch Elektronen enthalten). Die Verteilung der Lösungskandidaten auf die verschiedenen Schichten erfolgt mithilfe der Wahrscheinlichkeitsdichtefunktion (PDF), die die Wahrscheinlichkeit bestimmt, den Wert einer Variablen in einem bestimmten Bereich zu finden. Der Algorithmus verwendet eine Log-Normal-Verteilung, die es ihm ermöglicht, das reale Wellenverhalten von Elektronen zu simulieren. Die Lösungskandidaten werden auf verschiedene Schichten verteilt, wobei der Vektor Xk, der die Kandidaten in n Schichten enthält, wie folgt festgelegt wird:

Xk = [Xk1, Xk2, ..., Xki, ..., Xkp], wobei k ein Schichtindex und p die Anzahl der Kandidaten in der Schicht ist.

Nach dem atomaren Orbitalmodell wird davon ausgegangen, dass sich die Elektronen im Grundzustand befinden. Der Bindungszustand und die Bindungsenergie für jede Schicht werden wie folgt berechnet:

BS_k = (1/p) * Σ(Xki),

BE_k = (1/p) * Σ(Eki).

Das Gesamtenergieniveau eines Atoms ist definiert als:

BS = (1/m) * Σ(Xi),

BE = (1/m) * Σ(Ei).

Unter dem Einfluss von Photonen und anderen Wechselwirkungen können Elektronen ihre Position verändern und sich zwischen Schichten bewegen. Die Aktualisierung der Position der Lösungskandidaten im AOS-Algorithmus basiert auf der Interaktionswahrscheinlichkeit, die durch eine zufällig erzeugte ϕ-Zahl dargestellt wird, die im Bereich [0,1] verteilt ist. Wenn ϕ ≥ PR (Photonengeschwindigkeitsparameter), dann ist eine Emission oder Absorption von Energie möglich.

Wenn Eki ≥ BEk ist, kommt es zur Energieabgabe: Xki[t+1] = Xkit + αi × (βi × LE − γi × BS) / k.

Wenn Eki < BEk ist, erfolgt eine Energieabsorption: Xki[t+1] = Xkit + αi × (βi × LEk − γi × BSk).

Ist ϕ < PR, so werden Verschiebungen in Magnetfeldern oder Wechselwirkungen mit anderen Teilchen berücksichtigt: Xki[t+1] = Xkit + ri, wobei ri ein zufälliges Inkrement im Bereich von min bis max des entsprechenden optimierten Parameters des Problems ist.

Vereinfacht ausgedrückt, kann die Population der Lösungsvorschläge in AOS als Molekül dargestellt werden, wobei die Atome den Koordinaten im Suchraum und die Elektronen in diesen Atomen den spezifischen Lösungen entsprechen. Wenn also die Population aus 50 Lösungsansätzen besteht, dann gibt es in jedem Atom 50 Elektronen, die gemäß der Log-Normal-Verteilung über die Schichten verteilt sind.

In der Beschreibung des Algorithmus gibt der Autor nicht an, wie der Durchmesser der äußeren Atomschicht bestimmt wird, was bedeutet, dass sich der Atomkern im Verhältnis zu den Schichten in der Mitte befindet. Das bedeutet, dass sich das Atom zusammen mit den Schichten innerhalb der vorgegebenen Grenzen des Problems bewegt. Um dem Algorithmus mehr Flexibilität zu geben, vereinbaren wir, dass der Durchmesser der äußeren Schicht dem [min; max]-Bereich für die entsprechende Koordinate im Suchraum entspricht und der Mittelpunkt des Atomkerns am Punkt der besten globalen Lösung für die gegebene Koordinate liegt. Das Modell eines Atoms in AOS kann in Abbildung 1 dargestellt werden.

AOS

Abbildung 1. Modell eines Atoms im AOS-Algorithmus, wobei die Punkte Elektronen darstellen und die gestrichelte Linie die lognormale Verteilung der Elektronen repräsentiert

Pseudocode des Atomic Orbital Search (AOS)-Algorithmus:

1. Initialisierung

1.1 Ausgangspositionen (Xi)

Es wird eine Population von m Lösungsvorschlägen erstellt
Jedem Kandidaten wird eine zufällige Position im Suchraum zugewiesen.

1.2 Berechnung der anfänglichen Fitness (Ei)

Für jeden Kandidaten wird der Wert der Zielfunktion berechnet
Dieser Wert stellt die Energie des Teilchens dar.
Je niedriger die Energie, desto besser die Lösung.

1.3 Bestimmung der Atomparameter

BS (Binding State) ist der Bindungszustand des Atoms, der die aktuelle Durchschnittsposition aller Teilchen darstellt
BE (Binding Energy) steht für die durchschnittliche Energie aller Teilchen
LE (Lowest Energy) ist ein Teilchen mit der niedrigsten Energie (beste Lösung)

2. Erstellen einer Schicht-Struktur

2.1 Generierung einer zufälligen Anzahl von Schichten [1; n] für jedes Atom

Die Anzahl der imaginären Orbitale wird bestimmt
Jedes Orbital stellt eine Schicht der Suche mit unterschiedlicher Intensität dar.

2.2 Partikelverteilung

Die Partikel werden gemäß der Wahrscheinlichkeitsdichtefunktion (PDF) in Schichten verteilt
Die inneren Schichten enthalten in der Regel die besten Lösungen.
Die äußeren Schichten werden zur Erforschung des Raumes verwendet.

2.3 Suchprozess für jede Schicht (k)

3.1 Schicht-Parameter

BSk ist der Verbindungsstatus für eine bestimmte Schicht
BEk - Bindungsenergie der Schicht
LEk ist das Teilchen mit der niedrigsten Energie in der Schicht

3.2 Aktualisierung der Partikelpositionen

Für jedes Partikel i in der Schicht k:

3.3 Generierung von Steuerungsparametern:

   φ: Definition der Bewegungsart
   α: Skalierungsfaktor
   β: Koeffizient der Anziehungskraft auf die beste Lösung
   γ: Koeffizient der Abstoßung vom mittleren Zustand
   PR: Wahrscheinlichkeit der Photonenbewegung

3.4 Bewegungsart auswählen:

   wenn φ ≥ PR:
       wenn Eki ≥ BEk:
           // Globale Forschung
           Xi[t+1] = Xit + αi × (βi × LE - γi × BS) / k
       sonst:
           // Lokale Forschung
           Xi[t+1] = Xit + αi × (βi × LEk - γi × BSk)
   sonst:
       // Zufällige Bewegung
       Xki[t+1] = Xkit + ri

4. Berechnung der Fitness (Ei)  

5. Aktualisierung der globalen Einstellungen

6. Wiederholen des Vorgang ab 1.3, bis das Stoppkriterium erfüllt ist.

Um die Wahrscheinlichkeit der Elektronenverteilung um den Kern (die beste Lösung) zu berechnen, kann man die Zahlenbildung für verschiedene Verteilungen verwenden. Der Autor bevorzugt die Log-Normal-Verteilung, was ihre Implementierung im Code erfordert. Schreiben wir nun den Generatorcode. Für den Algorithmus ist es notwendig, nicht nur eine lognormale Verteilung zu erstellen, sondern eine, die asymmetrisch zum Zentrum (Kern) verschoben ist, wie in Abbildung 1 dargestellt. Wir implementieren die Funktion LognormalDistribution in der Funktionssammlungsbibliothek für Optimierungsalgorithmen, die eine Zufallszahl erzeugt, die nach dem Lognormalgesetz innerhalb der vorgegebenen Grenzen mit einer Vorspannung verteilt ist.

Die Funktion benötigt die folgenden Parameter:

1. center - Zentralwert der Verteilung.
2. min_value - Mindestwert, der erzeugt werden kann.
3. max_value - maximaler Wert, der erzeugt werden kann.
4. peakDisplCoeff - Koeffizient der Spitzenverschiebung relativ zum Verteilungszentrum (Standardwert ist 0,2).

Beschreibung der Funktion:

1. Kontrolle der Grenzen:
    Wenn min_value größer oder gleich max_value ist, gibt die Funktion max_value zurück.
    Wenn max_value kleiner oder gleich min_value ist, gibt die Funktion min_value zurück.

2. Die Zufallszahl wird im Bereich von 0 bis 1 erzeugt.

3. Einstellung der Mitte:
    Wenn center kleiner als min_value ist, wird es auf min_value und random wird auf 0 gesetzt.
    Wenn center größer als max_value ist, wird es auf max_value und random wird auf 0 gesetzt.

4. Berechnen der Werte peak_left und peak_right, die die Position der Verteilungsspitzen bestimmen.

5. Erzeugen eines Wertes:
    Wenn random kleiner als 0,5 ist, wird die Berechnung für den linken Teil der Verteilung durchgeführt:
        Berechnen der Parameter mu_left und sigma_left.
        Erzeugen von Zufallszahlen u1 und u2 für das Box-Muller-Verfahren.
        Anwenden der Box-Muller-Methode, um einen normalverteilten Wert z zu erhalten.
        Das Ergebnis für die linke Seite wird berechnet.
    Wenn random größer oder gleich 0,5 ist, wird ein ähnlicher Prozess für die rechte Seite der Verteilung unter Verwendung der Parameter mu_right und sigma_right durchgeführt.

6. Wenn der generierte Ergebniswert über min_value und max_value hinausgeht, wird die Funktion RNDfromCI aufgerufen, um den Wert in den akzeptablen Bereich zu „werfen“ und so die Akkumulation von Wahrscheinlichkeiten an den Grenzen der generierten Zufallszahlen zu verhindern.

//------------------------------------------------------------------------------
//The lognormal distribution of the species:  min|------P---C---P------|max
double C_AO_Utilities :: LognormalDistribution (double center, double min_value, double max_value, double peakDisplCoeff = 0.2)
{
  // Check the right border
  if (min_value >= max_value)
  {
    return max_value;
  }

  // Check the left border
  if (max_value <= min_value)
  {
    return min_value;
  }

  // Generate a random number from 0 to 1
  double random = MathRand () / 32767.0;

  // Correction of the center if it goes beyond the boundaries
  if (center < min_value)
  {
    center = min_value;
    random = 1;
  }

  if (center > max_value)
  {
    center = max_value;
    random = 0;
  }

  // Calculate the position of the peaks
  double peak_left  = center - (center - min_value) * peakDisplCoeff;
  double peak_right = center + (max_value - center) * peakDisplCoeff;

  double result = 0.0;

  if (random < 0.5) // Left side of the distribution
  {
    // Calculate parameters for the left side
    double diff_center_peak = MathMax (center - peak_left, DBL_EPSILON);
    double diff_center_min  = MathMax (center - min_value, DBL_EPSILON);

    double mu_left = MathLog (diff_center_peak);
    double sigma_left = MathSqrt (2.0 * MathLog (MathMax (diff_center_min / diff_center_peak, DBL_EPSILON)) / 9.0);

    // Generate random numbers for the Box-Muller method
    double u1 = MathRand () / 32767.0;
    double u2 = MathRand () / 32767.0;

    // Protection against null values
    u1 = MathMax (u1, DBL_EPSILON);

    // Application of the Box-Muller method
    double z = MathSqrt (-2.0 * MathLog (u1)) * MathCos (2.0 * M_PI * u2);

    // Calculate the result for the left side
    result = center - MathExp (mu_left + sigma_left * z);
  }
  else // Right side of the distribution
  {
    // Calculate parameters for the right side
    double diff_peak_center = MathMax (peak_right - center, DBL_EPSILON);
    double diff_max_center  = MathMax (max_value - center,  DBL_EPSILON);

    double mu_right    = MathLog  (diff_peak_center);
    double sigma_right = MathSqrt (2.0 * MathLog (MathMax (diff_max_center / diff_peak_center, DBL_EPSILON)) / 9.0);

    // Generate random numbers for the Box-Muller method
    double u1 = MathRand () / 32767.0;
    double u2 = MathRand () / 32767.0;

    // Protection against null values
    u1 = MathMax (u1, DBL_EPSILON);

    // Application of the Box-Muller method
    double z = MathSqrt (-2.0 * MathLog (u1)) * MathCos (2.0 * M_PI * u2);

    // Calculate the result for the right side
    result = center + MathExp (mu_right + sigma_right * z);
  }

  // Check and correct the result if it goes beyond the limits
  if (result < min_value || result > max_value) return RNDfromCI (min_value, max_value);

  return result;
}

Schreiben wir ein Skript, um die resultierende Verteilung visuell zu überprüfen. Das ist es, was das Testskript tut (wir werden den Rest des Codes nicht zur Verfügung stellen - die Klasse für die Arbeit mit dem Hintergrund „Canvas“ für den Test kann im Artikelarchiv gefunden werden):

1. Erstellen des Objekts Canvas zum Zeichnen von Grafiken.
2. Initialisierung der Canvas-Parameter: B Breite, H Höhe und O Abstände.
3. Erstellen der Arrays CountL und CountR, um die Werte links und rechts der mit Nullen initialisierten Eingabe Inp_P zu zählen.
4. Erstellen eines grafischen Elements (Canvas) mit bestimmten Abmessungen und Hintergrundfarben.

Die Log-Normalverteilung beschreibt Zufallsvariablen, deren Logarithmus normalverteilt ist. Im Code wird er verwendet, um Werte zu erzeugen, die im Diagramm angezeigt werden.

5. In der for-Schleife werden N Werte mit der Funktion U.LognormalDistribution() erzeugt. Jeder Wert wird mit Inp_P verglichen: Wenn er kleiner ist, wird der Zähler CountL[i] erhöht, wenn er größer ist - CountR[i].
6. Vor der Erzeugung werden CountL und CountR mit Nullen initialisiert.
7. Die Minimal- und Maximalwerte in den Feldern werden berechnet, um den Bereich der Diagramme zu bestimmen.
8. Die Koordinaten für das Zeichnen von Diagrammen werden berechnet, einschließlich der Mitte des Hintergrunds und der Schritte für den linken und rechten Teil.
9. Auf dem Hintergrund werden Punkte gezeichnet, die die Anzahl der Werte in den Bereichen darstellen, wobei die Farbe durch die Häufigkeit des Auftretens bestimmt wird.
10. Der Hintergrund wird aktualisiert, um die Änderungen widerzuspiegeln.

// Function called at startup
void OnStart ()
{
    CCanvas Canvas; // Object for handling graphics (canvas)

    // Canvas parameters
    int W = 750; // Canvas width
    int H = 400; // Canvas height
    int O = 10;  // Margins from canvas borders

    // Arrays for storing count values
    int CountL []; // Count values to the left of the input
    int CountR []; // Count values to the right of the input

    // Initialize arrays
    ArrayResize (CountL, Size_P);  // Resize the CountL array
    ArrayInitialize (CountL, 0);   // Initialize the CountL array with zeros

    ArrayResize (CountR, Size_P);  // Resize the CountR array
    ArrayInitialize (CountR, 0);   // Initialize the CountR array with zeros

    // Create a canvas
    string canvasName = "Test_Probability_Distribution_Canvas"; // Canvas name
    if (!Canvas.CreateBitmapLabel(canvasName, 5, 30, W, H, COLOR_FORMAT_ARGB_RAW))
    {
        Print ("Error creating Canvas: ", GetLastError()); // Display an error if creation fails
        return;
    }

    // Set up canvas properties
    ObjectSetInteger (0, canvasName, OBJPROP_HIDDEN, false);    // Make canvas visible
    ObjectSetInteger (0, canvasName, OBJPROP_SELECTABLE, true); // Make canvas selectable

    // Clear the canvas and draw the border
    Canvas.Erase (COLOR2RGB(clrWhite));                         // Fill with white color
    Canvas.Rectangle (1, 1, W - 1, H - 1, COLOR2RGB(clrBlack)); // Draw a black frame

    int    ind = 0;   // Index for counting
    double X   = 0.0; // Variable for storing values

    // Main loop for generating values
    for (int i = 0; i < CNT_P; i++)
    {
        // Generate log-normal distribution
        X = U.LognormalDistribution (Inp_P, Min_P, Max_P, PeakDisplCoeff_P);

        // Determine which side of the input parameter the value falls on
        if (X < Inp_P)
        {
            // Calculate the index for the left part
            ind = (int) U.Scale(X, Min_P, Inp_P, 0, Size_P, true);
            if (ind >= Size_P) ind = Size_P - 1; // Limit the index
            if (ind < 0) ind = 0;                // Limit the index
            CountL [ind] += 1;                   // Increment the counter for the left side
        }
        else
        {
            // Calculate the index for the right side
            ind = (int) U.Scale (X, Inp_P, Max_P, 0, Size_P, false);
            if (ind >= Size_P) ind = Size_P - 1; // Limit the index
            if (ind < 0) ind = 0;                // Limit the index
            CountR [ind] += 1;                   // Increment the counter for the right side
        }
    }

    // Define minimum and maximum values for the graph
    int minCNT = CNT_P; // Initial value for the minimum counter
    int maxCNT = 0;     // Initial value for the max counter

    // Finding minimum and maximum values in counters
    for (int i = 0; i < Size_P; i++)
    {
        if (CountL [i] > maxCNT) maxCNT = CountL [i]; // Update the max value for the left side
        if (CountR [i] > maxCNT) maxCNT = CountR [i]; // Update the max value for the right side

        if (CountL [i] < minCNT) minCNT = CountL [i]; // Update the min value for the left side
        if (CountR [i] < minCNT) minCNT = CountR [i]; // Update the minimum value for the right side
    }

    // Variables for drawing graphs
    int   x      = 0.0; // X coordinate
    int   y      = 0.0; // Y coordinate
    color clrF;         // Color
    int   centre = 0;   // Canvas center
    int   stepL  = 0;   // Left side step
    int   stH_L  = 0;   // Left side height
    int   stepR  = 0;   // Right side step
    int   stH_R  = 0;   // Right side height

    // Determine the center of the canvas
    centre = (int) U.Scale(Inp_P, Min_P, Max_P, O, W - O - 1, false);

    // Calculate steps and heights for the left side
    stepL = (centre - O) / Size_P;
    stH_L = stepL / 2;
    if (stH_L == 0) stH_L = 1; // Make sure the height is not 0

    // Calculate steps and heights for the right side
    stepR = (W - O - centre) / Size_P;
    stH_R = stepR / 2;
    if (stH_R == 0) stH_R = 1; // Make sure the height is not 0

    // Draw graphs for left and right parts
    for (int i = 0; i < Size_P; i++)
    {
        // Draw for the left side 
        x = (int) U.Scale (i, 0, Size_P - 1, O, centre - stH_L, true); // Calculate the X coordinate
        y = (int) U.Scale (CountL [i], 0, maxCNT, O, H - O - 1, true); // Calculate the Y coordinate

        clrF = DoubleToColor(CountL [i], minCNT, maxCNT, 0, 255); // Define color by value

        // Draw dots for the left side
        Canvas.Circle (x, y, 2, COLOR2RGB (clrF)); // Draw a small circle
        Canvas.Circle (x, y, 3, COLOR2RGB (clrF)); // Draw a larger circle

        // Draw for the right side
        x = (int) U.Scale (i, 0, Size_P - 1, centre + stH_R, W - O - 1, false); // Calculate the X coordinate
        y = (int) U.Scale (CountR[i], 0, maxCNT, O, H - O - 1, true);           // Calculate the Y coordinate

        clrF = DoubleToColor (CountR [i], minCNT, maxCNT, 0, 255); // Define color by value

        // Draw dots for the right side
        Canvas.Circle (x, y, 2, COLOR2RGB (clrF)); // Draw a small circle
        Canvas.Circle (x, y, 3, COLOR2RGB (clrF)); // Draw a larger circle
    }

    Canvas.Update (); // Update the canvas to reflect the changes}

Führen wir das Skript aus und erhalten wir ein Bild auf dem Chart wie in Abbildung 2.

LogNormDistr

Abbildung 2. Visualisierung einer asymmetrischen Log-Normal-Verteilung mit der Standardbibliothek Canvas

Nachdem wir die Theorie aller Stufen des Algorithmus eingehend untersucht haben, wollen wir uns nun direkt der Code-Implementierung zuwenden. Während der AOS-Algorithmus eine Minimierungsmethode für das Problem ist, werden wir die Logik so anpassen, dass sie für die Maximierung funktioniert. Implementieren wir die Struktur S_Layer, die die atomare Schicht simuliert und Informationen über die Anzahl der in dieser Schicht befindlichen Teilchen enthält. Sie enthält sowohl die numerischen Merkmale als auch die Methode zur Initialisierung. Die Felder der Struktur:

  • pc - Zähler der Teilchen, die sich in einer bestimmten Schicht eines Atoms befinden, mit dem man verfolgen kann, wie viele Teilchen (Elektronen) sich in einer bestimmten Schicht befinden. 
  • BSk - Zustand der Verbindung in der Schicht, spiegelt den Grad der Interaktion zwischen den Teilchen in der Schicht wider. 
  • BEk - Bindungsenergie in der Schicht, zeigt an, wie stark die Teilchen in der Schicht aneinander gebunden sind.
  • LEk - Mindestenergie in einer Schicht zur Bestimmung des niedrigsten Energieniveaus, das von Teilchen in einer bestimmten Schicht erreicht werden kann. 

Die Methode Init dient dazu, die Strukturfelder mit Standardwerten zu initialisieren und ermöglicht es uns, den Zustand der Schicht bei Bedarf mehrfach zurückzusetzen.

//——————————————————————————————————————————————————————————————————————————————
struct S_Layer
{
    int    pc;  // particle counter
    double BSk; // connection state
    double BEk; // binding energy
    double LEk; // minimum energy

    void Init ()
    {
      pc  = 0;
      BSk = 0.0;
      BEk = 0.0;
      LEk = 0.0;
    }
};
//——————————————————————————————————————————————————————————————————————————————

Als Nächstes wollen wir uns die Struktur S_Atom und ihre Methode Init ansehen. S_Atom ist eine Struktur, die ein aus mehreren Schichten bestehendes Atom darstellt. Jede Schicht wird mit dem Array layers[] der zuvor beschriebenen S_Layer-Struktur simuliert. Die Felder der Struktur:

  • Init - Methode zur Initialisierung eines Arrays von atomaren Schichten sowie zur Initialisierung jeder Schicht in diesem Array.
  • layersNumb - ganzzahliger Parameter, der die Anzahl der Schichten angibt, die für ein bestimmtes Atom erstellt werden.

//——————————————————————————————————————————————————————————————————————————————
struct S_Atom
{
    S_Layer layers [];  // array of atom layers

    void Init (int layersNumb)
    {
      ArrayResize (layers, layersNumb);
      for (int i = 0; i < layersNumb; i++) layers [i].Init ();
    }
};
//——————————————————————————————————————————————————————————————————————————————

Die nächste Struktur S_Electron und ihre Methode Init. Die Struktur ist ein Elektron, ein Mitglied der Lösungspopulation, das Informationen über seine Position in der entsprechenden Schicht des Atoms enthält. Die Felder von layerID[] stellen ein Array aus Ganzzahlen dar, das die IDs der Schichten speichert, zu denen das Elektron gehört. Jede ID entspricht einer bestimmten Schicht im Atom, sodass wir verfolgen können, auf welcher Schicht sich das Elektron befindet.

//——————————————————————————————————————————————————————————————————————————————
struct S_Electron
{
    int layerID [];  // array of layer IDs for the electron

    void Init (int coords)
    {
      ArrayResize (layerID, coords);
    }
};
//——————————————————————————————————————————————————————————————————————————————

Der Algorithmus der Klasse C_AO_AOS AOS erbt von der Basisklasse C_AO und impliziert das Vorhandensein einer gemeinsamen Funktionalität im Zusammenhang mit Atomumlaufbahnen.

Parameter der Klasse:

  • popSize - Größe der Population im Algorithmus.
  • maxLayers - maximale Anzahl von Schichten, die in einem atomaren Modell verwendet werden können.
  • photonEmissions - Anzahl der Photonenemissionen, die für den Optimierungsprozess verwendet werden.
  • PR - Photonenübergangskoeffizient, bestimmt die Wahrscheinlichkeit des Übergangs zwischen Zuständen.
  • peakPosition - Spitzenposition in der Log-Normal-Verteilung.

Methoden der Klasse:

1. SetParams() - setzt die Algorithmusparameter durch Lesen von Werten aus dem Array params.
2. Init() - initialisiert den Algorithmus mit den angegebenen Suchparametern: minimaler und maximaler Bereich, Suchschritt und Anzahl der Epochen.
3. Moving() - Methode zum Verschieben von Partikeln im Suchraum.
4. Überarbeitung() - die Methode ist für die Überarbeitung der besten Lösungen zuständig, die während der Optimierung gefunden wurden.

Private Felder der Klasse:

  • atomStage - aktueller Stand des Atomprozesses.
  • currentLayers[] - aktuelle Anzahl der Schichten für jedes Atom (zu jeder Epoche ist die Anzahl der Schichten in jedem Atom eine Zufallszahl im Bereich [1; maxLayers]).
  • S_Atom atoms[] - Array von Atomen, deren Größe der Anzahl der im Algorithmus verwendeten Koordinaten entspricht.
  • S_Electron electrons[] - Array von Elektronen, die der Populationsgröße entsprechen.
  • BS[] - Zustände von Bindungen zwischen Elektronen in der gesamten Population.

Private Methoden der Klasse:

1. GetOrbitBandID() - ermittelt die Orbitalband-ID für die angegebenen Parameter wie Anzahl der Schichten und Bereiche.
2. DistributeParticles() - Methode zum Verteilen von Partikeln im Suchraum.
3. LayersGenerationInAtoms() - erzeugt die Anzahl der Schichten in Atomen.
4. UpdateElectronsIDs() - Aktualisierung der Schicht-IDs für Elektronen.
5. CalcLayerParams() - berechnet die Parameter von Schichten und umfasst die Bestimmung von Energieniveaus und Bindungen.
6. UpdateElectrons() - aktualisiert die Position der Elektronen.

//——————————————————————————————————————————————————————————————————————————————
// Class implementing the atomic optimization algorithm (Atomic Orbital Search)
class C_AO_AOS : public C_AO
{
  public: //--------------------------------------------------------------------
  ~C_AO_AOS () { }
  C_AO_AOS ()
  {
    ao_name = "AOS";
    ao_desc = "Atomic Orbital Search";
    ao_link = "https://www.mql5.com/en/articles/16276";

    popSize         = 50;      // population size

    maxLayers       = 5;       // maximum number of layers
    photonEmissions = 1;       // number of photon emissions
    PR              = 0.1;     // photon transition coefficient
    peakPosition    = 0.05;    // peak position in the log-normal distribution

    ArrayResize (params, 5);

    params [0].name = "popSize";         params [0].val = popSize;
    params [1].name = "maxLayers";       params [1].val = maxLayers;
    params [2].name = "photonEmissions"; params [2].val = photonEmissions;
    params [3].name = "photonRate";      params [3].val = PR;
    params [4].name = "peakPsition";     params [4].val = peakPosition;
  }

  // Setting algorithm parameters
  void SetParams ()
  {
    popSize         = (int)params [0].val;
    maxLayers       = (int)params [1].val;
    photonEmissions = (int)params [2].val;
    PR              = params      [3].val;
    peakPosition    = params      [4].val;
  }

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

  void Moving   (); // Method of moving particles
  void Revision (); // Method of revising the best solutions

  //----------------------------------------------------------------------------
  int    maxLayers;       // maximum number of layers
  int    photonEmissions; // number of photon emissions
  double PR;              // photon transition coefficient
  double peakPosition;    // peak position in the log-normal distribution

  private: //-------------------------------------------------------------------
  int        atomStage;        // current stage of the atom
  int        currentLayers []; // current number of layers for the corresponding atom (coordinates)
  S_Atom     atoms         []; // atoms with their size corresponding to the number of coordinates
  S_Electron electrons     []; // electrons corresponding to the population size
  double     BS            []; // connection states

  // Get orbital band for given parameters
  int  GetOrbitBandID          (int layersNumb, double min, double max, double center, double p);

  // Distribution of particles in the search space
  void DistributeParticles     ();

  // Generate layers in atoms
  void LayersGenerationInAtoms ();

  // Update electron IDs
  void UpdateElectronsIDs      ();

  // Calculate layer parameters 
  void CalcLayerParams         ();

  // Update electron positions
  void UpdateElectrons         ();
};
//——————————————————————————————————————————————————————————————————————————————

Schauen wir uns an, was in der Methode Init der AOS-Algorithmusklasse passiert.

1. Standard-Initialisierung: Die Methode beginnt mit dem Aufruf von StandardInit und führt allgemeine Initialisierungsschritte durch, wie z. B. das Festlegen von Bereichen für Koordinaten. 

2. Initialisierung von Variablen:

  • atomStage - auf 0 gesetzt, was bedeutet, dass der Algorithmus mit der Anfangsphase beginnt.
  • ArrayResize(currentLayers, coords) ändert die Größe des Arrays currentLayers entsprechend der Anzahl der Koordinatenanzahl coords.
  • ArrayResize(atoms, coords) ändert die Größe des Arrays atoms und erstellt für jedes Atom (Koordinate) ein eigenes Objekt. Für jedes Atom wird die Methode Init(maxLayers) aufgerufen, die es mit der maximalen Anzahl von Schichten initialisiert.
  • ArrayResize(electrons, popSize) ändert die Größe des Elektronen-Arrays entsprechend der Populationsgröße popSize. Das Array layerID wird für jedes Elektron erstellt. Das Feld entspricht der Anzahl der Koordinaten.
  • ArrayResize(BS, coords) ändert die Größe des BS-Arrays, in dem Zustände für jede Koordinate gespeichert werden.

4. Wenn alle Initialisierungsvorgänge erfolgreich sind, gibt die Methode true zurück.

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

  //----------------------------------------------------------------------------
  atomStage = 0;

  ArrayResize (currentLayers, coords);

  ArrayResize (atoms, coords);
  for (int i = 0; i < coords; i++) atoms [i].Init (maxLayers);

  ArrayResize (electrons,   popSize);
  for (int i = 0; i < popSize; i++) ArrayResize (electrons [i].layerID, coords);

  ArrayResize (BS, coords);

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

Methode der Partikelverschiebung Beschreiben wir die Methode Moving:

1. Erste zufällige Positionierung:

  • Ist die Revisionsvariable gleich false, bedeutet dies, dass der Algorithmus noch nicht mit seiner Arbeit begonnen hat. In diesem Fall kommt es zu einer zufälligen Positionierung der Partikel.
  •  Als Nächstes durchläuft die verschachtelte for-Schleife alle Elektronen (Populationsgröße) und erzeugt mit der Methode u.RNDfromCI für jede Koordinate einen Zufallswert. Die Methode nimmt ihren Wert aus dem durch rangeMin und rangeMax angegebenen Bereich. Dieser Wert wird dann mit Hilfe der u.SeInDiSp angepasst, die den Wert entsprechend dem angegebenen „Schritt“ einstellt.

2. Ausführung der entsprechenden Evolutionsstufe der Atome:

  • Wenn Revision wahr ist, bedeutet dies, dass der Algorithmus bereits initialisiert wurde und seine Hauptphasen ausgeführt werden können. Je nachdem, in welchem Stadium sich atomStage befindet, werden unterschiedliche Methoden aufgerufen:
  • Wenn atomStage 0 ist, wird DistributeParticles() aufgerufen. Sie ist für die Verteilung der Teilchen im Raum gemäß der asymmetrischen Log-Normal-Verteilung verantwortlich.
  • Ansonsten werden Methoden aufgerufen, die Schichten in Atomen erzeugen, Elektronen-IDs aktualisieren, Schichtparameter berechnen und Elektronenpositionen aktualisieren.

3. Nach Abschluss aller notwendigen Operationen wird atomStage um 1 erhöht. Wenn atomStage den Wert von photonEmissions überschreitet, wird es auf 0 zurückgesetzt, sodass die Algorithmusphasen zyklisch wiederholt werden können.

//——————————————————————————————————————————————————————————————————————————————
// Particle displacement method
void C_AO_AOS::Moving ()
{
  // Initial random positioning
  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;
  }

  //----------------------------------------------------------------------------
  // Execute the corresponding stage of the algorithm
  if (atomStage == 0)
  {
    DistributeParticles ();
  }
  else
  {
    LayersGenerationInAtoms ();
    UpdateElectronsIDs      ();
    CalcLayerParams         ();
    UpdateElectrons         ();
  }

  // Proceed to the next stage
  atomStage++;
  if (atomStage > photonEmissions) atomStage = 0;
}
//——————————————————————————————————————————————————————————————————————————————

Kommen wir nun zur Analyse der einzelnen Methoden. Die Methode GetOrbitBandID der Klasse C_AO_AOS dient der Bestimmung des Orbitalbandes für ein Teilchen auf der Grundlage seiner Position relativ zu einem bestimmten Zentrum. Es nimmt die Anzahl der Schichten, die Minimal- und Maximalwerte, den Mittelpunkt und die Position des p-Partikel.

1. Berechnet die Breite der Bänder links und rechts der Mitte.
2. Wenn die Position des Teilchens p kleiner als die Mitte ist, dann wird gesucht, in welchem der linken Bänder es sich befindet.
3. Wenn es mehr sind, wird es es in den richtigen Bändern gesucht.
4. Wenn sie gleich dem Mittelpunkt ist, wird die Zahl 0 (der Mittelpunkt) zurückgegeben.

Die Funktion gibt also den Index des entsprechenden Orbitalbandes für die angegebene Position zurück.

//——————————————————————————————————————————————————————————————————————————————
// Determining the orbital band for a particle
int C_AO_AOS::GetOrbitBandID (int layersNumb, double min, double max, double center, double p)
{
  // Calculate the width of the bands to the left and right of the center
  double leftWidth  = (center - min) / layersNumb;
  double rightWidth = (max - center) / layersNumb;

  // Define the band index
  if (p < center)
  {
    // The object is located to the left of the center
    for (int i = 1; i <= layersNumb; i++)
    {
      if (p >= center - i * leftWidth) return i - 1;
    }
    return layersNumb - 1; // If the object is in the leftmost band
  }
  else
    if (p > center)
    {
      // The object is located to the right of the center
      for (int i = 1; i <= layersNumb; i++)
      {
        if (p <= center + i * rightWidth) return i - 1;
      }
      return layersNumb - 1; // If the object is in the far right band
    }
    else
    {
      // The object is in the center
      return 0;
    }
}
//——————————————————————————————————————————————————————————————————————————————

Die Methode DistributeParticles der Klasse C_AO_AOS ist für die Verteilung der Partikel im Suchraum zuständig. Die Methode verteilt die Partikel im Suchraum anhand einer Log-Normal-Verteilung.

Für jedes Partikel (in einer Schleife durch popSize) und für jede Koordinate (in einer Schleife durch „coords“):

  • Erzeugt eine Partikelposition unter Verwendung einer Log-Normal-Verteilung unter Angabe der Parameter (cB, rangeMin, rangeMax, peakPosition).
  • Wendet die Funktion SeInDiSp an, um den Partikelpositionswert innerhalb eines bestimmten Bereichs unter Berücksichtigung der Stufe anzupassen.
//——————————————————————————————————————————————————————————————————————————————
// Distribution of particles in the search space
void C_AO_AOS::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Use log-normal distribution to position particles
      a [i].c [c] = u.LognormalDistribution (cB [c], rangeMin [c], rangeMax [c], peakPosition);
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Die Methode UpdateElectronsIDs der Klasse C_AO_AOS aktualisiert die Schicht-IDs für Elektronen in Abhängigkeit von ihren Koordinaten und den angegebenen Parametern.

//——————————————————————————————————————————————————————————————————————————————
//  Update layer IDs for each electron
void C_AO_AOS::UpdateElectronsIDs ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      electrons [i].layerID [c] = GetOrbitBandID (currentLayers [c], rangeMin [c], rangeMax [c], cB [c], a [i].c [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Die Methode CalcLayerParams der Klasse C_AO_AOS dient der Berechnung von Parametern für jede Schicht von Atomen im System. Die wichtigsten Bestandteile der Methode:

1. Variableninitialisierung: energy ist eine Variable zur Speicherung der maximalen Energie, die beim Umgang mit dem Elektron aktualisiert wird.

2. Die Schleife durchläuft alle Atome (Koordinaten) des Systems. Der Index c zeigt auf das aktuelle Atom.

3. Für jedes Atom wird die Methode Init aufgerufen, die die Parameter für die durch die Variable maxLayers festgelegte maximale Anzahl von Schichten initialisiert.

4. Schichtenschleife: die innere Schleife, die alle mit dem aktuellen Atom verbundenen Schichten durchläuft; currentLayers[c] gibt die Anzahl der Schichten für das Atom c an.

5. Handhabung von Elektronen: Eine weitere interne Schleife durchläuft alle e-Elektronen in der Population, wobei geprüft wird, ob das aktuelle Elektron zur Schicht L für das Atom c gehört.

6. Aktualisierung der Schicht-Parameter:

  • Wenn das Elektron zu einer Schicht gehört, wird der Partikelzähler in der Schicht erhöht.
  • Die Energiewerte BEk und die Zustände BSk werden für die Schicht in Abhängigkeit von den Elektroneneigenschaften aktualisiert.
  • Wenn die Elektronenenergie a[e].f das aktuelle maximale Energieniveau überschreitet, werden die maximalen Energiewerte und die Zustände LEk aktualisiert.

7. Berechnung von Durchschnittswerten für eine Schicht: Wenn der Partikelzähler pc ungleich Null ist, werden Durchschnittswerte für Energie und Zustand berechnet.

8. Berechnung des allgemeinen Zustands der Bindungen: Der Bindungszustand jedes Atoms wird in ähnlicher Weise für jedes Atom BS, aber für die Gesamtheit der Elektronen berechnet.

//——————————————————————————————————————————————————————————————————————————————
// Calculate parameters for each layer
void C_AO_AOS::CalcLayerParams ()
{
  double energy;

  // Handle each coordinate (atom)
  for (int c = 0; c < coords; c++)
  {
    atoms [c].Init (maxLayers);

    // Handle each layer
    for (int L = 0; L < currentLayers [c]; L++)
    {
      energy = -DBL_MAX;

      // Handle each electron
      for (int e = 0; e < popSize; e++)
      {
        if (electrons [e].layerID [c] == L)
        {
          atoms [c].layers [L].pc++;
          atoms [c].layers [L].BEk = a [e].f;
          atoms [c].layers [L].BSk = a [e].c [c];

          if (a [e].f > energy)
          {
            energy = a [e].f;
            atoms [c].layers [L].LEk = a [e].c [c];
          }
        }
      }

      // Calculate average values for the layer
      if (atoms [c].layers [L].pc != 0)
      {
        atoms [c].layers [L].BEk /= atoms [c].layers [L].pc;
        atoms [c].layers [L].BSk /= atoms [c].layers [L].pc;
      }
    }
  }

  // Calculate the general state of connections
  ArrayInitialize (BS, 0);

  for (int c = 0; c < coords; c++)
  {
    for (int e = 0; e < popSize; e++)
    {
      BS [c] += a [e].c [c];
    }

    BS [c] /= popSize;
  }
}
//——————————————————————————————————————————————————————————————————————————————

Die Methode UpdateElectrons der Klasse C_AO_AOS ist für die Aktualisierung der Position der Elektronen im System zuständig.

1. Initialisierung der Parameter: Die Geschwindigkeitskoeffizienten, die Gewichte der besten Lösung, die Gewichte des Durchschnittszustands und die Übergangswahrscheinlichkeit werden bestimmt.

2. Für jedes Teilchen und jede Koordinate:

  • Es wird eine Zufallswahrscheinlichkeit φ erzeugt.
  • Ist φ kleiner als der Schwellenwert PR, wird eine zufällige Streuung vorgenommen und eine neue Position innerhalb eines bestimmten Bereichs zufällig gewählt.
  • Andernfalls:
  • Die Schicht-ID lID wird für das aktuelle Partikel ermittelt.
  • Es werden zufällige Werte für die Verhältnisse erzeugt.
    • Wenn die aktuelle Energie eines Teilchens geringer ist als die durchschnittliche Energie der Schicht, kommt es zu einer Bewegung in Richtung des globalen Optimums.
    • Ist dies nicht der Fall, kommt es zu einer Bewegung in Richtung des lokalen Optimums der Schicht.
  • Am Ende wird die neue Position innerhalb des angegebenen Bereichs unter Berücksichtigung des Schritts begrenzt.

//——————————————————————————————————————————————————————————————————————————————
// Update electron positions
void C_AO_AOS::UpdateElectrons ()
{
  double α;      // speed coefficient
  double β;      // best solution weight coefficient
  double γ;      // average state weight coefficient
  double φ;      // transition probability
  double newPos; // new position
  double LE;     // best energy
  double BSk;    // connection state
  int    lID;    // layer ID

  // Handle each particle
  for (int p = 0; p < popSize; p++)
  {
    for (int c = 0; c < coords; c++)
    {
      φ = u.RNDprobab ();

      if (φ < PR)
      {
        // Random scatter
        newPos = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      }
      else
      {
        lID = electrons [p].layerID [c];

        α = u.RNDfromCI (-1.0, 1.0);
        β = u.RNDprobab ();
        γ = u.RNDprobab ();

        // If the current particle energy is less than the average layer energy
        if (a [p].f < atoms [c].layers [lID].BEk)
        {
          // Moving towards the global optimum----------------------------
          LE = cB [c];

          newPos = a [p].c [c]+ α * (β * LE - γ * BS [c]) / currentLayers [c];
        }
        else
        {
          // Movement towards the local optimum of the layer
          LE  = atoms [c].layers [lID].LEk;
          BSk = atoms [c].layers [lID].BSk;

          newPos = a [p].c [c] + α * (β * LE - γ * BSk);
        }
      }

      // Limiting the new position within the search range taking into account the step
      a [p].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Die Methode Revision der Klasse C_AO_AOS dient der Überprüfung und Aktualisierung der besten Lösungen (oder optimalen Zustände) während der Iteration. Schritte der Methode:

1. Initialisierung der Variablen bestIndex, die zum Speichern des Index der besten Lösung verwendet wird.

2. Die Suche nach der besten Lösung. Bedingung für die Prüfung, ob der Funktionswert (oder die Schätzung) der aktuellen Lösung a[i].f den aktuellen Wert der global besten Lösung fB übersteigt. Wenn diese Bedingung erfüllt ist, wird der Wert der global besten Lösung auf den aktuellen Wert aktualisiert und der Index der aktuellen Lösung wird als beste Lösung gespeichert.

3. Wird die beste Lösung gefunden, so werden die Koordinaten der besten Lösung a[bestIndex].c in das Array cB kopiert.

//——————————————————————————————————————————————————————————————————————————————
// Method of revising the best solutions
void C_AO_AOS::Revision ()
{
  int bestIndex = -1;

  // Find the best solution in the current iteration
  for (int i = 0; i < popSize; i++)
  {
    // Update the global best solution
    if (a [i].f > fB)
    {
      fB = a [i].f;
      bestIndex = i;
    }
  }

  // Update the best coordinates if a better solution is found 
  if (bestIndex != -1) ArrayCopy (cB, a [bestIndex].c, 0, 0, WHOLE_ARRAY);
}
//——————————————————————————————————————————————————————————————————————————————


Testergebnisse

Führen wir den Test aus und erhalten die folgenden Ergebnisse des AOS-Betriebs:

AOS|Atomic Orbital Search|50.0|5.0|1.0|0.1|0.05|
=============================
5 Hilly's; Func runs: 10000; result: 0.6521321213930082
25 Hilly's; Func runs: 10000; result: 0.39883708808831186
500 Hilly's; Func runs: 10000; result: 0.2602779698842558
=============================
5 Forest's; Func runs: 10000; result: 0.5165008091396371
25 Forest's; Func runs: 10000; result: 0.30233740723010416
500 Forest's; Func runs: 10000; result: 0.1926906342754638
=============================
5 Megacity's; Func runs: 10000; result: 0.39384615384615385
25 Megacity's; Func runs: 10000; result: 0.1892307692307692
500 Megacity's; Func runs: 10000; result: 0.09903076923077013
=============================
All score: 3.00488 (33.39%)

Bei der Visualisierung des AOS-Algorithmus kann man ein interessantes Verhalten feststellen, charakteristische Bereiche der „Verklumpung“ in den Orbitalen der Atome, aber die Genauigkeit der Konvergenz ist nicht sehr hoch.

Hilly

AOS mit der Testfunktion Hilly

Forest

AOS mit der Testfunktion Forest

Megacity

AOS mit der Testfunktion Megacity

Auf der Grundlage der Testergebnisse wurde der AOS-Algorithmus in der Bewertungstabelle auf Platz 39 eingestuft.

# 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 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
7 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
8 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
9 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
10 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
11 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
12 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
13 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
14 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
15 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
16 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
17 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
18 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
19 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
20 (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
21 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
22 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
23 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
24 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
25 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
26 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
27 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
28 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
29 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
30 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
31 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
32 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
33 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
34 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
35 COAm Kuckuck-Optimierungsalgorithmus M 0.75820 0.48652 0.31369 1.55841 0.74054 0.28051 0.05599 1.07704 0.50500 0.17467 0.03380 0.71347 3.349 37.21
36 SDOm Optimierung der Spiraldynamik M 0.74601 0.44623 0.29687 1.48912 0.70204 0.34678 0.10944 1.15826 0.42833 0.16767 0.03663 0.63263 3.280 36.44
37 NMm Nelder-Mead-Verfahren M 0.73807 0.50598 0.31342 1.55747 0.63674 0.28302 0.08221 1.00197 0.44667 0.18667 0.04028 0.67362 3.233 35.92
38 FAm Firefly-Algorithmus M 0.58634 0.47228 0.32276 1.38138 0.68467 0.37439 0.10908 1.16814 0.28667 0.16467 0.04722 0.49855 3.048 33.87
39 AOS Suche nach atomaren Orbitalen 0.65213 0.39884 0.26028 1.31125 0.51650 0.30234 0.19269 1.01153 0.39385 0.18923 0.09903 0.68211 3.005 33.39
40 GSA Algorithmus für die Schwerkraftsuche 0.64757 0.49197 0.30062 1.44016 0.53962 0.36353 0.09945 1.00260 0.32667 0.12200 0.01917 0.46783 2.911 32.34
41 BFO Optimierung der bakteriellen Futtersuche 0.61171 0.43270 0.31318 1.35759 0.54410 0.21511 0.05676 0.81597 0.42167 0.13800 0.03195 0.59162 2.765 30.72
42 ABC Künstliches Bienenvolk (Artificial Bee Colony, ABC) 0.63377 0.42402 0.30892 1.36671 0.55103 0.21874 0.05623 0.82600 0.34000 0.14200 0.03102 0.51302 2.706 30.06
43 BA Fledermaus-Algorithmus 0.59761 0.45911 0.35242 1.40915 0.40321 0.19313 0.07175 0.66810 0.21000 0.10100 0.03517 0.34617 2.423 26.93
44 AAA Künstlicher Algenalgorithmus (AAA) 0.50007 0.32040 0.25525 1.07572 0.37021 0.22284 0.16785 0.76089 0.27846 0.14800 0.09755 0.52402 2.361 26.23
45 SA Simuliertes Abkühlen 0.55787 0.42177 0.31549 1.29513 0.34998 0.15259 0.05023 0.55280 0.31167 0.10033 0.02883 0.44083 2.289 25.43


Zusammenfassung

Wir haben einen interessanten Algorithmus für die Suche nach Atomorbitalen untersucht, der innovative Ansätze für die globale Suche und die lokale Verfeinerung der Ergebnisse verwendet. Dank der dynamischen Orbitalschichten der Atome bewegen sich die Elektronen auf der Suche nach einem stabilen Atomzustand im Gleichgewicht. Der Algorithmus zeigt begrenzte Fähigkeiten bei glatten Funktionen, zeigt aber gute Ergebnisse, wenn die Problemdimension zunimmt, sogar bei der diskreten Megacity-Funktion.

Dieser Algorithmus ist ein Beispiel für eine vielversprechende Idee, aber seine Effizienz leidet unter einigen kleinen, aber wichtigen Nuancen. Im nächsten Artikel werden wir uns meine Modifikation von AOS ansehen und analysieren, wozu dieses wunderbare Konzept der orbitalen Suche tatsächlich in der Lage ist.

Tabelle

Abbildung 3. Farbliche Abstufung der Algorithmen entsprechend den relevanten Tests Ergebnisse, die größer oder gleich 0,99 sind, werden weiß hervorgehoben

Histogramm

Abbildung 4. Das Histogramm der Algorithmus-Testergebnisse (auf einer Skala von 0 bis 100, je mehr, desto besser,

wobei 100 das maximal mögliche theoretische Ergebnis ist; im Archiv befindet sich ein Skript zur Berechnung der Wertungstabelle)


Vor- und Nachteile von AOS:

Vorteile:

  1. Eine vielversprechende Grundlage für die Verbesserung von Algorithmen.
  2. Eine kleine Anzahl externer Parameter.

Nachteile

  1. Langsam aufgrund der häufigen Erzeugung von Zufallszahlen.
  2. Eine recht komplexe Umsetzung.
  3. Geringe Konvergenzgenauigkeit.

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
Übergeordnete Klasse von Populationsoptimierungsalgorithmen
2 #C_AO_enum.mqh
Include
Enumeration von Algorithmen zur Bevölkerungsoptimierung
3 TestFunctions.mqh
Include
Bibliothek mit Testfunktionen
4
TestStandFunctions.mqh
Include
Bibliothek der Testfunktionen
5
Utilities.mqh
Include
Bibliothek der Hilfsfunktionen
6
CalculationTestResults.mqh
Include
Skript zur Berechnung der Ergebnisse in der Vergleichstabelle
7
Testing AOs.mq5
Skript Die einheitlichen Tests für alle Algorithmen zur Bevölkerungsoptimierung
8
AO_AOS_AtomicOrbitalSearch.mqh
Include AOS-Algorithmus-Klasse
9
Test_AO_AOS.mq5
Skript
AOS-Test

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

Beigefügte Dateien |
AOS.zip (131.48 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (1)
Pavel Ustinov
Pavel Ustinov | 24 Juni 2025 in 18:42
MetaQuotes:

Atomic Orbital Search Algorithm - Atomic Orbital Search (AOS) ist veröffentlicht worden:

Autor: Andrey Dik

Dies ist das gesamte System, das Physik, Mathematik, Schach, etc. umfasst.

Entwicklung eines Replay-Systems (Teil 75): Neuer Chart-Handel (II) Entwicklung eines Replay-Systems (Teil 75): Neuer Chart-Handel (II)
In diesem Artikel geht es um die Klasse C_ChartFloatingRAD. Das ist es, was Chart Trade ausmacht. Doch damit ist die Erklärung noch nicht zu Ende. Wir werden sie im nächsten Artikel vervollständigen, da der Inhalt dieses Artikels recht umfangreich ist und ein tiefes Verständnis erfordert. Der hier dargestellte Inhalt ist ausschließlich für Bildungszwecke bestimmt. Die Anwendung sollte unter keinen Umständen zu einem anderen Zweck als zum Erlernen und Beherrschen der vorgestellten Konzepte verwendet werden.
Entwicklung eines Replay-Systems (Teil 74): Neuer Chart-Handel (I) Entwicklung eines Replay-Systems (Teil 74): Neuer Chart-Handel (I)
In diesem Artikel werden wir den letzten Code, der in dieser Serie über Chart Trade gezeigt wurde, ändern. Diese Änderungen sind notwendig, um den Code an das aktuelle Wiedergabe-/Simulationssystemmodell anzupassen. Der hier dargestellte Inhalt ist ausschließlich für Bildungszwecke bestimmt. Die Anwendung sollte unter keinen Umständen zu einem anderen Zweck als zum Erlernen und Beherrschen der vorgestellten Konzepte verwendet werden.
Die Verwendung von Assoziationsregeln in der Forex-Datenanalyse Die Verwendung von Assoziationsregeln in der Forex-Datenanalyse
Wie lassen sich die Vorhersageregeln der Supermarkt-Einzelhandelsanalyse auf den realen Devisenmarkt anwenden? Wie hängt der Kauf von Keksen, Milch und Brot mit Börsentransaktionen zusammen? Der Artikel behandelt einen innovativen Ansatz für den algorithmischen Handel, der auf der Verwendung von Assoziationsregeln beruht.
Analyse der Auswirkungen des Wetters auf die Währungen der Agrarländer mit Python Analyse der Auswirkungen des Wetters auf die Währungen der Agrarländer mit Python
Welcher Zusammenhang besteht zwischen Wetter und Devisen? In der klassischen Wirtschaftstheorie wurde der Einfluss von Faktoren wie dem Wetter auf das Marktverhalten lange Zeit ignoriert. Aber alles hat sich geändert. Versuchen wir, Zusammenhänge zwischen den Witterungsbedingungen und der Stellung der Agrarwährungen auf dem Markt zu finden.