Eagle-Strategie (ES)
Inhalt
Einführung
In der Welt der Programmierung, insbesondere bei der Entwicklung von Trading-EAs, spielt eine effektive Optimierung eine entscheidende Rolle. Hochspezialisierte Probleme, bei denen es darum geht, aus einer Vielzahl möglicher Optionen eine optimale Lösung zu finden, erfordern den Einsatz fortschrittlicher Algorithmen. Herkömmliche Optimierungsmethoden erweisen sich oft als unwirksam, da sie in lokalen Optima stecken bleiben und keine global bessere Lösung finden.
Dementsprechend rücken sowohl von der Natur inspirierte metaheuristische Algorithmen als auch Methoden, die sich im Zuge natürlicher Evolution herausgebildet haben, zunehmend in den Fokus. Diese Algorithmen sind in der Lage, gute und oft nahezu optimale Lösungen zu finden, selbst bei Problemen, bei denen die Rechengeschwindigkeit von entscheidender Bedeutung ist.
Vor dem Hintergrund immer komplexerer und ressourcenintensiverer Aufgaben werden wir heute einen weiteren vielversprechenden Ansatz untersuchen: Eagle Strategy (ES). Dieser Algorithmus, der vom Jagdverhalten des Adlers inspiriert ist, ist eine neue Metaheuristik, die darauf ausgelegt ist, Optimierungsprobleme durch die Simulation einer Strategie der visuellen Suche und der dynamischen Verfolgung der Beute zu lösen.
Implementierung des Algorithmus
Stell dir einen Steinadler vor, der hoch am Himmel schwebt und nach Beute Ausschau hält. Seine Jagdstrategie ist bemerkenswert effizient und besteht aus zwei klar voneinander getrennten Phasen: Zunächst fliegt er in großer Höhe und überfliegt mit chaotischen Zickzackbewegungen ein weitläufiges Gebiet; hat er dann ein Ziel ausgemacht, stürzt er sich rasch hinab und konzentriert all seine Kräfte auf eine bestimmte Beute. Es ist diese natürliche Weisheit, die die Grundlage für den Algorithmus der „Adlerstrategie“ bildete, der 2010 zur Lösung komplexer Optimierungsprobleme entwickelt wurde.
In der ersten Phase nutzt der Algorithmus sogenannte Levy-Flüge – ein mathematisches Modell, das Bewegungen im Raum beschreibt. Im Gegensatz zu einem typischen Zufallsweg, bei dem die Schritte in etwa gleichmäßig verteilt sind, besteht ein Levy-Flug aus vielen kleinen Schritten, die von seltenen, aber sehr langen Sprüngen unterbrochen werden.
Wenn der Algorithmus einen vielversprechenden Bereich findet (wie ein Adler, der Beute erspäht), wird die zweite Stufe aktiviert – eine intensive lokale Suche unter Verwendung des Firefly-Algorithmus. Einen solchen bekannten Algorithmus haben wir bereits in einem früheren Artikel behandelt. Mehrere Suchagenten werden – wie Glühwürmchen in der Nacht – von helleren (erfolgreichen) Nachbarn angezogen. Die Helligkeit des Glühwürmchens hängt von der Qualität der Lösung ab, die es findet, und die Anziehungskraft nimmt mit zunehmender Entfernung exponentiell ab. Dadurch entsteht ein Gleichgewicht zwischen der Erkundung der Umgebung und der Bewegung in Richtung der bisher besten bekannten Lösung.
Die zentrale Neuerung von ES ist der zyklische Wechsel zwischen diesen beiden Modi. Nach einer intensiven lokalen Suche wechselt der Algorithmus wieder zur globalen Suche und macht einen großen Sprung in einen neuen, noch unerforschten Bereich des Suchraums. Dadurch wird eine vorzeitige Konvergenz verhindert und es kann selbst in sehr komplexen Landschaften mit vielen lokalen Optima ein globales Optimum gefunden werden.
Die Algorithmusparameter sind intuitiv und einfach zu konfigurieren. Die Populationsgröße bestimmt die Anzahl der gleichzeitig suchenden Agenten, der Levy-Parameter steuert das Verhältnis zwischen kurzen und langen Sprüngen, der Radius der Hyperkugel definiert den Bereich der intensiven lokalen Suche, und der Randomisierungskoeffizient fügt ein Zufallselement hinzu, um lokale Fallen zu überwinden. Dank dieser Flexibilität lässt sich der Algorithmus an ein bestimmtes Problem anpassen, ohne dass dafür tiefgreifende Kenntnisse der mathematischen Theorie erforderlich sind.
Die Philosophie des ES-Algorithmus ist einfach und elegant: globaler Überblick kombiniert mit lokaler Präzision. So wie ein Adler den Erkundungsflug mit einem gezielten Angriff verbindet, hält der Algorithmus das Gleichgewicht zwischen der Erkundung unbekannter Gebiete und der Nutzung vielversprechender Lösungen, die er findet.
Die Hauptmerkmale des Algorithmus sind: automatischer Wechsel zwischen den Phasen, sobald sich die Lösung verbessert, adaptive Parameter (λ nimmt bei Stagnation ab, die Schrittweite verringert sich mit der Zeit) sowie ein Gleichgewicht zwischen der Erkundung neuer Bereiche und der Nutzung der gefundenen Lösungen.

Abb. 1. Der ES-Algorithmus im Einsatz
Die Abbildung zeigt die beiden Betriebsphasen des Algorithmus, die Levy-Flugbahnen (rote gepunktete Linien), die lokale Suchhypersphäre (blauer Kreis), die Bewegung der Glühwürmchen innerhalb der Kugel (grüne Punkte mit Lichtkränzen) sowie die Konturlinien der Optimierungsfunktion.
Bereiten wir den Pseudocode vor.
INITIALISIERUNG:
1. Erstelle eine Population von Agenten mit zufälligen Positionen
2. Setze das Flag für die globale Suche (phase = global).
3. Initialisiere die Stagnations- und Fortschrittszähler
HAUPTSCHLEIFE (bis das Stoppkriterium erfüllt ist):
WENN (phase = global):
FÜR jeden Agenten:
– Erzeuge einen Levy-Schritt mithilfe des Mantegna-Algorithmus
– Berechne die adaptive Schrittweite (am Anfang größer, am Ende kleiner)
– Aktualisiere die Position: neue_Position = aktuelle_Position + Levy-Schritt × Skalierung
– Wende die Randbedingungen an
WENN (eine Verbesserung gegenüber der global besten Lösung festgestellt wird):
– Wechsel in die lokale Phase
– Bestimme den besten Agenten als Zentrum der lokalen Suche
– Setze den Stagnationszähler zurück
SONST:
– Erhöhe den Stagnationszähler
– WENN (Stagnation > 5 Iterationen):
– Verringere den λ-Parameter für aggressivere Flüge
SONST (Phase = lokal):
Mit einer Wahrscheinlichkeit von 80 %:
– Ermittle Agenten in einer Hypersphäre mit einem Radius von 0,1 um den besten Agenten
– WENN (Agenten < 5):
– Nimm die 5 nächsten Nachbarn oder 30 % der Population
Für jeden Agenten in der lokalen Gruppe:
Für jeden anderen Agenten in der Gruppe:
FALLS (ein anderer Agent besser ist):
– Berechne die Anziehungskraft β = β₀ × exp(-γ × Entfernung²)
– Verschiebe den Agenten: Position += β × (beste Position – aktuelle Position) + Zufallsrauschen
Mit einer Wahrscheinlichkeit von 20 %:
– Übertrage teilweise Koordinaten des global besten Agenten auf zufällig gewählte Koordinatenwerte.
– Erhöhe den lokalen Iterationszähler
– WENN (20 lokale Iterationen abgeschlossen):
– Kehre zur globalen Phase zurück
– Stelle den ursprünglichen λ-Parameter wieder her
UPDATE:
FÜR jeden Agenten:
– Berechne die Fitness
– Aktualisiere den persönlichen Bestwert
– Aktualisiere den globalen Bestwert
In dieser Implementierung des ES-Algorithmus wird ein numerisches Verfahren angewendet, um Zahlen mit der Levy-Verteilung zu erzeugen — Mantegna-Algorithmus. Das Verfahren wurde 1994 von R. N. Mantegna vorgeschlagen und wurde zur Standardmethode für die Simulation von Levy-Flügen in Optimierungsalgorithmen. Mantegna hat mathematisch nachgewiesen, dass das Verhältnis zweier speziell skalierter Gaußscher Größen eine Verteilung ergibt, die im für praktische Anwendungen relevanten Wertebereich der Levy-Verteilung sehr nahekommt. Der Kernpunkt lautet wie folgt:
// Calculating sigma for Mantegna algorithm double numerator = Gamma(1.0 + lambda) * MathSin(M_PI * lambda / 2.0); double denominator = Gamma((1.0 + lambda) / 2.0) * lambda * MathPow(2.0, (lambda - 1.0) / 2.0); double sigma = MathPow(numerator / denominator, 1.0 / lambda); // Generate u and v from normal distributions double u_val = GenerateGaussian() * sigma; double v_val = MathAbs(GenerateGaussian()); // Calculate Levy step levyStep[c] = u_val / MathPow(v_val, 1.0 / lambda);
Nehmen wir zwei Zufallsvariablen:
- u – aus der Normalverteilung N(0, σ²)
- v – aus der Normalverteilung N(0, 1)
σ = [Γ(1+λ) × sin(πλ/2) / (Γ((1+λ)/2) × λ × 2^((λ-1)/2))]^(1/λ)
wobei Γ die Gammafunktion ist und λ der Parameter der Levy-Verteilung (1 < λ ≤ 3).
Es ist wichtig zu beachten, dass bei der Bestimmung der Gammafunktion (zur Berechnung des σ-Parameters in der Mantegna-Methode) die Lanczos-Näherung verwendet wird, bei der es sich um eine hochgenaue numerische Methode zur Berechnung der Gammafunktion handelt. Dies ist eine der effizientesten Methoden zur Berechnung von Γ(z) und ist im Code als separate Funktion implementiert, auf die wir zum Schluss eingehen werden.
Die Grundgleichung lautet wie folgt:
Γ(z+1) = √(2π) × ((z+g+0.5)^(z+0.5)) × e^(-(z+g+0.5)) × Ag(z)
wobei: g ein Parameter ist (in der Regel 7); Ag(z) eine Reihe mit vorab berechneten Koeffizienten ist; bei g = 7 und 9 Koeffizienten ergibt sich eine Genauigkeit von etwa 15 signifikanten Stellen.
Für z < 0,5 verwendet die Reflexionsformel das Verhältnis, wodurch die Gammafunktion für alle reellen Zahlen berechnet werden kann:
Γ(z) × Γ(1-z) = π / sin(πz)
Ohne eine effiziente Berechnung der Gammafunktion wäre die Erzeugung von Levy-Flügen rechenintensiv, was den gesamten Optimierungsalgorithmus erheblich verlangsamen würde.
Endgültiger Levy-Schritt:
step = u / |v|^(1/λ) Der Algorithmus erzeugt eine Schrittfolge, deren Verhalten typisch für Levy-Flüge ist: viele kleine Schritte (lokale Erkundung), seltene, aber sehr große Sprünge (globale Erkundung) sowie eine Potenzgesetzverteilung der Schrittlängen.
Die Vorteile dieser Methode liegen in der Einfachheit der Lösung – da lediglich ein Normalverteilungsgenerator benötigt wird – sowie in der Stabilität und numerischen Robustheit des Algorithmus. Gerade diese Eigenschaft macht Levy-Flüge für die Optimierung so effektiv – sie bieten ein optimales Gleichgewicht zwischen der detaillierten Erkundung lokaler Bereiche und dem schnellen Übergang zu neuen Regionen des Suchraums.
Nach einer eingehenden Untersuchung der im ES-Algorithmus verwendeten Methoden können wir nun mit der Erstellung der Klasse C_AO_ES fortfahren, die die Implementierung einer auf der Eagle-Hunting-Strategie basierenden Optimierungsmethode darstellt und von der Basisklasse C_AO abgeleitet ist. Das Verfahren erfolgt in zwei Schritten: Zunächst wird eine globale Suche durchgeführt, um potenziell vielversprechende Bereiche zu identifizieren, anschließend wird eine lokale Suche innerhalb des ausgewählten Suchbereichs durchgeführt, um das Ergebnis zu verfeinern.
Die Populationsgröße popSize gibt die Anzahl der „Kandidaten“-Lösungen an, die an der Suche teilnehmen. Der Lambda-Levy-Parameter steuert die Verteilung der Zufallssprünge. Der Radius der Hyperkugel „sphereRadius“ legt den Bereich für die lokale Suche fest. Die Anzahl der lokalen Suchiterationen „localIterations“ gibt an, wie oft die Lösung innerhalb der Hyperkugel verfeinert wird. Die Randomisierungs- und Attraktivitätsparameter „alpha“ und „beta0“ steuern Komponenten der Suchmodelle, wie beispielsweise zufällige Bewegungen und den Einfluss von „Licht“ (im übertragenen Sinne).
Die globale Suchphase (GlobalExploration) konzentriert sich darauf, mithilfe von zufälligen Schritten, die nach der Levy-Verteilung generiert werden, „vielversprechende“ Regionen im gesamten Suchraum zu finden. Dieser Ansatz ermöglicht eine umfassende Erkundung und lässt sich gut auf große Suchräume skalieren.
Die lokale Intensivsuche (LocalExploitation) führt eine gründlichere Suche innerhalb der Hypersphäre um den ausgewählten Punkt herum durch. In diesem Fall werden kleinere und präzisere Schritte verwendet, was einer lokalen Optimierung entspricht.
Die Erzeugung von Levy-Schritten (GenerateLevyStep) generiert zufällige Bewegungen unter Verwendung der Levy-Verteilung; dies sorgt sowohl für kleine als auch für große Sprünge im Suchraum, um ein Gleichgewicht zwischen Erkundung und Ausnutzung herzustellen.
Die Klasse enthält Mechanismen zur Verfolgung des Suchfortschritts, wie beispielsweise das Speichern der besten gefundenen Lösung, Stagnationszähler (falls sich die Lösung nicht verbessert) sowie Epochen-Schleifen zur Begrenzung der Algorithmusausführung nach Zeit oder Iterationen, Berechnungen von Verteilungsparametern für Zufallsschritte, insbesondere die Erzeugung von Gauß- und Levy-Verteilungen, sowie Methoden zur Steuerung der Suchphasen, die den Wechsel zwischen der globalen und der lokalen Phase gewährleisten und die Kontrolle über deren Ablauf ermöglichen.
Insgesamt bietet die Methode eine Suchstrategie, die eine umfassende Erkundung des Suchraums zur Identifizierung potenzieller Bereiche mit einer anschließenden sorgfältigen lokalen Optimierung kombiniert, um präzise Lösungen zu erzielen. Dabei kommen Parameter und Mechanismen zum Einsatz, die es ermöglichen, das Verhalten der Methode an spezifische Probleme und Bedingungen anzupassen.
//———————————————————————————————————————————————————————————————————— class C_AO_ES : public C_AO { public: //---------------------------------------------------------- ~C_AO_ES () { } C_AO_ES () { ao_name = "ES"; ao_desc = "Eagle Strategy"; ao_link = "https://www.mql5.com/en/articles/18460"; popSize = 100; // population size lambda = 1.0; // Levy distribution parameter (1 < λ ≤ 3) sphereRadius = 0.1; // hypersphere radius for local search localIterations = 20; // number of local search iterations alpha = 0.1; // randomization parameter for Firefly beta0 = 1.2; // initial attractiveness ArrayResize (params, 6); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "lambda"; params [1].val = lambda; params [2].name = "sphereRadius"; params [2].val = sphereRadius; params [3].name = "localIterations"; params [3].val = localIterations; params [4].name = "alpha"; params [4].val = alpha; params [5].name = "beta0"; params [5].val = beta0; } void SetParams () { popSize = (int)params [0].val; lambda = params [1].val; sphereRadius = params [2].val; localIterations = (int)params [3].val; alpha = params [4].val; beta0 = params [5].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 (); //------------------------------------------------------------------ double lambda; // Levy distribution parameter (1 < λ ≤ 3) double sphereRadius; // hypersphere radius for local search int localIterations; // number of local search iterations double alpha; // randomization parameter double beta0; // initial attractiveness private: //--------------------------------------------------------- double gamma_es; // light absorption coefficient double levyStep []; // array for Levy steps // Phase tracking bool inLocalSearchPhase; // local search flag int localSearchCenter; // local search center int localSearchCounter; // local search iteration counter // Monitoring convergence double prevBestFitness; // previous best value int stagnationCounter; // stagnation counter // Tracking epochs int epochCurrent; // current epoch int epochMax; // maximum number of epochs // Auxiliary methods void GlobalExploration (); void LocalExploitation (); void GenerateLevyStep (); double GenerateGaussian (); double Gamma (double z); }; //————————————————————————————————————————————————————————————————————
Die Methode „Init“ der Klasse C_AO_ES initialisiert den Optimierungsalgorithmus vor Beginn der Suche. Zunächst wird die Methode „StandardInit“ aufgerufen, die für die Standardinitialisierung des Algorithmus zuständig ist. Es konfiguriert die allgemeinen Parameter und Datenstrukturen. Wenn StandardInit fehlschlägt, gibt die gesamte Methode „false“ zurück, was darauf hinweist, dass die Initialisierung nicht erfolgreich war.
Anschließend wird Speicher für das Array „levyStep“ zugewiesen, dessen Größe der Anzahl der Koordinaten „coords“ entspricht. Dieses Array dient zur Speicherung der gemäß der Levy-Verteilung generierten Schritte. Ist das Flag „inLocalSearchPhase“ auf „false“ gesetzt, befindet sich der Algorithmus zunächst in der globalen Suchphase. Die Variablen „localSearchCenter“ und „localSearchCounter“ werden auf „0“ gesetzt, um die Zähler für die lokale Suche vorzubereiten.
Initialisierung der Konvergenzparameter:
- prevBestFitness wird auf den kleinstmöglichen Wert gesetzt, damit die erste gefundene Lösung garantiert als besser als die vorherige angesehen wird.
- stagnationCounter wird auf „0“ gesetzt, um die Anzahl der Iterationen zu erfassen, bei denen die bisher beste Lösung nicht verbessert wurde.
Initialisierung der Epochenparameter:
- epochMax erhält den Wert der Eingabe epochsP, wodurch die maximale Anzahl von Epochen (Iterationen) des Algorithmus festgelegt wird.
- epochCurrent wird auf „0“ gesetzt, um die aktuelle Epoche zu verfolgen.
Es wird ein fester Parameter gesetzt: Der Variablen „gamma_es“ wird der Wert „1,0“ zugewiesen. Dieser Parameter wird im Firefly-Algorithmus verwendet, der Teil der Gesamtstrategie ist.
Die Ausgangspopulation von „a“ Lösungen wird initialisiert. Für jede Lösung in der Population:
- Jede Koordinate des Lösungsvektors (a[i].c[c]) wird mit einem Zufallswert aus dem Bereich [rangeMin[c], rangeMax[c]] initialisiert.
- Der Wert jeder Koordinate wird unter Berücksichtigung des Schritts (rangeStep[c]) mithilfe der Methode u.SeInDiSp auf den nächstgelegenen zulässigen Wert „gerundet“.
- Der Wert der Zielfunktion (a[i].f und a[i].fB) wird für jede Lösung auf „-DBL_MAX“ gesetzt.
//———————————————————————————————————————————————————————————————————— bool C_AO_ES::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //------------------------------------------------------------------ // Initialize arrays ArrayResize (levyStep, coords); // Initialize phase tracking inLocalSearchPhase = false; localSearchCenter = 0; localSearchCounter = 0; // Initialize convergence tracking prevBestFitness = -DBL_MAX; stagnationCounter = 0; // Initialize epoch tracking epochMax = epochsP; epochCurrent = 0; // Fixed Firefly parameter gamma_es = 1.0; // Initialize the population randomly 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]); } a [i].f = -DBL_MAX; a [i].fB = -DBL_MAX; } return true; } //————————————————————————————————————————————————————————————————————
Die Moving-Methode setzt die grundlegende Logik der iterativen Optimierung um, bei der zwischen globaler Suche und lokaler Ausnutzung gewechselt wird. Bei jedem Methodenaufruf wird der Epochenzähler erhöht, um den Fortschritt des Algorithmus zu verfolgen.
Abwicklung der Suchphasen:-
Wenn die aktuelle Phase eine globale Suche ist, wird der Raum anhand von Schritten erkundet, die der Levy-Verteilung nachempfunden sind, wodurch neue Lösungen im gesamten Raum generiert werden, um nach neuen Bereichen mit Potenzial zu suchen;
-
Wenn nach einer globalen Suche eine Verbesserung gefunden wird, wechselt der Algorithmus zur lokalen Phase. In diesem Fall wird die vielversprechendste Lösung (Agent) ausgewählt, um die herum eine Suche durchgeführt wird, um sie weiter zu verfeinern;
-
Wenn über mehrere Iterationen hinweg keine Verbesserungen eintreten (Stagnation setzt ein), wird die Suche nach neuen Lösungen durch aggressivere Flugsprünge intensiviert, wobei der Lambda-Parameter verringert wird, um den Raum umfassender zu erkunden;
-
Befindet sich der Algorithmus in der lokalen Suchphase, besteht eine Wahrscheinlichkeit von 80 %, dass die lokale Optimierung mithilfe einer Methode durchgeführt wird, die den Firefly-Algorithmus simuliert. In diesem Fall wird die gewählte Lösung verfeinert und der lokale Iterationszähler erhöht. Sobald die festgelegte Anzahl von Iterationen der lokalen Suche erreicht ist, kehrt der Algorithmus zur globalen Suche zurück.
Somit verfolgt das Verfahren einen schrittweisen und flexiblen Suchansatz, bei dem sich globale Erkundung und gezielte lokale Optimierung abwechseln. Dies ermöglicht ein Gleichgewicht zwischen der Erforschung neuer Bereiche und der Verbesserung bestehender Lösungen.
//———————————————————————————————————————————————————————————————————— void C_AO_ES::Moving () { epochCurrent++; // PHASE DECISION: Alternating between global and local search if (!inLocalSearchPhase) { // PHASE 1: GLOBAL EXPLORATION using Levy flights GlobalExploration (); // Check whether it is necessary to switch to local search // Switch if we find a promising area (improving the best fitness) if (fB > prevBestFitness) { inLocalSearchPhase = true; localSearchCounter = 0; prevBestFitness = fB; stagnationCounter = 0; // Find the best agent to center local search localSearchCenter = 0; double bestFit = -DBL_MAX; for (int i = 0; i < popSize; i++) { if (a [i].f > bestFit) { bestFit = a [i].f; localSearchCenter = i; } } } else { stagnationCounter++; // In case of stagnation, increase exploration if (stagnationCounter > 5) { lambda = MathMax (1.0, lambda - 0.1); // Make Levy flights more aggressive } } } else { if (u.RNDprobab () < 0.8) { // PHASE 2: LOCAL EXPLOITATION using the Firefly algorithm LocalExploitation (); localSearchCounter++; // Return to global search after local iterations are complete if (localSearchCounter >= localIterations) { inLocalSearchPhase = false; lambda = params [1].val; // Reset lambda to its original value } } else { for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { if (u.RNDprobab () < 0.5) { a [i].c [c] = cB [c]; } } } } } } //————————————————————————————————————————————————————————————————————
Die Revisionsmethode dient dazu, Informationen über die besten Lösungen während der Ausführung des Algorithmus zu aktualisieren. Die Methode durchläuft alle Elemente der aktuellen Lösungsmenge und vergleicht bei jeder Lösung deren aktuelle Fitness mit der in ihrem persönlichen Bestwert gespeicherten Fitness. Ist der aktuelle Wert besser, werden das persönliche Bestergebnis und die entsprechende Lösung aktualisiert (die beste Lösung der aktuellen Iteration wird gespeichert).
Anschließend vergleicht das Verfahren die Fitness jeder Lösung mit dem aktuell besten Wert, der in der gesamten Population gefunden wurde. Ist das aktuelle Ergebnis das beste, wird das globale Ergebnis aktualisiert und die entsprechende Lösung gespeichert. Auf diese Weise hält das Verfahren im aktuellen Zustand des Algorithmus aktuelle Informationen über lokale und globale optimale Lösungen bereit und stellt so sicher, dass die besten gefundenen Lösungen bei jedem Schritt erhalten bleiben.
//———————————————————————————————————————————————————————————————————— void C_AO_ES::Revision () { for (int i = 0; i < popSize; i++) { // Updating the personal best one if (a [i].f > a [i].fB) { a [i].fB = a [i].f; ArrayCopy (a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY); } // Update the global best one if (a [i].f > fB) { fB = a [i].f; ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY); } } } //————————————————————————————————————————————————————————————————————
Die GlobalExploration-Methode implementiert eine globale Suchphase, bei der der Lösungsraum mithilfe von Levy-Flügen durchsucht wird. Für jede Lösung in der Schleife wird unter Verwendung der Levy-Verteilung ein Zufallssprung über die gesamte Population generiert, der die Richtung und die Länge der Bewegung im Lösungsraum bestimmt.
Die Levy-Verteilung zeichnet sich durch „schwere Verteilungsschwänze“ aus, was sowohl kleine Verfeinerungsschritte als auch große, seltene Sprünge ermöglicht, um entfernte Regionen zu erkunden. In der Schleife wird für jede Koordinate der Lösung Folgendes berechnet:
- Suchbereich (die Differenz zwischen dem maximalen und dem minimalen Koordinatenwert),
- stepScale – adaptiver Skalierungsfaktor. Er nimmt im Verlauf der Suche ab (je näher man dem Ende kommt, desto kleiner werden die Schritte), was dazu beiträgt, den Suchbereich um vielversprechende Lösungen einzugrenzen, während die Schritte zu Beginn der Suche größer sind, um eine umfassendere Erkundung zu ermöglichen.
- Der Levy-Schritt wird angewendet: Die Koordinate der aktuellen Lösung wird um einen Wert verschoben, der proportional zum Levy-Schritt, zur Suchspanne und zum Skalierungsfaktor ist.
- Grenzkorrektur: Die neue Koordinate wird daraufhin überprüft, ob sie außerhalb des zulässigen Bereichs liegt; ist dies der Fall, wird der Wert so angepasst, dass er innerhalb des festgelegten Bereichs bleibt.
//———————————————————————————————————————————————————————————————————— // PHASE 1: GLOBAL EXPLORATION using Levy flights void C_AO_ES::GlobalExploration () { for (int i = 0; i < popSize; i++) { // Generate Levy step GenerateLevyStep (); // Update position using Levy flight for (int c = 0; c < coords; c++) { double range = rangeMax [c] - rangeMin [c]; // Adaptive step size depending on search progress double progress = (epochMax > 0) ? (double)epochCurrent / (double)epochMax : 0.5; double stepScale = 0.01 + 0.2 * (1.0 - progress); // Start with big steps // Apply the Levy step a [i].c [c] += levyStep [c] * range * stepScale; // Boundary restrictions a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } //————————————————————————————————————————————————————————————————————
Die Methode „LocalExploitation“ implementiert eine lokale Optimierungsphase für Lösungen unter Verwendung des Firefly-Algorithmus. Zunächst werden die Agenten ermittelt, die sich innerhalb einer bestimmten Hyperkugel um die beste Lösung befinden. Dazu wird der Abstand jedes Agenten zum Mittelpunkt der Hyperkugel berechnet; ist dieser kleiner als der Radius oder befindet sich der Agent im Mittelpunkt der Suche, wird er in die ausgewählte Gruppe aufgenommen.
Befinden sich zu wenige Agenten innerhalb der Hyperkugel, wird der Suchbereich um die nächsten Nachbarn erweitert. Dazu wird für alle Agenten die Entfernung zum Zentrum berechnet, und die nächstgelegenen werden ausgewählt – entweder nach ihrer Anzahl (zum Beispiel 5) oder nach ihrem Anteil an der Gesamtzahl (zum Beispiel 30 %). Diese Agenten werden der Gruppe hinzugefügt.
Anwendungsbereich des Firefly-Algorithmus: Die ausgewählten Agenten interagieren gemäß den Regeln des Algorithmus:- Für jeden Agenten wird geprüft, ob es in der Gruppe einen anderen Agenten mit besserer Fitness gibt.
- Gibt es einen solchen, bewegt sich der aktuelle Agent auf einen attraktiveren (besseren) Agenten zu, und der Abstand zwischen ihnen wird berechnet.
- Je attraktiver ein anderer Agent ist, desto größer ist seine „Leuchtkraft“ (abhängig von der Entfernung und den Algorithmusparametern).
- Die Bewegung verbindet die Anziehungskraft zu einem besseren Agenten mit einer zufälligen Störung, um die Vielfalt zu erhalten.
- Nach den Verschiebungen werden die Koordinatengrenzen überprüft, um sicherzustellen, dass die Lösungen innerhalb des zulässigen Bereichs bleiben.
Dadurch ermöglicht die Methode eine lokale Verbesserung der Lösungen in der Nähe der gefundenen besten Punkte, indem sie die Interaktion der Agenten gemäß dem Strategie-Modell des Firefly-Algorithmus nutzt: Die besten Lösungen ziehen die schlechtesten an, was die punktuelle Optimierung des Lösungsraums erleichtert.
//———————————————————————————————————————————————————————————————————— // PHASE 2: Local exploitation using the Firefly algorithm void C_AO_ES::LocalExploitation () { // Identification of agents inside the hypersphere around the best solution double agents_in_sphere []; ArrayResize (agents_in_sphere, 0); for (int i = 0; i < popSize; i++) { double normalized_dist = 0.0; for (int c = 0; c < coords; c++) { double diff = (a [i].c [c] - a [localSearchCenter].c [c]) / (rangeMax [c] - rangeMin [c]); normalized_dist += diff * diff; } normalized_dist = MathSqrt (normalized_dist); // Include agents inside the sphere or the center itself if (normalized_dist <= sphereRadius || i == localSearchCenter) { int size = ArraySize (agents_in_sphere); ArrayResize (agents_in_sphere, size + 1); agents_in_sphere [size] = i; } } // If there are too few agents, expand to the nearest neighbors if (ArraySize (agents_in_sphere) < 5) { ArrayResize (agents_in_sphere, 0); // Calculate distances for all agents double distances []; ArrayResize (distances, popSize); for (int i = 0; i < popSize; i++) { if (i == localSearchCenter) { distances [i] = 0.0; } else { double dist = 0.0; for (int c = 0; c < coords; c++) { double diff = (a [i].c [c] - a [localSearchCenter].c [c]) / (rangeMax [c] - rangeMin [c]); dist += diff * diff; } distances [i] = MathSqrt (dist); } } // Take the closest 5 agents or 30% of the population int numAgents = MathMin (popSize, MathMax (5, popSize / 3)); ArrayResize (agents_in_sphere, numAgents); // Simple selection of nearby agents for (int k = 0; k < numAgents; k++) { double minDist = DBL_MAX; int minIdx = -1; for (int i = 0; i < popSize; i++) { bool already_selected = false; for (int j = 0; j < k; j++) { if (agents_in_sphere [j] == i) { already_selected = true; break; } } if (!already_selected && distances [i] < minDist) { minDist = distances [i]; minIdx = i; } } agents_in_sphere [k] = minIdx; } } // Execute the Firefly algorithm on the selected agents int numLocalAgents = ArraySize (agents_in_sphere); for (int i = 0; i < numLocalAgents; i++) { int idx_i = (int)agents_in_sphere [i]; for (int j = 0; j < numLocalAgents; j++) { if (i == j) continue; int idx_j = (int)agents_in_sphere [j]; // If agent j is better than agent i, move i to j if (a [idx_j].f > a [idx_i].f) { // Calculate the distance double r_squared = 0.0; for (int c = 0; c < coords; c++) { double diff = (a [idx_j].c [c] - a [idx_i].c [c]) / (rangeMax [c] - rangeMin [c]); r_squared += diff * diff; } // Calculate attractiveness double beta = beta0 * MathExp (-gamma_es * r_squared); // Move agent i to agent j for (int c = 0; c < coords; c++) { double range = rangeMax [c] - rangeMin [c]; // Firefly motion equation a [idx_i].c [c] += beta * (a [idx_j].c [c] - a [idx_i].c [c]) + alpha * (u.RNDfromCI (-0.5, 0.5)) * range * 0.1; // Apply borders a [idx_i].c [c] = u.SeInDiSp (a [idx_i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } } } //————————————————————————————————————————————————————————————————————
Die Methode „GenerateLevyStep“ ist für die Erzeugung des Levy-Schritts zuständig, der für die Umsetzung der globalen Erkundungsstrategie im Optimierungsalgorithmus zuständig ist. Die Methode nutzt den Mantegna-Algorithmus zur Erzeugung dieser Schritte, eine Methode, die wir bereits oben erläutert haben.
Berechnung von Sigma:
Die Formel im Code berechnet den Sigma-Parameter. Dieser Parameter steht im Zusammenhang mit der Skala der Levy-Verteilung und hängt von der Konstante Lambda ab, die die Form der Levy-Verteilung charakterisiert (und bestimmt, wie „schwer“ die Verteilungsschwänze ausfallen). Gamma() ist die Gammafunktion, eine Verallgemeinerung der Fakultät auf reelle Zahlen (der Code für diese Methode ist weiter unten aufgeführt). Dieser Parameter wird benötigt, um normalverteilte Werte zu generieren, die anschließend im Mantegna-Algorithmus verwendet werden.
Die Erzeugung des Levy-Schritts erfolgt für jede Koordinate (jeden Parameter) der Lösung unabhängig voneinander. Es werden zwei Zufallsvariablen u_val und v_val aus einer Normalverteilung (Gauß-Verteilung) generiert, und der Absolutwert von v_val wird gebildet. Der Levy-Schritt „levyStep [c]“ wird anhand der Formel des Mantegna-Algorithmus berechnet: u_val / Math.pow(v_val, 1.0 / lambda). Es wird eine Überprüfung durchgeführt, um eine Division durch Null zu vermeiden (falls v_val sehr klein ist). Der Levy-Schritt ist im absoluten Wert begrenzt. Dies geschieht, um zu große Sprünge zu vermeiden.
Als Ergebnis dieser Methode wird das Array „levyStep“ erzeugt, das die Levy-Schrittwerte für jede Koordinate enthält. Diese Schritte werden dann in der Methode „GlobalExploration“ verwendet, um die Position jeder Lösung im Suchraum zu aktualisieren.
//———————————————————————————————————————————————————————————————————— // Generate Levy step using Mantegna algorithm void C_AO_ES::GenerateLevyStep () { // Calculate sigma for Mantegna algorithm double numerator = Gamma (1.0 + lambda) * MathSin (M_PI * lambda / 2.0); double denominator = Gamma ((1.0 + lambda) / 2.0) * lambda * MathPow (2.0, (lambda - 1.0) / 2.0); double sigma = MathPow (numerator / denominator, 1.0 / lambda); for (int c = 0; c < coords; c++) { // Generate u and v from normal distributions double u_val = GenerateGaussian () * sigma; double v_val = MathAbs (GenerateGaussian ()); // Calculate the Levy step if (v_val > 1e-10) { levyStep [c] = u_val / MathPow (v_val, 1.0 / lambda); } else { levyStep [c] = 0.0; } // Limit extreme values if (MathAbs (levyStep [c]) > 10.0) { levyStep [c] = 10.0 * (levyStep [c] > 0 ? 1.0 : -1.0); } } } //————————————————————————————————————————————————————————————————————
Die Methode GenerateGaussian dient zur Erzeugung von Zufallszahlen, die einer Normalverteilung (Gauß-Verteilung) mit dem Mittelwert „0“ und der Standardabweichung „1“ folgen. Es nutzt die Box-Muller-Transformation, eine für dieses Problem recht gängige Methode, die wir bereits in früheren Artikeln verwendet haben.
Es werden die statischen Variablen „hasSpare“ und „spare“ verwendet; die Box-Muller-Transformation generiert jeweils zwei unabhängige Zufallszahlen aus einer Normalverteilung. „hasSpare“ ist eine logische Variable, die bestimmt, ob einer der generierten Werte für den nächsten Funktionsaufruf zwischengespeichert wird, „spare“ ist eine Variable, die diese „Reservwert“ speichert.Neue Zufallszahlen generieren (falls erforderlich):
Wenn kein „zwischengespeicherter Wert“ vorhanden ist, werden zwei unabhängige Zufallsvariablen u_val und v_val aus einer Gleichverteilung auf dem Intervall (0, 1) generiert. Die Funktion „u.RNDfromCI“ erzeugt gleichverteilte Zahlen. Es wird die Box-Muller-Transformation angewendet:
- Die Variable „mag“ (Magnitude) wird berechnet als Quadratwurzel aus -2,0 * Math.log(u_val + 1e-10). Es ist notwendig, eine kleine Zahl zu u_val hinzuzufügen, um zu vermeiden, dass der Logarithmus von Null berechnet wird, was unzulässig ist.
- Die „Spare“-Zahl wird wie folgt berechnet: mag * Math.cos(2,0 * M_PI * v_val).
- Der zurückgegebene Wert lautet mag * Math.sin(2,0 * M_PI * v_val).
//———————————————————————————————————————————————————————————————————— // Generate a Gaussian random number using the Box-Muller transform double C_AO_ES::GenerateGaussian () { static bool hasSpare = false; static double spare; if (hasSpare) { hasSpare = false; return spare; } hasSpare = true; double u_val = u.RNDfromCI (0.0, 1.0); double v_val = u.RNDfromCI (0.0, 1.0); double mag = MathSqrt (-2.0 * MathLog (u_val + 1e-10)); spare = mag * MathCos (2.0 * M_PI * v_val); return mag * MathSin (2.0 * M_PI * v_val); } //————————————————————————————————————————————————————————————————————
Die Gamma-Methode ist eine Funktion, die die Gammafunktion für ein gegebenes Argument „z“ approximiert. Da die Gammafunktion eine wichtige mathematische Funktion ist, insbesondere in der Statistik und der Optimierung, ihre exakte Berechnung jedoch schwierig und rechenintensiv sein kann, werden häufig Näherungswerte verwendet. Wir verwenden die Lanczos-Näherung, die bei relativ geringem Rechenaufwand eine gute Genauigkeit bietet. Lassen Sie uns die wichtigsten Punkte besprechen.
Ist das Argument „z“ kleiner als „0,5“, wird die Euler-Reflexionsformel angewendet. Auf diese Weise lässt sich die Gammafunktion für Argumente nahe Null berechnen. Die Reflexionsformel setzt die Gammafunktion von „z“ in Beziehung zur Gammafunktion von „1 – z“. Wir werden feste Lanczos-Koeffizienten verwenden, die sorgfältig ausgewählt wurden, um eine hohe Näherungsgenauigkeit zu gewährleisten, sowie Koeffizienten und eine Formel, die Potenz- und Exponentialfunktionen enthalten. Die Methode gibt den Näherungswert der Gammafunktion für das angegebene Argument „z“ zurück.
Die Lanczos-Näherung bietet eine gute Genauigkeit, die für die meisten praktischen Anwendungen ausreicht. Der Algorithmus ist relativ effizient, da er nur wenige Rechenoperationen und das Nachschlagen von Koeffizienten in einer Tabelle erfordert. Sie eignet sich für eine Vielzahl von Argumentwerten, insbesondere in Verbindung mit der Reflexionsformel. Im Allgemeinen ist die Gamma-Methode eine recht genaue Methode zur Annäherung an die Gammafunktion.
//———————————————————————————————————————————————————————————————————— // Approximation of the gamma function using Lanczos approximation double C_AO_ES::Gamma (double z) { if (z < 0.5) { // Reflection formula for z < 0.5 return M_PI / (MathSin (M_PI * z) * Gamma (1.0 - z)); } // Lanczos coefficients const double g = 7.0; double coef [] = { 0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7 }; z -= 1.0; double x = coef [0]; for (int i = 1; i < 9; i++) { x += coef [i] / (z + i); } double t = z + g + 0.5; double sqrt2pi = MathSqrt (2.0 * M_PI); return sqrt2pi * MathPow (t, z + 0.5) * MathExp (-t) * x; } //————————————————————————————————————————————————————————————————————
Testergebnisse
Auch wenn der Algorithmus es nicht in unsere Rangliste geschafft hat, sind seine Ergebnisse doch bemerkenswert.=============================
5 Hilly's; Func runs: 10000; result: 0.7077570016043803
25 Hilly's; Func runs: 10000; result: 0.4307775904381953
500 Hilly's; Func runs: 10000; result: 0.2747545259235643
=============================
5 Forest's; Func runs: 10000; result: 0.7173720280531499
25 Forest's; Func runs: 10000; result: 0.3448423301485268
500 Forest's; Func runs: 10000; result: 0.1597390810339928
=============================
5 Megacity's; Func runs: 10000; result: 0.5184615384615384
25 Megacity's; Func runs: 10000; result: 0.2775384615384615
500 Megacity's; Func runs: 10000; result: 0.11063076923077016
=============================
All score: 3.54187 (39.35%)
Die Visualisierung zeigt deutlich, wie sich die Suchphasen je nach Strategie aufteilen und wann lange Sprünge und kurze Verfeinerungszüge stattfinden.

ES mit der Testfunktion Hilly

ES mit der Testfunktion Forest

ES mit der Testfunktion Megacity
Der ES-Algorithmus ist der Bewertungstabelle der Vollständigkeit halber beigefügt.
| # | 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-Lock-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 | BOAm | Billard-Optimierungsalgorithmus M | 0.95757 | 0.82599 | 0.25235 | 2.03590 | 1.00000 | 0.90036 | 0.30502 | 2.20538 | 0.73538 | 0.52523 | 0.09563 | 1.35625 | 5.598 | 62.19 |
| 9 | 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 |
| 10 | 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 |
| 11 | 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 |
| 12 | BBO | biogeografisch basierte Optimierung | 0.94912 | 0.69456 | 0.35031 | 1.99399 | 0.93820 | 0.67365 | 0.25682 | 1.86867 | 0.74615 | 0.48277 | 0.17369 | 1.40261 | 5.265 | 58.50 |
| 13 | 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 |
| 14 | 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 |
| 15 | 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 |
| 16 | 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 |
| 17 | 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 |
| 18 | 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 |
| 19 | 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 |
| 20 | 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 |
| 21 | SRA | Algorithmus für erfolgreiche Gastronomen (joo) | 0.96883 | 0.63455 | 0.29217 | 1.89555 | 0.94637 | 0.55506 | 0.19124 | 1.69267 | 0.74923 | 0.44031 | 0.12526 | 1.31480 | 4.903 | 54.48 |
| 22 | 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 |
| 23 | 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 |
| 24 | 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 |
| 25 | 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 |
| 26 | 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 |
| 27 | 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 |
| 28 | 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 |
| 29 | (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 |
| 30 | FBA | Fraktal-basierter Algorithmus | 0.79000 | 0.65134 | 0.28965 | 1.73099 | 0.87158 | 0.56823 | 0.18877 | 1.62858 | 0.61077 | 0.46062 | 0.12398 | 1.19537 | 4.555 | 50.61 |
| 31 | 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 |
| 32 | 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 |
| 33 | 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 |
| 34 | 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 |
| 35 | 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 |
| 36 | CAm | Kamel-Algorithmus M | 0.78684 | 0.56042 | 0.35133 | 1.69859 | 0.82772 | 0.56041 | 0.24336 | 1.63149 | 0.64846 | 0.33092 | 0.13418 | 1.11356 | 4.444 | 49.37 |
| 37 | 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 |
| 38 | 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 |
| 39 | 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 |
| 40 | 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 |
| 41 | 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 |
| 42 | 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 |
| 43 | CGO | Chaos Game Optimierung | 0.57256 | 0.37158 | 0.32018 | 1.26432 | 0.61176 | 0.61931 | 0.62161 | 1.85267 | 0.37538 | 0.21923 | 0.19028 | 0.78490 | 3.902 | 43.35 |
| 44 | CROm | Korallenriff-Optimierung M | 0.78512 | 0.46032 | 0.25958 | 1.50502 | 0.86688 | 0.35297 | 0.16267 | 1.38252 | 0.63231 | 0.26738 | 0.10734 | 1.00703 | 3.895 | 43.27 |
| 45 | 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 |
| ES | eagle_strategy_optimization | 0.70776 | 0.43078 | 0.27475 | 1.41328 | 0.71737 | 0.34484 | 0.15973 | 1.22194 | 0.51846 | 0.27754 | 0.11063 | 0.90663 | 3.542 | 39.35 | |
| RW | Neuroboids Optimierungsalgorithmus 2(joo) | 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
Der ES-Algorithmus schnitt im Benchmark zur Populationsoptimierung durchschnittlich ab und erreichte 39 % der maximal möglichen Punkte, wodurch er nicht unter die 45 besten Algorithmen kam.
Dennoch ist der Algorithmus aufgrund seines originellen zweistufigen Suchkonzepts, das auf einem biologisch inspirierten Modell des Jagdverhaltens von Adlern basiert, eine Überlegung wert. Die Verwendung von Levy-Flügen für die globale Erkundung ist eine mathematisch elegante Lösung, die sich theoretisch als optimal für Probleme der zufälligen Suche erwiesen hat. Adaptive Umsetzungsmechanismen, darunter der dynamische Wechsel zwischen den Phasen und die automatische Parameteranpassung während der Stagnationsphase, bieten Potenzial zur Verbesserung des Grundkonzepts.
Der Algorithmus könnte sich in bestimmten Problemklassen bewähren, in denen ein Gleichgewicht zwischen globaler Suche und lokaler Ausnutzung wichtig ist, insbesondere bei Vorhandensein mehrerer lokaler Optima und verrauschter Daten. Die Einbindung des Firefly-Algorithmus in die lokale Suche schafft eine interessante Synergie zwischen zwei von der Natur inspirierten Methoden, auch wenn die Gesamtleistung darauf hindeutet, dass eine weitere Parameteroptimierung und möglicherweise eine Anpassung der zugrunde liegenden Mechanismen erforderlich sind.
Der ES-Algorithmus kann als anschauliches Beispiel für einen hybriden Optimierungsansatz und als Grundlage für die Entwicklung fortgeschrittenerer Methoden angesehen werden, die verschiedene Metaheuristiken kombinieren. Dank seiner relativ einfachen Umsetzung und seiner intuitiven Logik eignet sich der Algorithmus für Forschungsexperimente im Bereich der evolutionären Optimierung.

Abbildung 2. Farbskala der Algorithmen nach den entsprechenden Tests

Abbildung 3. Histogramm der Algorithmus-Testergebnisse (Skala von 0 bis 100, je höher, desto besser, wobei 100 das maximal mögliche theoretische Ergebnis ist; im Archiv befindet sich ein Skript zur Berechnung der Bewertungstabelle)
Vor- und Nachteile von ES:
Vorteile:
- Schnell.
Nachteile:
- Eine Vielzahl von Parametern.
Dem Artikel ist ein Archiv mit den aktuellen Versionen der Algorithmuscodes beigefügt. 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 Experimente.
Im Artikel verwendete Programme
| # | Name | Typ | Beschreibung |
|---|---|---|---|
| 1 | #C_AO.mqh | Include | Übergeordnete Klasse von Populationsoptimierungsalgorithmen |
| 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 die Testumgebung |
| 5 | Utilities.mqh | Include | Bibliothek mit Hilfsfunktionen |
| 6 | CalculationTestResults.mqh | Include | Skript zur Berechnung der Ergebnisse in der Vergleichstabelle |
| 7 | Testing AOs.mq5 | Skript | Die einheitliche Testumgebung 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_ES.mq5 | Skript | ES-Testumgebung |
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/18460
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Entwicklung eines Toolkits für die Price-Action-Analyse (Teil 29): Boom and Crash Interceptor EA
Marktsimulation (Teil 24): Erste Schritte mit SQL (VII)
IWF-Daten mit Python herunterladen
Analyse der Bilanzdaten von Zentralbanken zur Einschätzung der globalen Liquidität
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.