Русский
preview
Estratégia da Águia — Eagle Strategy (ES)

Estratégia da Águia — Eagle Strategy (ES)

MetaTrader 5Negociação |
33 0
Andrey Dik
Andrey Dik

Conteúdo

  1. Introdução
  2. Implementação do algoritmo
  3. Resultados dos testes


Introdução

No mundo da programação, especialmente no desenvolvimento de EA, a otimização eficiente desempenha um papel criticamente importante. Tarefas altamente especializadas de busca pela solução ótima em um enorme espaço de variantes possíveis exigem a aplicação de algoritmos avançados. Métodos tradicionais de otimização frequentemente se mostram ineficazes, ficando presos em extremos locais e não encontrando a solução globalmente melhor.

Nesse contexto, cada vez mais atenção é dada a algoritmos metaheurísticos inspirados na própria natureza, métodos que passaram por evolução natural. Esses algoritmos são capazes de encontrar boas soluções e, muitas vezes, soluções próximas do ótimo, mesmo em tarefas nas quais a velocidade de cálculo tem importância primordial.

Em condições de constante busca por resolver tarefas cada vez mais complexas e intensivas em recursos, hoje analisaremos mais uma tentativa promissora, o algoritmo Eagle Strategy (ES). Esse algoritmo, inspirado no comportamento de caça da águia, representa uma nova metaheurística destinada à resolução de problemas de otimização, por meio da imitação da estratégia de busca visual e perseguição dinâmica da presa.


Implementação do algoritmo

Imagine uma águia-dourada planando alto no céu em busca de presa. Sua estratégia de caça é surpreendentemente eficiente e consiste em duas etapas claras: primeiro, ela voa em grande altitude, examinando um vasto território com movimentos caóticos em zigue-zague; em seguida, ao avistar o alvo, mergulha rapidamente para baixo, concentrando todos os esforços em uma presa específica. Foi exatamente essa sabedoria natural que fundamentou o algoritmo Eagle Strategy (Estratégia da Águia), desenvolvido em 2010 para resolver problemas complexos de otimização.

Na primeira etapa, o algoritmo utiliza os chamados voos de Lévy, um modelo matemático que descreve o movimento no espaço. Diferentemente de uma caminhada aleatória comum, na qual os passos são aproximadamente do mesmo tamanho, o voo de Lévy inclui numerosos passos pequenos intercalados com saltos raros, porém muito longos. 

Quando o algoritmo encontra uma área promissora, como uma águia que avista a presa, inicia-se a segunda etapa, a busca local intensiva com a ajuda do algoritmo de vaga-lumes, já analisado anteriormente em um dos artigos. Vários agentes de busca, como vaga-lumes na noite, são atraídos por vizinhos mais brilhantes, isto é, mais bem-sucedidos. O brilho do vaga-lume corresponde à qualidade da solução encontrada por ele, e a atração diminui com a distância segundo uma lei exponencial. Isso cria um equilíbrio entre a exploração da vizinhança e o movimento em direção à melhor solução conhecida.

A principal inovação do algoritmo ES consiste na alternância cíclica desses dois modos. Após a busca local intensiva, o algoritmo volta a alternar para a exploração global, realizando um salto longo para uma nova área inexplorada do espaço de busca. Isso evita a convergência prematura e permite encontrar o ótimo global mesmo em paisagens muito complexas com múltiplos extremos locais.

Os parâmetros do algoritmo são intuitivos e facilmente ajustáveis. O tamanho da população define o número de agentes que exploram simultaneamente, o parâmetro de Lévy controla a proporção entre saltos curtos e longos, o raio da hiperesfera define a área de busca local intensiva, e o coeficiente de randomização adiciona um elemento de aleatoriedade para sair de situações de impasse. Essa flexibilidade permite adaptar o algoritmo a uma tarefa específica sem a necessidade de profundo entendimento da teoria matemática.

A filosofia do algoritmo ES é simples e elegante: visão global combinada com precisão local. Assim como a águia combina o voo de observação com o ataque direcionado, o algoritmo equilibra a exploração de áreas desconhecidas com a intensificação das soluções promissoras encontradas.

As principais características do algoritmo são: alternância automática entre as fases quando há melhoria da solução, parâmetros adaptativos, sendo que λ diminui em caso de estagnação e o tamanho do passo decresce ao longo do tempo, e equilíbrio entre a exploração de novas áreas e a intensificação das soluções encontradas.

eagle_strategy

Figura 1. Ilustração do funcionamento do algoritmo ES

A ilustração mostra as duas fases de funcionamento do algoritmo, as trajetórias dos voos de Lévy, linhas vermelhas tracejadas, a hiperesfera de busca local, círculo azul-claro, o movimento dos vaga-lumes dentro da esfera, pontos verdes com halos, e as linhas de contorno da função de otimização.

Passamos à escrita do pseudocódigo do algoritmo.

INICIALIZAÇÃO:
1. Criar a população de agentes com posições aleatórias
2. Definir o sinalizador de busca global, fase = global
3. Inicializar os contadores de estagnação e progresso

CICLO PRINCIPAL enquanto o critério de parada não for atingido:
  
  SE fase = global:
    PARA cada agente:
      - gerar um passo de Lévy usando o algoritmo de Mantegna
      - calcular a escala adaptativa do passo, maior no início e menor no final
      - atualizar a posição: nova_posição = atual + passo_Lévy × escala
      - aplicar restrições de limite
    
    SE for encontrada melhoria do melhor global:
      - alternar para a fase local
      - identificar o melhor agente como centro da busca local
      - redefinir o contador de estagnação
    CASO CONTRÁRIO:
      - incrementar o contador de estagnação
      - SE estagnação > 5 iterações:
        - reduzir o parâmetro λ para voos mais agressivos
  
  SENÃO fase = local:
    Com probabilidade de 80%:
      - determinar os agentes na hiperesfera de raio 0.1 ao redor do melhor
      - SE agentes < 5:
        - selecionar os 5 vizinhos mais próximos ou 30% da população
      
      PARA cada agente no grupo local:
        PARA cada outro agente no grupo:
          SE o outro agente for melhor:
            - calcular a atratividade β = β₀ × exp(-γ × distância²)
            - mover o agente: posição += β × (melhor - atual) + ruído_aleatório
    
    Com probabilidade de 20%:
      - Copiar parcialmente as coordenadas do melhor global para agentes aleatórios
    
    - Incrementar o contador de iterações locais
    - SE 20 iterações locais forem executadas:
       - Retornar à fase global
       - Restaurar o valor original do parâmetro λ

  ATUALIZAÇÃO:
    PARA cada agente:
      - calcular a adaptabilidade
      - atualizar o melhor pessoal
      - atualizar o melhor global

Nesta implementação do algoritmo ES, para gerar números com distribuição de Lévy aplicamos um método numérico — oalgoritmo de Mantegna, proposto por R.N. Mantegna em 1994 e que se tornou a forma padrão de simulação de voos de Lévy em algoritmos de otimização. Mantegna demonstrou matematicamente que a razão entre duas variáveis gaussianas especialmente escaladas produz uma distribuição muito próxima da distribuição de Lévy na faixa de valores relevante para aplicações práticas. Sua essência é a seguinte:

// Вычисление сигмы для алгоритма Мантенья
double numerator   = Gamma(1.0 + lambda) * MathSin(M_PI * lambda / 2.0);
double denominator = Gamma((1.0 + lambda) / 2.0) * lambda * MathPow(2.0, (lambda - 1.0) / 2.0);
double sigma = MathPow(numerator / denominator, 1.0 / lambda);

// Генерация u и v из нормальных распределений
double u_val = GenerateGaussian() * sigma;
double v_val = MathAbs(GenerateGaussian());

// Вычисление шага Леви
levyStep[c] = u_val / MathPow(v_val, 1.0 / lambda);

Tomamos duas variáveis aleatórias:

  • u, da distribuição normal N(0, σ²)
  • v, da distribuição normal N(0, 1)
Fórmula especial para σ:
σ = [Γ(1+λ) × sin(πλ/2) / (Γ((1+λ)/2) × λ × 2^((λ-1)/2))]^(1/λ)

onde Γ é a função gama, λ é o parâmetro da distribuição de Lévy, 1 < λ ≤ 3.

É importante observar que, ao definir a função gama para calcular o parâmetro σ no método de Mantegna, utiliza-se a aproximação de Lanczos, um método numérico de alta precisão para o cálculo da função gama. Trata-se de uma das formas mais eficientes de calcular Γ(z) e, no código, isso é implementado em uma função separada, que analisaremos por último.

A fórmula principal tem a seguinte forma:

Γ(z+1) = √(2π) × ((z+g+0.5)^(z+0.5)) × e^(-(z+g+0.5)) × Ag(z)

onde g é o parâmetro, normalmente 7; Ag(z) é a série com coeficientes pré-calculados, e com g = 7 e 9 coeficientes fornece precisão de aproximadamente 15 dígitos significativos.

Para z < 0.5 utiliza-se a relação da fórmula de reflexão, o que permite calcular a função gama para todos os números reais:

Γ(z) × Γ(1-z) = π / sin(πz)

Sem um cálculo eficiente da função gama, a geração dos voos de Lévy seria computacionalmente custosa, o que desaceleraria significativamente todo o algoritmo de otimização.

O passo final de Lévy:

step = u / |v|^(1/λ)

O algoritmo gera uma sequência de passos com comportamento característico dos voos de Lévy: muitos passos pequenos, exploração local, saltos raros, porém muito grandes, exploração global, e uma lei de potência na distribuição dos comprimentos dos passos.

As vantagens desse método combinam simplicidade de implementação, pois é necessário apenas um gerador de distribuição normal, e estabilidade, isto é, robustez numérica do algoritmo. Essa propriedade torna os voos de Lévy eficazes para otimização, pois garantem um equilíbrio ideal entre o estudo detalhado de áreas locais e a rápida transição para novas regiões do espaço de busca.

Após a análise detalhada dos métodos utilizados no algoritmo ES, podemos avançar com segurança para a implementação da classe "C_AO_ES", que representa a realização do método de otimização baseado na estratégia de caça da águia e herda da classe base "C_AO". O método utiliza uma abordagem em duas etapas: primeiro é realizada a busca global para identificar áreas potencialmente promissoras, depois é executada a busca local dentro da parte selecionada do espaço de busca para refinar o resultado.

O tamanho da população "popSize" define a quantidade de soluções "candidate" que participam da busca. O parâmetro de Lévy "lambda" controla a distribuição dos passos aleatórios. O raio da hiperesfera "sphereRadius" determina a área da busca local. O número de iterações da busca local "localIterations" indica quantas vezes o refinamento da solução é realizado dentro da hiperesfera. Os parâmetros de randomização "alpha" e de atratividade "beta0" regulam os componentes do modelo de busca, como os movimentos aleatórios e a influência da "luz", em termos da metáfora. 

Fase global de exploração (GlobalExploration) é orientada à busca de áreas "promising" em todo o espaço de busca, utilizando passos aleatórios gerados segundo a distribuição de Lévy. Essa abordagem favorece uma busca expansiva e a escalabilidade para grandes espaços.

Fase local de intensificação (LocalExploitation) realiza uma busca mais minuciosa dentro da hiperesfera ao redor do ponto selecionado. Nesse caso, são utilizados passos menores e mais precisos, correspondentes à otimização local.

Geração dos passos de Lévy (GenerateLevyStep) cria movimentos aleatórios segundo o método da distribuição de Lévy, garantindo tanto saltos pequenos quanto grandes no espaço de busca para equilibrar diversificação e intensificação.

A classe contém mecanismos para acompanhar o progresso da busca, como o armazenamento da melhor solução encontrada, contadores de estagnação, caso a solução não melhore, bem como laços por épocas para limitar a execução do algoritmo no tempo ou por número de iterações, cálculos dos parâmetros das distribuições para os passos aleatórios, em particular a geração de distribuições gaussianas e de Lévy, e métodos para gerenciar as fases da busca, assegurando a alternância entre as etapas global e local e o controle do seu funcionamento.

De modo geral, o método representa uma estratégia de busca que combina ampla exploração do espaço para identificar áreas potenciais com posterior otimização local detalhada para alcançar soluções precisas, utilizando parâmetros e mecanismos que permitem adaptar seu comportamento a tarefas e condições específicas.

//————————————————————————————————————————————————————————————————————
class C_AO_ES : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_ES () { }
  C_AO_ES ()
  {
    ao_name = "ES";
    ao_desc = "Eagle Strategy";
    ao_link = "https://www.mql5.com/ru/articles/18460";

    popSize         = 100;   // размер популяции
    lambda          = 1.0;  // параметр распределения Леви (1 < λ ≤ 3)
    sphereRadius    = 0.1;  // радиус гиперсферы для локального поиска
    localIterations = 20;   // количество итераций локального поиска
    alpha           = 0.1;  // параметр рандомизации для Firefly
    beta0           = 1.2;  // начальная привлекательность

    ArrayResize (params, 6);

    params [0].name = "popSize";         params [0].val = popSize;
    params [1].name = "lambda";          params [1].val = lambda;
    params [2].name = "sphereRadius";    params [2].val = sphereRadius;
    params [3].name = "localIterations"; params [3].val = localIterations;
    params [4].name = "alpha";           params [4].val = alpha;
    params [5].name = "beta0";           params [5].val = beta0;
  }

  void SetParams ()
  {
    popSize         = (int)params [0].val;
    lambda          = params      [1].val;
    sphereRadius    = params      [2].val;
    localIterations = (int)params [3].val;
    alpha           = params      [4].val;
    beta0           = params      [5].val;
  }

  bool Init (const double &rangeMinP  [],  // минимальные значения
             const double &rangeMaxP  [],  // максимальные значения
             const double &rangeStepP [],  // шаг изменения
             const int     epochsP = 0);   // количество эпох

  void Moving   ();
  void Revision ();

  //------------------------------------------------------------------
  double lambda;          // параметр распределения Леви (1 < λ ≤ 3)
  double sphereRadius;    // радиус гиперсферы для локального поиска
  int    localIterations; // количество итераций локального поиска
  double alpha;           // параметр рандомизации
  double beta0;           // начальная привлекательность

  private: //---------------------------------------------------------
  double gamma_es;           // коэффициент поглощения света
  double levyStep [];        // массив для шагов Леви

  // Отслеживание фаз
  bool   inLocalSearchPhase; // флаг локального поиска
  int    localSearchCenter;  // центр локального поиска
  int    localSearchCounter; // счетчик итераций локального поиска

  // Отслеживание сходимости
  double prevBestFitness;    // предыдущее лучшее значение
  int    stagnationCounter;  // счетчик стагнации

  // Отслеживание эпох
  int    epochCurrent;       // текущая эпоха
  int    epochMax;           // максимальное количество эпох

  // Вспомогательные методы
  void   GlobalExploration  ();
  void   LocalExploitation  ();
  void   GenerateLevyStep   ();
  double GenerateGaussian   ();
  double Gamma              (double z);
};
//————————————————————————————————————————————————————————————————————

O método "Init" da classe "C_AO_ES" executa a inicialização do algoritmo de otimização antes do início do processo de busca. Primeiro é chamado o método "StandardInit", responsável pela inicialização padrão do algoritmo, que realiza a configuração dos parâmetros gerais e das estruturas de dados; se "StandardInit" terminar sem sucesso, então todo o método retorna "false", sinalizando falha na inicialização.

Em seguida, é alocada memória para o array "levyStep" com tamanho igual ao número de coordenadas "coords". Esse array será utilizado para armazenar os passos gerados conforme a distribuição de Lévy. Ao sinalizador "inLocalSearchPhase" é atribuído o valor "false", indicando que o algoritmo inicia na fase de busca global. As variáveis "localSearchCenter" e "localSearchCounter" são definidas como "0", preparando os contadores para a busca local.

Inicialização dos parâmetros de convergência:

  • prevBestFitness é definido com o valor mínimo possível, para que a primeira solução encontrada seja garantidamente considerada melhor que a anterior.
  • stagnationCounter é definido como "0" para acompanhar a quantidade de iterações sem melhoria da melhor solução encontrada.

Inicialização dos parâmetros de épocas:

  • epochMax recebe o valor do parâmetro de entrada "epochsP", que define o número máximo de épocas, iterações, de execução do algoritmo.
  • epochCurrent é definido como "0" para acompanhar a época atual.

Definição de um parâmetro fixo: à variável "gamma_es" é atribuído o valor "1.0". Esse parâmetro é utilizado no algoritmo "Firefly", que faz parte da estratégia geral.

É inicializada a população inicial de soluções "a". Para cada solução na população:

  • Cada coordenada do vetor de solução, a[i].c[c], é inicializada com um valor aleatório dentro do intervalo [rangeMin[c], rangeMax[c]].
  • O valor de cada coordenada é arredondado para o valor permitido mais próximo, considerando o passo rangeStep[c], utilizando o método "u.SeInDiSp".
  • O valor da função objetivo, a[i].f e a[i].fB, para cada solução é definido como "-DBL_MAX".
//————————————————————————————————————————————————————————————————————
bool C_AO_ES::Init (const double &rangeMinP  [],
                    const double &rangeMaxP  [],
                    const double &rangeStepP [],
                    const int     epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  // Инициализация массивов
  ArrayResize (levyStep, coords);

  // Инициализация отслеживания фаз
  inLocalSearchPhase = false;
  localSearchCenter  = 0;
  localSearchCounter = 0;

  // Инициализация отслеживания сходимости
  prevBestFitness   = -DBL_MAX;
  stagnationCounter = 0;

  // Инициализация отслеживания эпох
  epochMax     = epochsP;
  epochCurrent = 0;

  // Фиксированный параметр Firefly
  gamma_es = 1.0;

  // Инициализация популяции случайным образом
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      a [i].c [c] = u.SeInDiSp  (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }

    a [i].f  = -DBL_MAX;
    a [i].fB = -DBL_MAX;
  }

  return true;
}
//————————————————————————————————————————————————————————————————————

O método "Moving" implementa a lógica principal do processo iterativo de otimização, alternando entre a busca global e a intensificação local. Cada chamada do método incrementa o contador de épocas para acompanhar o progresso do algoritmo.

Processamento das fases de busca:
  • se a fase atual for busca global, é realizada a exploração do espaço por meio de passos modelados segundo a distribuição de Lévy, com geração de novas soluções em todo o espaço para identificar áreas com potencial;

  • se após a busca global for encontrada uma melhoria, o algoritmo alterna parafase local. Nesse caso, é selecionada a solução mais promissora, o agente, em torno da qual será realizada a busca para seu refinamento;

  • se não ocorrerem melhorias durante várias iterações, acumulando estagnação, a atividade de busca por novas soluções é aumentada por meio de passos mais agressivos, reduzindo o parâmetro "lambda" para uma exploração mais ampla do espaço;

  • caso o algoritmo esteja na fase de busca local, com probabilidade de 80% é executada a otimização local utilizando um método que modela o algoritmo "Firefly". Nesse caso, ocorre o refinamento da solução selecionada, e o contador de iterações locais é incrementado, após atingir o número definido de iterações locais ou por decisão do critério adotado, ocorre o retorno à busca global. 

Uma influência adicional randomizada com determinada probabilidade de modificar as soluções da população é direcionada à preservação da diversidade e à prevenção de aprisionamento em armadilhas locais.

    Dessa forma, o método implementa uma estratégia de busca gradual e flexível, com transição entre a exploração global do espaço e a otimização local direcionada. Isso permite equilibrar a exploração de novas áreas com a melhoria das soluções existentes.

    //————————————————————————————————————————————————————————————————————
    void C_AO_ES::Moving ()
    {
      epochCurrent++;
    
      // ПРИНЯТИЕ РЕШЕНИЯ О ФАЗЕ: Чередование между глобальным и локальным поиском
      if (!inLocalSearchPhase)
      {
        // ФАЗА 1: ГЛОБАЛЬНОЕ ИССЛЕДОВАНИЕ с использованием полетов Леви
        GlobalExploration ();
    
        // Проверка необходимости переключения на локальный поиск
        // Переключаемся, если нашли многообещающую область (улучшение лучшей приспособленности)
        if (fB > prevBestFitness)
        {
          inLocalSearchPhase = true;
          localSearchCounter = 0;
          prevBestFitness    = fB;
          stagnationCounter  = 0;
    
          // Поиск лучшего агента для центрирования локального поиска
          localSearchCenter = 0;
          double bestFit = -DBL_MAX;
    
          for (int i = 0; i < popSize; i++)
          {
            if (a [i].f > bestFit)
            {
              bestFit = a [i].f;
              localSearchCenter = i;
            }
          }
        }
        else
        {
          stagnationCounter++;
    
          // При стагнации увеличиваем исследование
          if (stagnationCounter > 5)
          {
            lambda = MathMax (1.0, lambda - 0.1); // Делаем полеты Леви более агрессивными
          }
        }
      }
      else
      {
        if (u.RNDprobab () < 0.8)
        {
          // ФАЗА 2: ЛОКАЛЬНАЯ ЭКСПЛУАТАЦИЯ с использованием алгоритма Firefly
          LocalExploitation ();
    
          localSearchCounter++;
    
          // Возврат к глобальному поиску после завершения локальных итераций
          if (localSearchCounter >= localIterations)
          {
            inLocalSearchPhase = false;
            lambda = params [1].val; // Сброс lambda к исходному значению
          }
        }
        else
        {
          for (int i = 0; i < popSize; i++)
          {
            for (int c = 0; c < coords; c++)
            {
              if (u.RNDprobab () < 0.5)
              {
                a [i].c [c] = cB [c];
              }
            }
          }
        }
      }
    }
    //————————————————————————————————————————————————————————————————————

    O método "Revision" é destinado a atualizar as informações sobre as melhores soluções durante a execução do algoritmo. O método percorre todos os elementos da população atual de soluções e, para cada solução, compara sua adaptabilidade atual, fitness, com o melhor resultado pessoal armazenado. Se o valor atual for melhor, então o melhor resultado pessoal e a solução correspondente são atualizados, preservando a melhor solução da iteração atual.

    Em seguida, o método compara a adaptabilidade de cada solução com o melhor valor global atual encontrado em toda a população e, se o resultado atual for o melhor, o resultado global é atualizado e a solução correspondente é armazenada. Assim, o método mantém informações atualizadas sobre as soluções ótimas locais e globais no estado atual do algoritmo, garantindo a preservação das melhores soluções encontradas a cada passo.

    //————————————————————————————————————————————————————————————————————
    void C_AO_ES::Revision ()
    {
      for (int i = 0; i < popSize; 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 (a [i].f > fB)
        {
          fB = a [i].f;
          ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY);
        }
      }
    }
    //————————————————————————————————————————————————————————————————————

    O método "GlobalExploration" implementa a fase de busca global utilizando voos de Lévy para explorar o espaço de soluções. Para cada solução no laço que percorre toda a população, é gerado um passo aleatório com base na distribuição de Lévy, que define a direção e o comprimento do deslocamento no espaço de soluções.

    A distribuição de Lévy é caracterizada por caudas pesadas, o que permite realizar tanto pequenos passos de refinamento quanto grandes saltos raros para explorar áreas distantes. No laço para cada coordenada da solução são calculados:

    • a amplitude de busca, diferença entre o valor máximo e mínimo da coordenada,
    • o coeficiente adaptativo de escala "stepScale". Ele diminui à medida que o processo de busca avança, quanto mais próximo do final, menores os passos, contribuindo para o estreitamento da área de busca em torno de soluções promissoras, enquanto no início os passos são maiores para uma exploração mais ampla.
    • é aplicado o passo de Lévy: a coordenada da solução atual é alterada por um valor proporcional ao passo de Lévy, à amplitude de busca e ao coeficiente de escala.
    • correção de limites: verifica-se se a nova coordenada ultrapassou os limites permitidos; se isso ocorrer, o valor é ajustado para permanecer dentro do intervalo definido.
    Como resultado, o método atualiza a posição de cada solução na população utilizando passos obtidos com base na distribuição de Lévy, garantindo assim a exploração global do espaço de soluções com controle adaptativo do tamanho do passo conforme o progresso da otimização. Isso permite explorar amplamente o espaço no início e gradualmente refinar os resultados à medida que se aproxima da solução ótima.
    //————————————————————————————————————————————————————————————————————
    // ФАЗА 1: Глобальное исследование с использованием полетов Леви
    void C_AO_ES::GlobalExploration ()
    {
      for (int i = 0; i < popSize; i++)
      {
        // Генерация шага Леви
        GenerateLevyStep ();
    
        // Обновление позиции с использованием полета Леви
        for (int c = 0; c < coords; c++)
        {
          double range = rangeMax [c] - rangeMin [c];
    
          // Адаптивный размер шага в зависимости от прогресса поиска
          double progress = (epochMax > 0) ? (double)epochCurrent / (double)epochMax : 0.5;
          double stepScale = 0.01 + 0.2 * (1.0 - progress); // Начинаем с больших шагов
    
          // Применение шага Леви
          a [i].c [c] += levyStep [c] * range * stepScale;
    
          // Ограничения границ
          a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    }
    //————————————————————————————————————————————————————————————————————

    O método "LocalExploitation" implementa a etapa de melhoria local das soluções por meio do algoritmo Firefly. Na fase inicial são determinados os agentes que se encontram dentro de uma hiperesfera definida ao redor da melhor solução. Para isso, calcula-se a distância de cada agente até o centro da hiperesfera e, se ela for menor que o raio ou se o agente for o próprio centro da busca, ele é incluído no grupo selecionado.

    Se dentro da hiperesfera houver poucos agentes, a área de busca é expandida por meio dos vizinhos mais próximos. Para isso, é calculada a distância de todos os agentes até o centro, e são selecionados os mais próximos — seja por quantidade fixa, por exemplo 5, seja por fração da população, por exemplo 30%. Esses agentes são adicionados ao grupo.

    Aplicação do algoritmo Firefly: nos agentes selecionados ocorre a interação de acordo com as regras do algoritmo:
    • Para cada agente é verificado se existe no grupo outro agente com melhor adaptabilidade.
    • Se existir, o agente atual move-se na direção do agente mais atrativo, isto é, melhor, sendo calculada a distância entre eles.
    • Quanto mais atrativo for o outro agente, maior sua "luminosidade", que depende da distância e dos parâmetros do algoritmo.
    • O movimento inclui uma combinação cuidadosa, o agente desloca-se na direção do agente mais atrativo com a adição de oscilações aleatórias para manter a diversidade da busca.
    • Após os deslocamentos, são verificados os limites das coordenadas para garantir que as soluções permaneçam dentro do intervalo permitido.

      Como resultado, o método permite melhorar localmente as soluções nas proximidades dos melhores pontos encontrados, utilizando a interação dos agentes conforme o modelo da estratégia do algoritmo Firefly: soluções melhores atraem as piores, promovendo uma otimização pontual do espaço de soluções.

      //————————————————————————————————————————————————————————————————————
      // ФАЗА 2: Локальная эксплуатация с использованием алгоритма Firefly
      void C_AO_ES::LocalExploitation ()
      {
        // Идентификация агентов внутри гиперсферы вокруг лучшего решения
        double agents_in_sphere [];
        ArrayResize (agents_in_sphere, 0);
      
        for (int i = 0; i < popSize; i++)
        {
          double normalized_dist = 0.0;
      
          for (int c = 0; c < coords; c++)
          {
            double diff = (a [i].c [c] - a [localSearchCenter].c [c]) / (rangeMax [c] - rangeMin [c]);
            normalized_dist += diff * diff;
          }
          normalized_dist = MathSqrt (normalized_dist);
      
          // Включаем агентов внутри сферы или сам центр
          if (normalized_dist <= sphereRadius || i == localSearchCenter)
          {
            int size = ArraySize (agents_in_sphere);
            ArrayResize (agents_in_sphere, size + 1);
            agents_in_sphere [size] = i;
          }
        }
      
        // Если слишком мало агентов, расширяем до ближайших соседей
        if (ArraySize (agents_in_sphere) < 5)
        {
          ArrayResize (agents_in_sphere, 0);
      
          // Вычисляем расстояния для всех агентов
          double distances [];
          ArrayResize (distances, popSize);
      
          for (int i = 0; i < popSize; i++)
          {
            if (i == localSearchCenter)
            {
              distances [i] = 0.0;
            }
            else
            {
              double dist = 0.0;
              for (int c = 0; c < coords; c++)
              {
                double diff = (a [i].c [c] - a [localSearchCenter].c [c]) / (rangeMax [c] - rangeMin [c]);
                dist += diff * diff;
              }
              distances [i] = MathSqrt (dist);
            }
          }
      
          // Берем ближайших 5 агентов или 30% популяции
          int numAgents = MathMin (popSize, MathMax (5, popSize / 3));
          ArrayResize (agents_in_sphere, numAgents);
      
          // Простой выбор ближайших агентов
          for (int k = 0; k < numAgents; k++)
          {
            double minDist = DBL_MAX;
            int minIdx = -1;
      
            for (int i = 0; i < popSize; i++)
            {
              bool already_selected = false;
      
              for (int j = 0; j < k; j++)
              {
                if (agents_in_sphere [j] == i)
                {
                  already_selected = true;
                  break;
                }
              }
      
              if (!already_selected && distances [i] < minDist)
              {
                minDist = distances [i];
                minIdx = i;
              }
            }
      
            agents_in_sphere [k] = minIdx;
          }
        }
      
        // Выполнение алгоритма Firefly на выбранных агентах
        int numLocalAgents = ArraySize (agents_in_sphere);
      
        for (int i = 0; i < numLocalAgents; i++)
        {
          int idx_i = (int)agents_in_sphere [i];
      
          for (int j = 0; j < numLocalAgents; j++)
          {
            if (i == j) continue;
      
            int idx_j = (int)agents_in_sphere [j];
      
            // Если агент j лучше агента i, двигаем i к j
            if (a [idx_j].f > a [idx_i].f)
            {
              // Вычисление расстояния
              double r_squared = 0.0;
      
              for (int c = 0; c < coords; c++)
              {
                double diff = (a [idx_j].c [c] - a [idx_i].c [c]) / (rangeMax [c] - rangeMin [c]);
                r_squared += diff * diff;
              }
      
              // Вычисление привлекательности
              double beta = beta0 * MathExp (-gamma_es * r_squared);
      
              // Перемещение агента i к агенту j
              for (int c = 0; c < coords; c++)
              {
                double range = rangeMax [c] - rangeMin [c];
      
                // Уравнение движения Firefly
                a [idx_i].c [c] += beta * (a [idx_j].c [c] - a [idx_i].c [c]) +
                                   alpha * (u.RNDfromCI (-0.5, 0.5)) * range * 0.1;
      
                // Применение границ
                a [idx_i].c [c] = u.SeInDiSp (a [idx_i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
              }
            }
          }
        }
      }
      //————————————————————————————————————————————————————————————————————

      O método "GenerateLevyStep" é responsável por gerar o passo de Lévy necessário para implementarestratégia de exploração global no algoritmo de otimização. O método utiliza o algoritmo de Mantegna para gerar esses passos, já descrito anteriormente.

      Cálculo de sigma:

      A fórmula no código calcula o parâmetro "sigma". Esse parâmetro está relacionado à escala da distribuição de Lévy e depende da constante "lambda", que caracteriza a forma da distribuição de Lévy, determinando o quão pesadas serão as caudas da distribuição. Gamma() é a função gama, uma generalização do fatorial para números reais, cujo código é apresentado abaixo. Esse parâmetro é necessário para gerar valores que seguem a distribuição normal e que posteriormente são utilizados no algoritmo de Mantegna.

      A geração do passo de Lévy ocorre de forma independente para cada coordenada, parâmetro, da solução. São geradas duas variáveis aleatórias "u_val" e "v_val" a partir da distribuição normal, gaussiana, sendo que "v_val" é tomado em valor absoluto. O passo de Lévy "levyStep[c]" é calculado segundo a fórmula do algoritmo de Mantegna: u_val / Math.pow(v_val, 1.0 / lambda). É realizada uma verificação para o caso de divisão por zero, quando v_val for muito pequeno. O passo de Lévy é limitado em valor absoluto para evitar saltos excessivamente grandes. Isso é feito para prevenir deslocamentos extremamente grandes.

      Como resultado da execução do método é gerado o array "levyStep", contendo os valores dos passos de Lévy para cada coordenada. Esses passos são então utilizados no método "GlobalExploration" para atualizar a posição de cada solução no espaço de busca.

      //————————————————————————————————————————————————————————————————————
      // Генерация шага Леви с использованием алгоритма Мантенья
      void C_AO_ES::GenerateLevyStep ()
      {
        // Вычисление сигмы для алгоритма Мантенья
        double numerator   = Gamma (1.0 + lambda) * MathSin (M_PI * lambda / 2.0);
        double denominator = Gamma ((1.0 + lambda) / 2.0) * lambda * MathPow (2.0, (lambda - 1.0) / 2.0);
        double sigma = MathPow (numerator / denominator, 1.0 / lambda);
      
        for (int c = 0; c < coords; c++)
        {
          // Генерация u и v из нормальных распределений
          double u_val = GenerateGaussian () * sigma;
          double v_val = MathAbs (GenerateGaussian ());
      
          // Вычисление шага Леви
          if (v_val > 1e-10)
          {
            levyStep [c] = u_val / MathPow (v_val, 1.0 / lambda);
          }
          else
          {
            levyStep [c] = 0.0;
          }
      
          // Ограничение экстремальных значений
          if (MathAbs (levyStep [c]) > 10.0)
          {
            levyStep [c] = 10.0 * (levyStep [c] > 0 ? 1.0 : -1.0);
          }
        }
      }
      //————————————————————————————————————————————————————————————————————

      O método "GenerateGaussian" implementa a geração de números aleatórios que seguem a distribuição normal, gaussiana, com média "0" e desvio padrão "1". Ele utiliza a transformação de Box-Muller, um método bastante difundido para essa finalidade, já aplicado em artigos anteriores.

      São utilizadas as variáveis estáticas "hasSpare" e "spare"; a transformação de Box-Muller gera dois números aleatórios independentes com distribuição normal por vez, hasSpare é uma variável lógica que indica se um dos números gerados foi armazenado para a próxima chamada da função, e spare é a variável que armazena esse valor de reserva.

        Geração de novos números aleatórios (se necessário):

        Se não houver número de reserva, então: são geradas duas variáveis aleatórias independentes "u_val" e "v_val" com distribuição uniforme no intervalo (0, 1). A função "u.RNDfromCI" é responsável pela geração de números com distribuição uniforme. Aplica-se a transformação de Box-Muller:

        • Calcula-se "mag", magnitude, como a raiz quadrada de -2.0 * Math.log(u_val + 1e-10). A adição de um pequeno valor a "u_val" é necessária para evitar o cálculo do logaritmo de zero, o que é inadmissível.
        • Calcula-se o número de reserva "spare" como mag * Math.cos(2.0 * M_PI * v_val).
        • Retorna-se o valor mag * Math.sin(2.0 * M_PI * v_val).

        O método retorna um dos números aleatórios gerados que seguem a distribuição normal.
        //————————————————————————————————————————————————————————————————————
        // Генерация гауссовского случайного числа с использованием преобразования Бокса-Мюллера
        double C_AO_ES::GenerateGaussian ()
        {
          static bool hasSpare = false;
          static double spare;
        
          if (hasSpare)
          {
            hasSpare = false;
            return spare;
          }
        
          hasSpare = true;
          double u_val = u.RNDfromCI (0.0, 1.0);
          double v_val = u.RNDfromCI (0.0, 1.0);
        
          double mag = MathSqrt (-2.0 * MathLog (u_val + 1e-10));
          spare = mag * MathCos (2.0 * M_PI * v_val);
        
          return mag * MathSin (2.0 * M_PI * v_val);
        }
        //————————————————————————————————————————————————————————————————————

        O método "Gamma" é uma função que aproxima a função gama para um argumento dado "z". Como a função gama é uma função matemática importante, especialmente em estatística e otimização, mas seu cálculo exato pode ser difícil e custoso, utilizam-se frequentemente aproximações. Empregamos a aproximação de Lanczos, que fornece boa precisão com custo computacional relativamente baixo. Destacamos os principais pontos.

        Se o argumento "z" for menor que "0.5", aplica-se a fórmula de reflexão de Euler. Isso permite calcular a função gama para argumentos próximos de zero. A fórmula de reflexão relaciona a função gama de "z" com a função gama de "1 − z". Utilizam-se coeficientes fixos de Lanczos, cuidadosamente selecionados para garantir alta precisão da aproximação, bem como coeficientes e fórmulas que incluem funções de potência e exponenciais. O método retorna o valor aproximado da função gama para o argumento "z".

        A aproximação de Lanczos oferece precisão suficiente para a maioria das aplicações práticas. O algoritmo é relativamente eficiente, pois requer apenas algumas operações aritméticas e consulta a coeficientes pré-calculados. É adequado para uma ampla faixa de valores do argumento, especialmente em combinação com a fórmula de reflexão. De modo geral, o método "Gamma" representa uma forma suficientemente precisa de aproximação da função gama.

        //————————————————————————————————————————————————————————————————————
        // Аппроксимация гамма-функции с использованием аппроксимации Ланцоша
        double C_AO_ES::Gamma (double z)
        {
          if (z < 0.5)
          {
            // Формула отражения для z < 0.5
            return M_PI / (MathSin (M_PI * z) * Gamma (1.0 - z));
          }
        
          // Коэффициенты Ланцоша
          const double g = 7.0;
          double coef [] =
          {
            0.99999999999980993,
            676.5203681218851,
            -1259.1392167224028,
            771.32342877765313,
            -176.61502916214059,
            12.507343278686905,
            -0.13857109526572012,
            9.9843695780195716e-6,
            1.5056327351493116e-7
          };
        
          z -= 1.0;
          double x = coef [0];
        
          for (int i = 1; i < 9; i++)
          {
            x += coef [i] / (z + i);
          }
        
          double t = z + g + 0.5;
          double sqrt2pi = MathSqrt (2.0 * M_PI);
        
          return sqrt2pi * MathPow (t, z + 0.5) * MathExp (-t) * x;
        }
        //————————————————————————————————————————————————————————————————————


        Resultados dos testes

        Embora o algoritmo não tenha conseguido entrar em nossa tabela classificatória, os resultados de seu desempenho merecem atenção.

        ES|Eagle Strategy|100.0|1.0|0.1|20.0|0.1|1.2|
        =============================
        5 Hilly's; Func runs: 10000; result: 0.7077570016043803
        25 Hilly's; Func runs: 10000; result: 0.4307775904381953
        500 Hilly's; Func runs: 10000; result: 0.2747545259235643
        =============================
        5 Forest's; Func runs: 10000; result: 0.7173720280531499
        25 Forest's; Func runs: 10000; result: 0.3448423301485268
        500 Forest's; Func runs: 10000; result: 0.1597390810339928
        =============================
        5 Megacity's; Func runs: 10000; result: 0.5184615384615384
        25 Megacity's; Func runs: 10000; result: 0.2775384615384615
        500 Megacity's; Func runs: 10000; result: 0.11063076923077016
        =============================
        All score: 3.54187 (39.35%)

        Na visualização é claramente perceptível como as fases de busca se separam por estratégias, quando ocorrem lançamentos longos e movimentos curtos de refinamento.

        Hilly

        ES na função de teste Hilly

        Forest

        ES na função de teste Forest

        Megacity

        ES na função de teste Megacity

        O algoritmo ES é apresentado na tabela classificatória para fins informativos.

        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 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
        13 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
        14 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
        15 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
        16 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
        17 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
        18 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
        19 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
        20 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
        21 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
        22 CRO chemical reaction optimisation 0,94629 0,66112 0,29853 1,90593 0,87906 0,58422 0,21146 1,67473 0,75846 0,42646 0,12686 1,31178 4,892 54,36
        23 BIO 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
        24 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
        25 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
        26 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
        27 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
        28 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
        29 (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
        30 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
        31 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
        32 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
        33 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
        34 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
        35 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
        36 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
        37 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
        38 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
        39 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
        40 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
        41 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
        42 ADAMm adaptive moment estimation M 0,88635 0,44766 0,26613 1,60014 0,84497 0,38493 0,16889 1,39880 0,66154 0,27046 0,10594 1,03794 4,037 44,85
        43 CGO chaos game optimization 0,57256 0,37158 0,32018 1,26432 0,61176 0,61931 0,62161 1,85267 0,37538 0,21923 0,19028 0,78490 3,902 43,35
        44 CROm coral reefs optimization M 0,78512 0,46032 0,25958 1,50502 0,86688 0,35297 0,16267 1,38252 0,63231 0,26738 0,10734 1,00703 3,895 43,27
        45 ATAm artificial tribe algorithm M 0,71771 0,55304 0,25235 1,52310 0,82491 0,55904 0,20473 1,58867 0,44000 0,18615 0,09411 0,72026 3,832 42,58
        ES eagle_strategy_optimization 0,70776 0,43078 0,27475 1,41328 0,71737 0,34484 0,15973 1,22194 0,51846 0,27754 0,11063 0,90663 3,542 39,35
        RW neuroboids optimization algorithm 2(joo) 0,48754 0,32159 0,25781 1,06694 0,37554 0,21944 0,15877 0,75375 0,27969 0,14917 0,09847 0,52734 2,348 26,09


        Considerações finais

        O algoritmo ES demonstra resultados médios nos testes comparativos de métodos populacionais de otimização, obtendo 39% da pontuação máxima possível, o que não lhe permitiu entrar na tabela classificatória dos 45 algoritmos mais fortes.

        Apesar disso, o algoritmo merece atenção graças à sua concepção original de busca em duas fases, baseada em um modelo biologicamente fundamentado do comportamento de caça da águia. O uso de voos de Lévy para a exploração global representa uma solução matematicamente elegante, cuja eficácia teórica foi comprovada para tarefas de busca aleatória. Os mecanismos adaptativos de implementação, incluindo a alternância dinâmica entre fases e o ajuste automático de parâmetros em caso de estagnação, demonstram potencial para o aprimoramento do conceito básico.

        O algoritmo pode encontrar seu nicho em classes específicas de problemas, nas quais é importante o equilíbrio entre exploração global e intensificação local, especialmente na presença de múltiplos ótimos locais e dados com ruído. A integração do algoritmo Firefly para a busca local cria uma sinergia interessante entre dois métodos inspirados na natureza, embora o desempenho geral indique a necessidade de otimização adicional dos parâmetros e possível modificação dos mecanismos fundamentais.

        O algoritmo ES pode ser considerado como um exemplo didático de abordagem híbrida para otimização e como base para o desenvolvimento de métodos mais avançados que combinem diferentes metaheurísticas. Sua implementação relativamente simples e lógica intuitiva tornam o algoritmo adequado para experimentos de pesquisa na área de computação evolutiva.

        tab

        Figura 2. Graduação de cores dos algoritmos nos testes correspondentes

        chart

        Figura 3. Histograma dos resultados dos testes dos algoritmos (na escala de 0 a 100, quanto maior, melhor, onde 100 — resultado teórico máximo possível, no arquivo há o script para cálculo da tabela classificatória)

        Vantagens e desvantagens do algoritmo ES:

        Vantagens:

        1. Rápido.

        Desvantagens:

        1. Grande quantidade de parâmetros.

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


        Programas utilizados no artigo

        # Nome Tipo Descrição
        1 #C_AO.mqh
        Arquivo de inclusão
        Classe base dos algoritmos populacionais de otimização
        2 #C_AO_enum.mqh
        Arquivo de inclusão
        Enumeração dos algoritmos populacionais de otimização
        3 TestFunctions.mqh
        Arquivo de inclusão
        Biblioteca de funções de teste
        4
        TestStandFunctions.mqh
        Arquivo de inclusão
        Biblioteca de funções do ambiente de testes
        5
        Utilities.mqh
        Arquivo de inclusão
        Biblioteca de funções auxiliares
        6
        CalculationTestResults.mqh
        Arquivo de inclusão
        Script para cálculo dos resultados na tabela comparativa
        7
        Testing AOs.mq5
        Script Ambiente de testes unificado para todos os algoritmos populacionais de otimização
        8
        Simple use of population optimization algorithms.mq5
        Script
        Exemplo simples de uso de algoritmos populacionais de otimização sem visualização
        9
        Test_AO_ES.mq5
        Script Ambiente de testes para ES

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

        Arquivos anexados |
        ES.ZIP (290.51 KB)
        A análise de lacunas temporais de preço em MQL5 (Parte I): Criando um indicador básico A análise de lacunas temporais de preço em MQL5 (Parte I): Criando um indicador básico
        A análise de lacunas temporais, ou time gaps, ajuda o trader a identificar potenciais pontos de reversão do mercado. O artigo examina o que é um time gap, como interpretá-lo e de que maneira ele pode ser utilizado para detectar a entrada de grande volume no mercado.
        Técnicas do MQL5 Wizard que você deve conhecer (Parte 55): SAC com Prioritized Experience Replay Técnicas do MQL5 Wizard que você deve conhecer (Parte 55): SAC com Prioritized Experience Replay
        Buffers de replay em Aprendizado por Reforço são particularmente importantes com algoritmos off-policy como DQN ou SAC. Isso coloca em destaque o processo de amostragem desse buffer de memória. Enquanto as opções padrão com SAC, por exemplo, utilizam seleção aleatória desse buffer, o Prioritized Experience Replay ajusta esse processo ao realizar amostragem com base em um score TD. Revisamos a importância do Aprendizado por Reforço e, como sempre, examinamos apenas essa hipótese (não a validação cruzada) em um Expert Advisor montado com o wizard.
        Redes neurais em trading: Segmentação periódica adaptativa (LightGTS) Redes neurais em trading: Segmentação periódica adaptativa (LightGTS)
        Propomos conhecer uma técnica inovadora de patching adaptativo, um método de segmentar séries temporais de forma flexível considerando sua periodicidade interna. Além disso, apresentamos uma técnica de codificação eficiente que permite preservar características semânticas importantes ao trabalhar com dados de diferentes escalas. Esses métodos abrem novas possibilidades para o processamento preciso de dados complexos multiescalares, característicos dos mercados financeiros, e aumentam significativamente a estabilidade e a fundamentação das previsões.
        Do básico ao intermediário: Sub Janelas (IV) Do básico ao intermediário: Sub Janelas (IV)
        Neste artigo iremos ver que nem tudo é como muitos pensam ser no inicio. Uma das coisas mais interessantes em utilizar a programação é o fato de que podemos garantir que as coisas sempre serão da forma como as planejamos. Então leiam este artigo com atenção, para que possam aprender alguns dos conceitos mais confusos envolvidos no uso de sub janelas. Se você entender o que será explicado aqui, irá conseguir fazer compreender diversas coisas que iremos fazer futuramente.