/*

(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 <johann.dreo@thalesgroup.com>

*/

#ifndef _eoDualFitness_h_
#define _eoDualFitness_h_

#include <functional>
#include <iostream>
#include <utility> // for std::pair
#include <string>

#include "utils/eoStat.h"
#include "utils/eoLogger.h"

/** @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<BaseType>, @see eoMaximizingDualFitness)
 * or minimizing (using greater<BaseType>, @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<BaseType,bool>( 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 BaseT, class Cmp >
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<BaseT,bool>& 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<double,std::less<double> > 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<class T>
    eoDualFitness<BaseT,Cmp> & operator+=( const T that )
    {
        this->_value += that;
        return *this;
    }

    //! Add a given fitness to the current one
    eoDualFitness<BaseT,Cmp> & operator+=( const eoDualFitness<BaseT,Cmp> & 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<class T>
    eoDualFitness<BaseT,Cmp> & operator-=( const T that )
    {
        this->_value -= that;
        return *this;
    }

    //! Substract a given fitness to the current one
    eoDualFitness<BaseT,Cmp> & operator-=( const eoDualFitness<BaseT,Cmp> & 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<class T>
    eoDualFitness<BaseT,Cmp> & operator/=( T that )
    {
        this->_value /= that;
        return *this;
    }

    //! Add a given fitness to the current one
    eoDualFitness<BaseT,Cmp> & operator/=( const eoDualFitness<BaseT,Cmp> & 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<class T>
    eoDualFitness<BaseT,Cmp> 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<BaseT,Cmp> operator+( const eoDualFitness<BaseT,Cmp> & that )
    {
        eoDualFitness<BaseT,Cmp> from( *this );
        return from += that;
    }

    template<class T>
    eoDualFitness<BaseT,Cmp> 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<BaseT,Cmp> operator-( const eoDualFitness<BaseT,Cmp> & that )
    {
        eoDualFitness<BaseT,Cmp> from( *this );
        return from -= that;
    }


    template<class T>
    eoDualFitness<BaseT,Cmp> 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<BaseT,Cmp> operator/( const eoDualFitness<BaseT,Cmp> & that )
    {
        eoDualFitness<BaseT,Cmp> 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<BaseT,Cmp> & 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<BaseT,Cmp> & 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<double, std::less<double> >    eoMaximizingDualFitness;

//! Compare dual fitnesses as if we were minimizing
typedef eoDualFitness<double, std::greater<double> > 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 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
 * the second one on the unfeasible ones, merge the two resulting value in
 * a string, separated by a given marker.
 */
template<class EOSTAT>
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<EOType> _pop_split;

public:
    using eoStat<EOType,std::string>::value;

    eoDualStatSwitch( EOSTAT & stat_feasible,  EOSTAT & stat_unfeasible, std::string sep=" "  ) :
        eoStat<EOType,std::string>(
                "?"+sep+"?",
                stat_feasible.longName()+sep+stat_unfeasible.longName()
                                ),
        _stat_feasible(stat_feasible),
        _stat_unfeasible(stat_unfeasible),
        _sep(sep)
    { }

    virtual void operator()( const eoPop<EOType> & 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_
