Algoritmos de otimização populacionais: Algoritmo do morcego

Andrey Dik | 27 abril, 2023

Conteúdo

1. Introdução
2. Descrição do algoritmo
3. Resultado dos testes


1. Introdução

Os morcegos são animais fascinantes. Os cientistas acreditam que eles surgiram há 65-100 milhões de anos, juntamente com os dinossauros. Entre todos os mamíferos, apenas os morcegos possuem asas. Existem mais de 1300 espécies desses animais alados, encontrados em quase todos os lugares, exceto nas regiões polares. Durante o dia, eles se escondem em abrigos. Para se locomover em cavernas escuras e caçar após o anoitecer, os morcegos contam com a ecolocalização, um sistema que lhes permite detectar objetos usando ondas sonoras. Eles emitem um som de alta frequência que se propaga até atingir um objeto e é refletido de volta, permitindo que os morcegos se orientem no espaço e determinem a posição de suas presas. A ecolocalização é uma espécie de sonar, no qual o morcego emite um som curto e pulsado, e quando o som atinge um objeto, o eco retorna aos seus ouvidos após um curto período de tempo. 

O algoritmo do Morcego (BA) é um algoritmo heurístico apresentado por Yang em 2010 que imita o comportamento de ecolocalização dos morcegos para realizar otimização global. As metaheurísticas, geralmente inspiradas na natureza e em processos físicos, são agora utilizadas como uma das técnicas mais poderosas para resolver muitos problemas complexos de otimização. A otimização consiste na seleção dos melhores elementos para um determinado conjunto de critérios a partir de uma série de opções eficientes, mostrando várias vantagens e desvantagens em termos de eficiência computacional e probabilidade de otimização global.

A otimização de funções oferece uma base formal para modelar e resolver uma série de problemas específicos, fornecendo uma função "objetivo" que usa um parâmetro como entrada e o objetivo é encontrar o valor do parâmetro combinado para retornar o melhor valor. Essa estrutura é suficientemente abstrata para que diferentes problemas possam ser interpretados como problemas de "otimização de funções".


No entanto, a otimização de funções tradicional é utilizada apenas para resolver alguns problemas pequenos, que muitas vezes não são aplicáveis na prática. Por isso, os cientistas estão voltando sua atenção para a natureza, que fornece modelos ricos para resolver esses problemas. Ao modelar sistemas biológicos naturais, são propostos muitos algoritmos inteligentes de otimização de enxame para resolver problemas aplicados usando métodos não tradicionais. Esses algoritmos são amplamente utilizados em diversos problemas de otimização devido ao seu excelente desempenho. O BA é um novo e moderno algoritmo, semelhante a um enxame, que realiza um processo de busca usando morcegos artificiais como agentes de busca, simulando o volume de pulso de som natural e a frequência de emissão de morcegos reais.


2. Descrição do algoritmo

Na versão básica do algoritmo do morcego, cada morcego é tratado como uma partícula "sem massa e sem tamanho" que representa uma solução válida no espaço de soluções. Para diferentes funções de adaptação, cada morcego possui um valor correspondente e determina o indivíduo ideal atual comparando os valores. Em seguida, a frequência da onda acústica, a velocidade, a velocidade de emissão de impulsos e o volume de cada morcego na população são atualizados, a evolução iterativa continua, a solução ótima atual é aproximada e gerada e, finalmente, a solução ótima global é encontrada. O algoritmo atualiza a frequência, velocidade e posição de cada morcego.

O algoritmo padrão requer cinco parâmetros básicos: frequência, volume, pulsação e coeficientes de volume e pulsação. A frequência é usada para equilibrar o impacto da melhor posição histórica na posição atual. Um morcego procurará longe da posição histórica do grupo quando a faixa de frequência de busca for grande, e vice-versa.

Há muitos parâmetros no algoritmo em comparação com outros previamente considerados:

input double MIN_FREQ_P          = 0.0;
input double MAX_FREQ_P         = 1.0;
input double MIN_LOUDNESS_P  = 0.0;
input double MAX_LOUDNESS_P = 1.5;
input double MIN_PULSE_P        = 0.0;
input double MAX_PULSE_P        = 1.0;
input double ALPHA_P               = 0.3;
input double GAMMA_P              = 0.3;

Ao desenvolver o algoritmo BA, deparei-me com a situação em que muitos autores descrevem o algoritmo de maneiras completamente diferentes em várias fontes, incluindo diferenças no uso de termos na descrição dos pontos-chave, bem como nas peculiaridades algorítmicas fundamentais. Portanto, vou descrever como entendi o algoritmo. Os princípios físicos básicos subjacentes à ecolocalização podem ser aplicados no algoritmo com certas ressalvas e convenções significativas. Supõe-se que os ratos usem pulsos sonoros com frequência variando de MinFreq a MaxFreq. A frequência afeta a velocidade de deslocamento do rato no espaço. Também é utilizado o conceito condicional de volume, que afeta a transição do estado de busca local na posição atual do morcego para o global nas proximidades da melhor solução. A frequência da ondulação aumenta ao longo da otimização, enquanto o volume dos sons diminui.

Pseudocódigo do algoritmo BA (Figura 1):

1. Inicialização da população de morcegos.
2. Geração da frequência, da velocidade e das novas soluções.
3. Busca de solução local.
4. Atualização da solução global.
5. Redução do volume e aumento da frequência de pulsação.
6. Repetição do passo 2 até que o critério de parada seja atingido.

scheme

Figura 1. Diagrama de blocos do algoritmo.

Vamos começar descrevendo o código. Vamos agora descrever o código em mais detalhes. Para descrever o agente de busca "morcego", precisamos de uma estrutura que descreva todas as características necessárias para uma descrição completa do estado em cada iteração. A matriz position [] é usada para armazenar as melhores coordenadas de posição no espaço, enquanto a matriz auxPosition [] armazena as coordenadas "operacionais" atuais. Outra matriz, speed [], é necessária para o cálculo do vetor de velocidade por coordenadas. A frequência, representada por "frequency", é a frequência dos pulsos sonoros emitidos. A taxa de pulso inicial, representada por "initPulseRate", é uma taxa de pulso individual para cada morcego desde o início da otimização. Já a taxa de pulso na iteração atual é representada por "pulseRate". A intensidade dos pulsos sonoros é representada por "loudness". O valor da função de adaptação após o último movimento é representado por "fitness", enquanto o melhor valor da função de adaptação do agente para todas as iterações é representado por "fitnessBest". 

//——————————————————————————————————————————————————————————————————————————————
struct S_Bat
{
  double position    [];
  double auxPosition [];
  double speed       [];
  double frequency;
  double initPulseRate;
  double pulseRate;
  double loudness;
  double fitness;
  double fitnessBest;
};
//——————————————————————————————————————————————————————————————————————————————

A classe de algoritmo dos morcegos inclui um conjunto de estruturas de agentes de busca, limites e passo do espaço explorado, as melhores coordenadas encontradas pelo algoritmo, o melhor valor da função de adaptação e constantes para armazenar os parâmetros do algoritmo, além de um método público de inicialização, dois métodos públicos necessários para operação do algoritmo e métodos privados específicos do algoritmo.

//——————————————————————————————————————————————————————————————————————————————
class C_AO_BA
{
  //============================================================================
  public: S_Bat  bats      []; //bats
  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search
  public: double cB        []; //best coordinates
  public: double fB;           //FF of the best coordinates

  public: void Init (const int    paramsP,
                     const int    batsNumberP,
                     const double min_FREQ_P,
                     const double max_FREQ_P,
                     const double min_LOUDNESS_P,
                     const double max_LOUDNESS_P,
                     const double min_PULSE_P,
                     const double max_PULSE_P,
                     const double alpha_P,
                     const double gamma_P,
                     const int    maxIterP);

  public: void Flight (int epoch);
  public: void Preparation ();

  //============================================================================
  private: void Walk               (S_Bat &bat);
  private: void AproxBest          (S_Bat &bat, double averageLoudness);
  private: void AcceptNewSolutions (S_Bat &bat);
  private: int  currentIteration;
  private: int  maxIter;

  private: double MIN_FREQ;
  private: double MAX_FREQ;

  private: double MIN_LOUDNESS;
  private: double MAX_LOUDNESS;

  private: double MIN_PULSE;
  private: double MAX_PULSE;

  private: double ALPHA;
  private: double GAMMA;

  private: int    params;
  private: int    batsNumber;

  private: bool   firstFlight;

  private: double SeInDiSp  (double In, double inMin, double inMax, double step);
  private: double RNDfromCI (double min, double max);
  private: double Scale     (double In, double InMIN, double InMAX, double OutMIN, double OutMAX,  bool revers);
};
//——————————————————————————————————————————————————————————————————————————————

No método público Init(), atribuímos valores aos parâmetros da superestrutura do algoritmo como constantes internas, alocamos memória para os arrays, redefinimos a variável de armazenamento para o melhor ajuste para o seu valor mínimo e também redefinimos o sinalizador para a iteração inicial. Em geral, esse método não é complicado e não tem nada de especial.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_BA::Init (const int    paramsP,
                    const int    batsNumberP,
                    const double min_FREQ_P,
                    const double max_FREQ_P,
                    const double min_LOUDNESS_P,
                    const double max_LOUDNESS_P,
                    const double min_PULSE_P,
                    const double max_PULSE_P,
                    const double alpha_P,
                    const double gamma_P,
                    const int    maxIterP)
{
  MathSrand (GetTickCount ());

  fB = -DBL_MAX;

  params       = paramsP;
  batsNumber   = batsNumberP;
  MIN_FREQ     = min_FREQ_P;
  MAX_FREQ     = max_FREQ_P;
  MIN_LOUDNESS = min_LOUDNESS_P;
  MAX_LOUDNESS = max_LOUDNESS_P;
  MIN_PULSE    = min_PULSE_P;
  MAX_PULSE    = max_PULSE_P;
  ALPHA        = alpha_P;
  GAMMA        = gamma_P;
  maxIter      = maxIterP;

  ArrayResize (rangeMax,  params);
  ArrayResize (rangeMin,  params);
  ArrayResize (rangeStep, params);

  firstFlight = false;

  ArrayResize (bats, batsNumber);

  for (int i = 0; i < batsNumber; i++)
  {
    ArrayResize (bats [i].position,    params);
    ArrayResize (bats [i].auxPosition, params);
    ArrayResize (bats [i].speed,       params);

    bats [i].fitness  = -DBL_MAX;
  }

  ArrayResize (cB, params);
}
//——————————————————————————————————————————————————————————————————————————————

O método Flight() é chamado em cada iteração e concentra a lógica principal de busca, enquanto os detalhes restantes são abstraídos em métodos privados auxiliares, específicos para este algoritmo de otimização. Na primeira iteração, o sinalizador firstFlight é resetado (essa operação ocorre durante a inicialização no método Init()).  Isso significa que é necessário atribuir um estado inicial para cada morcego, que é uma posição aleatória no espaço de busca:

Como podemos observar, todos os morcegos artificiais apresentam individualidade, cada um com um conjunto próprio de características sonoras, tornando-os mais semelhantes aos morcegos naturais. Em toda a população, que pode incluir diversas centenas de milhares de indivíduos, a mãe é capaz de localizar um único filhote pela assinatura sonora única que ele emite.

Se o sinalizador firstFlight estiver ativado, é necessário realizar operações básicas para mover os morcegos. Uma das características interessantes do algoritmo é a utilização do conceito de média de intensidade sonora de toda a população. Em geral, a intensidade do som diminui ao longo de todas as iterações pelo coeficiente alpha. Existem dois tipos de movimento dos morcegos ocorrendo aqui: Walk () - movimento individual com o cálculo do vetor de velocidade para cada componente de coordenada e movimento local nas proximidades da melhor solução.

A cada iteração subsequente, a intensidade das pulsações é reduzida, o que influencia a intensidade da pesquisa das áreas circundantes. Dessa forma, a pesquisa e a exploração são dinamicamente modificadas durante toda a otimização. A seguir, veremos como a iteração atual afeta o comportamento dos morcegos.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_BA::Flight (int epoch)
{
  currentIteration = epoch;

  //============================================================================
  if (!firstFlight)
  {
    fB = -DBL_MAX;

    //--------------------------------------------------------------------------
    for (int b = 0; b < batsNumber; b++)
    {
      for (int p = 0; p < params; p++)
      {
        bats [b].position    [p] = RNDfromCI (rangeMin [p], rangeMax [p]);
        bats [b].position    [p] = SeInDiSp (bats [b].position [p], rangeMin [p], rangeMax [p], rangeStep [p]);
        bats [b].auxPosition [p] = bats [b].position    [p];
        bats [b].speed       [p] = 0.0;
        bats [b].frequency       = RNDfromCI (MIN_FREQ, MAX_FREQ);
        bats [b].initPulseRate   = RNDfromCI (MIN_PULSE, MAX_PULSE / 2);
        bats [b].pulseRate       = bats [b].initPulseRate;
        bats [b].loudness        = RNDfromCI (MAX_LOUDNESS / 2, MAX_LOUDNESS);
        bats [b].fitness         = -DBL_MAX;
        bats [b].fitnessBest     = -DBL_MAX;
      }
    }

    firstFlight = true;
  }
  //============================================================================
  else
  {
    double avgLoudness = 0;

    for (int b = 0; b < batsNumber; b++)
    {
      avgLoudness += bats [b].loudness;
    }

    avgLoudness /= batsNumber;

    for (int b = 0; b < batsNumber; b++)
    {
      Walk (bats [b]);

      if (RNDfromCI (MIN_PULSE, MAX_PULSE) > bats [b].pulseRate)
      {
        AproxBest (bats [b], avgLoudness);
      }
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

O segundo método público obrigatório chamado em cada iteração é o Preparation(), que é necessário para atualizar a melhor solução global. Aqui, podemos ver como o conceito de "volume" é utilizado. À medida que cada iteração avança, o volume de cada morcego é reduzido por meio de um coeficiente (o parâmetro de ajuste alpha), o que diminui a probabilidade de explorar localmente, mas aumenta a intensidade da exploração global. Em outras palavras, a probabilidade de atualizar a melhor posição de cada morcego diminui a cada iteração. Este é um dos momentos do algoritmo que é menos compreendido, pelo menos para mim, mas o autor do algoritmo o implementou, o que significa que é necessário.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_BA::Preparation ()
{
  //----------------------------------------------------------------------------
  for (int b = 0; b < batsNumber; b++)
  {
    if (bats [b].fitness > fB)
    {
      fB = bats [b].fitness;
      ArrayCopy (cB, bats [b].auxPosition, 0, 0, WHOLE_ARRAY);
    }
  }

  //----------------------------------------------------------------------------
  for (int b = 0; b < batsNumber; b++)
  {
    if (RNDfromCI (MIN_LOUDNESS, MAX_LOUDNESS) < bats [b].loudness && bats [b].fitness >= bats [b].fitnessBest)
    {
      AcceptNewSolutions (bats [b]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

O método privado Walk() garante que cada morcego se mova individualmente em relação à sua melhor posição atual até o momento, levando em consideração a melhor solução global. Neste método, é usada a frequência dos impulsos sonoros, que varia aleatoriamente dentro do intervalo [MIN_FREQ;MAX_FREQ]. A frequência é necessária para calcular a velocidade do agente de busca, que é o produto da frequência pela diferença entre a melhor posição do morcego e a melhor solução global. Em seguida, o valor da velocidade é adicionado ao vetor da melhor solução atual do morcego. Portanto, estamos trabalhando com quantidades físicas desproporcionais, mas isso é apenas uma aproximação dos objetos físicos reais. A plausibilidade neste caso deve ser ignorada. Após o cálculo da nova posição, é necessário verificar se as coordenadas estão dentro do intervalo permitido usando o método SeInDiSp().

//——————————————————————————————————————————————————————————————————————————————
void C_AO_BA::Walk (S_Bat &bat)
{
  for (int j = 0; j < params; ++j)
  {
    bat.frequency       = MIN_FREQ + (MAX_FREQ - MIN_FREQ) * RNDfromCI (0.0, 1.0);
    bat.speed       [j] = bat.speed [j] + (bat.position [j] - cB [j]) * bat.frequency;
    bat.auxPosition [j] = bat.position [j] + bat.speed [j];

    bat.auxPosition [j] = SeInDiSp (bat.auxPosition [j], rangeMin [j], rangeMax [j], rangeStep [j]);
  }
}
//——————————————————————————————————————————————————————————————————————————————

O segundo método privado, AproxBest(), é responsável por mover os morcegos em relação à melhor solução global, fornecendo refinamento adicional das coordenadas. Não consigo compreender o significado físico desta ação, que consiste em adicionar vetor a vetor às coordenadas um incremento na forma da intensidade média entre toda a população de morcegos, multiplicado por um número aleatório no intervalo [-1.0; 1.0]. Eu tentei reduzir os valores para a dimensão da função sendo otimizada através do vetor de valores válidos do domínio de definição, mas os resultados dos testes foram piores do que na versão do algoritmo do autor. Por isso, decidi deixar tudo como está. No entanto, estou certo de que a eficiência do algoritmo BA pode ser melhorada, mas isso exigirá pesquisas adicionais, que não foram o objetivo neste caso. Após o cálculo das coordenadas, os valores são verificados para garantir que estejam dentro do intervalo permitido usando o método SeInDiSp().

//——————————————————————————————————————————————————————————————————————————————
void C_AO_BA::AproxBest (S_Bat &bat, double averageLoudness)
{
  for (int j = 0; j < params; ++j)
  {
    bat.auxPosition [j] = cB [j] + averageLoudness * RNDfromCI (-1.0, 1.0);
    bat.auxPosition [j] = SeInDiSp (bat.auxPosition [j], rangeMin [j], rangeMax [j], rangeStep [j]);
  }
}
//——————————————————————————————————————————————————————————————————————————————

Existe outro método privado específico, chamado AcceptNewSolutions(), que é invocado quando a condição de teste para a frequência de pulsação dos impulsos sonoros de cada morcego é atendida. Neste método, a nova melhor solução individual é aceita, recalculando-se o volume individual e a frequência de pulsação individual. Aqui podemos ver como o número de iterações é utilizado no cálculo da frequência de pulsação.

Neste ponto da lógica do algoritmo, eu tomei algumas liberdades e alterei a lógica para tornar o resultado independente da dimensão total do número de iterações, o que acabou por aumentar um pouco a eficiência do algoritmo. Na versão original do autor, o número de iteração estava diretamente envolvido na fórmula não linear de cálculo da frequência de impulsos. Já que existem muitas convenções no BA, neste caso, eu não pude ignorar mais uma.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_BA::AcceptNewSolutions (S_Bat &bat)
{
  ArrayCopy(bat.position, bat.auxPosition, 0, 0, WHOLE_ARRAY);
  bat.fitnessBest = bat.fitness;
  bat.loudness    = ALPHA * bat.loudness;
  double iter     = Scale (currentIteration, 1, maxIter, 0.0, 10.0, false);
  bat.pulseRate   = bat.initPulseRate *(1.0 - exp(-GAMMA * iter));
}
//——————————————————————————————————————————————————————————————————————————————

A Figura 2 mostra a dependência da frequência de pulsação no número da iteração atual (representado pelo eixo x no gráfico) e no parâmetro de configuração GAMMA.

gamma

Figura 2. Dependência da frequência de pulsação do número da iteração atual e do parâmetro de configuração GAMMA com valores de 0,9, 0,7, 0,5, 0,3, 0,2.

3. Resultado dos testes

No artigo anterior, mencionei planos de revisão da metodologia utilizada para calcular a classificação dos algoritmos testados. Em primeiro lugar, como a maioria dos algoritmos lida facilmente com as funções de teste de duas variáveis e a diferença entre os resultados é quase imperceptível, decidi aumentar o número de variáveis para os dois primeiros testes em todas as funções de teste. Agora, o número de variáveis será 10, 50 e 1000.

Em segundo lugar, a função de teste Skin foi substituída pela amplamente utilizada função Rastrigin (Figura 3). Esta função é suave como a Skin, possui uma superfície complexa com muitos extremos locais, um máximo global em quatro pontos e um mínimo global no centro dos eixos coordenados.

Em terceiro lugar, decidi normalizar os resultados dos testes em uma faixa de valores entre todos os algoritmos da tabela, onde o melhor resultado é igual a 1,0 e o pior resultado é igual a 0,0. Isso permite avaliar uniformemente os resultados dos testes, levando em consideração a complexidade das funções em relação aos resultados de cada um dos algoritmos de otimização testados.

Após isso, os resultados dos testes dos algoritmos são somados, e o valor máximo é atribuído a 100 (o valor de referência máximo), enquanto o valor mínimo é atribuído a 1. Isso permite comparar diretamente os algoritmos entre si, levando em consideração a complexidade das funções de teste. Agora, os resultados exibidos no Print() são salvos nos arquivos de origem dos scripts de teste para cada algoritmo, respectivamente, e o script que calcula as pontuações nos testes é anexado ao artigo no arquivo. Ele será atualizado nos artigos subsequentes com a adição dos resultados dos novos algoritmos em consideração.



rastrigin

Figura 3. Função de teste Rastrigin.

Impressão da bancada de teste:

2022.12.28 17:13:46.384    Test_AO_BA (EURUSD,M1)    C_AO_BA:50;0.0;1.0;0.0;1.5;0.0;1.0;0.3;0.3
2022.12.28 17:13:46.384    Test_AO_BA (EURUSD,M1)    =============================
2022.12.28 17:13:48.451    Test_AO_BA (EURUSD,M1)    5 Rastrigin's; Func runs 10000 result: 66.63334336098077
2022.12.28 17:13:48.451    Test_AO_BA (EURUSD,M1)    Score: 0.82562
2022.12.28 17:13:52.630    Test_AO_BA (EURUSD,M1)    25 Rastrigin's; Func runs 10000 result: 65.51391114042588
2022.12.28 17:13:52.630    Test_AO_BA (EURUSD,M1)    Score: 0.81175
2022.12.28 17:14:27.234    Test_AO_BA (EURUSD,M1)    500 Rastrigin's; Func runs 10000 result: 59.84512760590815
2022.12.28 17:14:27.234    Test_AO_BA (EURUSD,M1)    Score: 0.74151
2022.12.28 17:14:27.234    Test_AO_BA (EURUSD,M1)    =============================
2022.12.28 17:14:32.280    Test_AO_BA (EURUSD,M1)    5 Forest's; Func runs 10000 result: 0.5861602092218606
2022.12.28 17:14:32.280    Test_AO_BA (EURUSD,M1)    Score: 0.33156
2022.12.28 17:14:39.204    Test_AO_BA (EURUSD,M1)    25 Forest's; Func runs 10000 result: 0.2895682720055589
2022.12.28 17:14:39.204    Test_AO_BA (EURUSD,M1)    Score: 0.16379
2022.12.28 17:15:14.716    Test_AO_BA (EURUSD,M1)    500 Forest's; Func runs 10000 result: 0.09867854051596259
2022.12.28 17:15:14.716    Test_AO_BA (EURUSD,M1)    Score: 0.05582
2022.12.28 17:15:14.716    Test_AO_BA (EURUSD,M1)    =============================
2022.12.28 17:15:20.843    Test_AO_BA (EURUSD,M1)    5 Megacity's; Func runs 10000 result: 3.3199999999999994
2022.12.28 17:15:20.843    Test_AO_BA (EURUSD,M1)    Score: 0.27667
2022.12.28 17:15:26.624    Test_AO_BA (EURUSD,M1)    25 Megacity's; Func runs 10000 result: 1.2079999999999997
2022.12.28 17:15:26.624    Test_AO_BA (EURUSD,M1)    Score: 0.10067
2022.12.28 17:16:05.013    Test_AO_BA (EURUSD,M1)    500 Megacity's; Func runs 10000 result: 0.40759999999999996
2022.12.28 17:16:05.013    Test_AO_BA (EURUSD,M1)    Score: 0.03397

O algoritmo do morcego mostrou resultados impressionantes na função suave de Rastrigin e, curiosamente, com o aumento do número de variáveis na função, a estabilidade (repetibilidade) dos resultados aumentou, o que indica uma excelente escalabilidade do BA em funções suaves. Portanto, o BA foi o melhor na função de Rastrigin com 50 e 1000 variáveis entre todos os participantes do teste, o que permite recomendá-lo para trabalhar com funções suaves complexas e redes neurais. No entanto, nas funções Forest e Megacity, o algoritmo do morcego apresentou resultados médios, demonstrando uma tendência a ficar preso em extremos locais, com as coordenadas sendo localizadas em grupos e sem mostrar dinâmica de mudança e movimento em direção ao ótimo global. Suponho que esse comportamento do algoritmo se deva ao fato de ser sensível à presença de um gradiente na superfície da função em estudo. Na ausência de um gradiente, o algoritmo para rapidamente nas proximidades de áreas locais que não apresentam um incremento significativo nos valores da função de adaptação. Além disso, o algoritmo BA não possui mecanismos que permitam "saltar" para novas áreas desconhecidas, como o mecanismo implementado no COA com o auxílio de voos de Levy.

É importante enfatizar um aspecto crucial que é a presença de um grande número de parâmetros de ajuste no BA. Não só existem muitos parâmetros (graus de liberdade) em si, mas cada um deles tem um forte impacto nas propriedades de busca e nas taxas de convergência em geral. Alguns parâmetros podem produzir excelentes resultados em funções suaves, enquanto outros são mais adequados para funções discretas e com saltos, e encontrar parâmetros universais que possam lidar igualmente bem com diferentes tipos de funções de teste não é uma tarefa trivial. O código-fonte do algoritmo do morcego está anexado ao artigo com os parâmetros que parecem ser os mais ideais. Em geral, não recomendaria o uso do BA para usuários com pouca experiência em trabalhar com algoritmos de otimização, pois os resultados da otimização podem variar significativamente.  

rastrigin

  BA na função de teste Rastrigin.

forest

BA na função de teste Forest.

megacity

BA na função de teste Megacity.

Ao observar a visualização das funções de teste, é possível obter uma compreensão das características distintas do algoritmo de morcego. Em particular, ao trabalhar em todas as funções de teste, o algoritmo é caracterizado pelo agrupamento de coordenadas em pequenas áreas locais. No entanto, enquanto esse recurso permite movimento até mesmo em áreas onde o gradiente da função de adaptação muda ligeiramente em uma função suave, em uma função discreta, ele se manifesta como uma desvantagem, com o algoritmo ficando preso em platôs prolongados.

Impressão dos resultados dados pelo script para algoritmos de otimização de pontuação:

2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_RND=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.18210 | 0.15281 | 0.07011 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.08623 | 0.04810 | 0.06094 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.00000 | 0.00000 | 0.08904 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.6893397068905002
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_PSO=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.22131 | 0.12861 | 0.05966 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.15345 | 0.10486 | 0.28099 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.08028 | 0.02385 | 0.00000 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    1.053004072893302
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_ACOm=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.37458 | 0.28208 | 0.17991 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    1.00000 | 1.00000 | 1.00000 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    1.00000 | 1.00000 | 0.10959 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    5.946151922377553
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_ABC=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.84599 | 0.51308 | 0.22588 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.58850 | 0.21455 | 0.17249 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.47444 | 0.26681 | 0.35941 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    3.661160435265267
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_GWO=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.00000 | 0.00000 | 0.00000 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.00000 | 0.00000 | 0.00000 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.18977 | 0.04119 | 0.01802 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.24898721240154956
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_COAm=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    1.00000 | 0.73390 | 0.28892 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.64504 | 0.34034 | 0.21362 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.67153 | 0.34273 | 0.45422 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    4.690306586791184
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_FSS=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.50663 | 0.39737 | 0.11006 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.07806 | 0.05013 | 0.08423 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.00000 | 0.01084 | 0.18998 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    1.4272897567648186
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_FAm=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.64746 | 0.53292 | 0.18102 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.55408 | 0.42299 | 0.64360 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.21167 | 0.28416 | 1.00000 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    4.477897116029613
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    =======C_AO_BA=======
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.43859 | 1.00000 | 1.00000 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.17768 | 0.17477 | 0.33595 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.15329 | 0.07158 | 0.46287 |
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    3.8147314003892507
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    ================
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    ================
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    ================
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    0.24898721240154956 | 5.946151922377553
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_RND: 8.652
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_PSO: 14.971
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_ACOm: 100.000
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_ABC: 60.294
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_GWO: 1.000
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_COAm: 78.177
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_FSS: 21.475
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_FAm: 74.486
2023.01.03 17:55:57.386    CalculationTestResults (EURUSD,M1)    C_AO_BA: 62.962

Vamos analisar a tabela final de classificação. Como mencionado anteriormente, a metodologia de cálculo das características estimadas dos algoritmos foi alterada, o que resultou em uma nova posição para os algoritmos Alguns algoritmos clássicos foram removidos da tabela, deixando apenas suas versões modificadas, que demonstraram ter um desempenho superior nos testes. Agora, os resultados dos testes não são absolutos como antes (resultados absolutos normalizados dos valores da função de teste), mas sim relativos com base na comparação entre os algoritmos.

De acordo com a tabela, o líder absoluto neste momento é o ACOm (otimização de colônia de formigas), que apresentou os melhores resultados em cinco dos nove testes, obtendo 100 pontos no resultado final. Na segunda posição da classificação está o COAm, uma versão modificada do algoritmo de otimização do cuco, que foi o melhor na função Rastrigin suave e também apresentou bons resultados em outros testes em comparação com os demais participantes. Em terceiro lugar está o algoritmo de pirilampos modificado FAm, que obteve os melhores resultados na função discreta Megacity, igualando-se apenas ao FSS neste teste.

AO

Description

Rastrigin

Rastrigin final

Forest

Forest final

Megacity (discrete)

Megacity final

Final result

10 params (5 F)

50 params (25 F)

1000 params (500 F)

10 params (5 F)

50 params (25 F)

1000 params (500 F)

10 params (5 F)

50 params (25 F)

1000 params (500 F)

ACOm

otimização de colônia de formigas M

0,37458

0,28208

0,17991

0,83657

1,00000

1,00000

1,00000

3,00000

1,00000

1,00000

0,10959

2,10959

100,000

COAm

algoritmo de otimização de cuco M

1,00000

0,73390

0,28892

2,02282

0,64504

0,34034

0,21362

1,19900

0,67153

0,34273

0,45422

1,46848

78,177

FAm

algoritmo de vaga-lumes M

0,64746

0,53292

0,18102

1,36140

0,55408

0,42299

0,64360

1,62067

0,21167

0,28416

1,00000

1,49583

74,486

BA

algoritmo do morcego

0,43859

1,00000

1,00000

2,43859

0,17768

0,17477

0,33595

0,68840

0,15329

0,07158

0,46287

0,68774

62,962

ABC

colônia artificial de abelhas

0,84599

0,51308

0,22588

1,58495

0,58850

0,21455

0,17249

0,97554

0,47444

0,26681

0,35941

1,10066

60,294

FSS

busca por cardume de peixes

0,64746

0,53292

0,18102

1,36140

0,55408

0,42299

0,64360

1,62067

0,21167

0,28416

1,00000

1,49583

21,475

PSO

otimização de enxame de partículas

0,22131

0,12861

0,05966

0,40958

0,15345

0,10486

0,28099

0,53930

0,08028

0,02385

0,00000

0,10413

14,971

RND

aleatório

0,18210

0,15281

0,07011

0,40502

0,08623

0,04810

0,06094

0,19527

0,00000

0,00000

0,08904

0,08904

8,652

GWO

otimizador lobo-cinzento

0,00000

0,00000

0,00000

0,00000

0,00000

0,00000

0,00000

0,00000

0,18977

0,04119

0,01802

0,24898

1,000


Histograma dos resultados do teste de algoritmo na Figura 4.

rating

Figura 4. Histograma dos resultados finais dos testes dos algoritmos.

Conclusões sobre as propriedades do algoritmo do morcego (BA):

Prós:
1. Rápido.
2. Funciona bem com recursos suaves.
3. Escalabilidade.

Contras:
1. Muitos parâmetros.
2. Resultados medíocres em funções discretas.