English Русский 中文 Español 日本語 Português
preview
Blood inheritance optimization (BIO)

Blood inheritance optimization (BIO)

MetaTrader 5Tester |
85 0
Andrey Dik
Andrey Dik

Inhalt

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


Einführung

Eines Tages, als ich einer Krankenschwester bei der Entnahme von Blutproben von Patienten im Labor zusah, kam mir plötzlich ein Gedanke. Blutgruppen, dieses uralte System der Vererbung, das von Generation zu Generation nach strengen genetischen Gesetzen weitergegeben wird, erschien mir plötzlich in einem völlig neuen Licht. Was wäre, wenn diese natürlichen Eigenschaften der Vererbung im Bereich der Optimierungsalgorithmen ausgenutzt werden könnten?

Jeder von uns trägt eine einzigartige Kombination in seinen Adern, die er von seinen Eltern geerbt hat. So wie die Blutgruppen die Kompatibilität bei Transfusionen bestimmen, könnten sie bestimmen, wie die Parameter bei der Optimierung übertragen und mutiert werden. Diese Idee gefiel mir und ich beschloss, darauf zurückzukommen, wenn ich Zeit für Recherchen habe. Nach der Durchführung von Experimenten wurde der Algorithmus „Blood Inheritance Optimization“ (BIO) geboren – eine Methode, die die natürlichen Gesetze der Blutgruppenvererbung als Metapher für die Verwaltung der Evolution von Entscheidungen nutzt. In dem Algorithmus entwickelten sich die vier Blutgruppen zu vier verschiedenen Strategien für die Mutation von Parametern, und die Gesetze der Vererbung bestimmten, wie die Nachkommen die Merkmale ihrer Eltern erwerben und verändern.

Wie in der Natur ist die Blutgruppe eines Kindes nicht einfach ein Durchschnitt der Blutgruppen der Eltern, sondern unterliegt genetischen Gesetzen. In BIO werden die Parameter neuer Lösungen durch ein System von Vererbung und Mutationen gebildet. Jede Blutgruppe bringt ihre eigene Herangehensweise an die Erforschung des Lösungsraums mit sich: von der konservativen Beibehaltung der besten gefundenen Werte bis hin zu radikalen Mutationen, die neue vielversprechende Bereiche und Richtungen für die weitere Erforschung des Lösungsraums eröffnen.

In diesem Artikel möchte ich die Grundsätze des BIO-Algorithmus erläutern, der biologische Inspiration mit algorithmischer Strenge verbindet, und Testergebnisse zu Funktionen liefern, die wir bereits kennen. Lassen Sie uns das also tun.


Implementierung des Algorithmus

Machen wir uns zunächst mit der Tabelle der Vererbung der Blutgruppe der Nachkommen von den Eltern vertraut. Wie Sie sehen können, ist die Vererbung der Blutgruppe nicht einheitlich. Es gibt interessante Statistiken über die Verteilung der Blutgruppen in der WeltPopulation. Am weitesten verbreitet ist die erste Gruppe (O)etwa 40 % der WeltPopulation sind Träger dieser Krankheit. Es folgt die zweite Gruppe (A), die von etwa 30 % der Menschen besessen wird. Die dritte Gruppe (B) kommt bei 20 % der Population vor, und die vierte Gruppe (AB) ist die seltenste – nur etwa 10 % der Menschen tragen sie in sich.

Beim Studium der Vererbungsmechanismen habe ich gelernt, dass die erste Blutgruppe im Verhältnis zu allen anderen rezessiv ist. Das bedeutet, dass Menschen mit Blutgruppe 1 nur die Blutgruppe 1 an ihre Kinder weitergeben können. Gleichzeitig weisen die zweite und dritte Gruppe eine Ko-Dominanz zueinander auf, die in ihrer Kombination zur Entstehung der vierten Gruppe führt. Aus evolutionärer Sicht ist die vierte Blutgruppe die jüngste.

Ich interessierte mich besonders für einige der einzigartigen Eigenschaften der verschiedenen Blutgruppen. So gilt beispielsweise die Blutgruppe O als „Universalspender“, da sie Menschen mit jeder Blutgruppe transfundiert werden kann. Die vierte Gruppe hingegen macht ihre Träger zu „Universalempfängern“ – sie können Blut jeder Art annehmen. 

All diese Merkmale des Blutgruppensystems haben mich dazu inspiriert, entsprechende Mechanismen in meinem Algorithmus zu schaffen. Da die erste Blutgruppe die einfachste und häufigste ist, entspricht sie der Strategie, die beste im Algorithmus gefundene Lösung zu erhalten. Die Blutgruppenvererbungstabelle, in der alle möglichen Kombinationen der elterlichen Blutgruppen und die potenziellen Blutgruppen ihrer Kinder aufgeführt sind, bildet die Grundlage für die Bestimmung der „Blutgruppe“ einer neuen Lösung auf der Grundlage der „Blutgruppen“ der elterlichen Lösungen, was sich direkt auf die Art und Weise auswirkt, wie die Parameter im BIO-Algorithmus mutiert werden.

Blutgruppe

Abbildung 1. Blutgruppenvererbungstabelle 

Der BIO-Algorithmus basiert auf einer recht einfachen Idee: Jede Lösung in der Population (Elternindividuen) hat ihre eigene „Blutgruppe“ (von 1 bis 4), die durch ihre Ordnungszahl in der Population bestimmt wird. Wenn wir eine neue Generation von Lösungen erstellen, wählen wir zwei „Eltern“ aus der aktuellen Population aus. Die Wahrscheinlichkeit der Wahl ist nicht linear, sondern quadratisch – das bedeutet, dass die besten Entscheidungen eine deutlich höhere Chance haben, Eltern zu werden.

Jetzt beginnt der interessanteste Teil. Ausgehend von den Blutgruppen der Eltern werden mit Hilfe einer speziellen Vererbungsmatrix (sie ist im Code der Init-Methode enthalten) die möglichen Blutgruppen für das „Kind“ – die neue Lösung – bestimmt. Dann wird für jeden Parameter dieser neuen Lösung, wenn die erste Blutgruppe gefunden wurde, der Wert der besten gefundenen Lösung genommen. Ich habe dies in Analogie zur ersten Blutgruppe als Universalspender getan. Wenn die zweite Gruppe ausgewählt wird, nehmen wir den Wert von einem der Elternteile und wenden die Potenzverteilung auf ihn an. Dies führt zu einer Tendenz, die Ränder des Parameterbereichs zu erkunden. Für die dritte Gruppe nehmen wir ebenfalls einen Wert von einem der Elternteile, verschieben ihn aber um einen zufälligen Betrag in Richtung der besten Lösung. Und bei der vierten Gruppe nehmen wir den übergeordneten Wert und spiegeln ihn relativ zu den Bereichsgrenzen, eine Art Umkehrung, die es uns ermöglicht, neue Suchbereiche zu erkunden.

Nach der Erstellung einer neuen Generation prüfen wir, ob sich bessere Lösungen als die aktuelle Gesamtlösung ergeben haben, und speichern die besten Individuen für die nächste Iteration. In Analogie zur Vererbung von Blutgruppen erforscht mein Algorithmus den Lösungsraum durch die Kombination verschiedener Mutationsstrategien für Parameter. Nachstehend finden Sie den Pseudocode des Algorithmus.

Initialisierung:

  1. Erstelle eine Population von Agenten der Größe popSize (Standardwert 50).
  2. Erstelle einer Blutgruppenvererbungsmatrix, die die möglichen Blutgruppen der Kinder auf der Grundlage der Blutgruppen der Eltern bestimmt (1,2,3,4).
  3. Initialisiere die Bereiche der Parameter (Min., Max., Schrittwerte).

Hauptschleife:

  1. Wenn dies die erste Iteration ist (Revision = false):
    • Initialisiere die Positionen aller Agenten innerhalb der Parameterbereiche nach dem Zufallsprinzip
    • Setze das Revisionsflag auf „true“.
  2. Für jeden Agenten in der Population:
    • Wähle die elterlichen Agenten (Vater und Mutter) anhand einer quadratischen Wahrscheinlichkeitsverteilung
    • Bestimme die Blutgruppen beider Elternteile mit der Funktion: bloodType = 1 + (population_position % 4)
    • Für jeden Parameter der untergeordneten Lösung:
      • Ermittele der wahrscheinlichen Blutgruppe des Kindes anhand der Vererbungsmatrix auf der Grundlage der Blutgruppen der Eltern
      • Wenn das Kind die Blutgruppe 1 hat:
        • Verwende die beste bekannte Lösung für diesen Parameter.
      • Andernfalls:
        • Wähle zufällige einen Parameterwerts entweder vom Vater oder von der Mutter
        • Wende die Mutation auf der Grundlage der Blutgruppe des Kindes an:
          • Typ 2: Verwende eine Potenzgesetzverteilung mit Exponent 20.
          • Typ 3: Verschiebe des Parameterwerts in Richtung der besten Lösung mit einem Zufallsfaktor.
          • Typ 4: Spiegel den Parameterwert über den gesamten Parameterbereich.
      • Stelle sicher, dass der Parameter innerhalb des zulässigen Bereichs und der zulässigen Stufe bleibt.

Revisionsphase:

  1. Aktualisiere die global beste Lösung, wenn ein Agent eine bessere Eignung hat.
  2. Kopiere die aktuelle Population in die zweite Hälfte des erweiterten Populationsfeldes.
  3. Sortiere die erweiterte Population nach der Fitness.
  4. Bewahre die besten Agenten für die nächste Generation.

Beginnen wir mit dem Schreiben des Algorithmus-Codes. Die von C_AO abgeleitete Klasse C_AO_BIO implementiert den BIO-Algorithmus und setzt die Verwendung einer Datenstruktur zur Darstellung von Individuen (Agenten) in einer Population sowie deren Kontrolle voraus.

    C_AO_BIO () – Konstruktor, der die externen BIO-Parameter initialisiert: die Populationsgröße popSize wird auf 50 gesetzt, die Größe des Parameterarrays „params“ wird auf ein Element gesetzt, das popSize darstellt.
    SetParams ()
    – die Methode ermöglicht die Einstellung von Klassenparametern, in diesem Fall die Einstellung der Populationsgröße popSize aus dem Parameter-Array.
    Init ()
    – die Methode initialisiert den Algorithmus, indem sie die Minimal- und Maximalwerte der Parameter, den Änderungsschritt und die Anzahl der Epochen annimmt.
    Moving () und Revision () – Methoden sind für die Bewegung (Evolution) von Agenten in der Population und deren Revision (Leistungsbewertung und Auswahl der Besten) verantwortlich.
    S_Papa und S_Mama:
    • S_Papa ist eine Struktur, die ein Array von Blutgruppen (bTypes) enthält.
    • S_Mama enthält eine Reihe von vier S_Papa-Objekten, was auf das Vorhandensein von „Eltern“ zur weiteren genetischen Vermischung schließen lässt.

    Diese Art der Darstellung in Form von Strukturen ermöglicht es uns, die wahrscheinliche Blutgruppe der Nachkommen direkt von den Eltern zu erhalten, indem wir die Blutgruppe der Eltern angeben, also „ma [1].pa [2].bTypes“, wobei 1 und 2 die Blutgruppen der Mutter bzw. des Vaters sind.

    Die Methode GetBloodType ()liefert die Blutgruppe für einen bestimmten Erreger, während GetBloodMutation () den Mechanismus der Genmutation in Abhängigkeit von der Blutgruppe implementiert.

    //——————————————————————————————————————————————————————————————————————————————
    class C_AO_BIO : public C_AO
    {
      public: //--------------------------------------------------------------------
      C_AO_BIO ()
      {
        ao_name = "BIO";
        ao_desc = "Blood Inheritance Optimization";
        ao_link = "https://www.mql5.com/en/articles/17246";
    
        popSize = 50; // population size
    
        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: //-------------------------------------------------------------------
      struct S_Papa
      {
          int bTypes [];
      };
      struct S_Mama
      {
          S_Papa pa [4];
      };
      S_Mama ma [4];
    
      S_AO_Agent p [];
    
      int  GetBloodType     (int ind);
      void GetBloodMutation (double &gene, int indGene, int bloodType);
    };
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Init-Methode initialisiert eine Instanz der Klasse C_AO_BIO und bereitet sie auf die Arbeit vor, indem sie die Agentenpopulation und deren Eigenschaften einrichtet. Schauen wir uns nun die Umsetzung dieser Methode an.

    Aufruf der Methode StandardInit – die erste Zeichenkette prüft das Ergebnis des Aufrufs der Methode, die die grundlegenden Parameter prüft/initialisiert, die für das Funktionieren des Algorithmus erforderlich sind.

    Initialisierung des Agentenarrays:

    • Verändert die Größe des Agentenarrays „p“ auf das Doppelte der angegebenen Populationsgröße (popSize).
    • In der for-Schleife wird für jeden Agenten die Init-Methode aufgerufen, die den Agenten anhand der Koordinatenparameter initialisiert.
    Initialisierung der Blutgruppen:
    • Als Nächstes gibt die Methode die Größe der Arrays der Blutgruppen (bTypes) für die Strukturen S_Mama und S_Papa an.
    • Für verschiedene Kombinationen (z.B. ma [0].pa [0], ma [1].pa [2] usw.) werden verschiedene Bluttypen entsprechend einer speziellen Vererbungsmatrix gesetzt, und die Größe der Arrays wird über ArrayResize festgelegt.

    Die Init-Methode in der Klasse C_AO_BIO erfüllt also die wichtige Aufgabe, das Objekt für die Ausführung des Optimierungsalgorithmus vorzubereiten: Sie erstellt eine Population von Agenten, legt deren Anfangsparameter fest und definiert die Assoziationsregeln für die Blutgruppen (Vererbung). So kann man sofort die wahrscheinliche Blutgruppe der Nachkommen ermitteln und die Parameter ihres „Blutes“ für die weitere Evolution innerhalb des Algorithmus verwenden.

    //——————————————————————————————————————————————————————————————————————————————
    bool C_AO_BIO::Init (const double &rangeMinP  [],
                         const double &rangeMaxP  [],
                         const double &rangeStepP [],
                         const int     epochsP = 0)
    {
      if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
    
      //----------------------------------------------------------------------------
      ArrayResize (p, popSize * 2);
      for (int i = 0; i < popSize * 2; i++) p [i].Init (coords);
    
      //1-1
      ArrayResize (ma [0].pa [0].bTypes, 1);
    
      ma [0].pa [0].bTypes [0] = 1;
    
      //2-2
      ArrayResize (ma [1].pa [1].bTypes, 2);
    
      ma [1].pa [1].bTypes [0] = 1;
      ma [1].pa [1].bTypes [1] = 2;
    
      //3-3
      ArrayResize (ma [2].pa [2].bTypes, 2);
    
      ma [2].pa [2].bTypes [0] = 1;
      ma [2].pa [2].bTypes [1] = 3;
    
      //1-2; 2-1
      ArrayResize (ma [0].pa [1].bTypes, 2);
      ArrayResize (ma [1].pa [0].bTypes, 2);
    
      ma [0].pa [1].bTypes [0] = 1;
      ma [0].pa [1].bTypes [1] = 2;
    
      ma [1].pa [0].bTypes [0] = 1;
      ma [1].pa [0].bTypes [1] = 2;
    
      //1-3; 3-1
      ArrayResize (ma [0].pa [2].bTypes, 2);
      ArrayResize (ma [2].pa [0].bTypes, 2);
    
      ma [0].pa [2].bTypes [0] = 1;
      ma [0].pa [2].bTypes [1] = 3;
    
      ma [2].pa [0].bTypes [0] = 1;
      ma [2].pa [0].bTypes [1] = 3;
    
      //1-4; 4-1
      ArrayResize (ma [0].pa [3].bTypes, 2);
      ArrayResize (ma [3].pa [0].bTypes, 2);
    
      ma [0].pa [3].bTypes [0] = 2;
      ma [0].pa [3].bTypes [1] = 3;
    
      ma [3].pa [0].bTypes [0] = 2;
      ma [3].pa [0].bTypes [1] = 3;
    
      //2-3; 3-2
      ArrayResize (ma [1].pa [2].bTypes, 4);
      ArrayResize (ma [2].pa [1].bTypes, 4);
    
      ma [1].pa [2].bTypes [0] = 1;
      ma [1].pa [2].bTypes [1] = 2;
      ma [1].pa [2].bTypes [2] = 3;
      ma [1].pa [2].bTypes [3] = 4;
    
      ma [2].pa [1].bTypes [0] = 1;
      ma [2].pa [1].bTypes [1] = 2;
      ma [2].pa [1].bTypes [2] = 3;
      ma [2].pa [1].bTypes [3] = 4;
    
      //2-4; 4-2; 3-4; 4-3; 4-4
      ArrayResize (ma [1].pa [3].bTypes, 3);
      ArrayResize (ma [3].pa [1].bTypes, 3);
      ArrayResize (ma [2].pa [3].bTypes, 3);
      ArrayResize (ma [3].pa [2].bTypes, 3);
      ArrayResize (ma [3].pa [3].bTypes, 3);
    
      ma [1].pa [3].bTypes [0] = 2;
      ma [1].pa [3].bTypes [1] = 3;
      ma [1].pa [3].bTypes [2] = 4;
    
      ma [3].pa [1].bTypes [0] = 2;
      ma [3].pa [1].bTypes [1] = 3;
      ma [3].pa [1].bTypes [2] = 4;
    
      ma [2].pa [3].bTypes [0] = 2;
      ma [2].pa [3].bTypes [1] = 3;
      ma [2].pa [3].bTypes [2] = 4;
    
      ma [3].pa [2].bTypes [0] = 2;
      ma [3].pa [2].bTypes [1] = 3;
      ma [3].pa [2].bTypes [2] = 4;
    
      ma [3].pa [3].bTypes [0] = 2;
      ma [3].pa [3].bTypes [1] = 3;
      ma [3].pa [3].bTypes [2] = 4;
    
      return true;
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Methode Moving führt evolutionäre Schritte im Optimierungsprozess durch und wendet die Konzepte der Vererbung und Mutation auf eine Population von Agenten an. Schauen wir uns das genauer an:

    Prüfung der Notwendigkeit einer Revision – der erste Teil der Methode prüft, ob die Agenten aktualisiert oder „verschoben“ werden müssen, und wenn „Überarbeitung“ „falsch“ ist, erfolgt die anfängliche Initialisierung (oder Aktualisierung) der Koordinaten der Agenten (a [i] .c [j]):

    • Jeder Agent erhält Zufallswerte, die mit der Methode u.RNDfromCI im Bereich (rangeMin [j], rangeMax [j]) erzeugt werden.
    • Der Wert wird dann mit u.SeInDiSp in den gewünschten Bereich gebracht, wobei der in rangeStep angegebene Schritt angewendet wird.

    Wechsel zum Revisionsstatus – nach der ersten Iteration wird der Parameter „revision“ auf „true“ gesetzt, um zur nächsten Stufe zu wechseln, und die Methode schließt die Ausführung ab (Rückkehr).

    Initialisierung der Variablen – zu Beginn der Methode werden die Variablen für die Zufallswerte und die Blutgruppen der Eltern initialisiert (papIND, mamIND, pBloodType, mBloodType, cBloodType und bloodIND).

    Grundlegende Populationsschleife (popSize) – die Methode läuft in einer Schleife für jeden Agenten in der Population:

    • Zwei Zufallsindizes für Eltern (papIND und mamIND) werden mit der Methode u.RNDprobab () erzeugt, die Zufallswahrscheinlichkeiten generiert.
    • Die Funktion GetBloodType ermittelt die Blutgruppen beider Elternteile.

    Schleife nach Koordinaten (coords) – innerhalb der Hauptschleife für jede Agentenkoordinate:

    • Ein zufälliger Blutgruppenindex wird aus dem bTypes-Array der ausgewählten Eltern ausgewählt (basierend auf der Blutgruppe der Mutter und des Vaters).
    • Wenn die ausgewählte Blutgruppe 1 ist, erhält der Agent den Wert aus cB[c]. Andernfalls kommt es zu einer Vermischung:
      • Der Koordinatenwert der Agenten wird zufällig entweder vom Vater oder von der Mutter ausgewählt.
      • Es wird die Funktion GetBloodMutation verwendet, die den ausgewählten Wert auf der Grundlage der Blutgruppe mutiert.
      • Der Wert wird mit der Methode u.SeInDiSp angepasst, um sicherzustellen, dass er innerhalb akzeptabler Grenzen bleibt.

    Die gleitende Methode ist ein zentraler Bestandteil des Algorithmus, der die Evolution einer Agentenpopulation nachbildet und sowohl eine zufällige Initialisierung als auch Mechanismen zur Mutation und Kombination von Agentenparametern auf der Grundlage der Prinzipien der Blutgruppenvererbung umfasst. Die Methode kombiniert Aspekte des Zufalls und der Vererbung, um neue Nachkommen mit unterschiedlichen Werten zu erzeugen. Damit sind die Agenten für die weitere Optimierung und Suche im Lösungsraum gerüstet.

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_BIO::Moving ()
    {
      //----------------------------------------------------------------------------
      if (!revision)
      {
        for (int i = 0; i < popSize; i++)
        {
          for (int j = 0; j < coords; j++)
          {
            a [i].c [j] = u.RNDfromCI (rangeMin [j], rangeMax [j]);
            a [i].c [j] = u.SeInDiSp (a [i].c [j], rangeMin [j], rangeMax [j], rangeStep [j]);
          }
        }
        revision = true;
        return;
      }
    
      //----------------------------------------------------------------------------
      double rnd        = 0.0;
      int    papIND     = 0;
      int    mamIND     = 0;
      int    pBloodType = 0;
      int    mBloodType = 0;
      int    cBloodType = 0;
      int    bloodIND   = 0;
    
      for (int i = 0; i < popSize; i++)
      {
        rnd = u.RNDprobab ();
        rnd *= rnd;
        papIND = (int)u.Scale (rnd, 0.0, 1.0, 0, popSize - 1);
    
        rnd = u.RNDprobab ();
        rnd *= rnd;
        mamIND = (int)u.Scale (rnd, 0.0, 1.0, 0, popSize - 1);
    
        pBloodType = GetBloodType (papIND);
        mBloodType = GetBloodType (mamIND);
    
        for (int c = 0; c < coords; c++)
        {
          bloodIND   = MathRand () % ArraySize (ma [mBloodType - 1].pa [pBloodType - 1].bTypes);
          cBloodType = ma [mBloodType - 1].pa [pBloodType - 1].bTypes [bloodIND];
    
          if (cBloodType == 1) a [i].c [c] = cB [c];
          else
          {
            if (u.RNDbool () < 0.5) a [i].c [c] = p [papIND].c [c];
            else                    a [i].c [c] = p [mamIND].c [c];
    
            GetBloodMutation (a [i].c [c], c, cBloodType);
            a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
          }
        }
      }
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Methode GetBloodType bestimmt die Blutgruppe anhand des übergebenen Index „ind“ – der aktuellen Position in der Population. Die Methode gleicht also Indizes mit Blutgruppen durch eine einfache arithmetische Operation mit einem Rest ab. Dies ermöglicht eine zyklische Verteilung der Blutgruppen auf die verfügbaren Indizes (0-3).

    //——————————————————————————————————————————————————————————————————————————————
    int C_AO_BIO::GetBloodType (int ind)
    {
      if (ind % 4 == 0) return 1;
      if (ind % 4 == 1) return 2;
      if (ind % 4 == 2) return 3;
      if (ind % 4 == 3) return 4;
    
      return 1;
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Methode GetBloodMutation dient dazu, den Wert eines genetischen Parameters (Gens) in Abhängigkeit von seiner Blutgruppe und seinem Index zu ändern (zu mutieren).

    Parameter:

    • gene – Verweis auf den Genwert, der geändert werden soll.
    • indGene – Genindex, der zur Ermittlung der Mutationsbereiche verwendet wird.
    • bloodType – Blutgruppe, die die Mutationslogik bestimmt.

    Blutgruppe 2 – PowerDistribution wird auf den Genwert angewandt, wodurch das Gen auf der Grundlage eines gegebenen Bereichs verändert wird und die Werte um diesen Bereich herum probabilistisch verteilt werden.

    Blutgruppe 3 – das Gen erhöht sich um den Bruchteil der Differenz zwischen dem besten aktuellen Wert des Gens in der Population cB [indGene] und dem aktuellen Wert des Gens. Der Anteil der Vorspannung wird durch eine Zufallszahl [0,0; 1,0] bestimmt.

    Andere Blutgruppe (Standard) – das Gen wird so verändert, dass sein neuer Wert symmetrisch zum angegebenen Bereich (invers) ist und zwischen rangeMin [indGene] und rangeMax [indGene] liegt.

    //——————————————————————————————————————————————————————————————————————————————
    void  C_AO_BIO::GetBloodMutation (double &gene, int indGene, int bloodType)
    {
      switch (bloodType)
      {
        case 2:
          gene = u.PowerDistribution (gene, rangeMin [indGene], rangeMax [indGene], 20);
          return;
        case 3:
          gene += (cB [indGene] - gene) * u.RNDprobab ();
          return;
        default:
        {
          gene = rangeMax [indGene] - (gene - rangeMin [indGene]);
        }
      }
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Die Methode Revision ist für die Aktualisierung und Sortierung der Population im BIO-Algorithmus zuständig. In der ersten for-Schleife (von 0 bis popSize) iteriert die Methode über alle Mitglieder der Population a[i]. Wenn der Wert der Fitnessfunktion „f“ des aktuellen a[i].f-Populationsmitglieds den aktuell besten Wert von fB übersteigt, wird fB mit dem neuen Wert aktualisiert, und die Koordinaten „c“ des aktuellen Populationsmitglieds werden in das Array cB kopiert. In der zweiten „for“-Schleife werden die aktuellen Mitglieder der Population a[i] an das Ende des Arrays „p“ kopiert, beginnend mit dem Index popSize. Als Nächstes wird das pT-Array erstellt. Sie ist doppelt so groß wie die aktuelle Population „popSize * 2“. Die Sortiermethode u.Sorting wird aufgerufen, um das zusammengeführte Array von „p“ zu sortieren und die Ergebnisse in pT zu speichern.

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_BIO::Revision ()
    {
      //----------------------------------------------------------------------------
      for (int i = 0; i < popSize; i++)
      {
        // Update the best global solution
        if (a [i].f > fB)
        {
          fB = a [i].f;
          ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY);
        }
      }
    
      //----------------------------------------------------------------------------
      for (int i = 0; i < popSize; i++)
      {
        p [popSize + i] = a [i];
      }
    
      S_AO_Agent pT []; ArrayResize (pT, popSize * 2);
      u.Sorting (p, pT, popSize * 2);
    }
    //——————————————————————————————————————————————————————————————————————————————
    


    Testergebnisse

    Der Algorithmus wurde an drei verschiedenen Testfunktionen (Hilly, Forest und Megacity) mit unterschiedlichen Suchraumdimensionen (5*2, 25*2 und 500*2 Dimensionen) mit 10.000 Zielfunktionsbewertungen getestet. Das Gesamtergebnis von 53,80 % zeigt, dass BIO unter den Populationsbasierten Optimierungsalgorithmen eine durchschnittliche Position einnimmt, was für eine neue Methode recht gut ist. 

    BIO|Blood Inheritance Optimization|50.0|
    =============================
    5 Hilly's; Func runs: 10000; result: 0.8156790458423091
    25 Hilly's; Func runs: 10000; result: 0.6533623929914842
    500 Hilly's; Func runs: 10000; result: 0.3087659267627686
    =============================
    5 Forest's; Func runs: 10000; result: 0.8993708810337727
    25 Forest's; Func runs: 10000; result: 0.6531872390668734
    500 Forest's; Func runs: 10000; result: 0.21759965952460583
    =============================
    5 Megacity's; Func runs: 10000; result: 0.6784615384615384
    25 Megacity's; Func runs: 10000; result: 0.4763076923076923
    500 Megacity's; Func runs: 10000; result: 0.13901538461538585
    =============================
    All score: 4.84175 (53.80%)

    Das einzige Problem, das bei der Visualisierung des Algorithmus auftritt, ist die bei Populationsalgorithmen übliche Tendenz, bei Problemen mit kleinen Dimensionen in lokalen Optima stecken zu bleiben.

    Hilly

    BIO mit der Testfunktion Hilly

    Forest

    BIO mit der Testfunktion Forest

    Megacity

    BIO mit der Testfunktion Megacity

    Aufgrund der Testergebnisse belegt der BIO-Algorithmus Platz 20 in der Rangliste der Populationsoptimierungsalgorithmen.

    # 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 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
    39 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
    40 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
    41 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
    42 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
    43 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
    44 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
    45 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

    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

    Bei der Entwicklung und Erprobung des Algorithmus zur Optimierung der Blutvererbung (BIO) bin ich zu mehreren wichtigen Schlussfolgerungen gekommen. Zunächst einmal hat sich die Verwendung der Assoziation der Blutgruppenvererbung als erfolgreicher Ansatz erwiesen, um verschiedene Mutationsstrategien im Algorithmus zur Optimierung der Population zu organisieren. Tests mit verschiedenen Funktionen und Dimensionen haben gezeigt, dass der Algorithmus recht vielseitig ist und sowohl mit einfachen, niedrigdimensionalen Problemen als auch mit komplexeren, mehrdimensionalen Problemen effektiv arbeiten kann.

    Es ist besonders wichtig, darauf hinzuweisen, dass die vorgestellte BIO-Implementierung nur eine Basisversion zur Demonstration des Konzepts darstellt. Die Schlüsselidee des Algorithmus liegt nicht so sehr in den spezifischen Mutationsoperatoren (die durch beliebige andere ersetzt werden können), sondern in der Struktur der Vererbung von Strategien zur Änderung von Parametern durch eine Analogie mit Blutgruppen. Dies eröffnet weitreichende Möglichkeiten zur Änderung und Erweiterung des Algorithmus. Jede „Blutgruppe“ kann mit beliebigen anderen Mutationsoperatoren verbunden werden, die von anderen Algorithmen übernommen oder für eine bestimmte Aufgabe erstellt werden. Darüber hinaus können wir mit der Anzahl der „Blutgruppen“ experimentieren, neue Strategien hinzufügen oder bestehende Strategien kombinieren.

    Aktuelle Testergebnisse, die eine respektable Position in der Rangliste der Populationsalgorithmen zeigen (mit einer Punktzahl von etwa 54 %), weisen auf die Effizienz des Ansatzes bereits in seiner Grundimplementierung hin. Die beobachtete Tendenz, in lokalen Optima stecken zu bleiben, kann durch eine Änderung der Mutationsoperatoren oder durch neue Strategien zur Erkundung des Lösungsraums überwunden werden.

    Die vielversprechendste Richtung für die Entwicklung des Algorithmus sehe ich in der Schaffung adaptiver Versionen, bei denen sich die Mutationsoperatoren für jede „Blutgruppe“ während des Optimierungsprozesses dynamisch ändern und an die Landschaft der Zielfunktion anpassen können. Es ist auch interessant, die Möglichkeit zu untersuchen, andere Vererbungsmuster als das klassische ABO-Blutgruppensystem zu verwenden, was zur Schaffung einer ganzen Familie von Algorithmen führen könnte, die auf verschiedenen biologischen Vererbungssystemen basieren.

    BIO ist also nicht einfach nur ein weiterer Optimierungsalgorithmus, sondern eine flexible konzeptionelle Grundlage für die Schaffung einer Familie von Algorithmen, die durch die gemeinsame Idee der Vererbung von Lösungssuchstrategien durch die Metapher der Blutgruppen vereint sind, und eröffnet weitreichende Möglichkeiten für weitere Forschungen und Modifikationen zur Verbesserung der Effizienz des Algorithmus in verschiedenen Anwendungsbereichen.

    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)

    BIO Pro und Kontra:

    Vorteile:

    1. Keine externen Parameter
    2. Interessante Idee zur Vererbung nach Blutgruppen
    3. Gute Konvergenz bei hoch- und mitteldimensionalen Funktionen

    Nachteile:

    1. Bleibt bei niedrigdimensionalen Problemen an lokalen Extrema 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_BIO.mq5
    Skript BIO-Prüfstand

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

    Beigefügte Dateien |
    BIO.zip (166.57 KB)
    Neuronale Netze im Handel: Multi-Task-Lernen auf der Grundlage des ResNeXt-Modells (letzter Teil) Neuronale Netze im Handel: Multi-Task-Lernen auf der Grundlage des ResNeXt-Modells (letzter Teil)
    Wir erforschen weiterhin ein auf ResNeXt basierendes Multitasking-Lernsystem, das sich durch Modularität, hohe Recheneffizienz und die Fähigkeit, stabile Muster in Daten zu erkennen, auszeichnet. Die Verwendung eines einzigen Encoders und spezieller „Köpfe“ verringert das Risiko einer Überanpassung des Modells und verbessert die Qualität der Prognosen.
    Entwicklung eines Expert Advisors für mehrere Währungen (Teil 23): Ordnung in den Ablauf automatischer Projektoptimierungsstufe bringen (II) Entwicklung eines Expert Advisors für mehrere Währungen (Teil 23): Ordnung in den Ablauf automatischer Projektoptimierungsstufe bringen (II)
    Unser Ziel ist es, ein System zur automatischen periodischen Optimierung von Handelsstrategien zu schaffen, die in einem endgültigen EA verwendet werden. Im Laufe der Entwicklung wird das System immer komplexer, sodass es von Zeit zu Zeit in seiner Gesamtheit betrachtet werden muss, um Engpässe und suboptimale Lösungen zu ermitteln.
    Fibonacci am Devisenmarkt (Teil I): Prüfung des Verhältnisses zwischen Preis und Zeit Fibonacci am Devisenmarkt (Teil I): Prüfung des Verhältnisses zwischen Preis und Zeit
    Wie beobachtet der Markt Fibonacci-basierte Beziehungen? Diese Folge, bei der jede nachfolgende Zahl gleich der Summe der beiden vorhergehenden ist (1, 1, 2, 3, 5, 8, 13, 21...), beschreibt nicht nur das Wachstum der Kaninchenpopulation. Wir werden die pythagoreische Hypothese betrachten, dass alles in der Welt bestimmten Zahlenbeziehungen unterliegt...
    Marktsimulation (Teil 09): Sockets (III) Marktsimulation (Teil 09): Sockets (III)
    Der heutige Artikel ist eine Fortsetzung des vorangegangenen Artikels. Wir werden uns die Implementierung eines Expert Advisors ansehen und uns dabei vor allem darauf konzentrieren, wie der Servercode ausgeführt wird. Der im vorigen Artikel beschriebene Code reicht nicht aus, damit alles wie erwartet funktioniert. Daher ist es notwendig, beide Artikel zu lesen, um besser zu verstehen, was passieren wird.