# eoReduce.h

    00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
    00002
    00003 //-----------------------------------------------------------------------------
    00004 // eoReduce.h
    00005 //   Base class for population-merging classes
    00006 // (c) GeNeura Team, 1998
    00007 /*
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Lesser General Public
    00010    License as published by the Free Software Foundation; either
    00011    version 2 of the License, or (at your option) any later version.
    00012
    00013    This library is distributed in the hope that it will be useful,
    00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016    Lesser General Public License for more details.
    00017
    00018    You should have received a copy of the GNU Lesser General Public
    00019    License along with this library; if not, write to the Free Software
    00020    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00021
    00022    Contact: todos@geneura.ugr.es, http://geneura.ugr.es
    00023  */
    00024 //-----------------------------------------------------------------------------
    00025
    00026 #ifndef eoReduce_h
    00027 #define eoReduce_h
    00028
    00029 //-----------------------------------------------------------------------------
    00030
    00031 #include <iostream>
    00032
    00033 // EO includes
    00034 #include <eoPop.h>     // eoPop
    00035 #include <eoFunctor.h>  // eoReduce
    00036 #include <utils/selectors.h>
    00037
    00045 template<class EOT> class eoReduce: public eoBF<eoPop<EOT>&, unsigned, void>
    00046 {};
    00047
    00049 template <class EOT> class eoTruncate : public eoReduce<EOT>
    00050 {
    00051     void operator()(eoPop<EOT>& _newgen, unsigned _newsize)
    00052     {
    00053         if (_newgen.size() == _newsize)
    00054             return;
    00055         if (_newgen.size() < _newsize)
    00056           throw std::logic_error("eoTruncate: Cannot truncate to a larger size!\n");
    00057
    00058         _newgen.nth_element(_newsize);
    00059         _newgen.resize(_newsize);
    00060     }
    00061 };
    00062
    00064 template <class EOT> class eoRandomReduce : public eoReduce<EOT>
    00065 {
    00066     void operator()(eoPop<EOT>& _newgen, unsigned _newsize)
    00067     {
    00068         if (_newgen.size() == _newsize)
    00069             return;
    00070         if (_newgen.size() < _newsize)
    00071           throw std::logic_error("eoRandomReduce: Cannot truncate to a larger size!\n");
    00072
    00073         // shuffle the population, then trucate
    00074         _newgen.shuffle();
    00075         _newgen.resize(_newsize);
    00076     }
    00077 };
    00078
    00083 template <class EOT> class eoEPReduce : public eoReduce<EOT>
    00084 {
    00085 public:
    00086 typedef typename EOT::Fitness Fitness;
    00087
    00088   eoEPReduce(unsigned _t_size  ):
    00089     t_size(_t_size)
    00090   {
    00091     if (t_size < 2)
    00092       {
    00093         std::cout << "Warning: EP tournament size should be >= 2. Adjusted" << std::endl;
    00094         t_size = 2;
    00095       }
    00096   }
    00097
    00099   // compares the scores
    00100   // uses the fitness if scores are equals ????
    00101   typedef std::pair<float, typename eoPop<EOT>::iterator>  EPpair;
    00102   struct Cmp {
    00103     bool operator()(const EPpair a, const EPpair b) const
    00104     {
    00105       if (b.first == a.first)
    00106         return  (*b.second < *a.second);
    00107       return b.first < a.first;
    00108     }
    00109   };
    00110
    00111
    00112   void operator()(eoPop<EOT>& _newgen, unsigned _newsize)
    00113   {
    00114     unsigned int presentSize = _newgen.size();
    00115
    00116     if (presentSize == _newsize)
    00117             return;
    00118         if (presentSize < _newsize)
    00119           throw std::logic_error("eoTruncate: Cannot truncate to a larger size!\n");
    00120         std::vector<EPpair> scores(presentSize);
    00121         for (unsigned i=0; i<presentSize; i++)
    00122           {
    00123             scores[i].second = _newgen.begin()+i;
    00124             Fitness fit = _newgen[i].fitness();
    00125             for (unsigned itourn = 0; itourn < t_size; ++itourn)
    00126               {
    00127                 const EOT & competitor = _newgen[rng.random(presentSize)];
    00128                 if (fit > competitor.fitness())
    00129                   scores[i].first += 1;
    00130                 else if (fit == competitor.fitness())
    00131                   scores[i].first += 0.5;
    00132               }
    00133           }
    00134
    00135         // now we have the scores
    00136         typename std::vector<EPpair>::iterator it = scores.begin() + _newsize;
    00137         std::nth_element(scores.begin(), it, scores.end(), Cmp());
    00138         // sort(scores.begin(), scores.end(), Cmp());
    00139         unsigned j;
    00140 //      std::cout << "Les scores apres tri\n";
    00141 //      for (j=0; j<scores.size(); j++)
    00142 //        {
    00143 //          std::cout << scores[j].first << " " << *scores[j].second << std::endl;
    00144 //        }
    00145         eoPop<EOT> tmPop;
    00146         for (j=0; j<_newsize; j++)
    00147           {
    00148             tmPop.push_back(*scores[j].second);
    00149           }
    00150         _newgen.swap(tmPop);
    00151         // erase does not work, but I'm sure there is a way in STL to mark
    00152         // and later delete all inside a std::vector ??????
    00153         // this would avoid all copies here
    00154
    00155 //      it = scores.begin() + _newsize;
    00156 //      while (it < scores.end())
    00157 //        _newgen.erase(it->second);
    00158     }
    00159 private:
    00160   unsigned t_size;
    00161 };
    00162
    00166 template <class EOT>
    00167 class eoLinearTruncate : public eoReduce<EOT>
    00168 {
    00169   void operator()(eoPop<EOT>& _newgen, unsigned _newsize)
    00170   {
    00171     unsigned oldSize = _newgen.size();
    00172     if (oldSize == _newsize)
    00173       return;
    00174     if (oldSize < _newsize)
    00175       throw std::logic_error("eoLinearTruncate: Cannot truncate to a larger size!\n");
    00176     for (unsigned i=0; i<oldSize - _newsize; i++)
    00177       {
    00178         typename eoPop<EOT>::iterator it = _newgen.it_worse_element();
    00179         _newgen.erase(it);
    00180       }
    00181   }
    00182 };
    00183
    00187 template <class EOT>
    00188 class eoDetTournamentTruncate : public eoReduce<EOT>
    00189 {
    00190 public:
    00191   eoDetTournamentTruncate(unsigned _t_size):
    00192     t_size(_t_size)
    00193   {
    00194     if (t_size < 2)
    00195       {
    00196         std::cout << "Warning, Size for eoDetTournamentTruncate adjusted to 2\n";
    00197         t_size = 2;
    00198       }
    00199   }
    00200
    00201   void operator()(eoPop<EOT>& _newgen, unsigned _newsize)
    00202   {
    00203     unsigned oldSize = _newgen.size();
    00204     if (_newsize == 0)
    00205       {
    00206         _newgen.resize(0);
    00207         return;
    00208       }
    00209     if (oldSize == _newsize)
    00210       return;
    00211     if (oldSize < _newsize)
    00212       throw std::logic_error("eoDetTournamentTruncate: Cannot truncate to a larger size!\n");
    00213
    00214     // Now OK to erase some losers
    00215     for (unsigned i=0; i<oldSize - _newsize; i++)
    00216       {
    00217         //OLDCODE EOT & eo = inverse_deterministic_tournament<EOT>(_newgen, t_size);
    00218         //OLDCODE _newgen.erase(&eo);
    00219
    00220         // Jeroen Eggermont stdc++v3  patch
    00221         // in the new code from stdc++v3 an iterator from a container<T> is no longer an pointer to T
    00222         // Because eo already contained a fuction using eoPop<EOT>::iterator's we will use the following
    00223
    00224         _newgen.erase( inverse_deterministic_tournament(_newgen.begin(), _newgen.end(), t_size) );
    00225
    00226       }
    00227   }
    00228 private:
    00229   unsigned t_size;
    00230 };
    00231
    00235 template <class EOT>
    00236 class eoStochTournamentTruncate : public eoReduce<EOT>
    00237 {
    00238 public:
    00239   eoStochTournamentTruncate(double _t_rate):
    00240     t_rate(_t_rate)
    00241   {
    00242     if (t_rate <= 0.5)
    00243       {
    00244         std::cout << "Warning, Rate for eoStochTournamentTruncate adjusted to 0.51\n";
    00245         t_rate = 0.51;
    00246       }
    00247     if (t_rate > 1)
    00248       {
    00249         std::cout << "Warning, Rate for eoStochTournamentTruncate adjusted to 1\n";
    00250         t_rate = 1;
    00251       }
    00252   }
    00253
    00254   void operator()(eoPop<EOT>& _newgen, unsigned _newsize)
    00255   {
    00256     unsigned oldSize = _newgen.size();
    00257     if (_newsize == 0)
    00258       {
    00259         _newgen.resize(0);
    00260         return;
    00261       }
    00262     if (oldSize == _newsize)
    00263       return;
    00264     if (oldSize < _newsize)
    00265       throw std::logic_error("eoStochTournamentTruncate: Cannot truncate to a larger size!\n");
    00266     // Now OK to erase some losers
    00267     for (unsigned i=0; i<oldSize - _newsize; i++)
    00268       {
    00269         //OLDCODE EOT & eo = inverse_stochastic_tournament<EOT>(_newgen, t_rate);
    00270         //OLDCODE _newgen.erase(&eo);
    00271
    00272         // Jeroen Eggermont stdc++v3  patch
    00273         // in the new code from stdc++v3 an iterator from a container<T> is no longer an pointer to T
    00274         // Because eo already contained a fuction using eoPop<EOT>::iterator's we will use the following
    00275
    00276         _newgen.erase( inverse_stochastic_tournament(_newgen.begin(), _newgen.end(), t_rate) );
    00277
    00278
    00279       }
    00280   }
    00281
    00282 private:
    00283   double t_rate;
    00284 };
    00285
    00286 //-----------------------------------------------------------------------------
    00287
    00288 #endif