1 #ifndef __SELECTION_ROULETTE_H
2 #define __SELECTION_ROULETTE_H
5 #include <utility> // std::pair
8 #include "chromosome.h"
12 // namespace selection {
14 * Selection class Roulette.
15 * Applies Selection on given Generation using Roulette method.
17 template < typename _Chromosome >
18 class RouletteSelection : public Selection<_Chromosome> {
21 * Parent Selection class
23 typedef Selection<_Chromosome> BaseType;
26 * Value type returned by the Fitness function
28 typedef typename BaseType::FitnessValueType FitnessValueType;
31 * Method used for calculating fitness of each Chromosome in
34 * @param generation Generation for which fitness will be calculated
35 * @return vector containing fitness value of each Chromosome in
36 * Generation. Values are set in the same order as they are in
39 std::vector<FitnessValueType> calculateGenerationFitness(
40 const Generation<_Chromosome>& generation) {
41 std::vector<FitnessValueType> generationFitness;
42 const unsigned int generationSize = generation.size();
44 for (unsigned int i = 0; i < generationSize; i++) {
45 generationFitness.push_back(this->checkChromosomeFitness(generation[i]));
48 return generationFitness;
52 * Normalizes calculated fitness values of the generation.
54 * @param generationFitness fitness values of the generation
55 * @param chromosomeSize number of Gene's in the Chromosome.
57 * @return multimap containing normalized Fitness as a key and its
58 * Chromosome as the value
60 std::multimap<FitnessValueType, _Chromosome> normalizeFitness(
61 const std::vector<FitnessValueType>& generationFitness,
62 unsigned int chromosomeSize) {
65 FitnessValueType offset;
67 const unsigned int fitnessSize = generationFitness.size();
69 /* we use multimap because it stores multiple values with the
72 std::multimap<FitnessValueType, _Chromosome> normalizedFitness;
74 min = max = generationFitness[0];
77 for (unsigned int i = 0; i < fitnessSize; i++) {
78 if(generationFitness[i] < min) {
79 min = generationFitness[i];
82 if(generationFitness[i] > max) {
83 max = generationFitness[i];
87 offset = (max - min) / (chromosomeSize - 1) - min;
89 for (unsigned int i = 0; i < fitnessSize; i++) {
90 normalizedFitness.insert(std::make_pair(generationFitness[i] + offset, this->generation[i]));
93 return normalizedFitness;
99 * @param normalizedFitness multimap containing normalized Fitness
100 * as a key and its Chromosome as the value
101 * @return new Generation of Chromosome's that passed the Selection
103 Generation<_Chromosome> spinRoulette(
104 const std::multimap<FitnessValueType, _Chromosome>& normalizedFitness) {
106 typedef typename std::multimap<FitnessValueType, _Chromosome>::iterator FitnessIterator;
108 std::vector<_Chromosome> selected;
109 std::multimap<FitnessValueType, _Chromosome> probabilities;
111 unsigned int size = this->generation.size();
112 const unsigned int power2N = 1 << this->generation[0].size();
114 /** Random value used to draw chromosome */
115 FitnessValueType random = 0;
117 /** Position on the roulette wheele */
118 FitnessValueType position = 0;
120 FitnessValueType fitnessSum = 0;
122 // Calculate sum of normalized fitnesses, in order to calculate probabilities
123 for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) {
124 fitnessSum += it->first;
127 // Calculate probabilities for fitnesses
128 for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) {
129 position += (it->first / fitnessSum * power2N);
130 probabilities.insert(std::make_pair(position, it->second));
134 * Spin the Roulette until we draw as many chromosomes as in the
135 * original generation.
139 random = (rand() % power2N);
141 for (FitnessIterator it = probabilities.begin(); it != probabilities.end(); it++) {
142 if (random < it->first) {
144 selected.push_back(it->second);
147 // When NaN occur, just get first Chromosome
148 else if (it->first != it->first) {
149 selected.push_back(probabilities.begin()->second);
159 return Generation<_Chromosome>(selected);
163 * Draws new Generation using Roulette method
165 * @return new Generation of Chromosome's that passed the Selection
167 Generation<_Chromosome> do_draw() {
168 std::multimap<FitnessValueType, _Chromosome> normalizedFitness;
170 normalizedFitness = this->normalizeFitness(
171 this->calculateGenerationFitness(this->generation),
172 this->generation[0].size()
175 return spinRoulette(normalizedFitness);
180 * Class constructor. Initializes class with values.
182 * @param _generation Generation that will be checked against this
184 * @param _fitness Fitness method to calculate fitness of Chromosomes
186 RouletteSelection(const Generation<_Chromosome>& _generation, genetic::Fitness<_Chromosome>& _fitness) :
187 Selection<_Chromosome>(_generation, _fitness) {
193 #endif /* __SELECTION_ROULETTE_H */