Introdução
Algoritmos de otimização por enxame frequentemente sofrem com problemas de convergência prematura, facilidade em ficar preso em ótimos locais e baixa precisão de convergência quando aplicados a problemas de grande escala. A aplicação de estratégias de mutação adequadas pode mitigar significativamente essas limitações.
Este artigo apresenta uma coleção de 13 estratégias de mutação comumente utilizadas na literatura, com implementações em MATLAB que podem ser aplicadas a qualquer algoritmo de otimização meta-heurística. Todas as estratégias serão demonstradas utilizando o algoritmo Harris Hawk Optimization (HHO) como algoritmo base.
Lista das 13 Estratégias de Mutação
- Mutação Gaussiana
- Mutação Gaussiana Elite
- Mutação de Cauchy
- Mutação de Cauchy com Distribuição Inversa Acumulada
- Mutação com Perturbação t-Distribuída
- Mutação com Perturbação t-Distribuída Adaptativa
- Mutação de Nuvem Normal
- Mutação Periódica
- Mutação Diferencial Elite DE/best/1
- Mutação Diferencial Aleatório-para-Elite DE/rand-to-best/1
- Mutação Diferencial Aleatória DE/rand/2
- Mutação Diferencial Elite DE/best/2
- Mutação Não-Uniforme
Implementação das Estratégias
1. Mutação Gaussiana
A mutação gaussiana adiciona ruído seguindo uma distribuição normal ao indivíduo selecionado, permitindo exploração controlada do espaço de busca.
function individuo = mutacao_gaussiana(individuo, dim, limite_inferior, limite_superior)
sigma = 0.1 * (limite_superior - limite_inferior);
ruido = sigma * randn(1, dim);
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
2. Mutação Gaussiana Elite
Esta versão utiliza o melhor indivíduo da população para guiar a mutação, combinando informação elitista com perturbação gaussiana.
function individuo = mutacao_gaussiana_elite(individuo, elite, dim, limite_inferior, limite_superior)
fator_elite = 0.5;
sigma = 0.15 * (limite_superior - limite_inferior);
ruido = sigma * randn(1, dim);
individuo = individuo + fator_elite * (elite - individuo) + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
3. Mutação de Cauchy
A distribuição de Cauchy possui caudas mais pesadas que a distribuição normal, permitindo saltos maiores no espaço de busca.
function individuo = mutacao_cauchy(individuo, dim, limite_inferior, limite_superior)
escala = 0.2 * (limite_superior - limite_inferior);
ruido = escala * tcauchy(1, dim);
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
function resultado = tcauchy(n, dim)
resultado = zeros(1, dim);
for i = 1:dim
resultado(i) = tan(pi * (rand() - 0.5));
end
end
4. Mutação de Cauchy Inversa Acumulada
Utiliza a função inversa da distribuição acumulada de Cauchy para gerar perturbações com características distintas.
function individuo = mutacao_cauchy_inversa(individuo, dim, limite_inferior, limite_superior)
escala = 0.25 * (limite_superior - limite_inferior);
ruido = escala * (tan(pi * rand(1, dim) - 0.5 * ones(1, dim)));
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
5. Mutação com Perturbação t-Distribuída
A distribuição t de Student oferece flexibilidade entre gaussian e cauchy, controlada pelo parâmetro graus de liberdade.
function individuo = mutacao_t_student(individuo, dim, limite_inferior, limite_superior)
graus_liberdade = 3;
escala = 0.2 * (limite_superior - limite_inferior);
ruido = escala * trnd(graus_liberdade, 1, dim);
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
6. Mutação com Perturbação t-Distribuída Adaptativa
Os graus de liberdade são ajustados dinamicamente durante a execução, permitindo transição de exploração para explotação.
function individuo = mutacao_t_adaptativa(individuo, iteracao, max_iteracao, dim, limite_inferior, limite_superior)
progress = iteracao / max_iteracao;
graus_liberdade = 1 + 10 * progress;
escala = 0.3 * (1 - progress) * (limite_superior - limite_inferior);
ruido = escala * trnd(graus_liberdade, 1, dim);
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
7. Mutação de Nuvem Normal3>
Utiliza o modelo de nuvem normal para gerar perturbações com incerteza linguística, combinandoexpectativa e entropia.
function individuo = mutacao_nuvem_normal(individuo, dim, limite_inferior, limite_superior)
entropia = 0.15 * (limite_superior - limite_inferior);
expectativa = randn(1, dim) * entropia;
super_entropia = abs(randn(1, dim));
hi = entropia / super_entropia;
ruido = hi .* randn(1, dim) + expectativa;
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
8. Mutação Periódica
Introduz periodicidade na mutação usando funções trigonométricas, criando padrões oscilatórios de exploração.
function individuo = mutacao_periodica(individuo, iteracao, dim, limite_inferior, limite_superior)
frequencia = 0.05;
amplitude = 0.2 * (limite_superior - limite_inferior);
fase = 2 * pi * iteracao * frequencia;
ruido = amplitude * sin(fase + rand(1, dim) * pi);
individuo = individuo + ruido;
individuo = max(min(individuo, limite_superior), limite_inferior);
end
9. Mutação Diferencial DE/best/1
Escolhe o melhor indivíduo e dois indivíduos aleatórios para criar vetor de mutação direcionado.
function vetor_mutante = mutacao_de_best1(populacao, indices, melhor_indice, dim)
i1 = indices(1);
i2 = indices(2);
F = 0.8;
vetor_mutante = populacao(melhor_indice, :) + F * (populacao(i1, :) - populacao(i2, :));
end
10. Mutação Diferencial DE/rand-to-best/1
Combina aleatoriedade com informação do melhor indivíduo, balanceando exploração e explotação.
function vetor_mutante = mutacao_de_rand_best1(populacao, indices, melhor_indice, dim)
i1 = indices(1);
i2 = indices(2);
F = 0.7;
lambda = 0.5;
vetor_mutante = populacao(i1, :) + lambda * (populacao(melhor_indice, :) - populacao(i1, :)) + F * (populacao(i2, :) - populacao(melhor_indice, :));
end
11. Mutação Diferencial DE/rand/2
Utiliza quatro indivíduos aleatórios, oferecendo maior diversidade mas menor convergência direcionada.
function vetor_mutante = mutacao_de_rand2(populacao, indices, dim)
i1 = indices(1);
i2 = indices(2);
i3 = indices(3);
i4 = indices(4);
F = 0.6;
vetor_mutante = populacao(i1, :) + F * (populacao(i2, :) - populacao(i3, :)) + F * (populacao(i4, :) - populacao(i2, :));
end
12. Mutação Diferencial DE/best/2
Usa o melhor indivíduo com dois pares de diferenças, oferecendo convergência mais agressiva.
function vetor_mutante = mutacao_de_best2(populacao, indices, melhor_indice, dim)
i1 = indices(1);
i2 = indices(2);
i3 = indices(3);
i4 = indices(4);
F = 0.5;
vetor_mutante = populacao(melhor_indice, :) + F * (populacao(i1, :) - populacao(i2, :) + populacao(i3, :) - populacao(i4, :));
end
13. Mutação Não-Uniforme
A magnitude da mutação diminui com o tempo, permitindo exploração global inicial e explotação local posterior.
function individuo = mutacao_nao_uniforme(individuo, iteracao, max_iteracao, dim, limite_inferior, limite_superior)
taxa_encolhimento = 0.5;
for j = 1:dim
if rand() < 0.1
delta = (limite_superior(j) - limite_inferior(j)) * (1 - rand() ^ (1 - iteracao / max_iteracao) ^ taxa_encolhimento);
direcao = sign(rand() - 0.5);
individuo(j) = individuo(j) + direcao * delta;
end
end
individuo = max(min(individuo, limite_superior), limite_inferior);
end
Exemplo de Aplicação com HHO
A seguir, apresentamos um exemplo simplificado de como aplicar as estratégias de mutação ao algoritmo Harris Hawk Optimization:
function [melhor_solucao, melhor_fitness] = hho_com_mutacao(fobj, dim, lim_inf, lim_sup, populacao_tamanho, iteracoes_max, tipo_mutacao)
% Inicialização da população
populacao = lim_inf + (lim_sup - lim_inf) * rand(populacao_tamanho, dim);
fitness = zeros(populacao_tamanho, 1);
for i = 1:populacao_tamanho
fitness(i) = fobj(populacao(i, :));
end
[melhor_fitness, indice_melhor] = min(fitness);
melhor_solucao = populacao(indice_melhor, :);
for iter = 1:iteracoes_max
energia_exploracao = 2 * (1 - iter / iteracoes_max);
for i = 1:populacao_tamanho
for j = 1:dim
r1 = rand();
r2 = rand();
r3 = rand();
if energia_exploracao >= 1
X_aleatorio = populacao(floor(rand() * populacao_tamanho) + 1, :);
diferenca = abs(2 * r2 - X_aleatorio(j));
populacao(i, j) = X_aleatorio(j) - diferenca * energia_exploracao;
else
if r3 >= 0.5
populacao(i, j) = melhor_solucao(j) - energia_exploracao * abs(r1 * melhor_solucao(j) - populacao(i, j));
else
populacao(i, j) = melhor_solucao(j) - energia_exploracao * abs(r1 * melhor_solucao(j) - populacao(i, j));
end
end
end
% Aplicar estratégia de mutação selecionada
populacao(i, :) = aplicar_mutacao(populacao(i, :), melhor_solucao, iter, iteracoes_max, dim, lim_inf, lim_sup, tipo_mutacao);
fitness_atual = fobj(populacao(i, :));
if fitness_atual < fitness(i)
fitness(i) = fitness_atual;
if fitness_atual < melhor_fitness
melhor_fitness = fitness_atual;
melhor_solucao = populacao(i, :);
end
end
end
end
end
function individuo = aplicar_mutacao(individuo, elite, iter, max_iter, dim, lim_inf, lim_sup, tipo)
switch tipo
case 1
individuo = mutacao_gaussiana(individuo, dim, lim_inf, lim_sup);
case 2
individuo = mutacao_gaussiana_elite(individuo, elite, dim, lim_inf, lim_sup);
case 3
individuo = mutacao_cauchy(individuo, dim, lim_inf, lim_sup);
case 4
individuo = mutacao_cauchy_inversa(individuo, dim, lim_inf, lim_sup);
case 5
individuo = mutacao_t_student(individuo, dim, lim_inf, lim_sup);
case 6
individuo = mutacao_t_adaptativa(individuo, iter, max_iter, dim, lim_inf, lim_sup);
case 7
individuo = mutacao_nuvem_normal(individuo, dim, lim_inf, lim_sup);
case 8
individuo = mutacao_periodica(individuo, iter, dim, lim_inf, lim_sup);
case 9
indices = randperm(dim, 2);
individuo = mutacao_de_best1([individuo; elite], indices, 2, dim);
case 10
indices = randperm(dim, 2);
individuo = mutacao_de_rand_best1([individuo; elite], indices, 2, dim);
case 11
indices = randperm(dim, 4);
individuo = mutacao_de_rand2([individuo; elite; elite; elite], indices, dim);
case 12
indices = randperm(dim, 4);
individuo = mutacao_de_best2([individuo; elite; elite; elite], indices, 2, dim);
case 13
individuo = mutacao_nao_uniforme(individuo, iter, max_iter, dim, lim_inf, lim_sup);
end
end
Configurações de Teste
Para validação experimental, utilize os seguintes parâmetros:
- Número máximo de iterações: 500
- Tamanho da população: 50
- Funções de teste: conjunto CEC2017
- Número de execuções: 2 por algoritmo
Conclusão
As treze estratégias de mutação apresentadas oferecem diferentes mecanismos para melhorar o desempenho de algoritmos de otimização. A escolha da estratégia adequada depende das características específicas do problema, como a presença de múltiplos ótimos locais, a dimensionalidade do espaço de busca e os requisitos de precisão. Recomenda-se realizar experimentos comparativos para identificar a estratégia mais eficiente para cada aplicação específica.