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

    #include "matrix_fwd.h"

    namespace dlib
    {

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

        template <
            typename EXP
            >
        class matrix_exp
        {
            /*!
                REQUIREMENTS ON EXP
                    - must be an object that inherits publicly from matrix_exp (this class).

                WHAT THIS OBJECT REPRESENTS
                    This object represents an expression that evaluates to a matrix
                    of nr() rows and nc() columns.

                    The reason for having an object that represents an expression is that it
                    allows us to use the "expression templates" technique to eliminate the
                    temporary matrix objects that would normally be returned from expressions
                    such as M = A+B+C+D;  Normally each invocation of the + operator would
                    construct and return a temporary matrix object but using this technique we
                    can avoid creating all of these temporary objects and receive a large
                    speed boost.

                    Note that every time you invoke operator() on this object it recomputes
                    its result which may not be what you want to do.  For example, if you
                    are going to be accessing the same element over and over it might
                    be faster to assign the matrix_exp to a temporary matrix and then
                    use that temporary.

                    const_ret_type typedef (defined below)
                        The purpose of the const_ret_type typedef is to allow matrix expressions
                        to return their elements by reference when appropriate.  So const_ret_type
                        should be one of the following types:
                            - const type
                            - const type&
            !*/

        public:
            typedef typename EXP::type type;
            typedef type value_type; // Redefined for compatibility with the STL
            typedef typename EXP::const_ret_type const_ret_type;
            typedef typename EXP::mem_manager_type mem_manager_type;
            typedef typename EXP::layout_type layout_type;
            const static long cost = EXP::cost;
            const static long NR = EXP::NR;
            const static long NC = EXP::NC;
            typedef matrix<type,NR,NC, mem_manager_type,layout_type> matrix_type;
            typedef EXP exp_type;
            typedef matrix_exp_iterator<EXP> iterator;
            typedef matrix_exp_iterator<EXP> const_iterator;

            const_ret_type operator() (
                long r,
                long c
            ) const;
            /*!
                requires
                    - 0 <= r < nr()
                    - 0 <= c < nc()
                ensures
                    - returns ref()(r,c)
                      (i.e. returns the value at the given row and column that would be in
                      the matrix represented by this matrix expression)
            !*/

            const_ret_type operator() (
                long i
            ) const;
            /*!
                requires
                    - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)
                    - if (nc() == 1) then
                        - 0 <= i < nr()
                    - else
                        - 0 <= i < nc()
                ensures
                    - if (nc() == 1) then
                        - returns (*this)(i,0)
                    - else
                        - returns (*this)(0,i)
            !*/

            operator const type (
            ) const;
            /*!
                requires
                    - nr() == 1
                    - nc() == 1
                ensures
                    - returns (*this)(0,0)
            !*/

            long nr (
            ) const;
            /*!
                ensures
                    - returns the number of rows in this matrix expression.
            !*/

            long nc (
            ) const;
            /*!
                ensures
                    - returns the number of columns in this matrix expression.
            !*/

            long size (
            ) const;
            /*!
                ensures
                    - returns nr()*nc()
            !*/

            template <typename U>
            bool aliases (
                const matrix_exp<U>& item
            ) const;
            /*!
                ensures
                    - if (A change to the state of item could cause a change to the state of *this
                          matrix_exp object.  ) then
                        - returns true
                        - This happens when this matrix_exp contains item in some way.
                    - else
                        - returns false
            !*/

            template <typename U>
            bool destructively_aliases (
                const matrix_exp<U>& item
            ) const;
            /*!
                ensures
                    - if (aliases(item)) then
                        - if (nr() != item.nr() || nc() != item.nc()
                            - returns true
                              (i.e. if this expression has different dimensions than item then
                              we have destructive aliasing)

                        - returns true if the following assignment would evaluate incorrectly:
                          for (long r = 0; r < nr(); ++r)
                            for (long c = 0; c < nc(); ++c)
                              item(r,c) = (*this)(r,c)
                        - That is, if this matrix expression aliases item in such a way that a modification
                          to element item(r,c) causes a change in the value of something other than
                          (*this)(r,c) then this function returns true.

                        - returns false if none of the above conditions say we should return true
                    - else
                        - returns false
            !*/

            inline const exp_type& ref (
            ) const;
            /*!
                ensures
                    - returns a reference to the expression contained in *this.
                      (i.e. returns *static_cast<const exp_type*>(this) )
            !*/

            const_iterator begin(
            ) const;
            /*!
                ensures
                    - returns a forward access iterator pointing to the first element in this
                      matrix expression.
                    - Since matrix_exp objects represent immutable views of a matrix, the
                      returned iterator does not allow the user to modify the matrix
                      expression's elements.
                    - The iterator will iterate over the elements of the matrix in row major
                      order.
            !*/

            const_iterator end(
            ) const;
            /*!
                ensures
                    - returns a forward access iterator pointing to one past the end of the
                      last element in this matrix expression.
            !*/

        protected:

            // Only derived classes of matrix_exp may call the matrix_exp constructors.
            matrix_exp(const matrix_exp&);
            matrix_exp();

        private:
            // no one may ever use the assignment operator on a matrix_exp
            matrix_exp& operator= (const matrix_exp&);
        };

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

    }

    #endif // DLIB_MATRIx_EXP_ABSTRACT_