EvolvingObjects
|
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