    // Copyright (C) 2006  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_MATRIx_EXPRESSIONS_H_
    #define DLIB_MATRIx_EXPRESSIONS_H_

    #include "matrix_fwd.h"

    #ifdef _MSC_VER
    // This #pragma directive is also located in the algs.h file but for whatever
    // reason visual studio 9 just ignores it when it is only there.

    // this is to disable the "'this' : used in base member initializer list"
    // warning you get from some of the GUI objects since all the objects
    // require that their parent class be passed into their constructor.
    // In this case though it is totally safe so it is ok to disable this warning.
    #pragma warning(disable : 4355)
    #endif

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //            Helper templates for making operators used by expression objects
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <typename T>
        class matrix_range_exp;

        template <typename T>
        struct matrix_traits<matrix_range_exp<T> >
        {
            typedef T type;
            typedef const T const_ret_type;
            typedef default_memory_manager mem_manager_type;
            typedef row_major_layout layout_type;
            const static long NR = 1;
            const static long NC = 0;
            const static long cost = 1;
        };

        template <typename T>
        class matrix_range_exp : public matrix_exp<matrix_range_exp<T> >
        {
        public:
            typedef typename matrix_traits<matrix_range_exp>::type type;
            typedef typename matrix_traits<matrix_range_exp>::const_ret_type const_ret_type;
            typedef typename matrix_traits<matrix_range_exp>::mem_manager_type mem_manager_type;
            const static long NR = matrix_traits<matrix_range_exp>::NR;
            const static long NC = matrix_traits<matrix_range_exp>::NC;
            const static long cost = matrix_traits<matrix_range_exp>::cost;
            typedef typename matrix_traits<matrix_range_exp>::layout_type layout_type;

            matrix_range_exp (
                T start_,
                T end_
            )
            {
                start = start_;
                if (start_ <= end_)
                    inc = 1;
                else
                    inc = -1;
                nc_ = std::abs(end_ - start_) + 1;
            }
            matrix_range_exp (
                T start_,
                T inc_,
                T end_
            )
            {
                start = start_;
                nc_ = std::abs(end_ - start_)/inc_ + 1;
                if (start_ <= end_)
                    inc = inc_;
                else
                    inc = -inc_;
            }

            matrix_range_exp (
                T start_,
                T end_,
                long num,
                bool
            )
            {
                start = start_;
                nc_ = num;
                if (num > 1)
                {
                    inc = (end_-start_)/(num-1);
                }
                else
                {
                    inc = 0;
                    start = end_;
                }

            }

            const_ret_type operator() (
                long,
                long c
            ) const { return start + c*inc;  }

            const_ret_type operator() (
                long c
            ) const { return start + c*inc;  }

            template <typename U>
            bool aliases (
                const matrix_exp<U>&
            ) const { return false; }

            template <typename U>
            bool destructively_aliases (
                const matrix_exp<U>&
            ) const { return false; }

            long nr (
            ) const { return NR; }

            long nc (
            ) const { return nc_; }

            long nc_;
            T start;
            T inc;
        };

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

        template <typename T>
        class matrix_log_range_exp;

        template <typename T>
        struct matrix_traits<matrix_log_range_exp<T> >
        {
            typedef T type;
            typedef const T const_ret_type;
            typedef default_memory_manager mem_manager_type;
            typedef row_major_layout layout_type;
            const static long NR = 1;
            const static long NC = 0;
            const static long cost = 1;
        };

        template <typename T>
        class matrix_log_range_exp : public matrix_exp<matrix_log_range_exp<T> >
        {
        public:
            typedef typename matrix_traits<matrix_log_range_exp>::type type;
            typedef typename matrix_traits<matrix_log_range_exp>::const_ret_type const_ret_type;
            typedef typename matrix_traits<matrix_log_range_exp>::mem_manager_type mem_manager_type;
            const static long NR = matrix_traits<matrix_log_range_exp>::NR;
            const static long NC = matrix_traits<matrix_log_range_exp>::NC;
            const static long cost = matrix_traits<matrix_log_range_exp>::cost;
            typedef typename matrix_traits<matrix_log_range_exp>::layout_type layout_type;

            matrix_log_range_exp (
                T start_,
                T end_,
                long num
            )
            {
                start = start_;
                nc_ = num;
                if (num > 1)
                {
                    inc = (end_-start_)/(num-1);
                }
                else
                {
                    inc = 0;
                    start = end_;
                }

            }

            const_ret_type operator() (
                long,
                long c
            ) const { return std::pow((T)10,start + c*inc);  }

            const_ret_type operator() (
                long c
            ) const { return std::pow((T)10,start + c*inc);  }

            template <typename U>
            bool aliases (
                const matrix_exp<U>&
            ) const { return false; }

            template <typename U>
            bool destructively_aliases (
                const matrix_exp<U>&
            ) const { return false; }

            long nr (
            ) const { return NR; }

            long nc (
            ) const { return nc_; }

            long nc_;
            T start;
            T inc;
        };

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

        template <long start, long inc_, long end>
        class matrix_range_static_exp;

        template <long start, long inc_, long end>
        struct matrix_traits<matrix_range_static_exp<start,inc_,end> >
        {
            typedef long type;
            typedef const long const_ret_type;
            typedef default_memory_manager mem_manager_type;
            const static long NR = 1;
            const static long NC = tabs<(end - start)>::value/inc_ + 1;
            const static long cost = 1;
            typedef row_major_layout layout_type;
        };

        template <long start, long inc_, long end_>
        class matrix_range_static_exp : public matrix_exp<matrix_range_static_exp<start,inc_,end_> >
        {
        public:
            typedef typename matrix_traits<matrix_range_static_exp>::type type;
            typedef typename matrix_traits<matrix_range_static_exp>::const_ret_type const_ret_type;
            typedef typename matrix_traits<matrix_range_static_exp>::mem_manager_type mem_manager_type;
            const static long NR = matrix_traits<matrix_range_static_exp>::NR;
            const static long NC = matrix_traits<matrix_range_static_exp>::NC;
            const static long cost = matrix_traits<matrix_range_static_exp>::cost;
            typedef typename matrix_traits<matrix_range_static_exp>::layout_type layout_type;

            const static long inc = (start <= end_)?inc_:-inc_;

            matrix_range_static_exp (
            ) {}

            const_ret_type operator() (
                long ,
                long c
            ) const { return start + c*inc;  }

            const_ret_type operator() (
                long c
            ) const { return start + c*inc;  }

            template <typename U>
            bool aliases (
                const matrix_exp<U>&
            ) const { return false; }

            template <typename U>
            bool destructively_aliases (
                const matrix_exp<U>&
            ) const { return false; }

            long nr (
            ) const { return NR; }

            long nc (
            ) const { return NC; }

        };

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

    }

    #endif // DLIB_MATRIx_EXPRESSIONS_H_