Added classes: Algorithm, Crossover, Mutation. Fixed Roulette.
authorRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 29 Mar 2015 19:44:41 +0000 (21:44 +0200)
committerRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 29 Mar 2015 19:44:41 +0000 (21:44 +0200)
src/algorithm.h [new file with mode: 0644]
src/crossover/crossover.h [new file with mode: 0644]
src/fitness/wsti.h
src/main.cpp
src/mutation/mutation.h [new file with mode: 0644]
src/selection/roulette.h

diff --git a/src/algorithm.h b/src/algorithm.h
new file mode 100644 (file)
index 0000000..c12dfce
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef __ALGORITHM_H
+#define __ALGORITHM_H
+
+#include <iostream>
+
+#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 (file)
index 0000000..f494b7b
--- /dev/null
@@ -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<GeneType> 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 */
index fa303b0eb97fd13d706e8206ec8c609ca47e86e9..eaa0538b77d58f46cab63a68efd648d448fd4750 100644 (file)
@@ -26,6 +26,7 @@ namespace genetic {
                 _fenotype = _fenotype + this->chromosome.get()[i].get() * ratio;
                 ratio = ratio * 2;
             }
+//             cout << "Fenotyp: " << _fenotype << "\n";
             return _fenotype;
         }
 
index 9388101bd3d90fd26752d108b802a990011a07ed..920e3f11e354dad9b6cb55a2590505a9d04514e9 100644 (file)
@@ -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<int> _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 (file)
index 0000000..014ca70
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __MUTATION_MUTATION_H
+#define __MUTATION_MUTATION_H
+
+#include <iostream>
+
+#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 */
index 93f1514ab05c59a64ebc8d33f299242edee82eff..a4f1fd289ad8e2b2e58c4dcbef44e00e8eb87f6f 100644 (file)
@@ -31,14 +31,16 @@ namespace genetic {
 
                 return generationFitness;
             }
-            map<FitnessValueType, _Chromosome> normalizeFitness(
-                vector<FitnessValueType> generationFitness) {
+            multimap<FitnessValueType, _Chromosome> normalizeFitness(
+                vector<FitnessValueType> generationFitness,
+                unsigned int chromosomeSize) {
                 FitnessValueType min;
                 FitnessValueType max;
                 FitnessValueType offset;
-                map<FitnessValueType, _Chromosome> normalizedFitness;
+                multimap<FitnessValueType, _Chromosome> 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<FitnessValueType, _Chromosome> normalizedFitness) {
+                multimap<FitnessValueType, _Chromosome> normalizedFitness) {
 
-                typedef typename std::map<FitnessValueType, _Chromosome>::iterator FitnessIterator;
+                typedef typename std::multimap<FitnessValueType, _Chromosome>::iterator FitnessIterator;
 
                 vector<_Chromosome> selected;
-                map<FitnessValueType, _Chromosome> probabilities;
+                multimap<FitnessValueType, _Chromosome> 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<FitnessValueType, _Chromosome> normalizedFitness;
+                multimap<FitnessValueType, _Chromosome> 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));
             }
         };
 //     }