Finished Roulette Selection.
authorRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 29 Mar 2015 09:05:09 +0000 (11:05 +0200)
committerRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 29 Mar 2015 09:05:09 +0000 (11:05 +0200)
Makefile.am
src/chromosome.h
src/fitness/fitness.h [new file with mode: 0644]
src/fitness/wsti.h
src/generation.h
src/generator/generation.h
src/main.cpp
src/selection/roulette.h [new file with mode: 0644]
src/selection/selection.h [new file with mode: 0644]

index 45fb87235fc17ba94e299a37794894c37f4f847c..c54316149ee7fadccb162c40ed26313dfd07fa70 100644 (file)
@@ -1,5 +1,6 @@
 AUTOMAKE_OPTIONS = gnu subdir-objects
 ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
+AM_CXXFLAGS=-std=c++11
 
 EXTRA_DIST = \
     config.rpath
index ebed8353b6b5d25ed3caf0b01a82309cdeb77c28..e197f169be2a649d5427cb13f0264b25269c547d 100644 (file)
@@ -36,7 +36,8 @@ namespace genetic {
             : genes(chromosome.get()) {
         }
 
-        Chromosome& operator=(const Chromosome&){
+        Chromosome& operator=(const Chromosome& chromosome){
+            this->genes = chromosome.get();
             return *this;
         }
 
diff --git a/src/fitness/fitness.h b/src/fitness/fitness.h
new file mode 100644 (file)
index 0000000..14b6487
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __FITNESS_FITNESS_H
+#define __FITNESS_FITNESS_H
+
+#include "../chromosome.h"
+
+namespace genetic {
+    /**
+     * Base Fitness template class. It should be a base class for any custom
+     * fitness functions.
+     */
+    template < typename _Chromosome, typename _Value = double >
+    class Fitness {
+        template<typename> friend class Selection ;
+    public:
+        typedef typename _Chromosome::GeneType GeneType;
+        typedef _Value ValueType;
+    protected:
+        _Chromosome chromosome;
+
+        /*
+         * Some calculations here...
+         */
+        virtual _Value do_calculate() = 0;
+
+    public:
+        Fitness() {}
+
+        Fitness(_Chromosome& _chromosome)
+            : chromosome(_chromosome.get()) {
+        }
+
+        _Value calculate() {
+            return this->do_calculate();
+        }
+    };
+}
+
+#endif /* __FITNESS_FITNESS_H */
index b93439f204466028c6d6ba021a15d47ae2bcae7f..fa303b0eb97fd13d706e8206ec8c609ca47e86e9 100644 (file)
@@ -5,43 +5,46 @@
 
 #include "../gene.h"
 
+#include "fitness.h"
+
 using namespace std;
 
 namespace genetic {
     /**
      * Just an example Fitness function based on WSTI version.
      */
-    template < typename _Chromosome >
-    class WSTI {
+    template <typename _Chromosome, typename _Value = double>
+    class WSTI : public Fitness<_Chromosome, _Value> {
     protected:
-        _Chromosome chromosome;
-
         float span_start;
         float span_end;
 
-        double fenotype() {
+        _Value fenotype() {
             int _fenotype = 0;
             int ratio = 1;
-            for (unsigned int i = 0; i < chromosome.get().size(); i++) {
-                _fenotype = _fenotype + chromosome.get()[i].get() * ratio;
+            for (unsigned int i = 0; i < this->chromosome.get().size(); i++) {
+                _fenotype = _fenotype + this->chromosome.get()[i].get() * ratio;
                 ratio = ratio * 2;
             }
             return _fenotype;
         }
 
-        double calculateFenotype() {
+        _Value calculateFenotype() {
             const unsigned int power2N = 1 << this->chromosome.get().size();
             return span_start + (span_end - span_start) * this->fenotype() / power2N;
         }
-    public:
-        WSTI(_Chromosome& _chromosome, float start, float end)
-            : chromosome(_chromosome.get()), span_start(start), span_end(end) {
-        }
 
-        double calculate() {
-            double fenotype = this->calculateFenotype();
+        _Value do_calculate() {
+            _Value fenotype = this->calculateFenotype();
             return (exp(fenotype) * sin(3.1415 * fenotype) + 1) / fenotype;
         }
+    public:
+        WSTI(float start, float end)
+            : span_start(start), span_end(end) {
+        }
+        WSTI(_Chromosome& _chromosome, float start, float end)
+            : Fitness<_Chromosome>(_chromosome), span_start(start), span_end(end) {
+        }
     };
 }
 
index d36cd90e712374a61acf18a0bf9bd6828b16a4cf..39b9577bc4f7c855da8acdb0c2413de7dffe5721 100644 (file)
@@ -32,6 +32,11 @@ namespace genetic {
         vector<_Chromosome> get() const {
             return this->chromosomes;
         }
+
+        Generation& operator=(const Generation& generation){
+            this->chromosomes = generation.get();
+            return *this;
+        }
     };
 }
 
index a561d8e818fd941c505617b59ae69fabcbbfdcdf..a51e4b364525df380d5d70e126b1d7f67e908c46 100644 (file)
@@ -35,7 +35,7 @@ namespace genetic {
 
         public:
             /**
-             * Constructor. Initializes required variables and constans
+             * Constructor. Initializes required variables and constants
              *
              * @param generationSize Indicates size of the generation
              * @param generationSize Indicates size of the chromosome
index 3eaea51ec48c0466111e9ab5def86ed621819844..9388101bd3d90fd26752d108b802a990011a07ed 100644 (file)
@@ -6,6 +6,8 @@
 #include "generation.h"
 #include "generator/generation.h"
 
+#include "selection/roulette.h"
+
 #include "fitness/wsti.h"
 
 using namespace std;
@@ -17,14 +19,30 @@ int main() {
 
     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();
 
-    for (unsigned int i = 0; i < generationSize; i++) {
-        WSTI<_Chromosome> fitness(generation.get()[i], 0.5, 2.5);
+    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 << "Fitness is equal to: " << fitness.calculate() << "\n";
+    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";
     }
 
     return 0;
diff --git a/src/selection/roulette.h b/src/selection/roulette.h
new file mode 100644 (file)
index 0000000..93f1514
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef __SELECTION_ROULETTE_H
+#define __SELECTION_ROULETTE_H
+
+#include <vector>
+#include <utility>      // std::pair
+#include <algorithm>    // std::sort
+#include <map>
+#include <cstdlib>
+#include <iostream>
+
+#include "chromosome.h"
+#include "selection.h"
+
+using namespace std;
+
+namespace genetic {
+//     namespace selection {
+        template < typename _Chromosome >
+        class Roulette : public Selection<_Chromosome> {
+        public:
+            typedef Selection<_Chromosome> BaseType;
+            typedef typename BaseType::FitnessValueType FitnessValueType;
+        protected:
+            vector<FitnessValueType> calculateGenerationFitness(
+                Generation<_Chromosome> generation) {
+                vector<FitnessValueType> generationFitness;
+
+                for (unsigned int i = 0; i < generation.get().size(); i++) {
+                    generationFitness.push_back(this->checkChromosomeFitness(generation.get()[i]));
+                }
+
+                return generationFitness;
+            }
+            map<FitnessValueType, _Chromosome> normalizeFitness(
+                vector<FitnessValueType> generationFitness) {
+                FitnessValueType min;
+                FitnessValueType max;
+                FitnessValueType offset;
+                map<FitnessValueType, _Chromosome> normalizedFitness;
+
+                min = max = generationFitness[0];
+
+                for (unsigned int i = 0; i < generationFitness.size(); i++) {
+                    if(generationFitness[i] < min) {
+                        min = generationFitness[i];
+                    }
+
+                    if(generationFitness[i] > max) {
+                        max = generationFitness[i];
+                    }
+                }
+
+                offset = (max - min) / (generationFitness.size() - 1) - min;
+
+                for (unsigned int i = 0; i < generationFitness.size(); i++) {
+                    normalizedFitness[generationFitness[i] + offset] = this->generation.get()[i];
+                }
+
+                return normalizedFitness;
+            }
+
+            /**
+             * Spins the Roulette
+             */
+            Generation<_Chromosome> spinRoulette(
+                map<FitnessValueType, _Chromosome> normalizedFitness) {
+
+                typedef typename std::map<FitnessValueType, _Chromosome>::iterator FitnessIterator;
+
+                vector<_Chromosome> selected;
+                map<FitnessValueType, _Chromosome> probabilities;
+
+                unsigned int size = this->generation.get().size();
+                double random = 0;
+
+                FitnessValueType fitnessSum = 0;
+
+                // Calculate sum of normalized fitnesses, in order to calculate probabilities
+                for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) {
+                    fitnessSum += it->first;
+                }
+
+                // Calculate probabilities for fitnesses
+                for (FitnessIterator it = normalizedFitness.begin(); it != normalizedFitness.end(); it++) {
+                    probabilities[it->first / fitnessSum] = it->second;
+                }
+
+                /*
+                 * Spin the Roulette until we draw as many chromosomes as in the
+                 * original generation.
+                 */
+                while (size) {
+                    bool found = false;
+                    random = (rand() % 10000) / 100000.0;
+
+                    for (FitnessIterator it = probabilities.begin(); it != probabilities.end(); it++) {
+                        if (it->first > random) {
+                            found = true;
+                            selected.push_back(it->second);
+                            break;
+                        }
+                    }
+                    if (found) {
+                        size--;
+                    }
+                }
+                return Generation<_Chromosome>(selected);
+            }
+
+            /**
+             * Draws random 
+             */
+            Generation<_Chromosome> do_draw() {
+                map<FitnessValueType, _Chromosome> normalizedFitness;
+
+                normalizedFitness = this->normalizeFitness(
+                    this->calculateGenerationFitness(this->generation)
+                );
+
+                return spinRoulette(normalizedFitness);
+            }
+
+        public:
+            Roulette(Generation<_Chromosome> _generation, genetic::Fitness<_Chromosome>& _fitness) :
+                Selection<_Chromosome>(_generation, _fitness) {
+                this->generation = _generation;
+                this->fitness = _fitness;
+
+                time_t t;
+                srand((unsigned)time(&t));
+            }
+        };
+//     }
+}
+
+#endif /* __SELECTION_ROULETTE_H */
diff --git a/src/selection/selection.h b/src/selection/selection.h
new file mode 100644 (file)
index 0000000..f519ca1
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __SELECTION_SELECTION_H
+#define __SELECTION_SELECTION_H
+
+#include "chromosome.h"
+#include "generation.h"
+#include "../fitness/fitness.h"
+
+using namespace std;
+
+namespace genetic {
+//     namespace selection {
+        template < typename _Chromosome >
+        class Selection {
+        public:
+            typedef Fitness<_Chromosome> GeneticFitness;
+            typedef typename GeneticFitness::ValueType FitnessValueType;
+        protected:
+            Generation<_Chromosome> generation;
+            GeneticFitness& fitness;
+            
+            FitnessValueType checkChromosomeFitness(_Chromosome chromosome) {
+                this->fitness.chromosome = chromosome;
+                return fitness.calculate();
+            }
+
+            virtual Generation<_Chromosome> do_draw() = 0;
+
+        public:
+            Selection(Generation<_Chromosome> _generation, GeneticFitness& _fitness) :
+                generation(_generation), fitness(_fitness) {
+            }
+
+            Generation<_Chromosome> draw() {
+                return this->do_draw();
+            }
+        };
+//     }
+}
+
+#endif /* __SELECTION_SELECTION_H */