From 8ae796ab282011c459f5698f8dec56c7a1fad326 Mon Sep 17 00:00:00 2001 From: mac Date: Fri, 18 Aug 2000 08:44:22 +0000 Subject: [PATCH] Added symbolic regression, which tests combined ops as well --- eo/src/Makefile.am | 2 +- eo/src/eoGOpBreeder.h | 4 +- eo/src/eoPop.h | 73 -------------------- eo/src/eoSequentialGOpSel.h | 6 +- eo/src/eoSteadyStateTransform.h | 4 +- eo/src/eoWrappedOps.h | 22 +++--- eo/src/gp/eoParseTree.h | 51 +++++++------- eo/src/gp/node_pool.h | 2 +- eo/src/gp/parse_tree.h | 36 ++++------ eo/src/utils/eoStat.h | 16 ++++- eo/test/Makefile.am | 11 ++- eo/test/t-eoSymreg.cpp | 118 +++++++++++++++++--------------- eo/win/Makefile.am | 2 +- eo/win/eo_win.dsw | 15 ++++ 14 files changed, 162 insertions(+), 200 deletions(-) diff --git a/eo/src/Makefile.am b/eo/src/Makefile.am index ffa36a76..9ccbaf16 100644 --- a/eo/src/Makefile.am +++ b/eo/src/Makefile.am @@ -4,7 +4,7 @@ ## ############################################################################### -SUBDIRS = es ga utils other +SUBDIRS = es ga gp utils other lib_LIBRARIES = libeo.a libeo_a_SOURCES = eoPrintable.cpp eoPersistent.cpp eoFunctorStore.cpp diff --git a/eo/src/eoGOpBreeder.h b/eo/src/eoGOpBreeder.h index 913d4a5f..12d811c2 100644 --- a/eo/src/eoGOpBreeder.h +++ b/eo/src/eoGOpBreeder.h @@ -24,7 +24,7 @@ class eoGOpBreeder: public eoUnaryFunctor&> public: /// Default constructor. eoGOpBreeder( eoGOpSelector& _opSel, - eoPopIndiSelector& _selector) + eoSelectOneIndiSelector& _selector) : opSel( _opSel ), selector(_selector) {} @@ -47,7 +47,7 @@ class eoGOpBreeder: public eoUnaryFunctor&> private: eoGOpSelector& opSel; - eoPopIndiSelector& selector; + eoSelectOneIndiSelector& selector; // the inserter can be local as there's no point in changing it from the outside eoBackInserter inserter; diff --git a/eo/src/eoPop.h b/eo/src/eoPop.h index 0645038a..7028c80f 100644 --- a/eo/src/eoPop.h +++ b/eo/src/eoPop.h @@ -185,78 +185,5 @@ class eoPop: public vector, public eoObject, public eoPersistent }; -/** - Keeps and calculates information about a population such - as the sum of fitnesses and whether the population is sorted. - It can be used to cache information about a population between - calls of functors, see for instance how this makes eoProportional - just this tat more efficient - - @see eoSelectOne, eoSelect, eoProportional - -template -class eoPopStats -{ -public : - typedef typename EOT::Fitness FitnessType; - - /// Initialize by stating nothing is known - eoPopStats() : - sum_fitness_calculated(false), - pop_sorted_calculated(false) - {} - - /// Call this function after the pop might have/is changed - void reset() - { - sum_fitness_calculated = false; - pop_sorted_calculated = false; - } - - /// Calculate sum_fitness or return cached value - FitnessType get_sum_fitness(const eoPop& _pop) - { - if (sum_fitness_calculated) - return sum_fitness; - - sum_fitness = 0.0; - - for (int i = 0; i < _pop.size(); ++i) - { - sum_fitness += _pop[i].fitness(); - } - - sum_fitness_calculated = true; - return sum_fitness; - } - - /// Check if the pop is sorted or return cached_value - bool is_pop_sorted(const eoPop& _pop) - { - if (pop_sorted_calculated) - return pop_sorted; - - int i; - for (i = 1; i < _pop.size(); ++i) - { - if (!(_pop[i-1] < _pop[i])) - { // not in sort order - break; - } - } - - pop_sorted = (i == _pop.size()); - pop_sorted_calculated = true; - return pop_sorted; - } - - bool sum_fitness_calculated; - FitnessType sum_fitness; - - bool pop_sorted_calculated; - bool pop_sorted; -}; -*/ - #endif diff --git a/eo/src/eoSequentialGOpSel.h b/eo/src/eoSequentialGOpSel.h index 11c3c469..63acac43 100644 --- a/eo/src/eoSequentialGOpSel.h +++ b/eo/src/eoSequentialGOpSel.h @@ -40,12 +40,10 @@ template class eoSequentialGOpSel : public eoGOpSelector { public : - - eoSequentialGOpSel(void) : combined(*this, getRates()) {} - + virtual eoGeneralOp& selectOp() { - return combined; + return combined.bind(*this, getRates()); } private : diff --git a/eo/src/eoSteadyStateTransform.h b/eo/src/eoSteadyStateTransform.h index 82d9b471..890920a7 100644 --- a/eo/src/eoSteadyStateTransform.h +++ b/eo/src/eoSteadyStateTransform.h @@ -65,7 +65,7 @@ template class eoSteadyStateTransform: public eoTransform nSteps = pop.size(); // make a 'generation equivalent' } - for (unsigned i = 0; i < steps; ++i) + for (unsigned i = 0; i < nSteps; ++i) { selector.bind(pop); inserter.bind(pop); @@ -77,7 +77,7 @@ template class eoSteadyStateTransform: public eoTransform private: eoGOpSelector& opSelector; - eoSelectOneIndiSelector& selector; + eoSelectOneIndiSelector selector; eoSteadyStateInserter& inserter; unsigned steps; }; diff --git a/eo/src/eoWrappedOps.h b/eo/src/eoWrappedOps.h index 7ef717f6..cd7432ef 100644 --- a/eo/src/eoWrappedOps.h +++ b/eo/src/eoWrappedOps.h @@ -117,8 +117,12 @@ template class eoCombinedOp : public eoGeneralOp { public : - eoCombinedOp(const std::vector*>& _ops, const std::vector& rates) - : ops(_ops), rates(_rates) {} + eoCombinedOp& bind(const std::vector*>& _ops, const std::vector& _rates) + { + ops = &_ops; + rates = &_rates; + return *this; + } class eoDelayedSelector : public eoIndiSelector { @@ -147,7 +151,7 @@ class eoCombinedOp : public eoGeneralOp }; /** Applies all ops in the combined op - It works in the following way + It first applies the */ void operator()( eoIndiSelector& _in, eoInserter& _out ) @@ -156,7 +160,7 @@ class eoCombinedOp : public eoGeneralOp eoPop next; unsigned i; - for (i = 0; i < ops.size(); ++i) + for (i = 0; i < ops->size(); ++i) { eoDelayedSelector delay(_in, intermediate); inserter.bind(next); @@ -166,13 +170,13 @@ class eoCombinedOp : public eoGeneralOp // apply operators until we have as many outputs as inputs do { - if (flip(rates[i])) // should this flip be here? - (*ops[i])(delayedSelector, inserter); + if (rng.flip(rates->operator[](i))) // should this flip be here? + (*ops->operator[](i))(delay, inserter); counter++; if (counter > 1000) { - throw logical_error("eoCombinedOp: no termination after 1000 tries, did you forget to insert individuals in your eoGeneralOp?"); + throw logic_error("eoCombinedOp: no termination after 1000 tries, did you forget to insert individuals in your eoGeneralOp?"); } } while (next.size() < intermediate.size()); @@ -187,8 +191,8 @@ class eoCombinedOp : public eoGeneralOp } private : - const std::vector*>& ops; - const std::vector rates; + const std::vector*>* ops; + const std::vector* rates; eoBackInserter inserter; }; diff --git a/eo/src/gp/eoParseTree.h b/eo/src/gp/eoParseTree.h index 7be7c202..0b3eccf8 100644 --- a/eo/src/gp/eoParseTree.h +++ b/eo/src/gp/eoParseTree.h @@ -17,19 +17,12 @@ template class eoParseTree : public EO, public parse_tree { public : + + typedef parse_tree::subtree Subtree; + + eoParseTree(void) {} + eoParseTree(const parse_tree& tree) : parse_tree(tree) {} - typedef typename parse_tree::subtree Type; - - eoParseTree(void) : EO(), parse_tree() {} - eoParseTree(unsigned _size, eoRnd& _rnd) - : EO(), parse_tree(_rnd()) - { - pruneTree(_size); - } - eoParseTree(eoRnd& _rnd) - : EO(), parse_tree(_rnd()) - {} - virtual void pruneTree(unsigned _size) { if (_size < 1) @@ -37,7 +30,7 @@ public : if (size() > _size) { - Type* sub = &operator[](size() - 2); // prune tree + Subtree* sub = &operator[](size() - 2); // prune tree while (sub->size() > _size) { @@ -101,7 +94,7 @@ class eoGpDepthInitializer : public eoInit< eoParseTree > const vector& _initializor, bool _grow = true) : - eoRnd(), + eoInit(), max_depth(_max_depth), initializor(_initializor), grow(_grow) @@ -115,7 +108,8 @@ class eoGpDepthInitializer : public eoInit< eoParseTree > generate(sequence, max_depth); - _tree = parse_tree(sequence.begin(), sequence.end()); + parse_tree tmp(sequence.begin(), sequence.end()); + _tree.swap(tmp); } void generate(list& sequence, int the_max, int last_terminal = -1) @@ -180,10 +174,10 @@ public: /// Dtor virtual ~eoSubtreeXOver () {}; - void operator()(eoIndiSelector& _source, eoInserter& _sink ) const + void operator()(eoIndiSelector& _select, eoInserter& _insert ) { - EoType eo1 = _source.select(); - const EoType& eo2 = _source.select(); + EoType eo1 = _select(); + const EoType& eo2 = _select(); int i = rng.random(eo1.size()); int j = rng.random(eo2.size()); @@ -193,7 +187,7 @@ public: eo1.pruneTree(max_length); eo1.invalidate(); - _sink.insert(eo1); + _insert(eo1); } unsigned max_length; @@ -206,7 +200,7 @@ public: typedef eoParseTree EoType; - eoBranchMutation(eoRnd& _init, unsigned _max_length) + eoBranchMutation(eoInit& _init, unsigned _max_length) : eoGeneralOp(), max_length(_max_length), initializer(_init) {}; @@ -215,25 +209,28 @@ public: /// Dtor virtual ~eoBranchMutation() {}; - void operator()(eoIndiSelector& _source, eoInserter& _sink ) const + void operator()(eoIndiSelector& _select, eoInserter& _insert ) { - EoType eo1 = _source.select(); + EoType eo1 = _select(); int i = rng.random(eo1.size()); - EoType eo2(eo1[i].size(), initializer); // create random other to cross with + EoType eo2; + initializer(eo2); - eo1[i] = eo2.back(); // insert subtree + int j = rng.random(eo2.size()); + + eo1[i] = eo2[j]; // insert subtree eo1.pruneTree(max_length); - + eo1.invalidate(); - _sink.insert(eo1); + _insert(eo1); } private : unsigned max_length; - eoRnd& initializer; + eoInit& initializer; }; diff --git a/eo/src/gp/node_pool.h b/eo/src/gp/node_pool.h index ef5c4b42..94484b5b 100644 --- a/eo/src/gp/node_pool.h +++ b/eo/src/gp/node_pool.h @@ -148,7 +148,7 @@ public : if (arity == 0) return 0; - T* t new T [arity]; + T* t = new T [arity]; for (int i = 0; i < arity; ++i) { diff --git a/eo/src/gp/parse_tree.h b/eo/src/gp/parse_tree.h index 1ac2cf66..90be70bf 100644 --- a/eo/src/gp/parse_tree.h +++ b/eo/src/gp/parse_tree.h @@ -16,15 +16,6 @@ * modified is included with the above copyright notice. - * Special disclaimer and political statement: - - * In contrast with the rest of the EO package where you might have found this code, this software - * does NOT fall under the GNU Lesser Public License or the GNU Public License, nor is anyone allowed - * by the copyright holder (that's me) to put it under either license. - * Doing this would limit my and your freedom to use this software in any way - * you or I see fit, including but not limited to closed-source software. - - Usage information. @@ -173,7 +164,7 @@ namespace gp_parse_tree #include "node_pool.h" - +/// This ones defined because gcc does not always implement namespaces template inline void do_the_swap(T& a, T& b) { @@ -371,21 +362,20 @@ public : void swap(subtree& y) { - do_the_swap(content, y.content); - do_the_swap(args, y.args); - do_the_swap(parent, y.parent); + do_the_swap(content, y.content); + do_the_swap(args, y.args); + + adopt(); + y.adopt(); - do_the_swap(_cumulative_size, y._cumulative_size); - do_the_swap(_depth, y._depth); - do_the_swap(_size, y._size); + do_the_swap(parent, y.parent); + + do_the_swap(_cumulative_size, y._cumulative_size); + do_the_swap(_depth, y._depth); + do_the_swap(_size, y._size); updateAfterInsert(); } - friend void swap(subtree& x, subtree& y) - { - x.swap(y); - } - protected : virtual void updateAfterInsert(void) @@ -973,7 +963,7 @@ ptrdiff_t* distance_type(gp_parse_tree::parse_tree::iterator) return 0; } -// Put customized swaps also in std... +/* Put customized swaps also in std... template inline void swap(gp_parse_tree::parse_tree& a, gp_parse_tree::parse_tree& b) @@ -985,7 +975,7 @@ template inline void iter_swap(vector >::iterator a, vector > b) { a->swap(*b); -} +}*/ } // namespace std diff --git a/eo/src/utils/eoStat.h b/eo/src/utils/eoStat.h index a7d3c72f..142f400c 100644 --- a/eo/src/utils/eoStat.h +++ b/eo/src/utils/eoStat.h @@ -59,7 +59,7 @@ template class eoAverageStat : public eoStat { public : - eoAverageStat(std::string _description = "AverageFitness") : eoStat(0.0, _description) {} + eoAverageStat(std::string _description = "Average Fitness") : eoStat(0.0, _description) {} static double sumFitness(double _sum, const EOT& _eot) { @@ -103,6 +103,20 @@ public : } }; +template +class eoBestFitnessStat : public eoStat +{ +public : + typedef typename EOT::Fitness Fitness; + + eoBestFitnessStat(std::string _description = "Best Fitness") : eoStat(Fitness(), _description) {} + + virtual void operator()(const eoPop& _pop) + { + value() = _pop.nth_element_fitness(0); + } +}; + /* template class eoStdevStat : public eoStat diff --git a/eo/test/Makefile.am b/eo/test/Makefile.am index 81eadf58..9aea1d16 100644 --- a/eo/test/Makefile.am +++ b/eo/test/Makefile.am @@ -13,7 +13,7 @@ LDADDS = $(top_builddir)/src/libeo.a $(top_builddir)/src/utils/libeoutils.a ############################################################################### -noinst_PROGRAMS = t-eofitness t-eobin t-eoStateAndParser t-eoCheckpointing t-eoExternalEO t-eoESFull +noinst_PROGRAMS = t-eofitness t-eobin t-eoStateAndParser t-eoCheckpointing t-eoExternalEO t-eoESFull t-eoSymreg ############################################################################### @@ -57,4 +57,13 @@ t_eoExternalEO_LDADD = $(LDADDS) ############################################################################### +############################################################################### + +t_eoSymreg_SOURCES = t-eoSymreg.cpp +t_eoSymreg_DEPENDENCIES = $(DEPS) +t_eoSymreg_LDFLAGS = -lm +t_eoSymreg_LDADD = $(LDADDS) + +############################################################################### + diff --git a/eo/test/t-eoSymreg.cpp b/eo/test/t-eoSymreg.cpp index 5c995623..f7646730 100644 --- a/eo/test/t-eoSymreg.cpp +++ b/eo/test/t-eoSymreg.cpp @@ -1,7 +1,7 @@ #pragma warning(disable:4786) -#include "eoParseTree.h" -#include "eoEvalFunc.h" +#include +#include using namespace gp_parse_tree; using namespace std; @@ -20,34 +20,43 @@ public : // arity function, need this function! int arity(void) const { return op == X? 0 : 2; } - + + void randomize(void) {} + // evaluation function, single case, using first argument to give value of variable template - double operator()(double var, Children args) const + void operator()(double& result, Children args, double var) const { + double r1, r2; + + if (arity() == 2) + { + args[0].apply(r1, var); + args[1].apply(r2, var); + } + switch (op) { - case Plus : return args[0].apply(var) + args[1].apply(var); - case Min : return args[0].apply(var) - args[1].apply(var); - case Mult : return args[0].apply(var) * args[1].apply(var); + case Plus : result = r1 + r2; break; + case Min : result = r1 - r2; break; + case Mult : result = r1 * r2; break; case PDiv : { - double arg1 = args[1].apply(var); - if (arg1 == 0.0) - return 1.0; // protection a la Koza, realistic implementations should maybe throw an exception - - return args[0].apply(var) / arg1; + if (r2 == 0.0) + result = 1.0; // protection a la Koza, realistic implementations should maybe throw an exception + else + result = r1 / r2; + break; } - case X : return var; + case X : result = var; break; } - return var; // to avoid compiler error } /// 'Pretty' print to ostream function template - string operator()(string dummy, Children args) + void operator()(string& result, Children args) const { static const string lb = "("; static const string rb = ")"; @@ -56,13 +65,16 @@ public : if (arity() == 0) { - return string("x"); + result = "x"; + return; } // else - string result = lb + args[0].apply(dummy); + string r1; + args[0].apply(r1); + result = lb + r1; result += opStr; - result += args[1].apply(dummy) + rb; - return result; + args[1].apply(r1); + result += r1 + rb; } Operator getOp(void) const { return op; } @@ -100,15 +112,15 @@ std::istream& operator>>(std::istream& is, SymregNode& eot) //----------------------------------------------------------------------------- /** Implementation of a function evaluation object. */ -float targetFunction(float x) +double targetFunction(double x) { - return x * x * x * x - x * x * x + x * x * x - x * x + x - 1; + return x * x * x * x - x * x * x + x * x * x - x * x + x - 10; } // parameters controlling the sampling of points -const float xbegin = -10.0f; -const float xend = 10.0f; -const float xstep = 1.3f; +const double xbegin = -10.0f; +const double xend = 10.0f; +const double xstep = 1.3f; template struct RMS: public eoEvalFunc< eoParseTree > { @@ -128,7 +140,7 @@ public : int i = 0; - for (double x = xbegin; x < xend && i < n; ++i) + for (double x = xbegin; x < xend && i < n; ++i, x+=xstep) { target[i] = targetFunction(x); inputs[i] = x; @@ -137,7 +149,7 @@ public : ~RMS() {} - void operator()( EoType & _eo ) const + void operator()( EoType & _eo ) { vector outputs; outputs.resize(inputs.size()); @@ -146,7 +158,7 @@ public : for (int i = 0; i < inputs.size(); ++i) { - outputs[i] = _eo.apply(inputs[i]); + _eo.apply(outputs[i], inputs[i]); fitness += (outputs[i] - target[i]) * (outputs[i] - target[i]); } @@ -164,25 +176,6 @@ private : vector target; }; -#include "eoTerm.h" - -template -class eoGenerationTerm : public eoTerm -{ - public : - eoGenerationTerm(size_t _ngen) : eoTerm(), ngen(_ngen) {} - - bool operator()(const eoPop&) - { - cout << '.'; // pacifier - cout.flush(); - - return --ngen > 0; - } - private : - unsigned ngen; -}; - template void print_best(eoPop& pop) { @@ -201,7 +194,8 @@ void print_best(eoPop& pop) cout << "\t"; - string str = pop[index].apply(string()); + string str; + pop[index].apply(str); cout << str.c_str(); cout << endl << "RMS Error = " << pop[index].fitness() << endl; @@ -210,16 +204,15 @@ void print_best(eoPop& pop) #include #include "eoGOpBreeder.h" -#include "eoSequentialGOpSelector.h" -#include "eoProportionalGOpSelector.h" -#include "eoDetTournamentIndiSelector.h" +#include "eoSequentialGOpSel.h" +#include "eoProportionalGOpSel.h" #include "eoDetTournamentInserter.h" #include "eoSteadyStateEA.h" #include "eoScalarFitness.h" void main() { - typedef eoScalarFitness > FitnessType; + typedef eoMinimizingFitness FitnessType; typedef SymregNode GpNode; typedef eoParseTree EoType; @@ -237,7 +230,9 @@ void main() // Root Mean Squared Error Measure RMS eval; - Pop pop(500, MaxSize, initializer, eval); + Pop pop(500, initializer); + + apply(eval, pop); eoSubtreeXOver xover(MaxSize); eoBranchMutation mutation(initializer, MaxSize); @@ -247,15 +242,28 @@ void main() seqSel.addOp(mutation, 0.25); seqSel.addOp(xover, 0.75); - eoDetTournamentIndiSelector selector(5); + eoDetTournament selector(5); eoDetTournamentInserter inserter(eval, 5); // Terminators - eoGenerationTerm term(nGenerations); + eoGenContinue term(nGenerations); + + eoCheckPoint checkPoint(term); + + eoAverageStat avg; + eoBestFitnessStat best; + eoStdoutMonitor monitor; + + checkPoint.add(monitor); + checkPoint.add(avg); + checkPoint.add(best); + + monitor.add(avg); + monitor.add(best); // GP generation - eoSteadyStateEA gp(seqSel, selector, inserter, term); + eoSteadyStateEA gp(seqSel, selector, inserter, checkPoint); cout << "Initialization done" << endl; diff --git a/eo/win/Makefile.am b/eo/win/Makefile.am index 1f204e10..eab6c1f0 100644 --- a/eo/win/Makefile.am +++ b/eo/win/Makefile.am @@ -1,5 +1,5 @@ EXTRA_DIST=eo_win.dsw eo.dsp esfull.dsp t_eobin.dsp t_eoCheckpointing.dsp t_eofitness.dsp \ - t_eoFunctor.dsp t_externalEO.dsp t_StateAndParser.dsp + t_eoFunctor.dsp t_externalEO.dsp t_StateAndParser.dsp t_eoSymreg.dsp diff --git a/eo/win/eo_win.dsw b/eo/win/eo_win.dsw index ae9c722a..5b03cc95 100644 --- a/eo/win/eo_win.dsw +++ b/eo/win/eo_win.dsw @@ -75,6 +75,21 @@ Package=<4> ############################################################################### +Project: "t_eoSymreg"=.\t_eoSymreg.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name eo + End Project Dependency +}}} + +############################################################################### + Project: "t_eobin"=.\t_eobin.dsp - Package Owner=<4> Package=<5>