You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.9 KiB

#pragma once
#include "search_function.h"
class genetic_algorithm : public search_function {
public:
genetic_algorithm(function f) : search_function(f) {};
double search(int permutations, int dimensionality) {
elitism = elitism_rate * number_of_solutions;
// Set up random start population
std::vector<std::vector<double>> population;
for (int p = 0; p < number_of_solutions; p++) {
std::vector<double> tmp;
for (int i = 0; i < dimensionality; i++){
tmp.push_back(fmod(randomMT(), (func.upper_bound * 2)) + func.lower_bound);
}
population.push_back(tmp);
}
for (int i = 0; i < max_iterations; i++){
// Setup the random new population
std::vector<std::vector<double>> new_population;
for (int p = 0; p < number_of_solutions; p++) {
std::vector<double> tmp;
for (int i = 0; i < dimensionality; i++){
tmp.push_back(fmod(randomMT(), (func.upper_bound * 2)) + func.lower_bound);
}
new_population.push_back(tmp);
}
for (int s = 0; s < number_of_solutions; s += 2){
auto p1p2 = select(&population);
crossover(&std::get<0>(p1p2), &std::get<1>(p1p2));
mutate(&std::get<0>(p1p2));
mutate(&std::get<1>(p1p2));
}
reduce(&population, &new_population);
for (auto q: population){
double val = func.compute(q);
if (val < best_fitness)
best_fitness = val;
}
}
return best_fitness;
};
private:
double crossover_rate = 0.90;
double elitism_rate = 0.2;
int elitism = 10;
double mutation_rate = 0.008;
double mutation_range = 0.1;
double muration_precision = 3.5;
double best_fitness = 99999999999999999;
int number_of_solutions = 50;
int max_iterations = 100;
double get_fitness(std::vector<std::vector<double>> *population){
double fitness_sum = 0;
for (auto p: *population){
double fitness = func.compute(p);
if (fitness >= 0)
fitness_sum += 1 / (1 + fitness);
else
fitness_sum += 1 + abs(fitness);
}
return fitness_sum;
}
int select_parent(std::vector<std::vector<double>> *population){
double r = fmod(randomMT(), total_fitness(population));
int s = 0;
while (s < population->size()-1 && (r - func.compute(population->at(s)) > 0)) {
r -= func.compute(population->at(s++));
}
return s;
}
std::tuple<std::vector<double>, std::vector<double>> select(std::vector<std::vector<double>> *population){
auto p1 = population->at(select_parent(population));
auto p2 = population->at(select_parent(population));
return std::make_tuple(p1, p2);
};
void mutate(std::vector<double> *solution){
for (auto i: *solution){
if ((randomMT() * 1.0 / UINT32_MAX) < mutation_rate){
i += ((randomMT() * 1.0 / UINT32_MAX) * 2 - 1) * (func.upper_bound - func.lower_bound) *
mutation_range * pow(2, (-1 * (randomMT() * 1.0 / UINT32_MAX) * muration_precision));
}
}
}
void crossover(std::vector<double> *parent1, std::vector<double> *parent2){
if ((randomMT() * 1.0 / UINT32_MAX) < crossover_rate){
int d = randomMT() % (parent1->size() - 1) + 1;
int dim = parent1->size();
std::vector<double> temp;
temp.insert(temp.begin(), parent1->begin(), parent1->begin() + d);
parent1->erase(parent1->begin(), parent1->begin() + d);
parent1->insert(parent1->end(), parent2->begin() + dim - d, parent2->end());
parent2->erase(parent2->begin() + dim - d, parent2->end());
parent2->insert(parent2->end(), temp.begin(), temp.end());
}
}
void reduce(std::vector<std::vector<double>> *population, std::vector<std::vector<double>> *new_population){
std::sort(population->begin(), population->end(), [this](std::vector<double> a, std::vector<double> b){
return this->func.compute(a) < this->func.compute(b);
});
std::sort(new_population->begin(), new_population->end(), [this](std::vector<double> a, std::vector<double> b){
return this->func.compute(a) < this->func.compute(b);
});
for (int s = 0; s < elitism; s++) {
new_population->at(elitism + 1 - s) = population->at(s);
}
*population = *new_population;
}
double total_fitness(std::vector<std::vector<double>> *population){
double val = 0;
for (auto i: *population)
val += func.compute(i);
return val;
}
};