00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "factory.h"
00021 #include "gas/parallelga.h"
00022 #include "core/reproduction.h"
00023 #include "core/genome.h"
00024 #include "core/evaluation.h"
00025 #include <QThreadPool>
00026 #include <QtConcurrentMap>
00027 using namespace QtConcurrent;
00028
00029 namespace farsa {
00030
00031 ParallelGA::ParallelGA()
00032 : GeneticAlgo() {
00033 fitfunc = 0;
00034 reprod = 0;
00035 numGens = 0;
00036 currPhase = initEvaluation;
00037 numThreadv = 1;
00038 isInitialized = false;
00039 isFinalized = true;
00040 future = new QFuture<void>();
00041 }
00042
00043 ParallelGA::~ParallelGA() {
00044 foreach( ParallelGA::evaluationThread* e, evalThreads ) {
00045 delete e;
00046 }
00047 delete fitfunc;
00048 }
00049
00050 void ParallelGA::configure( ConfigurationParameters& params, QString prefix ) {
00051 setGenome( params.getObjectFromGroup<Genome>( prefix + QString( "GENOME" ) ) );
00052 setEvaluation( params.getObjectFromGroup<Evaluation>( prefix + QString( "EVALUATION" ) ) );
00053 fitfunc->setGenome( genome() );
00054 setReproduction( params.getObjectFromGroup<Reproduction>( prefix + QString( "REPRODUCTION" ) ) );
00055 setNumGenerations( params.getValue( prefix + QString( "ngenerations" ) ).toInt() );
00056 if ( numGenerations() == 0 ) {
00057 qWarning( "Setting number of Generations to ZERO!! Check your config file" );
00058 }
00059 setNumThreads( params.getValue( prefix + QString( "numThreads" ) ).toInt() );
00060 }
00061
00062 void ParallelGA::save( ConfigurationParameters& params, QString prefix ) {
00063 params.createParameter( prefix, QString("type"), "ParallelGA" );
00064 params.createParameter( prefix, QString("numThreads"), QString("%1").arg( numThreads() ) );
00065 params.createParameter( prefix, QString("ngenerations"), QString("%1").arg( numGenerations() ) );
00066
00067 fitfunc->save( params, params.createSubGroup( prefix, "EVALUATION" ) );
00068
00069 reproduction()->save( params, params.createSubGroup( prefix, "REPRODUCTION" ) );
00070
00071 genome()->save( params, params.createSubGroup( prefix, "GENOME" ) );
00072 }
00073
00074 void ParallelGA::describe( QString type ) {
00075 Descriptor d = addTypeDescription( type, "Parallel Genetic Algorithm", "Respect to SimpleGA and others type of Genetic Algorithm, the implementation of the parallelization is more efficient" );
00076 d.describeInt( "numThreads" ).limits( 1, 32 ).help( "Number of threads to parallelize the evaluation of individuals" );
00077 d.describeInt( "ngenerations" ).limits( 1, INT_MAX ).def( 1000 ).help( "Number of the generations of the evolutionary process" );
00078 d.describeSubgroup( "EVALUATION" ).type( "Evaluation" ).props( IsMandatory ).help( "Object that calculate the fitness", "Create a subclass of Evalution and code your custom fitness function" );
00079 d.describeSubgroup( "REPRODUCTION").type( "Reproduction" ).props( IsMandatory ).help( "Object that generate the new generations" );
00080 d.describeSubgroup( "GENOME" ).type( "Genome" ).props( IsMandatory ).help( "Object containing the individuals under evolution" );
00081 }
00082
00083 void ParallelGA::setNumThreads( int numThreads ) {
00084 if ( numThreads < 1 ) {
00085 qWarning( "The number of Threads must be greater than one!!" );
00086 }
00087 Q_ASSERT_X( !isInitialized && isFinalized ,
00088 "ParallelGA::setNumThreads",
00089 "This method can only called before initialize of ParallelGA" );
00090 Q_ASSERT_X( fitfunc != 0 ,
00091 "ParallelGA::setNumThreads",
00092 "This method must be called after an Evaluation object has been setted by ParallelGA::setEvaluation" );
00093 numThreadv = numThreads;
00094 return;
00095 }
00096
00097 int ParallelGA::numThreads() {
00098 return numThreadv;
00099 }
00100
00101 void ParallelGA::setEvaluation( Evaluation* fitfunc ) {
00102 this->fitfunc = fitfunc;
00103 this->fitfunc->setGA( this );
00104 }
00105
00106 Evaluation* ParallelGA::evaluationPrototype()
00107 {
00108 return fitfunc;
00109 }
00110
00111 QVector<Evaluation*> ParallelGA::evaluationPool() {
00112 QVector<Evaluation*> ev;
00113 foreach( ParallelGA::evaluationThread* e, evalThreads ) {
00114 ev.append( e->eval );
00115 }
00116 return ev;
00117 }
00118
00119 void ParallelGA::setReproduction( Reproduction* reprod ) {
00120 this->reprod = reprod;
00121 this->reprod->setGA( this );
00122 }
00123
00124 Reproduction* ParallelGA::reproduction() {
00125 return reprod;
00126 }
00127
00128 void ParallelGA::initialize() {
00129 if ( isInitialized && !isFinalized ) return;
00130 Q_ASSERT_X( fitfunc != 0 ,
00131 "ParallelGA::initialize",
00132 "You have to setup the Evaluation object of ParallelGA (Fitness Function)" );
00133 Q_ASSERT_X( reprod !=0 ,
00134 "ParallelGA::initialize",
00135 "You have to setup the Reproduction operator of ParallelGA" );
00136
00137 isInitialized = true;
00138 isFinalized = false;
00139 setGeneration( 0 );
00140 currPhase = initEvaluation;
00141 evolutionEnd = false;
00142 evaluationDone = false;
00143
00144 for( int i=0; i<evalThreads.size(); i++ ) {
00145 delete (evalThreads[i]);
00146 }
00147 evalThreads.clear();
00148 for( int i=0; i<numThreadv; i++ ) {
00149 evalThreads.append( new evaluationThread( fitfunc ) );
00150 }
00151
00152 QThreadPool::globalInstance()->setMaxThreadCount( numThreadv );
00153 }
00154
00155 void ParallelGA::gaStep() {
00156 switch( currPhase ) {
00157 case initEvaluation:
00158 for( int i=0; i<numThreadv; i++ ) {
00159 evalThreads[i]->sequence.clear();
00160 }
00161 for( int i=0; i<(int)genome()->size(); i++ ) {
00162 evalThreads[ i%numThreadv ]->sequence.append( i );
00163 }
00164 for( int i=0; i<numThreadv; i++ ) {
00165 evalThreads[i]->idSeq = 0;
00166 evalThreads[i]->id = evalThreads[i]->sequence[ evalThreads[i]->idSeq ];
00167 evalThreads[i]->eval->setGenome( genome() );
00168 }
00169 currPhase = evaluating;
00170
00171
00172 (*future) = map( evalThreads, ParallelGA::runStepWrapper );
00173 break;
00174 case evaluating:
00175
00176 if ( future->isFinished() ) {
00177 currPhase = nextGeneration_pass1;
00178 }
00179 break;
00180 case nextGeneration_pass1:
00181 qSort( genome()->begin(), genome()->end(), Genotype::rankGreaterThanComparator );
00182 updateStats();
00183 evaluationDone = true;
00184 if ( generation() < numGens ) {
00185 currPhase = nextGeneration_pass2;
00186 } else {
00187 currPhase = endEvolution;
00188 }
00189 break;
00190 case nextGeneration_pass2: {
00191
00192
00193
00194 Genome* old = genome();
00195 setGenome( reprod->reproduction( old ) );
00196 delete old;
00197 fitfunc->setGenome( genome() );
00198 evaluationDone = false;
00199 setGeneration( generation()+1 );
00200 currPhase = initEvaluation;
00201 }
00202 break;
00203 case endEvolution:
00204 finalize();
00205 break;
00206 default:
00207 qFatal( "Default switch in ParallelGA::gaStep" );
00208 break;
00209 }
00210 }
00211
00212 void ParallelGA::skipEvaluation() {
00213
00214 evaluationDone = true;
00215 if ( generation() < numGens ) {
00216 currPhase = nextGeneration_pass2;
00217 } else {
00218 currPhase = endEvolution;
00219 }
00220 }
00221
00222 void ParallelGA::finalize() {
00223 if ( isFinalized && !isInitialized ) return;
00224
00225 isInitialized = false;
00226 isFinalized = true;
00227 evolutionEnd = true;
00228 }
00229
00230 ParallelGA::evaluationThread::evaluationThread( Evaluation* eProto )
00231 : id(0) {
00232 eval = eProto->clone();
00233 eval->setGenome( eProto->GA()->genome() );
00234 eval->setGA( eProto->GA() );
00235 }
00236
00237 ParallelGA::evaluationThread::~evaluationThread() {
00238 delete eval;
00239 sequence.clear();
00240 }
00241
00242 void ParallelGA::evaluationThread::runStep() {
00243
00244 while( true ) {
00245 eval->initialize( eval->GA()->genome()->at( id ) );
00246 eval->evaluate();
00247 int nextIdSeq = idSeq + 1;
00248 eval->finalize();
00249 eval->genotype()->setRank( eval->genotype()->fitness() );
00250 if ( nextIdSeq >= sequence.size() ) {
00251 return;
00252 }
00253 idSeq = nextIdSeq;
00254 int nextId = sequence[ idSeq ];
00255 id = nextId;
00256 }
00257 }
00258
00259 void ParallelGA::runStepWrapper( ParallelGA::evaluationThread* e ) {
00260 e->runStep();
00261 }
00262
00263 }