EvolvingObjects
|
00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- 00002 00003 //----------------------------------------------------------------------------- 00004 // eoStochasticUniversalSelect.h 00005 // (c) Maarten Keijzer 2003 00006 /* 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library; if not, write to the Free Software 00019 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 00021 Contact: todos@geneura.ugr.es, http://geneura.ugr.es 00022 Marc.Schoenauer@polytechnique.fr 00023 mkeijzer@cs.vu.nl 00024 */ 00025 //----------------------------------------------------------------------------- 00026 00027 #ifndef eoStochasticUniversalSelect_h 00028 #define eoStochasticUniversalSelect_h 00029 00030 //----------------------------------------------------------------------------- 00031 00032 #include <utils/eoRNG.h> 00033 #include <eoSelectOne.h> 00034 #include <utils/selectors.h> 00035 #include <eoPop.h> 00036 00043 template <class EOT> class eoStochasticUniversalSelect: public eoSelectOne<EOT> 00044 { 00045 public: 00047 eoStochasticUniversalSelect(const eoPop<EOT>& pop = eoPop<EOT>()) 00048 { 00049 if (minimizing_fitness<EOT>()) 00050 throw std::logic_error("eoStochasticUniversalSelect: minimizing fitness"); 00051 } 00052 00053 void setup(const eoPop<EOT>& _pop) 00054 { 00055 if (_pop.size() == 0) return; 00056 00057 std::vector<typename EOT::Fitness> cumulative(_pop.size()); 00058 00059 cumulative[0] = _pop[0].fitness(); 00060 for (unsigned i = 1; i < _pop.size(); ++i) 00061 { 00062 cumulative[i] = _pop[i].fitness() + cumulative[i-1]; 00063 } 00064 00065 indices.reserve(_pop.size()); 00066 indices.resize(0); 00067 00068 double fortune = rng.uniform() * cumulative.back(); 00069 double step = cumulative.back() / double(_pop.size()); 00070 00071 unsigned i = std::upper_bound(cumulative.begin(), cumulative.end(), fortune) - cumulative.begin(); 00072 00073 while (indices.size() < _pop.size()) { 00074 00075 while (cumulative[i] < fortune) {i++;} // linear search is good enough as we average one step each time 00076 00077 indices.push_back(i); 00078 fortune += step; 00079 if (fortune >= cumulative.back()) { // start at the beginning 00080 fortune -= cumulative.back(); 00081 i = 0; 00082 } 00083 } 00084 // shuffle 00085 for (int i = indices.size() - 1; i > 0; --i) { 00086 int j = rng.random(i+1); 00087 std::swap(indices[i], indices[j]); 00088 } 00089 } 00090 00093 const EOT& operator()(const eoPop<EOT>& _pop) 00094 { 00095 if (indices.empty()) setup(_pop); 00096 00097 unsigned index = indices.back(); 00098 indices.pop_back(); 00099 return _pop[index]; 00100 } 00101 00102 private : 00103 00104 typedef std::vector<unsigned> IndexVec; 00105 IndexVec indices; 00106 }; 00110 #endif