From ed4537545107701d2f21aff5e80179ac0e6d088c Mon Sep 17 00:00:00 2001 From: mac Date: Sun, 9 Apr 2000 09:41:29 +0000 Subject: [PATCH] Changed the general operator interface to be consistent with the rest of EO, updated some documentation. --- eo/src/eoBackInserter.h | 6 +- eo/src/eoDetTournamentIndiSelector.h | 5 +- eo/src/eoDetTournamentInserter.h | 7 ++- eo/src/eoFitness.h | 4 +- eo/src/eoGOpBreeder.h | 2 +- eo/src/eoGOpSelector.h | 11 +++- eo/src/eoIndiSelector.h | 35 +++++++---- eo/src/eoInserter.h | 9 ++- eo/src/eoOp.h | 5 ++ eo/src/eoRandomIndiSelector.h | 1 + eo/src/eoScalarFitness.h | 2 +- eo/src/eoSteadyStateInserter.h | 3 +- eo/src/eoStochTournamentInserter.h | 10 ++-- eo/src/eoTerm.h | 87 +++++++++++++++++++++++++--- eo/src/eoUniform.h | 23 ++++++++ eo/src/eoWrappedOps.h | 26 ++++----- eo/test/t-eoGOpSel.cpp | 52 +++++++++++++++-- 17 files changed, 233 insertions(+), 55 deletions(-) diff --git a/eo/src/eoBackInserter.h b/eo/src/eoBackInserter.h index 5e9faef7..79727870 100644 --- a/eo/src/eoBackInserter.h +++ b/eo/src/eoBackInserter.h @@ -29,9 +29,10 @@ #ifndef eoBackInserter_h #define eoBackInserter_h -#include "eoInserter.h" +#include /** +\ingroup inserters * eoBackInserter: Interface class that enables an operator to insert new individuals at the back of the new population. */ @@ -42,9 +43,10 @@ class eoBackInserter : public eoPopInserter eoBackInserter(void) : eoPopInserter() {} - void insert(const EOT& _eot) + eoInserter& operator()(const EOT& _eot) { pop().push_back(_eot); + return *this; } string className(void) const { return "eoBackInserter"; } diff --git a/eo/src/eoDetTournamentIndiSelector.h b/eo/src/eoDetTournamentIndiSelector.h index d5c35df4..75d36c21 100644 --- a/eo/src/eoDetTournamentIndiSelector.h +++ b/eo/src/eoDetTournamentIndiSelector.h @@ -26,11 +26,12 @@ #define eoDetTournamentIndiSelector_h #include "eoIndiSelector.h" -#include "selectors.h" +#include "utils/selectors.h" /** - * eoDetTournamentIndiSelector: selects children through a deterministic_tournament +\ingroup selectors + * eoDetTournamentIndiSelector: selects children through a deterministic_tournament */ template class eoDetTournamentIndiSelector : public eoPopIndiSelector diff --git a/eo/src/eoDetTournamentInserter.h b/eo/src/eoDetTournamentInserter.h index bdc1dd0a..c4777794 100644 --- a/eo/src/eoDetTournamentInserter.h +++ b/eo/src/eoDetTournamentInserter.h @@ -29,8 +29,8 @@ #define eoDetTournamentInserter_h -#include "eoSteadyStateInserter.h" -#include "selectors.h" +#include +#include /** * eoDetTournamentInserter: Uses an inverse deterministic tournament to figure @@ -50,13 +50,14 @@ class eoDetTournamentInserter : public eoSteadyStateInserter } } - void insert(const EOT& _eot) + eoInserter& operator()(const EOT& _eot) { EOT& eo = inverse_deterministic_tournament(pop(), t_size); eo = _eot; // overwrite loser of tournament eo.invalidate(); // This line should probably be removed when all genetic operators do this themselves eval(eo); // Evaluate after insert + return *this; } string className(void) const { return "eoDetTournamentInserter"; } diff --git a/eo/src/eoFitness.h b/eo/src/eoFitness.h index ea514ae6..c1e03fc3 100644 --- a/eo/src/eoFitness.h +++ b/eo/src/eoFitness.h @@ -25,7 +25,9 @@ #define EOFITNESS_H //----------------------------------------------------------------------------- - +/** +\deprecated This class will dissapear in time, use eoScalarFitness instead +*/ class eoFitness: public eoPersistent { public: diff --git a/eo/src/eoGOpBreeder.h b/eo/src/eoGOpBreeder.h index b4a2bdbb..078428da 100644 --- a/eo/src/eoGOpBreeder.h +++ b/eo/src/eoGOpBreeder.h @@ -40,7 +40,7 @@ class eoGOpBreeder: public eoMonPopOp for (unsigned i = 0; i < size; i++) { // and the one liner - opSel.selectOp()(selector(_pop,size, i), inserter(_pop)); + opSel.selectOp()(selector.bind(_pop,size, i), inserter.bind(_pop)); } } diff --git a/eo/src/eoGOpSelector.h b/eo/src/eoGOpSelector.h index c2ec4fa4..2bab833f 100644 --- a/eo/src/eoGOpSelector.h +++ b/eo/src/eoGOpSelector.h @@ -55,8 +55,13 @@ public: } } - /// Add any kind of operator to the operator mix, with an argument - virtual ID addOp( eoOp& _op, float _arg ); + /* + Add any kind of operator to the operator mix, + @param _op operator, one of eoMonOp, eoBinOp, eoQuadraticOp or eoGeneralOp + @param _rate the rate at which it should be applied, it should be a probability + + */ + virtual ID addOp( eoOp& _op, float _rate ); // implementation can be found below /** Retrieve the operator using its integer handle @@ -79,7 +84,7 @@ public: return &selectOp(); } - /// + /// Select an operator from the operators present here virtual eoGeneralOp& selectOp() = 0; /// diff --git a/eo/src/eoIndiSelector.h b/eo/src/eoIndiSelector.h index a404f0d0..b2617e7c 100644 --- a/eo/src/eoIndiSelector.h +++ b/eo/src/eoIndiSelector.h @@ -42,19 +42,29 @@ public : virtual ~eoIndiSelector(void) {} + /** + return the number of individuals that can be selected by an nary operator (through operator[] below) + */ virtual size_t size(void) const = 0; - virtual const EOT& operator[](size_t) const = 0; - virtual const EOT& select(void) = 0; + /** + return the specified individual, the size_t argument should be between 0 and eoIndiSelector::size() + */ + virtual const EOT& operator[](size_t i) const = 0; + + /** + Select an individual, maybe from an underlying population (see eoPopIndiSelector) + */ + virtual const EOT& operator()(void) = 0; + /// default implementation just calls operator() a couple of times + /// this can be overridden in favour of a more efficient implementation virtual vector select(size_t _how_many) - { // default implementation just calls select a couple of times - // this can be overridden in favour of a more efficient implementation - vector result(_how_many); + { vector result(_how_many); for (unsigned i = 0; i < _how_many; ++i) { - result[i] = &select(); + result[i] = &operator()(); } return result; @@ -79,9 +89,10 @@ class eoPopIndiSelector : public eoIndiSelector struct eoUnitializedException{}; - /** Initialization function + /** Initialization function, binds the population to the selector, can also + be used to specify an optional end and the first individual to return in operator() */ - eoPopIndiSelector& operator()(const eoPop& _pop, int _end = -1, int _myGuy = -1) + eoPopIndiSelector& bind(const eoPop& _pop, int _end = -1, int _myGuy = -1) { pop = &_pop; last = _end; @@ -102,8 +113,8 @@ class eoPopIndiSelector : public eoIndiSelector eoPop::const_iterator end(void) const { valid(); return pop->end(); } - /// select does the work. Note that it is not virtual. It calls do_select that needs to be implemented by the derived classes - const EOT& select(void) + /// operator() does the work. Note that it is not virtual. It calls do_select that needs to be implemented by the derived classes + const EOT& operator()(void) { valid(); if (firstChoice < 0 || firstChoice >= (int) size()) @@ -116,6 +127,10 @@ class eoPopIndiSelector : public eoIndiSelector return result; } + /** + do_select, abstract member re-implemented by derived classes + This function will get called by operator() when it ran out of choices + */ virtual const EOT& do_select(void) = 0; private : diff --git a/eo/src/eoInserter.h b/eo/src/eoInserter.h index b651f571..d2758bea 100644 --- a/eo/src/eoInserter.h +++ b/eo/src/eoInserter.h @@ -36,14 +36,17 @@ new individuals into the (intermediate) population. */ template -class eoInserter : public eoObject +class eoInserter { public : virtual ~eoInserter() {} struct eoInserterException{}; - virtual void insert(const EOT&) = 0; // can throw an eoInserterException + /** + insert argument somewhere (quite likely a population) + */ + virtual eoInserter& operator()(const EOT&) = 0; // can throw an eoInserterException }; /** @@ -58,7 +61,7 @@ class eoPopInserter : public eoInserter eoPopInserter(void) : eoInserter(), thePop(0) {} /// Binds the population to this class. This is an initialization routine used by breeders - eoInserter& operator()(eoPop& _pop) + eoInserter& bind(eoPop& _pop) { thePop = &_pop; return *this; diff --git a/eo/src/eoOp.h b/eo/src/eoOp.h index e27051e1..6d4b147c 100644 --- a/eo/src/eoOp.h +++ b/eo/src/eoOp.h @@ -27,6 +27,11 @@ #include #include +/** +\defgroup operators +Genetic Operators are used for various purposes +*/ + /** @name Genetic operators What is a genetic algorithm without genetic operators? There is a genetic operator hierarchy, with eoOp as father and eoMonOp (monary or unary operator) and eoBinOp and eoQuadraticOp (binary operators) as siblings). Nobody should subclass eoOp, you should subclass eoGeneralOp, eoBinOp, eoQuadraticOp or eoMonOp, those are the ones actually used here. \\#eoOp#s are only printable objects, so if you want to build them from a file, it has to be done in another class, namely factories. Each hierarchy of #eoOp#s should have its own factory, which know how to build them from a description in a file. diff --git a/eo/src/eoRandomIndiSelector.h b/eo/src/eoRandomIndiSelector.h index 6eceec85..8d9a0ccd 100644 --- a/eo/src/eoRandomIndiSelector.h +++ b/eo/src/eoRandomIndiSelector.h @@ -29,6 +29,7 @@ #include "eoIndiSelector.h" /** +\ingroup selectors * eoRandomSelector: just selects a random child */ template diff --git a/eo/src/eoScalarFitness.h b/eo/src/eoScalarFitness.h index 63409191..46daad95 100644 --- a/eo/src/eoScalarFitness.h +++ b/eo/src/eoScalarFitness.h @@ -54,7 +54,7 @@ class eoScalarFitness operator ScalarType(void) const { return value; } - // Comparison, using less by default + /// Comparison, using less by default bool operator<(const eoScalarFitness& other) const { return Compare()(value, other.value); } diff --git a/eo/src/eoSteadyStateInserter.h b/eo/src/eoSteadyStateInserter.h index d2264294..1732c345 100644 --- a/eo/src/eoSteadyStateInserter.h +++ b/eo/src/eoSteadyStateInserter.h @@ -29,7 +29,8 @@ #define eoSteadyStateInserter_h -#include "eoEvalFunc.h" +#include +#include /** * eoSteadyStateInserter: Interface class that enables an operator to update diff --git a/eo/src/eoStochTournamentInserter.h b/eo/src/eoStochTournamentInserter.h index 56bb8e70..dbd161b9 100644 --- a/eo/src/eoStochTournamentInserter.h +++ b/eo/src/eoStochTournamentInserter.h @@ -29,11 +29,12 @@ #define eoStochTournamentInserter_h -#include "eoSteadyStateInserter.h" -#include "selectors.h" +#include +#include /** - * eoDetTournamentInserter: Uses an inverse stochastic tournament to figure +\ingroup inserters + * eoStochTournamentInserter: Uses an inverse stochastic tournament to figure * out who gets overridden by the new individual. It resets the fitness of the * individual. */ @@ -55,13 +56,14 @@ class eoStochTournamentInserter : public eoSteadyStateInserter } } - void insert(const EOT& _eot) + eoInserter& operator()(const EOT& _eot) { EOT& eo = inverse_stochastic_tournament(pop(), t_rate); eo = _eot; // overwrite loser of tournament eo.invalidate(); eval(eo); // Evaluate after insert + return *this; } string className(void) const { return "eoStochTournamentInserter"; } diff --git a/eo/src/eoTerm.h b/eo/src/eoTerm.h index ca73901a..e21b84ef 100644 --- a/eo/src/eoTerm.h +++ b/eo/src/eoTerm.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // eoTerm.h -// (c) GeNeura Team, 1999 +// (c) GeNeura Team, 1999, 2000 /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,11 +25,17 @@ #ifndef _EOTERM_H #define _EOTERM_H -#include +//#include + +// forward definition for fast(er) compilation +template class eoPop; + /** Termination condition for the genetic algorithm * Takes the population as input, returns true for continue, - * false for termination + * false for termination (although this begs the question why this + * terminator is not called a continuator) + * */ template< class EOT> class eoTerm : public eoObject { @@ -44,10 +50,77 @@ public: of the object, for instance, updating local data. */ virtual bool operator() ( const eoPop< EOT >& _pop ) = 0 ; - - /// Class name. - virtual string className() const { return "eoTerm"; } - }; + +/** eoParamTerm, a terminator that compares two statistics and decides whether the + * algorithm should stop or not. +*/ + +#include + +template +class eoBinaryTerm : public eoTerm +{ +public : + + typedef typename Pred::first_argument_type first_argument_type; + typedef typename Pred::second_argument_type second_argument_type; + + /// Ctors/dtors + eoBinaryTerm(first_argument_type& _param1, second_argument_type& _param2) : param1(_param1), param2(_param2), compare() {} + + virtual ~eoBinaryTerm() {}; + + /** + */ + virtual bool operator() ( const eoPop< EOT >& _pop ) + { + return compare(param1, param2); + } + + /// Class name. + virtual string className() const { return "eoStatTerm"; } + +private : + + first_argument_type& param1; + second_argument_type& param2; + Pred compare; +}; + +#include +/** Combined termination condition for the genetic algorithm + * + * The eoCombinedTerm will perform a logical and on all the terminators + * contained in it. This means that the terminator will say stop (return false) + * when one of the contained terminators says so + * + * + * So now you can say: + + eoTerm1 term1; + eoTerm2 term2; + eoCombinedTerm term3(term1, term2); + + +template +class eoCombinedTerm : public eoTerm, public std::pair&, eoTerm& > +{ +public : + + eoCombinedTerm(const eoTerm& _first, const eoTerm& _second) : std::pair(_first, _second) {} + + ~eoCombinedTerm() {} + + bool operator()(const eoPop& _pop) + { + if (first(_pop)) + return second(_pop); + + return false; // quit evolution + } +}; +*/ #endif + diff --git a/eo/src/eoUniform.h b/eo/src/eoUniform.h index 90df59fe..2c1f308d 100644 --- a/eo/src/eoUniform.h +++ b/eo/src/eoUniform.h @@ -66,6 +66,29 @@ class eoUniform: public eoRnd double diff; }; +template<> +class eoUniform: public eoRnd +{ + public: + /** + * Default constructor. + * @param _min The minimum value in the interval. + * @param _max The maximum value in the interval. + */ + eoUniform(bool _min = false, bool _max = true) + : eoRnd() {} + + /** Returns an uniform random number over the interval [min, max) + Uses global rng object */ + virtual bool operator()() { + return rng.flip(0.5); + } + + private: + T min; + double diff; +}; + //----------------------------------------------------------------------------- #endif diff --git a/eo/src/eoWrappedOps.h b/eo/src/eoWrappedOps.h index 83b99bdb..881db6e7 100644 --- a/eo/src/eoWrappedOps.h +++ b/eo/src/eoWrappedOps.h @@ -50,9 +50,9 @@ public : /// Instantiates the abstract method void operator()( eoIndiSelector& _in, eoInserter& _out) const { - EOT result = _in.select(); + EOT result = _in(); op( result ); - _out.insert(result); + _out(result); } /// @@ -78,10 +78,10 @@ public : /// Instantiates the abstract method. EOT should have copy ctor. void operator()(eoIndiSelector& _in, eoInserter& _out) const { - EOT out1 = _in.select(); - const EOT& out2 = _in.select(); + EOT out1 = _in(); + const EOT& out2 = _in(); op(out1, out2); - _out.insert(out1); + _out(out1); } /// @@ -105,11 +105,10 @@ public : /// Instantiates the abstract method. EOT should have copy ctor. void operator()(eoIndiSelector& _in, eoInserter& _out) const { - EOT out1 = _in.select(); - EOT out2 = _in.select(); + EOT out1 = _in(); + EOT out2 = _in(); op(out1, out2); - _out.insert(out1); - _out.insert(out2); + _out(out1)(out2); } /// @@ -154,11 +153,11 @@ public : size_t size() const { return in.size(); } const EOT& operator[](size_t _n) const { return in[_n]; } - const EOT& select(void) + const EOT& operator()(void) { if (results.empty()) { - return in.select(); + return in(); } // else we use the previously inserted individual, // an iterator to it is stored in 'results', but the memory @@ -169,10 +168,11 @@ public : return *it; } - void insert(const EOT& _eot) + eoInserter& operator()(const EOT& _eot) { intermediate.push_front(_eot); results.push_front(intermediate.begin()); + return *this; } void fill(eoInserter& _out) @@ -181,7 +181,7 @@ public : for (Iterator it = results.begin(); it != results.end(); ++it) { - _out.insert(**it); + _out(**it); } results.clear(); diff --git a/eo/test/t-eoGOpSel.cpp b/eo/test/t-eoGOpSel.cpp index efcae7e8..fbc7e835 100644 --- a/eo/test/t-eoGOpSel.cpp +++ b/eo/test/t-eoGOpSel.cpp @@ -32,8 +32,17 @@ #include #include #include -//#include +#include +#include +#include +#include +#include + +#include + +#include +#include // Fitness evaluation #include "binary_value.h" @@ -46,6 +55,8 @@ typedef eoBin Chrom; main() { + rng.reseed(42); // reproducible random seed + const unsigned POP_SIZE = 8, CHROM_SIZE = 4; unsigned i; @@ -68,16 +79,49 @@ main() eoBinBitFlip bitflip; eoBinCrossover xover; + eoEvalFuncPtr eval(binary_value); + //Create the proportional operator selector and add the // two operators creatd above to it. eoProportionalGOpSel propSel; + eoSequentialGOpSel seqSel; + propSel.addOp(bitflip, 0.5); propSel.addOp(xover, 0.5); - for ( i = 0; i < POP_SIZE; i ++ ) { - eoGeneralOp& foo = propSel.selectOp(); - } + // seqSel selects operator in sequence, creating a combined operator + // add a bitflip, an xover and another bitflip + seqSel.addOp(bitflip, 0.25); + seqSel.addOp(xover, 0.5); + seqSel.addOp(bitflip, 0.25); + + + eoRandomIndiSelector selector1; + eoDetTournamentIndiSelector selector2(2); + + eoBackInserter inserter1; + eoDetTournamentInserter inserter2(eval, 2); + eoStochTournamentInserter inserter3(eval, 0.9f); + + eoGOpBreeder breeder1(propSel, selector1); + eoGOpBreeder breeder2(seqSel, selector1); + eoGOpBreeder breeder3(propSel, selector2); + eoGOpBreeder breeder4(seqSel, selector2); + + // test the breeders + + breeder1(pop); + breeder2(pop); + breeder3(pop); + breeder4(pop); + + eoState state; + + state.registerObject(pop); + + state.save(std::cout); + return 0; }