169 lines
5.5 KiB
C++
169 lines
5.5 KiB
C++
# include <mpi/eoMultiStart.h>
|
|
using namespace eo::mpi;
|
|
|
|
#include <stdexcept>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include <eo>
|
|
#include <es.h>
|
|
|
|
/*
|
|
* This file is based on the tutorial lesson 1. We'll consider that you know all the EO
|
|
* related parts of the algorithm and we'll focus our attention on parallelization.
|
|
*
|
|
* This file shows an example of multistart applied to a eoSGA (simple genetic
|
|
* algorithm). As individuals need to be serialized, we implement a class inheriting
|
|
* from eoReal (which is the base individual), so as to manipulate individuals as they
|
|
* were eoReal AND serialize them.
|
|
*
|
|
* The main function shows how to launch a multistart job, with default functors. If you
|
|
* don't know which functors to use, these ones should fit the most of your purposes.
|
|
*/
|
|
|
|
using namespace std;
|
|
|
|
/*
|
|
* eoReal is a vector of double: we just have to serializes the value and the fitness.
|
|
*/
|
|
class SerializableEOReal: public eoReal<double>, public eoserial::Persistent
|
|
{
|
|
public:
|
|
|
|
SerializableEOReal(unsigned size = 0, double value = 0.0) :
|
|
eoReal<double>(size, value)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
void unpack( const eoserial::Object* obj )
|
|
{
|
|
this->clear();
|
|
eoserial::unpackArray
|
|
< std::vector<double>, eoserial::Array::UnpackAlgorithm >
|
|
( *obj, "vector", *this );
|
|
|
|
bool invalidFitness;
|
|
eoserial::unpack( *obj, "invalid_fitness", invalidFitness );
|
|
if( invalidFitness )
|
|
{
|
|
this->invalidate();
|
|
} else
|
|
{
|
|
double f;
|
|
eoserial::unpack( *obj, "fitness", f );
|
|
this->fitness( f );
|
|
}
|
|
}
|
|
|
|
eoserial::Object* pack( void ) const
|
|
{
|
|
eoserial::Object* obj = new eoserial::Object;
|
|
obj->add( "vector", eoserial::makeArray< std::vector<double>, eoserial::MakeAlgorithm >( *this ) );
|
|
|
|
bool invalidFitness = this->invalid();
|
|
obj->add( "invalid_fitness", eoserial::make( invalidFitness ) );
|
|
if( !invalidFitness )
|
|
{
|
|
obj->add( "fitness", eoserial::make( this->fitness() ) );
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
};
|
|
|
|
// REPRESENTATION
|
|
//-----------------------------------------------------------------------------
|
|
// define your individuals
|
|
typedef SerializableEOReal Indi;
|
|
|
|
// EVAL
|
|
//-----------------------------------------------------------------------------
|
|
// 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 only
|
|
}
|
|
|
|
/************************** PARALLELIZATION JOB *******************************/
|
|
int main(int argc, char **argv)
|
|
{
|
|
Node::init( argc, argv );
|
|
|
|
// PARAMETRES
|
|
// all parameters are hard-coded!
|
|
const unsigned int SEED = 133742; // seed for random number generator
|
|
const unsigned int VEC_SIZE = 8; // Number of object variables in genotypes
|
|
const unsigned int POP_SIZE = 100; // Size of population
|
|
const unsigned int T_SIZE = 3; // size for tournament selection
|
|
const unsigned int MAX_GEN = 100; // 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
|
|
|
|
eoEvalFuncPtr<Indi> eval( real_value );
|
|
eoPop<Indi> pop;
|
|
eoUniformGenerator< double > generator;
|
|
eoInitFixedLength< Indi > init( VEC_SIZE, generator );
|
|
pop = eoPop<Indi>( POP_SIZE, init );
|
|
|
|
eoDetTournamentSelect<Indi> select(T_SIZE);
|
|
eoSegmentCrossover<Indi> xover;
|
|
eoUniformMutation<Indi> mutation(EPSILON);
|
|
|
|
eoGenContinue<Indi> continuator(MAX_GEN);
|
|
/* Does work too with a steady fit continuator. */
|
|
// eoSteadyFitContinue< Indi > continuator( 10, 50 );
|
|
|
|
eoSGA<Indi> gga(select, xover, CROSS_RATE, mutation, MUT_RATE,
|
|
eval, continuator);
|
|
|
|
/* How to assign tasks, which are starts? */
|
|
DynamicAssignmentAlgorithm assignmentAlgo;
|
|
/* Before a worker starts its algorithm, how does it reinits the population?
|
|
* There are a few default usable functors, defined in eoMultiStart.h.
|
|
*
|
|
* This one (ReuseSamePopEA) doesn't modify the population after a start, so
|
|
* the same population is reevaluated on each multistart: the solution tend
|
|
* to get better and better.
|
|
*/
|
|
ReuseSamePopEA< Indi > resetAlgo( continuator, pop, eval );
|
|
/**
|
|
* How to send seeds to the workers, at the beginning of the parallel job?
|
|
* This functors indicates that seeds should be random values.
|
|
*/
|
|
GetRandomSeeds< Indi > getSeeds( SEED );
|
|
|
|
// Builds the store
|
|
MultiStartStore< Indi > store(
|
|
gga,
|
|
DEFAULT_MASTER,
|
|
resetAlgo,
|
|
getSeeds);
|
|
|
|
// Creates the multistart job and runs it.
|
|
// The last argument indicates that we want to launch 5 runs.
|
|
MultiStart< Indi > msjob( assignmentAlgo, DEFAULT_MASTER, store, 5 );
|
|
msjob.run();
|
|
|
|
if( msjob.isMaster() )
|
|
{
|
|
msjob.best_individuals().sort();
|
|
std::cout << "Global best individual has fitness " << msjob.best_individuals().best_element().fitness() << std::endl;
|
|
}
|
|
|
|
MultiStart< Indi > msjob10( assignmentAlgo, DEFAULT_MASTER, store, 10 );
|
|
msjob10.run();
|
|
|
|
if( msjob10.isMaster() )
|
|
{
|
|
msjob10.best_individuals().sort();
|
|
std::cout << "Global best individual has fitness " << msjob10.best_individuals().best_element().fitness() << std::endl;
|
|
}
|
|
return 0;
|
|
}
|