Main Page | Namespace List | Class List | File List | Class Members | File Members

Population.h

Go to the documentation of this file.
00001 //
00002 // $Id: Population.h,v 1.3 2004/11/29 14:37:10 min Exp min $
00003 //
00004 
00005 #ifndef __Population_h
00006 #define __Population_h
00007 
00008 #include <iostream>
00009 #include <vector>
00010 #include <assert.h>
00011 #include "Indiv.h"
00012 #include "MyRandom.h"
00013 
00014 using namespace std;
00015 
00016 // change to '#define EVODEBUG(x) x' to get runtime debugging info for this class
00017 #define EVODEBUG(x)
00018 
00019 
00020 
00021 
00022 
00023 template<class ParTraits>
00024 class Population
00025 {
00026 
00027 public:
00028 
00029   Population();
00030   ~Population();
00031 
00032   void init(vector<double>& parameter_ranges);
00033 
00034   void add_indiv(Indiv *indiv_p);
00035   
00036   int get_size() { return indivs.size(); }
00037 
00038   void select_parents();
00039   void shuffle();
00040 
00041   void recombine();
00042   
00043   void make_children(Indiv *parent1, Indiv *parent2);
00044 
00045   void mutate();
00046   
00047   void select_survivors();
00048   
00049   int get_best_index() { return best_index; }
00050   void set_best_index(int new_index) { best_index = new_index; }
00051   
00052   inline Indiv * operator[](int index) const { return indivs[index]; }
00053 
00054   
00055 private:
00056 
00057   std::vector<Indiv *> indivs;
00058 
00059   int nr_parameters;
00060 
00061   int best_index;
00062   
00063   
00064 };  // Population class
00065 
00066 
00067 
00068 //
00069 // Population class definition
00070 //
00071 
00072 template<class ParTraits>
00073 Population<ParTraits>::Population()
00074 {
00075 
00076 }  // constructor
00077 
00078 
00079 
00080 template<class ParTraits>
00081 Population<ParTraits>::~Population()
00082 {
00083   int pop_size = indivs.size();
00084   for(int i=0; i < pop_size; i++) delete indivs[i];
00085   
00086 }  // destructor
00087 
00088 
00089 
00090 template<class ParTraits>
00091 void
00092 Population<ParTraits>::init(vector<double>& parameter_ranges)
00093 {
00094   nr_parameters = parameter_ranges.size() / 2;
00095   
00096   if (ParTraits::VERBOSITY) {
00097     cout << "Population::init, creating " << ParTraits::POPULATION_SIZE << " individuals" << endl;
00098     cout << "  nr_parameters = " << nr_parameters << endl;
00099   }
00100   
00101   for(int i=0; i < ParTraits::POPULATION_SIZE; i++) {
00102     Indiv *ind_p = new Indiv(nr_parameters);
00103     ind_p->init(parameter_ranges);
00104     add_indiv(ind_p);
00105   }  // for
00106   
00107 }  // Population::init
00108 
00109 
00110 
00111 template<class ParTraits>
00112 void
00113 Population<ParTraits>::add_indiv(Indiv *indiv_p)
00114 {
00115   indivs.push_back(indiv_p);
00116 
00117 }  // Population::add_indiv
00118 
00119 
00120 
00121 template<class ParTraits>
00122 void
00123 Population<ParTraits>::make_children(Indiv *parent1, Indiv *parent2)
00124 {
00125   EVODEBUG(cout << "Population::make_children" << endl);
00126   
00127   for(int i=0; i < ParTraits::NR_CHILDREN; i++) {
00128     Indiv *ind_p = new Indiv(nr_parameters);
00129     add_indiv(ind_p);
00130 
00131     //
00132     // do the recombination here!
00133     //
00134     ind_p->recombine(parent1, parent2);
00135     
00136   }  // for
00137 
00138 }  // Population::make_children
00139 
00140 
00141 
00142 template<class ParTraits>
00143 void
00144 Population<ParTraits>::mutate()
00145 {
00146   //  cout << "Population::mutate" << endl;
00147   for(unsigned int i=0; i < indivs.size(); i++) {
00148     indivs[i]->mutate(i == 0);
00149   }
00150   
00151 }  // Population::mutate
00152 
00153 
00154 
00155 
00156 template<class ParTraits>
00157 void
00158 Population<ParTraits>::select_survivors()
00159 {
00160   EVODEBUG(cout << "Population::select_survivors" << endl);
00161 
00162   int pop_size = indivs.size();
00163   int *keep = new int[pop_size];
00164   for(int i=0; i < pop_size; i++) keep[i] = 0;
00165   
00166   // mu + lambda rule, find the mu best ones and keep those
00167   for(int i=0; i < ParTraits::POPULATION_SIZE; i++) {
00168     double best_fitness = 1e6;
00169     int cur_best_index = -1;
00170     for(int j=0; j < pop_size; j++) {
00171       double fitness = indivs[j]->get_fitness();
00172       if ((fitness < best_fitness) && !keep[j]) {
00173         best_fitness = fitness;
00174         cur_best_index = j;
00175       }
00176     }  // for
00177     keep[cur_best_index] = 1;
00178     if (i == 0) best_index = cur_best_index;  // keep overall best index
00179     
00180   }  // for
00181 
00182   int nr_removed = 0;
00183   int index = 0;
00184   for(int i=0; i < pop_size; i++) {
00185     if (keep[i]) {
00186       // swap them so they'll get properly deleted below
00187       Indiv *ind_p = indivs[index];
00188       indivs[index] = indivs[i];
00189       indivs[i] = ind_p;
00190       
00191       if (i == best_index) best_index = index;  // !!!
00192       index++;
00193     }
00194     else
00195       nr_removed++;
00196     
00197   }  // for
00198 
00199   delete[] keep;
00200   
00201   int new_size = ParTraits::POPULATION_SIZE;
00202   for(int i = new_size; i < pop_size; i++) delete indivs[i];
00203   indivs.erase(indivs.begin() + new_size, indivs.end());
00204   
00205   EVODEBUG(cout << "done, removed " << nr_removed << " individuals, population size now " << indivs.size() << endl);
00206   
00207 }  // Population::select_survivors
00208 
00209 
00210 
00211 template<class ParTraits>
00212 void
00213 Population<ParTraits>::select_parents()
00214 {
00215   int pop_size = indivs.size();
00216   EVODEBUG(cout << "Population::select_parents, population size is " << pop_size << endl);
00217   for(int i=0; i < pop_size; i++) indivs[i]->set_parent(0);
00218   
00219   int nr_desired_parents = (int)(floor(pop_size * ParTraits::PARENTS_PERCENTAGE / 100.0 + 0.5));
00220   if ((nr_desired_parents % 2) == 1) {
00221     // make sure nr_desired_parents is even, and not larger than the population size
00222     if (nr_desired_parents < pop_size) nr_desired_parents++;
00223     else nr_desired_parents--;
00224   }
00225 
00226   // compute average fitness (used to compute a threshold below)
00227   double sum = 0;
00228   for(int i=0; i < pop_size; i++) sum += indivs[i]->get_fitness();
00229   double avg = sum / pop_size;
00230   //  cout << "  average fitness: " << avg << endl;
00231 
00232   int nr_selected = 0;
00233 
00234   // nr passes through the main while loop, used for the acceptance threshold below
00235   int nr_passes = 0;  
00236   while((nr_selected < nr_desired_parents) && (nr_passes < ParTraits::MAX_PARENT_SELECTION_PASSES)) {
00237 
00238     // first compute a random permutation of all parents
00239     int *candidates = new int[pop_size];
00240     for(int i=0; i < pop_size; i++) candidates[i] = i;
00241     for(int i=0; i < pop_size; i++) {
00242       int rand_index = rand() % pop_size;
00243       int temp = candidates[rand_index];
00244       candidates[rand_index] = candidates[i];
00245       candidates[i] = temp;
00246     }  // for
00247 
00248     // now try them all and pick each as parent depending on their fitness level
00249 
00250     for(int i=0; i < pop_size; i++) {
00251       if (!indivs[i]->is_parent()) {
00252         double value = indivs[i]->get_fitness();
00253         // threshold should now also depend on main loop index
00254         double threshold = value / (2 * avg);
00255         double random = MyRandom::uniform(0, 1) * (nr_passes + 1);
00256         if (random > threshold) {
00257           indivs[i]->set_parent(1);
00258           nr_selected++;
00259         }
00260       }  // if not parent yet
00261     }  // for each individual
00262 
00263     nr_passes++;  // increases the likelihood that a parent will be picked
00264     
00265   }  // while, still need to selected parents
00266 
00267   EVODEBUG(cout << "Population::select_parents: selected " << nr_desired_parents << " parents" << endl);
00268 
00269 }  // Population::select_parents
00270 
00271 
00272 
00273 template<class ParTraits>
00274 void
00275 Population<ParTraits>::shuffle()
00276 {
00277   //  cout << "Population::shuffle" << endl;
00278 
00279   int pop_size = indivs.size();
00280   int nr_remaining = pop_size;
00281   for(int i=0; i < pop_size; i++) {
00282     int rand_index = rand() % nr_remaining + i;
00283     assert((rand_index >= 0) && (rand_index < pop_size));
00284     
00285     Indiv *temp_p = indivs[i];
00286     indivs[i] = indivs[rand_index];
00287     indivs[rand_index] = temp_p;
00288 
00289     nr_remaining--;
00290   }  // for
00291   
00292 }  // Population::shuffle
00293 
00294 
00295 
00296 template<class ParTraits>
00297 void
00298 Population<ParTraits>::recombine()
00299 {
00300   //  cout << "Population::recombine" << endl;
00301 
00302   int p[2];
00303   int nr_parents = 0;
00304   
00305   int pop_size = indivs.size();
00306   for(int i=0; i < pop_size; i += 2) {
00307 
00308     if (indivs[i]->is_parent()) {
00309       p[nr_parents] = i;
00310       nr_parents++;
00311       // make children as soon as we find two parents
00312       if (nr_parents == 2) {
00313         make_children(indivs[p[0]], indivs[p[1]]);
00314         nr_parents = 0;
00315       }
00316     }  // if individual is a parent
00317 
00318   }  // for
00319   
00320 }  // Population::recombine
00321 
00322 
00323 
00324 #endif
00325 
00326 

Generated on Tue Jun 14 11:37:51 2005 for evofunc by doxygen 1.3.6