fix eoAlgoFoundry management of numeric parameters
- Use a variant to avoid implicit casting to integer when selecting with brace-initialization. - Add more doc around parameter forges.
This commit is contained in:
parent
3a6236594e
commit
02eb0e967d
11 changed files with 393 additions and 163 deletions
|
|
@ -15,6 +15,7 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
© 2020 Thales group
|
||||
© 2022 Institut Pasteur
|
||||
|
||||
Authors:
|
||||
Johann Dreo <johann.dreo@thalesgroup.com>
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
#define _eoAlgoFoundry_H_
|
||||
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
/** A vector of eoForge which hold an index.
|
||||
*
|
||||
|
|
@ -36,13 +38,13 @@
|
|||
* which takes the class name as template and its constructor's parameters
|
||||
* as arguments. For example:
|
||||
* @code
|
||||
* eoOperatorFoundry< eoSelectOne<EOT> > selectors;
|
||||
* selectors.add< eoStochTournamentSelect<EOT> >( 0.5 );
|
||||
* eoOperatorFoundry< eoSelectOne<EOT> > selectors;
|
||||
* selectors.add< eoStochTournamentSelect<EOT> >( 0.5 );
|
||||
* @endcode
|
||||
*
|
||||
* @warning If the managed constructor takes a reference YOU SHOULD ABSOLUTELY wrap it
|
||||
* in a `std::ref` when using `add` or `setup`, or it will silently be passed as a copy,
|
||||
* which would effectively disable any link between operators.
|
||||
* in a `std::ref` when using `add` or `setup`, or it will silently be passed as a copy,
|
||||
* which would effectively disable any link between operators.
|
||||
*
|
||||
* @ingroup Core
|
||||
* @ingroup Foundry
|
||||
|
|
@ -51,11 +53,18 @@ template<class Itf>
|
|||
class eoOperatorFoundry : public eoForgeVector< Itf >
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
*
|
||||
* @param encoding_index The slot position in the encodings, at which this operator is held.
|
||||
* @param always_reinstantiate If false, will enable cache for the forges in this container.
|
||||
*/
|
||||
eoOperatorFoundry(size_t encoding_index, bool always_reinstantiate = true ) :
|
||||
eoForgeVector<Itf>(always_reinstantiate),
|
||||
_index(encoding_index)
|
||||
{ }
|
||||
|
||||
/** Returns the slot index at which this is registered.
|
||||
*/
|
||||
size_t index() const { return _index; }
|
||||
|
||||
protected:
|
||||
|
|
@ -63,6 +72,24 @@ class eoOperatorFoundry : public eoForgeVector< Itf >
|
|||
size_t _index;
|
||||
};
|
||||
|
||||
|
||||
/** A vector of eoForge which hold a scalar numeric value.
|
||||
*
|
||||
* To be used in conjunction with a subclass of an eoAlgoFoundry,
|
||||
* where it can hold a range of parameter values
|
||||
* and hold the link to the encoding. @see eoAlgoFoundryEA
|
||||
*
|
||||
* As with eoForgeScalar, managed parameters
|
||||
* are represented through a [min,max] range.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* eoParameterFoundry< double > proba(0.0, 1.0);
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup Core
|
||||
* @ingroup Foundry
|
||||
*/
|
||||
template<class Itf>
|
||||
class eoParameterFoundry : public eoForgeScalar< Itf >
|
||||
{
|
||||
|
|
@ -70,11 +97,26 @@ class eoParameterFoundry : public eoForgeScalar< Itf >
|
|||
"eoParameterFoundry should only be used on arithmetic types (i.e. integer or floating point types)");
|
||||
|
||||
public:
|
||||
/** Underlying type of the parameter.
|
||||
*
|
||||
* @note: You probably only want to use either `double` or `size_t`.
|
||||
* @see eoAlgoFoundry
|
||||
*/
|
||||
using Type = Itf;
|
||||
|
||||
/** Constructor
|
||||
*
|
||||
* @param encoding_index The slot position in the encodings, at which this parameter is held.
|
||||
* @param min Minimium possible value.
|
||||
* @param max Maximum possible value.
|
||||
*/
|
||||
eoParameterFoundry(size_t encoding_index, Itf min, Itf max) :
|
||||
eoForgeScalar<Itf>(min, max),
|
||||
_index(encoding_index)
|
||||
{ }
|
||||
|
||||
/** Returns the slot index at which this is registered.
|
||||
*/
|
||||
size_t index() const { return _index; }
|
||||
|
||||
protected:
|
||||
|
|
@ -84,48 +126,54 @@ class eoParameterFoundry : public eoForgeScalar< Itf >
|
|||
|
||||
/** Interface of a Foundry: a class that instantiate an eoAlgo on-the-fly, given a choice of its operators.
|
||||
*
|
||||
* The chosen operators are encoded in a vector of indices.
|
||||
* The chosen operators are encoded in a vector of numbers.
|
||||
*
|
||||
* The foundry subclass should first be set up with sets of operators of the same interface,
|
||||
* held within an eoOperatorFoundry member.
|
||||
* @code
|
||||
* eoOperatorFoundry< eoSelectOne<EOT> > selectors;
|
||||
* eoOperatorFoundry< eoSelectOne<EOT> > selectors;
|
||||
* @endcode
|
||||
*
|
||||
* In a second step, the operators to be used should be selected
|
||||
* by indicating their index, just like if the foundry was an array:
|
||||
* @code
|
||||
* foundry.select({0, 1, 2});
|
||||
* // ^ ^ ^
|
||||
* // | | |
|
||||
* // | | + 3d operator
|
||||
* // | + 2d operator
|
||||
* // + 1st operator
|
||||
* foundry.select({size_t{0}, size_t{1}, size_t{2}});
|
||||
* // ^ ^ ^
|
||||
* // | | |
|
||||
* // | | + 3d operator
|
||||
* // | + 2d operator
|
||||
* // + 1st operator
|
||||
* @endcode
|
||||
*
|
||||
* If you don't (want to) recall the order of the operators in the encoding,
|
||||
* you can use the `index()` member of eoOperatorFoundry, for example:
|
||||
* @code
|
||||
* foundry.at(foundry.continuators.index()) = 2; // select the third continuator
|
||||
* foundry.at(foundry.continuators.index()) = size_t{2}; // select the third continuator
|
||||
* @endcode
|
||||
*
|
||||
* Now, you must implement the foundry just like any eoAlgo, by using the eoPop interface:
|
||||
* @code
|
||||
* foundry(pop);
|
||||
* foundry(pop);
|
||||
* @encode
|
||||
* It will instantiate the needed operators (only) and the algorithm itself on-the-fly,
|
||||
* and then run it.
|
||||
*
|
||||
* @note: The "encoding" which represent the selected options, figuring the actual meta-algorithm,
|
||||
* is a vector of `std::variant`, which can hold either a `size_t` or a `double`.
|
||||
* The first one is used to indicate the index of an operator class
|
||||
* *or* a parameter which is a size.
|
||||
* The second is used to store numerical parameters values.
|
||||
*
|
||||
* @note: Thanks to the underlying eoOperatorFoundry, not all the added operators are instantiated.
|
||||
* Every instantiation is deferred upon actual use. That way, you can still reconfigure them
|
||||
* at any time with `eoForgeOperator::setup`, for example:
|
||||
* @code
|
||||
* foundry.selector.at(0).setup(0.5); // using constructor's arguments
|
||||
* @endcode
|
||||
* Every instantiation is deferred upon actual use. That way, you can still reconfigure them
|
||||
* at any time with `eoForgeOperator::setup`, for example:
|
||||
* @code
|
||||
* foundry.selector.at(0).setup(0.5); // using constructor's arguments
|
||||
* @endcode
|
||||
*
|
||||
* @warning If the managed constructor takes a reference YOU SHOULD ABSOLUTELY wrap it
|
||||
* in a `std::ref` when using `add` or `setup`, or it will silently be passed as a copy,
|
||||
* which would effectively disable any link between operators.
|
||||
* in a `std::ref` when using `add` or `setup`, or it will silently be passed as a copy,
|
||||
* which would effectively disable any link between operators.
|
||||
*
|
||||
* @ingroup Core
|
||||
* @ingroup Foundry
|
||||
|
|
@ -135,30 +183,104 @@ template<class EOT>
|
|||
class eoAlgoFoundry : public eoAlgo<EOT>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
// We could use `std::any` instead of a variant,
|
||||
// but this would be more prone to errors from the end user, at the end.
|
||||
// Either the encoding is an index (of the operator within the list of instances)
|
||||
// either it's a real-valued parameter,
|
||||
// either it's a size.
|
||||
// So there's no need for more types (AFAIK).
|
||||
|
||||
/** The type use to represent a selected option in the meta-algorithm.
|
||||
*
|
||||
* This can figure, either:
|
||||
* - the index of an operator in the list of possible ones,
|
||||
* - the actual value of a numeric paramater,
|
||||
* - the value of a parameter which is a size.
|
||||
*/
|
||||
eoAlgoFoundry( size_t nb_operators ) :
|
||||
_size(nb_operators),
|
||||
_encoding(_size,0)
|
||||
using Encoding = std::variant<size_t, double>;
|
||||
|
||||
/** The type use to store all selected options.
|
||||
*/
|
||||
using Encodings = std::vector<Encoding>;
|
||||
|
||||
/** Constructor.
|
||||
*
|
||||
* @param nb_slots Number of operators or parameters that are assembled to make an algorithm.
|
||||
*/
|
||||
eoAlgoFoundry( size_t nb_slots ) :
|
||||
_size(nb_slots)
|
||||
{ }
|
||||
|
||||
/** Select indices of all the operators.
|
||||
*
|
||||
* i.e. Select an algorithm to instantiate.
|
||||
*
|
||||
* @note: You need to indicate the type of each item
|
||||
* if you want to call this with a brace-initialized vector.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* foundry.select({ size_t{1}, double{0.5}, size_t{3} });
|
||||
* @endcode
|
||||
*
|
||||
* Or you can initialize the vector first:
|
||||
* @code
|
||||
* double crossover_rate = 0.5;
|
||||
* size_t crossover_oper = 3;
|
||||
* eoAlgoFoundry<EOT>::Encodings encoded_algo(foundry.size());
|
||||
* encoded_algo[foundry.crossover_rates.index()] = crossover_rate;
|
||||
* encoded_algo[foundry.crossover_opers.index()] = crossover_oper;
|
||||
* @encdoe
|
||||
*/
|
||||
void select( std::vector<size_t> encoding )
|
||||
void select( Encodings encodings )
|
||||
{
|
||||
assert(encoding.size() == _encoding.size());
|
||||
_encoding = encoding;
|
||||
assert(encodings.size() == _size);
|
||||
_encodings = encodings;
|
||||
}
|
||||
|
||||
/** Access to the index of the currently selected operator.
|
||||
/** Access to the encoding of the currently selected operator.
|
||||
*
|
||||
* @warning: This returns a `std::variant`, which you should `std::get<T>`.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* size_t opera_id = std::get<size_t>(foundry.at(2));
|
||||
* double param_id = std::get<double>(foundry.at(3));
|
||||
* @endcode
|
||||
*
|
||||
* @note: You can use rank, value or len to have automatic casting.
|
||||
*/
|
||||
size_t& at(size_t i)
|
||||
Encoding & at(size_t i)
|
||||
{
|
||||
return _encoding.at(i);
|
||||
return _encodings.at(i);
|
||||
}
|
||||
|
||||
/** Access to the currently selected ID of an operator.
|
||||
*/
|
||||
template<class OP>
|
||||
size_t rank(const OP& op)
|
||||
{
|
||||
return std::get<size_t>( at(op.index()) );
|
||||
}
|
||||
|
||||
/** Access to the currently selected value of a numeric parameter.
|
||||
*/
|
||||
template<class OP>
|
||||
double value(const OP& param)
|
||||
{
|
||||
return std::get<double>( at(param.index()) );
|
||||
}
|
||||
|
||||
/** Access to the currently selected value of a unsigned integer parameter.
|
||||
*/
|
||||
template<class OP>
|
||||
size_t len(const OP& param)
|
||||
{
|
||||
return std::get<size_t>( at(param.index()) );
|
||||
}
|
||||
|
||||
/** Returns the number of slots that makes this algorithm.
|
||||
*/
|
||||
size_t size() const
|
||||
{
|
||||
return _size;
|
||||
|
|
@ -166,14 +288,14 @@ class eoAlgoFoundry : public eoAlgo<EOT>
|
|||
|
||||
/** Return the underlying encoding vector.
|
||||
*/
|
||||
std::vector<size_t> encoding() const
|
||||
Encodings encodings() const
|
||||
{
|
||||
return _encoding;
|
||||
return _encodings;
|
||||
}
|
||||
|
||||
protected:
|
||||
const size_t _size;
|
||||
std::vector<size_t> _encoding;
|
||||
std::vector<Encoding> _encodings;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
© 2020 Thales group
|
||||
© 2022 Institut Pasteur
|
||||
|
||||
Authors:
|
||||
Johann Dreo <johann.dreo@thalesgroup.com>
|
||||
Johann Dreo <johann@dreo.fr>
|
||||
*/
|
||||
|
||||
#ifndef _eoAlgoFoundryEA_H_
|
||||
|
|
@ -36,7 +37,7 @@
|
|||
* which takes the class name as template and its constructor's parameters
|
||||
* as arguments. For example:
|
||||
* @code
|
||||
* foundry.selectors.add< eoStochTournamentSelect<EOT> >( 0.5 );
|
||||
* foundry.selectors.add< eoStochTournamentSelect<EOT> >( 0.5 );
|
||||
* @endcode
|
||||
*
|
||||
* @warning If the constructor takes a reference YOU SHOULD ABSOLUTELY wrap it
|
||||
|
|
@ -46,12 +47,12 @@
|
|||
* In a second step, the operators to be used should be selected
|
||||
* by indicating their index, just like the foundry was a array of five elements:
|
||||
* @code
|
||||
* foundry = {0, 1, 2, 0, 3};
|
||||
* // ^ ^ ^ ^ ^ replacement
|
||||
* // | | | + selection
|
||||
* // | | + mutation
|
||||
* // | + crossover
|
||||
* // + continue
|
||||
* foundry = {size_t{0}, size_t{1}, size_t{2}, size_t{0}, size_t{3}};
|
||||
* // ^ ^ ^ ^ ^ replacement
|
||||
* // | | | + selection
|
||||
* // | | + mutation
|
||||
* // | + crossover
|
||||
* // + continue
|
||||
* @endcode
|
||||
*
|
||||
* @note: by default, the firsts of the five operators are selected.
|
||||
|
|
@ -59,12 +60,12 @@
|
|||
* If you don't (want to) recall the order of the operators in the encoding,
|
||||
* you can use the `index()` member, for example:
|
||||
* @code
|
||||
* foundry.at(foundry.continuators.index()) = 2; // select the third continuator
|
||||
* foundry.at(foundry.continuators.index()) = size_t{2}; // select the third continuator
|
||||
* @endcode
|
||||
*
|
||||
* Now, you can call the fourdry just like any eoAlgo, by passing it an eoPop:
|
||||
* @code
|
||||
* foundry(pop);
|
||||
* foundry(pop);
|
||||
* @encode
|
||||
* It will instantiate the needed operators (only) and the algorithm itself on-the-fly,
|
||||
* and then run it.
|
||||
|
|
@ -73,7 +74,7 @@
|
|||
* Every instantiation is deferred upon actual use. That way, you can still reconfigure them
|
||||
* at any time with `eoForgeOperator::setup`, for example:
|
||||
* @code
|
||||
* foundry.selector.at(0).setup(0.5); // using constructor's arguments
|
||||
* foundry.selectors.at(0).setup(0.5); // using constructor's arguments
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup Foundry
|
||||
|
|
@ -111,11 +112,11 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT>
|
|||
*/
|
||||
void operator()(eoPop<EOT>& pop)
|
||||
{
|
||||
assert(continuators.size() > 0); assert(this->at(continuators.index()) < continuators.size());
|
||||
assert( crossovers.size() > 0); assert(this->at( crossovers.index()) < crossovers.size());
|
||||
assert( mutations.size() > 0); assert(this->at( mutations.index()) < mutations.size());
|
||||
assert( selectors.size() > 0); assert(this->at( selectors.index()) < selectors.size());
|
||||
assert(replacements.size() > 0); assert(this->at(replacements.index()) < replacements.size());
|
||||
assert(continuators.size() > 0); assert(this->rank(continuators) < continuators.size());
|
||||
assert( crossovers.size() > 0); assert(this->rank( crossovers) < crossovers.size());
|
||||
assert( mutations.size() > 0); assert(this->rank( mutations) < mutations.size());
|
||||
assert( selectors.size() > 0); assert(this->rank( selectors) < selectors.size());
|
||||
assert(replacements.size() > 0); assert(this->rank(replacements) < replacements.size());
|
||||
|
||||
eoSequentialOp<EOT> variator;
|
||||
variator.add(this->crossover(), 1.0);
|
||||
|
|
@ -140,11 +141,11 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT>
|
|||
std::string name()
|
||||
{
|
||||
std::ostringstream name;
|
||||
name << this->at(continuators.index()) << " (" << this->continuator().className() << ") + ";
|
||||
name << this->at(crossovers.index()) << " (" << this->crossover().className() << ") + ";
|
||||
name << this->at(mutations.index()) << " (" << this->mutation().className() << ") + ";
|
||||
name << this->at(selectors.index()) << " (" << this->selector().className() << ") + ";
|
||||
name << this->at(replacements.index()) << " (" << this->replacement().className() << ")";
|
||||
name << this->continuator().className() << " [" << this->rank(continuators) << "] + ";
|
||||
name << this->crossover() .className() << " [" << this->rank(crossovers) << "] + ";
|
||||
name << this->mutation() .className() << " [" << this->rank(mutations) << "] + ";
|
||||
name << this->selector() .className() << " [" << this->rank(selectors) << "] + ";
|
||||
name << this->replacement().className() << " [" << this->rank(replacements) << "]";
|
||||
return name.str();
|
||||
}
|
||||
|
||||
|
|
@ -153,34 +154,44 @@ class eoAlgoFoundryEA : public eoAlgoFoundry<EOT>
|
|||
const size_t _max_gen;
|
||||
|
||||
public:
|
||||
/** Currently selected continuator.
|
||||
*/
|
||||
eoContinue<EOT>& continuator()
|
||||
{
|
||||
assert(this->at(continuators.index()) < continuators.size());
|
||||
return continuators.instantiate(this->at(continuators.index()));
|
||||
assert(this->rank(continuators) < continuators.size());
|
||||
return continuators.instantiate(this->rank(continuators));
|
||||
}
|
||||
|
||||
/** Currently selected crossover.
|
||||
*/
|
||||
eoQuadOp<EOT>& crossover()
|
||||
{
|
||||
assert(this->at(crossovers.index()) < crossovers.size());
|
||||
return crossovers.instantiate(this->at(crossovers.index()));
|
||||
assert(this->rank(crossovers) < crossovers.size());
|
||||
return crossovers.instantiate(this->rank(crossovers));
|
||||
}
|
||||
|
||||
/** Currently selected mutation.
|
||||
*/
|
||||
eoMonOp<EOT>& mutation()
|
||||
{
|
||||
assert(this->at(mutations.index()) < mutations.size());
|
||||
return mutations.instantiate(this->at(mutations.index()));
|
||||
assert(this->rank(mutations) < mutations.size());
|
||||
return mutations.instantiate(this->rank(mutations));
|
||||
}
|
||||
|
||||
/** Currently selected selector.
|
||||
*/
|
||||
eoSelectOne<EOT>& selector()
|
||||
{
|
||||
assert(this->at(selectors.index()) < selectors.size());
|
||||
return selectors.instantiate(this->at(selectors.index()));
|
||||
assert(this->rank(selectors) < selectors.size());
|
||||
return selectors.instantiate(this->rank(selectors));
|
||||
}
|
||||
|
||||
/** Currently selected replacement.
|
||||
*/
|
||||
eoReplacement<EOT>& replacement()
|
||||
{
|
||||
assert(this->at(replacements.index()) < replacements.size());
|
||||
return replacements.instantiate(this->at(replacements.index()));
|
||||
assert(this->rank(replacements) < replacements.size());
|
||||
return replacements.instantiate(this->rank(replacements));
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,25 +29,37 @@
|
|||
|
||||
/** A class that assemble an eoFastGA on the fly, given a combination of available operators.
|
||||
*
|
||||
* The foundry should first be set up with sets of operators
|
||||
* The foundry should first be set up with sets of operators/parameters
|
||||
* for the main modules of a FastGA:
|
||||
* continuators, crossovers, mutations, selections, replacement operators, etc.
|
||||
* continuators, crossovers (and rate of call), mutations (and rate of call),
|
||||
* selections, replacement operators, offspring size, etc.
|
||||
*
|
||||
* This is done through public member variable's `add` method,
|
||||
* which takes the class name as template and its constructor's parameters
|
||||
* as arguments. For example:
|
||||
* @code
|
||||
* foundry.selectors.add< eoRandomSelect<EOT> >();
|
||||
* foundry.selectors.add< eoRandomSelect<EOT> >();
|
||||
* @endcode
|
||||
*
|
||||
* @warning If the constructor takes a reference YOU SHOULD ABSOLUTELY wrap it
|
||||
* in a `std::ref`, or it will silently be passed as a copy,
|
||||
* which would effectively disable any link with other operator(s).
|
||||
* in a `std::ref`, or it will silently be passed as a copy,
|
||||
* which would effectively disable any link with other operator(s).
|
||||
*
|
||||
* In a second step, the operators to be used should be selected
|
||||
* by indicating their index, passing an array of 10 elements:
|
||||
* by indicating their wanted index or value, passing an array of 10 elements:
|
||||
* @code
|
||||
* foundry.select({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
* foundry.select({
|
||||
* double{0.1}, // crossover rate
|
||||
* size_t{1}, // crossover selector
|
||||
* size_t{2}, // crossover
|
||||
* size_t{3}, // selector after crossover
|
||||
* double{0.4}, // mutation rate
|
||||
* size_t{5}, // mutation selector
|
||||
* size_t{6}, // mutation
|
||||
* size_t{7}, // replacement
|
||||
* size_t{8}, // continuator
|
||||
* size_t{9} // nb of offsprings
|
||||
* });
|
||||
* @endcode
|
||||
*
|
||||
* @note: by default, the firsts of the 10 operators are selected.
|
||||
|
|
@ -55,22 +67,22 @@
|
|||
* If you don't (want to) recall the order of the operators in the encoding,
|
||||
* you can use the `index()` member, for example:
|
||||
* @code
|
||||
* foundry.at(foundry.continuators.index()) = 2; // select the third continuator
|
||||
* foundry.at(foundry.continuators.index()) = size_t{2}; // select the third continuator
|
||||
* @endcode
|
||||
*
|
||||
* Now, you can call the foundry just like any eoAlgo, by passing it an eoPop:
|
||||
* @code
|
||||
* foundry(pop);
|
||||
* foundry(pop);
|
||||
* @encode
|
||||
* It will instantiate the needed operators (only) and the algorithm itself on-the-fly,
|
||||
* and then run it.
|
||||
*
|
||||
* @note: Thanks to the underlying eoOperatorFoundry, not all the added operators are instantiated.
|
||||
* Every instantiation is deferred upon actual use. That way, you can still reconfigure them
|
||||
* at any time with `eoForgeOperator::setup`, for example:
|
||||
* @code
|
||||
* foundry.selector.at(0).setup(0.5); // Will call constructor's arguments
|
||||
* @endcode
|
||||
* Every instantiation is deferred upon actual use. That way, you can still reconfigure them
|
||||
* at any time with `eoForgeOperator::setup`, for example:
|
||||
* @code
|
||||
* foundry.selector.at(0).setup(0.5); // Will call constructor's arguments
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup Foundry
|
||||
* @ingroup Algorithms
|
||||
|
|
@ -111,31 +123,31 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
|
|||
public:
|
||||
|
||||
/* Operators containers @{ */
|
||||
eoParameterFoundry< double > crossover_rates;
|
||||
eoParameterFoundry< double > crossover_rates;
|
||||
eoOperatorFoundry< eoSelectOne<EOT> > crossover_selectors;
|
||||
eoOperatorFoundry< eoQuadOp<EOT> > crossovers;
|
||||
eoOperatorFoundry< eoSelectOne<EOT> > aftercross_selectors;
|
||||
|
||||
eoParameterFoundry< double > mutation_rates;
|
||||
eoParameterFoundry< double > mutation_rates;
|
||||
eoOperatorFoundry< eoSelectOne<EOT> > mutation_selectors;
|
||||
eoOperatorFoundry< eoMonOp<EOT> > mutations;
|
||||
|
||||
eoOperatorFoundry< eoReplacement<EOT> > replacements;
|
||||
eoOperatorFoundry< eoContinue<EOT> > continuators;
|
||||
eoParameterFoundry< size_t > offspring_sizes;
|
||||
eoParameterFoundry< size_t > offspring_sizes;
|
||||
/* @} */
|
||||
|
||||
/** instantiate and call the pre-selected algorithm.
|
||||
*/
|
||||
void operator()(eoPop<EOT>& pop)
|
||||
{
|
||||
assert( crossover_selectors.size() > 0); assert(this->at( crossover_selectors.index()) < crossover_selectors.size());
|
||||
assert( crossovers.size() > 0); assert(this->at( crossovers.index()) < crossovers.size());
|
||||
assert(aftercross_selectors.size() > 0); assert(this->at(aftercross_selectors.index()) < aftercross_selectors.size());
|
||||
assert( mutation_selectors.size() > 0); assert(this->at( mutation_selectors.index()) < mutation_selectors.size());
|
||||
assert( mutations.size() > 0); assert(this->at( mutations.index()) < mutations.size());
|
||||
assert( replacements.size() > 0); assert(this->at( replacements.index()) < replacements.size());
|
||||
assert( continuators.size() > 0); assert(this->at( continuators.index()) < continuators.size());
|
||||
assert( crossover_selectors.size() > 0); assert(this->rank( crossover_selectors) < crossover_selectors.size());
|
||||
assert( crossovers.size() > 0); assert(this->rank( crossovers) < crossovers.size());
|
||||
assert(aftercross_selectors.size() > 0); assert(this->rank(aftercross_selectors) < aftercross_selectors.size());
|
||||
assert( mutation_selectors.size() > 0); assert(this->rank( mutation_selectors) < mutation_selectors.size());
|
||||
assert( mutations.size() > 0); assert(this->rank( mutations) < mutations.size());
|
||||
assert( replacements.size() > 0); assert(this->rank( replacements) < replacements.size());
|
||||
assert( continuators.size() > 0); assert(this->rank( continuators) < continuators.size());
|
||||
|
||||
// Objective function calls counter
|
||||
eoEvalCounterThrowException<EOT> eval(_eval, _max_evals);
|
||||
|
|
@ -165,7 +177,7 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
|
|||
try {
|
||||
// restart(pop);
|
||||
algo(pop);
|
||||
} catch(eoMaxEvalException e) {
|
||||
} catch(eoMaxEvalException & e) {
|
||||
#ifndef NDEBUG
|
||||
eo::log << eo::debug << "Reached maximum evaluations: " << eval.getValue() << " / " << _max_evals << std::endl;
|
||||
#endif
|
||||
|
|
@ -181,17 +193,18 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
|
|||
std::string name()
|
||||
{
|
||||
std::ostringstream name;
|
||||
name << "crossover_rates: " << this->at( crossover_rates.index()) << " (" << this-> crossover_rate() << ") + ";
|
||||
name << "crossover_selectors: " << this->at( crossover_selectors.index()) << " (" << this-> crossover_selector().className() << ") + ";
|
||||
name << "aftercross_selector: " << this->at(aftercross_selectors.index()) << " (" << this->aftercross_selector().className() << ") + ";
|
||||
name << "crossovers: " << this->at( crossovers.index()) << " (" << this-> crossover().className() << ") + ";
|
||||
name << "mutation_rates: " << this->at( mutation_rates.index()) << " (" << this-> mutation_rate() << ") + ";
|
||||
name << "mutation_selectors: " << this->at( mutation_selectors.index()) << " (" << this-> mutation_selector().className() << ") + ";
|
||||
name << "mutations: " << this->at( mutations.index()) << " (" << this-> mutation().className() << ") + ";
|
||||
name << "replacements: " << this->at( replacements.index()) << " (" << this-> replacement().className() << ") + ";
|
||||
name << "continuators: " << this->at( continuators.index()) << " (" << this-> continuator().className() << ") + ";
|
||||
name << "offspring_sizes: " << this->at( offspring_sizes.index()) << " (" << this-> offspring_size() << ")";
|
||||
return name.str();
|
||||
name << "crossover_rate: " << this-> crossover_rate() << " + ";
|
||||
name << "crossover_selector: " << this-> crossover_selector().className() << " [" << this->rank( crossover_selectors) << "] + ";
|
||||
name << "aftercross_selector: " << this->aftercross_selector().className() << " [" << this->rank(aftercross_selectors) << "] + ";
|
||||
name << "crossover: " << this-> crossover().className() << " [" << this->rank( crossovers) << "] + ";
|
||||
name << "mutation_rate: " << this-> mutation_rate() << " + ";
|
||||
name << "mutation_selector: " << this-> mutation_selector().className() << " [" << this->rank( mutation_selectors) << "] + ";
|
||||
name << "mutation: " << this-> mutation().className() << " [" << this->rank( mutations) << "] + ";
|
||||
name << "replacement: " << this-> replacement().className() << " [" << this->rank( replacements) << "] + ";
|
||||
name << "continuator: " << this-> continuator().className() << " [" << this->rank( continuators) << "] + ";
|
||||
name << "offspring_size: " << this-> offspring_size() << "";
|
||||
|
||||
return name.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -201,61 +214,97 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
|
|||
const size_t _max_restarts;
|
||||
|
||||
public:
|
||||
/** Currently selected continuator.
|
||||
*/
|
||||
eoContinue<EOT>& continuator()
|
||||
{
|
||||
assert(this->at(continuators.index()) < continuators.size());
|
||||
return continuators.instantiate(this->at(continuators.index()));
|
||||
const size_t r = this->rank(continuators);
|
||||
assert(r < continuators.size());
|
||||
return continuators.instantiate(r);
|
||||
}
|
||||
|
||||
/** Currently selected crossover_rate.
|
||||
*/
|
||||
double& crossover_rate()
|
||||
{
|
||||
return crossover_rates.instantiate(this->at(crossover_rates.index()));
|
||||
// We could have used `decltype(crossover_rates)::Type` instead of `double`, here,
|
||||
// but this is less readable and the type is declared just above,
|
||||
// so we are supposed to know it.
|
||||
const double val = this->value(crossover_rates);
|
||||
assert(crossover_rates.min() <= val and val <= crossover_rates.max());
|
||||
return crossover_rates.instantiate(val);
|
||||
}
|
||||
|
||||
/** Currently selected crossover.
|
||||
*/
|
||||
eoQuadOp<EOT>& crossover()
|
||||
{
|
||||
assert(this->at(crossovers.index()) < crossovers.size());
|
||||
return crossovers.instantiate(this->at(crossovers.index()));
|
||||
const size_t r = this->rank(crossovers);
|
||||
assert(r < crossovers.size());
|
||||
return crossovers.instantiate(r);
|
||||
}
|
||||
|
||||
/** Currently selected mutation_rate.
|
||||
*/
|
||||
double& mutation_rate()
|
||||
{
|
||||
return mutation_rates.instantiate(this->at(mutation_rates.index()));
|
||||
const double val = this->value(mutation_rates);
|
||||
assert(mutation_rates.min() <= val and val <= mutation_rates.max());
|
||||
return mutation_rates.instantiate(val);
|
||||
}
|
||||
|
||||
/** Currently selected mutation.
|
||||
*/
|
||||
eoMonOp<EOT>& mutation()
|
||||
{
|
||||
assert(this->at(mutations.index()) < mutations.size());
|
||||
return mutations.instantiate(this->at(mutations.index()));
|
||||
const size_t r = this->rank(mutations);
|
||||
assert(r < mutations.size());
|
||||
return mutations.instantiate(r);
|
||||
}
|
||||
|
||||
/** Currently selected crossover_selector.
|
||||
*/
|
||||
eoSelectOne<EOT>& crossover_selector()
|
||||
{
|
||||
assert(this->at(crossover_selectors.index()) < crossover_selectors.size());
|
||||
return crossover_selectors.instantiate(this->at(crossover_selectors.index()));
|
||||
const size_t r = this->rank(crossover_selectors);
|
||||
assert(r < crossover_selectors.size());
|
||||
return crossover_selectors.instantiate(r);
|
||||
}
|
||||
|
||||
/** Currently selected aftercross_selector.
|
||||
*/
|
||||
eoSelectOne<EOT>& aftercross_selector()
|
||||
{
|
||||
assert(this->at(aftercross_selectors.index()) < aftercross_selectors.size());
|
||||
return aftercross_selectors.instantiate(this->at(aftercross_selectors.index()));
|
||||
const size_t r = this->rank(aftercross_selectors);
|
||||
assert(r < aftercross_selectors.size());
|
||||
return aftercross_selectors.instantiate(r);
|
||||
}
|
||||
|
||||
/** Currently selected mutation_selector.
|
||||
*/
|
||||
eoSelectOne<EOT>& mutation_selector()
|
||||
{
|
||||
assert(this->at(mutation_selectors.index()) < mutation_selectors.size());
|
||||
return mutation_selectors.instantiate(this->at(mutation_selectors.index()));
|
||||
const size_t r = this->rank(mutation_selectors);
|
||||
assert(r < mutation_selectors.size());
|
||||
return mutation_selectors.instantiate(r);
|
||||
}
|
||||
|
||||
/** Currently selected offspring_size.
|
||||
*/
|
||||
size_t& offspring_size()
|
||||
{
|
||||
return offspring_sizes.instantiate(this->at(offspring_sizes.index()));
|
||||
const size_t val = this->len(offspring_sizes);
|
||||
assert(offspring_sizes.min() <= val and val <= offspring_sizes.max());
|
||||
return offspring_sizes.instantiate(val);
|
||||
}
|
||||
|
||||
/** Currently selected replacement.
|
||||
*/
|
||||
eoReplacement<EOT>& replacement()
|
||||
{
|
||||
assert(this->at(replacements.index()) < replacements.size());
|
||||
return replacements.instantiate(this->at(replacements.index()));
|
||||
const size_t r = this->rank(replacements);
|
||||
assert(r < replacements.size());
|
||||
return replacements.instantiate(r);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
© 2020 Thales group
|
||||
© 2022 Institut Pasteur
|
||||
|
||||
Authors:
|
||||
Johann Dreo <johann.dreo@thalesgroup.com>
|
||||
Johann Dreo <johann@dreo.fr>
|
||||
*/
|
||||
|
||||
#ifndef _eoEvalFoundryEA_H_
|
||||
|
|
@ -90,7 +91,7 @@ public:
|
|||
* auto& cont = foundry.continuator(); // Get the configured operator
|
||||
* @encode
|
||||
*/
|
||||
std::vector<size_t> decode( const EOT& sol ) const
|
||||
typename eoAlgoFoundry<SUB>::Encodings decode( const EOT& sol ) const
|
||||
{
|
||||
// // Denormalize
|
||||
// size_t cont = static_cast<size_t>(std::ceil( sol[i_cont] * _foundry.continuators.size() ));
|
||||
|
|
@ -125,18 +126,18 @@ public:
|
|||
_subpb_eval(pop,pop);
|
||||
|
||||
auto config = decode(sol);
|
||||
double cont = config[i_cont];
|
||||
double cros = config[i_cros];
|
||||
double muta = config[i_muta];
|
||||
double sele = config[i_sele];
|
||||
double repl = config[i_repl];
|
||||
size_t cont = std::get<size_t>(config[i_cont]);
|
||||
size_t cros = std::get<size_t>(config[i_cros]);
|
||||
size_t muta = std::get<size_t>(config[i_muta]);
|
||||
size_t sele = std::get<size_t>(config[i_sele]);
|
||||
size_t repl = std::get<size_t>(config[i_repl]);
|
||||
|
||||
if(
|
||||
0 <= cont and cont < _foundry.continuators.size()
|
||||
and 0 <= cros and cros < _foundry.crossovers .size()
|
||||
and 0 <= muta and muta < _foundry.mutations .size()
|
||||
and 0 <= sele and sele < _foundry.selectors .size()
|
||||
and 0 <= repl and repl < _foundry.replacements.size()
|
||||
cont < _foundry.continuators.size()
|
||||
and cros < _foundry.crossovers .size()
|
||||
and muta < _foundry.mutations .size()
|
||||
and sele < _foundry.selectors .size()
|
||||
and repl < _foundry.replacements.size()
|
||||
) {
|
||||
_foundry.select(config);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
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
|
||||
|
||||
© 2022 Institut Pasteur
|
||||
|
||||
Authors:
|
||||
Johann Dreo <johann@dreo.fr>
|
||||
*/
|
||||
|
||||
#ifndef _eoFastGA_H_
|
||||
|
|
@ -116,6 +121,11 @@ public:
|
|||
eoPop<EOT> crossed;
|
||||
crossed.push_back(sol1);
|
||||
crossed.push_back(sol2);
|
||||
|
||||
// The aftercross selector may need fitness,
|
||||
// so we evaluate those two solutions, if needed.
|
||||
_pop_eval(crossed,crossed);
|
||||
|
||||
_select_aftercross.setup(crossed);
|
||||
EOT sol3 = _select_aftercross(crossed);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
© 2020 Thales group
|
||||
© 2022 Institut Pasteur
|
||||
|
||||
Authors:
|
||||
Johann Dreo <johann.dreo@thalesgroup.com>
|
||||
Johann Dreo <johann@dreo.fr>
|
||||
*/
|
||||
|
||||
#ifndef _eoForge_H_
|
||||
|
|
@ -185,7 +186,7 @@ class eoForgeOperator<Itf,Op> : public eoForgeInterface<Itf>
|
|||
Itf* _instantiated;
|
||||
};
|
||||
|
||||
/** A vector holding an operator with deferred instantiation at a given index.
|
||||
/** A vector holding an operator (with deferred instantiation) at a given index.
|
||||
*
|
||||
* @note You can actually store several instances of the same class,
|
||||
* with different parametrization (or not).
|
||||
|
|
@ -319,18 +320,41 @@ class eoForgeVector : public std::vector<eoForgeInterface<Itf>*>
|
|||
bool _no_cache;
|
||||
};
|
||||
|
||||
/** A range holding a parameter value at a given index.
|
||||
*
|
||||
* This is essential a scalar numerical parameter, with bounds check
|
||||
* and an interface similar to an eoForgeVector.
|
||||
*
|
||||
* @note Contrary to eoForgeVector, this does not store a set of possible values.
|
||||
*
|
||||
* @code
|
||||
eoForgeScalar<double> factories(0.0, 1.0);
|
||||
|
||||
// Actually instantiate.
|
||||
double param = factories.instantiate(0.5);
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup Foundry
|
||||
*/
|
||||
template<class Itf>
|
||||
class eoForgeScalar
|
||||
{
|
||||
public:
|
||||
using Interface = Itf;
|
||||
|
||||
/** Constructor
|
||||
*
|
||||
* @param min Minimum possible value.
|
||||
* @param may Maximum possible value.
|
||||
*/
|
||||
eoForgeScalar(Itf min, Itf max) :
|
||||
_min(min),
|
||||
_max(max)
|
||||
{ }
|
||||
|
||||
/** Just return the same value, without managing any instantiation.
|
||||
*
|
||||
* Actually checks if value is in range.
|
||||
*/
|
||||
Itf& instantiate(double value)
|
||||
{
|
||||
|
|
@ -353,18 +377,24 @@ class eoForgeScalar
|
|||
Itf min() const { return _min; }
|
||||
Itf max() const { return _max; }
|
||||
|
||||
/** Set the minimum possible value.
|
||||
*/
|
||||
void min(Itf min)
|
||||
{
|
||||
assert(_min <= _max);
|
||||
_min = min;
|
||||
}
|
||||
|
||||
/** Set the maximum possible value.
|
||||
*/
|
||||
void max(Itf max)
|
||||
{
|
||||
assert(_max >= _min);
|
||||
_max = max;
|
||||
}
|
||||
|
||||
/** Set the possible range of values.
|
||||
*/
|
||||
void setup(Itf min, Itf max)
|
||||
{
|
||||
_min = min;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ typedef unsigned long uint32_t;
|
|||
#include "../eoObject.h"
|
||||
|
||||
|
||||
|
||||
/** Random Number Generator
|
||||
|
||||
@class eoRng eoRNG.h utils/eoRNG.h
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue