Neuroboids Optimierungsalgorithmus 2 (NOA2)
Inhalt
Einführung
Als ich mich im Laufe der Jahre eingehender mit Optimierungsalgorithmen beschäftigte, wurde ich oft von zwei parallelen Inspirationen angezogen: der Selbstorganisation biologischer Schwärme und den adaptiven Lernfähigkeiten neuronaler Netze. Die Synthese dieser beiden Paradigmen führte mich zur Entwicklung eines hybriden Algorithmus, der die räumliche Intelligenz der Boids von Craig Reynolds mit den adaptiven Lernfähigkeiten neuronaler Netze kombiniert.
Meine Reise begann mit der Beobachtung, dass herkömmliche Schwarmalgorithmen zwar für die Erkundung komplexer Suchräume durch kollektives Verhalten geeignet sind, aber oft nicht in der Lage sind, aus der Geschichte ihrer Erkundungen zu lernen. Umgekehrt sind neuronale Netze hervorragend in der Lage, komplexe Muster zu lernen, haben aber Schwierigkeiten, räumliche Muster effektiv zu untersuchen, wenn sie direkt auf Optimierungsprobleme angewandt werden. Die Frage, die meine Forschung motivierte, war trügerisch einfach: Was wäre, wenn jeder Agent in einem Schwarm lernen könnte, seine Bewegungsstrategien mithilfe eines speziellen neuronalen Netzwerks zu verbessern?
Der daraus resultierende Algorithmus verwendet Agenten, die den klassischen Boid-Regeln der Kohäsion, Separation und Ausrichtung folgen, was es ihnen ermöglicht, sich selbst zu organisieren und den Suchraum effizient zu erkunden. Im Gegensatz zu herkömmlichen Boid-Implementierungen ist jeder Agent jedoch mit einem mehrschichtigen neuronalen Netz ausgestattet, das kontinuierlich aus den Erfahrungen des Agenten lernt und seine Bewegungsstrategien an die spezifischen Merkmale der Fitnesslandschaft anpasst. Dieses Maß an neuronaler Kontrolle beeinflusst allmählich das Verhalten der Boids und geht von Strategien, die in den ersten Iterationen die Erkundung dominieren, zu einer auf Ausbeutung ausgerichteten Bewegung über, wenn vielversprechende Regionen identifiziert werden.
Was mich während der Entwicklung am meisten faszinierte, war die Beobachtung, wie neuronale Netze je nach ihrer Position im Suchraum unterschiedliche Strategien entwickelten. Agenten in der Nähe vielversprechender Regionen entwickelten neuronale Muster, die die lokale Ausbeutung förderten, während Agenten in dünn besiedelten Regionen exploratives Verhalten unterstützten. Diese Spezialisierung entstand auf natürliche Weise durch individuelle Lernprozesse und führte zu einem Schwarm mit heterogenem, kontextabhängigem Verhalten ohne erkennbare globale Koordination.
In diesem Artikel werde ich die Architektur, die Implementierungsdetails und die Leistungsanalyse des NOA2-Algorithmus vorstellen und seine Fähigkeiten anhand verschiedener Benchmark-Funktionen demonstrieren.
Implementierung des Algorithmus
Wie bereits erwähnt, besteht die Hauptidee des Neuroboids-Algorithmus darin, zwei Paradigmen zu kombinieren: die kollektive Intelligenz von Schwarmalgorithmen und das adaptive Lernen von neuronalen Netzen.
Beim traditionellen Boids-Algorithmus, der von Craig Reynolds vorgeschlagen wurde, folgen die Agenten drei einfachen Regeln: Konvergenz (Bewegung zum Zentrum der Gruppe), Trennung (Vermeidung von Kollisionen) und Ausrichtung (Anpassung der Geschwindigkeit an die Nachbarn). Diese Regeln schaffen ein realistisches Gruppenverhalten, ähnlich dem Verhalten von Vögeln in Schwärmen. Neuroboids erweitern dieses Konzept, indem sie jeden Agenten mit einem individuellen neuronalen Netz ausstatten, das aus den Erfahrungen des Agenten bei der Erkundung des Suchraums lernt. Dieses neuronale Netz erfüllt zwei wichtige Funktionen:
- Die adaptive Bewegungssteuerung passt die Geschwindigkeit des Agenten auf der Grundlage seines aktuellen Zustands und seiner Bewegungshistorie an.
- Durch die Modifizierung der Standardregeln für Boids wird der Einfluss der Konvergenz-, Trennungs- und Ausrichtungsregeln dynamisch und kontextabhängig angepasst.
Das Ergebnis ist ein hybrider Algorithmus, bei dem jeder Agent das soziale Verhalten beibehält, das für eine effiziente Erkundung des Raums erforderlich ist, sich aber gleichzeitig durch Lernen individuell an die Landschaft der Fitnessfunktionen anpasst. Dadurch entsteht ein selbstregulierendes Gleichgewicht zwischen Erkundung und Ausbeutung.
Die Hauptvorteile dieses Ansatzes sind das unabhängige Lernen der Agenten in optimalen Bewegungsstrategien, wodurch sich der Algorithmus automatisch an verschiedene Arten von Optimierungslandschaften anpasst, während die Erkundung des Raums dank des kollektiven Verhaltens ohne zentrale Steuerung erhalten bleibt. Ich möchte Ihnen eine einfache Analogie geben: Stellen Sie sich einen Vogelschwarm vor, der am Himmel fliegt. Sie bewegen sich koordiniert: Keiner stößt zusammen, sie bleiben zusammen und fliegen in dieselbe Richtung. Dieses Verhalten lässt sich durch drei einfache Regeln beschreiben: Bleiben Sie in der Nähe Ihrer Nachbarn (entfernen Sie sich nicht vom Schwarm), kollidieren Sie nicht mit Ihren Nachbarn (halten Sie Abstand) und fliegen Sie in die gleiche Richtung (halten Sie den gemeinsamen Kurs).
Dies ist die Grundlage des so genannten Boid-Algorithmus „Bird-oid“. Jeder Vogel im Schwarm befolgt nicht nur diese Regeln, sondern lernt auch aus seinen eigenen Erfahrungen. Der Vogel merkt sich, welche Handlungen zum Erfolg führten (z. B. mehr Futter zu finden) und welche nicht. Mit der Zeit wird der Vogel schlauer und trifft bessere Entscheidungen, wie er fliegen soll. Das ist die Essenz des Neuroboids-Algorithmus: die Kombination einfacher Regeln der Gruppenbewegung mit der Fähigkeit jedes Teilnehmers, aus seinen eigenen Erfahrungen zu lernen. Das „neuro“ im Namen weist auf die Fähigkeit zum Lernen hin. Dieser Ansatz ist besonders interessant, weil er die Stärke der kollektiven Forschung (niemand verpasst einen wichtigen Bereich) mit den Vorteilen des individuellen Lernens (jeder wird der Beste in seinem Forschungsgebiet) verbindet.

Abbildung 1. Betrieb des NOA2-Algorithmus
Die Abbildung zeigt die folgenden Schlüsselelemente: die Optimierungslandschaft, wobei der gelb-violette Bereich das globale Optimum darstellt, die orangefarbenen und violetten Bereiche die lokalen Optima, und die Konturlinien zeigen die „Höhe“ der Fitnessfunktionslandschaft.
Verschiedene Gruppen von Agenten: die blauen erkunden den Bereich des globalen Optimums, die violetten konzentrieren sich um das erste lokale Optimum, die grünen erkunden das zweite lokale Optimum und die roten erkunden den Raum nach dem Zufallsprinzip. Die Pfeile zeigen die Bewegungsrichtung der Boids. Der rote Punkt markiert die aktuell beste gefundene Lösung.

Abbildung 2. Betrieb des NOA2-Algorithmus
Das Diagramm umfasst: Initialisierungsblock (rot), neuronales Netz (rosa), Algorithmusiterationen mit Unterblöcken (blau), adaptive Mechanismen (grün), Visualisierung der Architektur des neuronalen Netzes mit Verbindungsbeispielen. Der untere Teil zeigt Miniaturdiagramme der Struktur des neuronalen Netzes, die Visualisierung der Regeln für die Bewegung der Boids und das Gleichgewicht zwischen Erkundung und Ausbeutung.
Nachdem wir das Grundkonzept verstanden haben, können wir mit der Beschreibung des Pseudocodes des Algorithmus fortfahren.
INITIALISIERUNG:
- Lege Suchparameter fest und erstelle eine Population von Agenten.
- Für jeden Agenten: Initialisiere eine zufällige Position, eine niedrige Geschwindigkeit, ein neuronales Netzes (Eingabe → ausgeblendet → Ausgabeschichten) und einen leeren Erfahrungsspeicher.
- Setze die global beste Fitness auf negativ Unendlich und den Stagnationszähler auf Null.
HAUPTSCHLEIFE:
-
Für jede Iteration:
SCHÄTZUNG:
- Berechne die Fitness für alle Agenten.
- Aktualisiere deren persönliche und die global beste Positionen.
- Speicher die Experimente in Speicherpuffern.
STAGNATIONSMANAGEMENT:
- Wenn keine Besserung eintritt: Forschung verstärken, schwache Mittel von Zeit zu Zeit neu starten.
- Andernfalls: schrittweise Reduzierung des Forschungsniveaus.
NEURONALE VERARBEITUNG:
- Für jeden Agenten:
- Vorwärtsdurchlauf: Eingaben (Position, Geschwindigkeit, Abstand zum Besten, Fitness) → versteckte Schichten → Ausgaben.
- Wenn genügend Erfahrungen gesammelt wurden und eine Verbesserung festgestellt wurde: Aktualisierung der neuronalen Gewichte.
AKTUALISIERUNG DER BEWEGUNG:
- Für jeden Agenten:
- Berechne die Standard-Boid-Kräfte (Kohäsion, Trennung, Ausrichtung).
- Wende neuronal modifizierter Kräfte und direkte neuronale Korrekturen an.
- Füge eine Zufallskomponente mit Wahrscheinlichkeit hinzu.
- Halte die Geschwindigkeitsbegrenzungen ein und respektiere die Grenzen.
- Aktualisiere die Position anhand der Endgeschwindigkeit.
UNTERSTÜTZENDE BERECHNUNGEN:
- Berechnung der Masse: Die Fitnesswerte werden normalisiert, um jedem Agenten eine Masse zuzuweisen.
- Zusammenhalt: Bewegen in Richtung des gewichteten Massenschwerpunkts der benachbarten Agenten.
- Trennung: Vermeide das Zusammenballen mit Nachbarn.
- Ausrichtung: Koordiniere die Geschwindigkeit mit den Agenten in der Nähe.
- Neuronale Aktualisierung: vereinfachtes Backpropagation auf der Grundlage von Fitnessverbesserung.
RÜCKGABE: der global besten Position und Fitness.
Jetzt ist alles bereit für das Schreiben des Algorithmuscodes. Wir weisen der Struktur S_NeuroBoids_Agent zu, die einen auf der Architektur eines neuronalen Netzes basierenden Neuro-Boid-Agenten zur Durchführung von Optimierungsaufgaben darstellt. In dieser Implementierung hat der Agent die folgenden Hauptkomponenten und Funktionen:
Koordinaten und Geschwindigkeiten:
- x [] – aktuelle Koordinaten des Agenten.
- dx [] – aktuelle Geschwindigkeiten des Agenten.
- inputs [] – Eingabewerte für die Neuronen (Koordinaten, Geschwindigkeiten, Abstand zur besten bekannten Position usw.).
- outputs [] – Ausgangswerte des neuronalen Netzes (Geschwindigkeitskorrektur und Anpassungsparameter).
- weights [] – Gewichte der Verbindungen im neuronalen Netz.
- biases [] – Verzerrung der Neuronen.
- memory [] – Array zum Speichern früherer Positionen und ihrer Fitnesswerte.
- memory_size – maximale Größe des Speichers für die Speicherung.
- memory_index – aktueller Index im Speicher.
- best_local_fitness – bester lokaler Fitness-Agent.
- m – Masse des Agenten.
- cB [] – Koordinaten der besten vom Agenten gefundenen Position.
- fB – Wert der Fitnessfunktion für die beste Position.
Initialisierung (Init) – alle Arrays und Variablen werden mit Nullen oder Zufallswerten initialisiert. Die Array-Größen werden festgelegt, und die Einflüsse (Gewichte und Verzerrungen) werden mit kleinen Zufallswerten initialisiert.
Aktivierungsfunktionen – Tanh, ReLU, Sigmoid: verschiedene Aktivierungsfunktionen, die in neuronalen Netzen verwendet werden.
Eingabedaten aktualisieren (UpdateInputs) füllt das Eingabefeld mit den aktuellen Koordinaten, Geschwindigkeiten, der Entfernung zur besten bekannten Position und dem aktuellen Fitnesswert.
ForwardPass (Vorwärtsdurchlauf) berechnet die Ausgaben eines neuronalen Netzes auf der Grundlage von Eingaben, Gewichten und Verzerrungen unter Verwendung von Aktivierungsfunktionen.
Erfahrungslernen (Learn) aktualisiert die Gewichte und Vorurteile auf der Grundlage der gesammelten Erfahrung, wenn die aktuelle Erfahrung besser ist als die vorherige.
Das Speichern von Erfahrungen (MemorizeExperience) speichert die aktuellen Koordinaten und die Fitness des Agenten im Speicher.
Aktualisierung der besten Position (UpdateBestPosition) – aktualisiert die beste Position, wenn der aktuelle Fitnesswert besser ist als der zuvor gefundene.
//—————————————————————————————————————————————————————————————————————————————— // Neuro-boid agent structure //—————————————————————————————————————————————————————————————————————————————— struct S_NeuroBoids_Agent { double x []; // current coordinates double dx []; // current speeds double inputs []; // neuron inputs double outputs []; // neuron outputs double weights []; // neuron weights double biases []; // neuron biases double memory []; // memory of previous positions and their fitnesses int memory_size; // memory size for accumulating experience int memory_index; // current index in memory double best_local_fitness; // best local agent fitness double m; // boid mass double cB []; // best position coordinates double fB; // fitness function value // Agent initialization void Init (int coords, int neuron_size) { ArrayResize (x, coords); ArrayResize (dx, coords); ArrayInitialize (x, 0.0); ArrayInitialize (dx, 0.0); // Initialize the best position structure ArrayResize (cB, coords); ArrayInitialize (cB, 0.0); fB = -DBL_MAX; // Inputs: coordinates, speeds, distance to best, etc. int input_size = coords * 2 + 2; // x, dx, dist_to_best, current_fitness ArrayResize (inputs, input_size); ArrayInitialize (inputs, 0.0); // Outputs: Speed correction and adaptive factors for flock rules int output_size = coords + 3; // dx_correction + 3 adaptive parameters ArrayResize (outputs, output_size); ArrayInitialize (outputs, 0.0); // Weights and biases for each output ArrayResize (weights, input_size * output_size); ArrayInitialize (weights, 0.0); ArrayResize (biases, output_size); ArrayInitialize (biases, 0.0); // Initialize weights and biases with small random values for (int i = 0; i < ArraySize (weights); i++) { weights [i] = 0.01 * (MathRand () / 32767.0 * 2.0 - 1.0); } for (int i = 0; i < ArraySize (biases); i++) { biases [i] = 0.01 * (MathRand () / 32767.0 * 2.0 - 1.0); } // Initialize memory for accumulating experience memory_size = 10; ArrayResize (memory, memory_size * (coords + 1)); // coordinates + fitness ArrayInitialize (memory, 0.0); memory_index = 0; best_local_fitness = -DBL_MAX; // Initialize mass m = 0.5; } // Activation function - hyperbolic tangent double Tanh (double input_val) { return MathTanh (input_val); } // ReLU activation function double ReLU (double input_val) { return (input_val > 0.0) ? input_val : 0.0; } // Sigmoid activation function double Sigmoid (double input_val) { return 1.0 / (1.0 + MathExp (-input_val)); } // Updating neural network inputs - Corrected version void UpdateInputs (double &global_best [], double current_fitness, int coords_count) { int input_index = 0; // Coordinates for (int c = 0; c < coords_count; c++) { inputs [input_index++] = x [c]; } // Speeds for (int c = 0; c < coords_count; c++) { inputs [input_index++] = dx [c]; } // Distance to the best global solution double dist_to_best = 0; for (int c = 0; c < coords_count; c++) { dist_to_best += MathPow (x [c] - global_best [c], 2); } dist_to_best = MathSqrt (dist_to_best); inputs [input_index++] = dist_to_best; // Current fitness function inputs [input_index++] = current_fitness; } // Direct distribution over the network void ForwardPass (int coords_count) { int input_size = ArraySize (inputs); int output_size = ArraySize (outputs); // For each output, calculate the weighted sum of the inputs + bias for (int o = 0; o < output_size; o++) { double sum = biases [o]; for (int i = 0; i < input_size; i++) { sum += inputs [i] * weights [o * input_size + i]; } // Apply different activation functions depending on the output if (o < coords_count) // Use the hyperbolic tangent to correct the speed { outputs [o] = Tanh (sum); } else // Use sigmoid for adaptive parameters { outputs [o] = Sigmoid (sum); } } } // Learning from accumulated experience void Learn (double learning_rate, int coords_count) { if (memory_index < memory_size) return; // Insufficient experience // Find the best experience in memory int best_index = 0; double best_fitness = memory [coords_count]; // The first fitness function in memory for (int i = 1; i < memory_size; i++) { double fitness = memory [i * (coords_count + 1) + coords_count]; if (fitness > best_fitness) { best_fitness = fitness; best_index = i; } } // If the current experience is not better than the previous one, do not update the weights if (best_fitness <= best_local_fitness) return; best_local_fitness = best_fitness; // Simple method for updating weights int input_size = ArraySize (inputs); int output_size = ArraySize (outputs); // Simple form of gradient update for (int o = 0; o < output_size; o++) { for (int i = 0; i < input_size; i++) { int weight_index = o * input_size + i; if (weight_index < ArraySize (weights)) { weights [weight_index] += learning_rate * outputs [o] * inputs [i]; } } // Update offsets biases [o] += learning_rate * outputs [o]; } } // Save current experience (coordinates and fitness) void MemorizeExperience (double fitness, int coords_count) { int offset = memory_index * (coords_count + 1); // Save the coordinates for (int c = 0; c < coords_count; c++) { memory [offset + c] = x [c]; } // Save the fitness function memory [offset + coords_count] = fitness; // Update the memory index memory_index = (memory_index + 1) % memory_size; } // Update the agent's best position void UpdateBestPosition (double current_fitness, int coords_count) { if (current_fitness > fB) { fB = current_fitness; ArrayCopy (cB, x, 0, 0, WHOLE_ARRAY); } } };
Die Klasse C_AO_NOA2 ist eine Implementierung des NOA2-Algorithmus und wird von der Basisklasse C_AO abgeleitet. Schauen wir uns die Struktur und die wichtigsten Aspekte des Kurses genauer an.
Wichtigste Parameter:- popSize – Anzahl der Agenten (boid).
- cohesionWeight, cohesionDist – Gewicht und Abstand für die Kohäsionsregel.
- separationWeight, separationDist – Gewicht und Abstand für die Trennungsregel.
- alignmentWeight, alignmentDist – Gewicht und Abstand für die Ausrichtungsregel.
- maxSpeed und minSpeed – maximale und minimale Geschwindigkeit der Agenten.
- learningRate – Lernrate für das neuronale Netz.
- neuralInfluence – Einfluss eines neuronalen Netzes auf die Bewegung von Agenten.
- explorationRate – Wahrscheinlichkeit der zufälligen Erkundung des Lösungsraums.
- m_stagnationCounter und m_prevBestFitness – Stagnationszähler und der vorherige beste Fitnesswert.
- SetParams () – Methode, die die Algorithmusparameter auf der Grundlage der im Array „params“ gespeicherten Werte festlegt.
- Init () – Initialisierung, übernimmt Parameter zur Festlegung von Wertebereichen für Agenten. Die Methode legt die Anfangsbedingungen für die Arbeit des Algorithmus fest.
- Moving () – zuständig für die Bewegung von Agenten auf der Grundlage verschiedener Interaktionsregeln.
- Revision () – wird verwendet, um den Zustand der Agenten während der Ausführung des Algorithmus zu revidieren.
Agenten: S_NeuroBoids_Agent agent [] – Array von Agenten, die Boids in der Population repräsentieren.
Private Methoden (zur Verwendung innerhalb der Klasse):
- CalculateMass () – Masse der Agenten.
- Kohäsion () – Kohäsionsregel.
- Trennung () – Trennungsregel.
- Alignment () – Ausrichtungsregel.
- LimitSpeed () – begrenzt die Geschwindigkeit des Agenten.
- KeepWithinBounds () – hält Agenten innerhalb der angegebenen Grenzen.
- Entfernung () – berechnet die Entfernung zwischen zwei Agenten.
- ApplyNeuralControl () – wendet die Steuerung des neuronalen Netzes auf den Agenten an.
- AdaptiveExploration() – implementiert die adaptive Erkundung.
//—————————————————————————————————————————————————————————————————————————————— // Class of neuron-like optimization algorithm inherited from C_AO //—————————————————————————————————————————————————————————————————————————————— class C_AO_NOA2 : public C_AO { public: //-------------------------------------------------------------------- ~C_AO_NOA2 () { } C_AO_NOA2 () { ao_name = "NOA2"; ao_desc = "Neuroboids Optimization Algorithm 2 (joo)"; ao_link = "https://www.mql5.com/en/articles/17497"; popSize = 50; // population size cohesionWeight = 0.6; // cohesion weight cohesionDist = 0.001; // cohesion distance separationWeight = 0.005; // separation weight separationDist = 0.03; // separation distance alignmentWeight = 0.1; // alignment weight alignmentDist = 0.1; // alignment distance maxSpeed = 0.001; // maximum speed minSpeed = 0.0001; // minimum speed learningRate = 0.01; // neural network learning speed neuralInfluence = 0.3; // influence of the neural network on movement explorationRate = 0.1; // random exploration probability ArrayResize (params, 12); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "cohesionWeight"; params [1].val = cohesionWeight; params [2].name = "cohesionDist"; params [2].val = cohesionDist; params [3].name = "separationWeight"; params [3].val = separationWeight; params [4].name = "separationDist"; params [4].val = separationDist; params [5].name = "alignmentWeight"; params [5].val = alignmentWeight; params [6].name = "alignmentDist"; params [6].val = alignmentDist; params [7].name = "maxSpeed"; params [7].val = maxSpeed; params [8].name = "minSpeed"; params [8].val = minSpeed; params [9].name = "learningRate"; params [9].val = learningRate; params [10].name = "neuralInfluence"; params [10].val = neuralInfluence; params [11].name = "explorationRate"; params [11].val = explorationRate; // Initialize the stagnation counter and the previous best fitness value m_stagnationCounter = 0; m_prevBestFitness = -DBL_MAX; } void SetParams () { popSize = (int)params [0].val; cohesionWeight = params [1].val; cohesionDist = params [2].val; separationWeight = params [3].val; separationDist = params [4].val; alignmentWeight = params [5].val; alignmentDist = params [6].val; maxSpeed = params [7].val; minSpeed = params [8].val; learningRate = params [9].val; neuralInfluence = params [10].val; explorationRate = params [11].val; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving (); void Revision (); //---------------------------------------------------------------------------- double cohesionWeight; // cohesion weight double cohesionDist; // cohesion distance double separationWeight; // separation weight double separationDist; // separation distance double alignmentWeight; // alignment weight double alignmentDist; // alignment distance double minSpeed; // minimum speed double maxSpeed; // maximum speed double learningRate; // neural network learning speed double neuralInfluence; // influence of the neural network on movement double explorationRate; // random exploration probability int m_stagnationCounter; // stagnation counter double m_prevBestFitness; // previous best fitness value S_NeuroBoids_Agent agent []; // agents (boids) private: //------------------------------------------------------------------- double distanceMax; // maximum distance double speedMax []; // maximum speeds by measurements int neuron_size; // neuron size (number of inputs) void CalculateMass (); // calculation of agent masses void Cohesion (S_NeuroBoids_Agent &boid, int pos); // cohesion rule void Separation (S_NeuroBoids_Agent &boid, int pos); // separation rule void Alignment (S_NeuroBoids_Agent &boid, int pos); // alignment rule void LimitSpeed (S_NeuroBoids_Agent &boid); // speed limit void KeepWithinBounds (S_NeuroBoids_Agent &boid); // keep within bounds double Distance (S_NeuroBoids_Agent &boid1, S_NeuroBoids_Agent &boid2); // calculate distance void ApplyNeuralControl (S_NeuroBoids_Agent &boid, int pos); // apply neural control void AdaptiveExploration (); // adaptive research }; //——————————————————————————————————————————————————————————————————————————————
Die Init-Methode ist für die Initialisierung der Parameter des Algorithmus und der Agenten zuständig und beginnt ihre Arbeit, indem sie StandardInit aufruft und ihr Arrays mit den Minimal- und Maximalwerten des Bereichs und der Suchschritte übergibt. Wenn die Standardinitialisierung fehlschlägt, gibt die Methode sofort „false“ zurück. Die Größe des Neurons, das im neuronalen Netz des Agenten verwendet werden soll, wird festgelegt.
In diesem Fall wird die Größe als die Anzahl der Koordinaten multipliziert mit 2 berechnet, und zwei zusätzliche Werte – dist_to_best und current_fitness – werden hinzugefügt. Die Größe des Agentenarrays wird entsprechend der angegebenen popSize geändert. Dann wird für jeden Agenten die Init-Methode aufgerufen, die seine Parameter, einschließlich des neuronalen Netzes, initialisiert.
Berechnen der maximalen Entfernung und Geschwindigkeit:
- Die Variable distanceMax wird auf Null initialisiert.
- Für jede Koordinate wird der maximale Geschwindigkeitswert auf der Grundlage der Differenz zwischen dem maximalen und dem minimalen Bereichswert berechnet.
- Die maximale Entfernung wird auch als Quadratwurzel aus der Summe der Quadrate der Höchstgeschwindigkeiten berechnet.
Der Stagnationszähler (m_stagnationCounter) wird auf Null zurückgesetzt, und die Variable, die den vorherigen besten Fitnesswert (m_prevBestFitness) speichert, wird auf den kleinstmöglichen Wert gesetzt. Die Methode legt verschiedene globale Variablen fest, wie Kohärenz, Trennungs- und Ausrichtungsgewichte, Höchst- und Mindestgeschwindigkeiten, Lernrate, Einfluss des neuronalen Netzes und Erkundungswahrscheinlichkeit. Wenn alle Schritte erfolgreich waren, gibt die Methode „true“ zurück, was die erfolgreiche Initialisierung bestätigt.
//—————————————————————————————————————————————————————————————————————————————— bool C_AO_NOA2::Init (const double &rangeMinP [], // minimum search range const double &rangeMaxP [], // maximum search range const double &rangeStepP [], // search step const int epochsP) // number of epochs { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //---------------------------------------------------------------------------- // Determine the size of a neuron neuron_size = coords * 2 + 2; // x, dx, dist_to_best, current_fitness // Initialize the agents ArrayResize (agent, popSize); for (int i = 0; i < popSize; i++) { agent [i].Init (coords, neuron_size); } distanceMax = 0; ArrayResize (speedMax, coords); for (int c = 0; c < coords; c++) { speedMax [c] = rangeMax [c] - rangeMin [c]; distanceMax += MathPow (speedMax [c], 2); } distanceMax = MathSqrt (distanceMax); // Reset the stagnation counter and the previous best fitness value m_stagnationCounter = 0; m_prevBestFitness = -DBL_MAX; GlobalVariableSet ("#reset", 1.0); GlobalVariableSet ("1cohesionWeight", params [1].val); GlobalVariableSet ("2cohesionDist", params [2].val); GlobalVariableSet ("3separationWeight", params [3].val); GlobalVariableSet ("4separationDist", params [4].val); GlobalVariableSet ("5alignmentWeight", params [5].val); GlobalVariableSet ("6alignmentDist", params [6].val); GlobalVariableSet ("7maxSpeed", params [7].val); GlobalVariableSet ("8minSpeed", params [8].val); GlobalVariableSet ("9learningRate", params [9].val); GlobalVariableSet ("10neuralInfluence", params [10].val); GlobalVariableSet ("11explorationRate", params [11].val); return true; } //——————————————————————————————————————————————————————————————————————————————
Die Methode Moving ist verantwortlich für die Bewegung der Agenten in der Umgebung auf der Grundlage der empfangenen Daten und der Interaktion zwischen ihnen. Zunächst prüft die Methode den Wert der globalen Variable #reset. Ist sie gleich 1,0, werden die Parameter zurückgesetzt (die Variable „revision“ wird auf „false“ gesetzt und kehrt dann zu 0,0 zurück). Die Werte verschiedener Parameter wie die Kohäsions-, Trennungs- und Ausrichtungsgewichte, die minimalen und maximalen Geschwindigkeiten, die Lernrate, der Einfluss des neuronalen Netzes und das Explorationsverhältnis werden aus den globalen Variablen extrahiert. Diese Parameter können konfiguriert werden, um das Verhalten der Agenten zu ändern.
Wenn die Variable „revision“ „false“ ist, werden die x-Positionen und dx-Geschwindigkeiten der Agenten initialisiert. Für jede Koordinate werden Zufallswerte aus einem bestimmten Bereich verwendet, und die Geschwindigkeiten werden auf kleine Zufallswerte gesetzt. Jede Koordinate speichert auch den Zustand des Agenten auf der Grundlage seiner aktuellen Position. Die Methode AdaptiveExploration () wird für die adaptive Exploration aufgerufen, die das Verhalten der Agenten in Abhängigkeit vom Stagnationszustand ändern kann.
In der Hauptschleife der Agentenbewegung (für jeden):
- Speicher die aktuelle Erfahrung des Agenten.
- Aktualisiere die beste Position, die der Agent gefunden hat.
- Aktualisiere die Eingabedaten des neuronalen Netzes des Agenten.
- Gib die Daten direkt weiter durch das neuronale Netz.
- Trainiere die Agenten auf der Grundlage ihrer gesammelten Erfahrungen.
Anwendung von Regeln und Bewegung: Die Schleife durch die Agenten beginnt erneut, und die Standardregeln des Boid-Algorithmus werden auf jeden Agenten angewendet:
- Kohäsion: Die Akteure streben danach, sich einander anzunähern.
- Trennung: Agenten vermeiden zu große Nähe zueinander, um Kollisionen zu vermeiden.
- Ausrichtung: Die Agenten versuchen, sich in dieselbe Richtung wie ihre Nachbarn zu bewegen.
//—————————————————————————————————————————————————————————————————————————————— void C_AO_NOA2::Moving () { double reset = GlobalVariableGet ("#reset"); if (reset == 1.0) { revision = false; GlobalVariableSet ("#reset", 0.0); } // Get parameters from global variables for interactive configuration cohesionWeight = GlobalVariableGet ("1cohesionWeight"); cohesionDist = GlobalVariableGet ("2cohesionDist"); separationWeight = GlobalVariableGet ("3separationWeight"); separationDist = GlobalVariableGet ("4separationDist"); alignmentWeight = GlobalVariableGet ("5alignmentWeight"); alignmentDist = GlobalVariableGet ("6alignmentDist"); maxSpeed = GlobalVariableGet ("7maxSpeed"); minSpeed = GlobalVariableGet ("8minSpeed"); learningRate = GlobalVariableGet ("9learningRate"); neuralInfluence = GlobalVariableGet ("10neuralInfluence"); explorationRate = GlobalVariableGet ("11explorationRate"); // Initialization of initial positions and speeds if (!revision) { for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { agent [i].x [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); agent [i].dx [c] = (rangeMax [c] - rangeMin [c]) * u.RNDfromCI (-1.0, 1.0) * 0.001; a [i].c [c] = u.SeInDiSp (agent [i].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } revision = true; return; } // Adaptive research depending on stagnation AdaptiveExploration (); //---------------------------------------------------------------------------- // Main loop of boid movement for (int i = 0; i < popSize; i++) { // Save the current experience agent [i].MemorizeExperience (a [i].f, coords); // Update the agent's best position agent [i].UpdateBestPosition (a [i].f, coords); // Update the neural network inputs agent [i].UpdateInputs (cB, a [i].f, coords); // Forward propagation through the neural network agent [i].ForwardPass (coords); // Learning from accumulated experience agent [i].Learn (learningRate, coords); } // Calculate masses CalculateMass (); // Application of rules and movement for (int i = 0; i < popSize; i++) { // Standard rules of the boid algorithm Cohesion (agent [i], i); Separation (agent [i], i); Alignment (agent [i], i); // Apply neural control ApplyNeuralControl (agent [i], i); // Speed limit and keeping within bounds LimitSpeed (agent [i]); KeepWithinBounds (agent [i]); // Update positions for (int c = 0; c < coords; c++) { agent [i].x [c] += agent [i].dx [c]; a [i].c [c] = u.SeInDiSp (agent [i].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } //——————————————————————————————————————————————————————————————————————————————
Die Methode CalculateMass berechnet die „Masse“ der Agenten auf der Grundlage ihrer Fitness (Produktivität) und normalisiert diese Werte. Die Variablen maxMass und minMass werden mit -DBL_MAX bzw. DBL_MAX initialisiert. Diese Variablen werden verwendet, um die höchsten und niedrigsten Fitnesswerte in der gesamten Agentenpopulation zu ermitteln. Die Methode prüft, ob es mindestens einen Agenten gibt, indem sie überprüft, ob „popSize“ (Populationsgröße) größer als Null ist. Wenn es keine Bearbeiter gibt, wird die Methode abgebrochen. In der ersten Schleife werden alle Agenten durchlaufen (von 0 bis popSize), und für jeden einzelnen wird geprüft, ob seine Fitness (der Wert von a[i].f) größer als die aktuelle maxMass oder kleiner als minMass ist.
Als Ergebnis dieser Schleife werden die maximalen und minimalen Fitnesswerte aller Agenten ermittelt. In der zweiten Schleife werden wieder alle Agenten durchlaufen, und für jeden einzelnen wird seine „Masse“ (Variable m) mit Hilfe der Funktion u.Scale berechnet, die die Fitnesswerte normalisiert.
//—————————————————————————————————————————————————————————————————————————————— void C_AO_NOA2::CalculateMass () { double maxMass = -DBL_MAX; double minMass = DBL_MAX; // Check for data presence before calculations if (popSize <= 0) return; for (int i = 0; i < popSize; i++) { if (a [i].f > maxMass) maxMass = a [i].f; if (a [i].f < minMass) minMass = a [i].f; } for (int i = 0; i < popSize; i++) { agent [i].m = u.Scale (a [i].f, minMass, maxMass, 0.1, 1.0); } } //——————————————————————————————————————————————————————————————————————————————
Die Methode ApplyNeuralControl ist für die Anwendung der auf den Ausgaben des neuronalen Netzes basierenden Steuerung auf den Agenten vom Typ „boid“ zuständig. Die Methode iteriert über alle „coords“-Koordinaten des Agenten. Für jede c-Koordinate wird geprüft, ob der aktuelle Index nicht über die Grenzen des Ausgabe-Arrays boid.outputs hinausgeht. Wenn der Index korrekt ist, wird die Geschwindigkeit des Agenten dx[c] auf der Grundlage des entsprechenden Wertes aus den Ausgaben des neuronalen Netzes, multipliziert mit seinem neuronalen Einfluss, angepasst.
Die Größe des Arrays boid.outputs wird abgefragt, um weitere Prüfungen zu vereinfachen. Wir prüfen, ob die entsprechenden Indizes innerhalb des Ausgabe-Arrays für cohesion_factor, separation_factor, alignment_factor cohesion, separation und alignment ratios liegen. Liegt der Index außerhalb des zulässigen Bereichs, wird der Standardwert 0,5 zugewiesen. Diese Verhältnisse werden zur Skalierung der Basisgewichte verwendet, um den Einfluss des neuronalen Netzes zu berücksichtigen. Sie beeinflussen das Verhalten der Agenten, indem sie die Gewichte für Konvergenz, Trennung und Ausrichtung ändern:
- local_cohesion legt das Kohäsionsgewicht fest.
- local_separation legt das Trennungsgewicht fest.
- local_alignment legt das Ausrichtungsgewicht fest.
Die Methode prüft, ob eine zufällige Erkundung mit der angegebenen xplorationRate-Wahrscheinlichkeit durchgeführt werden soll. Wenn die Bedingung erfüllt ist, wird eine zufällige c-Koordinate für die Störung ausgewählt. Die Größe der Störung wird auf der Grundlage der Masse des Agenten (die ein Maß für seine Fitness ist) und des Bereichs der möglichen Werte für diese Koordinate berechnet. Auf diese Weise kann das Ausmaß der zufälligen Schwankungen unabhängig von der Masse des Agens kontrolliert werden. Eine zufällige Störung aus dem Bereich von -perturbation_size bis +perturbation_size wird der Geschwindigkeit dx[c] hinzugefügt. Die Methode ApplyNeuralControl integriert die Ergebnisse der neuronalen Netzoperationen in das Bewegungsmanagement der Agenten. Sie passt ihre Geschwindigkeit auf der Grundlage von Daten an, und die Methode berücksichtigt auch die Notwendigkeit einer zufälligen Erkundung.
//—————————————————————————————————————————————————————————————————————————————— // Apply neural control to a boid void C_AO_NOA2::ApplyNeuralControl (S_NeuroBoids_Agent &boid, int pos) { // Use the neural network outputs to correct the speed for (int c = 0; c < coords; c++) { // Make sure the index is not outside the array bounds if (c < ArraySize (boid.outputs)) { // Apply neural speed correction with a given influence boid.dx [c] += boid.outputs [c] * neuralInfluence; } } // Use the neural network outputs to adapt the flock parameters // Check that the indices do not go beyond the array bounds int output_size = ArraySize (boid.outputs); double cohesion_factor = (coords < output_size) ? boid.outputs [coords] : 0.5; double separation_factor = (coords + 1 < output_size) ? boid.outputs [coords + 1] : 0.5; double alignment_factor = (coords + 2 < output_size) ? boid.outputs [coords + 2] : 0.5; // Scale the base weights considering neural adaptation // These variables are local and do not change global parameters double local_cohesion = cohesionWeight * (0.5 + cohesion_factor); double local_separation = separationWeight * (0.5 + separation_factor); double local_alignment = alignmentWeight * (0.5 + alignment_factor); // Random study with a given probability if (u.RNDprobab () < explorationRate) { // Select a random coordinate for perturbation int c = (int)u.RNDfromCI (0, coords - 1); // Adaptive perturbation size depending on mass (fitness) double perturbation_size = (1.0 - boid.m) * (rangeMax [c] - rangeMin [c]) * 0.01; // Add random perturbation boid.dx [c] += u.RNDfromCI (-perturbation_size, perturbation_size); } } //——————————————————————————————————————————————————————————————————————————————
Die Methode AdaptiveExploration der Klasse C_AO_NOA2 implementiert eine adaptive Exploration in Abhängigkeit vom Stadium der Stagnation im Optimierungsprozess. Die Methode beginnt mit der Überprüfung, ob sich der Wert der Zielfunktion fB im Vergleich zum vorherigen besten Wert m_prevBestFitness geändert hat. Ist die Differenz zwischen diesen beiden Werten kleiner als 0,000001, wird davon ausgegangen, dass kein Fortschritt vorliegt, und der m_stagnationCounter wird erhöht. Andernfalls wird die Stagnation beendet, der Zähler wird zurückgesetzt, und der aktuelle fB-Wert wird als neuer Bestwert gespeichert.
Wenn die Stagnation 20 übersteigt, erhöht sich die Wahrscheinlichkeit einer zufälligen Erkundung (explorationRate), aber sie ist auf 0,5 begrenzt, um eine zu hohe Wahrscheinlichkeit zufälliger Veränderungen zu verhindern. Alle 50 Iterationen der Stagnation erfolgt ein teilweiser Neustart: 70 % der Agenten in der Population werden mit neuen Zufallswerten innerhalb der angegebenen Bereiche rangeMin und rangeMax neu gestartet. Gleichzeitig bleiben die übrigen Top-Agenten mit ihren derzeitigen Positionen unverändert. Nach einem Neustart wird der Stagnationszähler zurückgesetzt.
Wenn es einen Fortschritt gibt und die Anzahl der „params“-Parameter größer als 11 ist, wird die Erkundungswahrscheinlichkeit „explorationRate“ aus dem Parameter-Array gesetzt. Sind weniger Parameter vorhanden, wird der Standardwert 0,1 eingestellt.
//—————————————————————————————————————————————————————————————————————————————— // Adaptive research depending on stagnation void C_AO_NOA2::AdaptiveExploration () { // Determine if there is progress in the search if (MathAbs (fB - m_prevBestFitness) < 0.000001) { m_stagnationCounter++; } else { m_stagnationCounter = 0; m_prevBestFitness = fB; } // Increase research during stagnation if (m_stagnationCounter > 20) { // Increase the probability of random exploration explorationRate = MathMin (0.5, explorationRate * 1.5); // Perform a partial restart every 50 stagnation iterations if (m_stagnationCounter % 50 == 0) { // Restart 70% of the population leaving the best agents int restart_count = (int)(popSize * 0.7); for (int i = popSize - restart_count; i < popSize; i++) { for (int c = 0; c < coords; c++) { agent [i].x [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); agent [i].dx [c] = (rangeMax [c] - rangeMin [c]) * u.RNDfromCI (-1.0, 1.0) * 0.001; } } // Reset the stagnation counter m_stagnationCounter = 0; } } else { // If progress is good enough, use the normal research level if (11 < ArraySize (params)) { explorationRate = params [11].val; } else { explorationRate = 0.1; // default value } } } //——————————————————————————————————————————————————————————————————————————————
Die Cohesion-Methode der Klasse C_AO_NOA2 ist für die Implementierung des „Kohäsions“-Verhaltens für das agentenbasierte Modell von Boids verantwortlich. Erklärung der Variablen:
- centerX – Array wird verwendet, um die Koordinaten des Massenschwerpunkts der benachbarten Agenten zu speichern. Die Größe des Arrays entspricht der Anzahl der „coords“-Koordinaten.
- numNeighbors – Nachbarschaftszähler, der die Anzahl der Agenten innerhalb der angegebenen Entfernung (unter Berücksichtigung der Masse) erfasst.
- sumMass – die Summe der Massen der benachbarten Agenten wird verwendet, um die Koordinaten des Massenschwerpunkts zu normalisieren.
Die erste Schleife (von 0 bis popSize) summiert die Massen aller Agenten in der Population, mit Ausnahme des aktuellen Boids (Agenten) am „pos“-Index. Die zweite Schleife durchläuft alle Agenten und prüft, ob sie sich innerhalb der maximalen Entfernung multipliziert mit dem cohesionDist-Faktor vom aktuellen Boid befinden. Ist der Abstand zu einem Agenten kleiner als der angegebene Höchstwert, werden die Koordinaten dieses Agenten (unter Berücksichtigung seiner Masse) zu centerX addiert, und der Zähler numNeighbors wird erhöht.
Nachdem die Koordinatensummen und Massen der Nachbarn berechnet wurden, wird geprüft, ob es Nachbarn gibt (d.h. numNeighbors > 0) und die Summe der Massen (sumMass > 0.0), und wenn Nachbarn gefunden werden, werden die Koordinaten des Massenschwerpunkts normalisiert (durch Division durch die Summe der Massen). Dann wird die aktuelle dx-Geschwindigkeit des Boids in Richtung des Massenschwerpunkts mit dem gegebenen cohesionWeight-Gewicht erhöht, d.h. der Boid bewegt sich in Richtung des Massenschwerpunkts seiner Nachbarn, wobei deren Massen berücksichtigt werden.
Die Kohäsionsmethode berechnet den Massenschwerpunkt und passt die aktuelle Geschwindigkeit des Boids so an, dass es zu diesem Zentrum „konvergiert“. Dieses Verhalten ist einer der wichtigsten Aspekte bei der Simulation von Herden- oder Gruppenverhalten. Mit Parametern wie cohesionDist und cohesionWeight lässt sich der Abstand, in dem dieses Verhalten zum Tragen kommt, und das Ausmaß, in dem der Massenschwerpunkt die Bewegung der Boids beeinflusst, steuern.
//—————————————————————————————————————————————————————————————————————————————— // Find the center of mass of other boids and adjust the speed towards the center of mass void C_AO_NOA2::Cohesion (S_NeuroBoids_Agent &boid, int pos) { double centerX []; ArrayResize (centerX, coords); ArrayInitialize (centerX, 0.0); int numNeighbors = 0; double sumMass = 0; for (int i = 0; i < popSize; i++) { if (pos != i) sumMass += agent [i].m; } for (int i = 0; i < popSize; i++) { if (pos != i) { if (Distance (boid, agent [i]) < distanceMax * cohesionDist) { for (int c = 0; c < coords; c++) { centerX [c] += agent [i].x [c] * agent [i].m; } numNeighbors++; } } } if (numNeighbors > 0 && sumMass > 0.0) { for (int c = 0; c < coords; c++) { centerX [c] /= sumMass; boid.dx [c] += (centerX [c] - boid.x [c]) * cohesionWeight; } } } //——————————————————————————————————————————————————————————————————————————————
Die Methode Separation der Klasse C_AO_NOA2 implementiert das Trennungsverhalten für die Modellagenten, das Kollisionen zwischen dem Boid und benachbarten Agenten verhindern soll. moveX-Parameter, wie das cohesionDist-Array, werden verwendet, um die Verschiebungsvektoren zu speichern, die den Boid von anderen Agenten wegschieben.
Die Größe des Arrays entspricht der Anzahl der „coords“-Koordinaten. Das moveX-Array wird auf Null initialisiert, um die Akkumulation von Zufallswerten zu vermeiden, dann wird über alle Agenten in der Population iteriert (von 0 bis popSize). Dann prüfen wir, ob sich der Agent in der Nähe des aktuellen Boids befindet. Wenn der Abstand zwischen dem Boid und dem Agenten kleiner ist als der angegebene Maximalwert (multipliziert mit dem Faktor separationDist), werden für jede Koordinate die Agenten-Koordinaten von den aktuellen Boid-Koordinaten subtrahiert, um einen Vektor zu erzeugen, der auf den aktuellen Boid zeigt (d.h. vom Agenten wegschiebt).
Nach Abschluss der Schleife durch die Agenten wird die aktuelle dx-Geschwindigkeit des Boids um den berechneten moveX-Verschiebungsvektor multipliziert mit dem separationWeight-Verhältnis erhöht. Auf diese Weise lässt sich die Abstoßungskraft steuern: Je höher der Wert für separationWeight, desto mehr vermeidet das Boid Kollisionen.
Die Trennungsmethode implementiert ein Verhalten, bei dem der Boid an seinen nächsten Nachbarn abprallt, um Kollisionen zu vermeiden. Dies ist ein wichtiger Aspekt bei der Simulation von Herdenverhalten, der dazu beiträgt, den persönlichen Raum für jeden Agenten zu erhalten und natürlichere Interaktionen zwischen ihnen zu fördern. Mit den Parametern separationDist und separationWeight können wir den Radius bzw. die Stärke des Abstoßungseffekts flexibel einstellen.
//—————————————————————————————————————————————————————————————————————————————— // Pushing away from other boids to avoid collisions void C_AO_NOA2::Separation (S_NeuroBoids_Agent &boid, int pos) { double moveX []; ArrayResize (moveX, coords); ArrayInitialize (moveX, 0.0); for (int i = 0; i < popSize; i++) { if (pos != i) { if (Distance (boid, agent [i]) < distanceMax * separationDist) { for (int c = 0; c < coords; c++) { moveX [c] += boid.x [c] - agent [i].x [c]; } } } } for (int c = 0; c < coords; c++) { boid.dx [c] += moveX [c] * separationWeight; } } //——————————————————————————————————————————————————————————————————————————————
Die Methode Alignment der Klasse C_AO_NOA2 implementiert das Ausrichtungsverhalten für Agenten im Modell. Dieses Verhalten veranlasst die Boids, ihre Geschwindigkeiten mit den benachbarten Agenten zu koordinieren, um eine harmonischere und koordinierte Gruppenbewegung zu schaffen. avgDX ist ein Array, das verwendet wird, um den durchschnittlichen Geschwindigkeitsvektor der benachbarten Agenten zu speichern. Die Größe des Arrays entspricht der Anzahl der Koordinaten, numNeighbors ist ein Zähler, der die Anzahl der Nachbarn innerhalb einer bestimmten Entfernung angibt.
Die Schleife durchläuft alle Agenten in der Population. Innerhalb der Schleife wird geprüft, ob der aktuelle Bearbeiter derselbe Boid ist. Ist der Abstand zu einem anderen Agenten kleiner als der angegebene Maximalwert multipliziert mit dem Faktor alignmentDist, wird die aktuelle dx-Geschwindigkeit dieses Agenten zu avgDX addiert. Der Zähler numNeighbors wird um 1 erhöht. Nach Abschluss der Schleife wird, wenn Nachbarn gefunden wurden (d. h. numNeighbors > 0), die Durchschnittsgeschwindigkeit (avgDX) berechnet, indem der summierte Geschwindigkeitsvektor durch die Anzahl der Nachbarn geteilt wird. Dann wird die aktuelle dx-Geschwindigkeit des Boids an die Durchschnittsgeschwindigkeit seiner Nachbarn angepasst, wobei das Verhältnis alignmentWeight berücksichtigt wird.
Die Methode Alignment ermöglicht es einem Boid, seine Geschwindigkeit an die seiner Nachbarn anzupassen. Dieses Verhalten trägt dazu bei, dass sich Gruppen von Boiden geschlossener bewegen und die Wahrscheinlichkeit von Konflikten oder abrupten Richtungswechseln verringert wird. Mit den Parametern alignmentDist und alignmentWeight wird der Radius des Ausrichtungseffekts bzw. der Grad der Beeinflussung der Geschwindigkeit des aktuellen Boids durch die Durchschnittsgeschwindigkeit der Nachbarn festgelegt.//—————————————————————————————————————————————————————————————————————————————— // Align speed with other boids void C_AO_NOA2::Alignment (S_NeuroBoids_Agent &boid, int pos) { double avgDX []; ArrayResize (avgDX, coords); ArrayInitialize (avgDX, 0.0); int numNeighbors = 0; for (int i = 0; i < popSize; i++) { if (pos != i) { if (Distance (boid, agent [i]) < distanceMax * alignmentDist) { for (int c = 0; c < coords; c++) { avgDX [c] += agent [i].dx [c]; } numNeighbors++; } } } if (numNeighbors > 0) { for (int c = 0; c < coords; c++) { avgDX [c] /= numNeighbors; boid.dx [c] += (avgDX [c] - boid.dx [c]) * alignmentWeight; } } } //——————————————————————————————————————————————————————————————————————————————
Die Methode LimitSpeed der Klasse C_AO_NOA2 soll die Geschwindigkeit der Agenten (Boids) im Modell kontrollieren, um sicherzustellen, dass die Geschwindigkeiten der Boids innerhalb eines bestimmten Bereichs liegen. „speed“ ist eine Variable zur Speicherung der aktuellen Geschwindigkeit der Boids, die als Länge des Geschwindigkeitsvektors berechnet wird. Die Koordinatenschleife (coords) berechnet das Quadrat der Geschwindigkeit für jede Koordinate (durch Addition von boid.dx[c] * boid.dx[c]) und summiert sie auf. Damit lässt sich das Quadrat der Länge des Geschwindigkeitsvektors berechnen. Die Länge (oder tatsächliche Geschwindigkeit) wird dann mit der Funktion MathSqrt ermittelt, die die Quadratwurzel aus der Summe der Quadrate berechnet. Ist die Geschwindigkeit größer als ein kleiner Wert (1e-10), wird das Programm weiter ausgeführt, ist die aktuelle Geschwindigkeit kleiner als die zulässige Mindestgeschwindigkeit (definiert als speedMax[0] * minSpeed), wird der Geschwindigkeitsvektor boid.dx normalisiert (geteilt durch seine aktuelle Länge) und auf einen Wert erhöht, der dem zulässigen Mindestwert entspricht.
Ist die aktuelle Geschwindigkeit größer als die zulässige Höchstgeschwindigkeit (speedMax[0] * maxSpeed), wird der Geschwindigkeitsvektor ebenfalls normalisiert und auf den Wert der Höchstgeschwindigkeit gesetzt. Ist die Geschwindigkeit fast Null (Null oder sehr nahe bei Null), wird jede Koordinate des Geschwindigkeitsvektors durch einen kleinen Zufallswert ersetzt, der mit der Funktion u.RNDfromCI(-1.0, 1.0) multipliziert mit der Höchstgeschwindigkeit ermittelt wird.
Die LimitSpeed-Methode sorgt dafür, dass die Geschwindigkeit der Boote innerhalb akzeptabler Grenzen gehalten wird und verhindert, dass sie sich zu langsam oder zu schnell bewegen. Dieses Verhalten ermöglicht realistischere Agentensimulationen, da es keine großen Geschwindigkeitsschwankungen zulässt, die zu unnatürlichen Bewegungen führen könnten. Die Parameter minSpeed und maxSpeed können konfiguriert werden, um das Verhalten und die Geschwindigkeit der Agenten je nach Simulationsaufgabe anzupassen.
//—————————————————————————————————————————————————————————————————————————————— // Speed limit void C_AO_NOA2::LimitSpeed (S_NeuroBoids_Agent &boid) { double speed = 0; for (int c = 0; c < coords; c++) { speed += boid.dx [c] * boid.dx [c]; } speed = MathSqrt (speed); // If the speed is not zero (prevent division by zero) if (speed > 1e-10) { // If the speed is too low, increase it if (speed < speedMax [0] * minSpeed) { for (int c = 0; c < coords; c++) { boid.dx [c] = boid.dx [c] / speed * speedMax [c] * minSpeed; } } // If the speed is too high, reduce it else if (speed > speedMax [0] * maxSpeed) { for (int c = 0; c < coords; c++) { boid.dx [c] = boid.dx [c] / speed * speedMax [c] * maxSpeed; } } } else { // If the speed is almost zero, set a small random speed for (int c = 0; c < coords; c++) { boid.dx [c] = u.RNDfromCI (-1.0, 1.0) * speedMax [c] * minSpeed; } } } //——————————————————————————————————————————————————————————————————————————————
Die Methode KeepWithinBounds der Klasse C_AO_NOA2 dient dazu, den Agenten (boid) innerhalb der angegebenen Grenzen zu halten. Wenn ein Boid zu nahe an den Rand der Region gerät, ändert diese Methode seine Richtung und sorgt für einen gewissen Rückstoß in die Grenzen. Die Methode beginnt mit einer Schleife über alle Koordinaten, was das Arbeiten im mehrdimensionalen Raum ermöglicht.
Für jede Koordinate wird geprüft, ob die Boid-Position (boid.x[c]) unterhalb der Mindestgrenze (rangeMin[c]) liegt. Ist dies der Fall, wird die Geschwindigkeitsrichtung (boid.dx[c]) mit „boid.dx[c] *= -1.0“ invertiert. Das bedeutet, dass sich der Boid in die entgegengesetzte Richtung bewegt. Dann wird ein kleiner Schub von der Begrenzung hinzugefügt: (rangeMax[c] – rangeMin[c]) * 0,001, was dazu beiträgt, das Boid zurück in den Bereich zu schieben.
Eine ähnliche Prüfung wird für die Maximalgrenze (rangeMax[c]) durchgeführt: Wenn die Position des Boids über die Maximalgrenze hinausgeht, wird seine Geschwindigkeit ebenfalls invertiert und angepasst, allerdings durch Abzug eines Wertes, der dem vorherigen Fall ähnelt.
Die Methode KeepWithinBounds schränkt die Bewegungen von Boids innerhalb eines bestimmten Gebiets wirksam ein und verhindert, dass sie aus dem Gebiet herausfliegen, und stellt sicher, dass sie innerhalb des Gebiets zurückkehren.
//—————————————————————————————————————————————————————————————————————————————— // Keep the boid within the boundaries. If it gets too close to the edge, // push it back and change direction. void C_AO_NOA2::KeepWithinBounds (S_NeuroBoids_Agent &boid) { for (int c = 0; c < coords; c++) { if (boid.x [c] < rangeMin [c]) { boid.dx [c] *= -1.0; // Add a small push from the border boid.dx [c] += (rangeMax [c] - rangeMin [c]) * 0.001; } if (boid.x [c] > rangeMax [c]) { boid.dx [c] *= -1.0; // Add a small push from the border boid.dx [c] -= (rangeMax [c] - rangeMin [c]) * 0.001; } } } //——————————————————————————————————————————————————————————————————————————————
Die Methode Distance der Klasse C_AO_NOA2 dient der Berechnung des Abstands zwischen zwei Agenten (Boids) in einem mehrdimensionalen Raum. Es verwendet eine Gleichung zur Berechnung des euklidischen Abstands, „dist“ ist eine Variable, die die Summe der quadrierten Differenzen zwischen den Koordinaten zweier Boids speichert.
Die Methode startet eine Schleife, die alle Koordinaten durchläuft, was die Berechnung der Entfernung in einem Raum beliebiger Dimension ermöglicht. Für jede Koordinate c wird das Quadrat der Differenz zwischen den entsprechenden Koordinaten der beiden Boids berechnet: boid1.x[c] – boid2.x[c].
Die Ergebnisse ((boid1.x[c] – boid2.x[c])^2) werden der Variablen „dist“ hinzugefügt. Nach Beendigung der Schleife enthält die Variable „dist“ die Summe der Quadrate der Koordinatendifferenzen. Um den tatsächlichen Abstand zu ermitteln, verwendet die Methode MathSqrt, um die Quadratwurzel der Summe der Quadrate zu berechnen, was der Gleichung für den euklidischen Abstand entspricht.
//—————————————————————————————————————————————————————————————————————————————— // Calculate the distance between two boids double C_AO_NOA2::Distance (S_NeuroBoids_Agent &boid1, S_NeuroBoids_Agent &boid2) { double dist = 0; for (int c = 0; c < coords; c++) { dist += MathPow (boid1.x [c] - boid2.x [c], 2); } return MathSqrt (dist); } //——————————————————————————————————————————————————————————————————————————————
Die Methode Revision der Klasse C_AO_NOA2 ist für die Aktualisierung der Informationen über die beste Lösung zuständig, die während der Optimierung gefunden wurde. Bei diesem Prozess werden sowohl der Wert der Fitnessfunktion als auch die diesem Wert entsprechenden Koordinaten aktualisiert. Die Methode überwacht auch den Fortschritt und passt die Parameter des Algorithmus an, wenn es zu signifikanten Verbesserungen kommt. Die Methode durchläuft die gesamte Population, dargestellt durch das Array a, das popSize (die Anzahl der Agenten) enthält.
Innerhalb der Schleife wird jeder Agent daraufhin überprüft, ob sein Fitnesswert (a[i].f) größer ist als der aktuelle Bestwert (fB). Wenn der aktuelle Agent den besten Fitnesswert aufweist, wird der global beste Wert der Fitnessfunktion aktualisiert, wobei fB ein neuer Wert von a[i].f zugewiesen wird, und dann werden die Koordinaten der besten Lösung aktualisiert. Für jede c-Koordinate wird das cB-Array (das die Koordinaten der besten Lösung enthält) mit den Werten des aktuellen Agenten aktualisiert. Der Stagnationszähler (m_stagnationCounter) wird auf Null zurückgesetzt, da eine Verbesserung der Lösung gefunden wurde.
Die Methode verwendet die Variable hasProgress, um festzustellen, ob ein Fortschritt erzielt wurde. Dazu wird die absolute Differenz zwischen dem aktuellen und dem vorherigen besten Wert der Fitnessfunktion berechnet (MathAbs(fB – m_prevBestFitness)), und wenn diese Differenz größer als 0,000001 ist, wird der Fortschritt als offensichtlich angesehen. Wenn es Fortschritte gibt, wird m_prevBestFitness auf den aktuell besten fB-Wert aktualisiert.
Die Erkundungsgeschwindigkeit explorationRate wird ebenfalls angepasst: Sie wird reduziert, wenn eine Verbesserung gefunden wird, wobei einige Parameter aus dem Array params und der aktuelle Wert von explorationRate berücksichtigt werden.
//—————————————————————————————————————————————————————————————————————————————— // Update the best solution found void C_AO_NOA2::Revision () { // Update the best coordinates and fitness function value for (int i = 0; i < popSize; i++) { // Update the global best solution if (a [i].f > fB) { fB = a [i].f; for (int c = 0; c < coords; c++) { cB [c] = a [i].c [c]; } // Reset the stagnation counter when a better solution is found m_stagnationCounter = 0; } } // Check for progress to adapt the algorithm parameters bool hasProgress = MathAbs (fB - m_prevBestFitness) > 0.000001; if (hasProgress) { m_prevBestFitness = fB; explorationRate = MathMax (params [11].val * 0.5, explorationRate * 0.9); } } //——————————————————————————————————————————————————————————————————————————————
Testergebnisse
Die Testergebnisse sind recht schwach.NOA2|Neuroboids Optimization Algorithm 2 (joo)|50.0|0.6|0.001|0.005|0.03|0.1|0.1|0.1|0.01|0.01|0.3|0.1|
=============================
5 Hilly's; Func runs: 10000; result: 0.47680799582735267
25 Hilly's; Func runs: 10000; result: 0.30763714006051013
500 Hilly's; Func runs: 10000; result: 0.2544737238936433
=============================
5 Forest's; Func runs: 10000; result: 0.3238017030688524
25 Forest's; Func runs: 10000; result: 0.20976876473929068
500 Forest's; Func runs: 10000; result: 0.15740101965732595
=============================
5 Megacity's; Func runs: 10000; result: 0.27076923076923076
25 Megacity's; Func runs: 10000; result: 0.14676923076923082
500 Megacity's; Func runs: 10000; result: 0.09729230769230844
=============================
All score: 2.24472 (24.94%)
Die Visualisierung zeigt bescheidene Suchmöglichkeiten. Die Möglichkeit, externe Parameter des Algorithmus mit Hilfe globaler Variablen zu ändern, erlaubt es, mit dem Verhalten von Boids zu experimentieren und interessante Verhaltensmuster zu entdecken. Nachfolgend finden sich die Visualisierungen einiger der vielen möglichen Verhaltensmuster.

NOA2 mit der Testfunktion Hilly

NOA2 mit der Testfunktion Forest-

NOA2 mit der Testfunktion Megacity
Auf der Grundlage der Testergebnisse wird der NOA2-Algorithmus in seiner Basisversion nur zur Information in unsere Rangliste der Algorithmen zur Populationsoptimierung aufgenommen.
| # | 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 | mit der Testfunktion | 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 | 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 |
| 13 | 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 |
| 14 | 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 |
| 15 | 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 |
| 16 | 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 |
| 17 | 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 |
| 18 | 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 |
| 19 | 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 |
| 20 | 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 |
| 21 | 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 |
| 22 | 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 |
| 23 | 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 |
| 24 | 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 |
| 25 | 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 |
| 26 | 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 |
| 27 | 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 |
| 28 | (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 |
| 29 | 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 |
| 30 | 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 |
| 31 | 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 |
| 32 | 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 |
| 33 | 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 |
| 34 | 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 |
| 35 | 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 |
| 36 | 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 |
| 37 | 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 |
| 38 | 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 |
| 39 | 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 |
| 40 | CGO | Chaos Game Optimization | 0.57256 | 0.37158 | 0.32018 | 1.26432 | 0.61176 | 0.61931 | 0.62161 | 1.85267 | 0.37538 | 0.21923 | 0.19028 | 0.78490 | 3.902 | 43.35 |
| 41 | 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 |
| 42 | CFO | Schwerkraftoptimierung | 0.60961 | 0.54958 | 0.27831 | 1.43750 | 0.63418 | 0.46833 | 0.22541 | 1.32792 | 0.57231 | 0.23477 | 0.09586 | 0.90294 | 3.668 | 40.76 |
| 43 | 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 |
| 44 | 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 |
| 45 | 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 |
| NOA2 | Neuroboids Optimierungsalgorithmus 2(joo) | 0.47681 | 0.30764 | 0.25447 | 1.03892 | 0.32380 | 0.20977 | 0.15740 | 0.69097 | 0.27077 | 0.14677 | 0.09729 | 0.51483 | 2.245 | 24.94 | |
Zusammenfassung
Der von mir entwickelte Neuroboid-Optimierungsalgorithmus (NOA2) ist ein hybrider Ansatz, der die Prinzipien der Schwarmintelligenz (der Boid-Algorithmus) mit der neuronalen Steuerung kombiniert. Die Kernidee ist die Verwendung eines neuronalen Netzes zur adaptiven Steuerung der Verhaltensparameter von Boid-Agenten. Die derzeitige Implementierung verwendet ein einfaches einschichtiges neuronales Netz ohne versteckte Schichten. Es besteht aus einer Eingabeschicht, die aktuelle Koordinaten, Geschwindigkeiten, die Entfernung zur besten Lösung und den Wert der Fitnessfunktion empfängt, sowie einer Ausgabeschicht, die Geschwindigkeitskorrekturen und adaptive Parameter für die Verhaltensregeln des Boid-Schwarms definiert.
Bei dieser Version gibt es keine Zwischenschichten. Die Anzahl der Eingaben ist definiert als (coords * 2 + 2), wobei „coords“ die Anzahl der Dimensionen des Suchraums ist. Die Ergebnisse umfassen eine Korrektur für jede Koordinate und drei zusätzliche Parameter zur Anpassung der Herdenregeln. Der Algorithmus hat eine große Anzahl von konfigurierbaren Parametern, was es schwierig macht, die besten zu finden. Ich habe verschiedene Kombinationen ausprobiert, aber ich habe immer noch nicht die ideale Kombination gefunden, die die besten Ergebnisse bei den Testfunktionen zeigt.
In seiner jetzigen Form dient der Algorithmus eindeutig als Proof-of-Concept und ist insgesamt ein interessantes Experiment im Bereich der hybriden Optimierungsverfahren, das jedoch keine ausreichende Leistung aufweist. Er schneidet bei den durchgeführten Tests nur minimal ab und kann nur als Beispiel für den Ansatz der Algorithmenhybridisierung betrachtet werden. Interessierten Forschern und Entwicklern kann der NOA2-Code als Ausgangspunkt dienen, um mit verschiedenen Konfigurationen und Parametern zu experimentieren und fortgeschrittenere hybride Optimierungsalgorithmen zu entwickeln, die die Vorteile von populationsbasierten und maschinellen Lernmethoden nutzen.

Abbildung 3. Farbabstufung der Algorithmen nach den entsprechenden Tests

Abbildung 4. 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 NOA2:
Vorteile:
- Interessante Idee.
Nachteile
- Schwache Ergebnisse.
Der Artikel wird von einem Archiv mit den aktuellen Versionen der Codes der Algorithmen begleitet. Der Autor des Artikels übernimmt keine Verantwortung für die absolute Richtigkeit der Beschreibung der kanonischen Algorithmen. An vielen von ihnen wurden Änderungen vorgenommen, um die Suchmöglichkeiten zu verbessern. Die in den Artikeln dargelegten Schlussfolgerungen und Urteile beruhen auf den Ergebnissen der Versuche.
Programme, die im diesem Artikel verwendet werden
| # | Name | Typ | Beschreibung |
|---|---|---|---|
| 1 | #C_AO.mqh | Include | Übergeordnete Klasse von Populationsoptimierungsalgorithmen |
| 2 | #C_AO_enum.mqh | Include | Enumeration 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_NOA2.mq5 | Skript | NOA2-Prüfstand |
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/17497
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.
Einführung in MQL5 (Teil 28): Beherrschung der API- und WebRequest-Funktion in MQL5 (II)
Von der Grundstufe bis zur Mittelstufe: Indikator (IV)
Von der Grundstufe bis zur Mittelstufe: Struktur (V)
Algorithmische Handelsstrategien: KI und ihr Weg zu den goldenen Zinnen
- 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.