Русский
preview
Algoritmo de busca orbital atômica — Atomic Orbital Search (AOS): Modificação

Algoritmo de busca orbital atômica — Atomic Orbital Search (AOS): Modificação

MetaTrader 5Testador | 30 abril 2025, 07:22
69 0
Andrey Dik
Andrey Dik

Conteúdo

  1. Introdução
  2. Implementação do algoritmo
  3. Exemplo de uso dos algoritmos da classe C_AO
  4. Resultados dos testes


Introdução

Na primeira parte do artigo, examinamos em detalhes o algoritmo AOS (Atomic Orbital Search), seus fundamentos inspirados no modelo orbital atômico e os mecanismos que sustentam seu funcionamento. Discutimos como o algoritmo utiliza distribuições probabilísticas e a dinâmica das interações para buscar soluções ótimas em problemas de otimização complexos.

Na segunda parte do artigo, focaremos na modificação do algoritmo AOS, pois não podemos ignorar uma ideia tão notável sem buscar aprimorá-la. Analisaremos o conceito de melhoria do algoritmo, com especial atenção para os operadores específicos que pertencem a este método e que podem aumentar sua eficiência e adaptabilidade.

Trabalhar no algoritmo AOS abriu para mim muitos aspectos interessantes relacionados aos seus métodos de busca no espaço de soluções. Durante a pesquisa, também cheguei a várias ideias sobre como melhorar esse algoritmo interessante. Em particular, concentrei-me na reformulação dos métodos existentes que podem melhorar o desempenho do algoritmo, aprimorando sua capacidade de explorar espaços de soluções complexos. Veremos como essas melhorias podem ser integradas à estrutura existente do algoritmo AOS, tornando-o uma ferramenta ainda mais poderosa para resolver problemas de otimização. Assim, nosso objetivo é não apenas analisar os mecanismos existentes, mas também propor novas abordagens que podem ampliar significativamente as capacidades do algoritmo AOS.


Implementação do algoritmo

No artigo anterior, examinamos em detalhes os componentes-chave do algoritmo AOS. Lembramos que neste algoritmo a população é considerada como uma molécula, e a área admissível de coordenadas, onde ocorre a busca por soluções ótimas, é representada como um átomo. Cada átomo é composto por diferentes camadas, que ajudam a organizar e direcionar a busca.

Os valores específicos obtidos em cada coordenada no processo de otimização podem ser interpretados como elétrons. Esses elétrons, localizados dentro do átomo, representam possíveis soluções para um dos parâmetros do problema em questão. Assim, cada molécula (população) busca encontrar os valores ótimos (elétrons) dentro da área definida (átomo).

Na versão original do algoritmo AOS, a energia da camada BEk é definida como a média aritmética da energia dos elétrons na camada, e a ligação BSk é definida como a média aritmética de suas coordenadas. A energia BEk é usada para comparar com a energia dos elétrons, a fim de determinar a maneira de seu deslocamento subsequente. A ligação BSk serve para calcular o incremento na posição dos elétrons, ou seja, a diferença entre a melhor posição dos elétrons, LEk, na camada, e a ligação BSk, pela seguinte fórmula: Xki[t+1] = Xkit + αi × (βi × LEk − γi × BSk).

Proponho abandonar a posição média dos elétrons BSk em favor da melhor posição individual de cada um. Dessa forma, o elétron se moverá em direção à melhor solução em sua camada, com base em seu próprio desempenho, e não em uma solução média da camada. Além disso, os dois componentes aleatórios βi e γi parecem ser redundantes, já que já existe um componente aleatório externo αi. Isso permitirá reduzir o tempo de geração de números aleatórios nesta fórmula em três vezes, sem que o sentido físico seja perdido.

Agora vamos analisar a estrutura que descreve a camada no átomo. Vermelho são destacados os elementos que serão removidos do código:

//——————————————————————————————————————————————————————————————————————————————
struct S_Layer
{
    int    pc;  // счетчик частиц
    double BSk; // состояние связи
    double BEk; // энергия связи
    double LEk; // минимальная энергия

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

Vamos analisar o código do método "CalcLayerParams", responsável pelo cálculo das características das camadas, como energia e ligação. As linhas destacadas em vermelho serão removidas, pois não serão mais necessárias. Lembramos que este método desempenha um papel fundamental na estratégia de busca do AOS, voltada para evitar que o algoritmo fique preso em armadilhas locais. Como o nível de energia nas camadas não depende de sua localização (a energia diminui do centro para as camadas externas do átomo), mas é determinado pela presença de extremos locais significativos (a camada externa pode ter energia superior às internas), as camadas servem para ajustar o movimento dos elétrons no espaço de busca.

A quantidade aleatória de camadas a cada época ajuda a combater o aprisionamento do algoritmo em armadilhas locais, impedindo que os elétrons fiquem presos apenas em uma camada. Na versão modificada, também não será mais necessário calcular a energia média de todo o átomo, portanto removeremos as linhas correspondentes.

AOS layers

Figura 1. Diferenças na direção e no tamanho do deslocamento do elétron e em função da quantidade de camadas no átomo

A Figura 1 ilustra as diferenças no comportamento dos elétrons em átomos com diferentes quantidades de camadas no algoritmo AOS. A parte superior mostra um átomo com três camadas, no qual o elétron está na camada L1 com o valor da função objetivo B1 e se move em direção ao melhor valor local LEk1. A parte inferior da figura ilustra um átomo com duas camadas, onde o elétron também está na camada L1 e se move em direção ao melhor valor local LEk1, com o valor da função objetivo B1 (no caso de três camadas, esse seria o ponto LEk2).

Elementos-chave na figura:

  • B0, B1, B2 — designações dos valores locais da função objetivo para as respectivas camadas,
  • LEk0, LEk1, LEk2 — melhores soluções nas respectivas camadas,
  • L0, L1, L2 — camadas no átomo,
  • e — elétron,
  • MIN, MAX — limites das camadas externas dos átomos (condições de fronteira para os parâmetros do problema de otimização).
//——————————————————————————————————————————————————————————————————————————————
// Расчет параметров для каждого слоя
void C_AO_AOS::CalcLayerParams ()
{
  double energy;

  // Обработка каждой координаты (атома)
  for (int c = 0; c < coords; c++)
  {
    atoms [c].Init (maxLayers);

    // Обработка каждого слоя
    for (int L = 0; L < currentLayers [c]; L++)
    {
      energy = -DBL_MAX;

      // Обработка каждого электрона
      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];
          }
        }
      }

      // Расчет средних значений для слоя
      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;
      }
    }
  }

  // Расчет общего состояния связей
  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;
  }
}
//——————————————————————————————————————————————————————————————————————————————

Para atualizar as melhores soluções individuais, adicionaremos código ao método "Revision" na classe da versão modificada "C_AO_AOSm".

//——————————————————————————————————————————————————————————————————————————————
// Метод пересмотра лучших решений
void C_AO_AOSm::Revision ()
{
  int bestIndex = -1;

  // Поиск лучшего решения в текущей итерации
  for (int i = 0; i < popSize; i++)
  {
    // Обновление глобального лучшего решения
    if (a [i].f > fB)
    {
      fB = a [i].f;
      bestIndex = i;
    }

    // Обновление персонального лучшего решения
    if (a [i].f > a [i].fB)
    {
      a [i].fB = a [i].f;
      ArrayCopy (a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }

  // Обновление лучших координат если найдено лучшее решение
  if (bestIndex != -1) ArrayCopy (cB, a [bestIndex].c, 0, 0, WHOLE_ARRAY);
}
//——————————————————————————————————————————————————————————————————————————————

No método "UpdateElectrons", removeremos as variáveis "β" e "γ", pois elas não serão mais necessárias para gerar os números aleatórios correspondentes. Além disso, eliminaremos a divisão do incremento do elétron pelo número de camadas no caso de movimento em direção à solução global. Para ser sincero, a decisão dos autores parece discutível, e o sentido físico dessa abordagem não é totalmente claro. Talvez os autores quisessem tornar a intensidade do movimento dos elétrons em direção à solução global variável, mudando-a de acordo com o número de camadas: quanto menos camadas, mais intenso deveria ser o movimento (embora meus experimentos tenham mostrado que isso não traz benefício algum).

//——————————————————————————————————————————————————————————————————————————————
// Обновление положения электронов
void C_AO_AOS::UpdateElectrons ()
{
  double α;      // коэффициент скорости
  double β;      // коэффициент веса лучшего решения
  double γ;      // коэффициент веса среднего состояния
  double φ;      // вероятность перехода
  double newPos; // новая позиция
  double LE;     // лучшая энергия
  double BSk;    // состояние связи
  int    lID;    // идентификатор слоя

  // Обработка каждой частицы
  for (int p = 0; p < popSize; p++)
  {
    for (int c = 0; c < coords; c++)
    {
      φ = u.RNDprobab ();

      if (φ < PR)
      {
        // Случайное рассеивание
        newPos = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      }
      else
      {
        lID = electrons [p].layerID [c];

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

        // Если текущая энергия частицы меньше средней энергии слоя
        if (a [p].f < atoms [c].layers [lID].BEk)
        {
          // Движение в сторону глобального оптимума----------------------------
          LE = cB [c];

          newPos = a [p].c [c]+ α * (β * LE - γ * BS [c]) / currentLayers [c];
        }
        else
        {
          // Движение в сторону локального оптимума слоя------------------------
          LE  = atoms [c].layers [lID].LEk;
          BSk = atoms [c].layers [lID].BSk;

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

      // Ограничение новой позиции в пределах диапазона поиска с учетом шага
      a [p].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Adicionalmente, no método "UpdateElectrons" da classe "C_AO_AOSm", em vez de espalhar aleatoriamente o elétron pelo espaço de busca, implementaremos o movimento do elétron para o centro do núcleo com certa probabilidade. Na prática, isso significa substituir o valor de alguma coordenada pelo valor da solução global, o que deve melhorar as propriedades combinatórias do algoritmo. Já a dispersão aleatória era destinada a proporcionar diversidade na população de soluções, mas essa propriedade acabava promovendo a propagação dos elétrons conforme uma distribuição lognormal, onde havia uma probabilidade diferente de zero de o elétron atingir qualquer ponto do espaço durante o movimento.

Verde são indicadas as mudanças nas fórmulas de movimentação dos elétrons, agora o incremento é calculado como a diferença entre a melhor solução local da camada e a melhor solução individual do elétron.

//——————————————————————————————————————————————————————————————————————————————
// Обновление положения электронов
void C_AO_AOSm::UpdateElectrons ()
{
  double α;      // коэффициент скорости
  double φ;      // вероятность перехода
  double newPos; // новая позиция
  double LE;     // лучшая энергия
  double BSk;    // состояние связи
  int    lID;    // идентификатор слоя

  // Обработка каждой частицы
  for (int p = 0; p < popSize; p++)
  {
    for (int c = 0; c < coords; c++)
    {
      φ = u.RNDprobab ();

      if (φ < PR)
      {
        // Случайный переход к центру
        newPos = cB [c];
      }
      else
      {
        lID = electrons [p].layerID [c];

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

        // Если текущая энергия частицы меньше средней энергии слоя
        if (a [p].f < atoms [c].layers [lID].BEk)
        {
          // Движение в сторону глобального оптимума----------------------------
          LE     = cB [c];

          newPos = a [p].cB [c]+ α * (LE - a [p].cB [c]);
        }
        else
        {
          // Движение в сторону локального оптимума слоя------------------------
          LE     = atoms [c].layers [lID].LEk;

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

      // Ограничение новой позиции в пределах диапазона поиска с учетом шага
      a [p].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

O método "DistributeParticles" distribui os elétrons no espaço de busca, utilizando uma distribuição lognormal para cada coordenada. Para cada partícula e cada coordenada, é chamada uma função que gera a posição considerando os parâmetros definidos (valor médio, mínimo e máximo, pico), e depois é aplicada uma função adicional para ajustar a posição dentro do intervalo especificado.

//——————————————————————————————————————————————————————————————————————————————
// Распределение частиц в пространстве поиска
void C_AO_AOS::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Используем логнормальное распределение для позиционирования частиц
      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]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Vamos alterar a distribuição dos elétrons para uma distribuição normal. Nesta distribuição é utilizado o desvio padrão igual a 8. Embora esse parâmetro pudesse ser exposto externamente ao algoritmo, decidi não fazer isso. Valores menores favorecem uma exploração mais ampla do espaço de busca, enquanto valores mais altos aumentam a precisão da convergência ao refinar a solução global.

//——————————————————————————————————————————————————————————————————————————————
// Распределение частиц в пространстве поиска
void C_AO_AOSm::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Используем гауссово распределение для позиционирования частиц
      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]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Todas as mudanças feitas na versão original do algoritmo AOS foram analisadas com o objetivo de aumentar sua eficiência. Como alterações significativas foram feitas na lógica da estratégia de busca, a versão modificada do algoritmo pode ser indicada pela letra "m". A partir de agora, apenas uma versão modificada será apresentada na tabela de classificação — AOSm.


Exemplo de uso dos algoritmos da classe C_AO

Como todos os algoritmos populacionais de otimização discutidos anteriormente foram herdados da classe comum C_AO, isso permite usá-los de maneira uniforme e com mínimo esforço para resolver diferentes problemas que exigem a busca de parâmetros ótimos. No exemplo abaixo é apresentado um script no qual é realizada a otimização de uma função objetivo:

1. No início do script você pode escolher qual algoritmo de otimização utilizar. Se nada for selecionado, o script informará o erro e será interrompido.
2. Configuração de parâmetros. O script define quantas vezes a função será chamada, quantos parâmetros precisam ser otimizados, o tamanho do grupo de soluções e quantas iterações serão executadas.
3. Limites de valores. Para cada parâmetro são definidos valores mínimos e máximos (neste exemplo de -10 a 10).
4. O script inicia o processo de otimização:

  • Ele gera soluções (conjuntos de parâmetros) e verifica o quão boas elas são, utilizando uma função especial (função objetivo).
  • A cada iteração, o algoritmo atualiza suas soluções com base naquelas que apresentaram melhores resultados.

5. Resultados. Após a conclusão da otimização, o script exibe informações sobre qual algoritmo foi utilizado, qual o melhor valor encontrado e quantas vezes a função foi executada.
6. A função objetivo — é uma tarefa abstrata de otimização (neste exemplo, a solução de encontrar o máximo global de uma parábola invertida), que recebe os parâmetros e retorna uma avaliação da sua qualidade.

#property script_show_inputs                           // Указывает, что скрипт будет показывать входные параметры в окне свойств

#include <Math\AOs\PopulationAO\#C_AO_enum.mqh>        // Подключение библиотеки для работы с алгоритмами оптимизации

input E_AO AOexactly = NONE_AO;                        // Параметр для выбора алгоритма оптимизации, по умолчанию - NONE_AO

//——————————————————————————————————————————————————————————————————————————————
void OnStart()
{
  //----------------------------------------------------------------------------
  int numbTestFuncRuns = 10000;                        // Общее количество запусков тестовой функции
  int params           = 1000;                         // Количество параметров для оптимизации
  int popSize          = 50;                           // Размер популяции для алгоритма оптимизации
  int epochCount       = numbTestFuncRuns / popSize;   // Общее количество эпох (итераций) для оптимизации
  
  
  double rangeMin [], rangeMax [], rangeStep [];       // Массивы для хранения границ и шагов параметров
  
  ArrayResize (rangeMin,  params);                     // Изменение размера массива min границ
  ArrayResize (rangeMax,  params);                     // Изменение размера массива max границ
  ArrayResize (rangeStep, params);                     // Изменение размера массива шагов
  
  // Инициализация границ и шагов для каждого параметра
  for (int i = 0; i < params; i++)
  {
    rangeMin  [i] = -10;                               // Минимальное значение параметра
    rangeMax  [i] =  10;                               // Максимальное значение параметра
    rangeStep [i] =  DBL_EPSILON;                      // Шаг для параметра
  }
  
  //----------------------------------------------------------------------------
  C_AO *ao = SelectAO (AOexactly);                     // Выбор алгоритма оптимизации
  if (ao == NULL)                                      // Проверка, был ли выбран алгоритм
  {
    Print ("AO не выбран...");                         // Сообщение об ошибке, если алгоритм не выбран
    return;
  }
  
  ao.params [0].val = popSize;                         // Назначение размера популяции....
  ao.SetParams ();                                     //... (необязательно, тогда будет использован размер популяции по умолчанию)
  
  
  ao.Init (rangeMin, rangeMax, rangeStep, epochCount); // Инициализация алгоритма с заданными границами и количеством эпох
  
  // Основной цикл по количеству эпох
  for (int epochCNT = 1; epochCNT <= epochCount; epochCNT++)
  {
    ao.Moving ();                                      // Выполнение одной эпохи алгоритма оптимизации

    // Вычисление значения целевой функции для каждого решения в популяции
    for (int set = 0; set < ArraySize (ao.a); set++)
    {
      ao.a [set].f = ObjectiveFunction (ao.a [set].c); // Применение целевой функции к каждому решению
    }

    ao.Revision ();                                    // Обновление популяции на основе результатов целевой функции
  }
  
  //----------------------------------------------------------------------------
  // Вывод имени алгоритма, лучшего результата и количества запусков функции
  Print (ao.GetName (), ", best result: ", ao.fB, ", number of function launches: ", numbTestFuncRuns);
  
  delete ao;                                           // Освобождение памяти, занятой объектом алгоритма
}
//——————————————————————————————————————————————————————————————————————————————

//——————————————————————————————————————————————————————————————————————————————
// Определение целевой функции пользователя, в данном случае как пример - параболоид, F(Xn) ∈ [0.0; 1.0], X ∈ [-10.0; 10.0], максимизация
double ObjectiveFunction (double &x [])
{
  double sum = 0.0;  // Переменная для накопления результата

  // Цикл по всем параметрам
  for (int i = 0; i < ArraySize (x); i++)
  {
    // Проверка, находится ли параметр в допустимом диапазоне
    if (x [i] < -10.0 || x [i] > 10.0) return 0.0;  // Если параметр вне диапазона, возвращаем 0
    sum += (-x [i] * x [i] + 100.0) * 0.01;         // Вычисление значения целевой функции
  }
  
  return sum /= ArraySize (x);
}
//——————————————————————————————————————————————————————————————————————————————


Resultados dos testes

Vamos passar para o teste da versão modificada do algoritmo.

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%)

Como pode ser observado, os resultados da versão modificada melhoraram significativamente em comparação com os indicadores anteriores da versão original, onde a pontuação geral foi de 3.00488 (33.39%). Essa melhoria torna-se evidente na análise da visualização, que demonstra não apenas uma melhor convergência, mas também uma exploração mais detalhada dos extremos significativos.

Um dos principais aspectos que merece destaque é o efeito de "agrupamento" das soluções em coordenadas específicas. Esse fenômeno é observado tanto na versão original quanto na modificada, o que ressalta uma característica típica dos algoritmos AOS. O "agrupamento" de soluções pode indicar que o algoritmo está encontrando de forma eficiente as regiões onde se localizam possíveis soluções ótimas.

Hilly

AOSm na função de teste Hilly

Forest

AOSm na função de teste Forest

Megacity

  AOSm na função de teste Megacity

A versão modificada do algoritmo Atomic Orbital Search (AOS) melhorou significativamente seus indicadores em relação à versão original e agora atinge mais de 55% do máximo possível. Este é realmente um resultado impressionante! Na tabela de classificação, o algoritmo ocupa o 12º lugar, na parte superior, o que indica resultados bastante respeitáveis.

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)
1ANSacross neighbourhood search0,949480,847760,438572,235811,000000,923340,399882,323230,709230,634770,230911,574916,13468,15
2CLAcode lock algorithm (joo)0,953450,871070,375902,200420,989420,917090,316422,222940,796920,693850,193031,683806,10767,86
3AMOmanimal migration ptimization M0,903580,843170,462842,209590,990010,924360,465982,380340,567690,591320,237731,396755,98766,52
4(P+O)ES(P+O) evolution strategies0,922560,881010,400212,203790,977500,874900,319452,171850,673850,629850,186341,490035,86665,17
5CTAcomet tail algorithm (joo)0,953460,863190,277702,094350,997940,857400,339492,194840,887690,564310,105121,557125,84664,96
6SDSmstochastic diffusion search M0,930660,854450,394762,179880,999830,892440,196192,088460,723330,611000,106701,441035,70963,44
7AAmarchery algorithm M0,917440,708760,421602,047800,925270,758020,353282,036570,673850,552000,237381,463235,54861,64
8ESGevolution of social groups (joo)0,999060,796540,350562,146161,000000,828630,131021,959650,823330,553000,047251,423585,52961,44
9SIAsimulated isotropic annealing (joo)0,957840,842640,414652,215130,982390,795860,205071,983320,686670,493000,090531,270205,46960,76
10ACSartificial cooperative search0,755470,747440,304071,806981,000000,888610,224132,112740,690770,481850,133221,305835,22658,06
11ASOanarchy society optimization0,848720,746460,314651,909830,961480,791500,238031,991010,570770,540620,166141,277525,17857,54
12AOSmatomic orbital search M0,802320,704490,310211,817020,856600,694510,219961,771070,746150,528620,143581,418355,00655,63
13TSEAturtle shell evolution algorithm (joo)0,967980,644800,296721,909490,994490,619810,227081,841390,690770,426460,135981,253225,00455,60
14DEdifferential evolution0,950440,616740,303081,870260,953170,788960,166521,908650,786670,360330,029531,176534,95555,06
15CROchemical reaction optimisation0,946290,661120,298531,905930,879060,584220,211461,674730,758460,426460,126861,311784,89254,36
16BSAbird swarm algorithm0,893060,649000,262501,804550,924200,711210,249391,884790,693850,326150,100121,120124,80953,44
17HSharmony search0,865090,687820,325271,878180,999990,680020,095901,775920,620000,422670,054581,097254,75152,79
18SSGsaplings sowing and growing0,778390,649250,395431,823080,859730,624670,174291,658690,646670,441330,105981,193984,67651,95
19BCOmbacterial chemotaxis optimization M0,759530,622680,314831,697040,893780,613390,225421,732590,653850,420920,144351,219124,64951,65
20ABOafrican buffalo optimization0,833370,622470,299641,755480,921700,586180,197231,705110,610000,431540,132251,173784,63451,49
21(PO)ES(PO) evolution strategies0,790250,626470,429351,846060,876160,609430,195911,681510,590000,379330,113221,082554,61051,22
22TSmtabu search M0,877950,614310,291041,783300,928850,518440,190541,637830,610770,382150,121571,114494,53650,40
23BSObrain storm optimization0,937360,576160,296881,810410,931310,558660,235371,725340,552310,290770,119140,962224,49849,98
24WOAmwale optimization algorithm M0,845210,562980,262631,670810,931000,522780,163651,617430,663080,411380,113571,188034,47649,74
25AEFAartificial electric field algorithm0,877000,617530,252351,746880,927290,726980,180641,834900,666150,116310,095080,877544,45949,55
26AEOartificial ecosystem-based optimization algorithm0,913800,467130,264701,645630,902230,437050,214001,553270,661540,308000,285631,255174,45449,49
27ACOmant colony optimization M0,881900,661270,303771,846930,858730,586800,150511,596040,596670,373330,024720,994724,43849,31
28BFO-GAbacterial foraging optimization - ga0,891500,551110,315291,757900,969820,396120,063051,428990,726670,275000,035251,036924,22446,93
29ABHAartificial bee hive algorithm0,841310,542270,263041,646630,878580,477790,171811,528180,509230,338770,103970,951974,12745,85
30ACMOatmospheric cloud model optimization0,903210,485460,304031,692700,802680,378570,191781,373030,623080,244000,107950,975034,04144,90
31ASHAartificial showering algorithm0,896860,404330,256171,557370,803600,355260,191601,350460,476920,181230,097740,755893,66440,71
32ASBOadaptive social behavior optimization0,763310,492530,326191,582020,795460,400350,260971,456770,264620,171690,182000,618313,65740,63
33MECmind evolutionary computation0,695330,533760,326611,555690,724640,330360,071981,126980,525000,220000,041980,786983,47038,55
34IWOinvasive weed optimization0,726790,522560,331231,580580,707560,339550,074841,121960,423330,230670,046170,700173,40337,81
35Micro-AISmicro artificial immune system0,795470,519220,308611,623300,729560,368790,093981,192330,376670,158670,028020,563353,37937,54
36COAmcuckoo optimization algorithm M0,758200,486520,313691,558410,740540,280510,055991,077040,505000,174670,033800,713473,34937,21
37SDOmspiral dynamics optimization M0,746010,446230,296871,489120,702040,346780,109441,158260,428330,167670,036630,632633,28036,44
38NMmNelder-Mead method M0,738070,505980,313421,557470,636740,283020,082211,001970,446670,186670,040280,673623,23335,92
39FAmfirefly algorithm M0,586340,472280,322761,381380,684670,374390,109081,168140,286670,164670,047220,498553,04833,87
40GSAgravitational search algorithm0,647570,491970,300621,440160,539620,363530,099451,002600,326670,122000,019170,467832,91132,34
41BFObacterial foraging optimization0,611710,432700,313181,357590,544100,215110,056760,815970,421670,138000,031950,591622,76530,72
42ABCartificial bee colony0,633770,424020,308921,366710,551030,218740,056230,826000,340000,142000,031020,513022,70630,06
43BAbat algorithm0,597610,459110,352421,409150,403210,193130,071750,668100,210000,101000,035170,346172,42326,93
44AAAalgae adaptive algorithm0,500070,320400,255251,075720,370210,222840,167850,760890,278460,148000,097550,524022,36126,23
45SAsimulated annealing0,557870,421770,315491,295130,349980,152590,050230,552800,311670,100330,028830,440832,28925,43


Considerações finais

Neste artigo foi apresentada a versão modificada do algoritmo de busca orbital atômica (AOSm), na qual abandonei a posição média dos elétrons BSk nas camadas do átomo em favor da melhor posição individual de cada elétron. Isso permitiu que os elétrons se movessem de forma mais eficiente em direção à melhor solução em sua camada, baseando-se em suas próprias conquistas e não em uma média geral. Além disso, foram eliminados dois componentes aleatórios βi e γi, o que reduziu em três vezes o tempo de geração de números aleatórios, sem perder o sentido físico do algoritmo.

No método "UpdateElectrons", foram removidas as variáveis que se tornaram desnecessárias e foi eliminada a divisão do incremento do elétron pelo número de camadas durante o movimento em direção à solução global. Embora os autores da versão original possivelmente tenham buscado tornar a intensidade de movimento variável, meus experimentos mostraram que isso não trouxe benefícios significativos.

Também foram implementadas mudanças no método "UpdateElectrons" da classe "C_AO_AOSm", substituindo a dispersão aleatória do elétron pelo movimento em direção ao centro do núcleo com uma determinada probabilidade. Isso melhorou as propriedades combinatórias do algoritmo, permitindo que os elétrons focassem com mais precisão no objetivo global. Além disso, a distribuição lognormal foi substituída pela distribuição normal, o que aumentou a precisão da convergência na busca pelo refinamento da solução global.

Os resultados da versão modificada AOSm mostraram uma melhoria significativa, com uma pontuação geral superior a 55% do máximo possível, o que confirma a alta eficiência e competitividade do algoritmo. Na tabela de classificação, o AOSm ocupa a 12ª posição, o que evidencia suas conquistas significativas entre outros métodos de otimização.

Um dos aspectos mais notáveis do AOSm é a melhoria na convergência, que se tornou evidente na visualização dos resultados. O algoritmo trabalha de forma mais detalhada os extremos significativos e demonstra capacidade de busca eficiente por soluções ótimas em espaços complexos e multidimensionais. O efeito de "agrupamento" de soluções, observado tanto na versão original quanto na modificada, destaca a habilidade do algoritmo em encontrar e se concentrar em regiões com potenciais ótimos, o que é especialmente útil em problemas de alta dimensionalidade e estrutura complexa.

Um benefício adicional da versão modificada é a redução do número de parâmetros externos, o que simplifica seu uso e configuração. Contudo, para todos os algoritmos apresentados anteriormente nos artigos, selecionei parâmetros externos otimizados para alcançar o máximo desempenho em testes complexos com diferentes tipos de problemas, portanto, todos os algoritmos estão prontos para uso e não requerem ajustes. Nesta série de artigos ficou demonstrado que, às vezes, pequenas alterações nos algoritmos de otimização podem mudar radicalmente suas propriedades de busca, enquanto grandes mudanças na lógica da estratégia de busca podem não resultar em melhorias perceptíveis. E, claro, compartilho nos artigos técnicas que realmente aumentam a eficiência da otimização.

Tab

Figura 2. Graduação de cores dos algoritmos conforme os respectivos testes. Os resultados maiores ou iguais a 0.99 são destacados em branco.

chart

Figura 3. Histograma dos resultados dos testes dos algoritmos (na escala de 0 a 100, quanto maior, melhor,

onde 100 é o resultado teórico máximo possível, no arquivo compactado há o script para o cálculo da tabela de classificação)


Prós e contras do algoritmo AOSm:

Prós:

  1. Boa performance em diferentes tipos de problemas.
  2. Pequeno número de parâmetros externos.
  3. Boa escalabilidade.
  4. Busca equilibrada tanto em extremos locais quanto globais.

Contras:

  1. Implementação relativamente complexa.
  2. Precisão de convergência média em comparação com outros algoritmos em funções suaves.

Está anexado ao artigo um arquivo compactado com as versões atualizadas dos códigos dos algoritmos. O autor do artigo não se responsabiliza pela precisão absoluta na descrição dos algoritmos canônicos, pois muitas alterações foram feitas para melhorar suas capacidades de busca. As conclusões e julgamentos apresentados nos artigos baseiam-se nos resultados dos experimentos realizados.

Programas utilizados no artigo

#NomeTipoDescrição
1#C_AO.mqh
Arquivo incluído
Classe pai dos algoritmos populacionais de otimização
2#C_AO_enum.mqh
Arquivo incluído
Enumeração dos algoritmos populacionais de otimização
3TestFunctions.mqh
Arquivo incluído
Biblioteca de funções de teste
4
TestStandFunctions.mqh
Arquivo incluído
Biblioteca de funções da bancada de testes
5
Utilities.mqh
Arquivo incluído
Biblioteca de funções auxiliares
6
CalculationTestResults.mqh
Arquivo incluído
Script para cálculo dos resultados na tabela comparativa
7
Testing AOs.mq5
ScriptBancada de testes unificada para todos os algoritmos populacionais de otimização
8
Simple use of population optimization algorithms.mq5
Script
Exemplo simples de uso dos algoritmos populacionais de otimização sem visualização
9
AO_AOSm_AtomicOrbitalSearch.mqh
Arquivo incluídoClasse do algoritmo AOSm
10
Test_AO_AOSm.mq5
Script
Bancada de testes para o AOSm

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/16315

Arquivos anexados |
AOSm.ZIP (137.09 KB)
Aprendendo MQL5 do iniciante ao profissional (Parte VI):  Fundamentos da criação de EAs Aprendendo MQL5 do iniciante ao profissional (Parte VI): Fundamentos da criação de EAs
O artigo dá continuidade à série para iniciantes. Aqui serão abordados os princípios básicos da construção de EAs. Primeiro, criaremos um EA que operará sem indicadores, usando ordens pendentes, depois, criaremos um segundo EA, baseado no indicador padrão MA, operando com ordens a preço atual. Parto do princípio de que você já não é totalmente iniciante e domina o material dos artigos anteriores.
Exemplo de Análise de Rede de Causalidade (CNA) e Modelo de Autorregressão Vetorial para Predição de Eventos de Mercado Exemplo de Análise de Rede de Causalidade (CNA) e Modelo de Autorregressão Vetorial para Predição de Eventos de Mercado
Este artigo apresenta um guia abrangente para implementar um sistema de negociação sofisticado utilizando Análise de Rede de Causalidade (CNA) e Autorregressão Vetorial (VAR) em MQL5. Ele aborda o embasamento teórico desses métodos, fornece explicações detalhadas das funções-chave no algoritmo de negociação e inclui exemplos de código para implementação.
Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 8): Desenvolvimento do Expert Advisor (II) Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 8): Desenvolvimento do Expert Advisor (II)
Pense em um Expert Advisor independente. Anteriormente, discutimos um Expert Advisor baseado em indicador que também contava com um script independente para desenhar a geometria de risco e recompensa. Hoje, discutiremos a arquitetura de um Expert Advisor em MQL5, que integra todos os recursos em um único programa.
Criando um Expert Advisor Integrado MQL5-Telegram (Parte 4): Modularizando Funções de Código para Maior Reutilização Criando um Expert Advisor Integrado MQL5-Telegram (Parte 4): Modularizando Funções de Código para Maior Reutilização
Neste artigo, reformulamos o código existente usado para enviar mensagens e capturas de tela do MQL5 para o Telegram, organizando-o em funções modulares reutilizáveis. Isso tornará o processo mais eficiente, permitindo uma execução mais rápida e uma gestão de código mais fácil em múltiplas instâncias.
OSZAR »