// Copyright (C) 2010 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_MATRIx_OP_H_ #define DLIB_MATRIx_OP_H_ #include "matrix_exp.h" namespace dlib { // ---------------------------------------------------------------------------------------- template <typename OP > class matrix_op; template < typename OP > struct matrix_traits<matrix_op<OP> > { typedef typename OP::type type; typedef typename OP::const_ret_type const_ret_type; typedef typename OP::mem_manager_type mem_manager_type; typedef typename OP::layout_type layout_type; const static long NR = OP::NR; const static long NC = OP::NC; const static long cost = OP::cost; }; template < typename OP > class matrix_op : public matrix_exp<matrix_op<OP> > { /*! WHAT THIS OBJECT REPRESENTS The matrix_op is simply a tool for reducing the amount of boilerplate you need to write when creating matrix expressions. !*/ public: typedef typename matrix_traits<matrix_op>::type type; typedef typename matrix_traits<matrix_op>::const_ret_type const_ret_type; typedef typename matrix_traits<matrix_op>::mem_manager_type mem_manager_type; typedef typename matrix_traits<matrix_op>::layout_type layout_type; const static long NR = matrix_traits<matrix_op>::NR; const static long NC = matrix_traits<matrix_op>::NC; const static long cost = matrix_traits<matrix_op>::cost; private: // This constructor exists simply for the purpose of causing a compile time error if // someone tries to create an instance of this object with the wrong kind of object. template <typename T1> matrix_op (T1); public: matrix_op ( const OP& op_ ) : op(op_) {} const_ret_type operator() ( long r, long c ) const { return op.apply(r,c); } const_ret_type operator() ( long i ) const { return matrix_exp<matrix_op>::operator()(i); } template <typename U> bool aliases ( const matrix_exp<U>& item ) const { return op.aliases(item); } template <typename U> bool destructively_aliases ( const matrix_exp<U>& item ) const { return op.destructively_aliases(item); } long nr ( ) const { return op.nr(); } long nc ( ) const { return op.nc(); } const OP op; }; // ---------------------------------------------------------------------------------------- template <typename OP > class matrix_diag_op; template < typename OP > struct matrix_traits<matrix_diag_op<OP> > { typedef typename OP::type type; typedef typename OP::const_ret_type const_ret_type; typedef typename OP::mem_manager_type mem_manager_type; typedef typename OP::layout_type layout_type; const static long NR = OP::NR; const static long NC = OP::NC; const static long cost = OP::cost; }; template < typename OP > class matrix_diag_op : public matrix_diag_exp<matrix_diag_op<OP> > { /*! WHAT THIS OBJECT REPRESENTS The matrix_diag_op is simply a tool for reducing the amount of boilerplate you need to write when creating matrix expressions. !*/ public: typedef typename matrix_traits<matrix_diag_op>::type type; typedef typename matrix_traits<matrix_diag_op>::const_ret_type const_ret_type; typedef typename matrix_traits<matrix_diag_op>::mem_manager_type mem_manager_type; typedef typename matrix_traits<matrix_diag_op>::layout_type layout_type; const static long NR = matrix_traits<matrix_diag_op>::NR; const static long NC = matrix_traits<matrix_diag_op>::NC; const static long cost = matrix_traits<matrix_diag_op>::cost; private: // This constructor exists simply for the purpose of causing a compile time error if // someone tries to create an instance of this object with the wrong kind of object. template <typename T1> matrix_diag_op (T1); public: matrix_diag_op ( const OP& op_ ) : op(op_) {} const_ret_type operator() ( long r, long c ) const { return op.apply(r,c); } const_ret_type operator() ( long i ) const { return matrix_exp<matrix_diag_op>::operator()(i); } template <typename U> bool aliases ( const matrix_exp<U>& item ) const { return op.aliases(item); } template <typename U> bool destructively_aliases ( const matrix_exp<U>& item ) const { return op.destructively_aliases(item); } long nr ( ) const { return op.nr(); } long nc ( ) const { return op.nc(); } const OP op; }; // ---------------------------------------------------------------------------------------- struct does_not_alias { /*! This is a partial implementation of a matrix operator that never aliases another expression. !*/ template <typename U> bool aliases ( const U& ) const { return false; } template <typename U> bool destructively_aliases ( const U& ) const { return false; } }; // ---------------------------------------------------------------------------------------- template <typename M> struct basic_op_m { /*! This is a partial implementation of a matrix operator that preserves the dimensions of its argument and doesn't have destructive aliasing. !*/ private: // This constructor exists simply for the purpose of causing a compile time error if // someone tries to create an instance of this object with the wrong kind of object. template <typename T1> basic_op_m (T1); public: basic_op_m( const M& m_ ) : m(m_){} const M& m; const static long NR = M::NR; const static long NC = M::NC; typedef typename M::mem_manager_type mem_manager_type; typedef typename M::layout_type layout_type; long nr () const { return m.nr(); } long nc () const { return m.nc(); } template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m.aliases(item); } template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); } }; // ---------------------------------------------------------------------------------------- template <typename M1, typename M2> struct basic_op_mm { /*! This is a partial implementation of a matrix operator that preserves the dimensions of its arguments and doesn't have destructive aliasing. !*/ private: // This constructor exists simply for the purpose of causing a compile time error if // someone tries to create an instance of this object with the wrong kind of object. template <typename T1, typename T2> basic_op_mm (T1, T2); public: basic_op_mm( const M1& m1_, const M2& m2_ ) : m1(m1_), m2(m2_){} const M1& m1; const M2& m2; const static long NR = M1::NR; const static long NC = M1::NC; typedef typename M1::mem_manager_type mem_manager_type; typedef typename M1::layout_type layout_type; long nr () const { return m1.nr(); } long nc () const { return m1.nc(); } template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); } template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.destructively_aliases(item) || m2.destructively_aliases(item); } }; // ---------------------------------------------------------------------------------------- template <typename M1, typename M2, typename M3> struct basic_op_mmm { /*! This is a partial implementation of a matrix operator that preserves the dimensions of its arguments and doesn't have destructive aliasing. !*/ private: // This constructor exists simply for the purpose of causing a compile time error if // someone tries to create an instance of this object with the wrong kind of object. template <typename T1, typename T2, typename T3> basic_op_mmm (T1, T2, T3); public: basic_op_mmm( const M1& m1_, const M2& m2_, const M3& m3_ ) : m1(m1_), m2(m2_), m3(m3_){} const M1& m1; const M2& m2; const M3& m3; const static long NR = M1::NR; const static long NC = M1::NC; typedef typename M1::mem_manager_type mem_manager_type; typedef typename M1::layout_type layout_type; long nr () const { return m1.nr(); } long nc () const { return m1.nc(); } template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item); } template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.destructively_aliases(item) || m2.destructively_aliases(item) || m3.destructively_aliases(item);} }; // ---------------------------------------------------------------------------------------- template <typename M1, typename M2, typename M3, typename M4> struct basic_op_mmmm { /*! This is a partial implementation of a matrix operator that preserves the dimensions of its arguments and doesn't have destructive aliasing. !*/ private: // This constructor exists simply for the purpose of causing a compile time error if // someone tries to create an instance of this object with the wrong kind of object. template <typename T1, typename T2, typename T3, typename T4> basic_op_mmmm (T1, T2, T3, T4); public: basic_op_mmmm( const M1& m1_, const M2& m2_, const M3& m3_, const M4& m4_ ) : m1(m1_), m2(m2_), m3(m3_), m4(m4_){} const M1& m1; const M2& m2; const M3& m3; const M4& m4; const static long NR = M1::NR; const static long NC = M1::NC; typedef typename M1::mem_manager_type mem_manager_type; typedef typename M1::layout_type layout_type; long nr () const { return m1.nr(); } long nc () const { return m1.nc(); } template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item) || m4.aliases(item); } template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.destructively_aliases(item) || m2.destructively_aliases(item) || m3.destructively_aliases(item) || m4.destructively_aliases(item);} }; // ---------------------------------------------------------------------------------------- #define DLIB_DEFINE_OP_M(op_name, function, extra_cost) \ template <typename M> \ struct op_name \ { \ op_name( \ const M& m_ \ ) : m(m_){} \ \ const M& m; \ \ const static long cost = M::cost+(extra_cost); \ const static long NR = M::NR; \ const static long NC = M::NC; \ typedef typename M::type type; \ typedef const typename M::type const_ret_type; \ typedef typename M::mem_manager_type mem_manager_type; \ typedef typename M::layout_type layout_type; \ \ const_ret_type apply (long r, long c) const { return function(m(r,c)); } \ \ long nr () const { return m.nr(); } \ long nc () const { return m.nc(); } \ \ template <typename U> bool aliases ( const matrix_exp<U>& item) const \ { return m.aliases(item); } \ template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \ { return m.destructively_aliases(item); } \ \ }; #define DLIB_DEFINE_FUNCTION_M(op_name, name, function, extra_cost) \ DLIB_DEFINE_OP_M(op_name, function, extra_cost) \ template < typename M > \ const matrix_op<op_name<M> > name ( const matrix_exp<M>& m) \ { \ typedef op_name<M> op; \ return matrix_op<op>(op(m.ref())); \ } // ---------------------------------------------------------------------------------------- #define DLIB_DEFINE_OP_MS(op_name, function, extra_cost) \ template <typename M, typename S> \ struct op_name \ { \ op_name( \ const M& m_, \ const S& s_ \ ) : m(m_), s(s_){} \ \ const M& m; \ const S s; \ \ const static long cost = M::cost+(extra_cost); \ const static long NR = M::NR; \ const static long NC = M::NC; \ typedef typename M::type type; \ typedef const typename M::type const_ret_type; \ typedef typename M::mem_manager_type mem_manager_type; \ typedef typename M::layout_type layout_type; \ \ const_ret_type apply (long r, long c) const { return function(m(r,c), s); } \ \ long nr () const { return m.nr(); } \ long nc () const { return m.nc(); } \ \ template <typename U> bool aliases ( const matrix_exp<U>& item) const \ { return m.aliases(item); } \ template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \ { return m.destructively_aliases(item); } \ \ }; #define DLIB_DEFINE_FUNCTION_MS(op_name, name, function, extra_cost) \ DLIB_DEFINE_OP_MS(op_name, function, extra_cost) \ template < typename M, typename S > \ const matrix_op<op_name<M, S> > name ( const matrix_exp<M>& m, const S& s) \ { \ typedef op_name<M, S> op; \ return matrix_op<op>(op(m.ref(), s)); \ } // ---------------------------------------------------------------------------------------- #define DLIB_DEFINE_OP_SM(op_name, function, extra_cost) \ template <typename S, typename M> \ struct op_name \ { \ op_name( \ const S& s_, \ const M& m_ \ ) : m(m_), s(s_){} \ \ const M& m; \ const S s; \ \ const static long cost = M::cost+(extra_cost); \ const static long NR = M::NR; \ const static long NC = M::NC; \ typedef typename M::type type; \ typedef const typename M::type const_ret_type; \ typedef typename M::mem_manager_type mem_manager_type; \ typedef typename M::layout_type layout_type; \ \ const_ret_type apply (long r, long c) const { return function(s, m(r,c)); } \ \ long nr () const { return m.nr(); } \ long nc () const { return m.nc(); } \ \ template <typename U> bool aliases ( const matrix_exp<U>& item) const \ { return m.aliases(item); } \ template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \ { return m.destructively_aliases(item); } \ \ }; #define DLIB_DEFINE_FUNCTION_SM(op_name, name, function, extra_cost) \ DLIB_DEFINE_OP_SM(op_name, function, extra_cost) \ template < typename S, typename M > \ const matrix_op<op_name<S, M> > name (const S& s, const matrix_exp<M>& m) \ { \ typedef op_name<S, M> op; \ return matrix_op<op>(op(s, m.ref())); \ } // ---------------------------------------------------------------------------------------- } #endif // DLIB_MATRIx_OP_H_