Механизм выбора генетического алгоритма

Я построил генетический алгоритм, но я чувствую, что что-то не так в части выбора / мутации моего кода. Это та часть кода, о которой я говорю:

#include "stdafx.h"#include <iostream>
#include <vector>
#include <random>
#include <string>
#include <iomanip>
#include <math.h>

// The random number generator I am using.
std::random_device rd;
std::mt19937 rng(rd());

for (int k = 1; k < population_size; k++)                       // Loop until new population is filled up. K = 1 because first individual has the best genes from last generation.
{
// Calculate total fitness.

double totalfitness = 0;

for (int i = 0; i < population_size; i++)
{
totalfitness += individuals[i].fitness;
}

// Calculate  relative fitness.

for (int i = 0; i < population_size; i++)
{
individuals[i].probability = individuals[i].fitness / totalfitness;
}

std::uniform_real_distribution<double> dist2(0.0, 1.0);     // Initiate random number generator to generate a double between 0 and 1.

double rndNumber = dist2(rng);                              // Generate first double
double rndNumber2 = dist2(rng);                             // Generate second double
double offset = 0.0;                                        // Set offset (starting point from which it'll add up probabilities) at 0.
int father = 0;                                             // father is the individual that is picked, initialize at 0.
int mother = 0;

// Pick first parent. Once picked, set the fitness for that individual at 0 so that it can not be picked again.

for (int i = 0; i < population_size; i++)
{
offset += individuals[i].probability;
if (rndNumber < offset)
{
father = i;
individuals[i].fitness = 0.0;
break;
}
}

offset = 0.0;       // Reset offset to zero because we'll start again for the second parent.
totalfitness = 0;   // Recalculate total fitness using only the remaining individuals and reset total fitness to 0

// Here we recalculate total fitness using only the fitness of the individuals remaining.

for (int i = 0; i < population_size; i++)
{
totalfitness += individuals[i].fitness;
}

// Then we recalculate probability for the individuals based on the new totalfitness.

for (int i = 0; i < population_size; i++)
{
individuals[i].probability = individuals[i].fitness / totalfitness;
}

// Then we give back the old fitness to the father/mother

individuals[father].fitness = 1 / (individuals[father].evaluation*individuals[father].evaluation);

// Then pick parent 2.

for (int i = 0; i < population_size; i++)
{
offset += individuals[i].probability;
if (rndNumber2 < offset)
{
mother = i;
break;
}
}

// Having picked father and mother, now the idea is to run a random number generator between 0 and 1 for each gene.
// So if:   father  {5, 8, 9, 3}
//          mother  {1, 5, 2, 6)
//          rndnum  {0, 0, 1, 1}
// then     child   {5, 8, 2, 6}

std::uniform_int_distribution<int> gene_selection(0, 1);        // Initiate random number generator to generate an integer between 0 and 1.

for (int i = 0; i < number_of_variables; i++)
{
int gene1 = gene_selection(rng);
if (gene1 == 0)
{
new_individuals[k].chromosomes[0].push_back(individuals[father].chromosomes[0].at(i));
}
else if (gene1 == 1)
{
new_individuals[k].chromosomes[0].push_back(individuals[mother].chromosomes[0].at(i));
}
}

for (int j = 0; j < number_of_variables; j++)
{
for (int l = 0; l < 32; l++)
{
std::uniform_int_distribution<int> mutation(0, 50);
int mutation_outcome = mutation(rng);
if (mutation_outcome == 1)
{
new_individuals[k].chromosomes[0].at(j) ^= (1 << l);
if (new_individuals[k].chromosomes[0].at(j) == 0)
{
int new_var = uni(rng);
new_individuals[k].chromosomes[0].at(j) = new_var;
}
}
}
}
}

// When all new individuals have values, give individuals values of new_individuals and start next round of evaluation.

for (int i = 0; i < population_size; i++)
{
individuals[i] = new_individuals[i];
}

Мой код в основном работает нормально. Похоже, я не могу понять, почему он работает хуже. Первые несколько поколений, кажется, находят новые, лучшие решения довольно часто. Через несколько поколений он перестает находить новые лучшие решения.

Конечно, это может быть из-за того, что лучшего решения не существует, но я также делаю вычисления в Excel одновременно, и человек часто может получить лучшую физическую форму, просто увеличив одну из своих «хромосом» на 1, что обычно изменение на 1 бит, и так как я обычно запускаю этот код с 10000 индивидами, вы бы сказали, что программа обязательно создаст индивида с этой мутацией.

Я много раз перебирал свой код с помощью отладчика, отображая значения на каждом этапе пути и т. Д., Но я не могу понять, где он идет не так, поэтому я решил опубликовать свой код здесь и посмотрим, сможет ли кто-нибудь определить, где я облажался.

Просто для записи, алгоритм просто решатель формул. Таким образом, я могу, например, ввести a = 1, b = 6, target = 50, a * gene1 + b * gene2, и это (теоретически) назначит более высокую пригодность, чем ближе человек будет к получению этого результата.

Кроме того, если бы мне пришлось угадывать, где я все испортил, я бы сказал, что это часть мутации кода:

for (int j = 0; j < number_of_variables; j++)
{
for (int l = 0; l < 32; l++)
{
std::uniform_int_distribution<int> mutation(0, 50);
int mutation_outcome = mutation(rng);
if (mutation_outcome == 1)
{
new_individuals[k].chromosomes[0].at(j) ^= (1 << l);
if (new_individuals[k].chromosomes[0].at(j) == 0)
{
int new_var = uni(rng);
new_individuals[k].chromosomes[0].at(j) = new_var;
}
}
}
}

Я говорю это просто потому, что это та часть, которую я меньше всего понимаю, и я могу себе представить, что я допустил там «невидимую» ошибку.

Во всяком случае, любая помощь будет высоко ценится.

1

Решение

Ну, это просто способ сделать ваш код лучше и эффективнее. Ты используешь std::uniform_int_distribution без посева и почти с 5 последовательными вызовами, может быть поэтомуour random number is not really random after all,

Один простой способ to get things better, было бы seeding the random engine with timeтаким образом, предоставляя лучшее создание случайных чисел в долгосрочной перспективе (10000 человек, как-то больших!).

Вот ссылка на сайт для лучшего объяснения этого и простого фрагмента кода для проверки, является следующее:

#include <iostream>
#include <random>

std::default_random_engine generator((unsigned int)time(0));
int random(int n) {
std::uniform_int_distribution<int> distribution(0, n);
return distribution(generator);
}
int main() {
for(int i = 0; i < 15; ++i)
std::cout << random(5) << " " << random(5)<< std::endl;
return 0;
}

Надеюсь, что это поможет! Ура,

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]