Русский
preview
Algoritmo de Aprendizagem Competitiva - Competitive Learning Algorithm (CLA)

Algoritmo de Aprendizagem Competitiva - Competitive Learning Algorithm (CLA)

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

Conteúdo

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


Introdução

Nas últimas décadas, foram propostos muitos algoritmos bioinspirados: de colônias de formigas e enxames de partículas a lobos-cinzentos e baleias. No entanto, a sociedade humana, com suas complexas interações sociais, também pode servir como uma rica fonte de ideias para a criação de métodos de otimização eficientes. Foi justamente essa ideia que deu origem ao algoritmo de aprendizagem competitiva (Competitive Learning Algorithm, CLA).

O CLA usa a metáfora do processo educacional, em que a população de soluções é representada como alunos agrupados em classes. O algoritmo modela de forma elegante três tipos de aprendizado: com o melhor da classe (o professor), a partir da experiência pessoal e por meio da interação entre classes. Essa abordagem garante o equilíbrio entre a exploração do espaço de busca e a intensificação das boas soluções encontradas, o que é essencial para uma otimização eficiente.

Neste artigo, examinamos em detalhe os princípios de funcionamento do CLA, sua base matemática, as particularidades de sua implementação e comparamos sua eficiência com a de outras metaheurísticas populares em nossas funções de teste padrão.


Implementação do algoritmo

O algoritmo de aprendizagem competitiva (Competitive Learning Algorithm) é baseado na metáfora do processo educacional em uma escola. Nessa metáfora, os alunos representam possíveis soluções para o problema de otimização, as classes são grupos de alunos, os professores são os melhores alunos de cada classe, o conhecimento corresponde às coordenadas no espaço de busca, e a avaliação é determinada pelo valor da função de fitness.

O algoritmo é inicializado no início da execução, que pode ser comparada ao início do ano letivo. É criada uma população, por exemplo, de 198 alunos, que são divididos em 9 classes com 22 alunos em cada uma. A cada aluno são atribuídos aleatoriamente "conhecimentos" iniciais, isto é, coordenadas no espaço de busca.

O aprendizado ocorre de forma iterativa e, em cada iteração, os alunos aprendem de três maneiras diferentes. A primeira é o aprendizado com o professor, em que cada aluno aprende com o melhor de sua classe e, quanto pior o desempenho da classe, mais intensamente ocorre a aprendizagem, embora com o tempo a intensidade do aprendizado diminua para todos. A segunda é o aprendizado individual, que começa somente após a quarta iteração. Nesse modo, o aluno relembra seus melhores resultados nas quatro "aulas" anteriores e tenta voltar ao seu melhor resultado pessoal. A terceira é o aprendizado com outras classes, que também começa após a quarta iteração. Com probabilidade de 50%, o aluno pode aprender com o "professor médio de todas as classes" de todas as classes, o que ajuda a evitar a convergência prematura para ótimos locais.

Após cada ciclo de aprendizagem, o desempenho é avaliado. Identifica-se o melhor aluno em cada classe, que passa a ser o professor, calcula-se a pontuação geral da classe com base no desempenho de todos os alunos e atualiza-se a melhor solução global encontrada.

O algoritmo usa cinco parâmetros-chave:

  • popSize — define o número total de alunos,
  • numClasses — define o número de classes,
  • beta — regula a influência de todos os alunos da classe sobre sua pontuação geral,
  • gamma — estabelece a probabilidade de aprender com outras classes,
  • deltaIter — indica a partir de qual iteração é ativado o modo ampliado de aprendizagem, com uso da experiência pessoal e da interação entre classes.

O algoritmo incorpora vários mecanismos inteligentes. Fatores adaptativos de aprendizagem promovem um aprendizado mais intenso nas classes mais fracas e uma desaceleração gradual ao longo do tempo, como ocorre em um ambiente educacional real. O equilíbrio entre exploração e intensificação é alcançado com exploração ativa nas etapas iniciais, seguida de concentração nas melhores soluções encontradas. O mecanismo de memória permite ao algoritmo manter o histórico de cada aluno e, quando necessário, retomar boas soluções obtidas anteriormente.

Matematicamente, a atualização do conhecimento do aluno pode ser representada como a soma do conhecimento atual, da lição do professor da classe, da experiência pessoal armazenada no histórico e do conhecimento recebido do professor médio de todas as classes. Essa fórmula garante o equilíbrio entre seguir o líder, usar a experiência pessoal e explorar novas regiões do espaço de busca.

Em suma, a eficiência do algoritmo decorre de vários fatores. A diversidade é obtida por meio de múltiplas classes que exploram diferentes direções no espaço de busca. A competição entre os alunos pela posição de professor estimula a melhoria das soluções. A cooperação, por meio da troca de conhecimento entre classes, busca evitar a convergência prematura. O mecanismo adaptativo oferece suporte adicional às classes mais fracas, enquanto o mecanismo de memória preserva informações sobre boas soluções.

CLA_L

Figura 1. Ilustração do funcionamento do algoritmo

A ilustração do funcionamento do algoritmo descreve três etapas principais: inicialização, fase de aprendizagem e avaliação e atualização. Agora, passamos à escrita do pseudocódigo do algoritmo CLA_L.

O QUE PRECISAMOS ANTES:
198 alunos (nossas soluções)
9 classes (grupos de alunos)
Parâmetro β = 0.9 (o quanto todos os alunos da classe são importantes)
Parâmetro γ = 0.5 (chance de aprender com outras classes)
Após a 4ª iteração, ativamos modalidades adicionais de aprendizagem
Função para avaliar a qualidade da solução

COMEÇAMOS:

1. CRIAMOS A ESCOLA:
   - Distribuímos 198 alunos em 9 classes (22 em cada uma)
   - Atribuímos a cada aluno uma posição inicial aleatória no espaço de busca
   - Em cada classe, escolhemos o melhor aluno, que se torna o professor
   - Criamos um registro para armazenar o histórico de cada aluno

2. CICLO DE APRENDIZAGEM (iterativo):
   
   Passo 1: Definimos a intensidade da aprendizagem
   - Para cada classe, definimos a intensidade de aprendizagem
   - As classes mais fracas (com pior classificação) aprendem com maior intensidade
   - Com o tempo, a intensidade da aprendizagem diminui para todos (como na vida real)
   
   Passo 2: Encontramos o "professor médio"
   - Pegamos as posições de todos os professores
   - Calculamos a posição média
   - Essa será a referência global de conhecimento da escola
   
   Passo 3: Cada aluno aprende:
   
   Cada aluno:
   
   a) SEMPRE aprende com seu professor:
      - Observa onde está o professor da sua classe
      - Move-se na direção dele
      - A velocidade do movimento depende do fator de aprendizagem da classe
   
   b) Após a 4ª iteração, relembra sua experiência:
      - Consulta o registro: onde teve seu melhor desempenho nas últimas 4 aulas?
      - Com uma magnitude aleatória, retorna àquela posição
      - Isso ajuda a não esquecer boas soluções
   
   c) Após a 4ª iteração, aprende com outras classes:
      - Lança uma moeda (com probabilidade de 50%)
      - Se cair coroa, observa o "professor médio"
      - Move-se um pouco na direção dele
      - Isso favorece a troca de conhecimento entre classes
   
   Passo 4: Avaliamos todos os alunos
   - Cada aluno recebe um valor de fitness
   - Quanto melhor a posição, maior a avaliação
   
   Passo 5: Atualizamos a hierarquia da escola
   
   Para cada classe:
   - Encontramos o novo melhor aluno - ele se torna o professor
   - Calculamos a pontuação geral da classe:
     - Pegamos a avaliação do professor
     - Somamos a média das notas de todos os alunos (multiplicada por β)
   - Determinamos a posição da classe no ranking:
     - As melhores classes recebem posições mais baixas no ranking (1, 2, 3...)
     - As piores classes recebem classificação alta
   
   Passo 6: Armazenamos a melhor solução
   - Se algum professor superar o recorde atual
   - Nós o armazenamos como o novo recorde
   
   Passo 7: Registramos no histórico as posições atuais
   - Armazenamos as posições atuais de todos os alunos
   - Isso será necessário para a aprendizagem individual

3. FINALIZAMOS:
   - Retornamos a melhor solução encontrada
   - E sua avaliação

Agora, passamos para a escrita do código do algoritmo. A classe "C_AO_CLA_l" herda da classe "C_AO" (classe base) e implementa o algoritmo de aprendizagem competitiva. A classe contém uma série de parâmetros configuráveis pelo usuário:

  • popSize — tamanho da população (quantidade de "agentes" ou "alunos");
  • numClasses — quantidade de classes em que os agentes são divididos;
  • beta — parâmetro que provavelmente influencia a velocidade de aprendizagem ou adaptação;
  • gamma — outro parâmetro, provavelmente relacionado à aprendizagem;
  • deltaIter — define a iteração a partir da qual começam as etapas adicionais de aprendizagem).

Construtor O construtor inicializa os parâmetros principais, define o nome e a descrição do algoritmo, atribui valores padrão às variáveis e dimensiona o array "params", destinado a armazenar informações sobre os parâmetros do algoritmo.

Métodos:

  • SetParams ()atualiza os valores das variáveis internas da classe (parâmetros do algoritmo) com base nos valores do array "params". Isso permite alterar parâmetros definidos externamente.
  • Init ()inicializa o algoritmo. Recebe os limites e o passo de variação de cada parâmetro
  • Moving ()método principal responsável pelas iterações e pela atualização dos agentes.
  • Revision ()método relacionado à correção ou ao refinamento das soluções.
  • Injection () — método para inserir novo conhecimento ou dados no agente.
Campos da classe:
  • numClasses, beta, gamma, deltaIter — parâmetros do algoritmo.
  • currentIter, studentsPerClass, totalIters — variáveis internas usadas no controle da execução do algoritmo.
  • teachers [] — array de estruturas "S_AO_Agent" que representam os "professores" de cada classe (pontos de referência).
  • classRanks [] — ranks das classes, que refletem seu desempenho.
  • classTotalCosts [] — custo total de cada classe.
  • CL [] — array temporário usado no cálculo da média do conhecimento dos professores.
  • UpdateTeachersAndCosts () — método interno para atualizar as informações sobre os professores e os custos correspondentes.
  • UpdateClassRanks () — método interno para atualizar os ranks das classes.
  • UpdateStudentsKnowledge () — método interno para atualizar o conhecimento ou os parâmetros dos "alunos".
//————————————————————————————————————————————————————————————————————
class C_AO_CLA_l : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_CLA_l () { }
  C_AO_CLA_l ()
  {
    ao_name = "CLA_L";
    ao_desc = "Competitive Learning Algorithm";
    ao_link = "https://www.mql5.com/ru/articles/18857";

    popSize        = 198;
    numClasses     = 3;
    beta           = 0.3;
    gamma          = 0.8;
    deltaIter      = 2;

    ArrayResize (params, 5);

    params [0].name = "popSize";     params [0].val = popSize;
    params [1].name = "numClasses";  params [1].val = numClasses;
    params [2].name = "beta";        params [2].val = beta;
    params [3].name = "gamma";       params [3].val = gamma;
    params [4].name = "deltaIter";   params [4].val = deltaIter;
  }

  void SetParams ()
  {
    popSize    = (int)params [0].val;
    numClasses = (int)params [1].val;
    beta       = params      [2].val;
    gamma      = params      [3].val;
    deltaIter  = (int)params [4].val;
  }

  bool Init (const double &rangeMinP  [],
             const double &rangeMaxP  [],
             const double &rangeStepP [],
             const int     epochsP = 0);

  void Moving   ();
  void Revision ();
  void Injection (const int popPos, const int coordPos, const double value) { }

  //------------------------------------------------------------------
  int    numClasses;
  double beta;
  double gamma;
  int    deltaIter;

  private: //---------------------------------------------------------
  int    currentIter;
  int    studentsPerClass;
  int    totalIters;

  // Структуры для классов
  S_AO_Agent teachers        [];
  double     classRanks      [];
  double     classTotalCosts [];

  // Временные массивы
  double     CL [];             // Среднее знание учителей

  // Вспомогательные методы
  void   UpdateTeachersAndCosts  ();
  void   UpdateClassRanks        ();
  void   UpdateStudentsKnowledge ();
};
//————————————————————————————————————————————————————————————————————

O método "Init ()" da classe "C_AO_CLA_l" inicializa o algoritmo antes do início da execução. Seu funcionamento é dividido em várias etapas. Standard Initialization: chama o método "StandardInit ()" e executa a inicialização padrão do algoritmo de otimização. Ele recebe os limites dos parâmetros "rangeMinP", "rangeMaxP" e o passo "rangeStepP". Se a inicialização padrão falhar, o método "Init ()" retorna "false".

Initialization of Algorithm Parameters: redefine o contador da iteração atual para "0", define o número total de iterações que o algoritmo deve executar com base no valor passado no argumento "epochsP" e calcula o número de "alunos" (agentes) em cada classe, dividindo o tamanho da população pelo número de classes. Em seguida, o método verifica se há pelo menos um aluno em cada classe. Depois, um loop "for" inicializa cada agente da população. Para cada agente do array "a", é chamado o método "Init ()". Esse método define a quantidade de coordenadas de cada agente.

Um loop "for" inicializa o "professor" de cada classe, define o rank de cada classe como "1.0" e atribui ao custo inicial de cada classe o menor valor possível, para garantir que a melhor solução seja encontrada posteriormente. Se todas as etapas de inicialização forem concluídas com sucesso, o método retorna "true".

//————————————————————————————————————————————————————————————————————
bool C_AO_CLA_l::Init (const double &rangeMinP  [],
                       const double &rangeMaxP  [],
                       const double &rangeStepP [],
                       const int epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  currentIter = 0;
  totalIters = epochsP;
  studentsPerClass = popSize / numClasses;

  if (studentsPerClass < 1)
  {
    Print ("Ошибка: слишком мало студентов на класс");
    return false;
  }

  // Корректировка размера популяции
  //spopSize = studentsPerClass * numClasses;
  ArrayResize (a, popSize);
  for (int i = 0; i < popSize; i++) a [i].Init (coords);

  // Инициализация структур классов
  ArrayResize (teachers, numClasses);
  ArrayResize (classRanks, numClasses);
  ArrayResize (classTotalCosts, numClasses);

  for (int i = 0; i < numClasses; i++)
  {
    teachers        [i].Init (coords);
    classRanks      [i] = 1.0;
    classTotalCosts [i] = -DBL_MAX;
  }

  // Временные массивы
  ArrayResize (CL, coords);

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

O método "Moving ()" da classe "C_AO_CLA_l" executa uma iteração do algoritmo de otimização. Ele verifica se esta é a primeira iteração e, se for o caso (isto é, quando "revision" tem valor "false"), inicializa as posições de todos os agentes da população com valores aleatórios no intervalo definido. Em seguida, percorre todos os agentes da população e, para cada agente, percorre todas as suas coordenadas.

Para cada coordenada, o método gera um valor aleatório "val" no intervalo entre "rangeMin [c]" e "rangeMax [c]" usando o método "u.RNDfromCI ()", responsável pela geração de números aleatórios. Em seguida, atribui à coordenada "a [i].c [c]" do agente "i" o valor "val", após ajustá-lo para que permaneça dentro do intervalo permitido e respeite o passo especificado em "rangeStep [c]". Para isso, é usado o método "u.SeInDiSp ()", que verifica e corrige o valor.

Após a inicialização da população, o método define uma flag para indicar que a inicialização foi concluída. Se não for a primeira iteração, ele incrementa o contador da iteração atual. Em seguida, chama o método "UpdateStudentsKnowledge ()", que implementa o mecanismo principal de aprendizagem ou adaptação dos agentes de acordo com os princípios da aprendizagem competitiva usados no algoritmo "CLA_L". A lógica desse método define como os agentes interagem, trocam informações e melhoram suas posições no espaço de busca.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::Moving ()
{
  // Начальная инициализация популяции
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        double val = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    revision = true;
    return;
  }

  currentIter++;

  // Обновление знаний студентов
  UpdateStudentsKnowledge ();
}
//————————————————————————————————————————————————————————————————————

O método "UpdateStudentsKnowledge ()" é responsável por atualizar a posição de cada aluno (agente) durante a otimização. Primeiro, calcula-se o progresso atual da otimização. Em seguida, são calculados dois fatores-chave de aprendizagem:

  • TF (Teaching Factor) — indica em que medida o aluno aprende com o professor.
  • CF (Confirmatory Factor) — indica em que medida o aluno leva em conta o conhecimento médio dos professores. Esses fatores dependem do progresso e do rank da classe do aluno.

Depois disso, calcula-se a média das coordenadas de todos os professores "ativos" (professores cujos resultados são válidos). Esse conhecimento médio é armazenado em um array temporário. Para cada aluno (agente), determina-se a classe à qual ele pertence e, para cada uma de suas coordenadas, calcula-se uma nova posição somando-se a coordenada atual às "fontes de conhecimento". O aluno aprende com seu professor, ajustando sua posição por uma quantidade proporcional à diferença entre a coordenada do professor e a sua própria, multiplicada por TF. Após iterações suficientes (currentIter > deltaIter) ee o aluno tiver uma melhor solução pessoal armazenada, ele passa a aprender com seu melhor resultado anterior, ajustando sua posição na direção da melhor coordenada e aplicando um fator aleatório.

Após iterações suficientes e houver professores com resultados válidos, o aluno aprende com o conhecimento médio de todos os professores, ajustando sua posição na direção da coordenada média, multiplicada por "CF", com determinada probabilidade (1-gamma). Limites são aplicados a cada coordenada do aluno para garantir que o valor permaneça dentro da faixa permitida. Em seguida, o valor é ajustado aos valores permitidos, levando em conta o passo de discretização da busca.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::UpdateStudentsKnowledge ()
{
  // Расчет факторов обучения для текущей итерации
  double progress = (double)currentIter / (double)MathMax (totalIters, 100);

  // Вычисление среднего знания всех учителей (CL)
  ArrayInitialize (CL, 0.0);
  int validTeachers = 0;

  for (int k = 0; k < numClasses; k++)
  {
    // Проверяем, что учитель инициализирован
    if (teachers [k].f > -DBL_MAX)
    {
      for (int c = 0; c < coords; c++)
      {
        CL [c] += teachers [k].c [c];
      }
      validTeachers++;
    }
  }

  if (validTeachers > 0)
  {
    for (int c = 0; c < coords; c++)
    {
      CL [c] /= validTeachers;
    }
  }

  // Обновление каждого студента
  for (int i = 0; i < popSize; i++)
  {
    int classIdx = i / studentsPerClass;

    // Teaching Factor - уменьшается с прогрессом
    double TF = MathExp (-0.6 * progress * classRanks [classIdx]);
    TF = MathMax (0.1, MathMin (1.0, TF));

    // Confirmatory Factor
    double CF = MathExp (-0.5 * progress * classRanks [classIdx]);
    CF = MathMax (0.1, MathMin (1.0, CF));

    // Обновление позиции студента
    for (int c = 0; c < coords; c++)
    {
      double newPos = a [i].c [c];

      // a) Teacher Learning - учимся у учителя класса
      if (teachers [classIdx].f > -DBL_MAX)
      {
        newPos += TF * (teachers [classIdx].c [c] - a [i].c [c]);
      }

      // b) Personal Learning - учимся у своего лучшего решения
      if (currentIter > deltaIter && a [i].fB > -DBL_MAX)
      {
        double PF = u.RNDprobab ();
        newPos += PF * (a [i].cB [c] - a [i].c [c]);
      }

      // c) Confirmatory Learning - учимся у среднего всех учителей
      if (currentIter > deltaIter && validTeachers > 0)
      {
        double rnd = u.RNDprobab ();
        if (rnd >= gamma) // Участвует с вероятностью (1-gamma)
        {
          newPos += CF * (CL [c] - a [i].c [c]);
        }
      }

      // Применение границ
      a [i].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//————————————————————————————————————————————————————————————————————

O método "Revision ()" da classe "C_AO_CLA_l" é usado para atualizar as informações sobre as melhores soluções de cada agente, bem como a melhor solução global e os parâmetros correspondentes.

Para cada agente, verifica-se se o valor atual da função objetivo (a [i].f) melhorou em relação ao seu melhor valor armazenado (a [i].fB). Se isso ocorrer, o melhor valor é salvo e as coordenadas correspondentes são copiadas. Depois de verificar todos os agentes, se algum deles obtiver um valor da função melhor que o melhor valor global atual (fB), os parâmetros globais são atualizados: fB, o melhor valor global da função, e cB, as coordenadas dessa melhor solução.

Em seguida, chama-se o método "UpdateTeachersAndCosts ()", que atualiza as informações sobre os professores de cada classe. Ao final, chama-se "UpdateClassRanks ()" para recalcular os ranks das classes, o que influencia a priorização de certas soluções nas iterações seguintes.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::Revision ()
{
  for (int i = 0; i < popSize; i++)
  {
    // Обновление персональных лучших позиций
    if (a [i].f > a [i].fB)
    {
      a [i].fB = a [i].f;
      ArrayCopy (a [i].cB, a [i].c);
    }
    // Обновление глобального лучшего
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ArrayCopy (cB, a [i].c);
    }
  }

  // Обновление учителей 
  UpdateTeachersAndCosts ();

  // Обновление рангов классов
  UpdateClassRanks ();
}
//————————————————————————————————————————————————————————————————————

O método "UpdateTeachersAndCosts ()" é responsável por atualizar as informações sobre os professores de cada classe e calcular o custo total da classe. O método percorre, em loop, todas as classes definidas no sistema. Para cada classe, são determinados os índices inicial e final dos alunos (agentes) que pertencem a ela.

Para encontrar o melhor aluno da classe, são inicializadas variáveis para armazenar o melhor valor da função, o índice do melhor aluno, a soma dos valores da função de todos os alunos da classe e a quantidade de alunos válidos. O loop percorre todos os alunos da classe atual. Para cada aluno, verifica-se se sua solução é válida e, em caso afirmativo, o valor da função desse aluno é adicionado a "sumFitness", o contador de alunos válidos é incrementado e, se o valor da função do aluno atual for melhor que o melhor valor atual em "bestFitness", então esse valor e "bestIdx" são atualizados.

Após identificar o melhor aluno da classe, o método verifica se há pelo menos um aluno válido na classe (validStudents > 0). Se essa condição for atendida, as coordenadas do melhor aluno são copiadas para as coordenadas do professor da classe correspondente, e ao professor é atribuído o valor da função do melhor aluno.

Em seguida, calcula-se a média dos valores da função de todos os alunos da classe, "avgFitness". O custo total da classe é calculado como a soma do valor da função do melhor aluno com o produto do coeficiente "beta" pelo valor médio da função de todos os alunos. Essa métrica combina o desempenho do professor com o desempenho médio da classe.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA::UpdateTeachersAndCosts ()
{
  for (int k = 0; k < numClasses; k++)
  {
    int startIdx = k * studentsPerClass;
    int endIdx = startIdx + studentsPerClass;

    double bestFitness = -DBL_MAX;
    int bestIdx = startIdx;
    double sumFitness = 0.0;
    int validStudents = 0;

    // Находим лучшего студента (учителя) в классе
    for (int i = startIdx; i < endIdx; i++)
    {
      if (a[i].f > -DBL_MAX) // Проверка валидности
      {
        sumFitness += a[i].f;
        validStudents++;
        
        if (a[i].f > bestFitness)
        {
          bestFitness = a[i].f;
          bestIdx = i;
        }
      }
    }

    // Обновляем учителя
    if (validStudents > 0)
    {
      ArrayCopy (teachers[k].c, a[bestIdx].c);
      teachers[k].f = bestFitness;
      
      // Расчет total cost класса
      double avgFitness = sumFitness / validStudents;
      classTotalCosts[k] = bestFitness + beta * avgFitness;
    }
  }
}
//————————————————————————————————————————————————————————————————————

O método "UpdateClassRanks ()" é usado para determinar os ranks das classes com base em seu custo total, que caracteriza a eficácia de cada classe. O método começa buscando o custo mínimo e o custo máximo entre todas as classes válidas. Se todas as classes tiverem o mesmo custo, ou se não houver classes válidas, então todas recebem o mesmo rank, igual a 1.

Se houver diferença entre os custos, esses valores são normalizados, ou seja, cada custo é mapeado para o intervalo de 0 a 1. Depois disso, aplica-se a inversão: classes com custo mais alto recebem rank mais baixo, próximo de 1, enquanto classes com custo mais baixo recebem rank mais alto, próximo do rank máximo, igual ao número de classes.

Em seguida, cada valor de rank é limitado aos valores mínimo e máximo permitidos, para evitar que ultrapasse os limites permitidos. Como resultado desse método, as classes recebem ranks com base em seu desempenho.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::UpdateClassRanks ()
{
  // Находим min и max costs среди валидных классов
  double minCost   = DBL_MAX;
  double maxCost   = -DBL_MAX;
  int validClasses = 0;

  for (int k = 0; k < numClasses; k++)
  {
    if (classTotalCosts [k] > -DBL_MAX)
    {
      if (classTotalCosts [k] < minCost) minCost = classTotalCosts [k];
      if (classTotalCosts [k] > maxCost) maxCost = classTotalCosts [k];
      validClasses++;
    }
  }

  if (validClasses == 0 || maxCost - minCost < 1e-10)
  {
    // Все классы одинаковые или нет валидных
    for (int k = 0; k < numClasses; k++) classRanks [k] = 1.0;
  }
  else
  {
    // Ранжирование: лучшие классы (высокий cost) получают низкий ранг
    for (int k = 0; k < numClasses; k++)
    {
      if (classTotalCosts [k] > -DBL_MAX)
      {
        // Нормализация от 0 до 1
        double normalized = (classTotalCosts [k] - minCost) / (maxCost - minCost);

        // Инверсия: лучшие получают ранг близкий к 1
        classRanks [k] = 1.0 + (1.0 - normalized) * (numClasses - 1.0);

        // Ограничение
        classRanks [k] = MathMax (1.0, MathMin ((double)numClasses, classRanks [k]));
      }
      else
      {
        classRanks [k] = numClasses; // Худший ранг для неинициализированных
      }
    }
  }
}
//————————————————————————————————————————————————————————————————————


Resultados dos testes

Nos testes, o algoritmo CLA_L apresenta bons resultados.

CLA_L|Competitive Learning Algorithm|198.0|3.0|0.3|0.8|2.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.6482993681242128
25 Hilly's; Func runs: 10000; result: 0.5535249826770444
500 Hilly's; Func runs: 10000; result: 0.2584959913710746
=============================
5 Forest's; Func runs: 10000; result: 0.8027208362980616
25 Forest's; Func runs: 10000; result: 0.49540442971179494
500 Forest's; Func runs: 10000; result: 0.20048686632188017
=============================
5 Megacity's; Func runs: 10000; result: 0.6353846153846153
25 Megacity's; Func runs: 10000; result: 0.2716923076923076
500 Megacity's; Func runs: 10000; result: 0.10086153846153936
=============================
All score: 3.96687 (44.08%)

Na visualização, nota-se que, na fase inicial, o algoritmo apresenta boa capacidade de busca, mas ela se deteriora ao convergir prematuramente para ótimos locais, o que leva à estagnação na segunda metade da execução.

Hilly

CLA_L na função de teste Hilly

Forest

CLA_L na função de teste Forest

Megacity

CLA_L na função de teste Megacity

Na tabela comparativa, o CLA_L é apresentado de forma ilustrativa.

AO Description Hilly Hilly
Final
Forest Forest
Final
Megacity (discrete) Megacity
Final
Final
Result
% of
MAX
10 p (5 F)50 p (25 F)1000 p (500 F)10 p (5 F)50 p (25 F)1000 p (500 F)10 p (5 F)50 p (25 F)1000 p (500 F)
1ANSacross neighbourhood search0,949480,847760,438572,235811,000000,923340,399882,323230,709230,634770,230911,574916,13468,15
2CLAcode lock algorithm (joo)0,953450,871070,375902,200420,989420,917090,316422,222940,796920,693850,193031,683806,10767,86
3AMOmanimal migration ptimization M0,903580,843170,462842,209590,990010,924360,465982,380340,567690,591320,237731,396755,98766,52
4(P+O)ES(P+O) evolution strategies0,922560,881010,400212,203790,977500,874900,319452,171850,673850,629850,186341,490035,86665,17
5CTAcomet tail algorithm (joo)0,953460,863190,277702,094350,997940,857400,339492,194840,887690,564310,105121,557125,84664,96
6TETAtime evolution travel algorithm (joo)0,913620,823490,319902,057010,970960,895320,293242,159520,734620,685690,160211,580525,79764,41
7SDSmstochastic diffusion search M0,930660,854450,394762,179880,999830,892440,196192,088460,723330,611000,106701,441035,70963,44
8BOAmbilliards optimization algorithm M0,957570,825990,252352,035901,000000,900360,305022,205380,735380,525230,095631,356255,59862,19
9AAmarchery algorithm M0,917440,708760,421602,047800,925270,758020,353282,036570,673850,552000,237381,463235,54861,64
10ESGevolution of social groups (joo)0,999060,796540,350562,146161,000000,828630,131021,959650,823330,553000,047251,423585,52961,44
11SIAsimulated isotropic annealing (joo)0,957840,842640,414652,215130,982390,795860,205071,983320,686670,493000,090531,270205,46960,76
12EOmextremal_optimization_M0,761660,772420,317471,851550,999990,767510,235272,002770,747690,539690,142491,429875,28458,71
13BBObiogeography based optimization0,949120,694560,350311,993990,938200,673650,256821,868670,746150,482770,173691,402615,26558,50
14ACSartificial cooperative search0,755470,747440,304071,806981,000000,888610,224132,112740,690770,481850,133221,305835,22658,06
15DAdialectical algorithm0,861830,700330,337241,899400,981630,727720,287181,996530,703080,452920,163671,319675,21657,95
16BHAmblack hole algorithm M0,752360,766750,345831,864930,935930,801520,271772,009230,650770,516460,154721,321955,19657,73
17ASOanarchy society optimization0,848720,746460,314651,909830,961480,791500,238031,991010,570770,540620,166141,277525,17857,54
18RFOroyal flush optimization (joo)0,833610,737420,346291,917330,894240,738240,240981,873460,631540,502920,164211,298675,08956,55
19AOSmatomic orbital search M0,802320,704490,310211,817020,856600,694510,219961,771070,746150,528620,143581,418355,00655,63
20TSEAturtle shell evolution algorithm (joo)0,967980,644800,296721,909490,994490,619810,227081,841390,690770,426460,135981,253225,00455,60
21BSAbacktracking_search_algorithm0,973090,545340,290981,809410,999990,585430,217471,802890,847690,369530,129781,347004,95955,10
22DEdifferential evolution0,950440,616740,303081,870260,953170,788960,166521,908650,786670,360330,029531,176534,95555,06
23SRAsuccessful restaurateur algorithm (joo)0,968830,634550,292171,895550,946370,555060,191241,692670,749230,440310,125261,314804,90354,48
24CROchemical reaction optimisation0,946290,661120,298531,905930,879060,584220,211461,674730,758460,426460,126861,311784,89254,36
25BIOblood inheritance optimization (joo)0,815680,653360,308771,777810,899370,653190,217601,770160,678460,476310,139021,293784,84253,80
26BSAbird swarm algorithm0,893060,649000,262501,804550,924200,711210,249391,884790,693850,326150,100121,120124,80953,44
27DEAdolphin_echolocation_algorithm0,759950,675720,341711,777380,895820,642230,239411,777460,615380,440310,151151,206844,76252,91
28HSharmony search0,865090,687820,325271,878180,999990,680020,095901,775920,620000,422670,054581,097254,75152,79
29SSGsaplings sowing and growing0,778390,649250,395431,823080,859730,624670,174291,658690,646670,441330,105981,193984,67651,95
30BCOmbacterial chemotaxis optimization M0,759530,622680,314831,697040,893780,613390,225421,732590,653850,420920,144351,219124,64951,65
31ABOafrican buffalo optimization0,833370,622470,299641,755480,921700,586180,197231,705110,610000,431540,132251,173784,63451,49
32(PO)ES(PO) evolution strategies0,790250,626470,429351,846060,876160,609430,195911,681510,590000,379330,113221,082554,61051,22
33FBAfractal-based Algorithm0,790000,651340,289651,730990,871580,568230,188771,628580,610770,460620,123981,195374,55550,61
34TSmtabu search M0,877950,614310,291041,783300,928850,518440,190541,637830,610770,382150,121571,114494,53650,40
35BSObrain storm optimization0,937360,576160,296881,810410,931310,558660,235371,725340,552310,290770,119140,962224,49849,98
36WOAmwale optimization algorithm M0,845210,562980,262631,670810,931000,522780,163651,617430,663080,411380,113571,188034,47649,74
37AEFAartificial electric field algorithm0,877000,617530,252351,746880,927290,726980,180641,834900,666150,116310,095080,877544,45949,55
38AEOartificial ecosystem-based optimization algorithm0,913800,467130,264701,645630,902230,437050,214001,553270,661540,308000,285631,255174,45449,49
39CAmcamel algorithm M0,786840,560420,351331,698590,827720,560410,243361,631490,648460,330920,134181,113564,44449,37
40ACOmant colony optimization M0,881900,661270,303771,846930,858730,586800,150511,596040,596670,373330,024720,994724,43849,31
41CMAEScovariance_matrix_adaptation_evolution_strategy0,762580,720890,000001,483470,820560,796160,000001,616720,758460,490770,000001,249234,34948,33
42BFO-GAbacterial foraging optimization - ga0,891500,551110,315291,757900,969820,396120,063051,428990,726670,275000,035251,036924,22446,93
43SOAsimple optimization algorithm0,915200,469760,270891,655850,896750,374010,169841,440600,695380,280310,108521,084224,18146,45
44ABHAartificial bee hive algorithm0,841310,542270,263041,646630,878580,477790,171811,528180,509230,338770,103970,951974,12745,85
45ACMOatmospheric cloud model optimization0,903210,485460,304031,692700,802680,378570,191781,373030,623080,244000,107950,975034,04144,90
CLA_Lcompetitivelearningalgorithm0,648290,553520,258491,460300,802720,495400,200481,498600,635380,271690,100861,007933,96744,08
RWrandom walk0,487540,321590,257811,066940,375540,219440,158770,753750,279690,149170,098470,527342,34826,09


Considerações finais

O algoritmo de aprendizagem competitiva (CLA_L) apresenta desempenho mediano na resolução de problemas padrão de otimização. A análise do funcionamento do algoritmo revelou uma dinâmica característica em duas fases: exploração ativa nas iterações iniciais e estagnação prematura na segunda metade da otimização.

A divisão da população em classes garante boa cobertura do espaço de busca nas etapas iniciais. Cada classe explora sua própria região, o que favorece a busca global. O modelo educacional torna o algoritmo compreensível e de fácil interpretação. Os conceitos de professores, alunos e diferentes tipos de aprendizagem são intuitivos. Os fatores de aprendizagem, que dependem do rank da classe, em tese devem garantir o equilíbrio entre exploração e intensificação. A combinação de três formas de aprendizagem, com o professor, individual e confirmatória, ajuda a evitar o aprisionamento em ótimos locais. Apesar dos mecanismos de diversificação, o algoritmo tende a ficar preso em ótimos locais. 

O algoritmo CLA apresenta uma proposta interessante de aplicação da metáfora educacional a problemas de otimização. Apesar da abordagem inovadora e dos bons resultados iniciais, o algoritmo exige modificações substanciais para se tornar competitivo em relação às metaheurísticas modernas. O principal desafio continua sendo manter o equilíbrio entre exploração e intensificação durante toda a otimização.

tab

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

chart

Figura 3. 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, no arquivo compactado está o script para calcular a tabela de classificação)

Vantagens e desvantagens do algoritmo CLA_L:

Vantagens:

  1. Rápido.

Desvantagens:

  1. Grande quantidade de parâmetros externos.
  2. Tendência a ficar preso em determinados problemas.

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


Programas utilizados no artigo

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

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

Arquivos anexados |
CLA_l.ZIP (317.9 KB)
Desenvolvimento do Toolkit de Análise de Price Action (Parte 16): Introduzindo a Teoria dos Quartis (II) — Intrusion Detector EA Desenvolvimento do Toolkit de Análise de Price Action (Parte 16): Introduzindo a Teoria dos Quartis (II) — Intrusion Detector EA
Em nosso artigo anterior, apresentamos um script simples chamado "The Quarters Drawer." Com base nessa fundação, agora estamos dando o próximo passo ao criar um Expert Advisor (EA) de monitoramento para acompanhar esses quartis e fornecer supervisão em relação a possíveis reações do mercado nesses níveis. Junte-se a nós enquanto exploramos o processo de desenvolvimento de uma ferramenta de detecção de zonas neste artigo.
Redes neurais em trading: Modelo multidimensional de ponta a ponta para previsão de séries temporais (Conclusão) Redes neurais em trading: Modelo multidimensional de ponta a ponta para previsão de séries temporais (Conclusão)
Apresentamos a parte final da série dedicada ao GinAR, um framework de redes neurais para previsão de séries temporais. Neste artigo, analisamos os resultados do teste do modelo com novos dados e avaliamos sua estabilidade em condições reais de mercado.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Técnicas do MQL5 Wizard que você deve conhecer (Parte 56): Fractais de Bill Williams Técnicas do MQL5 Wizard que você deve conhecer (Parte 56): Fractais de Bill Williams
Os Fractais de Bill Williams são um indicador poderoso que é fácil de ignorar quando inicialmente observado em um gráfico de preços. Ele parece muito carregado e provavelmente não é suficientemente incisivo. Nosso objetivo é remover essa impressão sobre este indicador, examinando o que seus diversos padrões podem realizar quando avaliados com testes forward walk em todos eles, utilizando um Expert Advisor montado pelo Wizard.