From: Rafał Długołęcki Date: Sun, 29 Mar 2015 19:44:41 +0000 (+0200) Subject: Added classes: Algorithm, Crossover, Mutation. Fixed Roulette. X-Git-Url: https://git.dlugolecki.net.pl/?p=genetic.git;a=commitdiff_plain;h=76e7a40f8acad0645dd755a55f6321760a41e1a6 Added classes: Algorithm, Crossover, Mutation. Fixed Roulette. --- diff --git a/src/algorithm.h b/src/algorithm.h new file mode 100644 index 0000000..c12dfce --- /dev/null +++ b/src/algorithm.h @@ -0,0 +1,122 @@ +#ifndef __ALGORITHM_H +#define __ALGORITHM_H + +#include + +#include "chromosome.h" +#include "generation.h" +#include "fitness/fitness.h" +#include "generator/generation.h" +#include "selection/selection.h" +#include "crossover/crossover.h" +#include "mutation/mutation.h" + +using namespace std; + +namespace genetic { + /** + * Genetic Algorithm itself + */ + template < typename _Chromosome, typename _Selection, typename _Crossover, typename _Mutation > + class Algorithm { + public: + typedef typename _Selection::FitnessValueType FitnessValueType; + protected: + /** + * Generator which draws initial population + */ + generator::Generation<_Chromosome>& generator; + + /** + * Fitness function used in selection + */ + Fitness<_Chromosome, FitnessValueType>& fitness; + + /** + * Crossover function + */ + _Crossover crossover; + + /** + * Mutation function + */ + _Mutation mutation; + + /** + * Current population + */ + Generation<_Chromosome> generation; + + const int numberOfGenerations = 100; + public: + Algorithm( + generator::Generation<_Chromosome>& _generator, + Fitness<_Chromosome, FitnessValueType>& _fitness, + double crossoverChance, + double mutationChance) : + generator(_generator), + fitness(_fitness), + crossover(crossoverChance), + mutation(mutationChance) { + + this->generation = this->generator.breed(); + } + + void searchForResult() { + cout << "generation avg best" << endl; + for(int i = 0; i < this->numberOfGenerations; i++) { + cout << i; + _Selection selection(this->generation, fitness); +// cout << "[+] Algorithm::Selection.draw()\n"; + this->generation = selection.draw(); +// cout << "[+] Crossover\n"; + this->generation = crossover.cross(this->generation); +// cout << "[+] Mutate\n"; + this->generation = mutation.mutate(this->generation); + +// cout << "New Generation:\n"; +// this->showGeneration(); + this->showAvgFitness(); + this->showBestFitness(); + } + } + + void showGeneration() { + for (unsigned int i = 0; i < this->generation.get().size(); i++) { + cout << "# " << i << ") "; + for (unsigned int j = 0; j < this->generation.get()[i].get().size(); j++) { + cout << this->generation.get()[i].get()[j].get(); + } + cout << "\n"; + } + } + + void showAvgFitness() { + double avg = 0; +// cout << "Fitness:\n"; + for (unsigned int i = 0; i < this->generation.get().size(); i++) { +// cout << "# " << i << ") "; + WSTI<_Chromosome, FitnessValueType> fit(this->generation.get()[i], 0.5, 2.5); +// cout << fit.calculate() << "\n"; + avg += fit.calculate(); + } + cout << " " << avg / this->generation.get().size(); + } + + void showBestFitness() { + double best = -100000; + for (unsigned int i = 0; i < this->generation.get().size(); i++) { +// cout << "# " << i << ") "; + WSTI<_Chromosome, FitnessValueType> fit(this->generation.get()[i], 0.5, 2.5); +// cout << fit.calculate() << "\n"; + double tmp = fit.calculate(); + if (tmp > best) { + best = tmp; + } + } + cout << " " << best << endl; + } + }; +} + +#endif /* __ALGORITHM_H */ diff --git a/src/crossover/crossover.h b/src/crossover/crossover.h new file mode 100644 index 0000000..f494b7b --- /dev/null +++ b/src/crossover/crossover.h @@ -0,0 +1,94 @@ +#ifndef __CROSSOVER_CROSSOVER_H +#define __CROSSOVER_CROSSOVER_H + +#include "chromosome.h" +#include "generation.h" + +using namespace std; + +namespace genetic { +// namespace crossover { + template < typename _Chromosome > + class Crossover { + public: + typedef double CrossoverChanceType; + typedef typename _Chromosome::GeneType GeneType; + protected: + CrossoverChanceType chance; + + _Chromosome do_cross(_Chromosome first, _Chromosome second, unsigned int splitPlace) { + const unsigned int chromosomeSize = first.get().size(); + +// cout << " "; +// for (unsigned int i = 0; i < chromosomeSize; i++) { +// cout << first.get()[i].get(); +// } +// cout << "\n x "; +// for (unsigned int i = 0; i < chromosomeSize; i++) { +// cout << second.get()[i].get(); +// } +// cout << "\n--------"; +// for (unsigned int i = 0; i < chromosomeSize; i++) { +// if (i == splitPlace) { +// cout << "^"; +// } +// else { +// cout << "-"; +// } +// } + + vector crossedChromosome; + for (unsigned int i = 0; i < chromosomeSize; i++) { + if (i < splitPlace) { + crossedChromosome.push_back(first.get()[i].get()); + } + else { + crossedChromosome.push_back(second.get()[i].get()); + } + } + +// cout << "\n "; +// for (unsigned int i = 0; i < chromosomeSize; i++) { +// cout << crossedChromosome[i].get(); +// } +// cout << "\n"; + + return _Chromosome(crossedChromosome); + } + + public: + Crossover(CrossoverChanceType chance) : + chance(chance) { + } + + Generation<_Chromosome> cross(Generation<_Chromosome> _generation) { + const unsigned int generationSize = _generation.get().size(); + vector<_Chromosome> newGeneration; + + for (unsigned int i = 0; i < generationSize; i++) { + CrossoverChanceType random = (rand() + 1 % 10000) / 10000.0; + _Chromosome chromosome = _generation.get()[i]; + if (random < this->chance) { + const unsigned int chromosomeSize = chromosome.get().size(); + const unsigned int splitPlace = rand() % chromosomeSize; + unsigned int pairedChromosome = 0; + + /** + * Search for different Chromosome, and crossover them together + */ + do { + pairedChromosome = rand() % generationSize; + } while(pairedChromosome == i); + + chromosome = do_cross(chromosome, _generation.get()[pairedChromosome], splitPlace); + } + newGeneration.push_back(chromosome); + } + + return Generation<_Chromosome>(newGeneration); + } + }; +// } +} + +#endif /* __CROSSOVER_CROSSOVER_H */ diff --git a/src/fitness/wsti.h b/src/fitness/wsti.h index fa303b0..eaa0538 100644 --- a/src/fitness/wsti.h +++ b/src/fitness/wsti.h @@ -26,6 +26,7 @@ namespace genetic { _fenotype = _fenotype + this->chromosome.get()[i].get() * ratio; ratio = ratio * 2; } +// cout << "Fenotyp: " << _fenotype << "\n"; return _fenotype; } diff --git a/src/main.cpp b/src/main.cpp index 9388101..920e3f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,9 +7,12 @@ #include "generator/generation.h" #include "selection/roulette.h" - +#include "crossover/crossover.h" +#include "mutation/mutation.h" #include "fitness/wsti.h" +#include "algorithm.h" + using namespace std; using namespace genetic; @@ -17,33 +20,26 @@ int main() { typedef Gene _Gene; typedef Chromosome<_Gene> _Chromosome; + typedef WSTI<_Chromosome> _Fitness; + typedef Roulette<_Chromosome> _Selection; + typedef Crossover<_Chromosome> _Crossover; + typedef Mutation<_Chromosome> _Mutation; + + typedef generator::Generation<_Chromosome> _Generator; + typedef Algorithm<_Chromosome, _Selection, _Crossover, _Mutation> _Algorithm; + const int chromosomeSize = 11; - const int generationSize = 20; - WSTI<_Chromosome> fitness(0.5, 2.5); - - generator::Generation<_Chromosome> generationGenerator(generationSize, chromosomeSize); - Generation<_Chromosome> generation = generationGenerator.breed(); - - cout << "Generation:\n"; - for (unsigned int i = 0; i < generation.get().size(); i++) { - cout << "# "; - for (unsigned int j = 0; j < generation.get()[i].get().size(); j++) { - cout << generation.get()[i].get()[j].get(); - } - cout << "\n"; - } - - Roulette<_Chromosome> roulette(generation, fitness); - Generation<_Chromosome> newGeneration = roulette.draw(); - - cout << "New Generation:\n"; - for (unsigned int i = 0; i < newGeneration.get().size(); i++) { - cout << "# "; - for (unsigned int j = 0; j < newGeneration.get()[i].get().size(); j++) { - cout << newGeneration.get()[i].get()[j].get(); - } - cout << "\n"; - } + const int generationSize = 30; + const double crossoverChance = 0.75; + const double mutationChance = 0.01; +// const int numberOfGenerations = 100; + + _Fitness fitness(0.5, 2.5); + _Generator generationGenerator(generationSize, chromosomeSize); + + _Algorithm algorithm(generationGenerator, fitness, crossoverChance, mutationChance); + + algorithm.searchForResult(); return 0; } diff --git a/src/mutation/mutation.h b/src/mutation/mutation.h new file mode 100644 index 0000000..014ca70 --- /dev/null +++ b/src/mutation/mutation.h @@ -0,0 +1,47 @@ +#ifndef __MUTATION_MUTATION_H +#define __MUTATION_MUTATION_H + +#include + +#include "chromosome.h" +#include "generation.h" + +using namespace std; + +namespace genetic { +// namespace crossover { + template < typename _Chromosome> + class Mutation { + public: + typedef double MutationChanceType; + protected: + MutationChanceType chance; + + public: + Mutation(MutationChanceType chance) : + chance(chance) { + } + + Generation<_Chromosome> mutate(Generation<_Chromosome> _generation) { + const unsigned int generationSize = _generation.get().size(); + const unsigned int chromosomeSize = _generation.get()[0].get().size(); + vector<_Chromosome> newGeneration; + + for (unsigned int i = 0; i < generationSize; i++) { + MutationChanceType random = (rand() % 10000) / 10000.0; +// cout << " Mutation chance: " << chance << ", random: " << random << "\n"; + newGeneration.push_back(_generation.get()[i]); + + if (random < this->chance) { +// cout << " > Mutated!\n"; + unsigned int which = (rand() % chromosomeSize); + newGeneration[i].get()[which] = !newGeneration[i].get()[which].get(); + } + } + return Generation<_Chromosome>(newGeneration); + } + }; +// } +} + +#endif /* __MUTATION_MUTATION_H */ diff --git a/src/selection/roulette.h b/src/selection/roulette.h index 93f1514..a4f1fd2 100644 --- a/src/selection/roulette.h +++ b/src/selection/roulette.h @@ -31,14 +31,16 @@ namespace genetic { return generationFitness; } - map normalizeFitness( - vector generationFitness) { + multimap normalizeFitness( + vector generationFitness, + unsigned int chromosomeSize) { FitnessValueType min; FitnessValueType max; FitnessValueType offset; - map normalizedFitness; + multimap normalizedFitness; min = max = generationFitness[0]; + offset = 0; for (unsigned int i = 0; i < generationFitness.size(); i++) { if(generationFitness[i] < min) { @@ -50,10 +52,10 @@ namespace genetic { } } - offset = (max - min) / (generationFitness.size() - 1) - min; + offset = (max - min) / (chromosomeSize - 1) - min; for (unsigned int i = 0; i < generationFitness.size(); i++) { - normalizedFitness[generationFitness[i] + offset] = this->generation.get()[i]; + normalizedFitness.insert(std::make_pair(generationFitness[i] + offset, this->generation.get()[i])); } return normalizedFitness; @@ -63,15 +65,21 @@ namespace genetic { * Spins the Roulette */ Generation<_Chromosome> spinRoulette( - map normalizedFitness) { + multimap normalizedFitness) { - typedef typename std::map::iterator FitnessIterator; + typedef typename std::multimap::iterator FitnessIterator; vector<_Chromosome> selected; - map probabilities; + multimap probabilities; unsigned int size = this->generation.get().size(); - double random = 0; + const unsigned int power2N = 1 << this->generation.get()[0].get().size(); + + /** Random value used to draw chromosome */ + FitnessValueType random = 0; + + /** Position on the roulette wheele */ + FitnessValueType position = 0; FitnessValueType fitnessSum = 0; @@ -82,24 +90,32 @@ namespace genetic { // Calculate probabilities for fitnesses for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) { - probabilities[it->first / fitnessSum] = it->second; + position += (it->first / fitnessSum * power2N); + probabilities.insert(std::make_pair(position, it->second)); } /* * Spin the Roulette until we draw as many chromosomes as in the * original generation. */ - while (size) { + while (size > 0) { bool found = false; - random = (rand() % 10000) / 100000.0; + random = (rand() % power2N); for (FitnessIterator it = probabilities.begin(); it != probabilities.end(); it++) { - if (it->first > random) { + if (random < it->first) { found = true; selected.push_back(it->second); break; } + // When NaN occur: + else if (it->first != it->first) { + selected.push_back(probabilities.begin()->second); + found = true; + break; + } } + if (found) { size--; } @@ -111,10 +127,11 @@ namespace genetic { * Draws random */ Generation<_Chromosome> do_draw() { - map normalizedFitness; + multimap normalizedFitness; normalizedFitness = this->normalizeFitness( - this->calculateGenerationFitness(this->generation) + this->calculateGenerationFitness(this->generation), + this->generation.get()[0].get().size() ); return spinRoulette(normalizedFitness); @@ -125,9 +142,6 @@ namespace genetic { Selection<_Chromosome>(_generation, _fitness) { this->generation = _generation; this->fitness = _fitness; - - time_t t; - srand((unsigned)time(&t)); } }; // }