//
// gasolver.h - GASolver is a class template.
// The template typename T must be derived
// from GAGenome.
//////////////////////////////////////////////
#ifndef GASOLVER_H
#define GASOLVER_H
#include "math.h"
////////////////////////////////////////
template<typename T>
class GASolver
{
protected :
int m_popSize ; // The genome
T* m_pop ; // population.
T m_bestEver; // The best ever genome.
// GA paramenters.
int m_nGenerations;// # of generations
bool m_maximize; // min/max flag
double m_mutation; // mutation probability
double m_cross ; // crossover probability
double m_sigma ; // sigma trucation
double m_trunc ; // truncation constant
public :
//--------------------------------
int Solve(T &bestSolution)
{
Initialize();
Evaluate();
for (int i=0;i<m_nGenerations;i++)
{
Select();
CrossOver();
Mutate();
Evaluate();
}
bestSolution = m_bestEver;
return 0;
}
//--------------------------------
int Maximize( T &bestSolution)
{
// Solve for maximum
m_maximize = true;
return Solve( bestSolution);
}
//--------------------------------
int Minimize( T &bestSolution)
{
// Solve for minimimum
m_maximize = false;
return Solve( bestSolution);
}
//
// constructor,destructor.
//--------------------------------
GASolver()
{
m_popSize = 0;
m_pop = NULL;
m_nGenerations = 100;
m_mutation = 0.01;
m_cross = 0.50;
m_sigma = 1.5;
m_trunc =0;
m_maximize = true;
};
~GASolver()
{
if (m_pop)
delete [] m_pop;
}
//--------------------------------
void SetPopSize( int popSize)
{
// Population size.
if (m_pop)
delete [] m_pop;
m_popSize = popSize;
m_pop = NULL;
if (m_popSize)
m_pop = new T[popSize];
}
//--------------------------------
void SetNumGenerations( int numGenerations)
{
m_nGenerations = numGenerations;
}
//--------------------------------
void SetMutationFactor( double mutationFactor)
{
// Probability of mutation.
m_mutation = mutationFactor;
}
//--------------------------------
void SetCrossOverFactor( double crossOverFactor)
{
// Probability of crossover.
m_cross = crossOverFactor;
}
//--------------------------------
void SetFitnessSigma( double fitnessSigma)
{
// Sigma trunctation parameter
// used for cacluating fitness.
m_sigma = fitnessSigma;
}
protected:
//--------------------------------
void Initialize()
{
// Initialize each genome in population.
RandomSeed( 15);
for (int j=0;j<m_popSize;j++)
{
m_pop[j].Initialize();
}
m_bestEver.Initialize();
m_bestEver.m_obj = m_bestEver.Evaluate();
}
//
//--------------------------------
void Select()
{
// This routine selects the next generation.
// First, get the fitness function total for
// the entier population.
double sumFit = 0;
for (int j=0;j<m_popSize;j++)
sumFit += m_pop[j].m_fitness;
//
// Weight each individual against total to
// to determine probability of selection
double sumProb = 0;
for (j=0;j<m_popSize;j++)
{
double prob;
prob = sumProb + m_pop[j].m_fitness/sumFit;
m_pop[j].m_selProb = prob;
sumProb = prob;
m_pop[j].m_selected = 0;
}
//
// Spin the roullete wheel popSize
// times to select
// the most fit individuals.
for (j=0;j<m_popSize;j++)
{
double r = RandomNum(10000)/10000.;
int k=0;
while ((m_pop[k].m_selProb < r)
&& (k < (m_popSize-1)))
{
k++;
}
m_pop[k].m_selected++;
}
//
// Kill off the unselected individuals
// and make copies of multiply
// selected individuals.
for (j=0;j<m_popSize;j++)
{
while (m_pop[j].m_selected > 1)
{
for (int k=0;k<m_popSize;k++)
{
if (m_pop[k].m_selected == 0)
{
m_pop[k] = m_pop[j];
m_pop[k].m_selected = 1;
m_pop[j].m_selected--;
break;
}
}
}
}
}
//--------------------------------
void CrossOver()
{
//
// Mate selected chromosomes in
// the new population randomly.
int first = -1;
for (int j=0;j<m_popSize;j++)
{
// generate a probability
double r = RandomNum(10000)/10000.;
//
// The probability of crossover
// is m_cross.
if (r < m_cross)
{
// found 1st partner
if (first == -1)
first = j;
else
{
// we have 2 parnters
// crossover
m_pop[j].CrossOver( &m_pop[first]);
first = -1;
}
}
}
}
//
//--------------------------------
void Mutate()
{
// Mutation
for (int j=0;j<m_popSize;j++)
{
//
// mutate the genome according
// to the m_mutation probability
// factor.
m_pop[j].Mutate(m_mutation);
}
}
//--------------------------------
void Evaluate()
{
//
// Evaluates the fitness of each genome.
// Keep track of best ever genome.
//
// First step is to caculate objective
// value for each genome and determine
// the best ever genome.
double totalObjVal=0;
for (int j=0;j<m_popSize;j++)
{
double objVal = m_pop[j].Evaluate();
m_pop[j].m_obj = objVal;
if (m_maximize)
{
if (m_pop[j].m_obj > m_bestEver.m_obj)
m_bestEver = m_pop[j];
}
else
{
if (m_pop[j].m_obj < m_bestEver.m_obj)
m_bestEver = m_pop[j];
}
totalObjVal += objVal;
}
//
// Sigma truncation constant (m_trunc)
// is calculated here. Used for fitness
// calculation further below.
m_trunc = 0;
if (m_sigma != 0)
{
// calulate fitness constant using avg, std dev.
double avg = totalObjVal/m_popSize;
double stdDev = 0;
for (int j=0;j<m_popSize;j++)
{
double delta = m_pop[j].m_obj - avg;
delta = delta*delta;
stdDev += delta;
}
//
// sigma truncation constant is some
// number of standard deviations from
// the average obj function value.
stdDev = sqrt( stdDev/(m_popSize-1.0));
if (m_maximize)
m_trunc=avg - m_sigma*stdDev;
else
m_trunc=avg + m_sigma*stdDev;
}
//
// Calcuate the fitness.
for (j=0;j<m_popSize;j++)
{
//
// Fitness for maximum and minimum optimization.
if (m_maximize)
m_pop[j].m_fitness = m_pop[j].m_obj-m_trunc;
else
m_pop[j].m_fitness = m_trunc - m_pop[j].m_obj;
//
// If the object value is too many
// standard deviations away from
// the average then it has zero fitness
// and it will be killed off in the
// selection process.
if (m_pop[j].m_fitness < 0)
{
m_pop[j].m_fitness = 0;
}
}
}
};
#endif
End of Listing