/* (c) 2010 Thales group This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; version 2 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 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 Contact: http://eodev.sourceforge.net Authors: Johann Dréo */ #ifndef _eoDualFitness_h_ #define _eoDualFitness_h_ #include #include #include // for std::pair #include #include #include /** @addtogroup Evaluation * @{ */ //! A fitness class that permits to compare feasible and unfeasible individuals and guaranties that a feasible individual will always be better than an unfeasible one. /** * Use this class as fitness if you have some kind of individuals * that must be always considered as better than others while having the same fitness type. * * Wraps a scalar fitness _values such as a double or int, with the option of * maximizing (using less, @see eoMaximizingDualFitness) * or minimizing (using greater, @see eoMinimizingDualFitness). * * Suitable constructors, assignments and casts are defined to work * with those quantities as if they were a pair of: a BaseType and a boolean. * * When changing the fitness, you can use: * individual.fitness( std::make_pair( fitness, feasibility ) ); * * Be aware that, when printing or reading an eDualFitness instance on a iostream, * friend IO classes use a space separator. * * This class overrides operator<() to use the Compare template argument and handle feasibility. * Over operators are coded using this sole function. * * Standard arithmetic operators are provided to add or substract dual fitnesses. * They behave as expected for the fitness value and gives priority to unfeasible fitness * (i.e. when adding or substracting dual fitness, the only case when the result will be * a feasible fitness is when both are feasible, else the result is an unfeasibe fitness) */ template class eoDualFitness { protected: //! Scalar type of the fitness (generally a double) BaseT _value; //! Flag that marks if the individual 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: typedef BaseT Base; typedef Cmp Compare; //! Empty initialization /*! * Unfeasible by default */ eoDualFitness() : _value(0.0), _is_feasible(false), _feasible_init(false) {} //! 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. * 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. */ eoDualFitness( const double value ) : _value(value), _is_feasible(false), _feasible_init(false) {} //! Copy constructor eoDualFitness(const eoDualFitness& other) : _value(other._value), _is_feasible(other._is_feasible), _feasible_init(other._feasible_init) {} //! Constructor from explicit value/feasibility eoDualFitness(const BaseT& v, const bool& is_feasible) : _value(v), _is_feasible(is_feasible), _feasible_init(true) {} //! From a std::pair (first element is the value, second is the feasibility) eoDualFitness(const std::pair& dual) : _value(dual.first), _is_feasible(dual.second), _feasible_init(true) {} /** Conversion operator: it permits to use a fitness instance as its scalar * type, if needed. For example, this is possible: * eoDualFitness > fit; * double val = 1.0; * val = fit; */ operator BaseT(void) const { return _value; } inline bool is_feasible() const { assert( _feasible_init ); 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 BaseT value() const { assert( _feasible_init ); return _value; } //! Comparison that separate feasible individuals from unfeasible ones. Feasible are always better /*! * Use less as a default comparison operator * (see the "Cmp" template of the class to change this behaviour, * @see eoMinimizingDualFitness for an example). */ bool operator<(const eoDualFitness& other) const { // am I better (less, by default) than the other ? // if I'm feasible and the other is not if( this->is_feasible() && !other.is_feasible() ) { // no, the other has a better fitness return false; } else if( !this->is_feasible() && other.is_feasible() ) { // yes, a feasible fitness is always better than an unfeasible one return true; } else { // the two fitness are of the same type // lets rely on the comparator return Cmp()(_value, other._value); } } //! Greater: if the other is lesser than me bool operator>( const eoDualFitness& other ) const { return other < *this; } //! Less or equal: if the other is not lesser than me bool operator<=( const eoDualFitness& other ) const { return !(other < *this); } //! Greater or equal: if the other is not greater than me bool operator>=(const eoDualFitness& other ) const { return !(*this < other); } //! Equal: if the other is equal to me bool operator==(const eoDualFitness& other) const { return ( this->is_feasible() == other.is_feasible() ) && ( _value == other._value ); } public: /* FIXME it would be better to raise errors (or warnings) if one try to apply arithmetics operators between feasible * and unfeasible fitnesses. This necessitates to add wrappers for operators that aggregates sets of dual fitnesses * (like eoStat), both for separating feasibility and for aggregating them. */ // NOTE: we cannot declare this set of operator classes as friend, because there is two differerent templated classes declared later // (for minimizing and maximizing) //! Add a given fitness to the current one template eoDualFitness & operator+=( const T that ) { this->_value += that; return *this; } //! Add a given fitness to the current one eoDualFitness & operator+=( const eoDualFitness & that ) { // from._value += that._value; this->_value += that._value; // true only if the two are feasible, else false this->_is_feasible = this->_is_feasible && that._is_feasible; // If the other was not correctly initialized this->_feasible_init = that._feasible_init; return *this; } //! Substract a given fitness to the current one template eoDualFitness & operator-=( const T that ) { this->_value -= that; return *this; } //! Substract a given fitness to the current one eoDualFitness & operator-=( const eoDualFitness & that ) { this->_value -= that._value; // true only if the two are feasible, else false this->_is_feasible = this->_is_feasible && that._is_feasible; // If the other was not correctly initialized this->_feasible_init = that._feasible_init; return *this; } //! Add a given fitness to the current one template eoDualFitness & operator/=( T that ) { this->_value /= that; return *this; } //! Add a given fitness to the current one eoDualFitness & operator/=( const eoDualFitness & that ) { this->_value /= that._value; // true only if the two are feasible, else false this->_is_feasible = this->_is_feasible && that._is_feasible; // If the other was not correctly initialized this->_feasible_init = that._feasible_init; return *this; } template eoDualFitness operator+( T that ) { this->_value += that; return *this; } // Add this fitness's value to that other, and return a _new_ instance with the result. eoDualFitness operator+( const eoDualFitness & that ) { eoDualFitness from( *this ); return from += that; } template eoDualFitness operator-( T that ) { this->_value -= that; return *this; } // Add this fitness's value to that other, and return a _new_ instance with the result. eoDualFitness operator-( const eoDualFitness & that ) { eoDualFitness from( *this ); return from -= that; } template eoDualFitness operator/( T that ) { this->_value /= that; return *this; } // Add this fitness's value to that other, and return a _new_ instance with the result. eoDualFitness operator/( const eoDualFitness & that ) { eoDualFitness from( *this ); return from /= that; } //! Print an eoDualFitness instance as a pair of numbers, separated by a space friend std::ostream& operator<<( std::ostream& os, const eoDualFitness & fitness ) { if( fitness._feasible_init ) { os << fitness._value << " " << fitness.is_feasible(); } else { os << fitness._value << " ?"; } return os; } //! Read an eoDualFitness instance as a pair of numbers, separated by a space friend std::istream& operator>>( std::istream& is, eoDualFitness & fitness ) { BaseT value; is >> value; bool feasible; is >> feasible; fitness._value = value; fitness.is_feasible( feasible ); return is; } }; //! Compare dual fitnesses as if we were maximizing typedef eoDualFitness > eoMaximizingDualFitness; //! Compare dual fitnesses as if we were minimizing typedef eoDualFitness > eoMinimizingDualFitness; //! A predicate that returns the feasibility of a given dual fitness /** Use this in STL algorithm that use binary predicates (e.g. count_if, find_if, etc.) */ template< class EOT> 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 eoDualPopSplit : public eoUF&, void> { protected: eoPop _pop_feasible; eoPop _pop_unfeasible; public: //! Split the pop and keep them in members void operator()( const eoPop& pop ) { _pop_feasible.clear(); _pop_feasible.reserve(pop.size()); _pop_unfeasible.clear(); _pop_unfeasible.reserve(pop.size()); for( typename eoPop::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 merge() const { eoPop merged; merged.reserve( _pop_feasible.size() + _pop_unfeasible.size() ); std::copy( _pop_feasible.begin(), _pop_feasible.end(), std::back_inserter >(merged) ); std::copy( _pop_unfeasible.begin(), _pop_unfeasible.end(), std::back_inserter >(merged) ); return merged; } eoPop& feasible() { return _pop_feasible; } eoPop& unfeasible() { return _pop_unfeasible; } }; /** 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 * a string, separated by a given marker. */ template class eoDualStatSwitch : public eoStat< typename EOSTAT::EOType, std::string > { public: typedef typename EOSTAT::EOType EOType; protected: EOSTAT & _stat_feasible; EOSTAT & _stat_unfeasible; std::string _sep; eoDualPopSplit _pop_split; public: using eoStat::value; eoDualStatSwitch( EOSTAT & stat_feasible, EOSTAT & stat_unfeasible, std::string sep=" " ) : eoStat( "?"+sep+"?", stat_feasible.longName()+sep+stat_unfeasible.longName() ), _stat_feasible(stat_feasible), _stat_unfeasible(stat_unfeasible), _sep(sep) { } virtual void operator()( const eoPop & pop ) { // create two separated pop in this operator _pop_split( pop ); std::ostringstream out; // do not call stat if the pop is empty // and it can be, because of the split if( _pop_split.feasible().size() > 0 ) { _stat_feasible( _pop_split.feasible() ); out << _stat_feasible.value(); } else { out << "?"; } out << _sep; if( _pop_split.unfeasible().size() > 0 ) { _stat_unfeasible( _pop_split.unfeasible() ); out << _stat_unfeasible.value(); } else { out << "?"; } value() = out.str(); } }; /** @} */ #endif // _eoDualFitness_h_