1 #ifndef __SELECTION_ROULETTE_H
2 #define __SELECTION_ROULETTE_H
5 #include <utility> // std::pair
8 #include "chromosome.h"
14 // namespace selection {
16 * Selection class Roulette.
17 * Applies Selection on given Generation using Roulette method.
19 template < typename _Chromosome >
20 class RouletteSelection : public Selection<_Chromosome> {
23 * Parent Selection class
25 typedef Selection<_Chromosome> BaseType;
28 * Value type returned by the Fitness function
30 typedef typename BaseType::FitnessValueType FitnessValueType;
33 * Method used for calculating fitness of each Chromosome in
36 * @param generation Generation for which fitness will be calculated
37 * @return vector containing fitness value of each Chromosome in
38 * Generation. Values are set in the same order as they are in
41 std::vector<FitnessValueType> calculateGenerationFitness(
42 const Generation<_Chromosome>& generation) {
43 std::vector<FitnessValueType> generationFitness;
44 const unsigned int generationSize = generation.size();
46 for (unsigned int i = 0; i < generationSize; i++) {
47 generationFitness.push_back(this->checkChromosomeFitness(generation[i]));
50 return generationFitness;
54 * Normalizes calculated fitness values of the generation.
56 * @param generationFitness fitness values of the generation
57 * @param chromosomeSize number of Gene's in the Chromosome.
59 * @return multimap containing normalized Fitness as a key and its
60 * Chromosome as the value
62 std::multimap<FitnessValueType, _Chromosome> normalizeFitness(
63 const std::vector<FitnessValueType>& generationFitness,
64 unsigned int chromosomeSize) {
67 FitnessValueType offset;
69 const unsigned int fitnessSize = generationFitness.size();
71 /* we use multimap because it stores multiple values with the
74 std::multimap<FitnessValueType, _Chromosome> normalizedFitness;
76 min = max = generationFitness[0];
79 for (unsigned int i = 0; i < fitnessSize; i++) {
80 if(generationFitness[i] < min) {
81 min = generationFitness[i];
84 if(generationFitness[i] > max) {
85 max = generationFitness[i];
89 offset = (max - min) / (chromosomeSize - 1) - min;
91 for (unsigned int i = 0; i < fitnessSize; i++) {
92 normalizedFitness.insert(std::make_pair(generationFitness[i] + offset, this->generation[i]));
95 return normalizedFitness;
101 * @param normalizedFitness multimap containing normalized Fitness
102 * as a key and its Chromosome as the value
103 * @return new Generation of Chromosome's that passed the Selection
105 Generation<_Chromosome> spinRoulette(
106 const std::multimap<FitnessValueType, _Chromosome>& normalizedFitness) {
108 typedef typename std::multimap<FitnessValueType, _Chromosome>::iterator FitnessIterator;
110 std::vector<_Chromosome> selected;
111 std::multimap<FitnessValueType, _Chromosome> probabilities;
113 unsigned int size = this->generation.size();
114 const unsigned int power2N = 1 << this->generation[0].size();
116 /** Random value used to draw chromosome */
117 FitnessValueType random = 0;
119 /** Position on the roulette wheele */
120 FitnessValueType position = 0;
122 FitnessValueType fitnessSum = 0;
124 // Calculate sum of normalized fitnesses, in order to calculate probabilities
125 for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) {
126 fitnessSum += it->first;
129 // Calculate probabilities for fitnesses
130 for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) {
131 position += (it->first / fitnessSum * power2N);
132 probabilities.insert(std::make_pair(position, it->second));
136 * Spin the Roulette until we draw as many chromosomes as in the
137 * original generation.
141 random = (rand() % power2N);
143 for (FitnessIterator it = probabilities.begin(); it != probabilities.end(); it++) {
144 if (random < it->first) {
146 selected.push_back(it->second);
149 // When NaN occur, just get first Chromosome
150 else if (it->first != it->first) {
151 selected.push_back(probabilities.begin()->second);
161 return Generation<_Chromosome>(selected);
165 * Draws new Generation using Roulette method
167 * @return new Generation of Chromosome's that passed the Selection
169 Generation<_Chromosome> do_draw() {
170 std::multimap<FitnessValueType, _Chromosome> normalizedFitness;
172 normalizedFitness = this->normalizeFitness(
173 this->calculateGenerationFitness(this->generation),
174 this->generation[0].size()
177 return spinRoulette(normalizedFitness);
182 * Class constructor. Initializes class with values.
184 * @param _generation Generation that will be checked against this
186 * @param _fitness Fitness method to calculate fitness of Chromosomes
188 RouletteSelection(const Generation<_Chromosome>& _generation, genetic::Fitness<_Chromosome>& _fitness) :
189 Selection<_Chromosome>(_generation, _fitness) {
195 #endif /* __SELECTION_ROULETTE_H */