fix: refactor foundry to be more dynamic than static

- Remove size template in favor of dynamic container: allow using the
generic interface.
- Using `operator=` was inducing slicing.
This commit is contained in:
Johann Dreo 2020-04-12 16:26:37 +02:00
commit 11ff72bdd9
5 changed files with 56 additions and 55 deletions

View file

@ -23,8 +23,7 @@
#ifndef _eoAlgoFoundry_H_ #ifndef _eoAlgoFoundry_H_
#define _eoAlgoFoundry_H_ #define _eoAlgoFoundry_H_
#include <array> #include <vector>
#include <tuple>
/** /**
* *
@ -32,18 +31,23 @@
* @ingroup Foundry * @ingroup Foundry
* @ingroup Algorithms * @ingroup Algorithms
*/ */
template<class EOT, unsigned NBOP> template<class EOT>
class eoAlgoFoundry : public eoAlgo<EOT> class eoAlgoFoundry : public eoAlgo<EOT>
{ {
public: public:
static const size_t dim = NBOP; /**
/** The constructon only take an eval, because all other operators
* are stored in the public containers.
*/ */
eoAlgoFoundry() eoAlgoFoundry( size_t nb_operators ) :
_size(nb_operators),
_encoding(_size,0)
{ }
/** Select indices of all the operators.
*/
void select( std::vector<size_t> encoding )
{ {
_encoding = { 0 }; // dim * 0 assert(encoding.size() == _encoding.size());
_encoding = encoding;
} }
/** Access to the index of the currently selected operator. /** Access to the index of the currently selected operator.
@ -53,15 +57,14 @@ class eoAlgoFoundry : public eoAlgo<EOT>
return _encoding.at(i); return _encoding.at(i);
} }
/** Select indices of all the operators. size_t size() const
*/
void operator=( std::array<size_t,dim> a)
{ {
_encoding = a; return _size;
} }
protected: protected:
std::array<size_t, dim> _encoding; const size_t _size;
std::vector<size_t> _encoding;
}; };

View file

@ -76,10 +76,20 @@
* @ingroup Algorithms * @ingroup Algorithms
*/ */
template<class EOT> template<class EOT>
class eoAlgoFoundryEA : public eoAlgoFoundry<EOT,5> class eoAlgoFoundryEA : public eoAlgoFoundry<EOT>
{ {
public: public:
using eoAlgoFoundry<EOT,5>::dim; /** The constructon only take an eval, because all other operators
* are stored in the public containers.
*/
eoAlgoFoundryEA( eoPopEvalFunc<EOT>& eval, size_t max_gen ) :
eoAlgoFoundry<EOT>(5),
index_of(),
_eval(eval),
_max_gen(max_gen)
{ }
public:
struct Indices struct Indices
{ {
@ -93,17 +103,6 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT,5>
/** Helper for keeping track of the indices of the underlying encoding. */ /** Helper for keeping track of the indices of the underlying encoding. */
const Indices index_of; const Indices index_of;
/** The constructon only take an eval, because all other operators
* are stored in the public containers.
*/
eoAlgoFoundryEA( eoPopEvalFunc<EOT>& eval, size_t max_gen ) :
index_of(),
_eval(eval),
_max_gen(max_gen)
{
_encoding = { 0 }; // dim * 0
}
/* Operators containers @{ */ /* Operators containers @{ */
eoForgeVector< eoContinue<EOT> > continuators; eoForgeVector< eoContinue<EOT> > continuators;
eoForgeVector< eoQuadOp<EOT> > crossovers; eoForgeVector< eoQuadOp<EOT> > crossovers;
@ -116,11 +115,11 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT,5>
*/ */
void operator()(eoPop<EOT>& pop) void operator()(eoPop<EOT>& pop)
{ {
assert(continuators.size() > 0); assert(_encoding.at(index_of.continuators) < continuators.size()); assert(continuators.size() > 0); assert(this->at(index_of.continuators) < continuators.size());
assert( crossovers.size() > 0); assert(_encoding.at(index_of.crossovers) < crossovers.size()); assert( crossovers.size() > 0); assert(this->at(index_of.crossovers) < crossovers.size());
assert( mutations.size() > 0); assert(_encoding.at(index_of.mutations) < mutations.size()); assert( mutations.size() > 0); assert(this->at(index_of.mutations) < mutations.size());
assert( selectors.size() > 0); assert(_encoding.at(index_of.selectors) < selectors.size()); assert( selectors.size() > 0); assert(this->at(index_of.selectors) < selectors.size());
assert(replacements.size() > 0); assert(_encoding.at(index_of.replacements) < replacements.size()); assert(replacements.size() > 0); assert(this->at(index_of.replacements) < replacements.size());
eoSequentialOp<EOT> variator; eoSequentialOp<EOT> variator;
variator.add(this->crossover(), 1.0); variator.add(this->crossover(), 1.0);
@ -145,48 +144,47 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT,5>
std::string name() std::string name()
{ {
std::ostringstream name; std::ostringstream name;
name << _encoding.at(index_of.continuators) << " (" << this->continuator().className() << ") + "; name << this->at(index_of.continuators) << " (" << this->continuator().className() << ") + ";
name << _encoding.at(index_of.crossovers) << " (" << this->crossover().className() << ") + "; name << this->at(index_of.crossovers) << " (" << this->crossover().className() << ") + ";
name << _encoding.at(index_of.mutations) << " (" << this->mutation().className() << ") + "; name << this->at(index_of.mutations) << " (" << this->mutation().className() << ") + ";
name << _encoding.at(index_of.selectors) << " (" << this->selector().className() << ") + "; name << this->at(index_of.selectors) << " (" << this->selector().className() << ") + ";
name << _encoding.at(index_of.replacements) << " (" << this->replacement().className() << ")"; name << this->at(index_of.replacements) << " (" << this->replacement().className() << ")";
return name.str(); return name.str();
} }
protected: protected:
eoPopEvalFunc<EOT>& _eval; eoPopEvalFunc<EOT>& _eval;
const size_t _max_gen; const size_t _max_gen;
std::array<size_t, dim> _encoding;
public: public:
eoContinue<EOT>& continuator() eoContinue<EOT>& continuator()
{ {
assert(_encoding.at(index_of.continuators) < continuators.size()); assert(this->at(index_of.continuators) < continuators.size());
return continuators.instanciate(_encoding.at(index_of.continuators)); return continuators.instanciate(this->at(index_of.continuators));
} }
eoQuadOp<EOT>& crossover() eoQuadOp<EOT>& crossover()
{ {
assert(_encoding.at(index_of.crossovers) < crossovers.size()); assert(this->at(index_of.crossovers) < crossovers.size());
return crossovers.instanciate(_encoding.at(index_of.crossovers)); return crossovers.instanciate(this->at(index_of.crossovers));
} }
eoMonOp<EOT>& mutation() eoMonOp<EOT>& mutation()
{ {
assert(_encoding.at(index_of.mutations) < mutations.size()); assert(this->at(index_of.mutations) < mutations.size());
return mutations.instanciate(_encoding.at(index_of.mutations)); return mutations.instanciate(this->at(index_of.mutations));
} }
eoSelectOne<EOT>& selector() eoSelectOne<EOT>& selector()
{ {
assert(_encoding.at(index_of.selectors) < selectors.size()); assert(this->at(index_of.selectors) < selectors.size());
return selectors.instanciate(_encoding.at(index_of.selectors)); return selectors.instanciate(this->at(index_of.selectors));
} }
eoReplacement<EOT>& replacement() eoReplacement<EOT>& replacement()
{ {
assert(_encoding.at(index_of.replacements) < replacements.size()); assert(this->at(index_of.replacements) < replacements.size());
return replacements.instanciate(_encoding.at(index_of.replacements)); return replacements.instanciate(this->at(index_of.replacements));
} }
}; };

View file

@ -72,6 +72,8 @@ public:
static const size_t i_repl = eoAlgoFoundryEA<SUB>::Indices::replacements; static const size_t i_repl = eoAlgoFoundryEA<SUB>::Indices::replacements;
/** Decode the high-level problem encoding as an array of indices. /** Decode the high-level problem encoding as an array of indices.
*
* @note: If the EOT is an eoInt, this will be optimized out.
* *
* May be useful for getting a solution back into an eoAlgoFoundryEA. * May be useful for getting a solution back into an eoAlgoFoundryEA.
* @code * @code
@ -80,7 +82,7 @@ public:
* auto& cont = foundry.continuator(); // Get the configured operator * auto& cont = foundry.continuator(); // Get the configured operator
* @encode * @encode
*/ */
std::array<size_t,eoAlgoFoundryEA<SUB>::dim> decode( const EOT& sol ) std::vector<size_t> decode( const EOT& sol ) const
{ {
// Denormalize // Denormalize
size_t cont = static_cast<size_t>(std::ceil( sol[i_cont] * _foundry.continuators.size() )); size_t cont = static_cast<size_t>(std::ceil( sol[i_cont] * _foundry.continuators.size() ));
@ -121,7 +123,7 @@ public:
and 0 <= sele and sele < _foundry.selectors .size() and 0 <= sele and sele < _foundry.selectors .size()
and 0 <= repl and repl < _foundry.replacements.size() and 0 <= repl and repl < _foundry.replacements.size()
) { ) {
_foundry = config; _foundry.select(config);
// Actually perform a search // Actually perform a search
_foundry(pop); _foundry(pop);

View file

@ -65,10 +65,8 @@ eoAlgoFoundryEA<Bits>& make_foundry(eoFunctorStore& store, eoPopEvalFunc<Bits>&
// A basic PSO algorithm. // A basic PSO algorithm.
std::pair< eoAlgo<Particle>*, eoPop<Particle>* > std::pair< eoAlgo<Particle>*, eoPop<Particle>* >
make_pso(eoFunctorStore& store, eoEvalFunc<Particle>& eval_foundry) make_pso(eoFunctorStore& store, eoEvalFoundryEA<Particle,Bits>& eval_foundry, size_t dim)
{ {
const size_t dim = eoAlgoFoundryEA<Bits>::dim;
auto& gen_pos = store.pack< eoUniformGenerator<double> >(0.1,0.9); auto& gen_pos = store.pack< eoUniformGenerator<double> >(0.1,0.9);
auto& random_pos = store.pack< eoInitFixedLength<Particle> >(dim, gen_pos); auto& random_pos = store.pack< eoInitFixedLength<Particle> >(dim, gen_pos);
@ -133,13 +131,13 @@ int main(int /*argc*/, char** /*argv*/)
eoAlgo<Particle>* pso; eoAlgo<Particle>* pso;
eoPop<Particle>* pop_foundry; eoPop<Particle>* pop_foundry;
std::tie(pso, pop_foundry) = make_pso(store, eval_foundry); std::tie(pso, pop_foundry) = make_pso(store, eval_foundry, foundry.size());
// Perform the best algorithm configuration search. // Perform the best algorithm configuration search.
(*pso)(*pop_foundry); (*pso)(*pop_foundry);
// Print a glimpse of the best algorithm found. // Print a glimpse of the best algorithm found.
foundry = eval_foundry.decode(pop_foundry->best_element()); foundry.select(eval_foundry.decode(pop_foundry->best_element()));
std::cout << "Best algorithm: " << foundry.name() << std::endl; std::cout << "Best algorithm: " << foundry.name() << std::endl;
} }

View file

@ -84,7 +84,7 @@ int main(int /*argc*/, char** /*argv*/)
foundry.at(foundry.index_of.replacements) = i_rep; foundry.at(foundry.index_of.replacements) = i_rep;
// Or, if you know the order. // Or, if you know the order.
foundry = {i_cont, i_cross, i_mut, i_sel, i_rep}; foundry.select({i_cont, i_cross, i_mut, i_sel, i_rep});
// Actually perform a search // Actually perform a search
foundry(pop); foundry(pop);