dlib C++ Library - matrix_utilities_abstract.h

    // Copyright (C) 2006  Davis E. King (davisking@users.sourceforge.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #undef DLIB_MATRIx_UTILITIES_ABSTRACT_
    #ifdef DLIB_MATRIx_UTILITIES_ABSTRACT_

    #include "matrix_abstract.h"
    #include <complex>
    #include "pixel.h"
    #include "../geometry.h"
    #inclue <vector>

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                             Elementary matrix operations
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        const matrix_exp diag (
            const matrix_exp& m
        );
        /*!
            requires
                - m is a square matrix
            ensures
                - returns a column vector R that contains the elements from the diagonal
                  of m in the order R(0)==m(0,0), R(1)==m(1,1), R(2)==m(2,2) and so on.
        !*/

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

        const matrix_exp diagm (
            const matrix_exp& m
        );
        /*!
            requires
                - m is a row or column matrix
            ensures
                - returns a square matrix M such that:
                    - diag(M) == m
                    - non diagonal elements of M are 0
        !*/

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

        const matrix_exp trans (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns the transpose of the matrix m
        !*/

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

        template <
            typename T,
            long NR,
            long NC,
            T val
            >
        const matrix_exp uniform_matrix (
        );
        /*!
            requires
                - NR > 0 && NC > 0
            ensures
                - returns an NR by NC matrix with elements of type T and all set to val.
        !*/

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

        template <
            long NR,
            long NC,
            typename T
            >
        const matrix_exp uniform_matrix (
            const T& val
        );
        /*!
            requires
                - NR > 0 && NC > 0
            ensures
                - returns an NR by NC matrix with elements of type T and all set to val.
        !*/

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

        template <
            typename T
            >
        const matrix_exp uniform_matrix (
            long nr,
            long nc,
            const T& val
        );
        /*!
            requires
                - nr > 0 && nc > 0
            ensures
                - returns an nr by nc matrix with elements of type T and all set to val.
        !*/

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

        template <
            typename T
            >
        const matrix_exp identity_matrix (
            long N
        );
        /*!
            requires
                - N > 0
            ensures
                - returns an N by N identity matrix with elements of type T.
        !*/

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

        template <
            typename T,
            long N
            >
        const matrix_exp identity_matrix (
        );
        /*!
            requires
                - N > 0
            ensures
                - returns an N by N identity matrix with elements of type T.
        !*/

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

        template <
            long R,
            long C
            >
        const matrix_exp rotate (
            const matrix_exp& m
        );
        /*!
            requires
                - R < m.nr()
                - C < m.nc()
            ensures
                - returns a matrix R such that:
                    - R::type == the same type that was in m
                    - R has the same dimensions as m
                    - for all valid r and c:
                      R( (r+R)%m.nr() , (c+C)%m.nc() ) == m(r,c)
        !*/

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

        template <
            typename vector_type
            >
        const matrix_exp vector_to_matrix (
            const vector_type& vector
        );
        /*!
            requires
                - vector_type is an implementation of array/array_kernel_abstract.h or
                  std::vector or dlib::std_vector_c or dlib::matrix
            ensures
                - if (vector_type is a dlib::matrix) then
                    - returns a reference to vector
                - else
                    - returns a matrix R such that:
                        - R.nr() == vector.size()
                        - R.nc() == 1
                        - for all valid r:
                          R(r) == vector[r]
        !*/

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

        template <
            typename array_type
            >
        const matrix_exp array_to_matrix (
            const array_type& array
        );
        /*!
            requires
                - array_type is an implementation of array2d/array2d_kernel_abstract.h
                  or dlib::matrix
            ensures
                - if (array_type is a dlib::matrix) then
                    - returns a reference to array
                - else
                    - returns a matrix R such that:
                        - R.nr() == array.nr()
                        - R.nc() == array.nc()
                        - for all valid r and c:
                          R(r, c) == array[r][c]
        !*/

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

        const rectangle get_rect (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns rectangle(0, 0, m.nc()-1, m.nr()-1)
                  (i.e. returns a rectangle that has the same dimensions as
                  the matrix m)
        !*/

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

        const matrix_exp subm (
            const matrix_exp& m,
            long row,
            long col,
            long nr,
            long nc
        );
        /*!
            requires
                - row >= 0
                - row + nr <= m.nr()
                - col >= 0
                - col + nc <= m.nc()
            ensures
                - returns a matrix R such that:
                    - R.nr() == nr
                    - R.nc() == nc
                    - for all valid r and c:
                      R(r, c) == m(r+row,c+col)
        !*/

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

        const matrix_exp subm (
            const matrix_exp& m,
            const rectangle& rect
        );
        /*!
            requires
                - get_rect(m).contains(rect) == true
                  (i.e. rect is a region inside the matrix m)
            ensures
                - returns a matrix R such that:
                    - R.nr() == rect.height()
                    - R.nc() == rect.width()
                    - for all valid r and c:
                      R(r, c) == m(r+rect.top(), c+rect.left())
        !*/

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

        const matrix_exp rowm (
            const matrix_exp& m,
            long row
        );
        /*!
            requires
                - 0 <= row < m.nr()
            ensures
                - returns a matrix R such that:
                    - R.nr() == 1
                    - R.nc() == m.nc()
                    - for all valid i:
                      R(i) == m(row,i)
        !*/

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

        const matrix_exp colm (
            const matrix_exp& m,
            long col
        );
        /*!
            requires
                - 0 <= col < m.nr()
            ensures
                - returns a matrix R such that:
                    - R.nr() == m.nr()
                    - R.nc() == 1
                    - for all valid i:
                      R(i) == m(i,col)
        !*/

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

        assignable_matrix_expression set_subm (
            matrix& m,
            long row,
            long col,
            long nr,
            long nc
        );
        /*!
            requires
                - row >= 0
                - row + nr <= m.nr()
                - col >= 0
                - col + nc <= m.nc()
            ensures
                - statements of the following form:
                    - set_subm(m,row,col,nr,nc) = some_matrix;
                  result in it being the case that:
                    - subm(m,row,col,nr,nc) == some_matrix.

                - statements of the following form:
                    - set_subm(m,row,col,nr,nc) = scalar_value;
                  result in it being the case that:
                    - subm(m,row,col,nr,nc) == uniform_matrix<matrix::type>(nr,nc,scalar_value).
        !*/

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

        assignable_matrix_expression set_subm (
            matrix& m,
            const rectangle& rect
        );
        /*!
            requires
                - get_rect(m).contains(rect) == true
                  (i.e. rect is a region inside the matrix m)
            ensures
                - statements of the following form:
                    - set_subm(m,rect) = some_matrix;
                  result in it being the case that:
                    - subm(m,rect) == some_matrix.

                - statements of the following form:
                    - set_subm(m,rect) = scalar_value;
                  result in it being the case that:
                    - subm(m,rect) == uniform_matrix<matrix::type>(nr,nc,scalar_value).
        !*/

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

        assignable_matrix_expression set_rowm (
            matrix& m,
            long row
        );
        /*!
            requires
                - 0 <= row < m.nr()
            ensures
                - statements of the following form:
                    - set_rowm(m,row) = some_matrix;
                  result in it being the case that:
                    - rowm(m,row) == some_matrix.

                - statements of the following form:
                    - set_rowm(m,row) = scalar_value;
                  result in it being the case that:
                    - rowm(m,row) == uniform_matrix<matrix::type>(1,nc,scalar_value).
        !*/

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

        assignable_matrix_expression set_colm (
            matrix& m,
            long col
        );
        /*!
            requires
                - 0 <= col < m.nr()
            ensures
                - statements of the following form:
                    - set_colm(m,col) = some_matrix;
                  result in it being the case that:
                    - colm(m,col) == some_matrix.

                - statements of the following form:
                    - set_colm(m,col) = scalar_value;
                  result in it being the case that:
                    - colm(m,col) == uniform_matrix<matrix::type>(nr,1,scalar_value).
        !*/

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

        template <
            long R,
            long C
            >
        const matrix_exp removerc (
            const matrix_exp& m
        );
        /*!
            requires
                - m.nr() > R
                - m.nc() > C
            ensures
                - returns a matrix M such that:
                    - M.nr() == m.nr() - 1
                    - M.nc() == m.nc() - 1
                    - M == m with its R row and C column removed
        !*/

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

        const matrix_exp removerc (
            const matrix_exp& m,
            long R,
            long C
        );
        /*!
            requires
                - m.nr() > R
                - m.nc() > C
            ensures
                - returns a matrix M such that:
                    - M.nr() == m.nr() - 1
                    - M.nc() == m.nc() - 1
                    - M == m with its R row and C column removed
        !*/

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

        template <
            long R
            >
        const matrix_exp remove_row (
            const matrix_exp& m
        );
        /*!
            requires
                - m.nr() > R
            ensures
                - returns a matrix M such that:
                    - M.nr() == m.nr() - 1
                    - M.nc() == m.nc()
                    - M == m with its R row removed
        !*/

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

        const matrix_exp remove_row (
            const matrix_exp& m,
            long R
        );
        /*!
            requires
                - m.nr() > R
            ensures
                - returns a matrix M such that:
                    - M.nr() == m.nr() - 1
                    - M.nc() == m.nc()
                    - M == m with its R row removed
        !*/

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

        template <
            long C
            >
        const matrix_exp remove_col (
            const matrix_exp& m
        );
        /*!
            requires
                - m.nc() > C
            ensures
                - returns a matrix M such that:
                    - M.nr() == m.nr()
                    - M.nc() == m.nc() - 1
                    - M == m with its C column removed
        !*/

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

        const matrix_exp remove_col (
            const matrix_exp& m,
            long C
        );
        /*!
            requires
                - m.nc() > C
            ensures
                - returns a matrix M such that:
                    - M.nr() == m.nr()
                    - M.nc() == m.nc() - 1
                    - M == m with its C column removed
        !*/

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

        template <
           typename target_type
           >
        const matrix_exp matrix_cast (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns a matrix R where for all valid r and c:
                  R(r,c) == static_cast<target_type>(m(r,c))
                  also, R has the same dimensions as m.
        !*/

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

        template <
            typename T,
            long NR,
            long NC,
            typename MM,
            typename U
            >
        void set_all_elements (
            matrix<T,NR,NC,MM>& m,
            U value
        );
        /*!
            ensures
                - for all valid r and c:
                  m(r,c) == value
        !*/

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

        const matrix_exp::matrix_type tmp (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns a temporary matrix object that is a copy of m.
                  (This is useful because it allows you to easily force a matrix_exp to
                  fully evaluate before giving it to some other function that queries
                  the elements of the matrix more than once each, such as the matrix
                  multiplication operator.)
        !*/

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

        bool equal (
            const matrix_exp& a,
            const matrix_exp& b,
            const matrix_exp::type epsilon = 100*std::numeric_limits<matrix_exp::type>::epsilon()
        );
        /*!
            ensures
                - if (a and b don't have the same dimensions) then
                    - returns false
                - else if (there exists an r and c such that abs(a(r,c)-b(r,c)) > epsilon) then
                    - returns false
                - else
                    - returns true
        !*/

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

        const matrix_exp pointwise_multiply (
            const matrix_exp& a,
            const matrix_exp& b
        );
        /*!
            requires
                - a.nr() == b.nr()
                - a.nc() == b.nc()
                - a and b both contain the same type of element
            ensures
                - returns a matrix R such that:
                    - R::type == the same type that was in a and b.
                    - R has the same dimensions as a and b.
                    - for all valid r and c:
                      R(r,c) == a(r,c) * b(r,c)
        !*/

        const matrix_exp pointwise_multiply (
            const matrix_exp& a,
            const matrix_exp& b,
            const matrix_exp& c
        );
        /*!
            performs pointwise_multiply(a,pointwise_multiply(b,c));
        !*/

        const matrix_exp pointwise_multiply (
            const matrix_exp& a,
            const matrix_exp& b,
            const matrix_exp& c,
            const matrix_exp& d
        );
        /*!
            performs pointwise_multiply(pointwise_multiply(a,b),pointwise_multiply(c,d));
        !*/

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

        const matrix_exp tensor_product (
            const matrix_exp& a,
            const matrix_exp& b
        );
        /*!
            requires
                - a and b both contain the same type of element
            ensures
                - returns a matrix R such that:
                    - R::type == the same type that was in a and b.
                    - R.nr() == a.nr()*b.nr()
                    - R.nc() == a.nc()*b.nc()
                    - for all valid r and c:
                      R(r,c) == a(r/b.nr(), c/b.nc()) * b(r%b.nr(), c%b.nc())
                    - I.e. R is the tensor product of matrix a with matrix b
        !*/

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

        const matrix_exp scale_columns (
            const matrix_exp& m,
            const matrix_exp& v
        );
        /*!
            requires
                - v.nc() == 1 (i.e. v is a column vector)
                - v.nr() == m.nc()
                - m and v both contain the same type of element
            ensures
                - returns a matrix R such that:
                    - R::type == the same type that was in m and v.
                    - R has the same dimensions as m.
                    - for all valid r and c:
                      R(r,c) == m(r,c) * v(c)
                    - i.e. R is the result of multiplying each of m's columns by
                      the corresponding scalar in v.
        !*/

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

        template <typename T>
        void sort_columns (
            matrix<T>& m,
            matrix<T>& v
        );
        /*!
            requires
                - v.nc() == 1 (i.e. v is a column vector)
                - v.nr() == m.nc()
                - m and v both contain the same type of element
            ensures
                - the dimensions for m and v are not changed
                - sorts the columns of m according to the values in v.
                  i.e.
                    - #v == the contents of v but in sorted order according to
                      operator<.  So smaller elements come first.
                    - Let #v(new(i)) == v(i) (i.e. new(i) is the index element i moved to)
                    - colm(#m,new(i)) == colm(m,i)
        !*/

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

        template <typename T>
        void rsort_columns (
            matrix<T>& m,
            matrix<T>& v
        );
        /*!
            requires
                - v.nc() == 1 (i.e. v is a column vector)
                - v.nr() == m.nc()
                - m and v both contain the same type of element
            ensures
                - the dimensions for m and v are not changed
                - sorts the columns of m according to the values in v.
                  i.e.
                    - #v == the contents of v but in sorted order according to
                      operator>.  So larger elements come first.
                    - Let #v(new(i)) == v(i) (i.e. new(i) is the index element i moved to)
                    - colm(#m,new(i)) == colm(m,i)
        !*/

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

        const matrix_exp::type length_squared (
            const matrix_exp& m
        );
        /*!
            requires
                - m.nr() == 1 || m.nc() == 1
                  (i.e. m must be a vector)
            ensures
                - returns sum(squared(m))
                  (i.e. returns the square of the length of the vector m)
        !*/

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

        const matrix_exp::type length (
            const matrix_exp& m
        );
        /*!
            requires
                - m.nr() == 1 || m.nc() == 1
                  (i.e. m must be a vector)
            ensures
                - returns sqrt(sum(squared(m)))
                  (i.e. returns the length of the vector m)
        !*/

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                             Linear algebra functions
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        const matrix_exp::matrix_type inv (
            const matrix_exp& m
        );
        /*!
            requires
                - m is a square matrix
            ensures
                - returns the inverse of m
                  (Note that if m is singular or so close to being singular that there
                  is a lot of numerical error then the returned matrix will be bogus.
                  You can check by seeing if m*inv(m) is an identity matrix)
        !*/

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

        const matrix pinv (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns the Moore-Penrose pseudoinverse of m.
                - The returned matrix has m.nc() rows and m.nr() columns.
        !*/

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

        void svd (
            const matrix_exp& m,
            matrix<matrix_exp::type>& u,
            matrix<matrix_exp::type>& w,
            matrix<matrix_exp::type>& v
        );
        /*!
            ensures
                - computes the singular value decomposition of m
                - m == #u*#w*trans(#v)
                - trans(#u)*#u == identity matrix
                - trans(#v)*#v == identity matrix
                - diag(#w) == the singular values of the matrix m in no
                  particular order.  All non-diagonal elements of #w are
                  set to 0.
                - #u.nr() == m.nr()
                - #u.nc() == m.nc()
                - #w.nr() == m.nc()
                - #w.nc() == m.nc()
                - #v.nr() == m.nc()
                - #v.nc() == m.nc()
        !*/

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

        long svd2 (
            bool withu,
            bool withv,
            const matrix_exp& m,
            matrix<matrix_exp::type>& u,
            matrix<matrix_exp::type>& w,
            matrix<matrix_exp::type>& v
        );
        /*!
            requires
                - m.nr() >= m.nc()
            ensures
                - computes the singular value decomposition of matrix m
                - m == subm(#u,get_rect(m))*diagm(#w)*trans(#v)
                - trans(#u)*#u == identity matrix
                - trans(#v)*#v == identity matrix
                - #w == the singular values of the matrix m in no
                  particular order.
                - #u.nr() == m.nr()
                - #u.nc() == m.nr()
                - #w.nr() == m.nc()
                - #w.nc() == 1
                - #v.nr() == m.nc()
                - #v.nc() == m.nc()
                - if (widthu == false) then
                    - ignore the above regarding #u, it isn't computed and its
                      output state is undefined.
                - if (widthv == false) then
                    - ignore the above regarding #v, it isn't computed and its
                      output state is undefined.
                - returns an error code of 0, if no errors and 'k' if we fail to
                  converge at the 'kth' singular value.
        !*/

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

        void svd3 (
            const matrix_exp& m,
            matrix<matrix_exp::type>& u,
            matrix<matrix_exp::type>& w,
            matrix<matrix_exp::type>& v
        );
        /*!
            ensures
                - computes the singular value decomposition of m
                - m == #u*diagm(#w)*trans(#v)
                - trans(#u)*#u == identity matrix
                - trans(#v)*#v == identity matrix
                - #w == the singular values of the matrix m in no
                  particular order.
                - #u.nr() == m.nr()
                - #u.nc() == m.nc()
                - #w.nr() == m.nc()
                - #w.nc() == 1
                - #v.nr() == m.nc()
                - #v.nc() == m.nc()
        !*/

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

        const matrix_exp::type det (
            const matrix_exp& m
        );
        /*!
            requires
                - m is a square matrix
            ensures
                - returns the determinant of m
        !*/

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

        const matrix_exp::matrix_type cholesky_decomposition (
            const matrix_exp& A
        );
        /*!
            requires
                - A is a square matrix
            ensures
                - if (A has a Cholesky Decomposition) then
                    - returns the decomposition of A.  That is, returns a matrix L
                      such that L*trans(L) == A.  L will also be lower triangular.
                - else
                    - returns a matrix with the same dimensions as A but it
                      will have a bogus value.  I.e. it won't be a decomposition.
        !*/

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

        const matrix_exp::matrix_type inv_lower_triangular (
            const matrix_exp& A
        );
        /*!
            requires
                - A is a square matrix
            ensures
                - if (A is lower triangular) then
                    - returns the inverse of A.
                - else
                    - returns a matrix with the same dimensions as A but it
                      will have a bogus value.  I.e. it won't be an inverse.
        !*/

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

        const matrix_exp::matrix_type inv_upper_triangular (
            const matrix_exp& A
        );
        /*!
            requires
                - A is a square matrix
            ensures
                - if (A is upper triangular) then
                    - returns the inverse of A.
                - else
                    - returns a matrix with the same dimensions as A but it
                      will have a bogus value.  I.e. it won't be an inverse.
        !*/

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                              Statistics
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        const matrix_exp::type min (
            const matrix_exp& m
        );
        /*!
            requires
                - m.size() > 0
            ensures
                - returns the value of the smallest element of m
        !*/

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

        const matrix_exp::type max (
            const matrix_exp& m
        );
        /*!
            requires
                - m.size() > 0
            ensures
                - returns the value of the biggest element of m
        !*/

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

        const matrix_exp::type sum (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns the sum of all elements in m
        !*/

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

        const matrix_exp::type prod (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns the results of multiplying all elements of m together.
        !*/

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

        const matrix_exp::type mean (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns the mean of all elements in m.
                  (i.e. returns sum(m)/(m.nr()*m.nc()))
        !*/

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

        const matrix_exp::type variance (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns the unbiased sample variance of all elements in m
                  (i.e. 1.0/(m.nr()*m.nc() - 1)*(sum of all pow(m(i,j) - mean(m),2)))
        !*/

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

        const matrix covariance (
            const matrix_exp& m
        );
        /*!
            requires
                - matrix_exp::type == a dlib::matrix object
                - m.nr() > 1
                - m.nc() == 1 (i.e. m is a column vector)
                - for all valid i, j:
                    - m(i).nr() > 0
                    - m(i).nc() == 1
                    - m(i).nr() == m(j).nr()
                    - i.e. m contains only column vectors and all the column vectors
                      have the same non-zero length
            ensures
                - returns the unbiased sample covariance matrix for the set of samples
                  in m.
                  (i.e. 1.0/(m.nr()-1)*(sum of all (m(i) - mean(m))*trans(m(i) - mean(m))))
                - the returned matrix will contain elements of type matrix_exp::type::type.
                - the returned matrix will have m(0).nr() rows and columns.
        !*/

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                                 Pixel and Image Utilities
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <
            typename T,
            typename P
            >
        const matrix_exp pixel_to_vector (
            const P& pixel
        );
        /*!
            requires
                - pixel_traits<P>::has_alpha == false
            ensures
                - returns a matrix M such that:
                    - M::type == T
                    - M::NC == 1
                    - M::NR == pixel_traits<P>::num
                    - if (pixel_traits<P>::grayscale) then
                        - M(0) == pixel
                    - if (pixel_traits<P>::rgb) then
                        - M(0) == pixel.red
                        - M(1) == pixel.green
                        - M(2) == pixel.blue
                    - if (pixel_traits<P>::hsi) then
                        - M(0) == pixel.h
                        - M(1) == pixel.s
                        - M(2) == pixel.i
        !*/

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

        template <
            typename P
            >
        void vector_to_pixel (
            P& pixel,
            const matrix_exp& vector
        );
        /*!
            requires
                - pixel_traits<P>::has_alpha == false
                - vector::NR == pixel_traits<P>::num
                - vector::NC == 1
                  (i.e. you have to use a statically dimensioned vector)
            ensures
                - if (pixel_traits<P>::grayscale) then
                    - pixel == M(0)
                - if (pixel_traits<P>::rgb) then
                    - pixel.red   == M(0)
                    - pixel.green == M(1)
                    - pixel.blue  == M(2)
                - if (pixel_traits<P>::hsi) then
                    - pixel.h == M(0)
                    - pixel.s == M(1)
                    - pixel.i == M(2)
        !*/

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

        template <
            long lower,
            long upper
            >
        const matrix_exp clamp (
            const matrix_exp& m
        );
        /*!
            ensures
                - returns a matrix R such that:
                    - R::type == the same type that was in m
                    - R has the same dimensions as m
                    - for all valid r and c:
                        - if (m(r,c) > upper) then
                            - R(r,c) == upper
                        - else if (m(r,c) < lower) then
                            - R(r,c) == lower
                        - else
                            - R(r,c) == m(r,c)
        !*/

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

    }

    #endif // DLIB_MATRIx_UTILITIES_ABSTRACT_