#include #include // setw #ifndef _tvmet_restrict #define _tvmet_restrict __restrict__ #endif namespace tvmet { /* forwards */ template class Matrix; /** * short type promotion */ template struct PromoteTraits { }; template<> struct PromoteTraits { typedef double value_type; }; /** * \class XprNull Null.h "tvmet/xpr/Null.h" * \brief Null object design pattern */ class XprNull { XprNull& operator=(const XprNull&); public: explicit XprNull() { } }; #define TVMET_BINARY_OPERATOR(OP) \ template< class T > \ inline \ T operator OP (const T& lhs, XprNull) { return lhs; } TVMET_BINARY_OPERATOR(+) TVMET_BINARY_OPERATOR(*) #undef TVMET_BINARY_OPERATOR namespace meta { /** * \class Matrix Matrix.h "tvmet/meta/Matrix.h" * \brief Meta %Matrix class using expression templates */ template class Matrix { Matrix(); Matrix(const Matrix&); Matrix& operator=(const Matrix&); private: enum { doRows = (RowStride < Rows - 1) ? 1 : 0, /**< recursive counter Rows. */ doCols = (ColStride < Cols - 1) ? 1 : 0 /**< recursive counter Cols. */ }; public: /** Assign an expression expr on columns on given row using the functional fn. */ template static inline void assign2(Mtrx& mat, const E& expr, const Fcnl& fn) { fn.applyOn(mat(RowStride, ColStride), expr(RowStride, ColStride)); Matrix::assign2(mat, expr, fn); } /** Assign an expression expr on row-wise using the functional fn. */ template static inline void assign(Mtrx& mat, const E& expr, const Fcnl& fn) { Matrix::assign2(mat, expr, fn); Matrix::assign(mat, expr, fn); } }; /** * \class Matrix<0, 0, 0, 0> Matrix.h "tvmet/meta/Matrix.h" * \brief Meta %Matrix specialized for recursion */ template<> class Matrix<0, 0, 0, 0> { Matrix(); Matrix(const Matrix&); Matrix& operator=(const Matrix&); public: template static inline void assign2(Mtrx&, const E&, const Fcnl&) { } template static inline void assign(Mtrx&, const E&, const Fcnl&) { } }; /** * \class gemm Gemm.h "tvmet/meta/Gemm.h" * \brief Meta class for matrix-matrix operations, like product. * \note The rows of matrix 2 have to be equal to cols of matrix 1, square * matrix is mandatory. */ template class gemm { gemm(); gemm(const gemm&); gemm& operator=(const gemm&); private: enum { doIt = (K != Cols1 - 1) /**< recursive counter */ }; public: template static inline typename PromoteTraits::value_type prod(const T1* _tvmet_restrict lhs, const T2* _tvmet_restrict rhs, std::size_t i, std::size_t j) { return lhs[i * RowStride1 + K * ColStride1] * rhs[K * RowStride2 + j * ColStride2] + gemm::prod(lhs, rhs, i, j); } }; /** * \class gemm<0,0,0,0,0,0,0,0> Gemm.h "tvmet/meta/Gemm.h" * \brief gemm Specialized for recursion. */ template<> class gemm<0,0,0,0,0,0,0,0> { gemm(); gemm(const gemm&); gemm& operator=(const gemm&); public: static inline XprNull prod(const void*, const void*, std::size_t, std::size_t) { return XprNull(); } }; } // namespace meta /** * \class fcnl_Assign BinaryFunctionals.h "tvmet/BinaryFunctionals.h" * \brief Binary operator for assign operations. */ template struct fcnl_Assign { typedef void return_type; static inline return_type applyOn(T1& _tvmet_restrict lhs, T2 rhs) { lhs = static_cast(rhs); } }; /** * \class XprMMProduct MMProduct.h "tvmet/xpr/MMProduct.h" * \brief Expression for matrix-matrix product. * \note The Rows2 has to be equal to Cols1. */ template class XprMMProduct { private: XprMMProduct(); XprMMProduct& operator=(const XprMMProduct&); public: typedef typename PromoteTraits::value_type value_type; public: /** Constructor. */ explicit XprMMProduct(const T1* _tvmet_restrict lhs, const T2* _tvmet_restrict rhs) : m_lhs(lhs), m_rhs(rhs) { } /** index operator for arrays/matrices */ value_type operator()(std::size_t i, std::size_t j) const { return meta::gemm::prod(m_lhs, m_rhs, i, j); } private: const T1* _tvmet_restrict m_lhs; const T2* _tvmet_restrict m_rhs; }; /** * \class XprMatrixTranspose MatrixTranspose.h "tvmet/xpr/MatrixTranspose.h" * \brief Expression for transpose matrix */ template class XprMatrixTranspose { XprMatrixTranspose(); XprMatrixTranspose& operator=(const XprMatrixTranspose&); public: typedef E expr_type; typedef typename expr_type::value_type value_type; public: /** Constructor. */ explicit XprMatrixTranspose(const expr_type& e) : m_expr(e) { } /** index operator for arrays/matrices. This simple swap the index access for transpose. */ value_type operator()(std::size_t i, std::size_t j) const { return m_expr(j, i); } private: const expr_type& _tvmet_restrict m_expr; }; /** * \class XprMatrix Matrix.h "tvmet/xpr/Matrix.h" * \brief Represents the expression for vectors at any node in the parse tree. */ template class XprMatrix { XprMatrix(); XprMatrix& operator=(const XprMatrix&); public: typedef E expr_type; typedef typename expr_type::value_type value_type; public: /** Constructor. */ explicit XprMatrix(const expr_type& e) : m_expr(e) { } /** index operator for arrays/matrizes */ value_type operator()(std::size_t i, std::size_t j) const { return m_expr(i, j); } private: const expr_type& _tvmet_restrict m_expr; }; /** * \class MatrixConstReference Matrix.h "tvmet/Matrix.h" * \brief value iterator for ET */ template class MatrixConstReference { public: // types typedef T value_type; private: MatrixConstReference(); MatrixConstReference& operator=(const MatrixConstReference&); public: /** Constructor. */ explicit MatrixConstReference(const Matrix& rhs) : m_data(rhs.data()) { } public: // access operators /** access by index. */ value_type operator()(std::size_t i, std::size_t j) const { return m_data[i * RowStride + j * ColStride]; } private: const value_type* _tvmet_restrict m_data; }; /** * \class Matrix Matrix.h "tvmet/Matrix.h" * \brief A tiny matrix class. */ template class Matrix { public: /** Data type of the tvmet::Matrix. */ typedef T value_type; /** This type of tvmet::Matrix, used to simplify member wrote. */ typedef Matrix this_type; public: /** Default Constructor. The allocated memory region isn't cleared. If you want a clean use the constructor argument zero. */ explicit Matrix() { } /** Construct a matrix by expression. */ template explicit Matrix(const XprMatrix& expr) { assign(expr, fcnl_Assign()); } public: // access operators value_type* _tvmet_restrict data() { return m_data; } const value_type* _tvmet_restrict data() const { return m_data; } public: // index access operators value_type& _tvmet_restrict operator()(std::size_t i, std::size_t j) { return m_data[i * Cols + j]; } value_type operator()(std::size_t i, std::size_t j) const { return m_data[i * Cols + j]; } public: // ET interface typedef MatrixConstReference ConstReference; /** Return a const Reference of the internal data */ ConstReference const_ref() const { return ConstReference(*this); } private: // assign operations /** Assign an expression to this matrix using the functional fn. */ template void assign(const E& expr, const Fcnl& fn) { meta::Matrix::assign(*this, expr, fn); } public: // assign operations /** Assign a given XprMatrix element wise to this matrix. */ template this_type& operator=(const XprMatrix& rhs) { this->assign(rhs, fcnl_Assign()); return *this; } public: // io std::ostream& print_on(std::ostream& os) const; private: value_type m_data[Rows * Cols]; }; /* * member function implementation for i/o */ template inline std::ostream& Matrix::print_on(std::ostream& os) const { std::streamsize w = os.width(); os << std::setw(0) << "Matrix<" << typeid(T).name() << ", " << Rows << ", " << Cols << "> = [\n"; for(std::size_t i = 0; i < Rows; ++i) { os << " ["; for(std::size_t j = 0; j < (Cols - 1); ++j) { os << std::setw(w) << this->operator()(i, j) << ", "; } os << std::setw(w) << this->operator()(i, Cols - 1) << (i != (Rows-1) ? "],\n" : "]\n"); } os << "]"; return os; } /** * \fn operator<<(std::ostream& os, const Matrix& rhs) * \brief Overload operator for i/o */ template inline std::ostream& operator<<(std::ostream& os, const Matrix& rhs) { return rhs.print_on(os); } /** * \fn prod(const XprMatrix& lhs, const Matrix& rhs) * \brief Evaluate the product of XprMatrix and Matrix. * \note This function is using temporaries for pre-evaluation of the matrix1 * expression. */ template inline XprMatrix< XprMMProduct< typename E1::value_type, Rows1, Cols1, T2, Cols2, Cols1, 1, Cols2, 1 >, Rows1, Cols2 > prod(const XprMatrix& lhs, const Matrix& rhs) { typedef Matrix temp_matrix_type; typedef XprMMProduct< typename E1::value_type, Rows1, Cols1, T2, Cols2, Cols1, 1, Cols2, 1 > expr_type; #if defined(TVMET_RVO_BUG_WO) temp_matrix_type temp_lhs(lhs); return XprMatrix(expr_type(temp_lhs.data(), rhs.data())); #else return XprMatrix(expr_type(temp_matrix_type(lhs).data(), rhs.data())); #endif } /** * \fn trans(const Matrix& rhs) * \brief Transpose the matrix */ template inline XprMatrix< XprMatrixTranspose< MatrixConstReference >, Cols, Rows > trans(const Matrix& rhs) { typedef XprMatrixTranspose< MatrixConstReference > expr_type; return XprMatrix(expr_type(rhs.const_ref())); } } // namespace tvmet /** * Test driver */ using namespace std; int main() { tvmet::Matrix B; tvmet::Matrix D; tvmet::Matrix K; B(0,0) = -0.05; B(0,1) = 0; B(1,0) = 0; B(1,1) = 0.05; B(2,0) = 0.05; B(2,1) = -0.05; D(0,0) = 2000; D(0,1) = 1000; D(0,2) = 0; D(1,0) = 1000; D(1,1) = 2000; D(1,2) = 0; D(2,0) = 0; D(2,1) = 0; D(2,2) = 500; cout << "B = " << B << endl; cout << "D = " << D << endl; K = prod(prod(trans(B), D), B); cout << "K = " << K << endl; }