// @(#)root/smatrix:$Id: MatrixFunctions.h 22920 2008-04-01 10:01:06Z moneta $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_MatrixFunctions #define ROOT_Math_MatrixFunctions // ******************************************************************** // // source: // // type: source code // // created: 20. Mar 2001 // // author: Thorsten Glebe // HERA-B Collaboration // Max-Planck-Institut fuer Kernphysik // Saupfercheckweg 1 // 69117 Heidelberg // Germany // E-mail: T.Glebe@mpi-hd.mpg.de // // Description: Functions/Operators special to Matrix // // changes: // 20 Mar 2001 (TG) creation // 20 Mar 2001 (TG) Added Matrix * Vector multiplication // 21 Mar 2001 (TG) Added transpose, product // 11 Apr 2001 (TG) transpose() speed improvment by removing rows(), cols() // through static members of Matrix and Expr class // // ******************************************************************** //doxygen tag /** @defgroup MatrixFunctions Matrix Template Functions @ingroup SMatrixGroup These function apply to matrices (and also Matrix expression) and can return a matrix expression of a particular defined type, like in the matrix multiplication or a vector, like in the matrix-vector product or a scalar like in the Similarity vector-matrix product. */ #ifndef ROOT_Math_BinaryOpPolicy #include "Math/BinaryOpPolicy.h" #endif namespace ROOT { namespace Math { #ifdef XXX //============================================================================== // SMatrix * SVector //============================================================================== template SVector operator*(const SMatrix& rhs, const SVector& lhs) { SVector tmp; for(unsigned int i=0; i struct meta_row_dot { template static inline typename A::value_type f(const A& lhs, const B& rhs, const unsigned int offset) { return lhs.apply(offset+I) * rhs.apply(I) + meta_row_dot::f(lhs,rhs,offset); } }; //============================================================================== // meta_row_dot<0> //============================================================================== template <> struct meta_row_dot<0> { template static inline typename A::value_type f(const A& lhs, const B& rhs, const unsigned int offset) { return lhs.apply(offset) * rhs.apply(0); } }; //============================================================================== // VectorMatrixRowOp //============================================================================== template class VectorMatrixRowOp { public: /// VectorMatrixRowOp(const Matrix& lhs, const Vector& rhs) : lhs_(lhs), rhs_(rhs) {} /// ~VectorMatrixRowOp() {} /// calc \f$ \sum_{j} a_{ij} * v_j \f$ inline typename Matrix::value_type apply(unsigned int i) const { return meta_row_dot::f(lhs_, rhs_, i*D2); } protected: const Matrix& lhs_; const Vector& rhs_; }; //============================================================================== // meta_col_dot //============================================================================== template struct meta_col_dot { template static inline typename Matrix::value_type f(const Matrix& lhs, const Vector& rhs, const unsigned int offset) { return lhs.apply(Matrix::kCols*I+offset) * rhs.apply(I) + meta_col_dot::f(lhs,rhs,offset); } }; //============================================================================== // meta_col_dot<0> //============================================================================== template <> struct meta_col_dot<0> { template static inline typename Matrix::value_type f(const Matrix& lhs, const Vector& rhs, const unsigned int offset) { return lhs.apply(offset) * rhs.apply(0); } }; //============================================================================== // VectorMatrixColOp //============================================================================== /** Class for Vector-Matrix multiplication @ingroup Expression */ template class VectorMatrixColOp { public: /// VectorMatrixColOp(const Vector& lhs, const Matrix& rhs) : lhs_(lhs), rhs_(rhs) {} /// ~VectorMatrixColOp() {} /// calc \f$ \sum_{j} a_{ij} * v_j \f$ inline typename Matrix::value_type apply(unsigned int i) const { return meta_col_dot::f(rhs_, lhs_, i); } protected: const Vector& lhs_; const Matrix& rhs_; }; /** Matrix * Vector multiplication \f$ a(i) = \sum_{j} M(i,j) * b(j) \f$ returning a vector expression @ingroup MatrixFunctions */ //============================================================================== // operator*: SMatrix * SVector //============================================================================== template inline VecExpr,SVector, D2>, T, D1> operator*(const SMatrix& lhs, const SVector& rhs) { typedef VectorMatrixRowOp,SVector, D2> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: SMatrix * Expr //============================================================================== template inline VecExpr, VecExpr, D2>, T, D1> operator*(const SMatrix& lhs, const VecExpr& rhs) { typedef VectorMatrixRowOp,VecExpr, D2> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: Expr * SVector //============================================================================== template inline VecExpr, SVector, D2>, T, D1> operator*(const Expr& lhs, const SVector& rhs) { typedef VectorMatrixRowOp,SVector, D2> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: Expr * VecExpr //============================================================================== template inline VecExpr, VecExpr, D2>, T, D1> operator*(const Expr& lhs, const VecExpr& rhs) { typedef VectorMatrixRowOp,VecExpr, D2> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: SVector * SMatrix //============================================================================== template inline VecExpr, SMatrix, D1>, T, D2> operator*(const SVector& lhs, const SMatrix& rhs) { typedef VectorMatrixColOp, SMatrix, D1> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: SVector * Expr //============================================================================== template inline VecExpr, Expr, D1>, T, D2> operator*(const SVector& lhs, const Expr& rhs) { typedef VectorMatrixColOp, Expr, D1> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: VecExpr * SMatrix //============================================================================== template inline VecExpr, SMatrix, D1>, T, D2> operator*(const VecExpr& lhs, const SMatrix& rhs) { typedef VectorMatrixColOp, SMatrix, D1> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // operator*: VecExpr * Expr //============================================================================== template inline VecExpr, Expr, D1>, T, D2> operator*(const VecExpr& lhs, const Expr& rhs) { typedef VectorMatrixColOp, Expr, D1> VMOp; return VecExpr(VMOp(lhs,rhs)); } //============================================================================== // meta_matrix_dot //============================================================================== template struct meta_matrix_dot { template static inline typename MatrixA::value_type f(const MatrixA& lhs, const MatrixB& rhs, const unsigned int offset) { return lhs.apply(offset/MatrixB::kCols*MatrixA::kCols + I) * rhs.apply(MatrixB::kCols*I + offset%MatrixB::kCols) + meta_matrix_dot::f(lhs,rhs,offset); } // multiplication using i and j indeces template static inline typename MatrixA::value_type g(const MatrixA& lhs, const MatrixB& rhs, unsigned int i, unsigned int j) { return lhs(i, I) * rhs(I , j) + meta_matrix_dot::g(lhs,rhs,i,j); } }; //============================================================================== // meta_matrix_dot<0> //============================================================================== template <> struct meta_matrix_dot<0> { template static inline typename MatrixA::value_type f(const MatrixA& lhs, const MatrixB& rhs, const unsigned int offset) { return lhs.apply(offset/MatrixB::kCols*MatrixA::kCols) * rhs.apply(offset%MatrixB::kCols); } // multiplication using i and j template static inline typename MatrixA::value_type g(const MatrixA& lhs, const MatrixB& rhs, unsigned int i, unsigned int j) { return lhs(i,0) * rhs(0,j); } }; //============================================================================== // MatrixMulOp //============================================================================== /** Class for Matrix-Matrix multiplication @ingroup Expression */ template class MatrixMulOp { public: /// MatrixMulOp(const MatrixA& lhs, const MatrixB& rhs) : lhs_(lhs), rhs_(rhs) {} /// ~MatrixMulOp() {} /// calc \f$\sum_{j} a_{ik} * b_{kj}\f$ inline T apply(unsigned int i) const { return meta_matrix_dot::f(lhs_, rhs_, i); } inline T operator() (unsigned int i, unsigned j) const { return meta_matrix_dot::g(lhs_, rhs_, i, j); } inline bool IsInUse (const T * p) const { return lhs_.IsInUse(p) || rhs_.IsInUse(p); } protected: const MatrixA& lhs_; const MatrixB& rhs_; }; /** Matrix * Matrix multiplication , \f$ C(i,j) = \sum_{k} A(i,k) * B(k,j)\f$ returning a matrix expression @ingroup MatrixFunctions */ //============================================================================== // operator* (SMatrix * SMatrix, binary) //============================================================================== template < class T, unsigned int D1, unsigned int D, unsigned int D2, class R1, class R2> inline Expr, SMatrix,T,D>, T, D1, D2, typename MultPolicy::RepType> operator*(const SMatrix& lhs, const SMatrix& rhs) { typedef MatrixMulOp, SMatrix, T,D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } //============================================================================== // operator* (SMatrix * Expr, binary) //============================================================================== template inline Expr, Expr,T,D>, T, D1, D2, typename MultPolicy::RepType> operator*(const SMatrix& lhs, const Expr& rhs) { typedef MatrixMulOp, Expr,T,D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } //============================================================================== // operator* (Expr * SMatrix, binary) //============================================================================== template inline Expr, SMatrix,T,D>, T, D1, D2, typename MultPolicy::RepType> operator*(const Expr& lhs, const SMatrix& rhs) { typedef MatrixMulOp, SMatrix,T,D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } //============================================================================== // operator* (Expr * Expr, binary) //============================================================================== template inline Expr, Expr,T,D>, T, D1, D2, typename MultPolicy::RepType> operator*(const Expr& lhs, const Expr& rhs) { typedef MatrixMulOp, Expr, T,D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } #ifdef XXX //============================================================================== // MatrixMulOp //============================================================================== template class MatrixMulOp { public: /// MatrixMulOp(const MatrixA& lhs, const MatrixB& rhs) : lhs_(lhs), rhs_(rhs) {} /// ~MatrixMulOp() {} /// calc $\sum_{j} a_{ik} * b_{kj}$ inline typename MatrixA::value_type apply(unsigned int i) const { return meta_matrix_dot::f(lhs_, rhs_, i); } protected: const MatrixA& lhs_; const MatrixB& rhs_; }; //============================================================================== // operator* (SMatrix * SMatrix, binary) //============================================================================== template < class T, unsigned int D1, unsigned int D, unsigned int D2, class R1, class R2> inline Expr, SMatrix, D>, T, D1, D2, typename MultPolicy::RepType> operator*(const SMatrix& lhs, const SMatrix& rhs) { typedef MatrixMulOp, SMatrix, D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } //============================================================================== // operator* (SMatrix * Expr, binary) //============================================================================== template inline Expr, Expr, D>, T, D1, D2, typename MultPolicy::RepType> operator*(const SMatrix& lhs, const Expr& rhs) { typedef MatrixMulOp, Expr, D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } //============================================================================== // operator* (Expr * SMatrix, binary) //============================================================================== template inline Expr, SMatrix, D>, T, D1, D2, typename MultPolicy::RepType> operator*(const Expr& lhs, const SMatrix& rhs) { typedef MatrixMulOp, SMatrix, D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } //============================================================================= // operator* (Expr * Expr, binary) //============================================================================= template inline Expr, Expr, D>, T, D1, D2, typename MultPolicy::RepType> operator*(const Expr& lhs, const Expr& rhs) { typedef MatrixMulOp, Expr, D> MatMulOp; return Expr::RepType>(MatMulOp(lhs,rhs)); } #endif //============================================================================== // TransposeOp //============================================================================== /** Class for Transpose Operations @ingroup Expression */ template class TransposeOp { public: /// TransposeOp( const Matrix& rhs) : rhs_(rhs) {} /// ~TransposeOp() {} /// inline T apply(unsigned int i) const { return rhs_.apply( (i%D1)*D2 + i/D1); } inline T operator() (unsigned int i, unsigned j) const { return rhs_( j, i); } inline bool IsInUse (const T * p) const { return rhs_.IsInUse(p); } protected: const Matrix& rhs_; }; /** Matrix Transpose B(i,j) = A(j,i) returning a matrix expression @ingroup MatrixFunctions */ //============================================================================== // transpose //============================================================================== template inline Expr,T,D1,D2>, T, D2, D1, typename TranspPolicy::RepType> Transpose(const SMatrix& rhs) { typedef TransposeOp,T,D1,D2> MatTrOp; return Expr::RepType>(MatTrOp(rhs)); } //============================================================================== // transpose //============================================================================== template inline Expr,T,D1,D2>, T, D2, D1, typename TranspPolicy::RepType> Transpose(const Expr& rhs) { typedef TransposeOp,T,D1,D2> MatTrOp; return Expr::RepType>(MatTrOp(rhs)); } #ifdef ENABLE_TEMPORARIES_TRANSPOSE // sometimes is faster to create a temp, not clear why //============================================================================== // transpose //============================================================================== template inline SMatrix< T, D2, D1, typename TranspPolicy::RepType> Transpose(const SMatrix& rhs) { typedef TransposeOp,T,D1,D2> MatTrOp; return SMatrix< T, D2, D1, typename TranspPolicy::RepType> ( Expr::RepType>(MatTrOp(rhs)) ); } //============================================================================== // transpose //============================================================================== template inline SMatrix< T, D2, D1, typename TranspPolicy::RepType> Transpose(const Expr& rhs) { typedef TransposeOp,T,D1,D2> MatTrOp; return SMatrix< T, D2, D1, typename TranspPolicy::RepType> ( Expr::RepType>(MatTrOp(rhs)) ); } #endif #ifdef OLD //============================================================================== // product: SMatrix/SVector calculate v^T * A * v //============================================================================== template inline T Product(const SMatrix& lhs, const SVector& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: SVector/SMatrix calculate v^T * A * v //============================================================================== template inline T Product(const SVector& lhs, const SMatrix& rhs) { return Dot(lhs, rhs * lhs); } //============================================================================== // product: SMatrix/Expr calculate v^T * A * v //============================================================================== template inline T Product(const SMatrix& lhs, const VecExpr& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: Expr/SMatrix calculate v^T * A * v //============================================================================== template inline T Product(const VecExpr& lhs, const SMatrix& rhs) { return Dot(lhs, rhs * lhs); } //============================================================================== // product: SVector/Expr calculate v^T * A * v //============================================================================== template inline T Product(const SVector& lhs, const Expr& rhs) { return Dot(lhs, rhs * lhs); } //============================================================================== // product: Expr/SVector calculate v^T * A * v //============================================================================== template inline T Product(const Expr& lhs, const SVector& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: Expr/Expr calculate v^T * A * v //============================================================================== template inline T Product(const Expr& lhs, const VecExpr& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: Expr/Expr calculate v^T * A * v //============================================================================== template inline T Product(const VecExpr& lhs, const Expr& rhs) { return Dot(lhs, rhs * lhs); } #endif /** Similarity Vector - Matrix Product: v^T * A * v returning a scalar value of type T \f$ s = \sum_{i,j} v(i) * A(i,j) * v(j)\f$ @ingroup MatrixFunctions */ //============================================================================== // product: SMatrix/SVector calculate v^T * A * v //============================================================================== template inline T Similarity(const SMatrix& lhs, const SVector& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: SVector/SMatrix calculate v^T * A * v //============================================================================== template inline T Similarity(const SVector& lhs, const SMatrix& rhs) { return Dot(lhs, rhs * lhs); } //============================================================================== // product: SMatrix/Expr calculate v^T * A * v //============================================================================== template inline T Similarity(const SMatrix& lhs, const VecExpr& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: Expr/SMatrix calculate v^T * A * v //============================================================================== template inline T Similarity(const VecExpr& lhs, const SMatrix& rhs) { return Dot(lhs, rhs * lhs); } //============================================================================== // product: SVector/Expr calculate v^T * A * v //============================================================================== template inline T Similarity(const SVector& lhs, const Expr& rhs) { return Dot(lhs, rhs * lhs); } //============================================================================== // product: Expr/SVector calculate v^T * A * v //============================================================================== template inline T Similarity(const Expr& lhs, const SVector& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: Expr/Expr calculate v^T * A * v //============================================================================== template inline T Similarity(const Expr& lhs, const VecExpr& rhs) { return Dot(rhs, lhs * rhs); } //============================================================================== // product: Expr/Expr calculate v^T * A * v //============================================================================== template inline T Similarity(const VecExpr& lhs, const Expr& rhs) { return Dot(lhs, rhs * lhs); } /** Similarity Matrix Product : B = U * A * U^T for A symmetric returning a symmetric matrix expression: \f$ B(i,j) = \sum_{k,l} U(i,k) * A(k,l) * U(j,l) \f$ @ingroup MatrixFunctions */ //============================================================================== // product: SMatrix/SMatrix calculate M * A * M^T where A is a symmetric matrix // return matrix will be nrows M x nrows M //============================================================================== template inline SMatrix > Similarity(const SMatrix& lhs, const SMatrix >& rhs) { SMatrix > tmp = lhs * rhs; typedef SMatrix > SMatrixSym; SMatrixSym mret; AssignSym::Evaluate(mret, tmp * Transpose(lhs) ); return mret; } //============================================================================== // product: SMatrix/SMatrix calculate M * A * M^T where A is a symmetric matrix // return matrix will be nrowsM x nrows M // M is a matrix expression //============================================================================== template inline SMatrix > Similarity(const Expr& lhs, const SMatrix >& rhs) { SMatrix > tmp = lhs * rhs; typedef SMatrix > SMatrixSym; SMatrixSym mret; AssignSym::Evaluate(mret, tmp * Transpose(lhs) ); return mret; } #ifdef XXX // not needed ( //============================================================================== // product: SMatrix/SMatrix calculate M * A * M where A and M are symmetric matrices // return matrix will be nrows M x nrows M //============================================================================== template inline SMatrix > Similarity(const SMatrix >& lhs, const SMatrix >& rhs) { SMatrix > tmp = lhs * rhs; typedef SMatrix > SMatrixSym; SMatrixSym mret; AssignSym::Evaluate(mret, tmp * lhs ); return mret; } #endif /** Transpose Similarity Matrix Product : B = U^T * A * U for A symmetric returning a symmetric matrix expression: \f$ B(i,j) = \sum_{k,l} U(k,i) * A(k,l) * U(l,j) \f$ @ingroup MatrixFunctions */ //============================================================================== // product: SMatrix/SMatrix calculate M^T * A * M where A is a symmetric matrix // return matrix will be ncolsM x ncols M //============================================================================== template inline SMatrix > SimilarityT(const SMatrix& lhs, const SMatrix >& rhs) { SMatrix > tmp = rhs * lhs; typedef SMatrix > SMatrixSym; SMatrixSym mret; AssignSym::Evaluate(mret, Transpose(lhs) * tmp ); return mret; } //============================================================================== // product: SMatrix/SMatrix calculate M^T * A * M where A is a symmetric matrix // return matrix will be ncolsM x ncols M // M is a matrix expression //============================================================================== template inline SMatrix > SimilarityT(const Expr& lhs, const SMatrix >& rhs) { SMatrix > tmp = rhs * lhs; typedef SMatrix > SMatrixSym; SMatrixSym mret; AssignSym::Evaluate(mret, Transpose(lhs) * tmp ); return mret; } // //============================================================================== // // Mult * (Expr * Expr, binary) with a symmetric result // // the operation is done only for half // //============================================================================== // template // inline Expr >, Expr,T,D>, T, D1, D2, typename MultPolicy::RepType> // operator*(const Expr& lhs, const Expr& rhs) { // typedef MatrixMulOp, Expr, T,D> MatMulOp; // return Expr::RepType>(MatMulOp(lhs,rhs)); // } //============================================================================== // TensorMulOp //============================================================================== /** Class for Tensor Multiplication (outer product) of two vectors giving a matrix @ingroup Expression */ template class TensorMulOp { public: /// TensorMulOp( const Vector1 & lhs, const Vector2 & rhs) : lhs_(lhs), rhs_(rhs) {} /// ~TensorMulOp() {} /// Vector2::kSize is the number of columns in the resulting matrix inline typename Vector1::value_type apply(unsigned int i) const { return lhs_.apply( i/ Vector2::kSize) * rhs_.apply( i % Vector2::kSize ); } inline typename Vector1::value_type operator() (unsigned int i, unsigned j) const { return lhs_.apply(i) * rhs_.apply(j); } inline bool IsInUse (const typename Vector1::value_type * ) const { return false; } protected: const Vector1 & lhs_; const Vector2 & rhs_; }; /** Tensor Vector Product : M(i,j) = v(i) * v(j) returning a matrix expression @ingroup VectFunction */ #ifndef _WIN32 // Tensor Prod (use default MatRepStd for the returned expression // cannot make a symmetric matrix //============================================================================== // TensorProd (SVector x SVector) //============================================================================== template inline Expr, SVector >, T, D1, D2 > TensorProd(const SVector& lhs, const SVector& rhs) { typedef TensorMulOp, SVector > TVMulOp; return Expr(TVMulOp(lhs,rhs)); } //============================================================================== // TensorProd (VecExpr x SVector) //============================================================================== template inline Expr, SVector >, T, D1, D2 > TensorProd(const VecExpr& lhs, const SVector& rhs) { typedef TensorMulOp, SVector > TVMulOp; return Expr(TVMulOp(lhs,rhs)); } //============================================================================== // TensorProd (SVector x VecExpr) //============================================================================== template inline Expr, VecExpr >, T, D1, D2 > TensorProd(const SVector& lhs, const VecExpr& rhs) { typedef TensorMulOp, VecExpr > TVMulOp; return Expr(TVMulOp(lhs,rhs)); } //============================================================================== // TensorProd (VecExpr x VecExpr) //============================================================================== template inline Expr, VecExpr >, T, D1, D2 > TensorProd(const VecExpr& lhs, const VecExpr& rhs) { typedef TensorMulOp, VecExpr > TVMulOp; return Expr(TVMulOp(lhs,rhs)); } #endif #ifdef _WIN32 /// case of WINDOWS - problem using Expression ( C1001: INTERNAL COMPILER ERROR ) //============================================================================== // TensorProd (SVector x SVector) //============================================================================== template inline SMatrix TensorProd(const SVector& lhs, const SVector& rhs) { SMatrix tmp; for (unsigned int i=0; i< D1; ++i) for (unsigned int j=0; j< D2; ++j) { tmp(i,j) = lhs[i]*rhs[j]; } return tmp; } //============================================================================== // TensorProd (VecExpr x SVector) //============================================================================== template inline SMatrix TensorProd(const VecExpr& lhs, const SVector& rhs) { SMatrix tmp; for (unsigned int i=0; i< D1; ++i) for (unsigned int j=0; j< D2; ++j) tmp(i,j) = lhs.apply(i) * rhs.apply(j); return tmp; } //============================================================================== // TensorProd (SVector x VecExpr) //============================================================================== template inline SMatrix TensorProd(const SVector& lhs, const VecExpr& rhs) { SMatrix tmp; for (unsigned int i=0; i< D1; ++i) for (unsigned int j=0; j< D2; ++j) tmp(i,j) = lhs.apply(i) * rhs.apply(j); return tmp; } //============================================================================== // TensorProd (VecExpr x VecExpr) //============================================================================== template inline SMatrix TensorProd(const VecExpr& lhs, const VecExpr& rhs) { SMatrix tmp; for (unsigned int i=0; i< D1; ++i) for (unsigned int j=0; j< D2; ++j) tmp(i,j) = lhs.apply(i) * rhs.apply(j); return tmp; } #endif } // namespace Math } // namespace ROOT #endif /* ROOT_Math_MatrixFunctions */