English Русский Español Deutsch 日本語
preview
Algoritmos de otimização populacionais: Algoritmo de evolução da mente (Mind Evolutionary Computation, MEC)

Algoritmos de otimização populacionais: Algoritmo de evolução da mente (Mind Evolutionary Computation, MEC)

MetaTrader 5Exemplos | 7 março 2024, 17:03
133 0
Andrey Dik
Andrey Dik

Conteúdo:

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


1. Introdução

Os cálculos evolutivos são uma subárea da inteligência computacional, aprendizado de máquina e inteligência artificial. Eles são amplamente aplicados em problemas de otimização, design de robôs, criação de árvores de decisão, ajuste de algoritmos de análise de dados, treinamento de redes neurais e ajuste de hiperparâmetros. Em vez de usar métodos numéricos clássicos, os cálculos evolutivos se inspiram na evolução biológica para desenvolver soluções eficazes. Eles são particularmente úteis quando não existe uma derivada da conhecida função de adaptação ou quando a função de adaptação possui muitos extremos locais, que podem complicar os métodos sequenciais.

Os algoritmos populacionais, usados nos cálculos evolutivos, têm várias vantagens sobre os algoritmos clássicos na solução de problemas complexos de alta dimensão. Eles podem encontrar soluções subótimas mais eficientemente, que são suficientemente próximas da ótima, o que muitas vezes é aceitável em problemas práticos significativos de otimização.

Um dos métodos interessantes em cálculos evolutivos é o algoritmo de evolução da mente (Mind Evolutionary Computation, MEC), proposto em 1998 por Cheng e seus coautores. Diferentemente da modelagem esperada do funcionamento do cérebro humano, o algoritmo MEC modela alguns aspectos do comportamento humano na sociedade. Neste algoritmo, cada indivíduo é considerado como um agente inteligente, funcionando em um grupo de pessoas. Ao tomar decisões, o indivíduo sente a influência tanto dos membros de seu próprio grupo quanto dos membros de outros grupos. Para alcançar uma posição elevada na sociedade, o indivíduo deve aprender com os membros mais bem-sucedidos de seu grupo. Ao mesmo tempo, para que seu grupo se torne mais bem-sucedido em comparação com outros grupos, todos os indivíduos devem seguir o mesmo princípio na competição intergrupal. Um aspecto importante do algoritmo MEC é a troca de informações entre os indivíduos dentro do grupo e entre grupos. Isso reflete a necessidade de uma troca contínua e livre de informações para o desenvolvimento bem-sucedido de uma sociedade de indivíduos inteligentes.

A concepção apresentada pelo algoritmo MEC é implementada por meio de operações de competições locais e dissimilação, responsáveis ​​pela busca local e global, respectivamente. Um quadro de avisos é usado pelo algoritmo para armazenar informações sobre o histórico de evolução da população, e com base nessas informações, é gerenciado o processo de otimização.


2. Descrição do algoritmo

O algoritmo MEC pode ser interpretado como um algoritmo multipopulacional, consistindo de grupos líderes e retardatários. Presume-se que o número de agentes em cada grupo seja igual. Cada grupo possui seu próprio quadro de avisos local, bem como existe um quadro de avisos global comum para toda a multipopulação.

Na versão original do algoritmo MEC, conhecida como Simple MEC (SMEC), são utilizadas operações de inicialização dos grupos, competições locais e dissimilação.

A operação de inicialização cria os grupos e os posiciona na área de busca. Para cada grupo, um vetor aleatório é gerado, que é identificado com um indivíduo do grupo. Em seguida, são determinadas as coordenadas iniciais dos outros agentes do grupo, posicionando-os aleatoriamente ao redor do indivíduo do grupo usando uma distribuição normal.

A operação de competições locais implementa a busca local do máximo da função de adaptação de cada grupo. Para cada grupo, lê-se a informação sobre o atual agente vencedor de seu quadro de avisos. Então, são determinadas as novas coordenadas dos outros agentes do grupo, posicionando-os aleatoriamente ao redor do vencedor usando uma distribuição normal. Os novos scores dos agentes do grupo são calculados, e é determinado o novo vencedor do grupo, que tem o maior score atual. A informação sobre o novo vencedor é registrada no quadro de avisos do grupo.

A operação de dissimilação gerencia a busca global. Primeiramente, os scores de todos os grupos são lidos do quadro de avisos global. Em seguida, esses scores são comparados entre si. Se o score do grupo líder for menor que o score de um dos grupos retardatários, o último assume a posição de líder, enquanto o grupo líder se torna um retardatário. Se o score do grupo for inferior aos scores de todos os grupos retardatários, o grupo é removido da população. Em vez dos grupos removidos, novos grupos são inicializados usando a operação de inicialização.

Assim, o algoritmo MEC representa um algoritmo multipopulacional, que inclui operações de inicialização, competições locais e dissimilação.

Foi apresentada uma descrição geral do simples algoritmo MEC pelos criadores do algoritmo, tal descrição, na minha opinião, dificulta a compreensão dos princípios subjacentes à estratégia de busca no espaço multidimensional e, em conexão com isso, surgem muitas questões, como "o que representa o quadro de avisos e como ele difere das características de indivíduos específicos do grupo?" e outras questões, portanto, vamos examinar mais de perto esses detalhes.

Foi dito acima que o algoritmo simula a sociedade humana e a interação entre seus membros. O conceito de "ideia", que pode ser uma ideia científica, artística, literária ou de qualquer outro tipo, pode ser facilmente e claramente compreendido. Na sociedade, sempre existem ideias dominantes e alternativas. Não dividiremos as ideias em "líderes e retardatários", como sugerem os autores em relação aos grupos. Isso, como veremos abaixo, dará certa vantagem ao algoritmo em comparação com sua versão básica. Como cada ideia inclui pelo menos uma tese (tese - parâmetro otimizável da função de adaptação), a ideia pode ter ramificações ideais, assim como existem diferentes teorias e correntes na ciência. Na Figura 1, as ideias são mostradas esquematicamente como i1, i2, etc. Cada ideia pode gerar ramificações dentro dos limites definidos pela força do pensamento (parâmetro externo do algoritmo), quanto mais distante a ramificação da ideia, menos provável é (a probabilidade e os limites das ramificações ideais são mostrados como círculos concêntricos que se expandem). Se uma ideia se mostrar mais viável (o valor da função de adaptação é melhor) do que seu progenitor ideológico, essa ramificação substitui a ideia parental (a nova ideia como resultado da ramificação ideológica é mostrada na figura como i5). Na figura, pode-se ver que não há limites para a interseção das fronteiras ideais, o que significa que podem surgir ramificações ideais com as mesmas teses.

ideas

Figura 1. Ideias i1, i2, i3, i4, seus limites, interseções de limites e o surgimento de uma nova ideia i5 como resultado da ramificação da ideia i1.

A ramificação das ideias realiza uma competição local dentro de cada ideia e garante a busca nas vizinhanças do extremo local. O conjunto de ramificações de todas as ideias constitui uma multipopulação, enquanto uma ideia individual e suas ramificações representam uma população separada. Cada ideia apenas mantém seus princípios e valor prático, enquanto o programa do usuário interage com as ramificações das ideias, não com as ideias em si.

Para garantir a busca global, é necessário promover o surgimento de novas ideias fora dos limites atuais na população, caso contrário, as ideias irão "ferver" internamente (ficar presas em extremos locais) sem que haja emergência de melhores valores da função de adaptação. Para isso, é destinado o processo de dissimilação (destruição). Usaremos um esquema um pouco diferente de troca de ideias entre o grupo dominante (cor verde) de ideias e o grupo alternativo (cor azul), diferente do algoritmo original. Após a classificação separada das ideias em cada grupo, removemos a pior ideia do grupo dominante e colocamos no lugar a melhor do grupo alternativo, promovendo assim uma troca de ideias. No espaço que fica disponível no grupo alternativo, colocamos uma nova ideia, que é compilada a partir dos princípios de ideias aleatoriamente selecionadas do grupo dominante (exceto a última). Para promover a variabilidade, uma componente aleatória pode ser adicionada a esta ação, o que deixo para possíveis futuros experimentos dos pesquisadores de algoritmos de otimização. A seleção de princípios das ideias do grupo dominante aumenta as capacidades combinatórias do algoritmo. Abaixo, na figura 2, é mostrado o esquema de substituição de ideias do grupo alternativo e criação de uma nova.

ideas 2

Figura 2. Esquema de substituição de ideias do grupo alternativo e criação de uma nova.

Escreveremos o pseudocódigo MEC para simplificar a escrita do código do algoritmo posteriormente:

1.1 Se for a primeira execução do algoritmo
1.1.1 Criar aleatoriamente dois grupos de ideias no campo de ideias (dominante e alternativo)

1.2 Se for a segunda execução e subsequentes do algoritmo
1.2.1 Para a ideia dominante, criar ramificações seguindo a lei de Levy*, uma das ramificações será o resultado da combinação de princípios das ideias dominantes.
1.2.2 Para a ideia alternativa, todas as ramificações são criadas seguindo a lei de Levy*

2 Calcular o valor das ramificações das ideias

3.1 Se houver uma ramificação de ideia melhor - substituir a ideia correspondente
3.2 Classificar separadamente os grupos dominante e alternativo
3.3 Substituir a pior ideia do grupo dominante pela melhor ideia do grupo alternativo
3.4 No lugar da ideia que ficou vaga no grupo alternativo, criar uma nova ideia com base nos elementos do grupo dominante** (todos exceto o último substituído)


* - em substituição à distribuição normal, como no autor original
** - em substituição à criação de princípios aleatórios, como no autor original

Podemos notar pelo pseudocódigo que o algoritmo original sofreu alterações.

Em primeiro lugar, em vez da distribuição normal proposta pelos autores do algoritmo, usamos a lei dos voos de Levy, o que aumentou as capacidades de exploração e refinamento do algoritmo. É importante notar que a lei dos voos de Levy nem sempre pode melhorar a eficácia de cada algoritmo de otimização, se tentarmos usá-la em vez da distribuição normal ou uniforme. Isso está relacionado, acima de tudo, com as características da estratégia de busca do algoritmo. Assim, no artigo anterior, examinamos o algoritmo de salto de sapo embaralhado, onde tentei usar a lei dos voos de Levy nos saltos dos sapos em vez da distribuição normal, o que não resultou em melhorias significativas na capacidade de busca.

Em segundo lugar, o algoritmo original não prevê absolutamente nenhum mecanismo combinatório na estratégia de busca, vamos tentar entender por que isso é extremamente importante. Como exemplo, imaginemos várias cestas contendo bolas de alumínio (leves) e uma bola de ouro (pesada). Diante de nós está a tarefa: encher uma cesta vazia com bolas de modo que todas sejam de ouro, enquanto nos é permitido ou modificar gradualmente a composição química de cada nova bola na cesta, sem saber se isso aumentará seu peso, ou simplesmente pegar aleatoriamente uma bola de uma das cestas, sabendo que uma delas é certamente de ouro, podendo apenas pesar a cesta inteira, mas não as bolas individualmente. Assim que enchemos a cesta, devemos pesá-la, e a tarefa consiste em maximizar o peso da cesta. Essa tarefa demonstra que, através da combinação simples, podemos encher a cesta com bolas de ouro em muito menos etapas.

Vamos à descrição do código do algoritmo.

A unidade lógica elementar do algoritmo é a ideia, que também representará a ramificação da ideia. Para descrever uma ideia, a estrutura S_Idea, que representa um objeto contendo informações sobre as coordenadas e a adaptação da ideia, é perfeitamente adequada. A estrutura tem um método Init para facilitar a inicialização da adaptação com um valor negativo DBL_MAX.

//——————————————————————————————————————————————————————————————————————————————
struct S_Idea
{
  void Init (int size)
  {
    ArrayResize (c, size);
    f = -DBL_MAX;
  }
  double c []; //coordinates
  double f;    //fitness
};
//——————————————————————————————————————————————————————————————————————————————

Na classe C_AO_MEC, descreveremos o algoritmo MEC. Ele contém uma série de variáveis e métodos para trabalhar com essas variáveis.

Variáveis da classe:
- cB: array que contém as melhores coordenadas
- fB: valor da função de adaptação para as melhores coordenadas
- idBr: array contendo os ramos ideológicos

- rangeMax: array contendo os valores máximos para a busca
- rangeMin: array contendo os valores mínimos para a busca
- rangeStep: array contendo os passos para a busca

- leadIdeolGroup: array contendo o grupo ideológico líder
- alteIdeolGroup: array contendo o grupo ideológico alternativo
- tempIdeolGroup: array contendo o grupo ideológico temporário

- coordinatesNumber: número de coordenadas
- populationSize: tamanho da população
- ideasNumber: número de ideias
- thoughtPower: força do pensamento
- ideasBr: número de ramos ideológicos
- leadIdGroupSize: tamanho do grupo ideológico líder
- alteIdGroupSize: tamanho do grupo ideológico alternativo

- vect: vetor para uso no incremento das coordenadas
- ind: array de índices
- val: array de valores
- revision: flag de revisão

Métodos da classe:
- Init: inicialização da classe com passagem de parâmetros
- Moving: execução de movimento
- Revision: revisão

- Sorting: ordenação dos grupos ideológicos
- SeInDiSp: cálculo do intervalo para busca
- RNDfromCI: geração de número aleatório a partir de um intervalo especificado

//——————————————————————————————————————————————————————————————————————————————
class C_AO_MEC
{
  //----------------------------------------------------------------------------
  public: double cB   []; //best coordinates
  public: double fB;      //FF of the best coordinates
  public: S_Idea idBr []; //ideological branches


  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search


  public: void Init (const int    coordinatesNumberP,   //coordinates number
                     const int    populationSizeP,      //population size
                     const int    ideasNumberP,         //ideas number
                     const double thoughtPowerP);       //thought power

  public: void Moving   ();
  public: void Revision ();

  //----------------------------------------------------------------------------
  private: S_Idea leadIdeolGroup []; //leading ideological group
  private: S_Idea alteIdeolGroup []; //alternative ideological group
  private: S_Idea tempIdeolGroup []; //temporal ideological group

  private: int    coordinatesNumber; //coordinates number
  private: int    populationSize;    //population size
  private: int    ideasNumber;       //ideas number
  private: double thoughtPower;      //thought power
  private: int    ideasBr;           //number of ideological branches
  private: int    leadIdGroupSize;   //leading ideological group size
  private: int    alteIdGroupSize;   //alternative ideological group size

  private: double vect    [];        //vector
  private: int    ind     [];
  private: double val     [];
  private: bool   revision;

  private: void   Sorting   (S_Idea &ideas []);
  private: double SeInDiSp  (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI (double min, double max);
};
//——————————————————————————————————————————————————————————————————————————————

O método de inicialização Init realiza as seguintes ações:

- No início do código, o valor inicial do gerador de números aleatórios é definido e a variável fB é estabelecida no valor mínimo do tipo double.
- Em seguida, as variáveis coordinatesNumber, populationSize, ideasNumber e thoughtPower são ajustadas para os valores passados para a função Init.
- Depois, os valores das variáveis ideasBr, leadIdGroupSize e alteIdGroupSize são calculados com base nos valores de populationSize e ideasNumber.
- Em seguida, os tamanhos dos arrays rangeMax, rangeMin, rangeStep, vect, ind, val, tempIdeolGroup e cB são alterados com a função ArrayResize.
- Por fim, objetos da classe Ideology são criados nos arrays leadIdeolGroup e alteIdeolGroup usando laços for e a função Init.
- Depois, objetos da classe Ideologia são criados no array idBr usando um loop for e a função Init.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MEC::Init (const int    coordinatesNumberP,   //coordinates number
                     const int    populationSizeP,      //population size
                     const int    ideasNumberP,         //ideas number
                     const double thoughtPowerP)        //thought power
{
  MathSrand ((int)GetMicrosecondCount ()); // reset of the generator
  fB       = -DBL_MAX;
  revision = false;

  coordinatesNumber = coordinatesNumberP;
  populationSize    = populationSizeP;
  ideasNumber       = ideasNumberP;
  thoughtPower      = thoughtPowerP;

  ideasBr         = populationSize / ideasNumber;
  leadIdGroupSize = ideasNumber / 2;
  alteIdGroupSize = ideasNumber - leadIdGroupSize;

  ArrayResize (rangeMax,       coordinatesNumber);
  ArrayResize (rangeMin,       coordinatesNumber);
  ArrayResize (rangeStep,      coordinatesNumber);
  ArrayResize (vect,           coordinatesNumber);
  ArrayResize (ind,            alteIdGroupSize, alteIdGroupSize);
  ArrayResize (val,            alteIdGroupSize, alteIdGroupSize);
  ArrayResize (tempIdeolGroup, alteIdGroupSize, alteIdGroupSize);
  ArrayResize (cB,             coordinatesNumber);

  ArrayResize (leadIdeolGroup, leadIdGroupSize);
  for (int i = 0; i < leadIdGroupSize; i++) leadIdeolGroup [i].Init (coordinatesNumber);

  ArrayResize (alteIdeolGroup, alteIdGroupSize);
  for (int i = 0; i < alteIdGroupSize; i++) alteIdeolGroup [i].Init (coordinatesNumber);

  ArrayResize (idBr, populationSize);
  for (int i = 0; i < populationSize; i++) idBr [i].Init (coordinatesNumber);
}
//——————————————————————————————————————————————————————————————————————————————

O método de criar ramificações ideológicas Moving executa a lógica principal da estratégia de busca por MEC. Parte do código é executada apenas na primeira iteração do algoritmo, e o restante é executado a cada iteração.

Na primeira iteração, é necessário inicializar um vetor, que é preenchido com valores calculados com base no alcance e na força do pensamento (thoughtPower) — estes são os incrementos no ramificação, e criar ideias em dois grupos, o dominante e o alternativo. Para isso, as ideias de ambos os grupos, sendo equivalentes, serão distribuídas com igual probabilidade por todo o campo de busca.

//============================================================================
if (!revision)
{
  fB = -DBL_MAX;
  int cnt = 0;

  for (int c = 0; c < coordinatesNumber; c++) vect [c] = (rangeMax [c] - rangeMin [c]) * thoughtPower;

  //--------------------------------------------------------------------------
  for (int i = 0; i < leadIdGroupSize; i++)
  {
    for (int c = 0; c < coordinatesNumber; c++)    
    {
      coord = RNDfromCI (rangeMin [c], rangeMax [c]);
      leadIdeolGroup [i].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    leadIdeolGroup [i].f = -DBL_MAX;
  }

  //--------------------------------------------------------------------------
  for (int i = 0; i < alteIdGroupSize; i++)
  {
    for (int c = 0; c < coordinatesNumber; c++)
    {
      coord = RNDfromCI (rangeMin [c], rangeMax [c]);
      alteIdeolGroup [i].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    alteIdeolGroup [i].f = -DBL_MAX;
  }

  revision = true;
}

Em seguida, na primeira e nas iterações subsequentes, geraremos ramificações ideológicas, uma vez que já criamos as próprias ideias. Estamos interessados especificamente nas ramificações ideológicas, que podemos avaliar pela função de adaptação.

A operação principal para criar uma ramificação é definir o movimento para as teses das ideias de acordo com a lei de vôos de Levy, normalizada pelo coeficiente da força do pensamento. Faremos isso para todas as ideias do grupo alternativo e para todas, exceto a última, do grupo dominante, pela fórmula:

coord = leadIdeolGroup [i].c [c] + r1 * vect [c] * pow (r2, -2.0);

Para a última ideia do grupo dominante, escolheremos aleatoriamente uma ideia desse grupo e pegaremos a tese do índice correspondente:

r1 = RNDfromCI (0.0, leadIdGroupSize - 1);
idBr [cnt].c [c] = leadIdeolGroup [(int)r1].c [c];

E aqui está todo o código para a criação de ramificações ideais para ambos os grupos:

//----------------------------------------------------------------------------
for (int i = 0; i < leadIdGroupSize; i++)
{
  for (int b = 0; b < ideasBr; b++)
  {
    if (b < ideasBr -1)
    {
      for (int c = 0; c < coordinatesNumber; c++)
      {
        r1 = RNDfromCI (0.0, 1.0);
        r1 = r1 > 0.5 ? 1.0 : -1.0;
        r2 = RNDfromCI (1.0, 20.0);

        coord = leadIdeolGroup [i].c [c] + r1 * vect [c] * pow (r2, -2.0);
        idBr [cnt].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    else
    {
      for (int c = 0; c < coordinatesNumber; c++)
      {
        r1 = RNDfromCI (0.0, leadIdGroupSize - 1);
        idBr [cnt].c [c] = leadIdeolGroup [(int)r1].c [c];
      }
    }

    cnt++;
  }
}

//----------------------------------------------------------------------------
for (int i = 0; i < alteIdGroupSize; i++)
{
  for (int b = 0; b < ideasBr; b++)
  {
    for (int c = 0; c < coordinatesNumber; c++)
    {
      r1 = RNDfromCI (0.0, 1.0);
      r1 = r1 > 0.5 ? 1.0 : -1.0;
      r2 = RNDfromCI (1.0, 20.0);

      coord = alteIdeolGroup [i].c [c] + r1 * vect [c] * pow (r2, -2.0);
      idBr [cnt].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }

    cnt++;
  }
}

O método Revision é destinado à revisão das ideias com base nos resultados da avaliação de suas ramificações ideais, assim como para a atualização dos indicadores da solução global. O código executa os seguintes passos:

1. Inicializam-se as variáveis cnt e pos.

2. Substituição das melhores ideias: Em um laço para cada líder no grupo de líderes (leadIdeolGroup), é realizada a busca pela melhor ramificação ideial global (idBr). Para cada ramificação, verifica-se se o seu valor de função de adaptação (f) é maior do que o valor do líder atual, então a posição (pos) é definida igual ao índice atual (cnt). Se uma ideia melhor é encontrada, então o valor funcional e as coordenadas do líder são atualizados com os valores dessa ideia. Se o valor funcional da nova ideia também for maior do que o atual melhor valor funcional (fB), então o fB e as coordenadas da melhor ideia (cB) também são atualizados.

3. De maneira similar para o grupo de soluções alternativas (alteIdeolGroup).

4. Ordenação dos grupos de ideias: Os grupos de líderes e de ideias alternativas são ordenados em ordem decrescente do valor da função de adaptação.

5. Substituição da pior ideia: A pior ideia no grupo de líderes (leadIdeolGroup) é substituída pela melhor ideia do grupo de soluções alternativas (alteIdeolGroup).

6. Criação de uma nova ideia: para cada coordenada (c) no grupo de soluções alternativas (alteIdeolGroup), cria-se uma nova ideia baseada em elementos do grupo dominante (leadIdeolGroup). A coordenada é escolhida aleatoriamente do grupo dominante de líderes.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MEC::Revision ()
{
  int cnt = 0;
  int pos = -1;

  //----------------------------------------------------------------------------
  //4. If there is a better ideological branch, replace the corresponding idea
  for (int i = 0; i < leadIdGroupSize; i++)
  {
    pos = -1;
    for (int b = 0; b < ideasBr; b++)
    {
      if (idBr [cnt].f > leadIdeolGroup [i].f) pos = cnt;

      cnt++;
    }

    if (pos != -1)
    {
      leadIdeolGroup [i].f = idBr [pos].f;
      ArrayCopy (leadIdeolGroup [i].c, idBr [pos].c, 0, 0, WHOLE_ARRAY);

      if (idBr [pos].f > fB)
      {
        fB = idBr [pos].f;
        ArrayCopy (cB, idBr [pos].c, 0, 0, WHOLE_ARRAY);
      }
    }
  }

  //----------------------------------------------------------------------------
  for (int i = 0; i < alteIdGroupSize; i++)
  {
    pos = -1;
    for (int b = 0; b < ideasBr; b++)
    {
      if (idBr [cnt].f > alteIdeolGroup [i].f) pos = cnt;

      cnt++;
    }

    if (pos != -1)
    {
      alteIdeolGroup [i].f = idBr [pos].f;
      ArrayCopy (alteIdeolGroup [i].c, idBr [pos].c, 0, 0, WHOLE_ARRAY);

      if (idBr [pos].f > fB)
      {
        fB = idBr [pos].f;
        ArrayCopy (cB, idBr [pos].c, 0, 0, WHOLE_ARRAY);
      }
    }
  }

  //----------------------------------------------------------------------------
  //5. Sort two groups of ideas.
  Sorting (leadIdeolGroup);
  Sorting (alteIdeolGroup);

  //----------------------------------------------------------------------------
  //6. Replace the worst idea of the first group with the best idea from the second group
  leadIdeolGroup [leadIdGroupSize - 1] = alteIdeolGroup [0];

  //----------------------------------------------------------------------------
  //7. Instead of an empty idea, create a new idea based on elements of the dominant group 
  double rnd   = 0.0;
  double coord = 0.0;
  for (int c = 0; c < coordinatesNumber; c++)
  {
    rnd = RNDfromCI (0.0, leadIdGroupSize - 2);
    alteIdeolGroup [0].c [c] = leadIdeolGroup [(int)rnd].c [c];
  }
}
//——————————————————————————————————————————————————————————————————————————————


3. Resultados dos testes

Impressão do funcionamento do algoritmo de evolução da mente no banco de testes:

C_AO_MEC:50;10;0.3
=============================
5 Rastrigin's; Func runs 10000 result: 78.73205273291103
Score: 0.97553
25 Rastrigin's; Func runs 10000 result: 58.554840607439516
Score: 0.72553
500 Rastrigin's; Func runs 10000 result: 42.32395504312925
Score: 0.52442
=============================
5 Forest's; Func runs 10000 result: 1.2024830541165685
Score: 0.68018
25 Forest's; Func runs 10000 result: 0.4588423143844061
Score: 0.25954
500 Forest's; Func runs 10000 result: 0.08756810826330522
Score: 0.04953
=============================
5 Megacity's; Func runs 10000 result: 5.279999999999999
Score: 0.44000
25 Megacity's; Func runs 10000 result: 2.048
Score: 0.17067
500 Megacity's; Func runs 10000 result: 0.4364
Score: 0.03637
=============================
All score: 3.86178
Ao observar a animação do algoritmo MEC, é possível ver a formação de agrupamentos de concentração de agentes em extremos locais. A qualidade da convergência inspira esperança quanto a lugares dignos na tabela de classificação.

rastrigin

  SFL na função de teste Rastrigin.

forest

  MEC na função de teste Forest.

megacity

  MEC na função de teste Megacity.


Ao analisar a tabela de classificação dos resultados dos testes de algoritmos de otimização, pode-se notar que o algoritmo MEC alcança indicadores muito altos e ocupa o honroso quinto lugar. MEC demonstra excelentes resultados nas funções Rastrigin, Forest e Megacity, apesar das superfícies completamente diferentes destas funções de teste. Resultados particularmente impressionantes são alcançados na função Megacity com 10 parâmetros. No entanto, vale ressaltar que o MEC mostra ainda mais alta eficiência em funções com menor número de parâmetros otimizados, em comparação com outros participantes da análise comparativa, o que é mais uma desvantagem do que uma vantagem. 

AO

Description

Rastrigin

Rastrigin final

Forest

Forest final

Megacity (discrete)

Megacity final

Final result

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

SSG

saplings sowing and growing

1,00000

1,00000

0,55665

2,55665

0,72740

0,94522

1,00000

2,67262

0,76364

0,85977

1,00000

2,62340

100,000

2

HS

harmony search

0,99676

0,95282

0,48178

2,43136

1,00000

0,98931

0,44806

2,43736

1,00000

1,00000

0,41537

2,41537

92,329

3

ACOm

ant colony optimization M

0,34611

0,17985

0,17044

0,69640

0,86888

1,00000

0,77362

2,64249

1,00000

0,88930

0,05606

1,94536

65,347

4

IWO

invasive weed optimization

0,95828

0,67083

0,29807

1,92719

0,70773

0,46349

0,31773

1,48896

0,80000

0,42067

0,33289

1,55356

61,104

5

MEC

mind evolutionary computation

0,99270

0,51040

0,22800

1,73110

0,60762

0,40658

0,25459

1,26880

0,93335

0,41328

0,26170

1,60833

56,227

6

COAm

cuckoo optimization algorithm M

0,92400

0,46794

0,26004

1,65199

0,58378

0,34034

0,16526

1,08939

0,72727

0,33025

0,17083

1,22835

47,612

7

FAm

firefly algorithm M

0,59825

0,33980

0,17135

1,10941

0,51073

0,42299

0,49790

1,43161

0,34545

0,28044

0,35258

0,97847

41,537

8

ABC

artificial bee colony

0,78170

0,32715

0,20822

1,31707

0,53837

0,21455

0,13344

0,88636

0,56364

0,26569

0,13926

0,96858

36,849

9

GSA

gravitational search algorithm

0,70167

0,45217

0,00000

1,15384

0,31660

0,36416

0,33204

1,01280

0,59395

0,35054

0,00000

0,94448

36,028

10

BA

bat algorithm

0,40526

0,63761

0,84451

1,88738

0,20841

0,17477

0,25989

0,64308

0,29698

0,09963

0,17371

0,57032

35,888

11

BFO

bacterial foraging optimization

0,67203

0,30963

0,11813

1,09979

0,39702

0,26623

0,20652

0,86976

0,52122

0,33211

0,18932

1,04264

34,693

12

EM

electroMagnetism-like algorithm

0,12235

0,46278

1,00000

1,58513

0,00000

0,03498

0,34880

0,38377

0,00000

0,00000

0,10924

0,10924

22,091

13

SFL

shuffled frog-leaping

0,40072

0,23739

0,26548

0,90360

0,20153

0,04147

0,02652

0,26952

0,27273

0,05535

0,06639

0,39446

15,203

14

MA

monkey algorithm

0,33192

0,33451

0,14644

0,81287

0,10012

0,07891

0,08932

0,26836

0,21818

0,04243

0,10720

0,36781

13,603

15

FSS

fish school search

0,46812

0,25337

0,11302

0,83451

0,12840

0,05013

0,06516

0,24369

0,16971

0,04796

0,08283

0,30050

12,655

16

PSO

particle swarm optimisation

0,20449

0,08200

0,07160

0,35809

0,18895

0,10486

0,21738

0,51119

0,23636

0,05903

0,01957

0,31496

10,031

17

RND

random

0,16826

0,09743

0,08019

0,34589

0,13496

0,04810

0,04715

0,23021

0,16971

0,03875

0,04922

0,25767

5,302

18

GWO

grey wolf optimizer

0,00000

0,00000

0,02256

0,02256

0,06570

0,00000

0,00000

0,06570

0,32727

0,07378

0,02557

0,42663

1,000


Considerações finais

O algoritmo de evolução da mente (MEC) é um método de otimização eficaz e poderoso, baseado nos princípios da evolução biológica. Ele possui uma série de vantagens significativas que o tornam atraente para resolver problemas complexos de otimização.

O algoritmo de evolução da mente pode ser aplicado a uma ampla gama de tarefas, incluindo otimização funcional, busca de valores ótimos de parâmetros, problemas de aprendizado de máquina e outros. Ele não requer conhecimento da forma analítica da função objetivo e pode trabalhar com espaços de soluções contínuos, discretos ou combinatórios.

MEC é facilmente paralelizável, o que permite o uso de múltiplos recursos computacionais para acelerar o processo de otimização. Isso é particularmente útil ao trabalhar com tarefas que exigem uma grande quantidade de cálculos ou iterações.

MEC tem certa tendência a ficar preso em extremos locais, mas essa desvantagem é manifestada principalmente em funções discretas e funções com descontinuidades, e considerando essa característica no design da função de adaptação, essa desvantagem do algoritmo pode ser considerada minimamente significativa.

MEC lida relativamente bem com tarefas nas quais o espaço de soluções tem uma grande dimensão. O algoritmo não foi suficientemente estudado e possui potencial para melhorias.

Em geral, o algoritmo de evolução da mente representa uma ferramenta de otimização poderosa, que possui flexibilidade, versatilidade e um bom tratamento de extremos locais. Estas vantagens o tornam uma escolha atraente para resolver problemas complexos de otimização em várias áreas, especialmente pode ser útil a simplicidade da lógica do algoritmo para uso em soluções de software customizadas e não padronizadas.

Para uma representação mais visual das vantagens e desvantagens dos diferentes algoritmos em comparação entre si, a tabela acima pode ser apresentada usando uma escala de cores na figura 3.

rating table

Figura 3. Graduação de cores dos algoritmos de acordo com os testes correspondentes.

Histograma dos resultados dos testes dos algoritmos na figura 3 (em uma escala de 0 a 100, quanto maior, melhor, no arquivo, o script para calcular a tabela de classificação pela metodologia neste artigo):

chart

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

Prós e contras do algoritmo de evolução da mente (MEC):

Prós:
1. Mínimo de parâmetros externos.
2. Alta eficiência na resolução de uma variedade de tarefas.
3. Baixa carga nos recursos computacionais.
4. Facilidade de implementação do algoritmo.

Contras:
1. Tendência a ficar preso em funções com áreas planas horizontais.

A cada artigo, anexo um arquivo contendo versões atualizadas e relevantes dos códigos dos algoritmos descritos em artigos anteriores. No entanto, é importante destacar que não me responsabilizo pela precisão absoluta na descrição dos algoritmos canônicos. Frequentemente, também adiciono minhas próprias ideias e melhorias, com base na experiência acumulada e opinião pessoal. As conclusões e julgamentos apresentados nos artigos são baseados nos resultados dos experimentos realizados.

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

Arquivos anexados |
Rede neural na prática: Reta Secante Rede neural na prática: Reta Secante
Como foi explicado na parte teórica. Precisamos usar regressões lineares e derivadas, quando o assunto é rede neural. Mas por que ?!?! O motivo disto, é que a regressão linear é uma das fórmulas mais simples que existe. Basicamente uma regressão linear, é apenas uma função afim. Porém quando falamos em rede neural, não estamos interessados na reta, que a regressão linear cria. Estamos interessados é na equação que gera tal reta. A reta gerada pouco importa. Mas você sabe qual é a equação principal a ser compreendida ?!?! Se não veja este artigo para começar a entender.
Modelos prontos para integrar indicadores nos Expert Advisors (Parte 3): Indicadores de tendência Modelos prontos para integrar indicadores nos Expert Advisors (Parte 3): Indicadores de tendência
Neste artigo de referência, vamos dar uma olhada nos indicadores padrão da categoria Indicadores de tendência. Criaremos modelos prontos a serem usados em Expert Advisors, modelos esses que incluirão: declaração e configuração de parâmetros, inicialização/desinicialização de indicadores e recuperação de dados/sinais a partir de buffers de indicador em EAs.
Teoria das Categorias em MQL5 (Parte 22): Outra Perspectiva sobre Médias Móveis Teoria das Categorias em MQL5 (Parte 22): Outra Perspectiva sobre Médias Móveis
Neste artigo, tentaremos simplificar a descrição dos conceitos discutidos nesta série, focando apenas em um indicador, o mais comum e, provavelmente, o mais fácil de entender. Estamos falando da média móvel. Também examinaremos o significado e as possíveis aplicações das transformações naturais verticais.
Avaliando o desempenho futuro com intervalos de confiança Avaliando o desempenho futuro com intervalos de confiança
Neste artigo, vamos explorar o uso do bootstrapping como um meio de avaliar a eficácia futura de uma estratégia automatizada.