diff --git a/eo/src/eoForge.h b/eo/src/eoForge.h index c4a3e78cd..02ddb6c8c 100644 --- a/eo/src/eoForge.h +++ b/eo/src/eoForge.h @@ -70,15 +70,22 @@ class eoForgeOperator : public eoForgeInterface { public: eoForgeOperator(Args&&... args) : - _args(std::forward(args)...) + _args(std::forward(args)...), + _instanciated(nullptr) { } Itf& instanciate() { - return *(constructor(_args)); + if(not _instanciated) { + _instanciated = constructor(_args); + } + return *_instanciated; } - virtual ~eoForgeOperator() {} + virtual ~eoForgeOperator() + { + delete _instanciated; + } protected: std::tuple _args; @@ -97,6 +104,7 @@ class eoForgeOperator : public eoForgeInterface Op* constructor(std::tuple& args, index) { Op* p_op = new Op(std::get(args)...); + _instanciated = p_op; return p_op; } @@ -106,50 +114,33 @@ class eoForgeOperator : public eoForgeInterface return constructor(args, gen_seq{}); } + protected: + Itf* _instanciated; }; -/** A map holding an operator with deferred instanciation at a given key. - * - * @note You can actually store several instances of the same class, - * with different parametrization (or not). - * - * @code - eoForgeMap> named_factories; - - // Capture constructor's parameters and defer instanciation. - named_factories.add>("RMS", 1); - named_factories.setup>("RMS", 5); // Edit - - // Actually instanciate. - eoSelect& op = named_factories.instanciate("RMS"); - - // Call. - op(); - * @endcode - * - * @ingroup Forge - */ -template -class eoForgeMap : public std::map> > +template +class eoForgeOperator : public eoForgeInterface { public: - template - void setup(std::string key, Args&&... args) + eoForgeOperator() : + _instanciated(nullptr) + { } + + Itf& instanciate() { - auto opf = std::make_shared< eoForgeOperator >(std::forward(args)...); - (*this)[key] = opf; + if(not _instanciated) { + _instanciated = new Op; + } + return *_instanciated; } - template - void add(std::string key, Args&&... args) + virtual ~eoForgeOperator() { - setup(key, std::forward(args)...); + delete _instanciated; } - Itf& instanciate(std::string key) - { - return this->at(key)->instanciate(); - } + protected: + Itf* _instanciated; }; /** A vector holding an operator with deferred instanciation at a given index. @@ -174,27 +165,44 @@ class eoForgeMap : public std::map -class eoForgeVector : public std::vector> > +class eoForgeVector : public std::vector*> { public: template void add(Args&&... args) { - auto opf = std::make_shared< eoForgeOperator >(std::forward(args)...); - this->push_back(opf); + auto pfo = new eoForgeOperator(std::forward(args)...); + this->push_back(pfo); + } + + template + void add() + { + eoForgeInterface* pfo = new eoForgeOperator; + this->push_back(pfo); } template void setup(size_t index, Args&&... args) { - auto opf = std::make_shared< eoForgeOperator >(std::forward(args)...); - this->at(index) = opf; + assert(this->at(index) != nullptr); + delete this->at(index); + auto pfo = new eoForgeOperator(std::forward(args)...); + this->at(index) = pfo; } Itf& instanciate(size_t index) { return this->at(index)->instanciate(); } + + virtual ~eoForgeVector() + { + for(auto p : *this) { + delete p; + } + } + }; #endif // _eoForge_H_ diff --git a/eo/test/CMakeLists.txt b/eo/test/CMakeLists.txt index d8c44b516..b392df824 100644 --- a/eo/test/CMakeLists.txt +++ b/eo/test/CMakeLists.txt @@ -73,6 +73,7 @@ set (TEST_LIST t-eoEvalCmd t-operator-forge t-forge-algo + t-algo-forged ) diff --git a/eo/test/t-algo-forged.cpp b/eo/test/t-algo-forged.cpp new file mode 100644 index 000000000..acee25f99 --- /dev/null +++ b/eo/test/t-algo-forged.cpp @@ -0,0 +1,218 @@ +#include +#include + +#include +#include +#include "../../problems/eval/oneMaxEval.h" + +template +class eoFoundryEA : public eoAlgo +{ + public: + static const size_t dim = 5; + + protected: + std::array _encoding; + + struct Indices + { + static const size_t continuators = 0; + static const size_t crossovers = 1; + static const size_t mutations = 2; + static const size_t selectors = 3; + static const size_t replacements = 4; + }; + + public: + const Indices index_of; + + eoFoundryEA( eoEvalFunc& eval ) : + index_of(), + _eval(eval) + { + _encoding = { 0 }; // dim * 0 + } + + size_t& at(size_t i) + { + return _encoding.at(i); + } + + void operator=( std::array a) + { + _encoding = a; + } + + eoForgeVector< eoContinue > continuators; + eoForgeVector< eoQuadOp > crossovers; + eoForgeVector< eoMonOp > mutations; + eoForgeVector< eoSelectOne > selectors; + eoForgeVector< eoReplacement > replacements; + + void operator()(eoPop& pop) + { + assert(continuators.size() > 0); assert(_encoding.at(index_of.continuators) < continuators.size()); + assert( crossovers.size() > 0); assert(_encoding.at(index_of.crossovers) < crossovers.size()); + assert( mutations.size() > 0); assert(_encoding.at(index_of.mutations) < mutations.size()); + assert( selectors.size() > 0); assert(_encoding.at(index_of.selectors) < selectors.size()); + assert(replacements.size() > 0); assert(_encoding.at(index_of.replacements) < replacements.size()); + + eoSequentialOp variator; + variator.add(this->crossover(), 1.0); + variator.add(this->mutation(), 1.0); + + eoGeneralBreeder breeder(this->selector(), variator, 1.0); + + eoGenContinue common_cont(100); + eoCombinedContinue gen_cont(common_cont); + gen_cont.add(this->continuator()); + + eoEasyEA algo = eoEasyEA(gen_cont, _eval, breeder, this->replacement()); + + algo(pop); + } + + std::string name() + { + std::ostringstream name; + name << _encoding.at(index_of.continuators) << " (" << this->continuator().className() << ") + "; + name << _encoding.at(index_of.crossovers) << " (" << this->crossover().className() << ") + "; + name << _encoding.at(index_of.mutations) << " (" << this->mutation().className() << ") + "; + name << _encoding.at(index_of.selectors) << " (" << this->selector().className() << ") + "; + name << _encoding.at(index_of.replacements) << " (" << this->replacement().className() << ")"; + return name.str(); + } + + protected: + eoEvalFunc& _eval; + + eoContinue& continuator() + { + assert(_encoding.at(index_of.continuators) < continuators.size()); + return continuators.instanciate(_encoding.at(index_of.continuators)); + } + + eoQuadOp& crossover() + { + assert(_encoding.at(index_of.crossovers) < crossovers.size()); + return crossovers.instanciate(_encoding.at(index_of.crossovers)); + } + + eoMonOp& mutation() + { + assert(_encoding.at(index_of.mutations) < mutations.size()); + return mutations.instanciate(_encoding.at(index_of.mutations)); + } + + eoSelectOne& selector() + { + assert(_encoding.at(index_of.selectors) < selectors.size()); + return selectors.instanciate(_encoding.at(index_of.selectors)); + } + + eoReplacement& replacement() + { + assert(_encoding.at(index_of.replacements) < replacements.size()); + return replacements.instanciate(_encoding.at(index_of.replacements)); + } + +}; + + +int main(int /*argc*/, char** /*argv*/) +{ + size_t dim = 500; + size_t pop_size = 10; + + eo::log << eo::setlevel(eo::warnings); + + using EOT = eoBit; + + oneMaxEval eval; + + eoBooleanGenerator gen(0.5); + eoInitFixedLength init(dim, gen); + + eoFoundryEA foundry(eval); + + /***** Continuators ****/ + for(size_t i=10; i < 30; i+=10 ) { + foundry.continuators.add< eoSteadyFitContinue >(10,i); + } + + /***** Crossovers ****/ + foundry.crossovers.add< eo1PtBitXover >(); + foundry.crossovers.add< eoUBitXover >(0.5); // preference over 1 + + for(size_t i=1; i < 11; i+=4) { + foundry.crossovers.add< eoNPtsBitXover >(i); // nb of points + } + + /***** Mutations ****/ + foundry.mutations.add< eoBitMutation >(0.01); // proba of flipping one bit + for(size_t i=1; i < 11; i+=4) { + foundry.mutations.add< eoDetBitFlip >(i); // mutate k bits + } + + foundry.selectors.add< eoStochTournamentSelect >(0.5); + foundry.selectors.add< eoSequentialSelect >(); + foundry.selectors.add< eoProportionalSelect >(); + for(size_t i=2; i < 10; i+=4) { + foundry.selectors.add< eoDetTournamentSelect >(i); + } + + /***** Replacements ****/ + foundry.replacements.add< eoCommaReplacement >(); + foundry.replacements.add< eoPlusReplacement >(); + foundry.replacements.add< eoSSGAWorseReplacement >(); + for(size_t i=2; i < 10; i+=4) { + foundry.replacements.add< eoSSGADetTournamentReplacement >(i); + } + foundry.replacements.add< eoSSGAStochTournamentReplacement >(0.51); + + + size_t n = foundry.continuators.size() * foundry.crossovers.size() * foundry.mutations.size() * foundry.selectors.size() * foundry.replacements.size(); + std::clog << n << " possible algorithms instances." << std::endl; + + EOT best_sol; + std::string best_algo = ""; + + size_t i=0; + for(size_t i_cont = 0; i_cont < foundry.continuators.size(); ++i_cont ) { + for(size_t i_cross = 0; i_cross < foundry.crossovers.size(); ++i_cross ) { + for(size_t i_mut = 0; i_mut < foundry.mutations.size(); ++i_mut ) { + for(size_t i_sel = 0; i_sel < foundry.selectors.size(); ++i_sel ) { + for(size_t i_rep = 0; i_rep < foundry.replacements.size(); ++i_rep ) { + std::clog << "\r" << i++ << "/" << n-1; std::clog.flush(); + + eoPop pop; + pop.append(pop_size, init); + apply(eval,pop); + + foundry.at(foundry.index_of.continuators) = i_cont; + foundry.at(foundry.index_of.crossovers) = i_cross; + foundry.at(foundry.index_of.mutations) = i_mut; + foundry.at(foundry.index_of.selectors) = i_sel; + foundry.at(foundry.index_of.replacements) = i_rep; + + // Or, if you know the order. + foundry = {i_cont, i_cross, i_mut, i_sel, i_rep}; + + // Actually perform a search + foundry(pop); + + if(best_sol.invalid()) { + best_sol = pop.best_element(); + best_algo = foundry.name(); + } else if(pop.best_element().fitness() > best_sol.fitness()) { + best_sol = pop.best_element(); + best_algo = foundry.name(); + } + } + } + } + } + } + std::cout << std::endl << "Best algo: " << best_algo << ", with " << best_sol << std::endl; + +} diff --git a/eo/test/t-forge-algo.cpp b/eo/test/t-forge-algo.cpp index b1304e05f..b6df3d293 100644 --- a/eo/test/t-forge-algo.cpp +++ b/eo/test/t-forge-algo.cpp @@ -19,6 +19,8 @@ int main(int /*argc*/, char** /*argv*/) eoBooleanGenerator gen(0.5); eoInitFixedLength init(dim, gen); + eoGenContinue common_cont(100); + eoForgeVector< eoContinue > continuators; continuators.add< eoSteadyFitContinue >(10,10); continuators.add< eoGenContinue >(100); @@ -46,7 +48,7 @@ int main(int /*argc*/, char** /*argv*/) replacors.add< eoSSGAStochTournamentReplacement >(0.51); std::clog << continuators.size() * crossovers.size() * mutations.size() * selectors.size() * replacors.size() - << " algorithm instances to test." << std::endl; + << " possible algorithms instances." << std::endl; EOT best_sol; std::string best_algo = ""; @@ -82,7 +84,10 @@ int main(int /*argc*/, char** /*argv*/) eoGeneralBreeder breeder(selector, variator, 1.0); - eoEasyEA algo(continuator, eval, breeder, replacor); + eoCombinedContinue gen_cont(common_cont); + gen_cont.add(continuator); + + eoEasyEA algo(gen_cont, eval, breeder, replacor); eoPop pop; pop.append(pop_size, init); diff --git a/eo/test/t-operator-forge.cpp b/eo/test/t-operator-forge.cpp index a764b9b30..8c7eee0d7 100644 --- a/eo/test/t-operator-forge.cpp +++ b/eo/test/t-operator-forge.cpp @@ -24,27 +24,6 @@ struct OpB : public OpInterface int main(int /*argc*/, char** /*argv*/) { - // Forge container using names. - eoForgeMap named_factories; - - // Capture constructor's parameters and defer instanciation. - named_factories.add("OpA", "I'm A"); - named_factories.setup("OpA", "I'm actually A"); // Edit - named_factories.add("OpB1", "I'm B", " prime"); - named_factories.add("OpB2", "I'm a B", " junior"); - - // Actually instanciante. - OpInterface& opa = named_factories.instanciate("OpA"); - OpInterface& opb1 = named_factories.instanciate("OpB1"); - - // Call. - opa(); - opb1(); - - // Instanciate and call. - named_factories.instanciate("OpB2")(); - - // Forge container using indices. eoForgeVector indexed_factories;