feat add cache management to forges

- Disabled by default, because dangerous on statefull operators.
- More doc.
This commit is contained in:
Johann Dreo 2020-04-20 15:26:51 +02:00
commit 13d62d0445
2 changed files with 72 additions and 10 deletions

View file

@ -85,6 +85,11 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT>
eoAlgoFoundryEA( eoPopEvalFunc<EOT>& eval, size_t max_gen ) : eoAlgoFoundryEA( eoPopEvalFunc<EOT>& eval, size_t max_gen ) :
eoAlgoFoundry<EOT>(5), eoAlgoFoundry<EOT>(5),
index_of(), index_of(),
continuators(true), // Always re-instanciate continuators, because they hold a state.
crossovers(false),
mutations(false),
selectors(false),
replacements(false),
_eval(eval), _eval(eval),
_max_gen(max_gen) _max_gen(max_gen)
{ } { }

View file

@ -54,7 +54,9 @@
// } // }
/** /**
* @defgroup Foundry Tools for automatic algorithms assembling, selection and search. * @defgroup Foundry
*
* Tools for automatic algorithms assembling, selection and search.
*/ */
/** Interface for a "Forge": a class that can defer instanciation of EO's operator. /** Interface for a "Forge": a class that can defer instanciation of EO's operator.
@ -69,7 +71,7 @@ template<class Itf>
class eoForgeInterface class eoForgeInterface
{ {
public: public:
virtual Itf& instanciate() = 0; virtual Itf& instanciate(bool no_cache = true) = 0;
virtual ~eoForgeInterface() {} virtual ~eoForgeInterface() {}
}; };
@ -79,7 +81,7 @@ class eoForgeInterface
* You can declare a parametrized operator at a given time, * You can declare a parametrized operator at a given time,
* then actually instanciate it (with the given interface) at another time. * then actually instanciate it (with the given interface) at another time.
* *
* This allows for creating containers of pre-parametrized operators (@see eoForgeMap or @see eoForgeVector). * This allows for creating containers of pre-parametrized operators (@see eoForgeVector).
* *
* @code * @code
eoForgeOperator<eoselect<EOT>,eoRankMuSelect<EOT>> forge(mu); eoForgeOperator<eoselect<EOT>,eoRankMuSelect<EOT>> forge(mu);
@ -89,6 +91,10 @@ class eoForgeInterface
eoSelect<EOT>& select = forge.instanciate(); eoSelect<EOT>& select = forge.instanciate();
* @endcode * @endcode
* *
* @warning You may want to enable instanciation cache to grab some performances.
* The default is set to disable the cache, because its use with operators
* which hold a state will lead to unwanted behaviour.
*
* @ingroup Foundry * @ingroup Foundry
*/ */
template<class Itf, class Op, typename... Args> template<class Itf, class Op, typename... Args>
@ -100,9 +106,20 @@ class eoForgeOperator : public eoForgeInterface<Itf>
_instanciated(nullptr) _instanciated(nullptr)
{ } { }
Itf& instanciate() /** Instanciate the managed operator class.
*
* That is call its constructor with the set up arguments.
*
* @warning Do not enable cache with operators which hold a state.
*
* @param no_cache If false, will enable caching previous instances.
*/
Itf& instanciate(bool no_cache = true)
{ {
if(not _instanciated) { if(no_cache or not _instanciated) {
if(_instanciated) {
delete _instanciated;
}
_instanciated = constructor(_args); _instanciated = constructor(_args);
} }
return *_instanciated; return *_instanciated;
@ -117,6 +134,7 @@ class eoForgeOperator : public eoForgeInterface<Itf>
std::tuple<Args...> _args; std::tuple<Args...> _args;
private: private:
/** Metaprogramming machinery which deals with arguments lists @{ */
template <int... Idx> template <int... Idx>
struct index {}; struct index {};
@ -139,12 +157,14 @@ class eoForgeOperator : public eoForgeInterface<Itf>
{ {
return constructor(args, gen_seq<sizeof...(Ts)>{}); return constructor(args, gen_seq<sizeof...(Ts)>{});
} }
/** @} */
protected: protected:
Itf* _instanciated; Itf* _instanciated;
}; };
//! Partial specialization for constructors without any argument. /** Partial specialization for constructors without any argument.
*/
template<class Itf, class Op> template<class Itf, class Op>
class eoForgeOperator<Itf,Op> : public eoForgeInterface<Itf> class eoForgeOperator<Itf,Op> : public eoForgeInterface<Itf>
{ {
@ -153,9 +173,12 @@ class eoForgeOperator<Itf,Op> : public eoForgeInterface<Itf>
_instanciated(nullptr) _instanciated(nullptr)
{ } { }
Itf& instanciate() Itf& instanciate( bool no_cache = true )
{ {
if(not _instanciated) { if(no_cache or not _instanciated) {
if(_instanciated) {
delete _instanciated;
}
_instanciated = new Op; _instanciated = new Op;
} }
return *_instanciated; return *_instanciated;
@ -175,8 +198,12 @@ class eoForgeOperator<Itf,Op> : public eoForgeInterface<Itf>
* @note You can actually store several instances of the same class, * @note You can actually store several instances of the same class,
* with different parametrization (or not). * with different parametrization (or not).
* *
* @warning You may want to enable instanciation cache to grab some performances.
* The default is set to disable the cache, because its use with operators
* which hold a state will lead to unwanted behaviour.
*
* @code * @code
eoForgeVector<eoSelect<EOT>> factories; eoForgeVector<eoSelect<EOT>> factories(false);
// Capture constructor's parameters and defer instanciation. // Capture constructor's parameters and defer instanciation.
factories.add<eoRankMuSelect<EOT>>(1); factories.add<eoRankMuSelect<EOT>>(1);
@ -195,6 +222,26 @@ template<class Itf>
class eoForgeVector : public std::vector<eoForgeInterface<Itf>*> class eoForgeVector : public std::vector<eoForgeInterface<Itf>*>
{ {
public: public:
/** Default constructor do not cache instanciations.
*
* @warning
* You most probably want to disable caching for operators that hold a state.
* If you enable the cache, the last used instanciation will be used,
* at its last state.
* For example, continuators should most probably not be cached,
* as they very often hold a state in the form of a counter.
* At the end of a search, the continuator will be in the end state,
* and thus always ask for a stop.
* Reusing an instance in this state will de facto disable further searches.
*
* @param always_reinstanciate If false, will enable cache for the forges in this container.
*/
eoForgeVector( bool always_reinstanciate = true ) :
_no_cache(always_reinstanciate)
{ }
/** Add an operator to the list.
*/
template<class Op, typename... Args> template<class Op, typename... Args>
void add(Args... args) void add(Args... args)
{ {
@ -202,6 +249,8 @@ class eoForgeVector : public std::vector<eoForgeInterface<Itf>*>
this->push_back(pfo); this->push_back(pfo);
} }
/** Specialization for operators with empty constructors.
*/
template<class Op> template<class Op>
void add() void add()
{ {
@ -209,6 +258,10 @@ class eoForgeVector : public std::vector<eoForgeInterface<Itf>*>
this->push_back(pfo); this->push_back(pfo);
} }
/** Change the set up arguments to the constructor.
*
* @warning The operator at `index` should have been added with eoForgeVector::add already..
*/
template<class Op, typename... Args> template<class Op, typename... Args>
void setup(size_t index, Args... args) void setup(size_t index, Args... args)
{ {
@ -218,9 +271,11 @@ class eoForgeVector : public std::vector<eoForgeInterface<Itf>*>
this->at(index) = pfo; this->at(index) = pfo;
} }
/** Instanciate the operator managed at the given index.
*/
Itf& instanciate(size_t index) Itf& instanciate(size_t index)
{ {
return this->at(index)->instanciate(); return this->at(index)->instanciate(_no_cache);
} }
virtual ~eoForgeVector() virtual ~eoForgeVector()
@ -230,6 +285,8 @@ class eoForgeVector : public std::vector<eoForgeInterface<Itf>*>
} }
} }
protected:
bool _no_cache;
}; };
#endif // _eoForge_H_ #endif // _eoForge_H_