Otimização por Comunidade de Cientistas - Community of Scientist Optimization (CoSO): Prática
Conteúdo:
Implementação do algoritmo
Continuaremos a descrição da implementação do algoritmo iniciada na primeira parte do artigo e também apresentaremos os resultados dos testes experimentais em funções de teste especializadas.
A função "AssignFunds" descreve o mecanismo de distribuição dos "recursos" disponíveis entre os pesquisadores no algoritmo CoSO. Esses recursos representam oportunidades de aprendizado, deslocamento ou participação em etapas posteriores, e sua distribuição influencia a dinâmica de evolução das soluções. A função recebe um parâmetro: "availableFunds", que representa a quantidade total de recursos a ser distribuída. Essa distribuição é dividida em várias etapas.
Divisão dos recursos em duas partes. É calculado "outsiderFunds", a parcela dos recursos destinada aos "outsiders". A quantidade desses recursos é definida como uma fração do "availableFunds" total, em que "omegaCurrent" (parâmetro que controla a parcela de recursos destinada aos outsiders) atua como coeficiente. Os recursos restantes, "existingFunds", são destinados à distribuição entre os pesquisadores ativos.Distribuição dos recursos aos pesquisadores existentes. Esta parte é executada somente se houver um "relatório global" (globalReport) e se seu tamanho for maior que zero; então é calculado "totalRank", a soma de todas as posições de classificação em progressão aritmética de "1" até "reportSize". Em essência, trata-se da soma dos coeficientes de peso que serão usados para a distribuição proporcional dos recursos. Em seguida, os recursos (existingFunds) são distribuídos um a um: para cada recurso, é gerado um número aleatório, multiplicado por "totalRank", que será usado para selecionar o pesquisador. O algoritmo então itera sobre "globalReport".
Para cada registro em "globalReport", é calculada a soma cumulativa "cumSum", à qual se adiciona um "peso" igual a (reportSize - i). Isso significa que pesquisadores com posições mais altas no relatório recebem um peso maior e, portanto, têm mais chances de obter recursos. Se o número aleatório cair no intervalo associado ao pesquisador atual (ou seja, rnd <= cumSum), a quantidade de recursos desse pesquisador aumenta em uma unidade. Depois disso, o ciclo de distribuição do recurso atual é interrompido, e o algoritmo passa à distribuição do próximo recurso.
Criação de outsiders. Por fim, é chamada a função "CreateOutsiders", para a qual se passa "outsiderFunds". Essa função usa os recursos alocados aos "outsiders" para criar novos pesquisadores ou, em outras palavras, para iniciar novos caminhos de pesquisa.Assim, "AssignFunds" implementa uma estratégia de gestão de bolsas que recompensa pesquisadores com bom desempenho comprovado (por meio de "existingFunds" e da distribuição por ranking) e, ao mesmo tempo, estimula o surgimento de novas ideias ou agentes (por meio de "outsiderFunds").
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::AssignFunds (int availableFunds) { // Средства для аутсайдеров int outsiderFunds = (int)(availableFunds * omegaCurrent); int existingFunds = availableFunds - outsiderFunds; int reportSize = ArraySize (globalReport); // Распределение средств существующим исследователям if (reportSize > 0) { int totalRank = reportSize * (reportSize + 1) / 2; for (int f = 0; f < existingFunds; f++) { double rnd = u.RNDprobab () * totalRank; double cumSum = 0; for (int i = 0; i < reportSize; i++) { cumSum += reportSize - i; if (rnd <= cumSum) { researchers [globalReport [i].index].m++; break; } } } } // Создание аутсайдеров CreateOutsiders (outsiderFunds); } //————————————————————————————————————————————————————————————————————
A função "CreateOutsiders" descreve a rotina de criação de novos "pesquisadores" no modelo CoSO, usando os recursos alocados especificamente aos "outsiders". Esses novos pesquisadores introduzem diversidade potencial ou novas ideias no sistema. A função recebe um parâmetro: "outsiderFunds", que indica a quantidade de recursos destinada à criação de outsiders. Se "outsiderFunds" for menor ou igual a zero, a função interrompe imediatamente a execução, pois não há recursos para criar outsiders.
Definição da quantidade de novos pesquisadores. É definido "maxNew": a quantidade máxima de novos outsiders que pode ser criada neste momento. Esse valor depende do tamanho atual da população. Se a população for grande (mais de 100 elementos), "maxNew" será igual a 2 (para desacelerar o crescimento). Caso contrário, "maxNew" será igual a 5. Esse é um mecanismo de controle do crescimento da população. Em seguida, é determinada a quantidade efetiva de novos pesquisadores que será criada. Ela é escolhida aleatoriamente no intervalo entre um e o menor valor entre "outsiderFunds" e "maxNew". Isso garante que a quantidade de novos pesquisadores não ultrapasse os recursos disponíveis nem o limite definido. Depois, calcula-se quantos recursos cada novo pesquisador receberá (divisão simples do "outsiderFunds" total por "newResearchers").
Ciclo de criação de novos pesquisadores. A função executa um ciclo "newResearchers" vezes: primeiro, procura-se uma posição "livre" no array de pesquisadores existente (researchers). Se uma posição livre for encontrada (idx != -1), ela é usada. Se não houver posição livre, mas o tamanho atual da população for menor que o tamanho máximo permitido (maxPopSize), uma nova posição será adicionada ao final do array (idx = actualPopSize).
Expansão do array (se necessário). Se não houver posição livre e "actualPopSize" já for igual ou superior a "maxPopSize", verifica-se se é possível aumentar o tamanho do array de pesquisadores. Nesse caso, calcula-se um novo tamanho máximo (newMaxSize) como "maxPopSize + 50", sem ultrapassar 500. Esse é mais um mecanismo para limitar o crescimento da população. Se o limite absoluto de 500 for atingido, a iteração atual será ignorada (novos outsiders não serão criados). Caso contrário, "maxPopSize" é atualizado para "newMaxSize". Após as verificações, "idx" é definido como "actualPopSize" para usar a primeira nova posição. Se, por algum motivo, "idx" ainda for "-1" depois de todas as tentativas de encontrar ou criar uma posição, a criação do pesquisador atual será ignorada.
Inicialização do novo pesquisador. Se a posição "idx" for encontrada ou criada com sucesso, "researchers [idx]. alive" é definido como "true", tornando o pesquisador ativo; a quantidade de recursos, ou "motivação", é definida como "fundsPerNew", e a "força", ou outro parâmetro inicial, recebe um número aleatório.
Inicialização das coordenadas (posição no espaço de solução). Para cada coordenada "c" (coords, quantidade de dimensões), a posição é inicializada com um número aleatório no intervalo definido. Em seguida, "researchers [idx]. x [c]" é ajustado considerando o passo de discretização por meio da função "SeInDiSp", e a "melhor" posição, inicialmente igual à atual, também é definida em "researchers [idx]. x [c]". A velocidade, ou vetor de variação, é inicializada com um número aleatório obtido de uma distribuição normal com os parâmetros definidos.
Inicialização das probabilidades dos periódicos (revistas científicas de publicação). Para cada periódico "j" (journalsNum, quantidade de periódicos), a probabilidade de publicação no periódico "j" é inicializada com um número aleatório. Em seguida, "NormalizeProbabilities" é chamada sobre "researchers [idx]. rho", fazendo com que a soma de todos os "rho" desse pesquisador seja igual a um.
Atualização do tamanho da população. Se o novo pesquisador tiver sido adicionado ao final do array, "actualPopSize" é atualizado para "idx + 1".
Assim, "CreateOutsiders" adiciona dinamicamente novos pesquisadores à população, com inicialização aleatória no espaço de solução e distribuindo entre eles os recursos alocados. Os mecanismos de limitação "maxNew" e "maxPopSize" controlam o tamanho da população, impedindo seu crescimento infinito.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::CreateOutsiders (int outsiderFunds) { if (outsiderFunds <= 0) return; // Ограничиваем количество новых аутсайдеров, особенно если популяция уже большая int maxNew = (actualPopSize > 100) ? 2 : 5; int newResearchers = (int)(u.RNDfromCI (1, MathMin (outsiderFunds, maxNew))); int fundsPerNew = outsiderFunds / newResearchers; for (int i = 0; i < newResearchers; i++) { // Находим свободное место int idx = -1; for (int j = 0; j < actualPopSize; j++) { if (!researchers [j].alive) { idx = j; break; } } if (idx == -1 && actualPopSize < maxPopSize) { idx = actualPopSize; } if (idx == -1) // Нет места, расширяем массив { if (actualPopSize >= maxPopSize) { // Ограничиваем рост популяции int newMaxSize = MathMin (maxPopSize + 50, 500); if (newMaxSize == maxPopSize) continue; // Достигнут лимит, пропускаем создание maxPopSize = newMaxSize; ArrayResize (researchers, maxPopSize); for (int j = actualPopSize; j < maxPopSize; j++) { researchers [j].Init (coords, journalsNum); researchers [j].alive = false; } idx = actualPopSize; } } if (idx == -1) continue; // Не удалось создать researchers [idx].alive = true; researchers [idx].m = fundsPerNew; researchers [idx].s = u.RNDprobab (); // Случайная инициализация for (int c = 0; c < coords; c++) { researchers [idx].x [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); researchers [idx].x [c] = u.SeInDiSp (researchers [idx].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); researchers [idx].b [c] = researchers [idx].x [c]; researchers [idx].v [c] = u.GaussDistribution (0.0, -0.01, 0.01, 1); } // Инициализация вероятностей журналов for (int j = 0; j < journalsNum; j++) { researchers [idx].rho [j] = u.RNDprobab (); } NormalizeProbabilities (researchers [idx].rho); if (idx >= actualPopSize) actualPopSize = idx + 1; } } //————————————————————————————————————————————————————————————————————
A função "HireResearchers" descreve a rotina de "contratação" de novos pesquisadores por um pesquisador existente que possui uma quantidade suficiente de bolsas de pesquisa. Trata-se de um mecanismo de criação de novos elementos (soluções) levando em conta as características dos já existentes, o que constitui uma forma de reprodução ou diversificação. A função recebe um parâmetro: o índice do "supervisor", ou seja, o pesquisador que contratará os novos. Se o pesquisador com esse índice tiver uma quantidade de recursos menor ou igual a um, a função interrompe imediatamente a execução. Isso significa que a contratação exige uma quantidade suficiente de recursos.
Divisão dos recursos do supervisor. Calcula-se a parcela dos recursos que o supervisor mantém para si. Essa parcela é obtida multiplicando os recursos totais do supervisor por "researchers [idx]. s". Em seguida, calculam-se os recursos disponíveis para contratação, correspondentes ao restante. Os recursos do supervisor são atualizados. Se "hireFunds" for menor ou igual a 0, a contratação não é possível, e a função interrompe a execução.
Definição da quantidade de pesquisadores a contratar. É definida a quantidade máxima de novos pesquisadores que pode ser contratada. Se a população atual for grande (mais de 100), "maxNew" será igual a 1. Caso contrário, "maxNew" será igual a 3. Esse é um mecanismo de controle do crescimento da população. Em seguida, é determinada a quantidade efetiva de novos pesquisadores que será criada. Ela é escolhida aleatoriamente no intervalo entre uma unidade e o menor valor entre "hireFunds" e "maxNew". Calcula-se quantos recursos cada novo pesquisador contratado receberá (divisão simples de "hireFunds" por "newCount").
Ciclo de criação de novos pesquisadores (contratação). A função executa um ciclo "newCount" vezes: primeiro, procura-se uma posição "livre" no array de pesquisadores existente. Considera-se livre a posição em que o indicador de atividade está definido como "false". Se uma posição livre for encontrada, ela é usada. Se não houver posição livre, mas o tamanho atual da população for menor que o tamanho máximo permitido, uma nova posição será adicionada ao final do array.
Verificação da possibilidade de contratação (ao atingir os limites). Se não houver posição livre e "actualPopSize" já for igual ou superior a "maxPopSize", ou se "actualPopSize" já tiver atingido o limite absoluto de 500, a criação do pesquisador atual será ignorada (o ciclo passa para a próxima iteração ou é encerrado). Se "newIdx" ainda for -1, isso indica que não é possível encontrar ou criar uma posição para o novo pesquisador, e a iteração atual do ciclo é ignorada.
Inicialização do novo pesquisador. Se a posição for encontrada com sucesso, "researchers [newIdx]. alive" é definido como "true", tornando o novo pesquisador ativo; seus recursos são definidos como "fundsPerNew". O parâmetro de "propensão" do novo pesquisador é inicializado com um número aleatório extraído de uma distribuição gaussiana. O valor médio dessa distribuição é obtido a partir de "researchers [idx]. s" (parâmetro do supervisor) e indica que o novo pesquisador será semelhante ao seu "supervisor". O valor "s" é limitado ao intervalo de "0" a "1".
Herança de características do supervisor. A melhor posição encontrada pelo novo pesquisador, ou seu "conhecimento", é copiada diretamente da melhor posição do supervisor, permitindo que ele herde "experiência".
Inicialização da posição (coordenadas). Para cada coordenada "c" (coords, quantidade de dimensões), a posição do novo pesquisador é inicializada como a posição do supervisor mais uma perturbação aleatória obtida de uma distribuição gaussiana. Isso significa que os novos pesquisadores aparecem "próximos" do seu supervisor, mas não exatamente na mesma posição. A posição é limitada aos intervalos definidos. Em seguida, "researchers [newIdx]. x [c]" é ajustado considerando o passo de discretização por meio da função "SeInDiSp". A velocidade, ou vetor de variação, também é inicializada aleatoriamente a partir de uma distribuição normal.
Inicialização das probabilidades dos periódicos (probabilidades de publicação). Para cada periódico "j" (journalsNum, quantidade de periódicos), a probabilidade de publicação no periódico "j" é inicializada com um número aleatório obtido de uma distribuição gaussiana. O valor médio dessa distribuição é obtido da probabilidade do supervisor. Isso permite que os novos pesquisadores herdem as preferências do supervisor em relação aos periódicos, mas com algum desvio aleatório. Valores negativos de "rho" são truncados para "0". Em seguida, "NormalizeProbabilities" é chamada sobre "researchers [newIdx]. rho", a fim de garantir que a soma de todos os "rho" desse pesquisador seja igual a um.
Atualização do tamanho da população. Se o novo pesquisador tiver sido adicionado ao final do array ("newIdx" for igual ou maior que "actualPopSize"), "actualPopSize" é atualizado para "newIdx + 1".
Assim, "HireResearchers" permite que pesquisadores bem-sucedidos se "reproduzam", criando novas instâncias que herdam parte de suas características, mas com alguma variação aleatória. Isso favorece a diversificação de regiões vizinhas no espaço de busca e a disseminação de estratégias bem-sucedidas, ao mesmo tempo que controla o tamanho total da população.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::HireResearchers (int idx) { if (researchers [idx].m <= 1) return; int keepFunds = (int)(researchers [idx].m * researchers [idx].s); int hireFunds = researchers [idx].m - keepFunds; researchers [idx].m = keepFunds; if (hireFunds <= 0) return; // Ограничиваем количество нанимаемых, особенно при большой популяции int maxNew = (actualPopSize > 100) ? 1 : 3; int newCount = (int)(u.RNDfromCI (1, MathMin (hireFunds, maxNew))); int fundsPerNew = hireFunds / newCount; for (int i = 0; i < newCount; i++) { // Находим свободное место int newIdx = -1; for (int j = 0; j < actualPopSize; j++) { if (!researchers [j].alive) { newIdx = j; break; } } if (newIdx == -1 && actualPopSize < maxPopSize) { newIdx = actualPopSize; } if (newIdx == -1) // Нет места { if (actualPopSize >= maxPopSize || actualPopSize >= 500) continue; // Пропускаем создание при достижении лимита } if (newIdx == -1) continue; // Не удалось найти место researchers [newIdx].alive = true; researchers [newIdx].m = fundsPerNew; researchers [newIdx].s = u.GaussDistribution (researchers [idx].s, 0, 1, 1); if (researchers [newIdx].s < 0) researchers [newIdx].s = 0; if (researchers [newIdx].s > 1) researchers [newIdx].s = 1; // Наследование от супервизора ArrayCopy (researchers [newIdx].b, researchers [idx].b, 0, 0, WHOLE_ARRAY); // Позиция около супервизора for (int c = 0; c < coords; c++) { researchers [newIdx].x [c] = researchers [idx].x [c] + u.GaussDistribution (0.0, -0.01, 0.01, 1); // Контроль границ if (researchers [newIdx].x [c] < rangeMin [c]) researchers [newIdx].x [c] = rangeMin [c]; if (researchers [newIdx].x [c] > rangeMax [c]) researchers [newIdx].x [c] = rangeMax [c]; researchers [newIdx].x [c] = u.SeInDiSp (researchers [newIdx].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); researchers [newIdx].v [c] = u.GaussDistribution (0.0, -0.01, 0.01, 1); } // Возмущенные вероятности журналов for (int j = 0; j < journalsNum; j++) { researchers [newIdx].rho [j] = u.GaussDistribution (researchers [idx].rho [j], 0, 1, 1); if (researchers [newIdx].rho [j] < 0) researchers [newIdx].rho [j] = 0; } NormalizeProbabilities (researchers [newIdx].rho); if (newIdx >= actualPopSize) actualPopSize = newIdx + 1; } } //————————————————————————————————————————————————————————————————————
A função "ComputeStdDev" é usada para calcular o desvio padrão dos valores da função objetivo para todos os pesquisadores ativos na população. Trata-se de uma medida de dispersão dos dados em torno do valor médio e, no contexto da otimização, pode indicar a diversidade das soluções na população atual.
Cálculo do valor médio (Mean):- Inicializam-se as variáveis "mean" (para acumular a soma dos valores de "f") e "count" (para contar a quantidade de pesquisadores ativos).
- A função itera sobre todos os pesquisadores no array "researchers", de "0" até "actualPopSize - 1".
- Dentro do ciclo, verifica-se se o pesquisador "researchers [i]" está "ativo", pois apenas pesquisadores ativos devem ser considerados nos cálculos.
- Se o pesquisador estiver ativo, seu valor "f" é adicionado a "mean" e "count" é incrementado em "1".
- Após a conclusão do primeiro ciclo, se "count" ainda for igual a "0" (nenhum pesquisador ativo foi encontrado), a função retorna "0".
- Por fim, "mean" é dividido por "count" para obter o valor médio aritmético de "f" para todos os pesquisadores ativos.
- A variável "variance" é inicializada com "0".
- A função itera novamente por todos os pesquisadores no array "researchers".
- A condição de pesquisador ativo é verificada novamente.
- Para cada pesquisador ativo, calcula-se o quadrado da diferença entre seu valor "f" e o "mean" já calculado. Esse resultado é adicionado a "variance".
- Após a conclusão do segundo ciclo, "variance" é dividido por "count". Isso fornece a variância dos valores de "f" para os pesquisadores ativos.
//———————————————————————————————————————————————————————————————————— double C_AO_CoSO::ComputeStdDev () { if (actualPopSize == 0) return 0; double mean = 0; int count = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) { mean += researchers [i].f; count++; } } if (count == 0) return 0; mean /= count; double variance = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) { variance += MathPow (researchers [i].f - mean, 2); } } variance /= count; return MathSqrt (variance); } //————————————————————————————————————————————————————————————————————
A função "UpdateOmega" ajusta dinamicamente o parâmetro "omegaCurrent", que representa a parcela de outsiders ou a probabilidade de seleção de um outsider no comportamento do algoritmo. O objetivo dessa função é gerir de forma adaptativa a estratégia de diversificação/intensificação de acordo com o estado atual da população de pesquisadores, mais especificamente, de acordo com a dispersão desses pesquisadores no espaço de busca.
Antes de tudo, a função chama "ComputeStdDev ()" para determinar "currentSigma", o desvio padrão atual dos valores da função objetivo para os pesquisadores ativos. Um "currentSigma" alto indica grande diversidade de soluções, enquanto um valor baixo indica convergência.
Caso 1: Convergência da população (currentSigma < sigma0). Se o desvio padrão atual for menor que um limiar predefinido "sigma0", isso indica que os pesquisadores começam a convergir ou a se agrupar em torno de determinadas soluções. Nesse caso, o algoritmo passa para a etapa de aproveitamento (refinamento) das soluções encontradas. Para evitar a convergência prematura para um ótimo local e estimular a continuação da diversificação e a busca por soluções melhores, a parcela de outsiders (omegaCurrent) é aumentada. O incremento é calculado como (omegaMax - omegaMin) / 2.0 * epsilonPlus. Aqui, "omegaMax" e "omegaMin" definem os limites superior e inferior de "omegaCurrent", enquanto "epsilonPlus" é um coeficiente positivo que controla o ritmo de aumento. O objetivo é atribuir maior peso aos elementos que podem se desviar da tendência geral ou representar abordagens completamente novas.
Caso 2: Dispersão ou ausência de convergência da população (currentSigma >= sigma0). Se o desvio padrão for maior ou igual ao limiar "sigma0", isso indica que a população ainda está amplamente distribuída ou se encontra nos estágios iniciais da diversificação. Nesse caso, a parcela de outsiders (omegaCurrent) é reduzida. A redução é calculada como (omegaMax - omegaMin) / 2.0 * epsilonMinus, em que "epsilonMinus" é um coeficiente negativo que controla o ritmo de redução. Isso é feito para que o algoritmo não gaste recursos demais com diversificação aleatória quando a população já é suficientemente diversa, para que o algoritmo comece a focar em áreas mais promissoras.
Limitação do intervalo (omegaCurrent). Após a alteração de "omegaCurrent", a função mantém seu valor dentro do intervalo definido: se "omegaCurrent" ficar abaixo de "omegaMin", seu valor é ajustado para "omegaMin"; se "omegaCurrent" exceder "omegaMax", seu valor é ajustado para "omegaMax". Isso impede que o parâmetro saia de limites operacionais razoáveis.
De modo geral, a função "UpdateOmega" implementa uma estratégia adaptativa. Quando a população de pesquisadores mostra sinais de convergência rápida (baixo desvio padrão), o algoritmo aumenta a probabilidade de seleção de "outsiders" (ou elementos capazes de romper a estrutura atual), ajudando a evitar ótimos locais e estimulando uma nova busca ou a diversificação de um espaço mais amplo. Por outro lado, quando a população ainda está amplamente distribuída, o algoritmo reduz a ênfase nos outsiders para se concentrar em uma busca mais sistemática ou no aproveitamento de áreas promissoras já encontradas.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::UpdateOmega () { double currentSigma = ComputeStdDev (); if (currentSigma < sigma0) { // Увеличиваем долю аутсайдеров при сходимости omegaCurrent += (omegaMax - omegaMin) / 2.0 * epsilonPlus; } else { // Уменьшаем долю аутсайдеров omegaCurrent -= (omegaMax - omegaMin) / 2.0 * epsilonMinus; } // Ограничиваем диапазон if (omegaCurrent < omegaMin) omegaCurrent = omegaMin; if (omegaCurrent > omegaMax) omegaCurrent = omegaMax; } //————————————————————————————————————————————————————————————————————
A função "NormalizeProbabilities" é usada para transformar o array de valores numéricos "probs" de modo que eles representem uma distribuição de probabilidades válida. Ou seja, após a execução da função, a soma de todos os elementos do array "probs" será igual a um. A variável "sum" é inicializada com 0 e usada para acumular a soma de todos os elementos do array "probs". Inicia-se um ciclo que percorre todos os elementos desse array. Dentro do ciclo, cada valor "probs [i]" é adicionado à variável "sum".
Se o valor calculado de "sum" for positivo, inicia-se um segundo ciclo, que também percorre todos os elementos do array "probs". Dentro desse ciclo, cada elemento do array é dividido por "sum". Após essa divisão, cada valor "probs [i]" passa a ser a fração correspondente da soma total, e a soma de todos os elementos do array passa a ser igual a "1". Trata-se do procedimento padrão de normalização.
Se o valor de "sum" for igual a "0" ou negativo, embora isso geralmente não seja esperado para probabilidades, a função também trata esse caso. Isso significa que não há soma positiva pela qual normalizar os valores originais. Por exemplo, todas as probabilidades iniciais eram zero. Nesse caso, a função passa para uma "distribuição uniforme". O valor "val" é calculado como (1.0 / size). Isso significa que cada elemento do array receberá a mesma probabilidade, de modo que a soma dos elementos seja igual a "1". Inicia-se um terceiro ciclo, que percorre todos os elementos do array "probs". Dentro desse ciclo, cada elemento recebe o valor calculado "val". Assim, cada elemento do array passa a ser igual a (1 / size), e a soma dos elementos será igual a "1".
Essa função é um método utilitário geral para permitir que um conjunto de pesos ou probabilidades "brutas" seja usado como uma distribuição de probabilidades válida (em que "real" significa que a soma de todas as probabilidades é igual a 1). Isso é importante em muitos algoritmos, como métodos de seleção baseados em probabilidades, método da roleta ou método de Monte Carlo, nos quais a normalização correta evita erros e assegura um comportamento estatístico adequado.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::NormalizeProbabilities (double &probs []) { double sum = 0; int size = ArraySize (probs); for (int i = 0; i < size; i++) { sum += probs [i]; } if (sum > 0) { for (int i = 0; i < size; i++) { probs [i] /= sum; } } else { // Равномерное распределение double val = 1.0 / size; for (int i = 0; i < size; i++) { probs [i] = val; } } } //————————————————————————————————————————————————————————————————————
A função "CompactPopulation" gerencia o tamanho e a composição da população de pesquisadores no algoritmo. O objetivo principal é remover os pesquisadores menos eficientes e, se necessário, reduzir a população a um tamanho controlável, para manter a eficiência e o desempenho do algoritmo.
Contagem de pesquisadores "ativos". A variável "aliveCount" (quantidade de sobreviventes) é inicializada com "0". Em seguida, um ciclo percorre todos os pesquisadores da população atual (de 0 até actualPopSize - 1). Para cada pesquisador, verifica-se seu estado (researchers [i]. alive). Se o pesquisador estiver "vivo" (seu campo alive for verdadeiro), "aliveCount" aumenta em uma unidade.Condição para compactação/redução. Após a contagem dos pesquisadores vivos, a função verifica se é necessário executar a compactação. Isso ocorre se uma das duas condições for atendida: a quantidade de pesquisadores ativos "aliveCount" corresponde a menos de 75% do tamanho total atual da população "actualPopSize" ou o tamanho atual da população "actualPopSize" excede 200 (mesmo que a maioria deles esteja viva, a população é considerada grande demais e precisa ser reduzida).
Primeira fase da compactação (remoção dos "inativos"). Se uma das condições de compactação for atendida, a compactação é iniciada. Inicializa-se um novo índice com "0". Esse índice apontará para a próxima posição livre no início do array "researchers", para a qual os pesquisadores "ativos" serão movidos. Inicia-se um ciclo que percorre todos os pesquisadores (de 0 até actualPopSize - 1). Dentro do ciclo, se o pesquisador atual estiver "ativo", verifica-se se ele já está na posição correta. Caso não esteja, ele deve ser movido para a frente no array.
O pesquisador é copiado para a posição "newIdx". Normalmente, nesses casos, define-se (researchers [i]. alive = false) para marcar o pesquisador original como "removido" ou inativo, embora ele já tenha sido copiado. Trata-se de uma limpeza; "newIdx" é incrementado em uma unidade para apontar para a posição do próximo pesquisador ativo. Após a conclusão desse ciclo, todos os pesquisadores "vivos" estarão no início do array "researchers". O tamanho da população é atualizado para "aliveCount".
Segunda fase da compactação (redução de uma população grande). Após a primeira fase (em que os inativos foram removidos e os vivos deslocados), a função verifica se "actualPopSize" continua acima de 150. Essa é uma condição interna, ou seja, é executada somente se a população já tiver sido compactada ou tiver muitos pesquisadores inativos. Se "actualPopSize" for maior que 150, isso significa que, mesmo após a remoção dos inativos, a população ainda está grande demais e precisa de uma nova redução até o tamanho máximo permitido de 150. Para isso, é executada uma ordenação por "fitness". Depois disso, os pesquisadores com melhores valores de "fitness" ficarão no início do array.
Remoção dos "piores" pesquisadores. Todos os pesquisadores a partir do 150º elemento (isto é, aqueles que ficaram na "cauda" após a ordenação) são marcados como "inativos" (researchers [i]. alive = false). Seu parâmetro "m" também é zerado. Por fim, "actualPopSize" é definido como 150, truncando efetivamente a população para o tamanho máximo desejado. Essa função faz com que a população:- Não acumule indivíduos não utilizados, que podem ocupar memória e desacelerar o processamento.
- Não cresça de forma descontrolada, o que também pode afetar negativamente o desempenho e a eficiência, além de levar a uma estagnação prematura.
- Mantenha certo nível de qualidade, descartando os piores indivíduos quando o tamanho da população atinge um nível crítico.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::CompactPopulation () { // Подсчитываем живых исследователей int aliveCount = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) aliveCount++; } // Если слишком много мертвых, компактифицируем if (aliveCount < actualPopSize * 0.75 || actualPopSize > 200) { int newIdx = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) { if (i != newIdx) { // Копируем живого исследователя на новое место researchers [newIdx] = researchers [i]; researchers [i].alive = false; } newIdx++; } } actualPopSize = aliveCount; // Если популяция все еще слишком большая, ограничиваем if (actualPopSize > 150) { // Сортируем по fitness и оставляем лучших for (int i = 0; i < actualPopSize - 1; i++) { for (int j = i + 1; j < actualPopSize; j++) { if (researchers [i].f < researchers [j].f) { S_Researcher temp = researchers [i]; researchers [i] = researchers [j]; researchers [j] = temp; } } } // Убиваем худших for (int i = 150; i < actualPopSize; i++) { researchers [i].alive = false; researchers [i].m = 0; } actualPopSize = 150; } } } //————————————————————————————————————————————————————————————————————
O método "Revision" restante no algoritmo CoSO. Inicia-se um ciclo que percorre todos os indivíduos no array "a", do índice "0" até "aSize - 1". Dentro do ciclo, para cada indivíduo "a [i]", verifica-se a condição: "if (a [i]. f > fB)". Se o valor da função objetivo do indivíduo atual for maior que o melhor valor global atual, "fB" é atualizado para o novo melhor valor: "fB = a [i]. f". O índice desse melhor indivíduo é registrado.
Ao final do ciclo que percorreu todos os indivíduos no array "a", verifica-se a condição "if (bestIND != -1)". Essa condição é verdadeira se tiver sido encontrado pelo menos um indivíduo cuja função objetivo seja melhor que o valor anterior de "fB". Se um novo melhor indivíduo tiver sido encontrado (bestIND diferente de -1), é chamada a função "ArrayCopy", que copia os parâmetros "c" do melhor indivíduo encontrado para o array global "cB".
O principal objetivo desse método é manter atualizado o estado da melhor solução global encontrada pelo algoritmo até o momento. Em algoritmos evolutivos como o CoSO, o conceito de "melhor solução global" (global best) é monitorado e atualizado continuamente à medida que soluções melhores são encontradas. Esse "melhor global" passa então a ser usado para orientar a busca. Em essência, essa função implementa a etapa de "registro da melhor solução" em cada iteração do algoritmo.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::Revision () { int bestIND = -1; int aSize = ArraySize (a); for (int i = 0; i < aSize; i++) { if (a [i].f > fB) { fB = a [i].f; bestIND = i; } } if (bestIND != -1) { ArrayCopy (cB, a [bestIND].c, 0, 0, WHOLE_ARRAY); } } //————————————————————————————————————————————————————————————————————
Resultados dos testes
O algoritmo CoSO funciona razoavelmente bem, com resultados nada ruins; claro, ainda é possível fazer experimentos com os parâmetros, isso fica para quem tiver interesse. =============================
5 Hilly's; Func runs: 10000; result: 0.8047081198587067
25 Hilly's; Func runs: 10000; result: 0.5429326559833119
500 Hilly's; Func runs: 10000; result: 0.30916988715342353
=============================
5 Forest's; Func runs: 10000; result: 0.7383405771205314
25 Forest's; Func runs: 10000; result: 0.38224371519203115
500 Forest's; Func runs: 10000; result: 0.20600693936217676
=============================
5 Megacity's; Func runs: 10000; result: 0.553846153846154
25 Megacity's; Func runs: 10000; result: 0.2550769230769231
500 Megacity's; Func runs: 10000; result: 0.11129230769230862
=============================
All score: 3.90362 (43.37%)
É a primeira vez que encontro uma visualização tão incomum de um algoritmo; isso está relacionado à lógica de implementação em várias camadas.

CoSO na função de teste Hilly

CoSO na função de teste Forest

CoSO na função de teste Megacity
Com base nos resultados obtidos, o algoritmo CoSO é apresentado na tabela de classificação apenas para fins informativos. Gostaria de observar que nossa tabela está ficando mais apertada, e resultados abaixo de 45% já ficam fora dos limites da tabela.
| № | 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 |
| CoSO | community_of_scientist_optimization | 0,80471 | 0,54293 | 0,30917 | 1,65681 | 0,73834 | 0,38224 | 0,20600 | 1,32658 | 0,55384 | 0,25507 | 0,11129 | 0,92020 | 3,904 | 43,37 | |
| 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 CoSO apresenta resultados medianos nas funções de teste, atingindo 43% do desempenho máximo possível. É claro que eu esperava resultados mais impressionantes. O ambiente de testes oferece um conjunto ampliado de funções, incluindo funções padrão e amplamente conhecidas, e nele qualquer interessado pode fazer experimentos adicionais tanto na escolha de parâmetros quanto na de funções para explorar melhor o potencial do algoritmo.
A principal desvantagem da implementação atual é a alta complexidade computacional. A arquitetura multicamadas, com periódicos, distribuição dinâmica de recursos e gestão adaptativa da população, impõe uma carga significativa. O algoritmo é consideravelmente mais lento do que outros métodos populacionais, o que limita sua aplicabilidade em tarefas que exigem soluções rápidas.
No entanto, a base conceitual do CoSO apresenta grande interesse. A modelagem da comunidade científica introduz mecanismos únicos que foram aplicados: a população dinâmica adapta automaticamente os recursos computacionais à complexidade da tarefa, o sistema de periódicos viabiliza uma troca eficiente de informações sem perda das melhores soluções, o financiamento competitivo cria uma seleção natural sem regras rígidas e o mecanismo de contratação tenta resolver o dilema da busca local/global.
O potencial de melhoria é evidente. O CoSO não deve ser tratado como uma solução pronta, mas como uma plataforma de pesquisa promissora. O algoritmo abre uma nova direção na otimização evolutiva, em que os mecanismos sociais de comunidades humanas se tornam uma fonte de estratégias computacionais. Com o refinamento adequado, o CoSO pode encontrar seu nicho em tarefas em que a adaptabilidade e a robustez a mudanças sejam importantes, e quando o tempo de processamento não for crítico.

Figura 1. Gradação de cores dos algoritmos nos testes correspondentes

Figura 2. Histograma dos resultados dos testes dos algoritmos (em uma escala de 0 a 100, quanto maior, melhor, em que 100 é o resultado teórico máximo possível, no arquivo há um script para calcular a tabela de classificação)
Vantagens e desvantagens do algoritmo CoSO:
Vantagens:
- boa base para o desenvolvimento de novas versões derivadas.
Desvantagens:
- grande quantidade de parâmetros externos;
- tendência à estagnação em determinadas tarefas;
- lento.
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 diversificaçã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_CoSO.mq5 | Script | Ambiente de testes para o CoSO |
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/18935
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.
Caminhe em novos trilhos: Personalize indicadores no MQL5
Do iniciante ao especialista: criação de um EA animado para notícias em MQL5 (VI): estratégia de ordens pendentes para trading baseado em notícias
Está chegando o novo MetaTrader 5 e MQL5
Explorando Técnicas Avançadas de Aprendizado de Máquina na Estratégia de Rompimento da Caixa de Darvas
- 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