Generates neural net instances through genetic algorithm for use in task learning by m3pi. Reward determined by detection of black areas on arena floor, or by amount of area explored in limited time. Due to memory size, limited # of nets.

Dependencies:   Ping m3pimaze mbed

Revision:
0:ac93d9db8dbd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/CGenAlg.cpp	Thu Apr 23 20:16:51 2015 +0000
@@ -0,0 +1,232 @@
+#include "CGenAlg.h"
+
+//const unsigned int numElite = 1;
+//const unsigned int numCopies = 2;
+
+// constructor
+// set up population with random floats
+CGenAlg::CGenAlg(int popsize, float MutRat, float CrossRat, int numweights) : m_iPopSize(popsize),
+                                                                                m_dMutationRate(MutRat),
+                                                                                m_dCrossoverRate(CrossRat),
+                                                                                m_iChromoLength(numweights),
+                                                                                m_dTotalFitness(0),
+                                                                                m_cGeneration(0),
+                                                                                m_iFittestGenome(0),
+                                                                                m_dBestFitness(0),
+                                                                                m_dWorstFitness(99999)
+{
+    //initialise population with randomly weighted chromosomes, set fitness to 0
+    for (int i=0; i<m_iPopSize; ++i)
+    {
+        m_vecPop.push_back(SGenome());
+
+        for (int j=0; j<m_iChromoLength; ++j)
+        {
+            m_vecPop[i].vecWeights.push_back(RandomClamped());
+        }
+    }
+}
+
+// Mutates a chromosome by perturbing its weights, m_dMutationRate given in main
+void CGenAlg::Mutate(vector<float> &chromo)
+{
+    //traverse the chromosome and mutate each weight dependent
+    //on the mutation rate
+    for (int i=0; i<chromo.size(); ++i)
+    {
+        //do we perturb this weight?
+        if (RandFloat() < m_dMutationRate)
+        {
+            //add or subtract a small value to the weight
+            chromo[i] += (RandomClamped() * 0.3);
+        }
+    }
+}
+
+// returns a chromo based on roulette wheel sampling
+SGenome CGenAlg::GetChromoRoulette()
+{
+    //generate a random number between 0 & total fitness count
+    float Slice = (float)(RandFloat() * m_dTotalFitness);
+
+    //this will be set to the chosen chromosome
+    SGenome TheChosenOne;
+    
+    //go through the chromosones adding up the fitness so far
+    float FitnessSoFar = 0;
+    
+    for (int i=0; i<m_iPopSize; ++i)
+    {
+        FitnessSoFar += m_vecPop[i].dFitness;
+        
+        //if the fitness so far > random number return the chromo at 
+        //this point
+        if (FitnessSoFar >= Slice)
+        {
+            TheChosenOne = m_vecPop[i];
+
+      break;
+        }
+        
+    }
+
+    return TheChosenOne;
+}
+
+// given parents and storage for the offspring this method performs
+// crossover according to the GAs crossover rate
+void CGenAlg::Crossover(const vector<float> &mum,
+                        const vector<float> &dad,
+                        vector<float>       &baby1,
+                        vector<float>       &baby2)
+{
+    //just return parents as offspring dependent on the rate
+    //or if parents are the same
+    if ( (RandFloat() > m_dCrossoverRate) || (mum == dad)) 
+    {
+        baby1 = mum;
+        baby2 = dad;
+
+        return;
+    }
+
+    //determine a crossover point
+    int cp = RandInt(0, m_iChromoLength - 1);
+
+    //create the offspring
+    for (int i=0; i<cp; ++i)
+    {
+        baby1.push_back(mum[i]);
+        baby2.push_back(dad[i]);
+    }
+
+    int i;
+    for (i=cp; i<mum.size(); ++i)
+    {
+        baby1.push_back(dad[i]);
+        baby2.push_back(mum[i]);
+    }
+    
+    
+    return;
+}
+
+
+// takes a population of chromosones and runs the algorithm through one cycle.
+//  Returns a new population of chromosones.
+vector<SGenome> CGenAlg::Epoch(vector<SGenome> &old_pop)
+{
+    //assign the given population to the classes population
+  m_vecPop = old_pop;
+
+  //reset the appropriate variables
+  Reset();
+
+  //sort the population (for scaling and elitism)
+  sort(m_vecPop.begin(), m_vecPop.end());
+
+  //calculate best, worst, average and total fitness
+    CalculateBestWorstAvTot();
+  
+  //create a temporary vector to store new chromosones
+    vector <SGenome> vecNewPop;
+
+    //Now to add a little elitism we shall add in some copies of the
+    //fittest genomes. Make sure we add an EVEN number or the roulette
+  //wheel sampling will crash
+
+    if (m_vecPop[1].dFitness > 130 && m_vecPop[2].dFitness > 130)//2 copies of 1 elite
+    {
+        GrabNBest(2, 2, vecNewPop);
+    }
+    else if (m_vecPop[1].dFitness > 130)//2 copies of 1 elite
+    {
+        GrabNBest(1, 4, vecNewPop);
+    }
+    
+
+    //now we enter the GA loop
+    
+    //repeat until a new population is generated
+    while (vecNewPop.size() < m_iPopSize)
+    {
+        //grab two chromosones
+        SGenome mum = GetChromoRoulette();
+        SGenome dad = GetChromoRoulette();
+
+        //create some offspring via crossover
+        vector<float>      baby1, baby2;
+
+        Crossover(mum.vecWeights, dad.vecWeights, baby1, baby2);
+
+        //now we mutate
+        Mutate(baby1);
+        Mutate(baby2);
+
+        //now copy into vecNewPop population
+        vecNewPop.push_back(SGenome(baby1, 0));
+        vecNewPop.push_back(SGenome(baby2, 0));
+    }
+
+    //finished so assign new pop back into m_vecPop
+    m_vecPop = vecNewPop;
+
+    return m_vecPop;
+}
+
+// Elitism, inserts NumCopies of NBest fittest genomes into a pop vector
+void CGenAlg::GrabNBest(int             NBest,
+                        const int         NumCopies,
+                        vector<SGenome> &Pop)
+{
+  //add the required amount of copies of the n most fittest 
+    //to the supplied vector
+    while(NBest--)
+    {
+        for (int i=0; i<NumCopies; ++i)
+        {
+            Pop.push_back(m_vecPop[(m_iPopSize - 1) - NBest]);
+      }
+    }
+}
+
+//  calculates fittest and weakest genomes
+void CGenAlg::CalculateBestWorstAvTot()
+{
+    m_dTotalFitness = 0;
+    
+    float HighestSoFar = 0;
+    float LowestSoFar  = 99999;
+    
+    for (int i=0; i<m_iPopSize; ++i)
+    {
+        //update fittest if necessary
+        if (m_vecPop[i].dFitness > HighestSoFar)
+        {
+            HighestSoFar     = m_vecPop[i].dFitness;
+            
+            m_iFittestGenome = i;
+
+            m_dBestFitness   = HighestSoFar;
+        }
+        
+        //update worst if necessary
+        if (m_vecPop[i].dFitness < LowestSoFar)
+        {
+            LowestSoFar = m_vecPop[i].dFitness;
+            
+            m_dWorstFitness = LowestSoFar;
+        }
+        
+        m_dTotalFitness += m_vecPop[i].dFitness;
+        
+        
+    }//next chromosome
+}
+
+void CGenAlg::Reset()
+{
+    m_dTotalFitness     = 0;
+    m_dBestFitness      = 0;
+    m_dWorstFitness     = 99999;
+}
\ No newline at end of file