00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "gas/laralga.h"
00021 #include "core/mutation.h"
00022 #include "core/genome.h"
00023 #include "evaluations/multitrials.h"
00024 #include "factory.h"
00025 #include <QThreadPool>
00026 #include <QtConcurrentMap>
00027 using namespace QtConcurrent;
00028
00029 namespace farsa {
00030
00031 LaralGA::LaralGA()
00032 : GeneticAlgo() {
00033 fitfunc = 0;
00034 muta = 0;
00035 currGenotype = 0;
00036 numGens = 0;
00037 nreproducing = 0;
00038 noffspring = 0;
00039 nelitism = 0;
00040 elitismEnabled = 0;
00041 currPhase = initEvaluation;
00042 numThreadv = 1;
00043 isInitialized = false;
00044 isFinalized = true;
00045 }
00046
00047 LaralGA::~LaralGA() {
00048
00049 }
00050
00051 void LaralGA::configure( ConfigurationParameters& params, QString prefix ) {
00052 setGenome( params.getObjectFromGroup<Genome>( prefix + QString( "GENOME" ) ) );
00053 setFitnessFunction( params.getObjectFromGroup<MultiTrials>( prefix + QString( "EVALUATION" ) ) );
00054 fitfunc->setGenome( genome() );
00055 setMutation( params.getObjectFromGroup<Mutation>( prefix + QString("REPRODUCTION/MUTATION") ) );
00056 setNumGenerations( params.getValue( prefix + QString( "ngenerations" ) ).toInt() );
00057 if ( numGenerations() == 0 ) {
00058 qWarning( "Setting number of Generations to ZERO!! Check your config file" );
00059 }
00060 const QString reproductionGroup( prefix + QString( "REPRODUCTION" ) + ConfigurationParameters::GroupSeparator() );
00061 int nreproduce = params.getValue( reproductionGroup + QString( "nreproducing" ) ).toInt();
00062 bool useElitism = ! (params.getValue( reproductionGroup + QString( "elitism" ) ).compare( "true", Qt::CaseInsensitive));
00063 int nelitism = params.getValue( reproductionGroup + QString( "nelited" ) ).toInt();
00064 setReproduceParams( nreproduce, useElitism, nelitism );
00065 setNumThreads( params.getValue( prefix + QString( "numThreads" ) ).toInt() );
00066 }
00067
00068 void LaralGA::save( ConfigurationParameters& params, QString prefix ) {
00069 params.createParameter( prefix, QString("type"), "LaralGA" );
00070 params.createParameter( prefix, QString("numThreads"), QString("%1").arg(numThreads()) );
00071 params.createParameter( prefix, QString("ngenerations"), QString("%1").arg( numGenerations() ) );
00072
00073 fitnessFunction()->save( params, params.createSubGroup( prefix, "EVALUATION" ) );
00074
00075 QString reproductionGroup = params.createSubGroup( prefix, "REPRODUCTION" );
00076 params.createParameter( reproductionGroup, "nreproducing", QString("%1").arg( numReproducing() ) );
00077 params.createParameter( reproductionGroup, "elitism", isElitismEnabled() ? "true" : "false" );
00078 params.createParameter( reproductionGroup, "nelited", QString("%1").arg( numElitism() ) );
00079 mutation()->save( params, params.createSubGroup( reproductionGroup, "MUTATION" ) );
00080
00081 genome()->save( params, params.createSubGroup( prefix, "GENOME" ) );
00082 }
00083
00084 void LaralGA::describe( QString type ) {
00085 Descriptor d = addTypeDescription( type, "A simple Genetic Algorithm used at LARAL laboratory", "This Genetic Algorithm runs more than one replica of the evolutionary process each of them use a reproduction schema without crossover and with a deterministic rank selection" );
00086 d.describeInt( "numThreads" ).limits( 1, 32 ).help( "Number of threads to parallelize the evaluation of individuals" );
00087 d.describeInt( "ngenerations" ).limits( 1, INT_MAX ).props( IsMandatory ).help( "Number of generations per evolutionary process" );
00088 d.describeSubgroup( "EVALUATION" ).type( "MultiTrials" ).props( IsMandatory ).help( "Object that calculate the fitness", "Create a subclass of MultiTrials and code your custom fitness function" );
00089 SubgroupDescriptor r = d.describeSubgroup( "REPRODUCTION" ).props( IsMandatory ).help( "Paramenters that affect the reproduction process" );
00090 r.describeInt( "nreproducing" ).limits( 1, INT_MAX ).def(10).props( IsMandatory ).help( "Number of the most fitted individual to reproduce" );
00091 r.describeBool( "elitism" ).def( false ).help( "Enable the elitism", "When true, the nelited most fitted individual will be copied exactly (without mutation) to the new generations" );
00092 r.describeInt( "nelited" ).limits( 1, INT_MAX ).def( 10 ).help( "Number of individual to copy exactly to the new generation" );
00093 r.describeSubgroup( "MUTATION" ).type( "Mutation" ).props( IsMandatory ).help( "The type of mutation to use" );
00094 d.describeSubgroup( "GENOME" ).type( "Genome" ).props( IsMandatory ).help( "The genome containing the individual under evolution" );
00095 }
00096
00097 void LaralGA::setNumThreads( int numThreads ) {
00098 if ( numThreads < 1 ) {
00099 qWarning( "The number of Threads must be greater than one!!" );
00100 }
00101 Q_ASSERT_X( !isInitialized && isFinalized ,
00102 "LaralGA::setNumThreads",
00103 "This method can only called before initialize of LaralGA" );
00104 Q_ASSERT_X( fitfunc != 0 ,
00105 "LaralGA::setNumThreads",
00106 "This method must be called after a MultiTrials object has been setted by LaralGA::setFitnessFunction" );
00107 numThreadv = numThreads;
00108 return;
00109 }
00110
00111 int LaralGA::numThreads() {
00112 return numThreadv;
00113 }
00114
00115 void LaralGA::setFitnessFunction( MultiTrials* fitfunc ) {
00116 this->fitfunc = fitfunc;
00117 this->fitfunc->setGA( this );
00118 }
00119
00120 Evaluation* LaralGA::evaluationPrototype()
00121 {
00122 return fitfunc;
00123 }
00124
00125 QVector<Evaluation*> LaralGA::evaluationPool() {
00126 QVector<Evaluation*> ev;
00127 foreach( LaralGA::evaluationThread* e, evalThreads ) {
00128 ev.append( e->eval );
00129 }
00130 return ev;
00131 }
00132
00133 MultiTrials* LaralGA::fitnessFunction() {
00134 return fitfunc;
00135 }
00136
00137 void LaralGA::setMutation( Mutation* mutate ) {
00138 this->muta = mutate;
00139 this->muta->setGA( this );
00140 }
00141
00142 Mutation* LaralGA::mutation() {
00143 return muta;
00144 }
00145
00146 void LaralGA::setReproduceParams( int nreproducing, bool useElitism, int nelitism ) {
00147 this->nreproducing = nreproducing;
00148 elitismEnabled = useElitism;
00149 this->nelitism = nelitism;
00150 noffspring = genomev->size()/nreproducing;
00151
00152 Q_ASSERT_X( noffspring * nreproducing == (int)(genomev->size()),
00153 "LaralGA::setReproduceParams",
00154 QString( "nreproducing must be divisible by genome dimension: %1 %2 %3" ).arg(noffspring).arg(nreproducing).arg(genomev->size()).toAscii().data() );
00155 if ( useElitism ) {
00156 Q_ASSERT_X( useElitism && ( nelitism <= nreproducing ),
00157 "LaralGA::setReproduceParams",
00158 "The number of elited genotype must be less or equal to selected ones" );
00159 }
00160 }
00161
00162 int LaralGA::numReproducing() {
00163 return nreproducing;
00164 }
00165
00166 int LaralGA::numOffspring() {
00167 return noffspring;
00168 }
00169
00170 int LaralGA::numElitism() {
00171 return nelitism;
00172 }
00173
00174 bool LaralGA::isElitismEnabled() {
00175 return elitismEnabled;
00176 }
00177
00178 void LaralGA::initialize() {
00179 if ( isInitialized && !isFinalized ) return;
00180 Q_ASSERT_X( fitfunc != 0 ,
00181 "LaralGA::initialize",
00182 "You have to setup the FitnessFunction of LaralGA" );
00183 Q_ASSERT_X( muta !=0 ,
00184 "LaralGA::initialize",
00185 "You have to setup the Mutate operator of LaralGA" );
00186
00187 isInitialized = true;
00188 isFinalized = false;
00189 currGenotype = 0;
00190 setGeneration( 0 );
00191 currPhase = initEvaluation;
00192 evolutionEnd = false;
00193 evaluationDone = false;
00194
00195 for( int i=0; i<evalThreads.size(); i++ ) {
00196 delete (evalThreads[i]);
00197 }
00198 evalThreads.clear();
00199 for( int i=0; i<numThreadv; i++ ) {
00200 evalThreads.append( new evaluationThread( this, fitfunc ) );
00201 }
00202
00203 QThreadPool::globalInstance()->setMaxThreadCount( numThreadv );
00204 }
00205
00206 void LaralGA::gaStep() {
00207 switch( currPhase ) {
00208 case initEvaluation:
00209 for( int i=0; i<numThreadv; i++ ) {
00210 evalThreads[i]->sequence.clear();
00211 }
00212 for( int i=0; i<(int)genome()->size(); i++ ) {
00213 evalThreads[ i%numThreadv ]->sequence.append( i );
00214 }
00215 for( int i=0; i<numThreadv; i++ ) {
00216 evalThreads[i]->idSeq = 0;
00217 evalThreads[i]->id = evalThreads[i]->sequence[ evalThreads[i]->idSeq ];
00218 evalThreads[i]->eval->setGenome( genome() );
00219 evalThreads[i]->eval->initialize( genome()->at( evalThreads[i]->id ) );
00220 evalThreads[i]->blocked = false;
00221 }
00222 currPhase = evaluating;
00223 break;
00224 case evaluating: {
00225 nextGeneration = true;
00226 if ( numThreadv == 1 ) {
00227
00228 evalThreads[0]->runStep();
00229 } else {
00230 QFuture<void> future = map( evalThreads, LaralGA::runStepWrapper );
00231 future.waitForFinished();
00232 }
00233 if ( nextGeneration ) {
00234 currPhase = nextGeneration_pass1;
00235 }
00236 }
00237 break;
00238 case nextGeneration_pass1:
00239 qSort( genome()->begin(), genome()->end(), Genotype::rankGreaterThanComparator );
00240 updateStats();
00241 evaluationDone = true;
00242 if ( generation() < numGens ) {
00243 currPhase = nextGeneration_pass2;
00244 } else {
00245 currPhase = endEvolution;
00246 }
00247 break;
00248 case nextGeneration_pass2:
00249
00250
00251
00252 setGeneration( generation()+1 );
00253 evaluationDone = false;
00254 createNextGeneration();
00255 currPhase = initEvaluation;
00256 break;
00257 case endEvolution:
00258 finalize();
00259 qWarning( "Finish Evolution" );
00260 break;
00261 default:
00262 qFatal( "Default switch in LaralGA::gaStep" );
00263 break;
00264 }
00265 }
00266
00267 void LaralGA::skipEvaluation() {
00268
00269 evaluationDone = true;
00270 if ( generation() < numGens ) {
00271 currPhase = nextGeneration_pass2;
00272 } else {
00273 currPhase = endEvolution;
00274 }
00275 }
00276
00277 void LaralGA::finalize() {
00278 if ( isFinalized && !isInitialized ) return;
00279
00280 isInitialized = false;
00281 isFinalized = true;
00282 evolutionEnd = true;
00283 }
00284
00285 void LaralGA::createNextGeneration() {
00286 Genome& genref = *(genome());
00287 muta->setGenome( genome() );
00288 for( int i=0; i<nreproducing; i++ ) {
00289
00290 for( int j=1; j<noffspring; j++ ) {
00291
00292 int id = i + j*nreproducing;
00293
00294 genref[id]->assign( genref[i] );
00295 muta->mutate( genref[id] );
00296 }
00297 }
00298
00299 int startId = 0;
00300 if ( elitismEnabled ) {
00301 startId = nelitism;
00302 }
00303 for( int i=startId; i<nreproducing; i++ ) {
00304 muta->mutate( genref[i] );
00305 }
00306 }
00307
00308 LaralGA::evaluationThread::evaluationThread( LaralGA* p, MultiTrials* eProto )
00309 : parent(p), id(0), blocked(false) {
00310 eval = eProto->clone();
00311 eval->setGenome( p->genome() );
00312 eval->setGA( p );
00313 }
00314
00315 LaralGA::evaluationThread::~evaluationThread() {
00316 delete eval;
00317 sequence.clear();
00318 }
00319
00320 void LaralGA::evaluationThread::runStep() {
00321 if ( blocked ) {
00322 return;
00323 }
00324
00325 parent->nextGeneration = false;
00326 eval->evaluateStep();
00327 if ( eval->isEvaluationDone() ) {
00328 int nextIdSeq = idSeq + 1;
00329 eval->finalize();
00330 eval->genotype()->setRank( eval->genotype()->fitness() );
00331 if ( nextIdSeq >= sequence.size() ) {
00332 blocked = true;
00333 return;
00334 }
00335 idSeq = nextIdSeq;
00336 int nextId = sequence[ idSeq ];
00337 id = nextId;
00338 eval->initialize( parent->genome()->at( id ) );
00339 }
00340 }
00341
00342 void LaralGA::runStepWrapper( LaralGA::evaluationThread* e ) {
00343 e->runStep();
00344 }
00345
00346 }