| do { | |
| select( population, offsprings ); | // select the offsprings from the current population |
| transform( offsprings ); | // crossover and mutation operators are applied on the selected offsprings |
| evaluate( offsprings ); | // evaluation step of the resulting offsprings |
| replace( population, offsprings ); | // replace the individuals in the current population whith individuals from the offspring population, according to a specified replacement strategy |
| } while ( eaCheckpointContinue( population ) ); | // checkpoint operators are applied on the current population |
The peoEA class offers an elementary evolutionary algorithm implementation. The peoEA class has the underlying structure for including parallel evaluation and parallel transformation operators, migration operators etc. Although there is no restriction on using the algorithms provided by the EO framework, no parallelism is provided - the EO implementation is exclusively sequential.
The source-code for this tutorial may be found in the paradiseo-peo/examples/lesson1 directory, in the main.cpp file. We strongly encourage creating a backup copy of the file if you consider modifying the source code. For a complete reference on the TSP-related classes and definitions please refer to the files under the paradiseo-peo/examples/shared. After the installation phase you should end up having an tspExample executable file in the paradiseo-peo/examples/lesson1 directory. We will discuss testing and launching aspects later in the tutorial.
You are supposed to be familiar with working in C/C++ (with an extensive use of templates) and you should have at least an introductory background in working with the EO framework.
The construction of a ParadisEO-PEO evolutionary algorithm requires following a few simple steps - please take your time to study the signature of the peoEA constructor:
| peoEA( eoContinue< EOT >& __cont, peoPopEval< EOT >& __pop_eval, eoSelect< EOT >& __select, peoTransform< EOT >& __trans, eoReplacement< EOT >& __replace ); |
|
A few remarks have to be made: while most of the parameters are passed as EO-specific types, the evaluation and the transformation objects have to be derived from the ParadisEO-PEO peoPopEval and peoTransform classes. Derived classes like the peoParaPopEval and peoParaSGATransform classes allow for parallel evaluation of the population and parallel transformation operators, respectively. Wrappers are provided thus allowing to make use of the EO classes.
In the followings, the main required elements for building an evolutionary algorithm are enumerated. For complete details regarding the implementation aspects of each of the components, please refer to the common shared source code. Each of the bellow referred header files may be found in the pardiseo-peo/examples/shared directory.
For our case study, the TSP, each city is defined as a Node in the node.h header file - in fact an unsigned value defined as typedef unsigned Node. Moreover, each individual (of the evolutionary algorithm) is represented as a Route object, a vector of Node objects, in the route.h header file - typedef eoVector< int, Node > Route. The definition of the Route object implies two elements: (1) a route is a vector of nodes, and (2) the fitness is an integer value (please refer to the eoVector definition in the EO framework).
In addition you should also take a look in the route_init.h header file which includes the RouteInit class, defined for initializing in random manner Route objects.
The fitness function for our TSP case study is implemented in the route_eval.h header file. The class is derived from the eoEvalFunc EO class, being defined as class RouteEval : public eoEvalFunc< Route >.
The transform operators, crossover and mutation, for the herein presented example are defined in the order_xover.h and the city_swap.h header files, respectively.
For our example we chose to use the eoRankingSelect strategy, provided in the EO framework.
#include "route.h" #include "route_init.h" #include "route_eval.h"
#include "order_xover.h" #include "city_swap.h"In addition we require having the paradiseo header file, in order to use the ParadisEO-PEO features, and a header specific for our problem, dealing with processing command-line parameters - the param.h header file. The complete picture at this point with all the required header files is as follows:
#include "route.h" #include "route_init.h" #include "route_eval.h"
#include "order_xover.h" #include "city_swap.h"
#include "param.h"
#include <paradiseo>NOTE: the paradiseo header file is in fact a "super-header" - it includes all the esential ParadisEO-PEO header files. It is at at your choice if you want use the paradiseo header file or to explicitly include different header files, like the peoEA.h header file, for example.
#include "route.h" #include "route_init.h" #include "route_eval.h"
#include "order_xover.h" #include "city_swap.h"
#include "param.h"
#include <paradiseo>
#define POP_SIZE 10 #define NUM_GEN 100 #define CROSS_RATE 1.0 #define MUT_RATE 0.01
...
int main( int __argc, char** __argv ) {
// initializing the ParadisEO-PEO environment peo :: init( __argc, __argv );
// processing the command line specified parameters loadParameters( __argc, __argv );
// EVOLUTIONARY ALGORITHM TO BE DEFINED
peo :: run( ); peo :: finalize( ); // shutting down the ParadisEO-PEO environment
return 0; }
RouteInit route_init; // random init object - creates random Route objects RouteEval full_eval; // evaluator object - offers a fitness value for a specified Route object
OrderXover crossover; // crossover operator - creates two offsprings out of two specified parents CitySwap mutation; // mutation operator - randomly mutates one gene for a specified individual
eoPop< Route > population( POP_SIZE, route_init ); // initial population for the algorithm having POP_SIZE individuals peoSeqPopEval< Route > eaPopEval( full_eval ); // evaluator object - to be applied at each iteration on the entire population
eoGenContinue< Route > eaCont( NUM_GEN ); // continuation criterion - the algorithm will iterate for NUM_GEN generations eoCheckPoint< Route > eaCheckpointContinue( eaCont ); // checkpoint object - verify at each iteration if the continuation criterion is met
eoRankingSelect< Route > selectionStrategy; // selection strategy - applied at each iteration for selecting parent individuals eoSelectNumber< Route > eaSelect( selectionStrategy, POP_SIZE ); // selection object - POP_SIZE individuals are selected at each iteration
// transform operator - includes the crossover and the mutation operators with a specified associated rate eoSGATransform< Route > transform( crossover, CROSS_RATE, mutation, MUT_RATE ); peoSeqTransform< Route > eaTransform( transform ); // ParadisEO transform operator (please remark the peo prefix) - wraps an e EO transform object
eoPlusReplacement< Route > eaReplace; // replacement strategy - for replacing the initial population with offspring individuals
peoEA< Route > eaAlg( eaCheckpointContinue, eaPopEval, eaSelect, eaTransform, eaReplace );
eaAlg( population ); // specifying the initial population for the algorithm, to be iteratively evolved
If you have not missed any of the enumerated points, your program should be like the following:
#include "route.h"
#include "route_init.h"
#include "route_eval.h"
#include "order_xover.h"
#include "city_swap.h"
#include "param.h"
#include <paradiseo>
#define POP_SIZE 10
#define NUM_GEN 100
#define CROSS_RATE 1.0
#define MUT_RATE 0.01
int main( int __argc, char** __argv ) {
// initializing the ParadisEO-PEO environment
peo :: init( __argc, __argv );
// processing the command line specified parameters
loadParameters( __argc, __argv );
// init, eval operators, EA operators -------------------------------------------------------------------------------------------------------------
RouteInit route_init; // random init object - creates random Route objects
RouteEval full_eval; // evaluator object - offers a fitness value for a specified Route object
OrderXover crossover; // crossover operator - creates two offsprings out of two specified parents
CitySwap mutation; // mutation operator - randomly mutates one gene for a specified individual
// ------------------------------------------------------------------------------------------------------------------------------------------------
// evolutionary algorithm components --------------------------------------------------------------------------------------------------------------
eoPop< Route > population( POP_SIZE, route_init ); // initial population for the algorithm having POP_SIZE individuals
peoSeqPopEval< Route > eaPopEval( full_eval ); // evaluator object - to be applied at each iteration on the entire population
eoGenContinue< Route > eaCont( NUM_GEN ); // continuation criterion - the algorithm will iterate for NUM_GEN generations
eoCheckPoint< Route > eaCheckpointContinue( eaCont ); // checkpoint object - verify at each iteration if the continuation criterion is met
eoRankingSelect< Route > selectionStrategy; // selection strategy - applied at each iteration for selecting parent individuals
eoSelectNumber< Route > eaSelect( selectionStrategy, POP_SIZE ); // selection object - POP_SIZE individuals are selected at each iteration
// transform operator - includes the crossover and the mutation operators with a specified associated rate
eoSGATransform< Route > transform( crossover, CROSS_RATE, mutation, MUT_RATE );
peoSeqTransform< Route > eaTransform( transform ); // ParadisEO transform operator (please remark the peo prefix) - wraps an e EO transform object
eoPlusReplacement< Route > eaReplace; // replacement strategy - for replacing the initial population with offspring individuals
// ------------------------------------------------------------------------------------------------------------------------------------------------
// ParadisEO-PEO evolutionary algorithm -----------------------------------------------------------------------------------------------------------
peoEA< Route > eaAlg( eaCheckpointContinue, eaPopEval, eaSelect, eaTransform, eaReplace );
eaAlg( population ); // specifying the initial population for the algorithm, to be iteratively evolved
// ------------------------------------------------------------------------------------------------------------------------------------------------
peo :: run( );
peo :: finalize( );
// shutting down the ParadisEO-PEO environment
return 0;
}
Compilation: being in the paradiseo-peo/examples/lesson1 directory, you have to type make. As a result the main.cpp file will be compiled and you should obtain an executable file called tspExample. If you have errors, please verify any of the followings:
NOTE: in order to successfully compile your program you should already have installed an MPI distribution in your system.
Execution: the execution of a ParadisEO-PEO program requires having already created an environment for launching MPI programs. For MPICH-2, for example, this requires starting a ring of daemons. The implementation that we provided as an example is sequential and includes no parallelism - we will see in the end how to include also parallelism. Executing a parallel program requires specifying a mapping of resources, in order to assing different algorithms to different machines, define worker machines etc. This mapping is defined by an XML file called schema.xml, which, for our case, has the following structure:
<?xml version="1.0"?>
<schema> <group scheduler="0"> <node name="0" num_workers="0"> </node>
<node name="1" num_workers="0"> <runner>1</runner> </node>
<node name="2" num_workers="1">
</node>
<node name="3" num_workers="1">
</node>
</group>
</schema>
Not going into details, the XML file presented above describes a mapping which includes four nodes, the first one having the role of scheduler, the second one being the node on which the evolutionary algorithm is actually executed and the third and the fourth ones being slave nodes. Overall the mapping says that we will be launching four processes, out of which only one will be executing the evolutionary algorithm. The other node entries in the XML file have no real functionality as we have no parallelism in our program - the entries were created for you convenience, in order to provide a smooth transition to creating a parallel program.
Launching the program may be different, depending on your MPI distribution - for MPICH-2, in a console, in the paradiseo-peo/examples/lesson1 directory you have to type the following command:
mpiexec -n 4 ./tspExample .param
NOTE: the "-n 4" indicates the number of processes to be launched. The last argument, "@lesson.param", indicates a file which specifies different application specific parameters (the mapping file to be used, for example, whether to use logging or not, etc).
The result of your execution should be similar to the following:
Loading '../data/eil101.tsp'.
NAME: eil101.
COMMENT: 101-city problem (Christofides/Eilon).
TYPE: TSP.
DIMENSION: 101.
EDGE_WEIGHT_TYPE: EUC_2D.
Loading '../data/eil101.tsp'.
NAME: eil101.
COMMENT: 101-city problem (Christofides/Eilon).
EOF.
TYPE: TSP.
DIMENSION: 101.
EDGE_WEIGHT_TYPE: EUC_2D.
EOF.
Loading '../data/eil101.tsp'.
NAME: eil101.
COMMENT: 101-city problem (Christofides/Eilon).
TYPE: TSP.
DIMENSION: 101.
EDGE_WEIGHT_TYPE: EUC_2D.
EOF.
Loading '../data/eil101.tsp'.
NAME: eil101.
COMMENT: 101-city problem (Christofides/Eilon).
TYPE: TSP.
DIMENSION: 101.
EDGE_WEIGHT_TYPE: EUC_2D.
EOF.
STOP in eoGenContinue: Reached maximum number of generations [100/100]
peoSeqPopEval< Route > eaPopEval( full_eval );
with
peoParaPopEval< Route > eaPopEval( full_eval );
The second line only tells that we would like to evaluate individuals in parallel - this is very interesting if you have a time consuming fitness evaluation function. If you take another look on the schema.xml XML file you will see the last two nodes being marked as slaves (the "num_workers" attribute - these nodes will be used for computing the fitness of the individuals.At this point you only have to recompile your program and to launch it again - as we are not using a time consuming fitness fitness function, the effects might not be visible - you may increase the number of individuals to experiment.
1.4.7