ga/src/gas/stefanosteadystatega.cpp

00001 /********************************************************************************
00002  *  FARSA Genetic Algorithm Library                                             *
00003  *  Copyright (C) 2007-2009 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #include "factory.h"
00021 #include "gas/stefanosteadystatega.h"
00022 #include "core/reproduction.h"
00023 #include "core/genome.h"
00024 #include "core/evaluation.h"
00025 #include "logger.h"
00026 #include <QThreadPool>
00027 #include <QtConcurrentMap>
00028 using namespace QtConcurrent;
00029 
00030 namespace farsa {
00031 
00032 StefanoSteadyStateGA::StefanoSteadyStateGA() :
00033     GeneticAlgo(),
00034     fitfunc(NULL),
00035     muta(NULL),
00036     curPhase(initParent),
00037     curGenotype(0),
00038     isInitialized(false),
00039     isFinalized(true),
00040     numEvaluations(),
00041     cumulatedFitness(),
00042     offspring(NULL)
00043 {
00044 }
00045 
00046 StefanoSteadyStateGA::~StefanoSteadyStateGA() {
00047     delete fitfunc;
00048     delete muta;
00049 }
00050 
00051 void StefanoSteadyStateGA::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     setMutation( params.getObjectFromGroup<Mutation>( prefix + QString( "MUTATION" ) ) );
00056     setNumGenerations( params.getValue( prefix + QString( "ngenerations" ) ).toInt() );
00057     if ( numGenerations() == 0 ) {
00058         Logger::warning( "StefanoSteadyStateGA: Setting number of Generations to ZERO!! Check your config file" );
00059     }
00060 }
00061 
00062 void StefanoSteadyStateGA::save( ConfigurationParameters& params, QString prefix ) {
00063     params.createParameter( prefix, QString("type"), "StefanoSteadyStateGA" );
00064     params.createParameter( prefix, QString("ngenerations"), QString("%1").arg( numGenerations() ) );
00065     //--- EVALUATION
00066     fitfunc->save( params, params.createSubGroup( prefix, "EVALUATION" ) );
00067     //--- MUTATION
00068     mutation()->save( params, params.createSubGroup( prefix, "MUTATION" ) );
00069     //--- GENOME
00070     genome()->save( params, params.createSubGroup( prefix, "GENOME" ) );
00071 }
00072 
00073 void StefanoSteadyStateGA::describe( QString type ) {
00074     Descriptor d = addTypeDescription( type, "A variant of Steady State Genetic Algorithm developed by Stefano Nolfi" );
00075     d.describeInt( "numThreads" ).limits( 1, 32 ).help( "Number of threads to parallelize the evaluation of individuals" );
00076     d.describeInt( "ngenerations" ).limits( 1, MaxInteger ).def( 1000 ).help( "Number of the generations of the evolutionary process" );
00077     d.describeSubgroup( "EVALUATION" ).type( "Evaluation" ).props( IsMandatory ).help( "Object that calculate the fitness", "Create a subclass of Evalution and code your custom fitness function" );
00078     d.describeSubgroup( "MUTATION").type( "Mutation" ).props( IsMandatory ).help( "Object that mutate the genotype of an individual" );
00079     d.describeSubgroup( "GENOME" ).type( "Genome" ).props( IsMandatory ).help( "Object containing the individuals under evolution" );
00080 }
00081 
00082 void StefanoSteadyStateGA::setEvaluation( Evaluation* fitfunc ) {
00083     this->fitfunc = fitfunc;
00084     this->fitfunc->setGA( this );
00085 }
00086 
00087 Evaluation* StefanoSteadyStateGA::evaluationPrototype()
00088 {
00089     return fitfunc;
00090 }
00091 
00092 QVector<Evaluation*> StefanoSteadyStateGA::evaluationPool() {
00093     // For the moment we only have one evaluator (no threads)
00094     QVector<Evaluation*> ev;
00095     ev.append(fitfunc);
00096     return ev;
00097 }
00098 
00099 void StefanoSteadyStateGA::setMutation( Mutation* mutation ) {
00100     this->muta = mutation;
00101     this->muta->setGA( this );
00102 }
00103 
00104 Mutation* StefanoSteadyStateGA::mutation() {
00105     return muta;
00106 }
00107 
00108 void StefanoSteadyStateGA::initialize() {
00109     if ( isInitialized && !isFinalized ) return;
00110     Q_ASSERT_X( fitfunc != 0 ,
00111             "StefanoSteadyStateGA::initialize",
00112             "You have to setup the Evaluation object of StefanoSteadyStateGA (Fitness Function)" );
00113     Q_ASSERT_X( muta !=0 ,
00114             "StefanoSteadyStateGA::initialize",
00115             "You have to setup the Mutation operator of StefanoSteadyStateGA" );
00116 
00117     isInitialized = true;
00118     isFinalized = false;
00119     setGeneration(0);
00120     curPhase = initParent;
00121     curGenotype = 0;
00122     evolutionEnd = false;
00123     evaluationDone = false;
00124     delete offspring;
00125     offspring = NULL;
00126 
00127     // Initializing mutation and evaluator
00128     muta->setGenome(genome());
00129     fitfunc->setGenome(genome());
00130     numEvaluations.fill(0, genome()->size());
00131     cumulatedFitness.fill(0.0, genome()->size());
00132 }
00133 
00134 void StefanoSteadyStateGA::gaStep() {
00135     switch (curPhase) {
00136         case initParent:
00137             {
00138                 fitfunc->initialize(genome()->at(curGenotype));
00139                 curPhase = evalParent;
00140             }
00141             break;
00142         case evalParent:
00143             {
00144                 fitfunc->evaluateStep();
00145                 if (fitfunc->isEvaluationDone()) {
00146                     fitfunc->finalize();
00147                     cumulatedFitness[curGenotype] += fitfunc->genotype()->fitness();
00148                     numEvaluations[curGenotype]++;
00149                     fitfunc->genotype()->setRank(cumulatedFitness[curGenotype] / double(numEvaluations[curGenotype]));
00150                     curPhase = initOffspring;
00151                 }
00152             }
00153             break;
00154         case initOffspring:
00155             {
00156                 // Generating one offspring of the current genome
00157                 delete offspring;
00158                 offspring = genome()->at(curGenotype)->clone();
00159                 muta->mutate(offspring);
00160                 fitfunc->initialize(offspring);
00161                 curPhase = evalOffspring;
00162             }
00163             break;
00164         case evalOffspring:
00165             {
00166                 fitfunc->evaluateStep();
00167                 if (fitfunc->isEvaluationDone()) {
00168                     fitfunc->finalize();
00169                     offspring->setRank(offspring->fitness());
00170                     curPhase = compareOffspring;
00171                 }
00172             }
00173             break;
00174         case compareOffspring:
00175             {
00176                 // Replacing the individual with the lowest fitness with the offspring. First searching
00177                 // the worst genome...
00178                 unsigned int worstGenome = 0;
00179                 double worstGenomeFitness = genome()->at(0)->rank();
00180                 for (unsigned int i = 1; i < genome()->size(); i++) {
00181                     if (numEvaluations[i] == 0) {
00182                         continue;
00183                     }
00184                     if (genome()->at(i)->rank() < worstGenomeFitness) {
00185                         worstGenome = i;
00186                         worstGenomeFitness = genome()->at(i)->rank();
00187                     }
00188                 }
00189                 // ... now checking if the worst genome is worse than the offspring. If so, swapping
00190                 if (worstGenomeFitness < offspring->rank()) {
00191                     *(genome()->at(worstGenome)) = *offspring;
00192                     cumulatedFitness[worstGenome] = offspring->rank();
00193                     numEvaluations[worstGenome] = 1;
00194                 }
00195                 if (curGenotype < (genome()->size() - 1)) {
00196                     curGenotype++;
00197                     curPhase = initParent;
00198                 } else {
00199                     evaluationDone = true;
00200                     curPhase = nextGeneration;
00201                 }
00202             }
00203             break;
00204         case nextGeneration:
00205             {
00206                 // We don't sort the genome, there is no need to
00207                 updateStats();
00208                 evaluationDone = false;
00209                 if (generation() < numGens) {
00210                     curPhase = initParent;
00211                     setGeneration( generation()+1 );
00212                     curGenotype = 0;
00213                 } else {
00214                     curPhase = endEvolution;
00215                 }
00216             }
00217             break;
00218         case endEvolution:
00219             {
00220                 finalize();
00221             }
00222             break;
00223         default:
00224             qFatal("Default switch in StefanoSteadyStateGA::gaStep");
00225             break;
00226     }
00227 }
00228 
00229 void StefanoSteadyStateGA::skipEvaluation() {
00230     // Set evaluation done, and set the new phase
00231     evaluationDone = true;
00232     curPhase = nextGeneration;
00233 }
00234 
00235 void StefanoSteadyStateGA::finalize() {
00236     if ( isFinalized && !isInitialized ) return;
00237 
00238     isInitialized = false;
00239     isFinalized = true;
00240     evolutionEnd = true;
00241     delete offspring;
00242     offspring = NULL;
00243 
00244     // Rank is already normalized
00245 
00246     // Finally sorting genome
00247     qSort( genome()->begin(), genome()->end(), Genotype::rankGreaterThanComparator );
00248 }
00249 
00250 } // end namespace farsa