
//-----------------------------------------------------------------------------
#include <stdexcept > // runtime_error
//-----------------------------------------------------------------------------
// FirstRealGA.cpp
//-----------------------------------------------------------------------------
//*
// An instance of a
VERY simple Real-coded Genetic Algorithm
//
//-----------------------------------------------------------------------------
// standard includes
#include
<iostream>// cout
#include
<strstream>// ostrstream, istrstream
// the general include for eo
#include <eo>
// specific incluse,
as Real is not (yet) in the standard eo source dir
#include
"eoeal.h"
#include
"eoRealOp.h"
//-----------------------------------------------------------------------------
// define your individual:
You say here that you will be handling arrays
of doubles, whose fitness is a double
Note that this makes Indi derive from STL
class vector<double>
//-----------------------------------------------------------------------------
/** a simple fitness
function that computes the euclidian norm of a real vector
@param
_indi A real-valued individual
*/
double
real_value(const Indi & _indi)
{
double sum = 0;
for (unsigned i = 0; i < _indi.size(); i++)
sum += _indi[i]*_indi[i];
return (-sum); // maximizing
}
This simple function computes the sum of the squares of the variables
(remember Indi is here a vector of doubles)
//-----------------------------------------------------------------------------
void
main_function(int argc, char **argv)
{
const
unsigned int SEED = 42;// seed for random number generator
const
unsigned int VEC_SIZE = 8; // Number of object variables in genotypes
const
unsigned int POP_SIZE = 20; // Size of population
const
unsigned int T_SIZE = 3; // size for tournament selection
const
unsigned int MAX_GEN = 500; // Maximum number of generation before STOP
const
float CROSS_RATE = 0.8; // Crossover rate
const
double EPSILON = 0.01; // range for real uniform mutation
const
float MUT_RATE = 0.5; // mutation rate
//////////////////////////
// Random seed
//////////////////////////
//reproducible random
seed: if you don't change SEED above,
// you'll aways get
the same result, NOT a random run
rng.reseed(SEED);
/////////////////////////////
// Fitness function
////////////////////////////
// Evaluation: from
a plain C++ fn to an EvalFunc Object
eoEvalFuncPtr<Indi>
eval( real_value );
This encapsulate the C++ function real_value into a functor object
////////////////////////////////
// Initilisation of
population
////////////////////////////////
// declare the population
eoPop<Indi>
pop;
Declares a population object, which is basically an STL vector<Indi>
// fill it!
for
(unsigned int igeno=0; igeno<POP_SIZE; igeno++)
{
Indi v; // generate a random individual
for (unsigned ivar=0; ivar<VEC_SIZE; ivar++)
{
double r = 2*rng.uniform() - 1; // new value, random in [-1,1)
v.push_back(r); //
}
eval(v); // evaluate it
pop.push_back(v); // and put it in the population
}
This initialization of the population is straightforward
rng.uniform() generates a double uniformly
in [0,1),
v.push_back simply appends its argument
at the end of STL vector v
eval(v)evaluates individal v
the functor way, calling eval.operator()(v)
// sort pop before printing
it!
pop.sort();
// Print (sorted) intial
population (raw printout)
cout
<< "Initial Population" << endl;
cout
<< pop;
If you looked at eoPop inheritance diagram, you noticed that it derives from eoPrintable: hence you can stream them using the << operator. Of course, Indis are EO objects , which also are eoPrintable, and the << operator for eoPop uses the << operator for Indi.
/////////////////////////////////////
//
selection and replacement
////////////////////////////////////
// The well-known roulette
selection
//
The robust tournament selection
eoDetTournament<Indi>
select(T_SIZE); // SIZE in [2,POP_SIZE]
//
eoSGA uses generational replacement by default
// so no replacement
procedure has to be given
//////////////////////////////////////
// termination condition
/////////////////////////////////////
// stop after MAX_GEN
generations
eoGenContinue<Indi>
continuator(MAX_GEN);
This class is called eoGenContinue because the main loop of all eoAlgo says ... while continuator(pop)
//////////////////////////////////////
//
The variation operators
//////////////////////////////////////
//
offspring(i) uniformly chosen in [parent(i)-epsilon, parent(i)+epsilon]
eoUniformMutation<Indi>
mutation(EPSILON);
//
offspring(i) is a linear combination of parent(i)
eoArithmeticCrossover<Indi>
xover;
The variation operators are respectively an eoMonOp (unary operator) and an eoQuadOp (binary operator that modifies both its arguments).
/////////////////////////////////////////
// the algorithm
////////////////////////////////////////
// standard Generational
GA requires
// selection, evaluation,
crossover and mutation, stopping criterion
eoSGA<Indi>
gga(select, xover, CROSS_RATE, mutation, MUT_RATE,
eval,
continuator);
// Apply algo to pop
- that's it!
gga(pop);
This simple algorithm of class eoSGA is a functor object, and running the algorithm amounts to call the operator() on the initial population!
// Print (sorted) intial
population (raw printout)
pop.sort();
cout
<< "FINAL Population\n" << pop << endl;
that's it - just print the final population and you're done!!!
}
//
A main that catches the exceptions - do not modify!
int
main(int argc, char **argv)
{
#ifdef
_MSC_VER
//
rng.reseed(42);
int
flag = _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
flag
|= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(flag);
//
_CrtSetBreakAlloc(100);
#endif
try
{
main_function(argc,
argv);
}
catch(exception&
e)
{
cout
<< "Exception: " << e.what() << '\n';
}
return
1;
}