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

    #include "../serialize.h"
    #include <functional>
    #include <iostream>
    #include "../matrix/matrix_abstract.h"

    namespace dlib
    {
        template <
            typename T,
            long NR = 3
            >
        class vector : public matrix<T,NR,1>
        {
            /*!
                REQUIREMENTS ON T
                    T should be some object that provides an interface that is
                    compatible with double, float, int, long and the like.

                REQUIREMENTS ON NR
                    NR == 3 || NR == 2

                INITIAL VALUE
                    x() == 0
                    y() == 0
                    z() == 0

                WHAT THIS OBJECT REPRESENTS
                    This object represents a three dimensional vector.  If NR == 2 then
                    this object is limited to representing points on the XY plane where
                    Z is set to 0.

                    Also note that this object performs the appropriate integer and
                    floating point conversions and promotions when vectors of mixed
                    type are used together.  For example:
                        vector<int,3> vi;
                        vector<double,2> vd;
                        vd + vi == a vector<double,3> object type since that is what
                                   is needed to contain the result of vi+vd without
                                   any loss of information.
            !*/

        public:

            typedef T type;

            vector (
            );
            /*!
                ensures
                   - #*this has been properly initialized
            !*/

            vector (
                const T _x,
                const T _y,
                const T _z
            );
            /*!
                requires
                    - NR == 3
                ensures
                    - #x() == _x
                    - #y() == _y
                    - #z() == _z
            !*/

            vector (
                const T _x,
                const T _y
            );
            /*!
                requires
                    - NR == 2
                ensures
                    - #x() == _x
                    - #y() == _y
                    - #z() == 0
            !*/

            template <typename U, long NRv>
            vector (
                const vector<U,NRv>& v
            );
            /*!
                ensures
                    - Initializes *this with the contents of v and does any rounding if necessary and also
                      takes care of converting between 2 and 3 dimensional vectors.
                    - if (U is a real valued type like float or double and T is an integral type like long) then
                        - if (NR == 3) then
                            - #x() == floor(v.x() + 0.5)
                            - #y() == floor(v.y() + 0.5)
                            - #z() == floor(v.z() + 0.5)
                        - else // NR == 2
                            - #x() == floor(v.x() + 0.5)
                            - #y() == floor(v.y() + 0.5)
                            - #z() == 0
                    - else
                        - if (NR == 3) then
                            - #x() == v.x()
                            - #y() == v.y()
                            - #z() == v.z()
                        - else // NR == 2
                            - #x() == v.x()
                            - #y() == v.y()
                            - #z() == 0
            !*/

            template <typename EXP>
            vector (
                const matrix_exp<EXP>& m
            );
            /*!
                requires
                    - m.size() == NR
                    - m.nr() == 1 || m.nc() == 1 (i.e. m must be a row or column matrix)
                ensures
                    - Initializes *this with the contents of m and does any rounding if necessary and also
                      takes care of converting between 2 and 3 dimensional vectors.
                    - if (m contains real valued values like float or double and T is an integral type like long) then
                        - #x() == floor(m(0) + 0.5)
                        - #y() == floor(m(1) + 0.5)
                        - if (NR == 3) then
                            - #z() == floor(m(2) + 0.5)
                        - else
                            - #z() == 0
                    - else
                        - #x() == m(0)
                        - #y() == m(1)
                        - if (NR == 3) then
                            - #z() == m(2)
                        - else
                            - #z() == 0
            !*/

            ~vector (
            );
            /*!
                ensures
                    - all resources associated with *this have been released
            !*/

            double length(
            ) const;
            /*!
                ensures
                    - returns the length of the vector
            !*/

            T& x (
            );
            /*!
                ensures
                    - returns a reference to the x component of the vector
            !*/

            T& y (
            );
            /*!
                ensures
                    - returns a reference to the y component of the vector
            !*/

            T& z (
            );
            /*!
                requires
                    - NR == 3 (this function actually doesn't exist when NR != 3)
                ensures
                    - returns a reference to the z component of the vector
            !*/

            const T& x (
            ) const;
            /*!
                ensures
                    - returns a const reference to the x component of the vector
            !*/

            const T& y (
            ) const;
            /*!
                ensures
                    - returns a const reference to the y component of the vector
            !*/

            const T& z (
            ) const;
            /*!
                ensures
                    - if (NR == 3) then
                        - returns a const reference to the z component of the vector
                    - else
                        - return 0
                          (there isn't really a z in this case so we just return 0)
            !*/

            T dot (
                const vector& rhs
            ) const;
            /*!
                ensures
                    - returns the result of the dot product between *this and rhs
            !*/

            vector<T,3> cross (
                const vector& rhs
            ) const;
            /*!
                ensures
                    - returns the result of the cross product between *this and rhs
            !*/

            vector<double,NR> normalize (
            ) const;
            /*!
                ensures
                    - returns a vector with length() == 1 and in the same direction as *this
            !*/

            vector operator+ (
                const vector& rhs
            ) const;
            /*!
                ensures
                    - returns the result of adding *this to rhs
            !*/

            vector operator- (
                const vector& rhs
            ) const;
            /*!
                ensures
                    - returns the result of subtracting rhs from *this
            !*/

            vector operator- (
            ) const;
            /*!
                ensures
                    - returns -1*(*this)
            !*/

            vector operator/ (
                const T rhs
            ) const;
            /*!
                ensures
                    - returns the result of dividing *this by rhs
            !*/

            vector& operator= (
                const vector& rhs
            );
            /*!
                ensures
                    - #x() == rhs.x()
                    - #y() == rhs.y()
                    - #z() == rhs.z()
                    - returns #*this
            !*/

            vector& operator += (
                const vector& rhs
            );
            /*!
                ensures
                    - #*this == *this + rhs
                    - returns #*this
            !*/

            vector& operator -= (
                const vector& rhs
            );
            /*!
                ensures
                    - #*this == *this - rhs
                    - returns #*this
            !*/

            vector& operator *= (
                const T rhs
            );
            /*!
                ensures
                    - #*this == *this * rhs
                    - returns #*this
            !*/

            vector& operator /= (
                const T rhs
            );
            /*!
                ensures
                    - #*this == *this / rhs
                    - returns #*this
            !*/

            template <typename U, long NR2>
            bool operator== (
                const vector<U,NR2>& rhs
            ) const;
            /*!
                ensures
                    - if (x() == rhs.x() && y() == rhs.y() && z() == rhs.z()) then
                        - returns true
                    - else
                        - returns false
            !*/

            template <typename U, long NR2>
            bool operator!= (
                const vector<U,NR2>& rhs
            ) const;
            /*!
                ensures
                    - returns !((*this) == rhs)
            !*/

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

        };

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

        template<typename T, typename U, long NR>
        vector operator* (
            const vector<T,NR> & lhs,
            const U rhs
        );
        /*!
            ensures
                - returns the result of multiplying the scalar rhs by lhs
        !*/

        template<typename T, typename U, long NR>
        vector operator* (
            const U lhs,
            const vector<T,NR> & rhs
        );
        /*!
            ensures
                - returns the result of multiplying the scalar lhs by rhs
        !*/

        template<typename T, long NR>
        inline void swap (
            vector<T,NR> & a,
            vector<T,NR> & b
        ) { a.swap(b); }
        /*!
            provides a global swap function
        !*/

        template<typename T, long NR>
        void serialize (
            const vector<T,NR>& item,
            std::ostream& out
        );
        /*!
            provides serialization support
        !*/

        template<typename T, long NR>
        void deserialize (
            vector<T,NR>& item,
            std::istream& in
        );
        /*!
            provides deserialization support
        !*/

        template<typename T>
        std::ostream& operator<< (
            std::ostream& out,
            const vector<T,3>& item
        );
        /*!
            ensures
                - writes item to out in the form "(x, y, z)"
        !*/

        template<typename T>
        std::istream& operator>>(
            std::istream& in,
            vector<T,3>& item
        );
        /*!
            ensures
                - reads a vector from the input stream in and stores it in #item.
                  The data in the input stream should be of the form (x, y, z)
        !*/

        template<typename T>
        std::ostream& operator<< (
            std::ostream& out,
            const vector<T,2>& item
        );
        /*!
            ensures
                - writes item to out in the form "(x, y)"
        !*/

        template<typename T>
        std::istream& operator>>(
            std::istream& in,
            vector<T,2>& item
        );
        /*!
            ensures
                - reads a vector from the input stream in and stores it in #item.
                  The data in the input stream should be of the form (x, y)
        !*/

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

        /*!A point
            This is just a typedef of the vector object.
        !*/

        typedef vector<long,2> point;

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

    }

    namespace std
    {
        /*!
            Define std::less<vector<T,3> > so that you can use vectors in the associative containers.
        !*/
        template<typename T>
        struct less<dlib::vector<T,3> > : public binary_function<dlib::vector<T,3> ,dlib::vector<T,3> ,bool>
        {
            inline bool operator() (const dlib::vector<T,3> & a, const dlib::vector<T,3> & b) const
            {
                if      (a.x() < b.x()) return true;
                else if (a.x() > b.x()) return false;
                else if (a.y() < b.y()) return true;
                else if (a.y() > b.y()) return false;
                else if (a.z() < b.z()) return true;
                else if (a.z() > b.z()) return false;
                else                    return false;
            }
        };

        /*!
            Define std::less<vector<T,2> > so that you can use vector<T,2>s in the associative containers.
        !*/
        template<typename T>
        struct less<dlib::vector<T,2> > : public binary_function<dlib::vector<T,2> ,dlib::vector<T,2> ,bool>
        {
            inline bool operator() (const dlib::vector<T,2> & a, const dlib::vector<T,2> & b) const
            {
                if      (a.x() < b.x()) return true;
                else if (a.x() > b.x()) return false;
                else if (a.y() < b.y()) return true;
                else if (a.y() > b.y()) return false;
                else                    return false;
            }
        };
    }

    #endif // DLIB_VECTOR_ABSTRACT_