diff --git a/eo/src/eo b/eo/src/eo index fd660b7b9..b87ca57f1 100644 --- a/eo/src/eo +++ b/eo/src/eo @@ -78,6 +78,7 @@ #include #include #include +#include // Continuators - all include eoContinue.h #include diff --git a/eo/src/eoEvalKeepBest.h b/eo/src/eoEvalKeepBest.h new file mode 100644 index 000000000..0287cf1de --- /dev/null +++ b/eo/src/eoEvalKeepBest.h @@ -0,0 +1,107 @@ + +/* + 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; + version 2 of the License. + + 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 + + © 2012 Thales group + + Authors: + Johann Dreo +*/ + +#ifndef eoEvalKeepBest_H +#define eoEvalKeepBest_H + +#include +#include + +/** + Evaluate with the given evaluator and keep the best individual found so far. + + This is useful if you use a non-monotonic algorithm, such as CMA-ES, where the + population's best fitness can decrease between two generations. This is + sometime necessary and one can't use elitist replacors, as one do not want to + introduce a bias in the population. + + The eoEvalBestKeep is a wrapper around a classical evaluator, that keep the + best individual it has found since its instanciation. + + To get the best individual, you have to call best_element() on the + eoEvalKeepBest itself, and not on the population (or else you would get the + best individual found at the last generation). + + Example: + + MyEval true_eval; + eoEvalKeepBest wrapped_eval( true_eval ); + + // as an interesting side effect, you will get the best individual since + // initalization. + eoPop pop( my_init ); + eoPopLoopEval loop_eval( wrapped_eval ); + + loop_eval( pop ); + + eoEasyEA algo( …, wrapped_eval, … ); + + algo(pop); + + // do not use pop.best_element()! + std::cout << wrapped_eval.best_element() << std::endl; + + @ingroup Evaluation + */ +template class eoEvalKeepBest : public eoEvalFunc, public eoValueParam +{ + public : + eoEvalKeepBest(eoEvalFunc& _func, std::string _name = "VeryBest. ") + : eoValueParam(EOT(), _name), func(_func) {} + + virtual void operator()(EOT& sol) + { + if( sol.invalid() ) { + func(sol); // evaluate + + // if there is no best kept + if( this->value().invalid() ) { + // take the first individual as best + this->value() = sol; + } else { + // if sol is better than the kept individual + if( sol.fitness() > this->value().fitness() ) { + this->value() = sol; + } + } + } // if invalid + } + + //! Return the best individual found so far. + EOT best_element() + { + return this->value(); + } + + /** Reset the best individual to the given one. If no individual is + * provided, the next evaluated one will be taken as a reference. + */ + void reset( const EOT& new_best = EOT() ) + { + this->value() = new_best; + } + + protected : + eoEvalFunc& func; +}; + +#endif diff --git a/eo/test/CMakeLists.txt b/eo/test/CMakeLists.txt index 5f098d3bf..db415bebc 100644 --- a/eo/test/CMakeLists.txt +++ b/eo/test/CMakeLists.txt @@ -34,6 +34,7 @@ ENDIF() ###################################################################################### SET (TEST_LIST + t-eoEvalKeepBest t-eoInitVariableLength t-eofitness t-eoRandom diff --git a/eo/test/t-eoEvalKeepBest.cpp b/eo/test/t-eoEvalKeepBest.cpp new file mode 100644 index 000000000..fdcdae866 --- /dev/null +++ b/eo/test/t-eoEvalKeepBest.cpp @@ -0,0 +1,78 @@ +#include + +#include +#include +#include +#include "real_value.h" + +using namespace std; + +int main(int argc, char* argv[]) +{ + + typedef eoReal EOT; + + eoParser parser(argc, argv); // for user-parameter reading + eoState state; // keeps all things allocated + + + /********************************************* + * problem or representation dependent stuff * + *********************************************/ + + // The evaluation fn - encapsulated into an eval counter for output + eoEvalFuncPtr&> + main_eval( real_value ); // use a function defined in real_value.h + + // wrap the evaluation function in a call counter + eoEvalFuncCounter eval_counter(main_eval); + + // the genotype - through a genotype initializer + eoRealInitBounded& init = make_genotype(parser, state, EOT()); + + // Build the variation operator (any seq/prop construct) + eoGenOp& op = make_op(parser, state, init); + + + /********************************************* + * Now the representation-independent things * + *********************************************/ + + + // initialize the population - and evaluate + // yes, this is representation indepedent once you have an eoInit + eoPop& pop = make_pop(parser, state, init); + + // stopping criteria + eoContinue & term = make_continue(parser, state, eval_counter); + + // things that are called at each generation + eoCheckPoint & checkpoint = make_checkpoint(parser, state, eval_counter, term); + + // wrap the evaluator in another one that will keep the best individual + // evaluated so far + eoEvalKeepBest eval_keep( eval_counter ); + + // algorithm + eoAlgo& ea = make_algo_scalar(parser, state, eval_keep, checkpoint, op); + + + /*************************************** + * Now, call functors and DO something * + ***************************************/ + + // to be called AFTER all parameters have been read! + make_help(parser); + + // evaluate intial population AFTER help and status in case it takes time + apply(eval_keep, pop); + + std::clog << "Best individual after initialization and " << eval_counter.value() << " evaluations" << std::endl; + std::cout << eval_keep.best_element() << std::endl; + + ea(pop); // run the ea + + std::cout << "Best individual after search and " << eval_counter.value() << " evaluations" << std::endl; + // you can also call value(), because it is an eoParam + std::cout << eval_keep.value() << std::endl; +}