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/nsga2.h"
00022 #include "core/reproduction.h"
00023 #include "core/genome.h"
00024 #include "core/evaluation.h"
00025 #include <cmath>
00026 #include <cfloat>
00027 #include <QThreadPool>
00028 #include <QtConcurrentMap>
00029 using namespace QtConcurrent;
00030
00031 namespace farsa {
00032
00033 NSGA2::NSGA2()
00034 : GeneticAlgo(), lastPareto() {
00035 fitfunc = 0;
00036 reprod = 0;
00037 numGens = 0;
00038 currPhase = initEvaluation;
00039 numThreadv = 1;
00040 isInitialized = false;
00041 isFinalized = true;
00042 }
00043
00044 NSGA2::~NSGA2() {
00045 foreach( NSGA2::evaluationThread* e, evalThreads ) {
00046 delete e;
00047 }
00048 delete fitfunc;
00049 }
00050
00051 void NSGA2::configure( ConfigurationParameters& params, QString prefix ) {
00052 setGenome( params.getObjectFromGroup<Genome>( prefix + QString( "GENOME" ) ) );
00053 setEvaluation( params.getObjectFromGroup<Evaluation>( prefix + QString( "EVALUATION" ) ) );
00054 fitfunc->setGenome( genome() );
00055 setReproduction( params.getObjectFromGroup<Reproduction>( prefix + QString( "REPRODUCTION" ) ) );
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 setNumThreads( params.getValue( prefix + QString( "numThreads" ) ).toInt() );
00061 }
00062
00063 void NSGA2::save( ConfigurationParameters& params, QString prefix ) {
00064 params.createParameter( prefix, QString("type"), "NSGA2" );
00065 params.createParameter( prefix, QString("numThreads"), QString("%1").arg( numThreads() ) );
00066 params.createParameter( prefix, QString("ngenerations"), QString("%1").arg( numGenerations() ) );
00067
00068 fitfunc->save( params, params.createSubGroup( prefix, "EVALUATION" ) );
00069
00070 reproduction()->save( params, params.createSubGroup( prefix, "REPRODUCTION" ) );
00071
00072 genome()->save( params, params.createSubGroup( prefix, "GENOME" ) );
00073 }
00074
00075 void NSGA2::describe( QString type ) {
00076 Descriptor d = addTypeDescription( type, "Non-dominated Sorting Genetic Algorithm version 2" );
00077 d.describeInt( "numThreads" ).limits( 1, 32 ).help( "Number of threads to parallelize the evaluation of individuals" );
00078 d.describeInt( "ngenerations" ).limits( 1, INT_MAX ).def( 1000 ).help( "Number of the generations of the evolutionary process" );
00079 d.describeSubgroup( "EVALUATION" ).type( "Evaluation" ).props( IsMandatory ).help( "Object that calculate the fitness", "Create a subclass of Evalution and code your custom fitness function" );
00080 d.describeSubgroup( "REPRODUCTION" ).type( "Reproduction" ).props( IsMandatory ).help( "Object that generate the new generations" );
00081 d.describeSubgroup( "GENOME" ).type( "Genome" ).props( IsMandatory ).help( "Object containing the individuals under evolution" );
00082 }
00083
00084 void NSGA2::setNumThreads( int numThreads ) {
00085 if ( numThreads < 1 ) {
00086 qWarning( "The number of Threads must be greater than one!!" );
00087 }
00088 Q_ASSERT_X( !isInitialized && isFinalized ,
00089 "NSGA2::setNumThreads",
00090 "This method can only called before initialize of NSGA2" );
00091 Q_ASSERT_X( fitfunc != 0 ,
00092 "NSGA2::setNumThreads",
00093 "This method must be called after an Evaluation object has been setted by NSGA2::setEvaluation" );
00094 numThreadv = numThreads;
00095 return;
00096 }
00097
00098 int NSGA2::numThreads() {
00099 return numThreadv;
00100 }
00101
00102 void NSGA2::setEvaluation( Evaluation* fitfunc ) {
00103 this->fitfunc = fitfunc;
00104 this->fitfunc->setGA( this );
00105 }
00106
00107 Evaluation* NSGA2::evaluationPrototype()
00108 {
00109 return fitfunc;
00110 }
00111
00112 QVector<Evaluation*> NSGA2::evaluationPool() {
00113 QVector<Evaluation*> ev;
00114 foreach( NSGA2::evaluationThread* e, evalThreads ) {
00115 ev.append( e->eval );
00116 }
00117 return ev;
00118 }
00119
00120 void NSGA2::setReproduction( Reproduction* reprod ) {
00121 this->reprod = reprod;
00122 this->reprod->setGA( this );
00123 }
00124
00125 Reproduction* NSGA2::reproduction() {
00126 return reprod;
00127 }
00128
00129 void NSGA2::initialize() {
00130 if ( isInitialized && !isFinalized ) return;
00131 Q_ASSERT_X( fitfunc != 0 ,
00132 "NSGA2::initialize",
00133 "You have to setup the Evaluation object of NSGA2 (Fitness Function)" );
00134 Q_ASSERT_X( reprod !=0 ,
00135 "NSGA2::initialize",
00136 "You have to setup the Reproduction operator of NSGA2" );
00137
00138 isInitialized = true;
00139 isFinalized = false;
00140 setGeneration( 0 );
00141 currPhase = initEvaluation;
00142 evolutionEnd = false;
00143 evaluationDone = false;
00144
00145 for( int i=0; i<evalThreads.size(); i++ ) {
00146 delete (evalThreads[i]);
00147 }
00148 evalThreads.clear();
00149 for( int i=0; i<numThreadv; i++ ) {
00150 evalThreads.append( new evaluationThread( this, fitfunc ) );
00151 }
00152
00153 QThreadPool::globalInstance()->setMaxThreadCount( numThreadv );
00154 }
00155
00156 void NSGA2::gaStep() {
00157 switch( currPhase ) {
00158 case initEvaluation:
00159 for( int i=0; i<numThreadv; i++ ) {
00160 evalThreads[i]->sequence.clear();
00161 }
00162 for( int i=0; i<(int)genome()->size(); i++ ) {
00163 evalThreads[ i%numThreadv ]->sequence.append( i );
00164 }
00165 for( int i=0; i<numThreadv; i++ ) {
00166 evalThreads[i]->idSeq = 0;
00167 evalThreads[i]->id = evalThreads[i]->sequence[ evalThreads[i]->idSeq ];
00168 evalThreads[i]->eval->setGenome( genome() );
00169 evalThreads[i]->eval->initialize( genome()->at( evalThreads[i]->id ) );
00170 evalThreads[i]->blocked = false;
00171 }
00172 currPhase = evaluating;
00173 break;
00174 case evaluating: {
00175 nextGeneration = true;
00176 if ( numThreadv == 1 ) {
00177
00178 evalThreads[0]->runStep();
00179 } else {
00180 QFuture<void> future = map( evalThreads, NSGA2::runStepWrapper );
00181 future.waitForFinished();
00182 }
00183 if ( nextGeneration ) {
00184 currPhase = nextGeneration_pass1;
00185 }
00186 }
00187 break;
00188 case nextGeneration_pass1: {
00189
00190
00191
00192 nsgaGenome allGenome;
00193 for( unsigned int i=0; i<lastPareto.size(); i++ ) {
00194 allGenome.append( new nsgaGenotype( lastPareto.at(i), 0, 0.0 ) );
00195 }
00196 for( unsigned int i=0; i<genome()->size(); i++ ) {
00197 allGenome.append( new nsgaGenotype( genome()->at(i), 0, 0.0 ) );
00198 }
00199
00200
00201 QVector<nsgaGenome> frontsByRank = fastNonDominatedSort( allGenome );
00202
00203
00204 unsigned int currentGenotype = 0;
00205 int numOfFronts = frontsByRank.size();
00206 int numObjs = allGenome[0]->genotype->numOfObjectives();
00207 for( int front=0; front<numOfFronts; front++ ) {
00208
00209 crowdingDistanceAssignment( frontsByRank[front] );
00210 qStableSort( frontsByRank[front].begin(), frontsByRank[front].end(), NSGA2::crowdingDistanceGreaterThan );
00211 foreach( nsgaGenotype* gen, frontsByRank[front] ) {
00212
00213 gen->genotype->setRank( 2*(numOfFronts - front) + (gen->distance/numObjs) );
00214 genome()->set( currentGenotype, gen->genotype );
00215 currentGenotype++;
00216 if ( currentGenotype == genome()->size() ) break;
00217 }
00218 if ( currentGenotype == genome()->size() ) break;
00219 }
00220
00221
00222 lastPareto = *(genome());
00223
00224 for( int i=0; i<allGenome.size(); i++ ) {
00225 delete (allGenome[i]);
00226 }
00227 updateStats();
00228 evaluationDone = true;
00229 if ( generation() < numGens ) {
00230 currPhase = nextGeneration_pass2;
00231 } else {
00232 currPhase = endEvolution;
00233 }
00234 }
00235 break;
00236 case nextGeneration_pass2: {
00237
00238
00239
00240 Genome* old = genome();
00241 setGenome( reprod->reproduction( old ) );
00242 delete old;
00243 fitfunc->setGenome( genome() );
00244 evaluationDone = false;
00245 setGeneration( generation()+1 );
00246 currPhase = initEvaluation;
00247 }
00248 break;
00249 case endEvolution:
00250 finalize();
00251 break;
00252 default:
00253 qFatal( "Default switch in NSGA2::gaStep" );
00254 break;
00255 }
00256 }
00257
00258 void NSGA2::skipEvaluation() {
00259
00260 evaluationDone = true;
00261 if ( generation() < numGens ) {
00262 currPhase = nextGeneration_pass2;
00263 } else {
00264 currPhase = endEvolution;
00265 }
00266 }
00267
00268 void NSGA2::finalize() {
00269 if ( isFinalized && !isInitialized ) return;
00270
00271 isInitialized = false;
00272 isFinalized = true;
00273 evolutionEnd = true;
00274 }
00275
00276 QVector<NSGA2::nsgaGenome> NSGA2::fastNonDominatedSort( nsgaGenome& pareto ) {
00277 QMap<nsgaGenotype*, nsgaGenome> dominatedBy;
00278 QVector<nsgaGenome> frontsByRank;
00279 frontsByRank.resize(1);
00280
00281 for( int p=0; p<pareto.size(); p++ ) {
00282
00283 pareto[p]->dominationCounter = 0;
00284 for( int q=0; q<pareto.size(); q++ ) {
00285 if ( p==q ) continue;
00286 if ( pareto[q]->genotype->dominatedBy( pareto[p]->genotype ) ) {
00287
00288 dominatedBy[ pareto[p] ].append( pareto[q] );
00289 } else if ( pareto[p]->genotype->dominatedBy( pareto[q]->genotype ) ) {
00290 pareto[p]->dominationCounter++;
00291 }
00292 }
00293
00294 if ( pareto[p]->dominationCounter == 0 ) {
00295 pareto[p]->rank = 0;
00296 frontsByRank[0].append( pareto[p] );
00297 }
00298 }
00299
00300 bool done = false;
00301 int currentFront = 0;
00302 while( !done ) {
00303 nsgaGenome newFront;
00304 for( int i=0; i<frontsByRank[currentFront].size(); i++ ) {
00305 nsgaGenotype* p = frontsByRank[currentFront][i];
00306 nsgaGenome pDominate = dominatedBy[p];
00307 for( int q=0; q<pDominate.size(); q++ ) {
00308 pDominate[q]->dominationCounter--;
00309 if ( pDominate[q]->dominationCounter == 0 ) {
00310 pDominate[q]->rank = currentFront+1;
00311 newFront.append( pDominate[q] );
00312 }
00313 }
00314 }
00315 currentFront++;
00316 if ( newFront.isEmpty() ) {
00317 done = true;
00318 } else {
00319 frontsByRank.append( newFront );
00320 }
00321 }
00322 int total = 0;
00323 for( int i=0; i<frontsByRank.size(); i++ ) {
00324 total += frontsByRank[i].size();
00325 }
00326 return frontsByRank;
00327 }
00328
00329 void NSGA2::crowdingDistanceAssignment( nsgaGenome& genome ) {
00330 int dimGenome = genome.size();
00331 if ( dimGenome == 0 ) return;
00332 int numObjs = genome[0]->genotype->numOfObjectives();
00333
00334 QVector<double> fmax;
00335 QVector<double> fmin;
00336 fmax.resize( numObjs );
00337 fmin.resize( numObjs );
00338 for( int i=0; i<numObjs; i++ ) {
00339 fmax[i] = genome[0]->genotype->objective( i );
00340 fmin[i] = genome[0]->genotype->objective( i );
00341 }
00342
00343 for( int i=0; i<dimGenome; i++ ) {
00344 genome[i]->distance = 0;
00345 for( int m=0; m<numObjs; m++ ) {
00346 fmax[m] = qMax( fmax[m], genome[i]->genotype->objective(m) );
00347 fmin[m] = qMin( fmin[m], genome[i]->genotype->objective(m) );
00348 }
00349 }
00350
00351 nObjectiveGreaterThan objCompare;
00352 for( int m=0; m<numObjs; m++ ) {
00353
00354 objCompare.currentObjective = m;
00355 qStableSort( genome.begin(), genome.end(), objCompare );
00356
00357
00358 genome[0]->distance = numObjs;
00359 genome.last()->distance = numObjs;
00360 for( int i=1; i<dimGenome-1; i++ ) {
00361 double m1 = genome[i+1]->genotype->objective(m);
00362 double m2 = genome[i-1]->genotype->objective(m);
00363 genome[i]->distance += fabs(m1-m2)/(fmax[m]-fmin[m]);
00364
00365 if ( genome[i]->distance != genome[i]->distance ) {
00366 genome[i]->distance = 0.0;
00367 }
00368 }
00369 }
00370 }
00371
00372 NSGA2::evaluationThread::evaluationThread( NSGA2* p, Evaluation* eProto )
00373 : parent(p), id(0), blocked(false) {
00374 eval = eProto->clone();
00375 eval->setGenome( p->genome() );
00376 eval->setGA( p );
00377 }
00378
00379 NSGA2::evaluationThread::~evaluationThread() {
00380 delete eval;
00381 sequence.clear();
00382 }
00383
00384 void NSGA2::evaluationThread::runStep() {
00385 if ( blocked ) {
00386 return;
00387 }
00388
00389 parent->nextGeneration = false;
00390 eval->evaluateStep();
00391 if ( eval->isEvaluationDone() ) {
00392 int nextIdSeq = idSeq + 1;
00393 eval->finalize();
00394 if ( nextIdSeq >= sequence.size() ) {
00395 blocked = true;
00396 return;
00397 }
00398 idSeq = nextIdSeq;
00399 int nextId = sequence[ idSeq ];
00400 id = nextId;
00401 eval->initialize( parent->genome()->at( id ) );
00402 }
00403 }
00404
00405 void NSGA2::runStepWrapper( NSGA2::evaluationThread* e ) {
00406 e->runStep();
00407 }
00408
00409 }