// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ONE_VS_ONE_DECISION_FUnCTION_ABSTRACT_H__
#ifdef DLIB_ONE_VS_ONE_DECISION_FUnCTION_ABSTRACT_H__


#include "../serialize.h"
#include <map>
#include "../any/any_decision_function_abstract.h"
#include "../unordered_pair.h"
#include "one_vs_one_trainer_abstract.h"
#include "null_df.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename one_vs_one_trainer,
        typename DF1 = null_df, typename DF2 = null_df, typename DF3 = null_df,
        typename DF4 = null_df, typename DF5 = null_df, typename DF6 = null_df,
        typename DF7 = null_df, typename DF8 = null_df, typename DF9 = null_df,
        typename DF10 = null_df
        >
    class one_vs_one_decision_function
    {
        /*!
            REQUIREMENTS ON one_vs_one_trainer
                This should be an instantiation of the one_vs_one_trainer template.  
                It is used to infer which types are used for various things, such as 
                representing labels.

            REQUIREMENTS ON DF*
                These types can either be left at their default values or set
                to any kind of decision function object capable of being
                stored in an any_decision_function<sample_type,scalar_type>
                object.  These types should also be serializable.

            WHAT THIS OBJECT REPRESENTS
                This object represents a multiclass classifier built out
                of a set of binary classifiers.  Each binary classifier
                is used to vote for the correct multiclass label using a 
                one vs. one strategy.  Therefore, if you have N classes then
                there will be N*(N-1)/2 binary classifiers inside this object.

                Note that the DF* template arguments are only used if you want
                to serialize and deserialize one_vs_one_decision_function objects. 
                Specifically, all the types of binary decision function contained
                within a one_vs_one_decision_function must be listed in the
                template arguments if serialization and deserialization is to
                be used.
        !*/
    public:

        typedef typename one_vs_one_trainer::label_type label_type;
        typedef typename one_vs_one_trainer::sample_type sample_type;
        typedef typename one_vs_one_trainer::scalar_type scalar_type;
        typedef typename one_vs_one_trainer::mem_manager_type mem_manager_type;

        typedef std::map<unordered_pair<label_type>, any_decision_function<sample_type, scalar_type> > binary_function_table;

        one_vs_one_decision_function(
        );
        /*!
            ensures
                - #number_of_classes() == 0
                - #get_binary_decision_functions().size() == 0
                - #get_labels().size() == 0
        !*/

        explicit one_vs_one_decision_function(
            const binary_function_table& decision_functions
        ); 
        /*!
            requires
                - find_missing_pairs(decision_functions).size() == 0
                  (i.e. all pairs of labels have an associated decision function)
            ensures
                - #get_binary_decision_functions() == decision_functions
                - #get_labels() == a list of all the labels which appear in the
                  given set of decision functions
                - #number_of_classes() == #get_labels().size() 
        !*/

        template <
            typename df1, typename df2, typename df3, typename df4, typename df5,
            typename df6, typename df7, typename df8, typename df9, typename df10
            >
        one_vs_one_decision_function (
            const one_vs_one_decision_function<one_vs_one_trainer, 
                                               df1, df2, df3, df4, df5,
                                               df6, df7, df8, df9, df10>& item
        ); 
        /*!
            ensures
                - #*this will be a copy of item
                - #number_of_classes() == item.number_of_classes()
                - #get_labels() == item.get_labels()
                - #get_binary_decision_functions() == item.get_binary_decision_functions()
        !*/

        const binary_function_table& get_binary_decision_functions (
        ) const;
        /*!
            ensures
                - returns the table of binary decision functions used by this
                  object.  The correspondence between binary decision functions
                  and multiclass labels is the following:
                    - for each element i of get_binary_decision_functions()
                        - i->first == the label pair associated with binary decision
                          function i->second.  
                        - if (decision function i->second outputs a value > 0) then
                            - i->second is indicating that a test sample should
                              receive a label of i->first.first
                        - else
                            - i->second is indicating that a test sample should
                              receive a label of i->first.second
        !*/

        const std::vector<label_type> get_labels (
        ) const;
        /*!
            ensures
                - returns a vector containing all the labels which can be
                  predicted by this object.
        !*/

        unsigned long number_of_classes (
        ) const;
        /*!
            ensures
                - returns get_labels().size()
                  (i.e. returns the number of different labels/classes predicted by
                  this object)
        !*/

        label_type operator() (
            const sample_type& sample
        ) const
        /*!
            requires
                - number_of_classes() != 0
            ensures
                - evaluates all the decision functions in get_binary_decision_functions()
                  and returns the label which received the most votes.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10 
        >
    void serialize(
        const one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item, 
        std::ostream& out
    );
    /*!
        ensures
            - writes the given item to the output stream out.
        throws
            - serialization_error.  
              This is thrown if there is a problem writing to the ostream or if item 
              contains a type of decision function not listed among the DF* template 
              arguments.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10 
        >
    void deserialize(
        one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item, 
        std::istream& in 
    );
    /*!
        ensures
            - deserializes a one_vs_one_decision_function from in and stores it in item.
        throws
            - serialization_error.  
              This is thrown if there is a problem reading from the istream or if the
              serialized data contains decision functions not listed among the DF*
              template arguments.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ONE_DECISION_FUnCTION_ABSTRACT_H__