#ifndef ICL_FIXED_MATRIX_H #define ICL_FIXED_MATRIX_H #include #include #include #include #include #include #include #include #include #include #ifdef WITH_IPP_OPTIMIZATION #include #endif namespace icl{ /// FixedMatrix base struct defining datamode enum struct FixedMatrixBase{ /// Optimized copy function template (for N>30 using std::copy, otherwise a simple loop is used) template static void optimized_copy(SrcIterator srcBegin, SrcIterator srcEnd, DstIterator dstBegin){ if(N>30){ std::copy(srcBegin,srcEnd,dstBegin); }else{ while(srcBegin != srcEnd){ // *dstBegin++ = *srcBegin++; *dstBegin = *srcBegin; dstBegin++; srcBegin++; } } } }; /** \cond */ /// Forward Declaration fo FixedMatrixPart struct template class FixedMatrix; /** \endcond */ /// Utility struct for FixedMatrix sub-parts /** FixedMatrix member functions row and col return an instance of this utility structure. FixedMatrixPart instances wrap a range of Iterators (begin- and end-Iterator) of template parameter type. Once created, FixedMatrixParts can not be setup with different Iterators. All further Assignments will only copy the ranged data represented by the source and destination iterator pairs.\\ To avoid problems with ranges of different size, FixedMatrixPart instances are 'templated' to the range size (template parameter N) **/ template class FixedMatrixPart : public FixedMatrixBase{ public: /// Start iterator Iterator begin; /// End iterator Iterator end; /// Creates a new FixedMatrixPart instance with given Iterator Pair FixedMatrixPart(Iterator begin, Iterator end):begin(begin),end(end){} /// Assignment with a new value (all data in range will be assigned with that value) FixedMatrixPart& operator=(const T &value){ std::fill(begin,end,value); return *this; } /// Assignment with another (identical) instance of FixedMatrixPart /** Internally std::copy is used */ FixedMatrixPart& operator=(const FixedMatrixPart &other){ FixedMatrixBase::optimized_copy(other.begin,other.end,begin); return *this; } /// Assignment with another (compatible) instance of FixedMatrixPart /** For compatibility. Iterator type and destination type may differ but RangeSize must be equal */ template FixedMatrixPart& operator=(const FixedMatrixPart &other){ std::transform(other.begin,other.end,begin,clipped_cast); return *this; } /// Assignment with a compatible FixedMatrix instance (FixedMatrix DIM must be euqal to Part-size) /** DIM equality is forced by Argument template parameters <...,COLS,N/COLS> */ template FixedMatrixPart& operator=(const FixedMatrix &m); /// Assignment with a FixedMatrix instance (FixedMatrix DIM must be euqal to Part-size) /** DIM equality is forced by Argument template parameters <...,COLS,N/COLS> */ template FixedMatrixPart& operator=(const FixedMatrix &m); }; /// Powerful and highly flexible Matrix class implementation /** By using fixed template parameters as Matrix dimensions, specializations to e.g. row or column vectors, are also as performant as possible. */ template class FixedMatrix : public FixedMatrixBase{ public: /// returning a reference to a null matrix static const FixedMatrix &null(){ static FixedMatrix null_matrix(T(0)); return null_matrix; } /// count of matrix elements (COLS x ROWS) static const unsigned int DIM = COLS*ROWS; protected: /// internal data storage T m_data[COLS*ROWS]; /// flag to indicate whether current data pointer is owned and must be freed in the desturctor bool m_ownData; public: /// Default constructor /** New data is created internally but elements are not initialized */ FixedMatrix(){} /// Create Matrix and initialize elements with given value FixedMatrix(const T &initValue){ std::fill(begin(),end(),initValue); } /// Create matrix with given data pointer (const version) /** As given data pointer is const, no shallow pointer copies are allowed here @params srcdata const source data pointer copied deeply */ FixedMatrix(const T *srcdata){ FixedMatrixBase::optimized_copy(srcdata,srcdata+dim(),begin()); //std::copy(srcdata,srcdata+dim(),begin()); } /// Create matrix with given initializer elements (16 values max) /** default parameters for unnecessary parameters are not created when compiled with -O4 **/ FixedMatrix(const T& v0,const T& v1,const T& v2=0,const T& v3=0, const T& v4=0,const T& v5=0,const T& v6=0,const T& v7=0, const T& v8=0,const T& v9=0,const T& v10=0,const T& v11=0, const T& v12=0,const T& v13=0,const T& v14=0,const T& v15=0){ #define C1(N) if(DIM>N) m_data[N]=v##N #define C4(A,B,C,D) C1(A);C1(B);C1(C);C1(D) C4(0,1,2,3);C4(4,5,6,7);C4(8,9,10,11);C4(12,13,14,15); #undef C1 #undef C2 } /** \cond */ /** \endcond */ /// Range based constructor for STL compatiblitiy /** Range size must be compatible to the new matrix's dimension */ template FixedMatrix(OtherIterator begin, OtherIterator end){ FixedMatrixBase::optimized_copy(begin,end,begin()); // std::copy(begin,end,begin()); } // Explicit Copy template based constructor (deep copy) FixedMatrix(const FixedMatrix &other){ FixedMatrixBase::optimized_copy(other.begin(),other.end(),begin()); //std::copy(other.begin(),other.end(),begin()); } // Explicit Copy template based constructor (deep copy) template FixedMatrix(const FixedMatrix &other){ std::transform(other.begin(),other.end(),begin(),clipped_cast); } /// Create matrix of a sub-part of another matrix (identical types) template FixedMatrix (const FixedMatrixPart &r){ FixedMatrixBase::optimized_copy(r.begin,r.end,begin()); } /// Create matrix of a sub-part of another matrix (compatible types) template FixedMatrix(const FixedMatrixPart &r){ std::transform(r.begin,r.end,begin(),clipped_cast); } /// Assignment operator (with compatible data type) (deep copy) FixedMatrix &operator=(const FixedMatrix &other){ if(this == &other) return *this; FixedMatrixBase::optimized_copy(other.begin(),other.end(),begin()); //std::copy(other.begin(),other.end(),begin()); return *this; } /// Assignment operator (with compatible data type) (deep copy) /** Internally using std::transform with icl::clipped_cast */ template FixedMatrix &operator=(const FixedMatrix &other){ if(this == &other) return *this; std::transform(other.begin(),other.end(),begin(),clipped_cast); return *this; } /// Assign all elements with given value FixedMatrix &operator=(const T &t){ std::fill(begin(),end(),t); return *this; } /// Assign matrix elements with sup-part of another matrix (identical types) template FixedMatrix &operator=(const FixedMatrixPart &r){ // std::copy(r.begin,r.end,begin()); FixedMatrixBase::optimized_copy(r.begin,r.end,begin()); return *this; } /// Assign matrix elements with sup-part of another matrix (compatible types) template FixedMatrix &operator=(const FixedMatrixPart &r){ std::transform(r.begin,r.end,begin(),clipped_cast); return *this; } /// Matrix devision /** A/B is equal to A*inv(B) Only allowed form square matrices B @param m denominator for division expression */ FixedMatrix operator/(const FixedMatrix &m) const throw (IncompatibleMatrixDimensionException, InvalidMatrixDimensionException, SingularMatrixException){ return this->operator*(m.inv()); } /// Matrix devision (inplace) FixedMatrix &operator/=(const FixedMatrix &m) const throw (IncompatibleMatrixDimensionException, InvalidMatrixDimensionException, SingularMatrixException){ return *this = this->operator*(m.inv()); } /// Multiply all elements by a scalar FixedMatrix operator*(T f) const{ FixedMatrix d; std::transform(begin(),end(),d.begin(),std::bind2nd(std::multiplies(),f)); return d; } /// moved outside the class Multiply all elements by a scalar (inplace) FixedMatrix &operator*=(T f){ std::transform(begin(),end(),begin(),std::bind2nd(std::multiplies(),f)); return *this; } /// Divide all elements by a scalar FixedMatrix operator/(T f) const{ return this->operator*(1/f); } /// Divide all elements by a scalar FixedMatrix &operator/=(T f){ return this->operator*=(1/f); } /// Add a scalar to each element FixedMatrix operator+(const T &t){ FixedMatrix d; std::transform(begin(),end(),d.begin(),std::bind2nd(std::plus(),t)); return d; } /// Add a scalar to each element (inplace) FixedMatrix &operator+=(const T &t){ std::transform(begin(),end(),begin(),std::bind2nd(std::plus(),t)); return *this; } /// Substract a scalar from each element FixedMatrix operator-(const T &t){ FixedMatrix d; std::transform(begin(),end(),d.begin(),std::bind2nd(std::minus(),t)); return d; } /// Substract a scalar from each element (inplace) FixedMatrix &operator-=(const T &t){ std::transform(begin(),end(),begin(),std::bind2nd(std::minus(),t)); return *this; } /// Element-wise matrix addition FixedMatrix operator+(const FixedMatrix &m){ FixedMatrix d; std::transform(begin(),end(),m.begin(),d.begin(),std::plus()); return d; } /// Element-wise matrix addition (inplace) FixedMatrix &operator+=(const FixedMatrix &m){ std::transform(begin(),end(),m.begin(),begin(),std::plus()); return *this; } /// Element-wise matrix subtraction FixedMatrix operator-(const FixedMatrix &m){ FixedMatrix d; std::transform(begin(),end(),m.begin(),d.begin(),std::minus()); return d; } /// Element-wise matrix subtraction (inplace) FixedMatrix &operator-=(const FixedMatrix &m){ std::transform(begin(),end(),m.begin(),begin(),std::minus()); return *this; } /// Prefix - operator /** M + (-M) = 0; */ FixedMatrix operator-() const { FixedMatrix cpy(*this); std::transform(cpy.begin(),cpy.end(),cpy.begin(),std::negate()); return cpy; } /// Element access operator T &operator()(unsigned int col,unsigned int row){ return m_data[col+cols()*row]; } /// Element access operator (const) const T &operator() (unsigned int col,unsigned int row) const{ return m_data[col+cols()*row]; } /// Element access index save (with exception if index is invalid) T &at(unsigned int col,unsigned int row) throw (InvalidIndexException){ if(col>=cols() || row >= rows()) throw InvalidIndexException("row or col index too large"); return m_data[col+cols()*row]; } /// Element access index save (with exception if index is invalid) (const) const T &at(unsigned int col,unsigned int row) const throw (InvalidIndexException){ return const_cast(this)->at(col,row); } /// linear data view element access /** This function is very useful e.g. for derived classes FixedRowVector and FixedColVector */ T &operator[](unsigned int idx){ return m_data[idx]; } /// linear data view element access (const) /** This function is very useful e.g. for derived classes FixedRowVector and FixedColVector */ const T &operator[](unsigned int idx) const{ return m_data[idx]; } /// iterator type typedef T* iterator; /// const iterator type typedef const T* const_iterator; /// row_iterator typedef T* row_iterator; /// const row_iterator typedef const T* const_row_iterator; /// compatibility-function returns template parameter ROWS static unsigned int rows(){ return ROWS; } /// compatibility-function returns template parameter COLS static unsigned int cols(){ return COLS; } /// return internal data pointer T *data() { return m_data; } /// return internal data pointer (const) const T *data() const { return m_data; } /// return static member variable DIM (COLS*ROWS) static unsigned int dim() { return DIM; } /// internal struct for row-wise iteration with stride=COLS struct col_iterator : public std::iterator{ /// just for compatibility with STL typedef unsigned int difference_type; /// wrapped data pointer (held shallowly) mutable T *p; /// the stride is equal to parent Matrix' classes COLS template parameter static const unsigned int STRIDE = COLS; /// Constructor col_iterator(T *col_begin):p(col_begin){} /// prefix increment operator col_iterator &operator++(){ p+=STRIDE; return *this; } /// prefix increment operator (const) const col_iterator &operator++() const{ p+=STRIDE; return *this; } /// postfix increment operator col_iterator operator++(int){ col_iterator tmp = *this; ++(*this); return tmp; } /// postfix increment operator (const) const col_iterator operator++(int) const{ col_iterator tmp = *this; ++(*this); return tmp; } /// prefix decrement operator col_iterator &operator--(){ p-=STRIDE; return *this; } /// prefix decrement operator (const) const col_iterator &operator--() const{ p-=STRIDE; return *this; } /// postfix decrement operator col_iterator operator--(int){ col_iterator tmp = *this; --(*this); return tmp; } /// postfix decrement operator (const) const col_iterator operator--(int) const{ col_iterator tmp = *this; --(*this); return tmp; } /// jump next n elements (inplace) col_iterator &operator+=(difference_type n){ p += n * STRIDE; return *this; } /// jump next n elements (inplace) (const) const col_iterator &operator+=(difference_type n) const{ p += n * STRIDE; return *this; } /// jump backward next n elements (inplace) col_iterator &operator-=(difference_type n){ p -= n * STRIDE; return *this; } /// jump backward next n elements (inplace) (const) const col_iterator &operator-=(difference_type n) const{ p -= n * STRIDE; return *this; } /// jump next n elements col_iterator operator+(difference_type n) { col_iterator tmp = *this; tmp+=n; return tmp; } /// jump next n elements (const) const col_iterator operator+(difference_type n) const{ col_iterator tmp = *this; tmp+=n; return tmp; } /// jump backward next n elements col_iterator operator-(difference_type n) { col_iterator tmp = *this; tmp-=n; return tmp; } /// jump backward next n elements (const) const col_iterator operator-(difference_type n) const { col_iterator tmp = *this; tmp-=n; return tmp; } /// steps between two iterators ... (todo: check!) difference_type operator-(const col_iterator &i) const{ return (p-i.p)/STRIDE; } /// Dereference operator T &operator*(){ return *p; } /// const Dereference operator const T &operator*() const{ return *p; } /// comparison operator == bool operator==(const col_iterator &i) const{ return p == i.p; } /// comparison operator != bool operator!=(const col_iterator &i) const{ return p != i.p; } /// comparison operator < bool operator<(const col_iterator &i) const{ return p < i.p; } /// comparison operator <= bool operator<=(const col_iterator &i) const{ return p <= i.p; } /// comparison operator >= bool operator>=(const col_iterator &i) const{ return p >= i.p; } /// comparison operator > bool operator>(const col_iterator &i) const{ return p > i.p; } }; // const column operator typedef typedef const col_iterator const_col_iterator; /// returns an iterator to first element iterating over each element (row-major order) iterator begin() { return m_data; } /// returns an iterator after the last element iterator end() { return m_data+dim(); } /// returns an iterator to first element iterating over each element (row-major order) (const) const_iterator begin() const { return m_data; } /// returns an iterator after the last element (const) const_iterator end() const { return m_data+dim(); } /// returns an iterator iterating over a certain column col_iterator col_begin(unsigned int col) { return col_iterator(m_data+col); } /// row end iterator col_iterator col_end(unsigned int col) { return col_iterator(m_data+col+dim()); } /// returns an iterator iterating over a certain column (const) const_col_iterator col_begin(unsigned int col) const { return col_iterator(const_cast(m_data)+col); } /// row end iterator const const_col_iterator col_end(unsigned int col) const { return col_iterator(const_cast(m_data)+col+dim()); } /// returns an iterator iterating over a certain row row_iterator row_begin(unsigned int row) { return m_data+row*cols(); } /// row end iterator row_iterator row_end(unsigned int row) { return m_data+(row+1)*cols(); } /// returns an iterator iterating over a certain row (const) const_row_iterator row_begin(unsigned int row) const { return m_data+row*cols(); } /// row end iterator (const) const_row_iterator row_end(unsigned int row) const { return m_data+(row+1)*cols(); } /// inplace matrix multiplication (dst = (*this)*m) /** Inplace matrix multiplication for 4x4-float-matrices (using ipp-optimization) is approximately twice as fast as D=A*B operator based multiplication \section BM Benchmark 1.000.000 Multiplications of 4x4-float matrices (using ipp-optimization) on a 2GHz Core-2-Duo take about 145ms using inplace multiplication and about 290ms using not-inplace multiplication. @param m right matrix multiplication operand @dst destination of matrix multiplication @see operator*(const FixedMatrix&) */ template void mult(const FixedMatrix &m, FixedMatrix &dst) const{ for(unsigned int c=0;c __MCOLS__ | c | | c | COLS c | = right operand | c | |______c__| _COLS__ __________ | | | /\ | | | | | | = result ROWS | | | | |rrrrrr| |<-----x | x is inner product |______| |_________| */ template FixedMatrix operator*(const FixedMatrix &m) const{ FixedMatrix d; mult(m,d); return d; } /// invert the matrix (only implemented with IPP_OPTIMIZATION and only for icl32f and icl64f) /** This function internally uses an instance of DynMatrix */ FixedMatrix inv() const throw (InvalidMatrixDimensionException,SingularMatrixException){ DynMatrix m(COLS,ROWS,m_data,false); DynMatrix mi = m.inv(); m.set_data(0); FixedMatrix r; FixedMatrixBase::optimized_copy(mi.begin(),mi.end(),begin()); // std::copy(mi.begin(),mi.end(),r.begin()); return r; } /// calculate matrix determinant T det() const throw(InvalidMatrixDimensionException){ DynMatrix m(COLS,ROWS,m_data,false); return m.det(); } /// returns matrix's transposed FixedMatrix transp() const{ FixedMatrix d; for(unsigned int i=0;i::row_iterator,DIM>(col_begin(i),col_end(i),d.row_begin(i)); // std::copy(col_begin(i),col_end(i),d.row_begin(i)); } return d; } /// returns a matrix row-reference iterator pair FixedMatrixPart row(unsigned int idx){ return FixedMatrixPart(row_begin(idx),row_end(idx)); } /// returns a matrix row-reference iterator pair (const) FixedMatrixPart row(unsigned int idx) const{ return FixedMatrixPart(row_begin(idx),row_end(idx)); } /// returns a matrix col-reference iterator pair FixedMatrixPart col(unsigned int idx){ return FixedMatrixPart(col_begin(idx),col_end(idx)); } /// returns a matrix col-reference iterator pair (const) FixedMatrixPart col(unsigned int idx) const{ return FixedMatrixPart(col_begin(idx),col_end(idx)); } /// create identity matrix /** if matrix is not a spare one, upper left square matrix is initialized with the fitting identity matrix and other elements are initialized with 0 */ static FixedMatrix id(){ FixedMatrix m(T(0)); for(unsigned int i=0;i bool operator==(const FixedMatrix &m) const{ for(unsigned int i=0;i bool operator!=(const FixedMatrix &m) const{ return !this->operator==(m); } }; /// Matrix multiplication (inplace) /** inplace matrix multiplication does only work for squared source and destination matrices of identical size */ template inline FixedMatrix &operator*=(FixedMatrix &v, const FixedMatrix &m){ return v = (m*v); } /** \cond */ template inline std::ostream &fixed_matrix_aux_to_stream(std::ostream &s,const T &t){ return s << t; } template<> inline std::ostream &fixed_matrix_aux_to_stream(std::ostream &s,const unsigned char &t){ return s << (int)t; } /** \endcond */ /// put the matrix into a std::ostream (human readable) template inline std::ostream &operator<<(std::ostream &s,const FixedMatrix &m){ for(unsigned int i=0;i(s,m(j,i)) << " "; //s << m(j,i) << " "; } s << "|" << std::endl; } return s; } /// creates a 2D rotation matrix (defined for float and double) template FixedMatrix create_rot_2D(T angle); /// creates a 2D homogen matrix (defined for float and double) template FixedMatrix create_hom_3x3(T angle, T dx=0, T dy=0, T v0=0, T v1=0); /// creates a 2D homogen matrix with translation part only (defined for float and double) template inline FixedMatrix create_hom_3x3_trans(T dx, T dy){ FixedMatrix m = FixedMatrix::id(); m(2,0)=dx; m(2,1)=dy; return m; } /// creates a 3D rotation matrix (defined for float and double) template FixedMatrix create_rot_3D(T rx,T ry,T rz); /// creates a 3D homogen matrix (defined for float and double) template FixedMatrix create_hom_4x4(T rx, T ry, T rz, T dx=0, T dy=0, T dz=0, T v0=0, T v1=0, T v2=0); /// creates a 3D homogen matrix with translation part only (defined for float and double) template inline FixedMatrix create_hom_4x4_trans(T dx, T dy, T dz){ FixedMatrix m = FixedMatrix::id(); m(3,0)=dx; m(3,1)=dy; m(3,2)=dy; return m; } /// calculate the trace of a square matrix template FixedMatrix trace(const FixedMatrix &m){ FixedMatrix t; for(unsigned int i=0;i template inline FixedMatrixPart& FixedMatrixPart::operator=(const FixedMatrix &m){ FixedMatrixBase::optimized_copy(m.begin(),m.end(),begin); //std::copy(m.begin(),m.end(),begin); return *this; } template template inline FixedMatrixPart& FixedMatrixPart::operator=(const FixedMatrix &m){ std::transform(m.begin(),m.end(),begin,clipped_cast); return *this; } /** \endcond */ #ifdef WITH_IPP_OPTIMIZATION #define OPTIMIZED_MATRIX_MULTIPLICATION(LEFT_COLS,LEFT_ROWS,RIGHT_COLS,TYPE,IPPSUFFIX) \ template<> template<> \ inline void \ FixedMatrix::mult \ ( \ const FixedMatrix &m, \ FixedMatrix &dst \ ) const { \ static const unsigned int ST=sizeof(TYPE); \ ippmMul_mm_##IPPSUFFIX(data(),LEFT_COLS*ST,ST,LEFT_COLS,LEFT_ROWS, \ m.data(),RIGHT_COLS*ST,ST,RIGHT_COLS,LEFT_COLS, \ dst.data(),RIGHT_COLS*ST,ST); \ } OPTIMIZED_MATRIX_MULTIPLICATION(2,2,2,float,32f); OPTIMIZED_MATRIX_MULTIPLICATION(3,3,3,float,32f); OPTIMIZED_MATRIX_MULTIPLICATION(4,4,4,float,32f); OPTIMIZED_MATRIX_MULTIPLICATION(2,2,2,double,64f); OPTIMIZED_MATRIX_MULTIPLICATION(3,3,3,double,64f); OPTIMIZED_MATRIX_MULTIPLICATION(4,4,4,double,64f); #undef OPTIMIZED_MATRIX_MULTIPLICATION #endif } #endif