Русский Español Português
preview
Atomic Orbital Search (AOS) algorithm: Modification

Atomic Orbital Search (AOS) algorithm: Modification

MetaTrader 5Tester | 1 July 2025, 12:25
1 134 5
Andrey Dik
Andrey Dik

Contents

  1. Introduction
  2. Implementation of the algorithm
  3. An example of using the C_AO class
  4. Test results


Introduction

In the first part of the article we examined the basics of the AOS (Atomic Orbital Search) algorithm inspired by the atomic orbital model and its underlying mechanisms. We discussed how the algorithm uses probability distributions and interaction dynamics to find optimal solutions to complex optimization problems.

In the second part of the article, we will focus on modifying the AOS algorithm, since we cannot pass by such an outstanding idea without trying to improve it. We will analyze the concept of improving the algorithm, paying special attention to the specific operators that are inherent to this method and can improve its efficiency and adaptability.

Working on the AOS algorithm has opened up many interesting aspects for me regarding its methods of searching the solution space. During the research, I also came up with a number of ideas on how this interesting algorithm could be improved. In particular, I focused on reworking existing methods that can improve the performance of the algorithm by improving its ability to explore complex solution spaces. We will consider how these improvements can be integrated into the existing structure of the AOS algorithm to make it an even more powerful tool for solving optimization problems. Thus, our goal is not only to analyze existing mechanisms, but also to propose other approaches that can significantly expand the capabilities of the AOS algorithm.


Implementation of the algorithm

In the previous article, we took a detailed look at the key components of the AOS algorithm. As you might remember, in this algorithm, the population is considered as a molecule, and the admissible region of coordinates, in which the search for optimal solutions is carried out, is represented as an atom. Each atom is made up of different layers that help arrange and direct the search.

The specific coordinate values that we obtain during the optimization can be interpreted as electrons. These electrons, being within the atom, represent possible solutions to one of the parameters of the problem we are optimizing. Thus, each molecule (population) strives to find optimal values (electrons) within a given region (atom).

In the original version of the AOS algorithm, the BEk layer energy is defined as the arithmetic mean of the energy of electrons in the layer, and the bond BSk is defined as the arithmetic mean of their coordinates. The BEk energy is used to compare with the energy of the electrons to determine the mode of their subsequent movement. The BSk connection is used to calculate the increment to the position of electrons as the difference between the best position of electrons LEk in the layer and the BSk connection according to the following equation: Xki[t+1] = Xkit + αi × (βi × LEk − γi × BSk).

I propose to abandon the BSk average position of electrons in favor of the personal best position of the electron. Thus, the electron will move towards the best solution in its layer based on its individual achievement, not on the average solution across the layer. Moreover, the two βi and γi random components seem redundant since there is already an external αi random component. This will reduce the time for generating random numbers in this equation by three times, without losing physical meaning.

Now let's look at the structure that describes a layer in an atom. Elements removed from the code are highlighted in red:

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

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

Let's consider the CalcLayerParams method code, which calculates layer characteristics such as energy and connectivity. Strings highlighted in red will be removed as they are no longer needed. As you might remember, this method plays a key role in the AOS search strategy, which aims to prevent the algorithm from getting stuck in local traps. Since the energy level in the layers does not depend on their location (the energy decreases from the center to the outer layers of the atom), but is determined by the presence of significant local extremes (the outer layer can have energy exceeding the inner ones), the layers serve to correct the movement of electrons in the search space.

The random number of layers at each epoch helps to combat the algorithm getting stuck in local traps, preventing electrons from stagnating in only one of the layers. The modified version also eliminates the need to calculate the average energy over the entire atom, so we will remove the corresponding lines.

AOS layers

Figure 1. The difference in direction and size of the e electron displacement depending on the number of layers in the atom

Figure 1 illustrates the differences in the behavior of electrons in atoms with different numbers of layers in the AOS algorithm. The top panel shows a three-layer atom where the electron is located in the layer L1 with the B1 objective function value and moves towards the LEk1 local best value. The lower part of the figure illustrates an atom with two layers, where the electron is also in layer L1 and moves towards the local best value LEk1 with the B1 objective function value (in the case of three layers this would be the point LEk2).

Key elements in the figure:

  • B0, B1, B2 — designations of local values of the objective function for the corresponding layers,
  • LEk0, LEk1, LEk2 — best solutions in the corresponding layers,
  • L0, L1, L2 — atom layers,
  • e — electron,
  • MIN, MAX — boundaries of the outer layers of atoms (boundary conditions for the optimized parameters of the problem).
//——————————————————————————————————————————————————————————————————————————————
// Calculate parameters for each layer
void C_AO_AOS::CalcLayerParams ()
{
  double energy;

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

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

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

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

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

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

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

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

To update the best individual solutions, add the code to the Revision method of the modified C_AO_AOSm version.

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

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

    // Update the personal best solution
    if (a [i].f > a [i].fB)
    {
      a [i].fB = a [i].f;
      ArrayCopy (a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }

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

In the UpdateElectrons method, remove the β and γ variables since they are not needed to generate the corresponding random numbers. In addition, exclude deletion of the electron increment by the number of layers in the case of movement towards the global solution. Frankly speaking, the authors' solution seems controversial, and the physical meaning of this approach is not entirely clear. Perhaps the authors wanted to make the degree of electron movement towards the global solution variable, changing it depending on the number of layers: the fewer layers, the more intense the movement should be (although my experiments showed that this is not the case).

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

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

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

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

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

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

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

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

Additionally, in the UpdateElectrons method of the C_AO_AOSm class, instead of randomly scattering the electron across the search space, we implement the movement of the electron to the core center with some probability. In essence, this means replacing the value of some coordinate with the value of the global solution, which should improve the combinatorial properties of the algorithm. Random scattering was intended to provide diversity in the population of solutions, but this property ensured the distribution of electrons according to a lognormal distribution, where there was a non-zero probability of an electron hitting any point in space while moving.

Changes in the electron movement equations are displayed in green. Now the increment is calculated as the difference between the local best solution of the layer and the individual best solution of the electron.

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

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

      if (φ < PR)
      {
        // Random jump to center
        newPos = cB [c];
      }
      else
      {
        lID = electrons [p].layerID [c];

        α = u.RNDfromCI (-1.0, 1.0);

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

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

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

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

The DistributeParticles method distributes electrons in the search space using lognormal distribution for each coordinate. For each particle and each coordinate, a function is called that generates a position given the given parameters (average, minimum and maximum values, peak), and then an additional function is applied to adjust the position within the given range.

//——————————————————————————————————————————————————————————————————————————————
// Distribution of particles in the search space
void C_AO_AOS::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Use log-normal distribution to position particles
      a [i].c [c] = u.LognormalDistribution (cB [c], rangeMin [c], rangeMax [c], peakPosition);
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Change the electron distribution to normal. This distribution uses a standard deviation of 8. Although this parameter could have been made external to the algorithm, I chose not to do so. Smaller values encourage a wider exploration of the search space, while higher values improve the accuracy of convergence when refining the global solution.

//——————————————————————————————————————————————————————————————————————————————
// Distribution of particles in the search space
void C_AO_AOSm::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Use a Gaussian distribution to position particles
      a [i].c [c] = u.GaussDistribution (cB [c], rangeMin [c], rangeMax [c], 8);
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

All changes made to the original version of the AOS algorithm were analyzed in order to improve its efficiency. Since significant changes were made to the logic of the search strategy, the modified version of the algorithm can be designated by the letter "m". From now on, only the modified version will be presented in the rating table - AOSm.


An example of using the C_AO class

Since all population optimization algorithms discussed earlier are inherited from the general C_AO class, this allows them to be used uniformly and with minimal effort to solve various problems that require the selection of optimal parameters. The example below shows a script that performs optimization of the objective function:

1. At the beginning of the script, you can choose which optimization algorithm to use. If nothing is selected, the script will report an error and stop.
2. Setting up parameters. The script defines how many times the function will be run, how many parameters need to be optimized, the size of the solution group, and how many iterations will be performed.
3. Value limits. Minimum and maximum values are set for each parameter (in this example, from -10 to 10).
4. The script starts optimization:

  • It generates solutions (sets of parameters) and checks how good they are using a special function (the objective function).
  • At each iteration, the algorithm updates its solutions based on which ones performed best.

5. Results. After the optimization is complete, the script outputs information about which algorithm was used, what the best value was found, and how many times the function was launched.
6. The objective function is an abstract optimization problem (in this example, solving the problem of finding the global maximum of an inverted parabola is used) that takes parameters and returns a score for their quality.

#property script_show_inputs                           // Specify that the script will show the inputs in the properties window

#include <Math\AOs\PopulationAO\#C_AO_enum.mqh>        // Connect the library for handling optimization algorithms

input E_AO AOexactly = NONE_AO;                        // Parameter for selecting the optimization algorithm, default is NONE_AO

//——————————————————————————————————————————————————————————————————————————————
void OnStart()
{
  //----------------------------------------------------------------------------
  int numbTestFuncRuns = 10000;                        // Total number of function runs
  int params           = 1000;                         // Number of parameters for optimization
  int popSize          = 50;                           // Population size for optimization algorithm
  int epochCount       = numbTestFuncRuns / popSize;   // Total number of epochs (iterations) for optimization
  
  
  double rangeMin [], rangeMax [], rangeStep [];       // Arrays for storing the parameters' boundaries and steps
  
  ArrayResize (rangeMin,  params);                     // Resize 'min' borders array
  ArrayResize (rangeMax,  params);                     // Resize 'max' borders array
  ArrayResize (rangeStep, params);                     // Resize the steps array
  
  // Initialize the borders and steps for each parameter
  for (int i = 0; i < params; i++)
  {
    rangeMin  [i] = -10;                               // Minimum value of the parameter
    rangeMax  [i] =  10;                               // Maximum value of the parameter
    rangeStep [i] =  DBL_EPSILON;                      // Parameter step
  }
  
  //----------------------------------------------------------------------------
  C_AO *ao = SelectAO (AOexactly);                     // Select an optimization algorithm
  if (ao == NULL)                                      // Check if an algorithm has been selected
  {
    Print ("AO not selected...");                         // Error message if no algorithm is selected
    return;
  }
  
  ao.params [0].val = popSize;                         // Assigning population size....
  ao.SetParams ();                                     //... (optional, then default population size will be used)
  
  
  ao.Init (rangeMin, rangeMax, rangeStep, epochCount); // Initialize the algorithm with given boundaries and number of epochs
  
  // Main loop by number of epochs
  for (int epochCNT = 1; epochCNT <= epochCount; epochCNT++)
  {
    ao.Moving ();                                      // Execute one epoch of the optimization algorithm

    // Calculate the value of the objective function for each solution in the population
    for (int set = 0; set < ArraySize (ao.a); set++)
    {
      ao.a [set].f = ObjectiveFunction (ao.a [set].c); // Apply the objective function to each solution
    }

    ao.Revision ();                                    // Update the population based on the results of the objective function
  }
  
  //----------------------------------------------------------------------------
  // Output the algorithm name, best result and number of function runs
  Print (ao.GetName (), ", best result: ", ao.fB, ", number of function launches: ", numbTestFuncRuns);
  
  delete ao;                                           // Release the memory occupied by the algorithm object
}
//——————————————————————————————————————————————————————————————————————————————

//——————————————————————————————————————————————————————————————————————————————
// Definition of the user's objective function, in this case as an example - a paraboloid, F(Xn) ∈ [0.0; 1.0], X ∈ [-10.0; 10.0], maximization
double ObjectiveFunction (double &x [])
{
  double sum = 0.0;  // Variable for accumulation of the result

  // Loop through all parameters
  for (int i = 0; i < ArraySize (x); i++)
  {
    // Check if the parameter is in the allowed range
    if (x [i] < -10.0 || x [i] > 10.0) return 0.0;  // If the parameter is out of range, return 0
    sum += (-x [i] * x [i] + 100.0) * 0.01;         // Calculate the value of the objective function
  }
  
  return sum /= ArraySize (x);
}
//——————————————————————————————————————————————————————————————————————————————


Test results

Let's move on to testing the modified version of the algorithm.

AOS|Atomic Orbital Search|50.0|10.0|20.0|0.1|
=============================
5 Hilly's; Func runs: 10000; result: 0.8023218355650774
25 Hilly's; Func runs: 10000; result: 0.7044908398821188
500 Hilly's; Func runs: 10000; result: 0.3102116882841442
=============================
5 Forest's; Func runs: 10000; result: 0.8565993699987462
25 Forest's; Func runs: 10000; result: 0.6945107796904211
500 Forest's; Func runs: 10000; result: 0.21996085558228406
=============================
5 Megacity's; Func runs: 10000; result: 0.7461538461538461
25 Megacity's; Func runs: 10000; result: 0.5286153846153846
500 Megacity's; Func runs: 10000; result: 0.1435846153846167
=============================
All score: 5.00645 (55.63%)

As you can see, the results of the modified version have improved significantly compared to the previous results of the original version, where the overall score was 3.00488 (33.39%). This improvement becomes apparent when analyzing the visualization, which shows not only improved convergence, but also more detailed elaboration of significant extremes.

One of the key aspects worth noting is the effect of "clumping" of solutions on individual coordinates. This phenomenon is observed in both the original and modified versions, which highlights the characteristic feature of AOS algorithms. Clumping of solutions may indicate that the algorithm is effective in finding areas where potential optimal solutions are located.

Hilly

AOSm on the Hilly test function

Forest

AOSm on the Forest test function

Megacity

  AOSm on the Megacity test function

The modified version of the Atomic Orbital Search (AOS) algorithm has significantly improved its performance compared to the original version and now reaches more than 55% of the maximum possible value. This is a truly impressive result! In the rating table, the algorithm occupies 12 th place, which indicates very decent results.

# 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 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
7 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
8 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
9 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
10 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
11 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
12 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
13 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
14 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
15 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
16 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
17 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
18 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
19 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
20 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
21 (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
22 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
23 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
24 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
25 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
26 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
27 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
28 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
29 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
30 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
31 ASHA artificial showering algorithm 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
32 ASBO adaptive social behavior optimization 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
33 MEC mind evolutionary computation 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
34 IWO invasive weed optimization 0.72679 0.52256 0.33123 1.58058 0.70756 0.33955 0.07484 1.12196 0.42333 0.23067 0.04617 0.70017 3.403 37.81
35 Micro-AIS micro artificial immune system 0.79547 0.51922 0.30861 1.62330 0.72956 0.36879 0.09398 1.19233 0.37667 0.15867 0.02802 0.56335 3.379 37.54
36 COAm cuckoo optimization algorithm M 0.75820 0.48652 0.31369 1.55841 0.74054 0.28051 0.05599 1.07704 0.50500 0.17467 0.03380 0.71347 3.349 37.21
37 SDOm spiral dynamics optimization M 0.74601 0.44623 0.29687 1.48912 0.70204 0.34678 0.10944 1.15826 0.42833 0.16767 0.03663 0.63263 3.280 36.44
38 NMm Nelder-Mead method M 0.73807 0.50598 0.31342 1.55747 0.63674 0.28302 0.08221 1.00197 0.44667 0.18667 0.04028 0.67362 3.233 35.92
39 FAm firefly algorithm M 0.58634 0.47228 0.32276 1.38138 0.68467 0.37439 0.10908 1.16814 0.28667 0.16467 0.04722 0.49855 3.048 33.87
40 GSA gravitational search algorithm 0.64757 0.49197 0.30062 1.44016 0.53962 0.36353 0.09945 1.00260 0.32667 0.12200 0.01917 0.46783 2.911 32.34
41 BFO bacterial foraging optimization 0.61171 0.43270 0.31318 1.35759 0.54410 0.21511 0.05676 0.81597 0.42167 0.13800 0.03195 0.59162 2.765 30.72
42 ABC artificial bee colony 0.63377 0.42402 0.30892 1.36671 0.55103 0.21874 0.05623 0.82600 0.34000 0.14200 0.03102 0.51302 2.706 30.06
43 BA bat algorithm 0.59761 0.45911 0.35242 1.40915 0.40321 0.19313 0.07175 0.66810 0.21000 0.10100 0.03517 0.34617 2.423 26.93
44 AAA algae adaptive algorithm 0.50007 0.32040 0.25525 1.07572 0.37021 0.22284 0.16785 0.76089 0.27846 0.14800 0.09755 0.52402 2.361 26.23
45 SA simulated annealing 0.55787 0.42177 0.31549 1.29513 0.34998 0.15259 0.05023 0.55280 0.31167 0.10033 0.02883 0.44083 2.289 25.43


Summary

In this article, a modified version of the atomic orbital search (AOSm) algorithm was presented, in which I abandoned the BSk average position of electrons in the atom layers in favor of the individual best position of each electron. This allowed electrons to move more efficiently towards the best solution in their layer, based on individual achievement rather than an average value. In addition, two random components βi and γi were excluded, which reduced the time for generating random numbers by three times, without losing the physical meaning of the algorithm.

In the UpdateElectrons method, unnecessary variables have been removed and divisions of the electron increment by the number of layers when moving to the global solution have been eliminated. While the authors of the original versions may have intended for the degree of movement to be variable, my experiments have shown that this does not provide significant benefits.

Changes were also made to the UpdateElectrons method in the C_AO_AOSm class - the random scattering of an electron was replaced with a movement to the center of the core with a certain probability. This increased the combinatorial properties of the algorithm, allowing electrons to more accurately target the global solution. The lognormal distribution was also replaced by a normal one, which increased the accuracy of convergence when refining the global solution.

The results of the modified version of AOSm showed significant improvement, with an overall score exceeding 55% of the maximum possible, which confirms the high efficiency and competitiveness of the algorithm. AOSm ranks 12 th in the ranking table, which shows its significant achievements among other optimization methods.

One of the most noticeable aspects of AOSm is the improvement in convergence, which became evident when visualizing the results. The algorithm works out significant extremes in more detail and demonstrates the ability to effectively search for optimal solutions in complex multidimensional spaces. The "clumping" effect of solutions observed in both the original and modified versions highlights the ability of the algorithm to find and focus on areas with potential optima, which is especially useful in problems with high dimensionality and complex structure.

An additional plus to the advantages of the modified version is the reduction in the number of external parameters, which simplifies its use and configuration. However, for all the algorithms presented earlier in the articles, I have selected the optimal external parameters to achieve maximum efficiency in complex testing on various types of test tasks, so all the algorithms are ready for use and do not require any configuration. The article demonstrates that sometimes the smallest changes in optimization algorithms can dramatically change their search properties, while significant changes in the logic of the search strategy may not bring any noticeable changes in the results. Of course, in my articles, I share the methods that really improve the efficiency of optimization.

Tab

Figure 2. Color gradation of algorithms according to relevant tests Results greater than or equal to 0.99 are highlighted in white

chart

Figure 3. The histogram of algorithm test results (on a scale from 0 to 100, the more the better,

where 100 is the maximum possible theoretical result, the archive features a script for calculating the rating table)


AOSm pros and cons:

Pros:

  1. Good performance on various tasks.
  2. Small number of external parameters.
  3. Good scalability.
  4. Balanced search by both local and global extremes.

Cons:

  1. Quite a complex implementation.
  2. Average accuracy of convergence on smooth functions compared to other algorithms.

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
AO_AOSm_AtomicOrbitalSearch.mqh
Include AOSm algorithm class
10
Test_AO_AOSm.mq5
Script
AOSm test stand

Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/16315

Attached files |
AOSm.zip (139.64 KB)
Last comments | Go to discussion (5)
Evgeniy Chernish
Evgeniy Chernish | 15 Nov 2024 at 11:51

Thanks for the article!

I sat for a while yesterday and today on the Hilly function and alglib methods. Here are my thoughts.

In order to find the maximum of this function, especially when the number of parameters is 10 and more, it is pointless to apply gradient methods, this is the task of combinatorial methods of optimisation. Gradient methods just instantly get stuck in the local extremum. And it does not matter how many times to restart from a new point of the parameter space, the chance to get to the right region of space from which the gradient method instantly finds a solution tends to zero as the number of parameters increases.

For example, the point of space from which lbfgs or CG for 2(two) iterations find the maximum for any number of parameters is {x = -1,2 , y = 0.5}.


lbfgs

But the chance to get into this region as I have already said is simply zero. It must be a hundred years to generate random numbers.

Therefore, it is necessary to somehow combine the genetic algorithms presented in the article (so that they could do reconnaissance and reduce the search space) with gradient methods that would quickly find the extremum from a more favourable point.

Andrey Dik
Andrey Dik | 15 Nov 2024 at 16:25
Evgeniy Chernish #:

Thank you for the article!

Thank you for your feedback.

In order to find the maximum of a given function, especially when the number of parameters is 10 or more, it is pointless to use gradient methods.

Yes, that's right.

This is the task of combinatorial methods of optimisation.

Combinatorial methods, such as the classical "ant", are designed for problems like the "travelling salesman problem" and the "knapsack problem", i.e. they are designed for discrete problems with a fixed step (graph edge). For multidimensional "continuous" problems, these algorithms are not designed at all, for example, for tasks such as training neural networks. Yes, combinatorial properties are very useful for stochastic heuristic methods, but they are not the only and sufficient property for successful solution of such near-real test problems. The search strategies themselves in the algo are also important.

Gradient-based ones simply get stuck in a local extremum instantly. And it doesn't matter how many times to restart from a new point of the parameter space, the chance to get to the right region of the space from which the gradient method instantly finds a solution tends to zero as the number of parameters increases.

Yes, it does.

But the chance to get to this region, as I have already said, is simply zero. It would take about a hundred years to generate random numbers.

Yes, that's right. In low-dimensional spaces (1-2) it is very easy to get into the vicinity of the global, simple random generators can even work for this. But everything changes completely when the dimensionality of the problem grows, here search properties of algorithms start to play an important role, not Mistress Luck.

So we need to somehow combine genetic algorithms presented in the article (that they would do exploration, reduce the search space) with gradient methods, which would then quickly find the extremum from a more favourable point.

"genetic" - you probably mean "heuristic". Why "the fish needs an umbrella" and "why do we need a blacksmith? We don't need a blacksmith.")))) There are efficient ways to solve complex multidimensional in continuous space problems, which are described in articles on population methods. And for classical gradient problems there are their own tasks - one-dimensional analytically determinable problems (in this they have no equal, there will be fast and exact convergence).

And, question, what are your impressions of the speed of heuristics?

SZY:

Oh, how many wonderful discoveries

Prepare the spirit of enlightenment

And experience, the son of errors,

And genius, the friend of paradoxes,

And chance, God's inventor.


ZZZY. One moment. In an unknown space of search it is never possible to know at any moment of time or step of iteration that it is actually a really promising direction towards the global. Therefore, it is impossible to scout first and refine later. Only whole search strategies can work, they either work well or poorly. Everyone chooses the degree of "goodness" and "suitability for the task" himself, for this purpose a rating table is kept to choose an algorithm according to the specifics of the task.

Evgeniy Chernish
Evgeniy Chernish | 15 Nov 2024 at 16:53
Andrey Dik #:
Yes, that's right. In low-dimensional spaces (1-2) it is very easy to get into the neighbourhood of a global, simple random generators can even be useful for this. But everything changes completely when the dimensionality of the problem grows, here search properties of algorithms, not Lady Luck, start to play an important role.

So they fail

Andrey Dik #:
And, question, what are your impressions of the speed of heuristics?

Despite the fact that they work fast. The result for 1000 parameters something about 0.4.

That's why I intuitively thought that it makes sense to combine GA and gradient methods to get to the maximum. Otherwise, separately they will not solve your function. I haven't tested it in practice.


P.S. I still think that this function is too thick, in real tasks (training of neural networks, for example) there are no such problems, although there too the error surface is all in local minima.

Andrey Dik
Andrey Dik | 15 Nov 2024 at 18:47
Evgeniy Chernish #:

1. They're not doing a good job

2. even though they work fast. The result for 1000 parameters is something around 0.4.

3. That's why I intuitively thought that it makes sense to combine GA and gradient methods to get to the maximum. Otherwise, separately they won't solve your function. I haven't tested it in practice.

4. P.S. I still think that this function is too thick, in real tasks (training of neural networks, for example) there are no such problems, although there too the error surface is all in local minima.

1. What do you mean "they can't cope"? There is a limit on the number of accesses to the target function, the one who showed a better result is the one who can't cope)). Should we increase the number of allowed accesses? Well, then the more agile and adapted to complex functions will come to the finish line anyway. Try to increase the number of references, the picture will not change.

2. Yes. And some have 0.3, and others 0.2, and others 0.001. Better are those who showed 0.4.

3. It won't help, intuitively hundreds of combinations and variations have been tried and re-tried. Better is the one that shows better results for a given number of epochs (iterations). Increase the number of references to the target, see which one reaches the finish line first.

4. If there are leaders on difficult tasks, do you think that on easy tasks leaders will show worse results than outsiders? This is not the case, to put it mildly. I am working on a more "simple" but realistic task of grid training. I will share the results as always. It will be interesting.


Just experiment, try different algorithms, different tasks, don't get stuck on one thing. I have tried to provide all the tools for this.

Evgeniy Chernish
Evgeniy Chernish | 15 Nov 2024 at 19:18
Andrey Dik #:

1. What do you mean "fail"? There is a limit on the number of accesses to the target function, the one who has shown the best result is the one who can't cope)). Should we increase the number of allowed accesses? Well, then the more agile and adapted to complex functions will come to the finish line anyway. Try increasing the number of references, the picture will not change.

2. Yes. And some have 0.3, and others 0.2, and others 0.001. Better are those who showed 0.4.

3. It won't help, intuitively hundreds of combinations and variations have been tried and re-tried. Better is the one that shows better results for a given number of epochs (iterations). Increase the number of references to the target, see which one reaches the finish line first.

4. If there are leaders on difficult tasks, do you think that on easy tasks leaders will show worse results than outsiders? This is not the case, to put it mildly. I am working on a more "simple" but realistic task of grid training. I will share the results as always. It will be interesting.


Just experiment, try different algorithms, different tasks, don't fixate on one thing. I have tried to provide all the tools for this.

I am experimenting,

ANS

About the realistic task it is right to test algorithms on tasks close to combat.

It's doubly interesting to see how genetic networks will be trained.

Automating Trading Strategies in MQL5 (Part 21): Enhancing Neural Network Trading with Adaptive Learning Rates Automating Trading Strategies in MQL5 (Part 21): Enhancing Neural Network Trading with Adaptive Learning Rates
In this article, we enhance a neural network trading strategy in MQL5 with an adaptive learning rate to boost accuracy. We design and implement this mechanism, then test its performance. The article concludes with optimization insights for algorithmic trading
Data Science and ML (Part 45): Forex Time series forecasting using PROPHET by Facebook Model Data Science and ML (Part 45): Forex Time series forecasting using PROPHET by Facebook Model
The Prophet model, developed by Facebook, is a robust time series forecasting tool designed to capture trends, seasonality, and holiday effects with minimal manual tuning. It has been widely adopted for demand forecasting and business planning. In this article, we explore the effectiveness of Prophet in forecasting volatility in forex instruments, showcasing how it can be applied beyond traditional business use cases.
MQL5 Wizard Techniques you should know (Part 72): Using Patterns of MACD and the OBV with Supervised Learning MQL5 Wizard Techniques you should know (Part 72): Using Patterns of MACD and the OBV with Supervised Learning
We follow up on our last article, where we introduced the indicator pair of the MACD and the OBV, by looking at how this pairing could be enhanced with Machine Learning. MACD and OBV are a trend and volume complimentary pairing. Our machine learning approach uses a convolution neural network that engages the Exponential kernel in sizing its kernels and channels, when fine-tuning the forecasts of this indicator pairing. As always, this is done in a custom signal class file that works with the MQL5 wizard to assemble an Expert Advisor.
From Novice to Expert: Animated News Headline Using MQL5 (III) — Indicator Insights From Novice to Expert: Animated News Headline Using MQL5 (III) — Indicator Insights
In this article, we’ll advance the News Headline EA by introducing a dedicated indicator insights lane—a compact, on-chart display of key technical signals generated from popular indicators such as RSI, MACD, Stochastic, and CCI. This approach eliminates the need for multiple indicator subwindows on the MetaTrader 5 terminal, keeping your workspace clean and efficient. By leveraging the MQL5 API to access indicator data in the background, we can process and visualize market insights in real-time using custom logic. Join us as we explore how to manipulate indicator data in MQL5 to create an intelligent and space-saving scrolling insights system, all within a single horizontal lane on your trading chart.