English Русский 中文 Español Deutsch 日本語
preview
Algoritmo de busca através de vizinhança — Across Neighborhood Search (ANS)

Algoritmo de busca através de vizinhança — Across Neighborhood Search (ANS)

MetaTrader 5Exemplos |
198 0
Andrey Dik
Andrey Dik
Conteúdo
  1. Introdução
  2. Implementação do algoritmo
  3. Resultados dos testes


1. Introdução

No mundo moderno, o desenvolvimento de métodos eficazes de otimização é fundamental para resolver uma diversidade de problemas, desde aplicações de engenharia até pesquisas científicas em aprendizado de máquina e inteligência artificial. Nesse contexto, os algoritmos evolutivos meta-heurísticos são ferramentas poderosas para solucionar tarefas complexas de otimização. No entanto, para melhorar ainda mais seu desempenho e eficácia, é necessário o contínuo desenvolvimento e modificação de métodos existentes, bem como a criação de novos algoritmos.

Neste artigo, apresentamos um algoritmo de otimização conhecido como Across Neighborhood Search (ANS), proposto por Guohua Wu em 2014, baseado na busca por populações para otimização numérica. O algoritmo ANS desenvolvido é um avanço significativo na área de otimização, prometendo resolver uma ampla gama de problemas do mundo real com alta eficiência e precisão; se isso é verdade ou não, confirmaremos ou desmentiremos adiante. A ideia central do ANS é modelar o comportamento de um sistema multiagente, onde cada agente se movimenta no espaço de soluções, interagindo com vizinhos e trocando informações. Essa abordagem permite uma exploração eficaz do espaço de busca, combinando otimização local e global.

Apresentaremos a estrutura detalhada do algoritmo ANS e os princípios de seu funcionamento, além de realizar uma análise comparativa com métodos de otimização já existentes. O algoritmo ANS desenvolvido abre novas possibilidades no campo da otimização, possibilitando resolver uma variedade de problemas com alto desempenho. Além disso, no contexto do desenvolvimento da inteligência artificial, é importante notar que o ANS representa um passo significativo em direção à criação de métodos de otimização mais flexíveis e inteligentes, que considerem a especificidade da tarefa e a dinâmica do ambiente.

2. Implementação do algoritmo

O algoritmo Across Neighborhood Search, ANS (busca através de vizinhança), é um método de otimização que usa ideias da área de algoritmos evolutivos e meta-heurísticas, projetado para encontrar soluções ideais no espaço de parâmetros do problema.

Principais características do ANS:

  • Busca através de vizinhança: agentes exploram as vizinhanças das soluções atuais, permitindo encontrar ótimos locais de maneira mais eficaz.
  • Uso de distribuição normal: ANS utiliza a distribuição normal para gerar novos valores de parâmetros.
  • Coleções de soluções: no ANS, são usadas coleções das melhores soluções, que ajudam a orientar o algoritmo em várias direções promissoras simultaneamente.

No ANS, um grupo de indivíduos realiza conjuntamente uma busca no espaço de soluções para otimizar a tarefa em questão. A ideia principal do algoritmo é manter e atualizar dinamicamente uma coleção de soluções superiores descobertas pelos indivíduos até o momento. Em cada geração, o indivíduo busca diretamente em sua vizinhança por várias soluções boas, seguindo a distribuição normal de probabilidades. Isso explora a ideia de que podem existir múltiplas soluções potencialmente boas, já que não se sabe antecipadamente qual será a melhor.

A seguir, descrevemos completamente o algoritmo ANS com fórmulas e etapas, conforme a concepção original do autor. O ANS realiza os seguintes passos:

1. Inicialização de parâmetros:

  • Tamanho da população m
  • Coleção de um conjunto das melhores soluções c
  • Desvio padrão da distribuição gaussiana sigma
  • Dimensionalidade do espaço de busca D
  • Número máximo de gerações MaxG

2. Inicialização da população. Inicializa-se aleatoriamente a posição de cada indivíduo da população no espaço de busca.

3. Atualização das melhores soluções. Cada indivíduo na população atualiza sua posição, explorando as vizinhanças das melhores soluções da coleção, usando a distribuição normal.

4. Escolha da coordenada para busca. Seleciona-se um número aleatório n (grau de busca em vizinhança) para definir a coordenada atual da posição do indivíduo no espaço de soluções.

5. Atualização da posição do indivíduo. Atualiza-se a posição do indivíduo i conforme o passo anterior.

Fórmulas e operações:

1. Atualização da posição pos_i do indivíduo i (exploração da vizinhança de uma solução da coleção):

  • A posição do indivíduo i é atualizada pela distribuição Gaussiana: pos_i = r_g + G (r_g - pos_i), onde:
  • G - valor aleatório da distribuição gaussiana
  • r_g - posição da melhor solução da coleção

2. Atualização da posição pos_i do indivíduo i (exploração da vizinhança de sua própria melhor solução):

  • A posição do indivíduo i é atualizada pela distribuição Gaussiana: pos_i = r_i + G (r_i - pos_i), onde:
  • G - valor aleatório da distribuição gaussiana
  • r_i - posição da melhor solução do indivíduo

3. Atualização do conjunto das melhores soluções:

  • A coleção das melhores soluções é atualizada com base nas novas posições dos indivíduos.

Dessa forma, as fórmulas refletem o mecanismo de busca do indivíduo i nas vizinhanças de sua melhor solução r_i, bem como nas vizinhanças de outras melhores soluções r_g da coleção R. Esses passos constituem a lógica principal do método ANS (Across Neighborhood Search) para resolver problemas de otimização. O algoritmo inclui a inicialização de parâmetros, a inicialização aleatória das posições dos indivíduos, a atualização dessas posições considerando as vizinhanças das melhores soluções, e a atualização da coleção das melhores soluções. O processo continua até que a condição de parada seja atendida.

A busca por melhores soluções ou indivíduos é uma técnica comum em algoritmos que empregam estratégias populacionais, embora os processos que implementam esse mecanismo possam variar entre diferentes algoritmos de otimização. Nesse caso, além da população principal de agentes, é introduzida uma população adicional: uma coleção de melhores soluções (direções de busca potenciais). O tamanho da coleção é determinado por parâmetros externos do algoritmo e pode ser configurado como menor ou maior que o tamanho da população principal.

A estratégia de busca no algoritmo ANS começa com o preenchimento da coleção das melhores soluções e prossegue com a exploração da vizinhança dessas melhores soluções na coleção, além das melhores soluções individuais de cada agente. O tamanho do desvio padrão sigma desempenha um papel muito importante no algoritmo. Valores pequenos de sigma promovem uma exploração mais ampla do espaço de busca, enquanto valores maiores permitem o refinamento de soluções, concentrando a busca em suas vizinhanças. Esse parâmetro é importante para o equilíbrio entre intensificação e diversificação da busca. Em alguns algoritmos, esse equilíbrio está vinculado ao número da época atual, garantindo um ajuste dinâmico entre exploração e refinamento. Porém, neste caso, os autores configuraram a regulação desse equilíbrio como um parâmetro externo do ANS.

Assim, o algoritmo ANS combina a exploração das melhores soluções encontradas (por meio da busca em suas vizinhanças) e a exploração do espaço de soluções (através da busca nas vizinhanças das melhores soluções individuais dos agentes). Isso, teoricamente, deve garantir um bom equilíbrio entre a intensificação e a diversificação da busca.

Agora, vamos à implementação e análise do código do algoritmo ANS. Definiremos a estrutura "S_ANS_Agent", que será usada para representar os agentes no algoritmo ANS. Campos da estrutura:

  • c: array para armazenar as coordenadas do agente.
  • cBest: array para armazenar as melhores coordenadas do agente.
  • f: valor de aptidão (fitness) do agente.
  • fBest: melhor valor de aptidão do agente.
  • Init(int coords): método de inicialização que define os tamanhos dos arrays "c" e "cBest" e configura os valores iniciais de "f" e "fBest".

Essa parte do código define a estrutura básica do agente, cujo conjunto (array) de agentes formará a população principal no algoritmo ANS.

//——————————————————————————————————————————————————————————————————————————————
struct S_ANS_Agent
{
    double c     []; //coordinates
    double cBest []; //best coordinates
    double f;        //fitness
    double fBest;    //best fitness

    void Init (int coords)
    {
      ArrayResize (c,     coords);
      ArrayResize (cBest, coords);
      f     = -DBL_MAX;
      fBest = -DBL_MAX;
    }
};
//—————————————————————————————————————————————————————————————————————————————

Para descrever a coleção de melhores soluções, implementaremos a estrutura "S_Collection", que será usada para armazenar informações sobre as melhores coordenadas no espaço de busca e o respectivo valor de aptidão. A estrutura contém os seguintes campos:

  • c: array para armazenar as coordenadas.
  • f: valor de aptidão (fitness) para a solução na coleção.
  • Init(int coords): método de inicialização que define o tamanho do array "c" e configura o valor inicial de "f" para o menor valor possível do tipo "double".
//——————————————————————————————————————————————————————————————————————————————
struct S_Collection
{
    double c []; //coordinates
    double f;    //fitness

    void Init (int coords)
    {
      ArrayResize (c, coords);
      f = -DBL_MAX;
    }
};
//——————————————————————————————————————————————————————————————————————————————

Declararemos a classe "C_AO_ANS", que é derivada da classe base "C_AO" e representa a implementação do algoritmo Across Neighborhood Search (ANS). Aqui estão alguns pontos importantes:

  • ao_name, ao_desc, ao_link: propriedades que descrevem o algoritmo ANS.
  • popSize: tamanho da população.
  • collectionSize, sigma, range, collChoiceProbab: parâmetros do algoritmo ANS.
  • SetParams(): método para definir os parâmetros.
  • Init(), Moving(), Revision(): métodos para inicializar, mover os agentes e atualizar a população e a coleção de soluções.
  • S_ANS_Agent, S_Collection: estruturas para armazenamento de dados dos agentes e da coleção.
//——————————————————————————————————————————————————————————————————————————————
class C_AO_ANS : public C_AO
{
  public: //--------------------------------------------------------------------
  ~C_AO_ANS () { }
  C_AO_ANS ()
  {
    ao_name = "ANS";
    ao_desc = "Across Neighbourhood Search";
    ao_link = "https://www.mql5.com/ru/articles/15049";

    popSize          = 50;   //population size

    collectionSize   = 20;   //Best solutions collection
    sigma            = 3.0;  //Form of normal distribution
    range            = 0.5;  //Range of values dispersed
    collChoiceProbab = 0.8;  //Collection choice probab

    ArrayResize (params, 5);

    params [0].name = "popSize";          params [0].val = popSize;
    params [1].name = "collectionSize";   params [1].val = collectionSize;
    params [2].name = "sigma";            params [2].val = sigma;
    params [3].name = "range";            params [3].val = range;
    params [4].name = "collChoiceProbab"; params [4].val = collChoiceProbab;
  }

  void SetParams ()
  {
    popSize          = (int)params [0].val;
    collectionSize   = (int)params [1].val;
    sigma            = params      [2].val;
    range            = params      [3].val;
  }

  bool Init (const double &rangeMinP  [], //minimum search range
             const double &rangeMaxP  [], //maximum search range
             const double &rangeStepP [], //step search
             const int     epochsP = 0);  //number of epochs

  void Moving   ();
  void Revision ();

  //----------------------------------------------------------------------------
  int    collectionSize;    //Best solutions collection
  double sigma;             //Form of normal distribution
  double range;             //Range of values dispersed
  double collChoiceProbab;  //Collection choice probab

  S_ANS_Agent agent [];

  private: //-------------------------------------------------------------------
  S_Collection coll     [];
  S_Collection collTemp [];
};
//——————————————————————————————————————————————————————————————————————————————

O método "Init" inicializa os parâmetros do algoritmo ANS (Across Neighborhood Search).

  • rangeMinP, rangeMaxP, rangeStepP: arrays que representam os valores mínimos, máximos e o passo do intervalo de busca.
  • epochsP: número de épocas (gerações).

Dentro do método:

  • Verifica-se a inicialização bem-sucedida dos parâmetros padrão com "StandardInit".
  • São criados arrays de agentes "agent" e das coleções "coll" (segunda população para armazenamento das melhores soluções) e "collTemp" (array temporário para ordenação da coleção).
  • Para cada agente e elemento da coleção, o método "Init" é chamado para definir os valores iniciais.

Esse método é essencial para preparar o algoritmo ANS para a execução da otimização. É importante destacar que os arrays "coll" e "collTemp" são inicializados com o dobro do tamanho especificado pelo parâmetro "collectionSize".  Isso é feito para que os novos agentes adicionados à coleção sejam inseridos na segunda metade do array. Em seguida, a coleção é ordenada como um todo, mas somente a primeira metade, que contém os melhores agentes, é usada para as operações subsequentes.

//——————————————————————————————————————————————————————————————————————————————
bool C_AO_ANS::Init (const double &rangeMinP  [], //minimum search range
                     const double &rangeMaxP  [], //maximum search range
                     const double &rangeStepP [], //step search
                     const int     epochsP = 0)   //number of epochs
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //----------------------------------------------------------------------------
  ArrayResize (agent, popSize);
  for (int i = 0; i < popSize; i++) agent [i].Init (coords);

  ArrayResize (coll,     collectionSize * 2);
  ArrayResize (collTemp, collectionSize * 2);
  for (int i = 0; i < collectionSize * 2; i++)
  {
    coll     [i].Init (coords);
    collTemp [i].Init (coords);
  }

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

O método "Moving" realiza o movimento (deslocamento) dos agentes no algoritmo ANS. Vamos detalhar o funcionamento deste código:

1. Inicialização (se "revision" for "false"):

  • Se for o primeiro passo (primeira geração), para cada agente:
    • Gera-se um valor aleatório "val" no intervalo de "rangeMin[c]" a "rangeMax[c]".
    • Aplica-se o operador "SeInDiSp" para considerar o passo "rangeStep[c]".
    • O valor "val" é atribuído às coordenadas do agente "agent[i].c[c]".
    • O valor "val" também é atribuído às melhores coordenadas do agente "agent[i].cBest[c]" (nesta fase, os valores de aptidão dos agentes ainda não são conhecidos, então as melhores coordenadas são iguais às coordenadas iniciais).
    • O valor "val" é atribuído ao array de agentes "a[i].c[c]".

2. Movimento dos agentes (se "revision" for "true"):

  • Para cada agente e cada coordenada:
    • Se um número aleatório for menor que "collChoiceProbab", escolhe-se uma solução aleatória da coleção:
      • Seleciona-se um índice aleatório "ind" da coleção (até que uma solução não nula seja encontrada).
      • O valor "p" é extraído das coordenadas atuais do agente.
      • O valor "r" é retirado da solução selecionada da coleção.
    • Caso contrário, usam-se as melhores coordenadas do agente:
      • O valor "p" é extraído das coordenadas atuais do agente.
      • O valor "r" é retirado das melhores coordenadas do agente.
    • Calcula-se a distância "dist" e o intervalo ("min" e "max") para o movimento.
    • Os valores "min" e "max" são limitados pelos intervalos "rangeMin[c]" e "rangeMax[c]".
    • Aplica-se a distribuição normal com os parâmetros "r", "min", "max" e "sigma".
    • O valor "val" é atribuído às coordenadas do agente "agent[i].c[c]".
    • O valor "val" também é atribuído ao array de agentes "a[i].c[c]".

Este trecho de código atualiza as coordenadas dos agentes no algoritmo ANS, levando em conta as melhores coordenadas próprias dos agentes e as soluções armazenadas na coleção.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ANS::Moving ()
{
  double val = 0.0;

  //----------------------------------------------------------------------------
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        val = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        val = u.SeInDiSp  (val, rangeMin [c], rangeMax [c], rangeStep [c]);

        agent [i].c     [c] = val;
        agent [i].cBest [c] = val;

        a [i].c [c] = val;
      }
    }

    revision = true;
    return;
  }

  //----------------------------------------------------------------------------
  double min  = 0.0;
  double max  = 0.0;
  double dist = 0.0;
  int    ind  = 0;
  double r    = 0.0;
  double p    = 0.0;

  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      if (u.RNDprobab () < collChoiceProbab)
      {
        do ind = u.RNDminusOne (collectionSize);
        while (coll [ind].f == -DBL_MAX);

        p = agent [i].c   [c];
        r = coll  [ind].c [c];

      }
      else
      {
        p = agent [i].c     [c];
        r = agent [i].cBest [c];
      }

      dist = fabs (p - r) * range;
      min  = r - dist;
      max  = r + dist;

      if (min < rangeMin [c]) min = rangeMin [c];
      if (max > rangeMax [c]) max = rangeMax [c];

      val = u.GaussDistribution (r, min, max, sigma);
      val = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]);

      agent [i].c [c] = val;
      a     [i].c [c] = val;
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

O método "Revision" realiza uma revisão (ou atualização) dos agentes e da coleção no algoritmo ANS. Aqui estão os principais pontos:

  • Primeira parte do método: busca o agente cuja aptidão (fitness) é melhor que a do melhor resultado global, identificado por "fB", e salva suas coordenadas no array "cB".
  • Segunda parte do método: atualiza as melhores coordenadas dos agentes "agent[i].cBest" com base na aptidão atual "a[i].f".
  • Terceira parte do método: atualiza a coleção "coll" usando as melhores coordenadas dos agentes.
  • A coleção é, então, ordenada.

Este método desempenha um papel crucial na atualização contínua dos agentes e da coleção de soluções durante a execução do algoritmo. Os agentes da população são inseridos na segunda metade da coleção. Em seguida, a coleção é ordenada, e apenas a primeira metade, contendo as melhores soluções, é usada nas etapas seguintes.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_ANS::Revision ()
{
  //----------------------------------------------------------------------------
  int ind = -1;

  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ind = i;
    }
  }

  if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY);

  //----------------------------------------------------------------------------
  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > agent [i].fBest)
    {
      agent [i].fBest = a [i].f;
      ArrayCopy (agent [i].cBest, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }

  //----------------------------------------------------------------------------
  int cnt = 0;
  for (int i = collectionSize; i < collectionSize * 2; i++)
  {
    if (cnt < popSize)
    {
      coll [i].f = agent [cnt].fBest;
      ArrayCopy (coll [i].c, agent [cnt].cBest, 0, 0, WHOLE_ARRAY);
      cnt++;
    }
    else break;
  }

  u.Sorting (coll, collTemp, collectionSize * 2);
}
//——————————————————————————————————————————————————————————————————————————————


3. Resultados dos testes

Resultados impressos da execução do algoritmo ANS em um conjunto de funções de teste:

ANS|Across Neighbourhood Search|50.0|100.0|8.0|1.0|0.6|
=============================
5 Hilly's; Func runs: 10000; result: 0.9494753644543816
25 Hilly's; Func runs: 10000; result: 0.8477633752716718
500 Hilly's; Func runs: 10000; result: 0.43857039929159747
=============================
5 Forest's; Func runs: 10000; result: 0.9999999999988883
25 Forest's; Func runs: 10000; result: 0.9233446583489741
500 Forest's; Func runs: 10000; result: 0.3998822848099108
=============================
5 Megacity's; Func runs: 10000; result: 0.709230769230769
25 Megacity's; Func runs: 10000; result: 0.6347692307692309
500 Megacity's; Func runs: 10000; result: 0.2309076923076936
=============================
All score: 6.13394 (68.15%)

O ANS apresenta resultados impressionantes em todas as funções de teste. Agora, veremos a visualização do funcionamento desse algoritmo no ambiente de testes. Embora os resultados do ANS sejam realmente extraordinários, a visualização levanta algumas questões. Em particular, observa-se o comportamento da população, que parece desaparecer do campo de visão. Percebe-se que o espaço de soluções é esvaziado, e o terreno da função permanece sem agentes. Isso pode indicar apenas uma coisa: apesar dos resultados notáveis do algoritmo, a população tende à degeneração. A coleção de soluções superiores acaba sendo preenchida por soluções muito semelhantes, o que impede a criação de novas soluções, já que todas são derivadas das que já existem.

Essa dinâmica populacional sugere a necessidade de aperfeiçoar os mecanismos de manutenção da diversidade dentro da população. Talvez seja interessante considerar a adição de um operador de mutação ou a introdução de outros mecanismos que contribuam para preservar uma maior variedade de soluções durante o processo de otimização. Isso ajudaria a evitar a degeneração da população e garantiria um desempenho mais estável do algoritmo.

Hilly

  Execução do ANS na função de teste Hilly.

Forest

  Execução do ANS na função de teste Forest.

Megacity

  Execução do ANS na função de teste Megacity.

O algoritmo analisado neste artigo conquistou com segurança a segunda posição no ranking. Dispensa comentários adicionais, mas alguns pontos principais merecem destaque: o algoritmo demonstra uma escalabilidade impressionante, mantendo a capacidade de busca mesmo em problemas de alta dimensionalidade.  

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 BGA binary genetic algorithm 0,99989 0,99518 0,42835 2,42341 0,96153 0,96181 0,32027 2,24360 0,91385 0,95908 0,24220 2,11512 6,782 75,36
2 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
3 CLA code lock algorithm 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
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 0,95346 0,86319 0,27770 2,09435 0,99794 0,85740 0,33949 2,19484 0,88769 0,56431 0,10512 1,55712 5,846 64,96
6 SDSm stochastic diffusion search M 0,93066 0,85445 0,39476 2,17988 0,99983 0,89244 0,19619 2,08846 0,72333 0,61100 0,10670 1,44103 5,709 63,44
7 ESG evolution of social groups 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
8 SIA simulated isotropic annealing 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
9 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
10 TSEA turtle shell evolution algorithm 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
11 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
12 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
13 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
14 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
15 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
16 (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
17 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
18 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
19 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
20 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
21 MEC mind evolutionary computation 0,69533 0,53376 0,32661 1,55569 0,72464 0,33036 0,07198 1,12698 0,52500 0,22000 0,04198 0,78698 3,470 38,55
22 IWO invasive weed optimization 0,72679 0,52256 0,33123 1,58058 0,70756 0,33955 0,07484 1,12196 0,42333 0,23067 0,04617 0,70017 3,403 37,81
23 Micro-AIS micro artificial immune system 0,79547 0,51922 0,30861 1,62330 0,72956 0,36879 0,09398 1,19233 0,37667 0,15867 0,02802 0,56335 3,379 37,54
24 COAm cuckoo optimization algorithm M 0,75820 0,48652 0,31369 1,55841 0,74054 0,28051 0,05599 1,07704 0,50500 0,17467 0,03380 0,71347 3,349 37,21
25 SDOm spiral dynamics optimization M 0,74601 0,44623 0,29687 1,48912 0,70204 0,34678 0,10944 1,15826 0,42833 0,16767 0,03663 0,63263 3,280 36,44
26 NMm Nelder-Mead method M 0,73807 0,50598 0,31342 1,55747 0,63674 0,28302 0,08221 1,00197 0,44667 0,18667 0,04028 0,67362 3,233 35,92
27 FAm firefly algorithm M 0,58634 0,47228 0,32276 1,38138 0,68467 0,37439 0,10908 1,16814 0,28667 0,16467 0,04722 0,49855 3,048 33,87
28 GSA gravitational search algorithm 0,64757 0,49197 0,30062 1,44016 0,53962 0,36353 0,09945 1,00260 0,32667 0,12200 0,01917 0,46783 2,911 32,34
29 BFO bacterial foraging optimization 0,61171 0,43270 0,31318 1,35759 0,54410 0,21511 0,05676 0,81597 0,42167 0,13800 0,03195 0,59162 2,765 30,72
30 ABC artificial bee colony 0,63377 0,42402 0,30892 1,36671 0,55103 0,21874 0,05623 0,82600 0,34000 0,14200 0,03102 0,51302 2,706 30,06
31 BA bat algorithm 0,59761 0,45911 0,35242 1,40915 0,40321 0,19313 0,07175 0,66810 0,21000 0,10100 0,03517 0,34617 2,423 26,93
32 SA simulated annealing 0,55787 0,42177 0,31549 1,29513 0,34998 0,15259 0,05023 0,55280 0,31167 0,10033 0,02883 0,44083 2,289 25,43
33 IWDm intelligent water drops M 0,54501 0,37897 0,30124 1,22522 0,46104 0,14704 0,04369 0,65177 0,25833 0,09700 0,02308 0,37842 2,255 25,06
34 PSO particle swarm optimisation 0,59726 0,36923 0,29928 1,26577 0,37237 0,16324 0,07010 0,60572 0,25667 0,08000 0,02157 0,35823 2,230 24,77
35 Boids boids algorithm 0,43340 0,30581 0,25425 0,99346 0,35718 0,20160 0,15708 0,71586 0,27846 0,14277 0,09834 0,51957 2,229 24,77
36 MA monkey algorithm 0,59107 0,42681 0,31816 1,33604 0,31138 0,14069 0,06612 0,51819 0,22833 0,08567 0,02790 0,34190 2,196 24,40
37 SFL shuffled frog-leaping 0,53925 0,35816 0,29809 1,19551 0,37141 0,11427 0,04051 0,52618 0,27167 0,08667 0,02402 0,38235 2,104 23,38
38 FSS fish school search 0,55669 0,39992 0,31172 1,26833 0,31009 0,11889 0,04569 0,47467 0,21167 0,07633 0,02488 0,31288 2,056 22,84
39 RND random 0,52033 0,36068 0,30133 1,18234 0,31335 0,11787 0,04354 0,47476 0,25333 0,07933 0,02382 0,35648 2,014 22,37
40 GWO grey wolf optimizer 0,59169 0,36561 0,29595 1,25326 0,24499 0,09047 0,03612 0,37158 0,27667 0,08567 0,02170 0,38403 2,009 22,32
41 CSS charged system search 0,44252 0,35454 0,35201 1,14907 0,24140 0,11345 0,06814 0,42299 0,18333 0,06300 0,02322 0,26955 1,842 20,46
42 EM electroMagnetism-like algorithm 0,46250 0,34594 0,32285 1,13129 0,21245 0,09783 0,10057 0,41085 0,15667 0,06033 0,02712 0,24412 1,786 19,85


Nesta parte do artigo, geralmente são apresentadas as conclusões. No entanto, neste caso, parece prematuro tirar conclusões finais. Antes de resumirmos, vamos primeiro observar as representações visuais tradicionais dos resultados — uma tabela de classificação colorida e um histograma que mostram a posição relativa dos algoritmos em uma escala de 100%, comparando-os com o resultado teórico máximo possível. Esses dados visuais nos ajudarão a entender e avaliar melhor a eficácia do ANS em relação a outros métodos.

Tab

Figura 1. Graduação de cores dos algoritmos para os respectivos testes. Os resultados iguais ou superiores a 0,99 são destacados em branco.

chart

Figura 2. Histograma dos resultados dos testes dos algoritmos (em uma escala de 0 a 100, quanto maior, melhor,

onde 100 é o resultado teórico máximo possível; o script para cálculo da tabela de classificação está incluído no arquivo).

Como mencionado anteriormente, a população do algoritmo ANS tende a se degenerar. Para mitigar esse problema crítico, decidi modificar o algoritmo, adicionando um operador de mutação. Neste caso, a mutação consiste em uma probabilidade gaussiana de gerar uma nova coordenada nas proximidades da melhor solução do agente, mas dentro do intervalo permitido para essa coordenada, variando de um valor mínimo a um máximo. Para isso, é necessário fazer algumas alterações no método "Moving".

Aqui está um resumo das mudanças e da lógica aplicada no método:

  • Se um número aleatório for menor que 0,005, ocorre uma mutação usando a distribuição normal.
  • Caso contrário, um solução aleatória é escolhida da coleção, ou as melhores coordenadas do agente são usadas.
  • Calcula-se a distância e o intervalo para a distribuição normal.
  • A distribuição normal é então aplicada para gerar novos valores de coordenadas.
//----------------------------------------------------------------------------
double min  = 0.0;
double max  = 0.0;
double dist = 0.0;
int    ind  = 0;
double r    = 0.0;
double p    = 0.0;

for (int i = 0; i < popSize; i++)
{
  for (int c = 0; c < coords; c++)
  {
    if (u.RNDprobab () < 0.005)
    {
      val = u.GaussDistribution (agent [i].cBest [c], rangeMin [c], rangeMax [c], sigma);
      val = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    else
    {
      if (u.RNDprobab () < collChoiceProbab)
      {
        do ind = u.RNDminusOne (collectionSize);
        while (coll [ind].f == -DBL_MAX);

        p = agent [i].c   [c];
        r = coll  [ind].c [c];
 
      }
      else
      {
        p = agent [i].c     [c];
        r = agent [i].cBest [c];
      }

      dist = fabs (p - r) * range;
      min  = r - dist;
      max  = r + dist;

      if (min < rangeMin [c]) min = rangeMin [c];
      if (max > rangeMax [c]) max = rangeMax [c];

      val = u.GaussDistribution (r, min, max, sigma);
      val = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
      
    agent [i].c [c] = val;
    a     [i].c [c] = val;
  }
}

Após a introdução do operador de mutação, o algoritmo continua explorando o espaço de busca, independentemente do número de épocas, como ilustrado na Figura 3 (captura de tela da visualização do funcionamento do algoritmo).

Agent left

Figura 3. Os agentes permanecem, a população não se degenera (parâmetro mut = 0,005).

Com base nos resultados do ANS em funções de teste com diferentes números de coordenadas e vários valores do operador de mutação (mut), podemos tirar a seguinte conclusão:
  • O operador de mutação com o parâmetro "mut = 0,1" teve um impacto negativo no resultado geral. Com um coeficiente de mutação tão alto (10% do total de operações em cada coordenada), observou-se uma piora no desempenho do algoritmo. Por isso, foi decidido reduzir gradualmente esse parâmetro. À medida que o valor foi diminuído, os resultados melhoraram, e finalmente, estabeleci o valor de 0,005. Esse coeficiente mostrou-se suficiente para evitar a degeneração da população, ao mesmo tempo garantindo uma melhoria no desempenho do algoritmo, conforme ilustrado nas impressões abaixo.

Resultados do algoritmo com a probabilidade de mutação mut = 0,1:

500 Megacity's; Func runs: 10000; result: 0.19352307692307838

=============================
All score: 6.05103 (67.23%)
ANS|Across Neighbourhood Search|50.0|100.0|8.0|1.0|0.6|
=============================
5 Hilly's; Func runs: 10000; result: 0.9534829314854332
25 Hilly's; Func runs: 10000; result: 0.8136803288623282
500 Hilly's; Func runs: 10000; result: 0.31144979106165716
=============================
5 Forest's; Func runs: 10000; result: 0.9996561274415626
25 Forest's; Func runs: 10000; result: 0.81670393859872
500 Forest's; Func runs: 10000; result: 0.25620559379918284
=============================
5 Megacity's; Func runs: 10000; result: 0.8753846153846153
25 Megacity's; Func runs: 10000; result: 0.5778461538461539
500 Megacity's; Func runs: 10000; result: 0.13375384615384744
=============================
All score: 5.73816 (63.76%)

Resultados do algoritmo com a probabilidade de mutação mut = 0.01:

ANS|Across Neighbourhood Search|50.0|100.0|8.0|1.0|0.6|

=============================
5 Hilly's; Func runs: 10000; result: 0.9073657389037575
25 Hilly's; Func runs: 10000; result: 0.871278233418226
500 Hilly's; Func runs: 10000; result: 0.3960769225373809
=============================
5 Forest's; Func runs: 10000; result: 0.989394440004635
25 Forest's; Func runs: 10000; result: 0.9513150500729907
500 Forest's; Func runs: 10000; result: 0.35407610928209116
=============================
5 Megacity's; Func runs: 10000; result: 0.7492307692307691
25 Megacity's; Func runs: 10000; result: 0.6387692307692309
500 Megacity's; Func runs: 10000; result: 0.19352307692307838
=============================
All score: 6.05103 (67.23%)

Resultados do algoritmo com a probabilidade de mutação mut = 0.005:

ANS|Across Neighbourhood Search|50.0|100.0|8.0|1.0|0.6|
=============================
5 Hilly's; Func runs: 10000; result: 0.949632264944664
25 Hilly's; Func runs: 10000; result: 0.871206955779846
500 Hilly's; Func runs: 10000; result: 0.40738389742274217
=============================
5 Forest's; Func runs: 10000; result: 0.9924803131691761
25 Forest's; Func runs: 10000; result: 0.9493489251290264
500 Forest's; Func runs: 10000; result: 0.3666276564633121
=============================
5 Megacity's; Func runs: 10000; result: 0.8061538461538461
25 Megacity's; Func runs: 10000; result: 0.6732307692307691
500 Megacity's; Func runs: 10000; result: 0.20844615384615534
=============================
All score: 6.22451 (69.16%)


Considerações finais

Agora que analisamos os resultados obtidos com a introdução do operador de mutação, podemos tirar as seguintes conclusões:

1. Simplicidade e facilidade de implementação.
2. Equilíbrio entre exploração e exploração intensiva.
3. Eficiência na resolução de diferentes tipos de problemas.
4. Adaptabilidade a várias tarefas.
5. Potencial para futuras melhorias.

Portanto, o ANS é um algoritmo de otimização simples, mas eficaz, que apresenta resultados competitivos em uma ampla variedade de problemas e possui um grande potencial para desenvolvimento futuro.

Vantagens e desvantagens gerais do algoritmo de busca através de vizinhança (ANS):

Vantagens:

  1. Boa convergência em diferentes tipos de funções.
  2. Alta velocidade de execução.
  3. Implementação simples.
  4. Excelente escalabilidade.

Desvantagens:

  1. Ocasionalmente, fica preso em extremos locais.

O artigo inclui um arquivo com as versões atualizadas dos códigos dos algoritmos. O autor do artigo não se responsabiliza pela precisão absoluta na descrição dos algoritmos canônicos, pois foram realizadas diversas modificações para aprimorar as capacidades de busca. As conclusões e observações apresentadas são baseadas nos resultados dos experimentos realizados.

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

Arquivos anexados |
ANS.zip (26.81 KB)
Redes neurais de maneira fácil (Parte 97): Treinamento do modelo usando o MSFformer Redes neurais de maneira fácil (Parte 97): Treinamento do modelo usando o MSFformer
Ao estudar diferentes arquiteturas de construção de modelos, temos dado pouca atenção ao processo de treinamento dos modelos. Neste artigo, tentarei preencher essa lacuna.
Redes neurais de maneira fácil (Parte 96): Extração multinível de características (MSFformer) Redes neurais de maneira fácil (Parte 96): Extração multinível de características (MSFformer)
A extração e integração eficazes de dependências de longo prazo e características de curto prazo continuam sendo uma tarefa importante na análise de séries temporais. Compreendê-las e integrá-las corretamente é necessário para criar modelos preditivos precisos e confiáveis.
Redes neurais em trading: Representação linear por partes de séries temporais Redes neurais em trading: Representação linear por partes de séries temporais
Este artigo é um pouco diferente dos trabalhos anteriores desta série. Nele, discutiremos uma representação alternativa de séries temporais. A representação linear por partes de séries temporais é um método de aproximação de séries temporais usando funções lineares em pequenos intervalos.
Do básico ao intermediário: União (II) Do básico ao intermediário: União (II)
Este será um artigo muito divertido e bastante curioso em diversos aspectos. Ele abordará a união para resolver um problema discutido anteriormente. Além disso, exploraremos algumas situações inusitadas que podem surgir ao usar uma união em aplicativos. O conteúdo exposto aqui visa pura e simplesmente a didática. De modo algum deve ser encarado como uma aplicação cuja finalidade não seja o aprendizado e estudo dos conceitos mostrados.