Allow scalar init of dual fitness; add a pop splitter
Scalar init of a dual fitness is dangerous, thus adds an explicit security against use of a partially initialized object. Use the pop splitter in the dual stat switch and in the MOEO dual fitness assignment.
This commit is contained in:
parent
39621f8711
commit
4af7f3d1bc
2 changed files with 124 additions and 75 deletions
|
|
@ -74,6 +74,25 @@ protected:
|
||||||
//! Flag that marks if the individual is feasible
|
//! Flag that marks if the individual is feasible
|
||||||
bool _is_feasible;
|
bool _is_feasible;
|
||||||
|
|
||||||
|
/** Flag to prevent partial initialization
|
||||||
|
*
|
||||||
|
* The reason behind the use of this flag is a bit complicated.
|
||||||
|
* Normally, we would not want to allow initialization on a scalar.
|
||||||
|
* But in MOEO, this would necessitate to re-implement most of the
|
||||||
|
* operator computing metrics, as they expect generic scalars.
|
||||||
|
*
|
||||||
|
* As this would be too much work, we use derived metric classes and
|
||||||
|
* overload them so that they initialize dual fitnesses with the
|
||||||
|
* feasibility flag. But the compiler still must compile the base
|
||||||
|
* methods, that use the scalar interface.
|
||||||
|
*
|
||||||
|
* Thus, eoDualFitness has a scalar interface, but this flag add a
|
||||||
|
* security against partial initialization. In DEBUG mode, asserts
|
||||||
|
* will fail if the feasibility has not been explicitly initialized
|
||||||
|
* at runtime.
|
||||||
|
*/
|
||||||
|
bool _feasible_init;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Empty initialization
|
//! Empty initialization
|
||||||
|
|
@ -82,58 +101,71 @@ public:
|
||||||
*/
|
*/
|
||||||
eoDualFitness() :
|
eoDualFitness() :
|
||||||
_value(0.0),
|
_value(0.0),
|
||||||
_is_feasible(false)
|
_is_feasible(false),
|
||||||
|
_feasible_init(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//! Initialization with only the value, the fitness will be unfeasible.
|
//! Initialization with only the value, the fitness will be unfeasible.
|
||||||
/*!
|
/*!
|
||||||
* WARNING: this is what is used when you initialize a new fitness from a double.
|
* WARNING: this is what is used when you initialize a new fitness from a double.
|
||||||
* Unfeasible by default
|
* If you use this interface, you MUST set the feasibility BEFORE
|
||||||
|
* asking for it or the value. Or else, an assert will fail in debug mode.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
eoDualFitness( T value ) :
|
eoDualFitness( T value ) :
|
||||||
_value(value),
|
_value(value),
|
||||||
_is_feasible(false)
|
_is_feasible(false),
|
||||||
|
_feasible_init(false)
|
||||||
{
|
{
|
||||||
assert( _value == 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Copy constructor
|
//! Copy constructor
|
||||||
eoDualFitness(const eoDualFitness& other) :
|
eoDualFitness(const eoDualFitness& other) :
|
||||||
_value(other._value),
|
_value(other._value),
|
||||||
_is_feasible(other._is_feasible)
|
_is_feasible(other._is_feasible),
|
||||||
|
_feasible_init(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//! Constructor from explicit value/feasibility
|
//! Constructor from explicit value/feasibility
|
||||||
eoDualFitness(const BaseType& v, const bool& is_feasible) :
|
eoDualFitness(const BaseType& v, const bool& is_feasible) :
|
||||||
_value(v),
|
_value(v),
|
||||||
_is_feasible(is_feasible)
|
_is_feasible(is_feasible),
|
||||||
|
_feasible_init(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//! From a std::pair (first element is the value, second is the feasibility)
|
//! From a std::pair (first element is the value, second is the feasibility)
|
||||||
eoDualFitness(const std::pair<BaseType,bool>& dual) :
|
eoDualFitness(const std::pair<BaseType,bool>& dual) :
|
||||||
_value(dual.first),
|
_value(dual.first),
|
||||||
_is_feasible(dual.second)
|
_is_feasible(dual.second),
|
||||||
|
_feasible_init(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// FIXME is it a good idea to include implicit conversion here?
|
|
||||||
/** Conversion operator: it permits to use a fitness instance as its scalar
|
/** Conversion operator: it permits to use a fitness instance as its scalar
|
||||||
* type, if needed. For example, this is possible:
|
* type, if needed. For example, this is possible:
|
||||||
* eoDualFitness<double,std::less<double> > fit;
|
* eoDualFitness<double,std::less<double> > fit;
|
||||||
* double val = 1.0;
|
* double val = 1.0;
|
||||||
* val = fit;
|
* val = fit;
|
||||||
*/
|
*/
|
||||||
operator BaseType(void) const { return _value; }
|
operator BaseType(void) const { return _value; }
|
||||||
|
|
||||||
|
|
||||||
inline bool is_feasible() const
|
inline bool is_feasible() const
|
||||||
{
|
{
|
||||||
|
assert( _feasible_init );
|
||||||
return _is_feasible;
|
return _is_feasible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Explicitly set the feasibility. Useful if you have used previously the instantiation on a single scalar.
|
||||||
|
inline void is_feasible( bool feasible )
|
||||||
|
{
|
||||||
|
this->is_feasible( feasible );
|
||||||
|
this->_feasible_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
inline BaseType value() const
|
inline BaseType value() const
|
||||||
{
|
{
|
||||||
|
assert( _feasible_init );
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,7 +173,7 @@ public:
|
||||||
eoDualFitness& operator=( const std::pair<BaseType, bool>& v )
|
eoDualFitness& operator=( const std::pair<BaseType, bool>& v )
|
||||||
{
|
{
|
||||||
this->_value = v.first;
|
this->_value = v.first;
|
||||||
this->_is_feasible = v.second;
|
this->is_feasible( v.second );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,21 +183,20 @@ public:
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
this->_value = other._value;
|
this->_value = other._value;
|
||||||
this->_is_feasible = other._is_feasible;
|
this->is_feasible( other.is_feasible() );
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
//! Copy operator from a scalar
|
//! Copy operator from a scalar
|
||||||
template<class T>
|
template<class T>
|
||||||
eoDualFitness& operator=(const T v)
|
eoDualFitness& operator=(const T v)
|
||||||
{
|
{
|
||||||
this->_value = v;
|
this->_value = v;
|
||||||
this->_is_feasible = false;
|
this->_is_feasible = false;
|
||||||
|
this->_feasible_init = false;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
//! Comparison that separate feasible individuals from unfeasible ones. Feasible are always better
|
//! Comparison that separate feasible individuals from unfeasible ones. Feasible are always better
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -178,11 +209,11 @@ public:
|
||||||
// am I better (less, by default) than the other ?
|
// am I better (less, by default) than the other ?
|
||||||
|
|
||||||
// if I'm feasible and the other is not
|
// if I'm feasible and the other is not
|
||||||
if( this->_is_feasible && !other._is_feasible ) {
|
if( this->is_feasible() && !other.is_feasible() ) {
|
||||||
// no, the other has a better fitness
|
// no, the other has a better fitness
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else if( !this->_is_feasible && other._is_feasible ) {
|
} else if( !this->is_feasible() && other.is_feasible() ) {
|
||||||
// yes, a feasible fitness is always better than an unfeasible one
|
// yes, a feasible fitness is always better than an unfeasible one
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -322,7 +353,7 @@ public:
|
||||||
friend
|
friend
|
||||||
std::ostream& operator<<( std::ostream& os, const eoDualFitness<BaseType,Compare> & fitness )
|
std::ostream& operator<<( std::ostream& os, const eoDualFitness<BaseType,Compare> & fitness )
|
||||||
{
|
{
|
||||||
os << fitness._value << " " << fitness._is_feasible;
|
os << fitness._value << " " << fitness.is_feasible();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,7 +368,7 @@ public:
|
||||||
is >> feasible;
|
is >> feasible;
|
||||||
|
|
||||||
fitness._value = value;
|
fitness._value = value;
|
||||||
fitness._is_feasible = feasible;
|
fitness.is_feasible( feasible );
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -355,18 +386,72 @@ template< class EOT>
|
||||||
bool eoIsFeasible ( const EOT & sol ) { return sol.fitness().is_feasible(); }
|
bool eoIsFeasible ( const EOT & sol ) { return sol.fitness().is_feasible(); }
|
||||||
|
|
||||||
|
|
||||||
|
/** Separate the population into two: one with only feasible individuals, the other with unfeasible ones.
|
||||||
|
*/
|
||||||
|
template<class EOT>
|
||||||
|
class eoDualPopSplit : public eoUF<const eoPop<EOT>&, void>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
eoPop<EOT> _pop_feasible;
|
||||||
|
eoPop<EOT> _pop_unfeasible;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Split the pop and keep them in members
|
||||||
|
void operator()( const eoPop<EOT>& pop )
|
||||||
|
{
|
||||||
|
_pop_feasible.clear();
|
||||||
|
_pop_feasible.reserve(pop.size());
|
||||||
|
|
||||||
|
_pop_unfeasible.clear();
|
||||||
|
_pop_unfeasible.reserve(pop.size());
|
||||||
|
|
||||||
|
for( typename eoPop<EOT>::const_iterator ieot=pop.begin(), iend=pop.end(); ieot!=iend; ++ieot ) {
|
||||||
|
/*
|
||||||
|
if( ieot->invalid() ) {
|
||||||
|
eo::log << eo::errors << "ERROR: trying to access to an invalid fitness" << std::endl;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if( ieot->fitness().is_feasible() ) {
|
||||||
|
_pop_feasible.push_back( *ieot );
|
||||||
|
} else {
|
||||||
|
_pop_unfeasible.push_back( *ieot );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Merge feasible and unfeasible populations into a new one
|
||||||
|
eoPop<EOT> merge() const
|
||||||
|
{
|
||||||
|
eoPop<EOT> merged;
|
||||||
|
merged.reserve( _pop_feasible.size() + _pop_unfeasible.size() );
|
||||||
|
std::copy( _pop_feasible.begin(), _pop_feasible.end(), std::back_inserter<eoPop<EOT> >(merged) );
|
||||||
|
std::copy( _pop_unfeasible.begin(), _pop_unfeasible.end(), std::back_inserter<eoPop<EOT> >(merged) );
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
eoPop<EOT>& feasible() { return _pop_feasible; }
|
||||||
|
eoPop<EOT>& unfeasible() { return _pop_unfeasible; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Embed two eoStat and call the first one on the feasible individuals and
|
/** Embed two eoStat and call the first one on the feasible individuals and
|
||||||
* the second one on the unfeasible ones, merge the two resulting value in
|
* the second one on the unfeasible ones, merge the two resulting value in
|
||||||
* a string, separated by a given marker.
|
* a string, separated by a given marker.
|
||||||
*/
|
*/
|
||||||
//template<class EOT, class T>
|
|
||||||
template<class EOT, class EOSTAT>
|
template<class EOT, class EOSTAT>
|
||||||
class eoDualStatSwitch : public eoStat< EOT, std::string >
|
class eoDualStatSwitch : public eoStat< EOT, std::string >
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
EOSTAT & _stat_feasible;
|
||||||
|
EOSTAT & _stat_unfeasible;
|
||||||
|
|
||||||
|
std::string _sep;
|
||||||
|
|
||||||
|
eoDualPopSplit<EOT> _pop_split;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using eoStat<EOT,std::string>::value;
|
using eoStat<EOT,std::string>::value;
|
||||||
|
|
||||||
// eoDualStatSwitch( eoStat<EOT,T> & stat_feasible, eoStat<EOT,T> & stat_unfeasible, std::string sep=" " ) :
|
|
||||||
eoDualStatSwitch( EOSTAT & stat_feasible, EOSTAT & stat_unfeasible, std::string sep=" " ) :
|
eoDualStatSwitch( EOSTAT & stat_feasible, EOSTAT & stat_unfeasible, std::string sep=" " ) :
|
||||||
eoStat<EOT,std::string>(
|
eoStat<EOT,std::string>(
|
||||||
"?"+sep+"?",
|
"?"+sep+"?",
|
||||||
|
|
@ -379,41 +464,17 @@ public:
|
||||||
|
|
||||||
virtual void operator()( const eoPop<EOT> & pop )
|
virtual void operator()( const eoPop<EOT> & pop )
|
||||||
{
|
{
|
||||||
eoPop<EOT> pop_feasible;
|
// create two separated pop in this operator
|
||||||
pop_feasible.reserve(pop.size());
|
_pop_split( pop );
|
||||||
|
|
||||||
eoPop<EOT> pop_unfeasible;
|
_stat_feasible( _pop_split.feasible() );
|
||||||
pop_unfeasible.reserve(pop.size());
|
_stat_unfeasible( _pop_split.unfeasible() );
|
||||||
|
|
||||||
for( typename eoPop<EOT>::const_iterator ieot=pop.begin(), iend=pop.end(); ieot!=iend; ++ieot ) {
|
|
||||||
/*
|
|
||||||
if( ieot->invalid() ) {
|
|
||||||
eo::log << eo::errors << "ERROR: trying to access to an invalid fitness" << std::endl;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if( ieot->fitness().is_feasible() ) {
|
|
||||||
pop_feasible.push_back( *ieot );
|
|
||||||
} else {
|
|
||||||
pop_unfeasible.push_back( *ieot );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_stat_feasible( pop_feasible );
|
|
||||||
_stat_unfeasible( pop_unfeasible );
|
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << _stat_feasible.value() << _sep << _stat_unfeasible.value();
|
out << _stat_feasible.value() << _sep << _stat_unfeasible.value();
|
||||||
|
|
||||||
value() = out.str();
|
value() = out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
// eoStat<EOT,T> & _stat_feasible;
|
|
||||||
// eoStat<EOT,T> & _stat_unfeasible;
|
|
||||||
EOSTAT & _stat_feasible;
|
|
||||||
EOSTAT & _stat_unfeasible;
|
|
||||||
|
|
||||||
std::string _sep;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
|
|
||||||
|
#ifndef MOEOEXPBINARYINDICATORBASEDDUALFITNESSASSIGNMENT_H_
|
||||||
|
#define MOEOEXPBINARYINDICATORBASEDDUALFITNESSASSIGNMENT_H_
|
||||||
|
|
||||||
#include <fitness/moeoExpBinaryIndicatorBasedFitnessAssignment.h>
|
#include <fitness/moeoExpBinaryIndicatorBasedFitnessAssignment.h>
|
||||||
|
|
||||||
template<class MOEOT>
|
template<class MOEOT>
|
||||||
class moeoExpBinaryIndicatorBasedDualFitnessAssignment : public moeoExpBinaryIndicatorBasedFitnessAssignment<MOEOT>
|
class moeoExpBinaryIndicatorBasedDualFitnessAssignment : public moeoExpBinaryIndicatorBasedFitnessAssignment<MOEOT>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
eoPop<MOEOT> _feasible_pop;
|
eoDualPopSplit<MOEOT> _pop_split;
|
||||||
eoPop<MOEOT> _unfeasible_pop;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename MOEOT::ObjectiveVector ObjectiveVector;
|
typedef typename MOEOT::ObjectiveVector ObjectiveVector;
|
||||||
|
|
@ -26,20 +28,24 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void operator()( eoPop<MOEOT>& pop )
|
virtual void operator()( eoPop<MOEOT>& pop )
|
||||||
{
|
{
|
||||||
// separate the pop in the members
|
// separate the pop in feasible/unfeasible
|
||||||
split( pop );
|
_pop_split( pop );
|
||||||
|
|
||||||
eoPop<MOEOT>* ppop;
|
eoPop<MOEOT>* ppop;
|
||||||
// if there is at least one feasible individual, it will supersede all the unfeasible ones
|
// if there is at least one feasible individual,
|
||||||
if( _feasible_pop.size() == 0 ) {
|
// it will supersede all the unfeasible ones
|
||||||
ppop = & _unfeasible_pop;
|
if( _pop_split.feasible().size() == 0 ) {
|
||||||
|
ppop = & _pop_split.unfeasible();
|
||||||
} else {
|
} else {
|
||||||
ppop = & _feasible_pop;
|
ppop = & _pop_split.feasible();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setup(*ppop);
|
this->setup(*ppop);
|
||||||
this->computeValues(*ppop);
|
this->computeValues(*ppop);
|
||||||
this->setFitnesses(*ppop);
|
this->setFitnesses(*ppop); // NOTE: this alter individuals
|
||||||
|
|
||||||
|
// bring back altered individuals in the pop
|
||||||
|
pop = _pop_split.merge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -47,25 +53,6 @@ protected:
|
||||||
|
|
||||||
using moeoExpBinaryIndicatorBasedFitnessAssignment<MOEOT>::kappa;
|
using moeoExpBinaryIndicatorBasedFitnessAssignment<MOEOT>::kappa;
|
||||||
|
|
||||||
//! Split up the population in two: in one pop the feasible individual, in the other the feasible ones
|
|
||||||
virtual void split( eoPop<MOEOT> & pop )
|
|
||||||
{
|
|
||||||
// clear previously used populations
|
|
||||||
_feasible_pop.clear();
|
|
||||||
_unfeasible_pop.clear();
|
|
||||||
_feasible_pop.reserve(pop.size());
|
|
||||||
_unfeasible_pop.reserve(pop.size());
|
|
||||||
|
|
||||||
for( typename eoPop<MOEOT>::iterator it=pop.begin(), end=pop.end(); it != end; ++it ) {
|
|
||||||
// The ObjectiveVector should implement "is_feasible"
|
|
||||||
if( it->objectiveVector().is_feasible() ) {
|
|
||||||
_feasible_pop.push_back( *it );
|
|
||||||
} else {
|
|
||||||
_unfeasible_pop.push_back( *it );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute every indicator value in values (values[i] = I(_v[i], _o))
|
* Compute every indicator value in values (values[i] = I(_v[i], _o))
|
||||||
* @param _pop the population
|
* @param _pop the population
|
||||||
|
|
@ -112,3 +99,4 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // MOEOEXPBINARYINDICATORBASEDDUALFITNESSASSIGNMENT_H_
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue