Competitive Learning Algorithm (CLA)
Contents
Introduction
Over the past decades, many bioinspired algorithms have been proposed, from ant colonies and particle swarms to gray wolves and whales. However, human society, with its complex social interactions, can also serve as a rich source of ideas for effective optimization methods. This idea is the basis for the Competitive Learning Algorithm (CLA).
CLA uses a metaphor of the educational process, where the population of solutions is represented by students organized into classes. The algorithm elegantly models three types of learning: from the best in the class (teacher), from personal experience, and through cross-class interaction. This approach provides a balance between exploring the search space and exploiting the good solutions found, which is critical for effective optimization.
In this article, we will examine in detail the principles of CLA, its mathematical basis, implementation features, and compare its effectiveness with other popular metaheuristics on our standard test functions.
Implementation of the algorithm
The Competitive Learning Algorithm is based on a metaphor of the educational process in school. In this metaphor, students represent possible solutions to the optimization problem, classes are groups of students, teachers are the best students in each class, knowledge corresponds to coordinates in the search space, and the score is determined by the value of the fitness function.
The algorithm starts with an initialization, which can be compared to the beginning of the school year. A population of, for example, 198 students is created, which are divided into 9 classes of 22 students each. Each student is randomly assigned initial "knowledge" - coordinates in the search space.
The learning process is iterative, and at each iteration, students learn in three different ways. The first method is teacher-led learning, where each student learns from the best in their class, and the worse the class's performance, the more active the learning process, but over time the intensity of learning decreases for everyone. The second method is personal training, which begins only after the fourth iteration. In this mode, the student recalls his best results over the last four "lessons" and tries to return to his personal best. The third method is learning from other classes, which also begins after the fourth iteration. With a 50% probability, a student learns from the average teacher computed across all classes, which helps avoid getting stuck in local optima.
After each training cycle, progress is assessed. The best student in each class is identified and becomes the teacher, the overall class rating is calculated taking into account the performance of all students, and the globally best solution found is updated.
The algorithm uses five key parameters:
- popSize - total number of students,
- numClasses — number of classes,
- beta - influence of all students in a class on its overall rating,
- gamma — probability of learning from other classes,
- deltaIter — after which iteration extended learning begins using personal experience and inter-class interactions.
The algorithm implements several smart mechanisms. Adaptive learning factors provide more intensive learning for weaker classes and a gradual slowdown of learning over time, as happens in the real educational process. The balance between exploration and exploitation is achieved through active exploration in the early stages, followed by a focus on the best solutions found. The memory mechanism allows the algorithm to remember the history of each student and, if necessary, return to good decisions from the past.
Mathematically, a student’s knowledge update can be represented as the sum of the current knowledge and three components: instruction from the class teacher, personal historical experience, and knowledge obtained from the average teacher across all classes. This formula provides a balance between following the leader, using personal experience and exploring new areas.
Ultimately, the algorithm's effectiveness is determined by several factors. Diversity is achieved through multiple classes exploring different directions in the search space. Competition between students for a teaching position encourages better solutions. Cooperation through knowledge sharing between classes helps prevent premature convergence. Adaptivity provides additional help for weak classes, and the memory mechanism stores information about good solutions.

Figure 1. Algorithm operation
The illustration of the algorithm's operation describes three main steps: initialization, training phase, and evaluation with updating. Now let's start writing pseudocode for the CLA_L algorithm.
WHAT WE NEED IN ADVANCE:
- 198 students (our solutions)
- 9 classes (student groups)
- Parameter β = 0.9 (how important are all students in the class)
- Parameter γ = 0.5 (chance to learn from other classes)
- After the 4th iteration, include additional types of learning
- Function for evaluating the quality of the solution
LET'S START:
1. CREATE A SCHOOL:
- Distribute 198 students into 9 classes (22 in each)
- Give each student a random initial position in the search space
- In each class, choose the best student - they become a teacher
- Create a journal to record each student's history
2. LEARNING PROCESS (iterative process):
Step 1: Determine the learning intensity
- For each class we calculate how actively students need to study
- Weak classes (with a bad rank) study more intensively
- Over time, everyone studies less intensively (like in real life)
Step 2: Find the "average teacher"
- Take the positions of all teachers
- Calculate their average value
- This will be a school-wide standard of knowledge
Step 3: Each student learns:
For each student:
a) ALWAYS learn from their own teacher:
- Look where the class teacher is
- Move in their direction
- The speed of movement depends on the class learning factor
b) After the 4th iteration, we recall our experience:
- Look at the journal: where was I best in the last 4 lessons?
- With some random force, return to that position
- This helps preserve good solutions
c) After the 4th iteration, learn from other classes:
- Toss a coin (with a 50% probability)
- If it lands on tails, we look at the "average teacher"
- Move a little towards it
- This helps to exchange experiences between classes
Step 4: Evaluate all students
- Each student receives a fitness value
- The better the position, the higher the rating
Step 5: Update the school hierarchy
For each class:
- Find a new best student - they become a teacher
- Calculate the general level of the class:
* Take the teacher's fitness value
* Add the average score of all students (multiplied by β)
- Determine the class rank:
* The best classes get a low rank (1, 2, 3...)
* Worst classes get a high rank
Step 6: Remember the best solution
- If some teacher is better than our record value
- Save it as a new record
Step 7: Saving history
- Save the current positions of all student
- This will be needed for personal training
3. FINISHING:
- Return the best solution found
- And its fitness value
Now let's start writing the algorithm code. The C_AO_CLA_l class inherits from the parent class C_AO and implements an algorithm based on the concept of competitive learning. The class contains a number of user-configurable parameters:
- popSize — population size (number of "agents" or "students");
- numClasses — number of classes agents are divided into;
- beta — parameter that likely influences the speed of learning or adaptation;
- gamma — another parameter related to the learning process;
- deltaIter — the iteration number after which certain stages of the algorithm are activated.
The constructor initializes the main parameters, sets the name and description of the algorithm, specifies default values for variables, and sizes the "params" array, which is used to store information about the algorithm parameters.
Methods:
- SetParams () updates the values of the class's internal variables (algorithm parameters) using the values from the "params" array. This allows you to change externally set parameters.
- Init () — initialize the algorithm. Accepts parameters to define the boundaries and step of changing the parameters.
- Moving () — main method for "moving" agents (performing iterations and steps of the algorithm).
- Revision () — method is associated with the correction or improvement of decisions.
- Injection () — method for inserting new knowledge or data into an agent.
- numClasses, beta, gamma, deltaIter — algorithm parameters.
- currentIter, studentsPerClass, totalIters — internal variables for controlling the algorithm flow.
- teachers [] — array of S_AO_Agent structures representing the "teachers" in each class (anchor points).
- classRanks [] — class ranks reflecting their performance.
- classTotalCosts [] — total costs or "cost" of each class.
- CL [] — temporary array for calculating the average knowledge of teachers.
- UpdateTeachersAndCosts () — internal method to update information about teachers and their costs.
- UpdateClassRanks () — internal method for updating class ranks.
- UpdateStudentsKnowledge () — internal method for updating knowledge or "students" parameters.
//———————————————————————————————————————————————————————————————————— class C_AO_CLA_l : public C_AO { public: //---------------------------------------------------------- ~C_AO_CLA_l () { } C_AO_CLA_l () { ao_name = "CLA_L"; ao_desc = "Competitive Learning Algorithm"; ao_link = "https://www.mql5.com/en/articles/18857"; popSize = 198; numClasses = 3; beta = 0.3; gamma = 0.8; deltaIter = 2; ArrayResize (params, 5); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "numClasses"; params [1].val = numClasses; params [2].name = "beta"; params [2].val = beta; params [3].name = "gamma"; params [3].val = gamma; params [4].name = "deltaIter"; params [4].val = deltaIter; } void SetParams () { popSize = (int)params [0].val; numClasses = (int)params [1].val; beta = params [2].val; gamma = params [3].val; deltaIter = (int)params [4].val; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving (); void Revision (); void Injection (const int popPos, const int coordPos, const double value) { } //------------------------------------------------------------------ int numClasses; double beta; double gamma; int deltaIter; private: //--------------------------------------------------------- int currentIter; int studentsPerClass; int totalIters; // Structures for classes S_AO_Agent teachers []; double classRanks []; double classTotalCosts []; // Temporary array double CL []; // Average knowledge of teachers // Auxiliary methods void UpdateTeachersAndCosts (); void UpdateClassRanks (); void UpdateStudentsKnowledge (); }; //————————————————————————————————————————————————————————————————————
The Init() method of the C_AO_CLA_l class initializes the algorithm before it starts working. The logic of the work is divided into several stages. Standard Initialization: the StandardInit () method is called and performs standard initialization for the optimization algorithm. It receives the rangeMinP, rangeMaxP and the rangeStepP step parameters. If standard initialization fails, the Init() method returns 'false'.
Initialization of Algorithm Parameters: resets the current iteration counter to "0", sets the total number of iterations the algorithm should perform using the value passed in the epochsP argument, calculates the number of "students" (agents) in each class by dividing the population size by the number of classes. Next, the method checks that there is at least one student in each class. Next, the "for" loop initializes each agent in the population. The 'a' array the Init() method is called for each agent to initialize its coordinate array.
The "for" loop initializes a "teacher" for each class, sets the rank of each class to 1.0, and sets the initial "cost" of each class to a negative maximum value to ensure that a better solution is found later. If all initialization steps are successful, the method returns 'true'.
//———————————————————————————————————————————————————————————————————— bool C_AO_CLA_l::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //------------------------------------------------------------------ currentIter = 0; totalIters = epochsP; studentsPerClass = popSize / numClasses; if (studentsPerClass < 1) { Print ("Error: Too few students per class"); return false; } // Adjust the population size //spopSize = studentsPerClass * numClasses; ArrayResize (a, popSize); for (int i = 0; i < popSize; i++) a [i].Init (coords); // Initialize class structures ArrayResize (teachers, numClasses); ArrayResize (classRanks, numClasses); ArrayResize (classTotalCosts, numClasses); for (int i = 0; i < numClasses; i++) { teachers [i].Init (coords); classRanks [i] = 1.0; classTotalCosts [i] = -DBL_MAX; } // Temporary array ArrayResize (CL, coords); return true; } //————————————————————————————————————————————————————————————————————
The Moving() method of the C_AO_CLA_l class implements one iteration of the main optimization algorithm, checks whether it is the first iteration, and if it is the first iteration (i.e., "revision" is 'false'), the method initializes the positions of all agents in the population to random values in the given range. It iterates over all agents in the population and for each agent iterates over all its coordinates.
For each coordinate, the method generates a random value "val" in the range from rangeMin[c] to rangeMax[c] using the u.RNDfromCI() method, which provides a function for generating random numbers. It assigns "val" to the a[i].c[c] coordinate of 'i' agent, having previously "trimmed" it so that it is within the acceptable range and corresponds to the given rangeStep[c] step. The u.SeInDiSp() method is used, which performs value checking and adjustment.
After initializing the population, a flag is set to indicate that initialization has been performed. If this is not the first iteration, the current iteration counter is incremented. The UpdateStudentsKnowledge() method is called to implement the main mechanism for training or adapting agents in accordance with the principles of competitive learning used in the CLA_L algorithm. The logic of this method determines how agents interact, exchange information, and improve their positions in the solution search space.
//———————————————————————————————————————————————————————————————————— void C_AO_CLA_l::Moving () { // Initial population setup if (!revision) { for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { double val = u.RNDfromCI (rangeMin [c], rangeMax [c]); a [i].c [c] = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]); } } revision = true; return; } currentIter++; // Update students' knowledge UpdateStudentsKnowledge (); } //————————————————————————————————————————————————————————————————————
The UpdateStudentsKnowledge() method is responsible for updating the position of each student (agent) during the optimization. The current optimization progress is calculated. Two key learning factors are calculated:
- TF (Teaching Factor) - shows how much a student learns from a teacher.
- CF (Confirmatory Factor) - shows the extent to which a student takes into account the average knowledge of teachers. These factors depend on the student's progress and class rank.
Next, the average value of the coordinates of all "active" teachers (teachers whose results are valid) is calculated. This average knowledge is stored in a temporary array. For each student (agent), the class to which the student belongs is determined, and for each student's coordinate, a new student position is calculated by summing the current coordinate with the "knowledge sources". The student learns from his teacher by adjusting his position by an amount proportional to the difference between the teacher's coordinate and his own, multiplied by TF. If enough iterations have passed (currentIter > deltaIter) and the student has a "best solution", then the student learns from its previous successful experience by adjusting its position towards the best coordinate, multiplied by a random factor.
If enough iterations have passed and the number of teachers is valid, the student learns from the average knowledge of all teachers, adjusting its position in the direction of the average coordinate multiplied by CF with a certain probability (1-gamma). Boundaries (constraints) are applied to each student coordinate to ensure that the value is within the acceptable range. The value is adjusted to match the acceptable values given the search sampling step.
//———————————————————————————————————————————————————————————————————— void C_AO_CLA_l::UpdateStudentsKnowledge () { // Calculate learning factors for the current iteration double progress = (double)currentIter / (double)MathMax (totalIters, 100); // Calculate the average knowledge of all teachers (CL) ArrayInitialize (CL, 0.0); int validTeachers = 0; for (int k = 0; k < numClasses; k++) { // Make sure the teacher is initialized if (teachers [k].f > -DBL_MAX) { for (int c = 0; c < coords; c++) { CL [c] += teachers [k].c [c]; } validTeachers++; } } if (validTeachers > 0) { for (int c = 0; c < coords; c++) { CL [c] /= validTeachers; } } // Update each student for (int i = 0; i < popSize; i++) { int classIdx = i / studentsPerClass; // Teaching Factor - decreases with progress double TF = MathExp (-0.6 * progress * classRanks [classIdx]); TF = MathMax (0.1, MathMin (1.0, TF)); // Confirmatory Factor double CF = MathExp (-0.5 * progress * classRanks [classIdx]); CF = MathMax (0.1, MathMin (1.0, CF)); // Update the student position for (int c = 0; c < coords; c++) { double newPos = a [i].c [c]; // a) Teacher Learning - learn from the class teacher if (teachers [classIdx].f > -DBL_MAX) { newPos += TF * (teachers [classIdx].c [c] - a [i].c [c]); } // b) Personal Learning - learn from your best solution if (currentIter > deltaIter && a [i].fB > -DBL_MAX) { double PF = u.RNDprobab (); newPos += PF * (a [i].cB [c] - a [i].c [c]); } // c) Confirmatory Learning - learn from the average of all teachers if (currentIter > deltaIter && validTeachers > 0) { double rnd = u.RNDprobab (); if (rnd >= gamma) // Participate with probability (1-gamma) { newPos += CF * (CL [c] - a [i].c [c]); } } // Apply borders a [i].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]); } } } //————————————————————————————————————————————————————————————————————
The Revision() method in the C_AO_CLA_l class is used to update information about the best solutions of each agent, as well as to update the global best solution and the corresponding parameters.
For each agent, it is checked whether its current objective function (a[i].f) has improved compared to its remembered best value (a[i].fB). If so, the best value is saved and the corresponding coordinates are copied. After checking all agents, if any of them got a better function value than the current global maximum (fB), the global parameters are updated: fB is the global best function value and cB are the coordinates of this best solution.
Next, the UpdateTeachersAndCosts() method is called, which updates information about the best teachers. At the end, UpdateClassRanks() is called to recalculate the class ranks, which affects the priority of choosing certain solutions in subsequent iterations.
//———————————————————————————————————————————————————————————————————— void C_AO_CLA_l::Revision () { for (int i = 0; i < popSize; i++) { // Update personal best positions if (a [i].f > a [i].fB) { a [i].fB = a [i].f; ArrayCopy (a [i].cB, a [i].c); } // Update the global best one if (a [i].f > fB) { fB = a [i].f; ArrayCopy (cB, a [i].c); } } // Update teachers UpdateTeachersAndCosts (); // Update class ranks UpdateClassRanks (); } //————————————————————————————————————————————————————————————————————
The UpdateTeachersAndCosts() method is used to update information about teachers in each class and calculate the total "cost" of the class. The method loops through all classes defined in the system. For each class, the initial and final indices of students (agents) included in this class are determined.
To find the best student in the class, variables are initialized to store the best function value, the index of the best student, the sum of the function values of all students in the class, and the number of valid students. The cycle goes through all students in the current class. For each student, it is checked whether their solution is valid, and if the solution is valid, then: the student's fitness value is added to sumFitness, the counter of valid students is incremented, and if the current student's feature value is better than the current best value bestFitness, then it is updated and bestIdx is updated.
After finding the best student in the class, it is checked that there was at least one valid student in the class (validStudents > 0). If the condition is met, then the coordinates of the best student are copied to the coordinates of the teacher of the corresponding class, and the value of the best student's function is assigned to the value of the teacher's function.
The average value of the function of all students in the avgFitness class is calculated. The total "cost" of the class is calculated as the sum of the value of the best student's function and the product of the "beta" coefficient by the average value of the function of all students. It is a combination of teacher effectiveness and average class wealth.
//———————————————————————————————————————————————————————————————————— void C_AO_CLA::UpdateTeachersAndCosts () { for (int k = 0; k < numClasses; k++) { int startIdx = k * studentsPerClass; int endIdx = startIdx + studentsPerClass; double bestFitness = -DBL_MAX; int bestIdx = startIdx; double sumFitness = 0.0; int validStudents = 0; // Find the best student (teacher) in the class for (int i = startIdx; i < endIdx; i++) { if (a[i].f > -DBL_MAX) // Validity check { sumFitness += a[i].f; validStudents++; if (a[i].f > bestFitness) { bestFitness = a[i].f; bestIdx = i; } } } // Update the teacher if (validStudents > 0) { ArrayCopy (teachers[k].c, a[bestIdx].c); teachers[k].f = bestFitness; // Calculate the class total cost double avgFitness = sumFitness / validStudents; classTotalCosts[k] = bestFitness + beta * avgFitness; } } } //————————————————————————————————————————————————————————————————————
The UpdateClassRanks() method is used to determine the ranks of classes based on their overall "cost", which characterizes how effective the class is. The process starts by finding the minimum and maximum cost among all valid classes. If all classes have the same value, or there are no valid classes, then the same rank of 1 is set for all.
If there are differences in cost, then these values are normalized - each cost is brought to a range from 0 to 1. After this, an inversion is performed: classes with a higher cost receive a lower rank, close to 1, and those with a lower cost receive a maximum rank equal to the number of classes.
Each rank value is then constrained to a minimum and maximum value to avoid out-of-bounds values. Ultimately, based on the results of this method, classes are given ranks based on their performance.
//———————————————————————————————————————————————————————————————————— void C_AO_CLA_l::UpdateClassRanks () { // Find the min and max costs among valid classes double minCost = DBL_MAX; double maxCost = -DBL_MAX; int validClasses = 0; for (int k = 0; k < numClasses; k++) { if (classTotalCosts [k] > -DBL_MAX) { if (classTotalCosts [k] < minCost) minCost = classTotalCosts [k]; if (classTotalCosts [k] > maxCost) maxCost = classTotalCosts [k]; validClasses++; } } if (validClasses == 0 || maxCost - minCost < 1e-10) { // All classes have the same score for (int k = 0; k < numClasses; k++) classRanks [k] = 1.0; } else { // Ranking: best classes (high cost) get low rank for (int k = 0; k < numClasses; k++) { if (classTotalCosts [k] > -DBL_MAX) { // Normalize from 0 to 1 double normalized = (classTotalCosts [k] - minCost) / (maxCost - minCost); // Inversion: the best get a rank close to 1 classRanks [k] = 1.0 + (1.0 - normalized) * (numClasses - 1.0); // Limitation classRanks [k] = MathMax (1.0, MathMin ((double)numClasses, classRanks [k])); } else { classRanks [k] = numClasses; // Worst rank for uninitialized } } } } //————————————————————————————————————————————————————————————————————
Test results
According to the test, the CLA_L algorithm delivers fairly good results.CLA_L|Competitive Learning Algorithm|198.0|3.0|0.3|0.8|2.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.6482993681242128
25 Hilly's; Func runs: 10000; result: 0.5535249826770444
500 Hilly's; Func runs: 10000; result: 0.2584959913710746
=============================
5 Forest's; Func runs: 10000; result: 0.8027208362980616
25 Forest's; Func runs: 10000; result: 0.49540442971179494
500 Forest's; Func runs: 10000; result: 0.20048686632188017
=============================
5 Megacity's; Func runs: 10000; result: 0.6353846153846153
25 Megacity's; Func runs: 10000; result: 0.2716923076923076
500 Megacity's; Func runs: 10000; result: 0.10086153846153936
=============================
All score: 3.96687 (44.08%)
The visualization shows that the algorithm initially has good search capabilities, which deteriorate due to local traps, leading to stagnation in the second half of the algorithm's operation.

CLA_L on the Hilly test function

CLA_L on the Forest test function

CLA_L on the Megacity test function
Based on the results of the algorithm's work, the CLA_L ranking table is presented for informational purposes.
| # | AO | Description | 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 | across neighbourhood search | 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 algorithm (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 | animal migration ptimization 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) evolution strategies | 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 | comet tail algorithm (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 | time evolution travel algorithm (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 | stochastic diffusion search 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 | billiards optimization algorithm 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 | archery algorithm 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 | evolution of social groups (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 | simulated isotropic annealing (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 | EOm | extremal_optimization_M | 0.76166 | 0.77242 | 0.31747 | 1.85155 | 0.99999 | 0.76751 | 0.23527 | 2.00277 | 0.74769 | 0.53969 | 0.14249 | 1.42987 | 5.284 | 58.71 |
| 13 | BBO | biogeography based optimization | 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 |
| 14 | ACS | artificial cooperative search | 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 |
| 15 | DA | dialectical algorithm | 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 |
| 16 | BHAm | black hole algorithm 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 |
| 17 | ASO | anarchy society optimization | 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 |
| 18 | RFO | royal flush optimization (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 |
| 19 | AOSm | atomic orbital search 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 |
| 20 | TSEA | turtle shell evolution algorithm (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 |
| 21 | BSA | backtracking_search_algorithm | 0.97309 | 0.54534 | 0.29098 | 1.80941 | 0.99999 | 0.58543 | 0.21747 | 1.80289 | 0.84769 | 0.36953 | 0.12978 | 1.34700 | 4.959 | 55.10 |
| 22 | DE | differential 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 |
| 23 | SRA | successful restaurateur algorithm (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 |
| 24 | CRO | chemical reaction optimization | 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 |
| 25 | BIO | blood inheritance optimization (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 |
| 26 | BSA | bird swarm algorithm | 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 |
| 27 | DEA | dolphin_echolocation_algorithm | 0.75995 | 0.67572 | 0.34171 | 1.77738 | 0.89582 | 0.64223 | 0.23941 | 1.77746 | 0.61538 | 0.44031 | 0.15115 | 1.20684 | 4.762 | 52.91 |
| 28 | HS | harmony search | 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 |
| 29 | SSG | saplings sowing and growing | 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 |
| 30 | BCOm | bacterial chemotaxis optimization 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 |
| 31 | ABO | african buffalo optimization | 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 |
| 32 | (PO)ES | (PO) evolution strategies | 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 |
| 33 | FBA | Fractal-Based Algorithm | 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 |
| 34 | TSm | tabu search 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 |
| 35 | BSO | brain storm optimization | 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 |
| 36 | WOAm | wale optimization algorithm 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 |
| 37 | AEFA | artificial electric field algorithm | 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 |
| 38 | AEO | artificial ecosystem-based optimization algorithm | 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 |
| 39 | CAm | camel algorithm 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 |
| 40 | ACOm | ant colony optimization 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 |
| 41 | CMAES | covariance_matrix_adaptation_evolution_strategy | 0.76258 | 0.72089 | 0.00000 | 1.48347 | 0.82056 | 0.79616 | 0.00000 | 1.61672 | 0.75846 | 0.49077 | 0.00000 | 1.24923 | 4.349 | 48.33 |
| 42 | BFO-GA | bacterial foraging optimization - 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 |
| 43 | SOA | simple optimization algorithm | 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 |
| 44 | ABHA | artificial bee hive algorithm | 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 |
| 45 | ACMO | atmospheric cloud model optimization | 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 |
| CLA_L | competitivelearningalgorithm | 0.64829 | 0.55352 | 0.25849 | 1.46030 | 0.80272 | 0.49540 | 0.20048 | 1.49860 | 0.63538 | 0.27169 | 0.10086 | 1.00793 | 3.967 | 44.08 | |
| RW | random walk | 0.48754 | 0.32159 | 0.25781 | 1.06694 | 0.37554 | 0.21944 | 0.15877 | 0.75375 | 0.27969 | 0.14917 | 0.09847 | 0.52734 | 2.348 | 26.09 | |
Summary
The competitive learning algorithm (CLA_L) demonstrates average performance in solving standard optimization problems. Analysis of the algorithm's operation revealed a characteristic two-phase dynamic: an active research phase in the initial iterations and a premature stagnation phase in the second half of the optimization process.
Dividing the population into classes ensures good coverage of the search space in the early stages. Each class explores its own area, which contributes to a global search. The educational model makes the algorithm clear and easy to interpret. The concepts of teachers, students and different types of learning are natural to understand. Learning factors that depend on class rank should theoretically provide a balance between exploration and exploitation. The combination of three types of learning (teacher learning, personal learning, and confirmatory learning) creates the potential to avoid local optima. Despite the diversification mechanisms, the algorithm is prone to getting stuck in local optima.
The CLA algorithm presents an interesting concept of applying an educational metaphor to optimization problems. Despite the innovative approach and good initial performance, the algorithm requires significant modifications to be competitive with modern metaheuristics. The main challenge remains to ensure a balance between exploration and exploitation throughout the optimization process.

Figure 2. Color coding of the algorithms by test

Figure 3. Histogram of algorithm testing results (scale from 0 to 100, the higher the better, where 100 is the maximum possible theoretical result, in the archive there is a script for calculating the rating table)
CLA_L pros and cons:
Pros:
- Fast.
Cons:
- A large number of external parameters.
- Prone to getting stuck in local optima.
The article is accompanied by an archive with the current versions of the algorithm codes. The author of the article is not responsible for the absolute accuracy in the description of canonical algorithms. Changes have been made to many of them to improve search capabilities. The conclusions and judgments presented in the articles are based on the results of the experiments.
Programs used in the article
| # | Name | Type | Description |
|---|---|---|---|
| 1 | #C_AO.mqh | Include | Parent class of population optimization algorithms |
| 2 | #C_AO_enum.mqh | Include | Enumeration of population optimization algorithms |
| 3 | TestFunctions.mqh | Include | Library of test functions |
| 4 | TestStandFunctions.mqh | Include | Test stand function library |
| 5 | Utilities.mqh | Include | Library of auxiliary functions |
| 6 | CalculationTestResults.mqh | Include | Script for calculating results in the comparison table |
| 7 | Testing AOs.mq5 | Script | The unified test stand for all population optimization algorithms |
| 8 | Simple use of population optimization algorithms.mq5 | Script | A simple example of using population optimization algorithms without visualization |
| 9 | Test_AO_CLA_L.mq5 | Script | CLA_L test stand |
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/18857
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is prohibited.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
The Repository Pattern in MQL5: Abstracting Trade History Access for Testable EA Logic
Gaussian Processes in Machine Learning (Part 1): Classification Model in MQL5
MQL5 Wizard Techniques you should know (Part 96): Using Wavelet Thresholding and LSTM Network in a Custom Money Management Class
Neural Networks in Trading: Actor—Director—Critic (Final Part)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use