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:
Johann Dreo 2022-01-26 10:40:50 +01:00
commit 02eb0e967d
11 changed files with 393 additions and 163 deletions

View file

@ -16,8 +16,6 @@
* ParadisEO algorithmic grammar definition.
*****************************************************************************/
// using Particle = eoRealParticle<eoMaximizingFitness>;
using Ints = eoInt<eoMaximizingFitnessT<int>, size_t>;
using Bits = eoBit<eoMaximizingFitnessT<int>, int>;
// by enumerating candidate operators and their parameters.
@ -341,7 +339,7 @@ int main(int argc, char* argv[])
"problem", "Problem ID",
'p', "Problem", /*required=*/true);
const size_t problem = problem_p.value();
assert(0 <= problem and problem < benchmark.size());
assert(problem < benchmark.size());
// const size_t dimension = parser.getORcreateParam<size_t>(1000,
// "dimension", "Dimension size",
@ -624,7 +622,7 @@ int main(int argc, char* argv[])
eoInitFixedLength<Bits> onemax_init(/*bitstring size=*/dimension, bgen);
auto& foundry = make_foundry(store, onemax_init, eval_count, max_evals, generations, max_target);
Ints encoded_algo(foundry.size());
eoAlgoFoundry<Bits>::Encodings encoded_algo(foundry.size());
encoded_algo[foundry.crossover_rates .index()] = crossover_rate;
encoded_algo[foundry.crossover_selectors .index()] = crossover_selector;
@ -641,16 +639,6 @@ int main(int argc, char* argv[])
foundry.select(encoded_algo);
std::clog << foundry.name() << std::endl;
// // Evaluation of a forged encoded_algo on the sub-problem
// eoEvalFoundryFastGA<Ints, Bits> eval_foundry(
// foundry, pop_size,
// onemax_init, onemax_eval,
// /*penalization=*/ dimension, // Worst case penalization.
// /*normalized=*/ false); // Use direct integer encoding.
//
// // Actually instanciate and run the algorithm.
// eval_foundry(encoded_algo);
/*****************************************************************************
* Run and output results.
*****************************************************************************/
@ -661,7 +649,7 @@ int main(int argc, char* argv[])
onemax_eval(pop,pop);
foundry(pop); // Actually run the selected algorithm.
} catch(eoMaxEvalException e) {
} catch(eoMaxEvalException & e) {
eo::log << eo::debug << "Reached maximum evaluations: " << eval_count.getValue() << " / " << max_evals << std::endl;
}

View file

@ -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;
};

View file

@ -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));
}
};

View file

@ -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);
}
};

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -55,6 +55,7 @@ typedef unsigned long uint32_t;
#include "../eoObject.h"
/** Random Number Generator
@class eoRng eoRNG.h utils/eoRNG.h

View file

@ -77,14 +77,13 @@ int main(int /*argc*/, char** /*argv*/)
pop.append(pop_size, init);
eval(pop,pop);
foundry.at(foundry.continuators.index()) = i_cont;
foundry.at(foundry.crossovers.index()) = i_cross;
foundry.at(foundry.mutations.index()) = i_mut;
foundry.at(foundry.selectors.index()) = i_sel;
foundry.at(foundry.replacements.index()) = i_rep;
// Or, if you know the order.
foundry.select({i_cont, i_cross, i_mut, i_sel, i_rep});
foundry.select({
size_t{i_cont},
size_t{i_cross},
size_t{i_mut},
size_t{i_sel},
size_t{i_rep}
});
// Actually perform a search
foundry(pop);

View file

@ -16,6 +16,7 @@ int main(int /*argc*/, char** /*argv*/)
using EOT = eoBit<double>;
oneMaxEval<EOT> eval;
eoPopLoopEval<EOT> popeval(eval);
eoBooleanGenerator gen(0.5);
eoInitFixedLength<EOT> init(dim, gen);
@ -76,6 +77,8 @@ int main(int /*argc*/, char** /*argv*/)
;
std::clog << n << " possible algorithms instances." << std::endl;
std::clog << "Running everything (this may take time)..." << std::endl;
EOT best_sol;
std::string best_algo = "";
@ -91,15 +94,20 @@ int main(int /*argc*/, char** /*argv*/)
eoPop<EOT> pop;
pop.append(pop_size, init);
popeval(pop,pop);
// FIXME put the parameters in the test?
foundry.select({
i_crossselect,
i_cross,
i_aftercrosel,
i_mutselect,
i_mut,
i_rep,
i_cont
double{0.5}, // crossover_rate
size_t{i_crossselect},
size_t{i_cross},
size_t{i_aftercrosel},
double{0.5}, // mutation_rate
size_t{i_mutselect},
size_t{i_mut},
size_t{i_rep},
size_t{i_cont},
size_t{pop_size} // offspring_size
});
// Actually perform a search

View file

@ -99,7 +99,18 @@ int main(int /*argc*/, char** /*argv*/)
pop.append(5,init);
::apply(onemax_eval,pop);
foundry.select({0,0,0,0,0,0/*,0,0*/});
foundry.select({
/*crossover_rates */ double{0.8},
/*crossover_selectors */ size_t{0},
/*crossovers */ size_t{0},
/*aftercross_selectors*/ size_t{0},
/*mutation_rates */ double{0.9},
/*mutation_selectors */ size_t{0},
/*mutations */ size_t{0},
/*replacements */ size_t{0},
/*continuators */ size_t{0},
/*offspring_sizes */ size_t{1},
});
foundry(pop);
std::cout << "Done" << std::endl;