#ifndef __BOOST_UBLAS__ #define __BOOST_UBLAS__ #include #include #include #include #include #include #include #include #include "math_exception.hpp" namespace math { namespace ublas { /*! *\fn typedef boost::numeric::ublas::matrix Matrix * \brief Definition of a matrix using double precision */ typedef boost::numeric::ublas::matrix Matrix; /*! *\fn typedef boost::numeric::ublas::vector Vector * \brief Definition of a vector using double precision */ typedef boost::numeric::ublas::vector Vector; /*! *\fn typedef boost::numeric::ublas::zero_vector ZeroVector; * \brief Definition of empty vector using double precision */ typedef boost::numeric::ublas::zero_vector ZeroVector; /*! *\fn typedef boost::numeric::ublas::zero_matrix ZeroMatrix; * \brief Definition of empty matrix using double precision */ typedef boost::numeric::ublas::zero_matrix ZeroMatrix; /*! * \fn inline boost::numeric::ublas::matrix operator *(const boost::numeric::ublas::matrix & m1, const boost::numeric::ublas::matrix & m2) * \brief multiplication of two matrices * \param m1 : ublas matrix * \param m2 : ublas matrix * \return ublas matrix */ template inline boost::numeric::ublas::matrix operator *(const boost::numeric::ublas::matrix & m1, const boost::numeric::ublas::matrix & m2) { return prod(m1,m2); } /*! * \fn inline boost::numeric::ublas::vector operator *(const boost::numeric::ublas::matrix & m, const boost::numeric::ublas::vector & v) * \brief product of a vector by a matrix * \param m : ublas matrix * \param v : ublas vector * \return ublas vector */ template inline boost::numeric::ublas::vector operator *(const boost::numeric::ublas::matrix & m, const boost::numeric::ublas::vector & v) { return prod(m,v); } /*! * \fn inline boost::numeric::ublas::vector operator +(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2) * \brief addition of two vectors * \param v1 : ublas vector * \param v2 : ublas vector * \return ublas vector */ template inline boost::numeric::ublas::vector operator +(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2) { boost::numeric::ublas::vector tmp = v1; return tmp+=v2; } /*! * \fn inline boost::numeric::ublas::vector operator -(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2) * \brief subtraction of two vectors * \param v1 : ublas vector * \param v2 : ublas vector * \return ublas vector */ template inline boost::numeric::ublas::vector operator -(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2) { boost::numeric::ublas::vector tmp = v1; return tmp-=v2; } /*! * \fn inline boost::numeric::ublas::matrixTrans(boost::numeric::ublas::matrix &m) * \brief transpose a matrix * \param m : ublas matrix * \return ublas matrix */ template inline boost::numeric::ublas::matrixTrans(boost::numeric::ublas::matrix &m) { return trans(m); } /*! * \fn inline boost::numeric::ublas::matrix vector2matrix(const boost::numeric::ublas::vector &v) * \brief convert a vector to a matrix * \param v : ublas vector * \return ublas matrix */ template inline boost::numeric::ublas::matrix vector2matrix(const boost::numeric::ublas::vector &v) { boost::numeric::ublas::matrix tmp(v.size(),1); for(size_t i=0;i & v) * \brief compute the norm of a vector * \param v : ublas vector * \return norm value */ template inline double Norm(const boost::numeric::ublas::vector & v){ double norm =0; for(typename boost::numeric::ublas::vector::const_iterator I=v.begin();I!=v.end();I++) norm+=(*I)*(*I); return std::sqrt(norm); } /*! * \fn inline boost::numeric::ublas::vector Mult(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2) * \brief term by term multiplication of two vectors * \param v1 : ublas vector * \param v2 : ublas vector * \return ublas vector */ template inline boost::numeric::ublas::vector Mult(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2){ if(v1.size()!=v2.size()) throw math_error("Dot(v1,v2) : vectors must have the same size"); boost::numeric::ublas::vector v(v1.size()); for(size_t i=0;i & v1, const boost::numeric::ublas::vector & v2) * \brief dot product * \param v1 : ublas vector * \param v2 : ublas vector * \return dot value */ template inline double Dot(const boost::numeric::ublas::vector & v1, const boost::numeric::ublas::vector & v2){ if(v1.size()!=v2.size()) throw math_error("Dot(v1,v2) : vectors must have the same size"); double dot=0; for(size_t i=0;i pmatrix; if(m.size1() != m.size2()) throw math_error("Inv(m): matrix must be square"); // create a working copy of the input Matrix A(m); // create a permutation matrix for the LU-factorization pmatrix pm(A.size1()); // perform LU-factorization int res = lu_factorize(A,pm); if( res != 0 ) throw math_error("Inv(m) : singular matrix"); // create identity matrix of "inverse" Matrix inverse = identity_matrix(A.size1()); // backsubstitute to get the inverse lu_substitute(A, pm, inverse); return inverse; } //////////////////////////////////////////////////////////////////////////////// ///////////////////////// QR DECOMPOSITION //////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// template bool InvertMatrix (const boost::numeric::ublas::matrix& input, boost::numeric::ublas::matrix& inverse) { using namespace boost::numeric::ublas; typedef permutation_matrix pmatrix; // create a working copy of the input matrix A(input); // create a permutation matrix for the LU-factorization pmatrix pm(A.size1()); // perform LU-factorization int res = lu_factorize(A,pm); if( res != 0 ) return false; // create identity matrix of "inverse" inverse.assign(boost::numeric::ublas::identity_matrix(A.size1())); // backsubstitute to get the inverse lu_substitute(A, pm, inverse); return true; } template void TransposeMultiply (const boost::numeric::ublas::vector& vector, boost::numeric::ublas::matrix& result, size_t size) { result.resize (size,size); result.clear (); for(unsigned int row=0; row< vector.size(); ++row) { for(unsigned int col=0; col < vector.size(); ++col) result(row,col) = vector(col) * vector(row); } } template void HouseholderCornerSubstraction (boost::numeric::ublas::matrix& LeftLarge, const boost::numeric::ublas::matrix& RightSmall) { using namespace boost::numeric::ublas; using namespace std; if( !( (LeftLarge.size1() >= RightSmall.size1()) && (LeftLarge.size2() >= RightSmall.size2()) ) ) { cerr << "invalid matrix dimensions" << endl; return; } size_t row_offset = LeftLarge.size2() - RightSmall.size2(); size_t col_offset = LeftLarge.size1() - RightSmall.size1(); for(unsigned int row = 0; row < RightSmall.size2(); ++row ) for(unsigned int col = 0; col < RightSmall.size1(); ++col ) LeftLarge(col_offset+col,row_offset+row) -= RightSmall(col,row); } template void QR (const boost::numeric::ublas::matrix& M, boost::numeric::ublas::matrix& Q, boost::numeric::ublas::matrix& R) { using namespace boost::numeric::ublas; using namespace std; if( !( (M.size1() == M.size2()) ) ) { cerr << "invalid matrix dimensions" << endl; return; } size_t size = M.size1(); // init Matrices matrix H, HTemp; HTemp = identity_matrix(size); Q = identity_matrix(size); R = M; // find Householder reflection matrices for(unsigned int col = 0; col < size-1; ++col) { // create X vector boost::numeric::ublas::vector RRowView = boost::numeric::ublas::column(R,col); vector_range< boost::numeric::ublas::vector > X2 (RRowView, range (col, size)); boost::numeric::ublas::vector X = X2; // X -> U~ if(X(0) >= 0) X(0) += norm_2(X); else X(0) += -1*norm_2(X); HTemp.resize(X.size(),X.size(),true); TransposeMultiply(X, HTemp, X.size()); // HTemp = the 2UUt part of H HTemp *= ( 2 / inner_prod(X,X) ); // H = I - 2UUt H = identity_matrix(size); HouseholderCornerSubstraction(H,HTemp); // add H to Q and R Q = prod(Q,H); R = prod(H,R); } } //////////////////////////////////////////////////////////////////////////////////////////:: /*! * \fn inline Matrix InvQR(const Matrix &m) * \brief matrix inversion using QR decomposition * \param m : ublas matrix * \return ubls matrix */ inline Matrix InvQR(const Matrix &m) throw(math_error){ using namespace boost::numeric::ublas; if(m.size1() != m.size2()) throw math_error("Inv(m): matrix must be square"); Matrix Q(m), R(m), Rinv(m); QR (m,Q,R); for( int i = 0 ; i < R.size1() ; i++ ) for( int j = 0 ; j < R.size2() ; j++ ) if( R(i,j) < 1e-10 ) R(i,j) = 0; InvertMatrix(R,Rinv); return Rinv*Trans(Q); } /*! * \fn inline double DetLU(const Matrix & m) * \brief compute matrix determinant using LU decomposition * \param m : ublas matrix * \return ublas matrix */ inline double DetLU(const Matrix & m) throw(math_error){ using namespace boost::numeric::ublas; typedef permutation_matrix pmatrix; if(m.size1() != m.size2()) throw math_error("Determinant(m): matrix must be square"); // create a working copy of the input Matrix A(m); // create a permutation matrix for the LU-factorization pmatrix pm(m.size1()); // perform LU-factorization int res = lu_factorize(A, pm); if( res != 0 ) throw math_error("Determinant(m) : singular matrix"); //compute determinant double det = 1.0; for (std::size_t i=0; i < pm.size(); ++i) { if (pm(i) != i) det *= -1.0; det *= A(i,i); } return det; } // output stream function inline std::ostream& operator << (std::ostream& ostrm, const Matrix & m) { for (size_t i=0; i < m.size1(); i++) { ostrm << '['<<'\t'; for (size_t j=0; j < m.size2(); j++) { double x = m(i,j); ostrm << x << '\t'; } ostrm << ']'<< std::endl; } return ostrm; } // output stream function inline std::ostream& operator << (std::ostream& ostrm, const Vector & v) { for (size_t i=0; i < v.size(); i++) { ostrm << '['<<'\t'; double x = v(i); ostrm << x << '\t'; ostrm << ']'<< std::endl; } return ostrm; } }; }; #endif