Algoritmo de Aprendizagem Competitiva - Competitive Learning Algorithm (CLA)
Conteúdo
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.

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.
- 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.

CLA_L na função de teste Hilly

CLA_L na função de teste Forest

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) | ||||||||
| 1 | ANS | across neighbourhood search | 0,94948 | 0,84776 | 0,43857 | 2,23581 | 1,00000 | 0,92334 | 0,39988 | 2,32323 | 0,70923 | 0,63477 | 0,23091 | 1,57491 | 6,134 | 68,15 |
| 2 | CLA | code lock algorithm (joo) | 0,95345 | 0,87107 | 0,37590 | 2,20042 | 0,98942 | 0,91709 | 0,31642 | 2,22294 | 0,79692 | 0,69385 | 0,19303 | 1,68380 | 6,107 | 67,86 |
| 3 | AMOm | animal migration ptimization M | 0,90358 | 0,84317 | 0,46284 | 2,20959 | 0,99001 | 0,92436 | 0,46598 | 2,38034 | 0,56769 | 0,59132 | 0,23773 | 1,39675 | 5,987 | 66,52 |
| 4 | (P+O)ES | (P+O) evolution strategies | 0,92256 | 0,88101 | 0,40021 | 2,20379 | 0,97750 | 0,87490 | 0,31945 | 2,17185 | 0,67385 | 0,62985 | 0,18634 | 1,49003 | 5,866 | 65,17 |
| 5 | CTA | comet tail algorithm (joo) | 0,95346 | 0,86319 | 0,27770 | 2,09435 | 0,99794 | 0,85740 | 0,33949 | 2,19484 | 0,88769 | 0,56431 | 0,10512 | 1,55712 | 5,846 | 64,96 |
| 6 | TETA | time evolution travel algorithm (joo) | 0,91362 | 0,82349 | 0,31990 | 2,05701 | 0,97096 | 0,89532 | 0,29324 | 2,15952 | 0,73462 | 0,68569 | 0,16021 | 1,58052 | 5,797 | 64,41 |
| 7 | SDSm | stochastic diffusion search M | 0,93066 | 0,85445 | 0,39476 | 2,17988 | 0,99983 | 0,89244 | 0,19619 | 2,08846 | 0,72333 | 0,61100 | 0,10670 | 1,44103 | 5,709 | 63,44 |
| 8 | BOAm | billiards optimization algorithm M | 0,95757 | 0,82599 | 0,25235 | 2,03590 | 1,00000 | 0,90036 | 0,30502 | 2,20538 | 0,73538 | 0,52523 | 0,09563 | 1,35625 | 5,598 | 62,19 |
| 9 | AAm | archery algorithm M | 0,91744 | 0,70876 | 0,42160 | 2,04780 | 0,92527 | 0,75802 | 0,35328 | 2,03657 | 0,67385 | 0,55200 | 0,23738 | 1,46323 | 5,548 | 61,64 |
| 10 | ESG | evolution of social groups (joo) | 0,99906 | 0,79654 | 0,35056 | 2,14616 | 1,00000 | 0,82863 | 0,13102 | 1,95965 | 0,82333 | 0,55300 | 0,04725 | 1,42358 | 5,529 | 61,44 |
| 11 | SIA | simulated isotropic annealing (joo) | 0,95784 | 0,84264 | 0,41465 | 2,21513 | 0,98239 | 0,79586 | 0,20507 | 1,98332 | 0,68667 | 0,49300 | 0,09053 | 1,27020 | 5,469 | 60,76 |
| 12 | EOm | extremal_optimization_M | 0,76166 | 0,77242 | 0,31747 | 1,85155 | 0,99999 | 0,76751 | 0,23527 | 2,00277 | 0,74769 | 0,53969 | 0,14249 | 1,42987 | 5,284 | 58,71 |
| 13 | BBO | biogeography based optimization | 0,94912 | 0,69456 | 0,35031 | 1,99399 | 0,93820 | 0,67365 | 0,25682 | 1,86867 | 0,74615 | 0,48277 | 0,17369 | 1,40261 | 5,265 | 58,50 |
| 14 | 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 |
| 15 | DA | dialectical algorithm | 0,86183 | 0,70033 | 0,33724 | 1,89940 | 0,98163 | 0,72772 | 0,28718 | 1,99653 | 0,70308 | 0,45292 | 0,16367 | 1,31967 | 5,216 | 57,95 |
| 16 | BHAm | black hole algorithm M | 0,75236 | 0,76675 | 0,34583 | 1,86493 | 0,93593 | 0,80152 | 0,27177 | 2,00923 | 0,65077 | 0,51646 | 0,15472 | 1,32195 | 5,196 | 57,73 |
| 17 | ASO | anarchy society optimization | 0,84872 | 0,74646 | 0,31465 | 1,90983 | 0,96148 | 0,79150 | 0,23803 | 1,99101 | 0,57077 | 0,54062 | 0,16614 | 1,27752 | 5,178 | 57,54 |
| 18 | RFO | royal flush optimization (joo) | 0,83361 | 0,73742 | 0,34629 | 1,91733 | 0,89424 | 0,73824 | 0,24098 | 1,87346 | 0,63154 | 0,50292 | 0,16421 | 1,29867 | 5,089 | 56,55 |
| 19 | AOSm | atomic orbital search M | 0,80232 | 0,70449 | 0,31021 | 1,81702 | 0,85660 | 0,69451 | 0,21996 | 1,77107 | 0,74615 | 0,52862 | 0,14358 | 1,41835 | 5,006 | 55,63 |
| 20 | TSEA | turtle shell evolution algorithm (joo) | 0,96798 | 0,64480 | 0,29672 | 1,90949 | 0,99449 | 0,61981 | 0,22708 | 1,84139 | 0,69077 | 0,42646 | 0,13598 | 1,25322 | 5,004 | 55,60 |
| 21 | BSA | backtracking_search_algorithm | 0,97309 | 0,54534 | 0,29098 | 1,80941 | 0,99999 | 0,58543 | 0,21747 | 1,80289 | 0,84769 | 0,36953 | 0,12978 | 1,34700 | 4,959 | 55,10 |
| 22 | 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 |
| 23 | SRA | successful restaurateur algorithm (joo) | 0,96883 | 0,63455 | 0,29217 | 1,89555 | 0,94637 | 0,55506 | 0,19124 | 1,69267 | 0,74923 | 0,44031 | 0,12526 | 1,31480 | 4,903 | 54,48 |
| 24 | 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 |
| 25 | BIO | blood inheritance optimization (joo) | 0,81568 | 0,65336 | 0,30877 | 1,77781 | 0,89937 | 0,65319 | 0,21760 | 1,77016 | 0,67846 | 0,47631 | 0,13902 | 1,29378 | 4,842 | 53,80 |
| 26 | 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 |
| 27 | DEA | dolphin_echolocation_algorithm | 0,75995 | 0,67572 | 0,34171 | 1,77738 | 0,89582 | 0,64223 | 0,23941 | 1,77746 | 0,61538 | 0,44031 | 0,15115 | 1,20684 | 4,762 | 52,91 |
| 28 | 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 |
| 29 | 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 |
| 30 | BCOm | bacterial chemotaxis optimization M | 0,75953 | 0,62268 | 0,31483 | 1,69704 | 0,89378 | 0,61339 | 0,22542 | 1,73259 | 0,65385 | 0,42092 | 0,14435 | 1,21912 | 4,649 | 51,65 |
| 31 | ABO | african buffalo optimization | 0,83337 | 0,62247 | 0,29964 | 1,75548 | 0,92170 | 0,58618 | 0,19723 | 1,70511 | 0,61000 | 0,43154 | 0,13225 | 1,17378 | 4,634 | 51,49 |
| 32 | (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 |
| 33 | FBA | fractal-based Algorithm | 0,79000 | 0,65134 | 0,28965 | 1,73099 | 0,87158 | 0,56823 | 0,18877 | 1,62858 | 0,61077 | 0,46062 | 0,12398 | 1,19537 | 4,555 | 50,61 |
| 34 | TSm | tabu search M | 0,87795 | 0,61431 | 0,29104 | 1,78330 | 0,92885 | 0,51844 | 0,19054 | 1,63783 | 0,61077 | 0,38215 | 0,12157 | 1,11449 | 4,536 | 50,40 |
| 35 | 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 |
| 36 | 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 |
| 37 | AEFA | artificial electric field algorithm | 0,87700 | 0,61753 | 0,25235 | 1,74688 | 0,92729 | 0,72698 | 0,18064 | 1,83490 | 0,66615 | 0,11631 | 0,09508 | 0,87754 | 4,459 | 49,55 |
| 38 | AEO | artificial ecosystem-based optimization algorithm | 0,91380 | 0,46713 | 0,26470 | 1,64563 | 0,90223 | 0,43705 | 0,21400 | 1,55327 | 0,66154 | 0,30800 | 0,28563 | 1,25517 | 4,454 | 49,49 |
| 39 | CAm | camel algorithm M | 0,78684 | 0,56042 | 0,35133 | 1,69859 | 0,82772 | 0,56041 | 0,24336 | 1,63149 | 0,64846 | 0,33092 | 0,13418 | 1,11356 | 4,444 | 49,37 |
| 40 | 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 |
| 41 | CMAES | covariance_matrix_adaptation_evolution_strategy | 0,76258 | 0,72089 | 0,00000 | 1,48347 | 0,82056 | 0,79616 | 0,00000 | 1,61672 | 0,75846 | 0,49077 | 0,00000 | 1,24923 | 4,349 | 48,33 |
| 42 | 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 |
| 43 | SOA | simple optimization algorithm | 0,91520 | 0,46976 | 0,27089 | 1,65585 | 0,89675 | 0,37401 | 0,16984 | 1,44060 | 0,69538 | 0,28031 | 0,10852 | 1,08422 | 4,181 | 46,45 |
| 44 | ABHA | artificial bee hive algorithm | 0,84131 | 0,54227 | 0,26304 | 1,64663 | 0,87858 | 0,47779 | 0,17181 | 1,52818 | 0,50923 | 0,33877 | 0,10397 | 0,95197 | 4,127 | 45,85 |
| 45 | ACMO | atmospheric cloud model optimization | 0,90321 | 0,48546 | 0,30403 | 1,69270 | 0,80268 | 0,37857 | 0,19178 | 1,37303 | 0,62308 | 0,24400 | 0,10795 | 0,97503 | 4,041 | 44,90 |
| CLA_L | competitivelearningalgorithm | 0,64829 | 0,55352 | 0,25849 | 1,46030 | 0,80272 | 0,49540 | 0,20048 | 1,49860 | 0,63538 | 0,27169 | 0,10086 | 1,00793 | 3,967 | 44,08 | |
| RW | random walk | 0,48754 | 0,32159 | 0,25781 | 1,06694 | 0,37554 | 0,21944 | 0,15877 | 0,75375 | 0,27969 | 0,14917 | 0,09847 | 0,52734 | 2,348 | 26,09 | |
Considerações finais
O algoritmo 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.

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

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:
- Rápido.
Desvantagens:
- Grande quantidade de parâmetros externos.
- 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
| # | Nome | Tipo | Descrição |
|---|---|---|---|
| 1 | #C_AO.mqh | Arquivo de inclusão | Classe base dos algoritmos populacionais de otimização |
| 2 | #C_AO_enum.mqh | Arquivo de inclusão | Enumeração dos algoritmos populacionais de otimização |
| 3 | TestFunctions.mqh | Arquivo de inclusão | Biblioteca de funções de teste |
| 4 | TestStandFunctions.mqh | Arquivo de inclusão | Biblioteca de funções do ambiente de testes |
| 5 | Utilities.mqh | Arquivo de inclusão | Biblioteca de funções auxiliares |
| 6 | CalculationTestResults.mqh | Arquivo de inclusão | Script para cálculo dos resultados na tabela comparativa |
| 7 | Testing AOs.mq5 | Script | Ambiente de testes unificado para todos os algoritmos populacionais de otimização |
| 8 | Simple use of population optimization algorithms.mq5 | Script | Exemplo simples de uso de algoritmos populacionais de otimização sem visualização |
| 9 | Test_AO_CLA_L.mq5 | Script | Ambiente de testes para o CLA_L |
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/18857
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Desenvolvimento do Toolkit de Análise de Price Action (Parte 16): Introduzindo a Teoria dos Quartis (II) — Intrusion Detector EA
Redes neurais em trading: Modelo multidimensional de ponta a ponta para previsão de séries temporais (Conclusão)
Está chegando o novo MetaTrader 5 e MQL5
Técnicas do MQL5 Wizard que você deve conhecer (Parte 56): Fractais de Bill Williams
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso