stefanosteadystatega.cpp
1 /********************************************************************************
2  * FARSA Genetic Algorithm Library *
3  * Copyright (C) 2007-2009 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #include "factory.h"
21 #include "gas/stefanosteadystatega.h"
22 #include "core/reproduction.h"
23 #include "core/genome.h"
24 #include "core/evaluation.h"
25 #include "logger.h"
26 #include "configurationhelper.h"
27 #include <QThreadPool>
28 #include <QtConcurrentMap>
29 using namespace QtConcurrent;
30 
31 namespace farsa {
32 
33 StefanoSteadyStateGA::StefanoSteadyStateGA() :
34  GeneticAlgo(),
35  fitfunc(NULL),
36  muta(NULL),
37  curPhase(initParent),
38  curGenotype(0),
39  isInitialized(false),
40  isFinalized(true),
41  numEvaluations(),
42  cumulatedFitness(),
43  offspring(NULL)
44 {
45 }
46 
48  delete fitfunc;
49  delete muta;
50 }
51 
53  setGenome( params.getObjectFromGroup<Genome>( prefix + QString( "GENOME" ) ) );
54  setEvaluation( params.getObjectFromGroup<Evaluation>( prefix + QString( "EVALUATION" ) ) );
55  fitfunc->setGenome( genome() );
56  setMutation( params.getObjectFromGroup<Mutation>( prefix + QString( "MUTATION" ) ) );
57  setNumGenerations( ConfigurationHelper::getInt( params, prefix + QString( "ngenerations" ), 1000 ) );
58 }
59 
60 void StefanoSteadyStateGA::save( ConfigurationParameters& params, QString prefix ) {
61  params.createParameter( prefix, QString("type"), "StefanoSteadyStateGA" );
62  params.createParameter( prefix, QString("ngenerations"), QString("%1").arg( numGenerations() ) );
63  //--- EVALUATION
64  fitfunc->save( params, params.createSubGroup( prefix, "EVALUATION" ) );
65  //--- MUTATION
66  mutation()->save( params, params.createSubGroup( prefix, "MUTATION" ) );
67  //--- GENOME
68  genome()->save( params, params.createSubGroup( prefix, "GENOME" ) );
69 }
70 
71 void StefanoSteadyStateGA::describe( QString type ) {
72  Descriptor d = addTypeDescription( type, "A variant of Steady State Genetic Algorithm developed by Stefano Nolfi" );
73  d.describeInt( "numThreads" ).limits( 1, 32 ).help( "Number of threads to parallelize the evaluation of individuals" );
74  d.describeInt( "ngenerations" ).limits( 1, MaxInteger ).def( 1000 ).help( "Number of the generations of the evolutionary process" );
75  d.describeSubgroup( "EVALUATION" ).type( "Evaluation" ).props( IsMandatory ).help( "Object that calculate the fitness", "Create a subclass of Evalution and code your custom fitness function" );
76  d.describeSubgroup( "MUTATION").type( "Mutation" ).props( IsMandatory ).help( "Object that mutate the genotype of an individual" );
77  d.describeSubgroup( "GENOME" ).type( "Genome" ).props( IsMandatory ).help( "Object containing the individuals under evolution" );
78 }
79 
81  this->fitfunc = fitfunc;
82  this->fitfunc->setGA( this );
83 }
84 
86 {
87  return fitfunc;
88 }
89 
90 QVector<Evaluation*> StefanoSteadyStateGA::evaluationPool() {
91  // For the moment we only have one evaluator (no threads)
92  QVector<Evaluation*> ev;
93  ev.append(fitfunc);
94  return ev;
95 }
96 
98  this->muta = mutation;
99  this->muta->setGA( this );
100 }
101 
103  return muta;
104 }
105 
107  if ( isInitialized && !isFinalized ) return;
108  Q_ASSERT_X( fitfunc != 0 ,
109  "StefanoSteadyStateGA::initialize",
110  "You have to setup the Evaluation object of StefanoSteadyStateGA (Fitness Function)" );
111  Q_ASSERT_X( muta !=0 ,
112  "StefanoSteadyStateGA::initialize",
113  "You have to setup the Mutation operator of StefanoSteadyStateGA" );
114 
115  isInitialized = true;
116  isFinalized = false;
117  setGeneration(0);
118  curPhase = initParent;
119  curGenotype = 0;
120  evolutionEnd = false;
121  evaluationDone = false;
122  delete offspring;
123  offspring = NULL;
124 
125  getIODelegate()->recoverData(this);
126 
127  // Initializing mutation and evaluator
128  muta->setGenome(genome());
131  numEvaluations.fill(0, genome()->size());
132  cumulatedFitness.fill(0.0, genome()->size());
133 }
134 
136  switch (curPhase) {
137  case initParent:
138  {
140  curPhase = evalParent;
141  }
142  break;
143  case evalParent:
144  {
146  if (fitfunc->isEvaluationDone()) {
147  fitfunc->finalize();
151  curPhase = initOffspring;
152  }
153  }
154  break;
155  case initOffspring:
156  {
157  // Generating one offspring of the current genome
158  delete offspring;
162  curPhase = evalOffspring;
163  }
164  break;
165  case evalOffspring:
166  {
168  if (fitfunc->isEvaluationDone()) {
169  fitfunc->finalize();
171  curPhase = compareOffspring;
172  }
173  }
174  break;
175  case compareOffspring:
176  {
177  // Replacing the individual with the lowest fitness with the offspring. First searching
178  // the worst genome...
179  unsigned int worstGenome = 0;
180  double worstGenomeFitness = genome()->at(0)->rank();
181  for (unsigned int i = 1; i < genome()->size(); i++) {
182  if (numEvaluations[i] == 0) {
183  continue;
184  }
185  if (genome()->at(i)->rank() < worstGenomeFitness) {
186  worstGenome = i;
187  worstGenomeFitness = genome()->at(i)->rank();
188  }
189  }
190  // ... now checking if the worst genome is worse than the offspring. If so, swapping
191  if (worstGenomeFitness < offspring->rank()) {
192  *(genome()->at(worstGenome)) = *offspring;
193  cumulatedFitness[worstGenome] = offspring->rank();
194  numEvaluations[worstGenome] = 1;
195  }
196  if (curGenotype < (genome()->size() - 1)) {
197  curGenotype++;
198  curPhase = initParent;
199  } else {
200  evaluationDone = true;
201  curPhase = nextGeneration;
202  }
203  }
204  break;
205  case nextGeneration:
206  {
207  // We don't sort the genome, there is no need to
208  updateStats();
209  evaluationDone = false;
212  getIODelegate()->saveData(this);
213  if (generation() < numGens) {
214  curPhase = initParent;
215  setGeneration( generation()+1 );
217  curGenotype = 0;
218  } else {
219  curPhase = endEvolution;
220  }
221  }
222  break;
223  case endEvolution:
224  {
225  finalize();
226  }
227  break;
228  default:
229  qFatal("Default switch in StefanoSteadyStateGA::gaStep");
230  break;
231  }
232 }
233 
235  // Set evaluation done, and set the new phase
236  evaluationDone = true;
237  curPhase = nextGeneration;
238 }
239 
241  if ( isFinalized && !isInitialized ) return;
242 
243  isInitialized = false;
244  isFinalized = true;
245  evolutionEnd = true;
246  delete offspring;
247  offspring = NULL;
248 
249  // Rank is already normalized
250 
251  // Finally sorting genome
252  qSort( genome()->begin(), genome()->end(), Genotype::rankGreaterThanComparator );
253 }
254 
255 } // end namespace farsa