diff --git a/eo/src/Makefile.am b/eo/src/Makefile.am index 306370783..0365acb7a 100644 --- a/eo/src/Makefile.am +++ b/eo/src/Makefile.am @@ -4,7 +4,7 @@ ## ############################################################################### -SUBDIRS = es ga gp utils other +SUBDIRS = es ga utils other CPPFLAGS = -O2 lib_LIBRARIES = libeo.a diff --git a/eo/src/eo b/eo/src/eo index c4674416b..62c8de89f 100644 --- a/eo/src/eo +++ b/eo/src/eo @@ -30,8 +30,20 @@ // some defines to make things easier to get at first sight +// tunigni the amount of output using a boolean argument: +// true should always mean more output #define eo_verbose true #define eo_no_verbose false +// to be used in selection / replacement procedures to indicate whether +// the argument (rate, a double) shoudl be treated as a rate (number=rate*popSize) +// or as an absolute integer (number=rate regardless of popsize). +// the default value shoudl ALWAYS be true (eo_as_a_rate). +// +// this construct is mandatory because in some cases you might not know the +// population size that will enter the replacement for instance - so you +// cannot simply have a pre-computed (double) rate of 1/popSize +#define eo_is_a_rate true +#define eo_is_an_integer false //----------------------------------------------------------------------------- #include @@ -86,13 +98,24 @@ #include #include -// Selection and reproduction stuff +// Selection #include #include #include #include #include +#include +#include +#include + +// Replacement +// #include +#include +#include +#include + +// Variation #include #include #include diff --git a/eo/src/eoEasyEA.h b/eo/src/eoEasyEA.h index d23bac1bf..dc066601b 100644 --- a/eo/src/eoEasyEA.h +++ b/eo/src/eoEasyEA.h @@ -119,24 +119,23 @@ template class eoEasyEA: public eoAlgo { try { + unsigned pSize = _pop.size(); breed(_pop, offspring); apply(eval, offspring); - - replace(_pop, offspring); - if (offspring.size() < _pop.size()) + replace(_pop, offspring); // after replace, the new pop. is in _pop + + if (pSize > _pop.size()) throw runtime_error("Population shrinking!"); - else if (offspring.size() > _pop.size()) + else if (pSize < _pop.size()) throw runtime_error("Population growing!"); - _pop.swap(offspring); - } catch (exception& e) { string s = e.what(); - s.append( " in eoSelectTransformReduce "); + s.append( " in eoEasyEA"); throw runtime_error( s ); } } // while diff --git a/eo/src/eoMerge.h b/eo/src/eoMerge.h index 4261d2495..ae8b00bea 100644 --- a/eo/src/eoMerge.h +++ b/eo/src/eoMerge.h @@ -50,32 +50,55 @@ template class eoMerge: public eoBF&, eoPop class eoElitism : public eoMerge { - public : - eoElitism(unsigned _howmany) : howmany(_howmany) {} - - void operator()(const eoPop& _pop, eoPop& offspring) - { - if (howmany == 0) - return; - - if (howmany > _pop.size()) - throw std::logic_error("Elite larger than population"); - - vector result; - _pop.nth_element(howmany, result); - - for (size_t i = 0; i < result.size(); ++i) - { - offspring.push_back(*result[i]); - } - } - - private : - unsigned howmany; +public : + eoElitism(double _rate, bool _interpret_as_rate = true): + rate(0), howmany(0) + { + if (_interpret_as_rate) + { + if ( (_rate<0) || (_rate>1) ) + throw std::logic_error("eoElitism: rate shoud be in [0,1]"); + rate = _rate; + } + else + { + if (_rate<0) + throw std::logic_error("Negative number of offspring in eoElitism!"); + howmany = (unsigned int)_rate; + if (howmany != _rate) + cout << "Warning: Number of guys to merge in eoElitism was rounded"; + } + } + + void operator()(const eoPop& _pop, eoPop& _offspring) + { + if ((howmany == 0) && (rate == 0.0)) + return; + unsigned howmanyLocal; + if (howmany == 0) // rate is specified + howmanyLocal = (unsigned int) (rate * _pop.size()); + else + howmanyLocal = howmany; + + if (howmanyLocal > _pop.size()) + throw std::logic_error("Elite larger than population"); + + vector result; + _pop.nth_element(howmanyLocal, result); + + for (size_t i = 0; i < result.size(); ++i) + { + _offspring.push_back(*result[i]); + } + } + +private : + double rate; + unsigned howmany; }; /** @@ -93,18 +116,17 @@ Very elitist class, copies entire population into next gen template class eoPlus : public eoMerge { public : - void operator()(const eoPop& _pop, eoPop& offspring) + void operator()(const eoPop& _pop, eoPop& _offspring) { - offspring.reserve(offspring.size() + _pop.size()); + _offspring.reserve(_offspring.size() + _pop.size()); for (size_t i = 0; i < _pop.size(); ++i) { - offspring.push_back(_pop[i]); + _offspring.push_back(_pop[i]); } } private : - unsigned howmany; }; //----------------------------------------------------------------------------- diff --git a/eo/src/eoMergeReduce.h b/eo/src/eoMergeReduce.h new file mode 100644 index 000000000..6a7aebf0b --- /dev/null +++ b/eo/src/eoMergeReduce.h @@ -0,0 +1,98 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoMergeReduce.h + (c) Maarten Keijzer, GeNeura Team, 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + */ +//----------------------------------------------------------------------------- + +#ifndef _eoMergeReduce_h +#define _eoMergeReduce_h + + +//----------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +//----------------------------------------------------------------------------- +/** +Replacement strategies that combine en eoMerge and an eoReduce. + +@classes: eoMergeReduce, the base (pure abstract) class + eoPlusReplacement the ES plus strategy + eoCommaReplacement the ES comma strategy +*/ + +/** +eoMergeReduce: abstract replacement strategy that is just an application of +an embedded merge, followed by an embedded reduce +*/ +template +class eoMergeReduce : public eoReplacement +{ + public: + eoMergeReduce(eoMerge& _merge, eoReduce& _reduce) : + merge(_merge), reduce(_reduce) + {} + + void operator()(eoPop& _parents, eoPop& _offspring) + { + merge(_parents, _offspring); // parents untouched, result in offspring + reduce(_offspring, _parents.size()); + _parents.swap(_offspring); + } + + private : + eoMerge& merge; + eoReduce& reduce; +}; + +/** +ES type of replacement strategy: first add parents to population, then truncate +*/ +template +class eoPlusReplacement : public eoMergeReduce +{ + public : + eoPlusReplacement() : eoMergeReduce(plus, truncate) {} + + private : + eoPlus plus; + eoTruncate truncate; +}; + +/** +ES type of replacement strategy: ignore parents, truncate offspring +*/ +template +class eoCommaReplacement : public eoMergeReduce +{ + public : + eoCommaReplacement() : eoMergeReduce(no_elite, truncate) {} + + private : + eoNoElitism no_elite; + eoTruncate truncate; +}; + + +#endif diff --git a/eo/src/eoPop.h b/eo/src/eoPop.h index 22bd93b5c..cfb6b9814 100644 --- a/eo/src/eoPop.h +++ b/eo/src/eoPop.h @@ -123,6 +123,7 @@ class eoPop: public vector, public eoObject, public eoPersistent std::sort(begin(), end(), greater()); } + // creates a vector pointing to the individuals in descending order void sort(vector& result) const { result.resize(size()); @@ -132,9 +133,37 @@ class eoPop: public vector, public eoObject, public eoPersistent std::sort(result.begin(), result.end(), Cmp()); } + // returns an iterator to the best individual DOES NOT MOVE ANYBODY + eoPop::iterator it_best_element() + { + typename eoPop::const_iterator it = max_element(begin(), end()); + return it; + } + + // returns an iterator to the best individual DOES NOT MOVE ANYBODY + const EOT & best_element() const + { + typename eoPop::const_iterator it = max_element(begin(), end()); + return (*it); + } + + // returns a const reference to the worse individual DOES NOT MOVE ANYBODY + const EOT & worse_element() const + { + typename eoPop::const_iterator it = min_element(begin(), end()); + return (*it); + } + +// returns an iterator to the worse individual DOES NOT MOVE ANYBODY + eoPop::iterator it_worse_element() + { + typename eoPop::iterator it = min_element(begin(), end()); + return it; + } + /** slightly faster algorithm than sort to find all individuals that are better - than the nth individual + than the nth individual. INDIVIDUALS ARE MOVED AROUND in the pop. */ eoPop::iterator nth_element(int nth) { @@ -168,6 +197,7 @@ class eoPop: public vector, public eoObject, public eoPersistent std::nth_element(result.begin(), it, result.end(), Cmp()); } + // does STL swap with other pop void swap(eoPop& other) { std::swap(static_cast& >(*this), static_cast& >(other)); diff --git a/eo/src/eoReduce.h b/eo/src/eoReduce.h index 150963ef1..138dc59f4 100644 --- a/eo/src/eoReduce.h +++ b/eo/src/eoReduce.h @@ -33,26 +33,199 @@ // EO includes #include // eoPop #include // eoReduce +#include /** * eoReduce: .reduce the new generation to the specified size + At the moment, limited to truncation - with 2 different methods, + one that sorts the whole population, and one that repeatidely kills + the worst. Ideally, we should be able to choose at run-time!!! */ -template class eoReduce: public eoBF&, unsigned, void> +template class eoReduce: public eoBF&, unsigned, void> {}; +/** truncation method using sort */ template class eoTruncate : public eoReduce { void operator()(eoPop& _newgen, unsigned _newsize) { if (_newgen.size() == _newsize) return; + if (_newgen.size() < _newsize) + throw std::logic_error("eoTruncate: Cannot truncate to a larger size!\n"); _newgen.nth_element(_newsize); _newgen.resize(_newsize); } }; +/** +EP truncation method (some global stochastic tournament + sort) +Softer selective pressure than pure truncate +*/ +template class eoEPReduce : public eoReduce +{ +public: +typedef typename EOT::Fitness Fitness; + + eoEPReduce(unsigned _t_size): + t_size(_t_size) + { + if (t_size < 2) + { // warning, error? + t_size = 2; + } + } + + /// helper struct for comparing on pairs + typedef pair::iterator> EPpair; + struct Cmp { + bool operator()(const EPpair a, const EPpair b) const + { return b.first < a.first; } + }; + + + void operator()(eoPop& _newgen, unsigned _newsize) + { + unsigned int presentSize = _newgen.size(); + if (presentSize == _newsize) + return; + if (presentSize < _newsize) + throw std::logic_error("eoTruncate: Cannot truncate to a larger size!\n"); + vector scores(presentSize); + for (unsigned i=0; i competitor.fitness()) + scores[i].first += 1; + else if (fit == competitor.fitness()) + scores[i].first += 0.5; + } + } + // now we have the scores + typename vector::iterator it = scores.begin() + _newsize; + std::nth_element(scores.begin(), it, scores.end(), Cmp()); + it = scores.begin() + _newsize; // just in case ??? + while (it < scores.end()) + _newgen.erase(it->second); + } +private: + unsigned t_size; +}; + +/** a truncate class that does not sort, but repeatidely kills the worse. +To be used in SSGA-like replacements (e.g. see eoSSGAWorseReplacement) +*/ +template +class eoLinearTruncate : public eoReduce +{ + void operator()(eoPop& _newgen, unsigned _newsize) + { + unsigned oldSize = _newgen.size(); + if (oldSize == _newsize) + return; + if (oldSize < _newsize) + throw std::logic_error("eoLinearTruncate: Cannot truncate to a larger size!\n"); + for (unsigned i=0; i::iterator it = _newgen.it_worse_element(); + _newgen.erase(it); + } + } +}; + +/** a truncate class based on a repeated deterministic (reverse!) tournament +To be used in SSGA-like replacements (e.g. see eoSSGADetTournamentReplacement) +*/ +template +class eoDetTournamentTruncate : public eoReduce +{ +public: + eoDetTournamentTruncate(unsigned _t_size): + t_size(_t_size) + { + if (t_size < 2) + { + cout << "Warning, Size for eoDetTournamentTruncate adjusted to 2\n"; + t_size = 2; + } + } + + void operator()(eoPop& _newgen, unsigned _newsize) + { + unsigned oldSize = _newgen.size(); + if (_newsize == 0) + { + _newgen.resize(0); + return; + } + if (oldSize == _newsize) + return; + if (oldSize < _newsize) + throw std::logic_error("eoDetTournamentTruncate: Cannot truncate to a larger size!\n"); + + // Now OK to erase some losers + for (unsigned i=0; i(_newgen, t_size); + _newgen.erase(&eo); + } + } +private: + unsigned t_size; +}; + +/** a truncate class based on a repeated deterministic (reverse!) tournament +To be used in SSGA-like replacements (e.g. see eoSSGAStochTournamentReplacement) +*/ +template +class eoStochTournamentTruncate : public eoReduce +{ +public: + eoStochTournamentTruncate(double _t_rate): + t_rate(_t_rate) + { + if (t_rate <= 0.5) + { + cout << "Warning, Rate for eoStochTournamentTruncate adjusted to 0.51\n"; + t_rate = 0.51; + } + if (t_rate > 1) + { + cout << "Warning, Rate for eoStochTournamentTruncate adjusted to 1\n"; + t_rate = 1; + } + } + + void operator()(eoPop& _newgen, unsigned _newsize) + { + unsigned oldSize = _newgen.size(); + if (_newsize == 0) + { + _newgen.resize(0); + return; + } + if (oldSize == _newsize) + return; + if (oldSize < _newsize) + throw std::logic_error("eoStochTournamentTruncate: Cannot truncate to a larger size!\n"); + // Now OK to erase some losers + for (unsigned i=0; i(_newgen, t_rate); + _newgen.erase(&eo); + } + } + +private: + double t_rate; +}; + //----------------------------------------------------------------------------- #endif //eoInsertion_h diff --git a/eo/src/eoReduceMerge.h b/eo/src/eoReduceMerge.h new file mode 100644 index 000000000..52088cd00 --- /dev/null +++ b/eo/src/eoReduceMerge.h @@ -0,0 +1,119 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoReduceMerge.h + (c) Maarten Keijzer, Marc Schoenauer, GeNeura Team, 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@polytechnique.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef _eoReduceMerge_h +#define _eoReduceMerge_h + + +//----------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +//----------------------------------------------------------------------------- + + +/** +eoReduceMerge: Replacement strategies that start by reducing the parents, + then merge with the offspring + +This is the way to do SSGA: the offspring gets inserted in the population +even if it is worse than anybody else. + +@classes: eoReduceMerge, eoSSGAWorseReplacement, + eoSSGADetTournamentReplacement, eoSSGAStochTournamentReplacement +*/ + +template +class eoReduceMerge : public eoReplacement +{ + public: + eoReduceMerge(eoReduce& _reduce, eoMerge& _merge) : + reduce(_reduce), merge(_merge) + {} + + void operator()(eoPop& _parents, eoPop& _offspring) + { + if (_parents.size() < _offspring.size()) + throw std::logic_error("eoReduceMerge: More offspring than parents!\n"); + reduce(_parents, _parents.size() - _offspring.size()); + merge(_offspring, _parents); + } + + private : + eoReduce& reduce; + eoMerge& merge; +}; + +/** +SSGA replace worst. Is an eoReduceMerge. +*/ +template +class eoSSGAWorseReplacement : public eoReduceMerge +{ + public : + eoSSGAWorseReplacement() : eoReduceMerge(truncate, plus) {} + + private : + eoLinearTruncate truncate; + eoPlus plus; +}; + +/** +SSGA deterministic tournament replacement. Is an eoReduceMerge. +*/ +template +class eoSSGADetTournamentReplacement : public eoReduceMerge +{ + public : + eoSSGADetTournamentReplacement(unsigned _t_size) : + eoReduceMerge(truncate, plus), truncate(_t_size) {} + + private : + eoDetTournamentTruncate truncate; + eoPlus plus; +}; + +/** SSGA stochastic tournament replacement. Is an eoReduceMerge. +It much cleaner to insert directly the offspring in the parent population, +but it is NOT equivalent in case of more than 1 offspring as already +replaced could be removed , which is not possible in the eoReduceMerge +So what the heck ! */ +template +class eoSSGAStochTournamentReplacement : public eoReduceMerge +{ + public : + eoSSGAStochTournamentReplacement(double _t_rate) : + eoReduceMerge(truncate, plus), truncate(_t_rate) {} + + private : + eoStochTournamentTruncate truncate; + eoPlus plus; +}; + +#endif diff --git a/eo/src/eoReplacement.h b/eo/src/eoReplacement.h index 3a57db639..d0b6452ce 100644 --- a/eo/src/eoReplacement.h +++ b/eo/src/eoReplacement.h @@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- eoReplacement.h - (c) Maarten Keijzer, GeNeura Team, 2000 + (c) Maarten Keijzer, Marc Schoenauer, GeNeura Team, 2000 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,9 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@polytechnique.fr + mkeijzer@dhi.dk */ //----------------------------------------------------------------------------- @@ -31,81 +33,85 @@ #include #include #include +#include //----------------------------------------------------------------------------- /** eoReplacement: High level strategy for creating a new generation -from parents and offspring. This is a combination of eoMerge and eoReduce, -so there is an implementation called eoMergeReduce that can be found below +from parents and offspring. - @see eoMerge, eoReduce, eoMergeReduce +The eoMergeReduce, combination of eoMerge and eoReduce, can be found +in file eoMergeReduce.h + +Removed the const before first argument: though it makes too many classes +with the same interface, it allows to minimize the number of actual copies +by choosing the right destination +I also removed the enforced "swap" in the eoEasyAlgo and hence the generational +replacement gets a class of its own that only does the swap (instead of the +eoNoReplacement that did nothing, relying on the algo to swap popualtions). +MS 12/12/2000 + +NOTE: the resulting population should always be in the first argument +(replace parents by offspring)! The second argument can contain any rubbish + + @see eoMerge, eoReduce, eoMergeReduce, eoReduceMerge + +@classes eoReplacement, base (pure abstract) class + eoGenerationalReplacement, as it says ... + eoWeakElitistReplacement a wrapper to add elitism */ + +/** +eoReplacement: the base class for all replacementp functors + */ template -class eoReplacement : public eoBF&, eoPop&, void> +class eoReplacement : public eoBF&, eoPop&, void> {}; /** -no replacement +generational replacement == swap populations */ template -class eoNoReplacement : public eoReplacement +class eoGenerationalReplacement : public eoReplacement { public : - /// do nothing - void operator()(const eoPop&, eoPop&) - {} + /// swap + void operator()(eoPop& _parents, eoPop& _offspring) + { + _parents.swap(_offspring); + } }; -/** -eoMergeReduce: special replacement strategy that is just an application of an embedded merge, -followed by an embedded reduce +/** +eoWeakElitistReplacement: a wrapper for other replacement procedures. +Copies in the new pop the best individual from the old pop, +AFTER normal replacement, if the best of the new pop is worse than the best +of the old pop. Removes the worse individual from the new pop. +This could be changed by adding a selector there... */ template -class eoMergeReduce : public eoReplacement +class eoWeakElitistReplacement : public eoReplacement { - public: - eoMergeReduce(eoMerge& _merge, eoReduce& _reduce) : - merge(_merge), reduce(_reduce) - {} +public : + typedef typename EOT::Fitness Fitness; - void operator()(const eoPop& _parents, eoPop& _offspring) - { - merge(_parents, _offspring); - reduce(_offspring, _parents.size()); - } + // Ctor, takes an eoReplacement + eoWeakElitistReplacement(eoReplacement & _replace) : + replace(_replace) {} - private : - eoMerge& merge; - eoReduce& reduce; + /// do replacement + void operator()(eoPop& _pop, eoPop& _offspring) + { + const EOT & oldChamp = _pop.best_element(); + replace(_pop, _offspring); // "normal" replacement, parents are the new + if (_pop.best_element() < oldChamp) // need to do something + { + typename eoPop::iterator itPoorGuy = _pop.it_worse_element(); + (*itPoorGuy) = oldChamp; + } + } +private: + eoReplacement & replace; }; -/** -ES type of replacement strategy: first add parents to population, then truncate -*/ -template -class eoPlusReplacement : public eoMergeReduce -{ - public : - eoPlusReplacement() : eoMergeReduce(plus, truncate) {} - - private : - eoPlus plus; - eoTruncate truncate; -}; - -/** -ES type of replacement strategy: ignore parents, truncate offspring -*/ -template -class eoCommaReplacement : public eoMergeReduce -{ - public : - eoCommaReplacement() : eoMergeReduce(no_elite, truncate) {} - - private : - eoNoElitism no_elite; - eoTruncate truncate; -}; - - #endif diff --git a/eo/src/eoSelectMany.h b/eo/src/eoSelectMany.h new file mode 100644 index 000000000..f1b765f26 --- /dev/null +++ b/eo/src/eoSelectMany.h @@ -0,0 +1,76 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoSelectMany.h + (c) Maarten Keijzer, Marc Schoenauer, GeNeura Team, 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@polytechnique.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef _eoSelectMany_h +#define _eoSelectMany_h + + +//----------------------------------------------------------------------------- +#include +#include +#include +#include +//----------------------------------------------------------------------------- + +/** eoSelectMany selects many individuals using eoSelectOne as it's + mechanism. Therefore eoSelectMany needs an eoSelectOne in its ctor + + It will use an eoHowMnay to determine the number of guys to select, + and push them to the back of the destination population. +*/ +template +class eoSelectMany : public eoSelect +{ + public: + /// init + eoSelectMany(eoSelectOne& _select, + double _rate, bool _interpret_as_rate = true) + : select(_select), howMany(_rate, _interpret_as_rate) {} + + /** + The implementation repeatidly selects an individual + + @param _source the source population + @param _dest the resulting population (size of this population is the number of times eoSelectOne is called. It empties the destination and adds the selection into it) + */ + virtual void operator()(const eoPop& _source, eoPop& _dest) + { + unsigned target = howMany(_source.size()); + + _dest.resize(target); + + select.setup(_source); + + for (size_t i = 0; i < _dest.size(); ++i) + _dest[i] = select(_source); + } + +private : + eoSelectOne& select; + eoHowMany howMany; +}; + +#endif diff --git a/eo/src/eoSelectNumber.h b/eo/src/eoSelectNumber.h new file mode 100644 index 000000000..2b5d2a8cd --- /dev/null +++ b/eo/src/eoSelectNumber.h @@ -0,0 +1,72 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoSelectNumber.h + (c) Maarten Keijzer, Marc Schoenauer, GeNeura Team, 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + */ +//----------------------------------------------------------------------------- + +#ifndef _eoSelectNumber_h +#define _eoSelectNumber_h + + +//----------------------------------------------------------------------------- +#include +#include +#include +//----------------------------------------------------------------------------- + +/** eoSelectNumber selects many individuals using eoSelectOne as it's + mechanism. Therefore eoSelectNumber needs an eoSelectOne in its ctor + + It will select a fixed number of individuals and pushes them to + the back of the destination population. +*/ +template +class eoSelectNumber : public eoSelect +{ + public: + /// init + eoSelectNumber(eoSelectOne& _select, unsigned _nb_to_select = 1) + : select(_select), nb_to_select(_nb_to_select) {} + + /** + The implementation repeatidly selects an individual + + @param _source the source population + @param _dest the resulting population (size of this population is the number of times eoSelectOne is called. It empties the destination and adds the selection into it) + */ + virtual void operator()(const eoPop& _source, eoPop& _dest) + { + size_t target = static_cast(nb_to_select); + + _dest.resize(target); + + select.setup(_source); + + for (size_t i = 0; i < _dest.size(); ++i) + _dest[i] = select(_source); + } + +private : + eoSelectOne& select; + unsigned nb_to_select; +}; + +#endif diff --git a/eo/src/eoSurviveAndDie.h b/eo/src/eoSurviveAndDie.h new file mode 100644 index 000000000..eb582cb17 --- /dev/null +++ b/eo/src/eoSurviveAndDie.h @@ -0,0 +1,188 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoSurviveAndDie.h + (c) Maarten Keijzer, Marc Schoenauer, GeNeura Team, 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@polytechnique.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef _eoSurviveAndDie_h +#define _eoSurviveAndDie_h + + +//----------------------------------------------------------------------------- +#include +#include +#include +#include +#include +//----------------------------------------------------------------------------- + +/** +eoSurviveAndDie: takes a population (first argument), +kills the ones that are to die, +puts the ones that are to survive into the second argument +removes them from the first pop argument + +@classes: eoSurviveAndDie, eoDeterministicSurviveAndDie, + eoDeterministicSaDReplacement +*/ + +/** eoSurviveAndDie +A pure abstract class, to store the howmany's +*/ +template +class eoSurviveAndDie : public eoBF &, eoPop &, void> +{ +public: + eoSurviveAndDie(double _survive, double _die, bool _interpret_as_rate = true): + howmanySurvive(_survive, _interpret_as_rate), + howmanyDie(_die, _interpret_as_rate) + {} + +protected: + eoHowMany howmanySurvive; + eoHowMany howmanyDie; + +}; + +/** +an instance (theonly one as of today, Dec. 20, 2000) of an eoSurviveAndDie, +that does everything deterministically + +used in eoDeterministicSaDReplacement +*/ + +template +class eoDeterministicSurviveAndDie : public eoSurviveAndDie +{ +public: + eoDeterministicSurviveAndDie(double _survive, double _die, + bool _interpret_as_rate = true): + eoSurviveAndDie(_survive, _die, _interpret_as_rate) + {} + + void operator()(eoPop & _pop, eoPop & _luckyGuys) + { + unsigned pSize = _pop.size(); + unsigned nbSurvive = howmanySurvive(pSize); + // first, save the best into _luckyGuys + if (nbSurvive) + { + _pop.nth_element(nbSurvive); + // copy best + _luckyGuys.resize(nbSurvive); + copy(_pop.begin(), _pop.begin()+nbSurvive, _luckyGuys.begin()); + // erase them from pop + _pop.erase(_pop.begin(), _pop.begin()+nbSurvive); + } + unsigned nbRemaining = _pop.size(); + + // carefull, we can have a rate of 1 if we want to kill all remaining + unsigned nbDie = min(howmanyDie(pSize), pSize-nbSurvive); + if (nbDie > nbRemaining) + throw std::logic_error("eoDeterministicSurviveAndDie: Too many to kill!\n"); + + if (!nbDie) + { + return; + } + // else + // kill the worse nbDie + _pop.nth_element(nbRemaining-nbDie); + _pop.resize(nbRemaining-nbDie); + } + +}; + +/** +eoDeterministicSaDReplacement: replacement strategy that is just, in sequence + saves best and kill worse from parents ++ saves best and kill worse from offspring ++ merge remaining (neither save nor killed) parents and offspring ++ reduce that merged population += returns reduced pop + best parents + best offspring + +An obvious use is as strong elitist strategy, + i.e. preserving best parents, and reducing + (either offspring or parents+offspring) +*/ +template +class eoDeterministicSaDReplacement : public eoReplacement +{ +public: + /** Constructor with reduce */ + eoDeterministicSaDReplacement(eoReduce& _reduceGlobal, + double _surviveParents, double _dieParents=0, + double _surviveOffspring=0, double _dieOffspring=0, + bool _interpret_as_rate = true ) : + reduceGlobal(_reduceGlobal), + sAdParents(_surviveParents, _dieParents, _interpret_as_rate), + sAdOffspring(_surviveOffspring, _dieOffspring, _interpret_as_rate) + {} + + /** Constructor with default truncate used as reduce */ + eoDeterministicSaDReplacement( + double _surviveParents, double _dieParents=0, + double _surviveOffspring=0, double _dieOffspring=0, + bool _interpret_as_rate = true ) : + reduceGlobal(truncate), + sAdParents(_surviveParents, _dieParents, _interpret_as_rate), + sAdOffspring(_surviveOffspring, _dieOffspring, _interpret_as_rate) + {} + + void operator()(eoPop& _parents, eoPop& _offspring) + { + unsigned pSize = _parents.size(); // target number of individuals + + eoPop luckyParents; // to hold the absolute survivors + sAdParents(_parents, luckyParents); + + eoPop luckyOffspring; // to hold the absolute survivors + sAdOffspring(_offspring, luckyOffspring); + + unsigned survivorSize = luckyOffspring.size() + luckyParents.size(); + if (survivorSize > pSize) + throw std::logic_error("eoGeneralReplacement: More survivors than parents!\n"); + + plus(_parents, _offspring); // all that remain in _offspring + + reduceGlobal(_offspring, pSize - survivorSize); + plus(luckyParents, _offspring); + plus(luckyOffspring, _offspring); + + _parents.swap(_offspring); + + } + +private : + eoReduce& reduceGlobal; + eoDeterministicSurviveAndDie sAdParents; + eoDeterministicSurviveAndDie sAdOffspring; + // plus helper (could be replaced by operator+= ???) + eoPlus plus; + // the default reduce: deterministic truncation + eoTruncate truncate; +}; + + + +#endif