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

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../optimization/optimization_solve_qp3_using_smo_abstract.h"

namespace dlib
{

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

    template <
        typename K 
        >
    class svr_trainer
    {
        /*!
            REQUIREMENTS ON K 
                is a kernel function object as defined in dlib/svm/kernel_abstract.h 

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for performing epsilon-insensitive support 
                vector regression.  It is implemented using the SMO algorithm.

                The implementation of the eps-SVR training algorithm used by this object is based
                on the following paper:
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector 
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm
        !*/

    public:
        typedef K kernel_type;
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::sample_type sample_type;
        typedef typename kernel_type::mem_manager_type mem_manager_type;
        typedef decision_function<kernel_type> trained_function_type;

        svr_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_c() == 1
                - #get_epsilon_insensitivity() == 0.1
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        void set_cache_size (
            long cache_size
        );
        /*!
            requires
                - cache_size > 0
            ensures
                - #get_cache_size() == cache_size 
        !*/

        const long get_cache_size (
        ) const;
        /*!
            ensures
                - returns the number of megabytes of cache this object will use
                  when it performs training via the this->train() function.
                  (bigger values of this may make training go faster but won't affect 
                  the result.  However, too big a value will cause you to run out of 
                  memory, obviously.)
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps 
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_epsilon_insensitivity (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon_insensitivity() == eps
        !*/

        const scalar_type get_epsilon_insensitivity (
        ) const;
        /*!
            ensures
                - This object tries to find a function which minimizes the
                  regression error on a training set.  This error is measured
                  in the following way:
                    - if (abs(predicted_value - true_labeled_value) < eps) then
                        - The error is 0.  That is, any function which gets within
                          eps of the correct output is good enough.
                    - else
                        - The error grows linearly once it gets bigger than eps
                 
                  So epsilon-insensitive regression means we do regression but 
                  stop trying to fit a data point once it is "close enough".  
                  This function returns that eps value which controls what we 
                  mean by "close enough".
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k 
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_c (
            scalar_type C 
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C 
        !*/

        const scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVR regularization parameter.  It is the parameter that 
                  determines the trade-off between trying to reduce the training error 
                  or allowing more errors but hopefully improving the generalization 
                  of the resulting decision_function.  Larger values encourage exact 
                  fitting while smaller values of C may encourage better generalization. 
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_learning_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - performs support vector regression given the training samples in x and 
                  target values in y.  
                - returns a decision_function F with the following properties:
                    - F(new_x) == predicted y value
        !*/

        void swap (
            svr_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    }; 

    template <typename K>
    void swap (
        svr_trainer<K>& a,
        svr_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

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

}

#endif // DLIB_SVm_EPSILON_REGRESSION_TRAINER_ABSTRACT_