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 <QThreadPool>
27 #include <QtConcurrentMap>
28 using namespace QtConcurrent;
29 
30 namespace farsa {
31 
32 StefanoSteadyStateGA::StefanoSteadyStateGA() :
33  GeneticAlgo(),
34  fitfunc(NULL),
35  muta(NULL),
36  curPhase(initParent),
37  curGenotype(0),
38  isInitialized(false),
39  isFinalized(true),
40  numEvaluations(),
41  cumulatedFitness(),
42  offspring(NULL)
43 {
44 }
45 
47  delete fitfunc;
48  delete muta;
49 }
50 
52  setGenome( params.getObjectFromGroup<Genome>( prefix + QString( "GENOME" ) ) );
53  setEvaluation( params.getObjectFromGroup<Evaluation>( prefix + QString( "EVALUATION" ) ) );
54  fitfunc->setGenome( genome() );
55  setMutation( params.getObjectFromGroup<Mutation>( prefix + QString( "MUTATION" ) ) );
56  setNumGenerations( params.getValue( prefix + QString( "ngenerations" ) ).toInt() );
57  if ( numGenerations() == 0 ) {
58  Logger::warning( "StefanoSteadyStateGA: Setting number of Generations to ZERO!! Check your config file" );
59  }
60 }
61 
62 void StefanoSteadyStateGA::save( ConfigurationParameters& params, QString prefix ) {
63  params.createParameter( prefix, QString("type"), "StefanoSteadyStateGA" );
64  params.createParameter( prefix, QString("ngenerations"), QString("%1").arg( numGenerations() ) );
65  //--- EVALUATION
66  fitfunc->save( params, params.createSubGroup( prefix, "EVALUATION" ) );
67  //--- MUTATION
68  mutation()->save( params, params.createSubGroup( prefix, "MUTATION" ) );
69  //--- GENOME
70  genome()->save( params, params.createSubGroup( prefix, "GENOME" ) );
71 }
72 
73 void StefanoSteadyStateGA::describe( QString type ) {
74  Descriptor d = addTypeDescription( type, "A variant of Steady State Genetic Algorithm developed by Stefano Nolfi" );
75  d.describeInt( "numThreads" ).limits( 1, 32 ).help( "Number of threads to parallelize the evaluation of individuals" );
76  d.describeInt( "ngenerations" ).limits( 1, MaxInteger ).def( 1000 ).help( "Number of the generations of the evolutionary process" );
77  d.describeSubgroup( "EVALUATION" ).type( "Evaluation" ).props( IsMandatory ).help( "Object that calculate the fitness", "Create a subclass of Evalution and code your custom fitness function" );
78  d.describeSubgroup( "MUTATION").type( "Mutation" ).props( IsMandatory ).help( "Object that mutate the genotype of an individual" );
79  d.describeSubgroup( "GENOME" ).type( "Genome" ).props( IsMandatory ).help( "Object containing the individuals under evolution" );
80 }
81 
83  this->fitfunc = fitfunc;
84  this->fitfunc->setGA( this );
85 }
86 
88 {
89  return fitfunc;
90 }
91 
92 QVector<Evaluation*> StefanoSteadyStateGA::evaluationPool() {
93  // For the moment we only have one evaluator (no threads)
94  QVector<Evaluation*> ev;
95  ev.append(fitfunc);
96  return ev;
97 }
98 
100  this->muta = mutation;
101  this->muta->setGA( this );
102 }
103 
105  return muta;
106 }
107 
109  if ( isInitialized && !isFinalized ) return;
110  Q_ASSERT_X( fitfunc != 0 ,
111  "StefanoSteadyStateGA::initialize",
112  "You have to setup the Evaluation object of StefanoSteadyStateGA (Fitness Function)" );
113  Q_ASSERT_X( muta !=0 ,
114  "StefanoSteadyStateGA::initialize",
115  "You have to setup the Mutation operator of StefanoSteadyStateGA" );
116 
117  isInitialized = true;
118  isFinalized = false;
119  setGeneration(0);
120  curPhase = initParent;
121  curGenotype = 0;
122  evolutionEnd = false;
123  evaluationDone = false;
124  delete offspring;
125  offspring = NULL;
126 
127  // Initializing mutation and evaluator
128  muta->setGenome(genome());
130  numEvaluations.fill(0, genome()->size());
131  cumulatedFitness.fill(0.0, genome()->size());
132 }
133 
135  switch (curPhase) {
136  case initParent:
137  {
139  curPhase = evalParent;
140  }
141  break;
142  case evalParent:
143  {
145  if (fitfunc->isEvaluationDone()) {
146  fitfunc->finalize();
150  curPhase = initOffspring;
151  }
152  }
153  break;
154  case initOffspring:
155  {
156  // Generating one offspring of the current genome
157  delete offspring;
161  curPhase = evalOffspring;
162  }
163  break;
164  case evalOffspring:
165  {
167  if (fitfunc->isEvaluationDone()) {
168  fitfunc->finalize();
170  curPhase = compareOffspring;
171  }
172  }
173  break;
174  case compareOffspring:
175  {
176  // Replacing the individual with the lowest fitness with the offspring. First searching
177  // the worst genome...
178  unsigned int worstGenome = 0;
179  double worstGenomeFitness = genome()->at(0)->rank();
180  for (unsigned int i = 1; i < genome()->size(); i++) {
181  if (numEvaluations[i] == 0) {
182  continue;
183  }
184  if (genome()->at(i)->rank() < worstGenomeFitness) {
185  worstGenome = i;
186  worstGenomeFitness = genome()->at(i)->rank();
187  }
188  }
189  // ... now checking if the worst genome is worse than the offspring. If so, swapping
190  if (worstGenomeFitness < offspring->rank()) {
191  *(genome()->at(worstGenome)) = *offspring;
192  cumulatedFitness[worstGenome] = offspring->rank();
193  numEvaluations[worstGenome] = 1;
194  }
195  if (curGenotype < (genome()->size() - 1)) {
196  curGenotype++;
197  curPhase = initParent;
198  } else {
199  evaluationDone = true;
200  curPhase = nextGeneration;
201  }
202  }
203  break;
204  case nextGeneration:
205  {
206  // We don't sort the genome, there is no need to
207  updateStats();
208  evaluationDone = false;
209  if (generation() < numGens) {
210  curPhase = initParent;
211  setGeneration( generation()+1 );
212  curGenotype = 0;
213  } else {
214  curPhase = endEvolution;
215  }
216  }
217  break;
218  case endEvolution:
219  {
220  finalize();
221  }
222  break;
223  default:
224  qFatal("Default switch in StefanoSteadyStateGA::gaStep");
225  break;
226  }
227 }
228 
230  // Set evaluation done, and set the new phase
231  evaluationDone = true;
232  curPhase = nextGeneration;
233 }
234 
236  if ( isFinalized && !isInitialized ) return;
237 
238  isInitialized = false;
239  isFinalized = true;
240  evolutionEnd = true;
241  delete offspring;
242  offspring = NULL;
243 
244  // Rank is already normalized
245 
246  // Finally sorting genome
247  qSort( genome()->begin(), genome()->end(), Genotype::rankGreaterThanComparator );
248 }
249 
250 } // end namespace farsa