EvolvingObjects
selectors.h
00001 /* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
00002 
00003   -----------------------------------------------------------------------------
00004   selectors.h
00005     A bunch of useful selector functions. They generally have three forms:
00006 
00007     template <class It>
00008     It select(It begin, It end, params, eoRng& gen = rng);
00009 
00010     template <class EOT>
00011     const EOT& select(const eoPop<EOT>& pop, params, eoRng& gen = rng);
00012 
00013     template <class EOT>
00014     EOT& select(eoPop<EOT>& pop, params, eoRng& gen = rng);
00015 
00016     where select is one of: roulette_wheel, deterministic_tournament
00017     and stochastic_tournament (at the moment).
00018 
00019  (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 2000
00020 
00021     This library is free software; you can redistribute it and/or
00022     modify it under the terms of the GNU Lesser General Public
00023     License as published by the Free Software Foundation; either
00024     version 2 of the License, or (at your option) any later version.
00025 
00026     This library is distributed in the hope that it will be useful,
00027     but WITHOUT ANY WARRANTY; without even the implied warranty of
00028     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00029     Lesser General Public License for more details.
00030 
00031     You should have received a copy of the GNU Lesser General Public
00032     License along with this library; if not, write to the Free Software
00033     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00034 
00035     Contact: todos@geneura.ugr.es, http://geneura.ugr.es
00036  */
00037 
00038 #ifndef SELECT__H
00039 #define SELECT__H
00040 
00041 #include <stdexcept>
00042 
00043 #include "eoRNG.h"
00044 #include <eoPop.h>
00050 template <class EOT>
00051 bool minimizing_fitness()
00052 {
00053     EOT eo1; // Assuming people don't do anything fancy in the default constructor!
00054     EOT eo2;
00055 
00056     /* Dear user, when the two line below do not compile you are most
00057        likely not working with scalar fitness values. In that case we're sorry
00058        but you cannot use lottery or roulette_wheel selection...
00059     */
00060 
00061 #ifdef _MSC_VER
00062     eo1.fitness( EOT::Fitness(0.0) );
00063     eo2.fitness( EOT::Fitness(1.0) );
00064 #else
00065     eo1.fitness( typename EOT::Fitness(0.0) ); // tried to cast it to an EOT::Fitness, but for some reason GNU barfs on this
00066     eo2.fitness( typename EOT::Fitness(1.0) );
00067 #endif
00068 
00069     return eo2 < eo1; // check whether we have a minimizing fitness
00070 }
00071 
00072 inline double scale_fitness(const std::pair<double, double>& _minmax, double _value)
00073 {
00074     if (_minmax.first == _minmax.second)
00075     {
00076         return 0.0; // no differences in fitness, population converged!
00077     }
00078     // else
00079 
00080     return (_value - _minmax.first) / (_minmax.second - _minmax.first);
00081 }
00082 
00083 template <class It>
00084 double sum_fitness(It begin, It end)
00085 {
00086     double sum = 0.0;
00087 
00088     for (; begin != end; ++begin)
00089     {
00090         double v = static_cast<double>(begin->fitness());
00091         if (v < 0.0)
00092             throw std::logic_error("sum_fitness: negative fitness value encountered");
00093         sum += v;
00094     }
00095 
00096     return sum;
00097 }
00098 
00099 template <class EOT>
00100 double sum_fitness(const eoPop<EOT>& _pop)
00101 {
00102     return sum_fitness(_pop.begin(), _pop.end());
00103 }
00104 
00105 template <class EOT>
00106 double sum_fitness(const eoPop<EOT>& _pop, std::pair<double, double>& _minmax)
00107 {
00108     double rawTotal, scaledTotal;
00109 
00110     typename eoPop<EOT>::const_iterator it = _pop.begin();
00111 
00112     _minmax.first = it->fitness();
00113     _minmax.second = it++->fitness();
00114 
00115     for(; it != _pop.end(); ++it)
00116     {
00117         double v = static_cast<double>(it->fitness());
00118 
00119         _minmax.first = std::min(_minmax.first, v);
00120         _minmax.second = std::max(_minmax.second, v);
00121 
00122         rawTotal += v;
00123     }
00124 
00125     if (minimizing_fitness<EOT>())
00126     {
00127         std::swap(_minmax.first, _minmax.second);
00128     }
00129 
00130     scaledTotal = 0.0;
00131 
00132     // unfortunately a second loop is neccessary to scale the fitness
00133     for (it = _pop.begin(); it != _pop.end(); ++it)
00134     {
00135         double v = scale_fitness(_minmax, static_cast<double>(it->fitness()));
00136 
00137         scaledTotal += v;
00138     }
00139 
00140     return scaledTotal;
00141 }
00142 
00143 template <class It>
00144 It roulette_wheel(It _begin, It _end, double total, eoRng& _gen = rng)
00145 {
00146 
00147     double roulette = _gen.uniform(total);
00148 
00149     if (roulette == 0.0)           // covers the case where total==0.0
00150       return _begin + _gen.random(_end - _begin); // uniform choice
00151 
00152     It i = _begin;
00153 
00154     while (roulette > 0.0)
00155     {
00156             roulette -= static_cast<double>(*(i++));
00157     }
00158 
00159     return --i;
00160 }
00161 
00162 template <class EOT>
00163 const EOT& roulette_wheel(const eoPop<EOT>& _pop, double total, eoRng& _gen = rng)
00164 {
00165     double roulette = _gen.uniform(total);
00166 
00167     if (roulette == 0.0)           // covers the case where total==0.0
00168       return _pop[_gen.random(_pop.size())]; // uniform choice
00169 
00170     typename eoPop<EOT>::const_iterator i = _pop.begin();
00171 
00172     while (roulette > 0.0)
00173     {
00174             roulette -= static_cast<double>((i++)->fitness());
00175     }
00176 
00177     return *--i;
00178 }
00179 
00180 template <class EOT>
00181 EOT& roulette_wheel(eoPop<EOT>& _pop, double total, eoRng& _gen = rng)
00182 {
00183     float roulette = _gen.uniform(total);
00184 
00185     if (roulette == 0.0)           // covers the case where total==0.0
00186       return _pop[_gen.random(_pop.size())]; // uniform choice
00187 
00188     typename eoPop<EOT>::iterator i = _pop.begin();
00189 
00190     while (roulette > 0.0)
00191     {
00192             roulette -= static_cast<double>((i++)->fitness());
00193     }
00194 
00195     return *--i;
00196 }
00197 
00198 template <class It>
00199 It deterministic_tournament(It _begin, It _end, unsigned _t_size, eoRng& _gen = rng)
00200 {
00201     It best = _begin + _gen.random(_end - _begin);
00202 
00203     for (unsigned i = 0; i < _t_size - 1; ++i)
00204     {
00205         It competitor = _begin + _gen.random(_end - _begin);
00206 
00207         if (*best < *competitor)
00208         {
00209             best = competitor;
00210         }
00211     }
00212 
00213     return best;
00214 }
00215 
00216 template <class EOT>
00217 const EOT& deterministic_tournament(const eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
00218 {
00219     return *deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen);
00220 }
00221 
00222 template <class EOT>
00223 EOT& deterministic_tournament(eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
00224 {
00225     return *deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen);
00226 }
00227 
00228 template <class It>
00229 It inverse_deterministic_tournament(It _begin, It _end, unsigned _t_size, eoRng& _gen = rng)
00230 {
00231     It worst = _begin + _gen.random(_end - _begin);
00232 
00233     for (unsigned i = 1; i < _t_size; ++i)
00234     {
00235         It competitor = _begin + _gen.random(_end - _begin);
00236 
00237         if (competitor == worst)
00238         {
00239             --i;
00240             continue; // try again
00241         }
00242 
00243         if (*competitor < *worst)
00244         {
00245             worst = competitor;
00246         }
00247     }
00248 
00249     return worst;
00250 }
00251 
00252 template <class EOT>
00253 const EOT& inverse_deterministic_tournament(const eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
00254 {
00255     return *inverse_deterministic_tournament<EOT>(_pop.begin(), _pop.end(), _t_size, _gen);
00256 }
00257 
00258 template <class EOT>
00259 EOT& inverse_deterministic_tournament(eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
00260 {
00261     return *inverse_deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen);
00262 }
00263 
00264 template <class It>
00265 It stochastic_tournament(It _begin, It _end, double _t_rate, eoRng& _gen = rng)
00266 {
00267   It i1 = _begin + _gen.random(_end - _begin);
00268   It i2 = _begin + _gen.random(_end - _begin);
00269 
00270   bool return_better = _gen.flip(_t_rate);
00271 
00272   if (*i1 < *i2)
00273   {
00274       if (return_better) return i2;
00275       // else
00276 
00277       return i1;
00278    }
00279     else
00280     {
00281       if (return_better) return i1;
00282       // else
00283     }
00284     // else
00285 
00286     return i2;
00287 }
00288 
00289 template <class EOT>
00290 const EOT& stochastic_tournament(const eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
00291 {
00292     return *stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
00293 }
00294 
00295 template <class EOT>
00296 EOT& stochastic_tournament(eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
00297 {
00298     return *stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
00299 }
00300 
00301 template <class It>
00302 It inverse_stochastic_tournament(It _begin, It _end, double _t_rate, eoRng& _gen = rng)
00303 {
00304   It i1 = _begin + _gen.random(_end - _begin);
00305   It i2 = _begin + _gen.random(_end - _begin);
00306 
00307   bool return_worse = _gen.flip(_t_rate);
00308 
00309   if (*i1 < *i2)
00310   {
00311       if (return_worse) return i1;
00312       // else
00313 
00314       return i2;
00315    }
00316     else
00317     {
00318       if (return_worse) return i2;
00319       // else
00320     }
00321     // else
00322 
00323     return i1;
00324 }
00325 
00326 template <class EOT>
00327 const EOT& inverse_stochastic_tournament(const eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
00328 {
00329     return *inverse_stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
00330 }
00331 
00332 template <class EOT>
00333 EOT& inverse_stochastic_tournament(eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
00334 {
00335     return *inverse_stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
00336 }
00337 
00340 #endif
 All Classes Namespaces Files Functions Variables Typedefs Friends