Main MRPT website > C++ reference
MRPT logo
CSparseMatrix.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef CSparseMatrix_H
00029 #define CSparseMatrix_H
00030 
00031 #include <mrpt/utils/utils_defs.h>
00032 #include <mrpt/utils/exceptions.h>
00033 #include <mrpt/utils/CUncopiable.h>
00034 
00035 #include <mrpt/math/math_frwds.h>
00036 #include <mrpt/math/CSparseMatrixTemplate.h>
00037 #include <mrpt/math/CMatrixTemplateNumeric.h>
00038 #include <mrpt/math/CMatrixFixedNumeric.h>
00039 
00040 // I don't like this solution, since can cause problems if CSparse structs
00041 //  change in the future (unlikely): even if we are linking against the CSparse
00042 //  embedded lib or a system lib, use the embedded headers. The reason: not to
00043 //  force MRPT users to install CSparse headers.
00044 extern "C"{
00045 #include <mrpt/otherlibs/CSparse/cs.h>
00046 }
00047 
00048 namespace mrpt
00049 {
00050         namespace math
00051         {
00052                 /** Used in mrpt::math::CSparseMatrix */
00053                 class CExceptionNotDefPos : public mrpt::utils::CMRPTException
00054                 {
00055                 public:
00056                         CExceptionNotDefPos(const std::string &s) : CMRPTException(s) {  }
00057                 };
00058 
00059 
00060                 /** A sparse matrix capable of efficient math operations (a wrapper around the CSparse library)
00061                   *  The type of cells is fixed to "double".
00062                   *
00063                   *  There are two main formats for the non-zero entries in this matrix:
00064                   *             - A "triplet" matrix: a set of (r,c)=val triplet entries.
00065                   *             - A column-compressed sparse matrix.
00066                   *
00067                   *  The latter is the "normal" format, which is expected by most mathematical operations defined
00068                   *   in this class. There're two three ways of initializing and populating a sparse matrix:
00069                   *
00070                   *   <ol>
00071                   *    <li> <b>As a triplet (empty), then add entries, then compress:</b>
00072                   *         \code
00073                   *             CSparseMatrix  SM(100,100);
00074                   *             SM.insert_entry(i,j, val);  // or
00075                   *             SM.insert_submatrix(i,j, MAT); //  ...
00076                   *             SM.compressFromTriplet();
00077                   *         \endcode
00078                   *    </li>
00079                   *    <li> <b>As a triplet from a CSparseMatrixTemplate<double>:</b>
00080                   *         \code
00081                   *             CSparseMatrixTemplate<double>  data;
00082                   *             data(row,col) = val;
00083                   *             ...
00084                   *             CSparseMatrix  SM(data);
00085                   *         \endcode
00086                   *    </li>
00087                   *    <li> <b>From an existing dense matrix:</b>
00088                   *         \code
00089                   *             CMatrixDouble data(100,100); // or
00090                   *             CMatrixFloat  data(100,100); // or
00091                   *             CMatrixFixedNumeric<double,4,6>  data; // etc...
00092                   *             CSparseMatrix  SM(data);
00093                   *         \endcode
00094                   *    </li>
00095                   *
00096                   *   </ol>
00097                   *
00098                   *  Due to its practical utility, there is a special inner class CSparseMatrix::CholeskyDecomp to handle Cholesky-related methods and data.
00099                   *
00100                   *
00101                   * \note This class was initially adapted from "robotvision", by Hauke Strasdat, Steven Lovegrove and Andrew J. Davison. See http://www.openslam.org/robotvision.html
00102                   * \note CSparse is maintained by Timothy Davis: http://people.sc.fsu.edu/~jburkardt/c_src/csparse/csparse.html .
00103                   * \note See also his book "Direct methods for sparse linear systems". http://books.google.es/books?id=TvwiyF8vy3EC&pg=PA12&lpg=PA12&dq=cs_compress&source=bl&ots=od9uGJ793j&sig=Wa-fBk4sZkZv3Y0Op8FNH8PvCUs&hl=es&ei=UjA0TJf-EoSmsQay3aXPAw&sa=X&oi=book_result&ct=result&resnum=8&ved=0CEQQ6AEwBw#v=onepage&q&f=false
00104                   *
00105                   * \sa mrpt::math::CMatrixFixedNumeric, mrpt::math::CMatrixTemplateNumeric, etc.
00106                   * \ingroup mrpt_base_grp
00107                   */
00108                 class BASE_IMPEXP CSparseMatrix
00109                 {
00110                 private:
00111                         cs sparse_matrix;
00112 
00113                         /** Initialization from a dense matrix of any kind existing in MRPT. */
00114                         template <class MATRIX>
00115                         void construct_from_mrpt_mat(const MATRIX & C)
00116                         {
00117                                 std::vector<int> row_list, col_list;  // Use "int" for convenience so we can do a memcpy below...
00118                                 std::vector<double> content_list;
00119                                 const int nCol = C.getColCount();
00120                                 const int nRow = C.getRowCount();
00121                                 for (int c=0; c<nCol; ++c)
00122                                 {
00123                                         col_list.push_back(row_list.size());
00124                                         for (int r=0; r<nRow; ++r)
00125                                                 if (C.get_unsafe(r,c)!=0)
00126                                                 {
00127                                                         row_list.push_back(r);
00128                                                         content_list.push_back(C(r,c));
00129                                                 }
00130                                 }
00131                                 col_list.push_back(row_list.size());
00132 
00133                                 sparse_matrix.m = nRow;
00134                                 sparse_matrix.n = nCol;
00135                                 sparse_matrix.nzmax = content_list.size();
00136                                 sparse_matrix.i = (int*)malloc(sizeof(int)*row_list.size());
00137                                 sparse_matrix.p = (int*)malloc(sizeof(int)*col_list.size());
00138                                 sparse_matrix.x = (double*)malloc(sizeof(double)*content_list.size());
00139 
00140 				::memcpy(sparse_matrix.i, &row_list[0], sizeof(row_list[0])*row_list.size() );
00141 				::memcpy(sparse_matrix.p, &col_list[0], sizeof(col_list[0])*col_list.size() );
00142 				::memcpy(sparse_matrix.x, &content_list[0], sizeof(content_list[0])*content_list.size() );
00143 
00144                                 sparse_matrix.nz = -1;  // <0 means "column compressed", ">=0" means triplet.
00145                         }
00146 
00147                         /** Initialization from a triplet "cs", which is first compressed */
00148                         void construct_from_triplet(const cs & triplet);
00149 
00150                         /** To be called by constructors only, assume previous pointers are trash and overwrite them */
00151                         void construct_from_existing_cs(const cs &sm);
00152 
00153                         /** free buffers (deallocate the memory of the i,p,x buffers) */
00154                         void internal_free_mem();
00155 
00156                         /** Copy the data from an existing "cs" CSparse data structure */
00157                         void  copy(const cs  * const sm);
00158 
00159                         /** Fast copy the data from an existing "cs" CSparse data structure, copying the pointers and leaving NULLs in the source structure. */
00160                         void  copy_fast(cs  * const sm);
00161 
00162                 public:
00163 
00164                         /** @name Constructors, destructor & copy operations
00165                             @{  */
00166 
00167                         /** Create an initially empty sparse matrix, in the "triplet" form.
00168                           *  Notice that you must call "compressFromTriplet" after populating the matrix and before using the math operatons on this matrix.
00169                           *  The initial size can be later on extended with insert_entry() or setRowCount() & setColCount().
00170                           * \sa insert_entry, setRowCount, setColCount
00171                           */
00172                         CSparseMatrix(const size_t nRows=0, const size_t nCols=0);
00173 
00174                         /** A good way to initialize a sparse matrix from a list of non NULL elements.
00175                           *  This constructor takes all the non-zero entries in "data" and builds a column-compressed sparse representation.
00176                           */
00177                         template <typename T>
00178                         inline CSparseMatrix(const CSparseMatrixTemplate<T> & data)
00179                         {
00180                                 ASSERTMSG_(!data.empty(), "Input data must contain at least one non-zero element.")
00181                                 sparse_matrix.i = NULL; // This is to know they shouldn't be tried to free()
00182                                 sparse_matrix.p = NULL;
00183                                 sparse_matrix.x = NULL;
00184 
00185                                 // 1) Create triplet matrix
00186                                 CSparseMatrix  triplet(data.getRowCount(),data.getColCount());
00187                                 // 2) Put data in:
00188                                 for (typename CSparseMatrixTemplate<T>::const_iterator it=data.begin();it!=data.end();++it)
00189                                         triplet.insert_entry_fast(it->first.first,it->first.second, it->second);
00190 
00191                                 // 3) Compress:
00192                                 construct_from_triplet(triplet.sparse_matrix);
00193                         }
00194 
00195 
00196                         // We can't do a simple "template <class ANYMATRIX>" since it would be tried to match against "cs*"...
00197 
00198                         /** Constructor from a dense matrix of any kind existing in MRPT, creating a "column-compressed" sparse matrix. */
00199                         template <typename T,size_t N,size_t M> inline explicit CSparseMatrix(const CMatrixFixedNumeric<T,N,M> &MAT) { construct_from_mrpt_mat(MAT); }
00200 
00201                         /** Constructor from a dense matrix of any kind existing in MRPT, creating a "column-compressed" sparse matrix. */
00202                         template <typename T>  inline explicit CSparseMatrix(const CMatrixTemplateNumeric<T> &MAT) { construct_from_mrpt_mat(MAT); }
00203 
00204                         /** Copy constructor */
00205                         CSparseMatrix(const CSparseMatrix & other);
00206 
00207                         /** Copy constructor from an existing "cs" CSparse data structure */
00208                         explicit CSparseMatrix(const cs  * const sm);
00209 
00210                         /** Destructor */
00211                         virtual ~CSparseMatrix();
00212 
00213                         /** Copy operator from another existing object */
00214                         void operator = (const CSparseMatrix & other);
00215 
00216                         /** Erase all previous contents and leave the matrix as a "triplet" 1x1 matrix without any data. */
00217                         void clear();
00218 
00219                         /** @}  */
00220 
00221                         /** @name Math operations (the interesting stuff...)
00222                                 @{ */
00223 
00224                         void add_AB(const CSparseMatrix & A,const CSparseMatrix & B); //!< this = A+B
00225                         void multiply_AB(const CSparseMatrix & A,const CSparseMatrix & B); //!< this = A*B
00226                         void multiply_Ab(const mrpt::vector_double &b, mrpt::vector_double &out_res) const; //!< out_res = this * b
00227 
00228                         inline CSparseMatrix operator + (const CSparseMatrix & other) const
00229                         {
00230                                 CSparseMatrix RES;
00231                                 RES.add_AB(*this,other);
00232                                 return RES;
00233                         }
00234                         inline CSparseMatrix operator * (const CSparseMatrix & other) const
00235                         {
00236                                 CSparseMatrix RES;
00237                                 RES.multiply_AB(*this,other);
00238                                 return RES;
00239                         }
00240                         inline mrpt::vector_double operator * (const mrpt::vector_double & other) const {
00241                                 mrpt::vector_double res;
00242                                 multiply_Ab(other,res);
00243                                 return res;
00244                         }
00245                         inline void operator += (const CSparseMatrix & other) {
00246                                 this->add_AB(*this,other);
00247                         }
00248                         inline void operator *= (const CSparseMatrix & other) {
00249                                 this->multiply_AB(*this,other);
00250                         }
00251                         CSparseMatrix transpose() const;
00252 
00253                         /** @}  */
00254 
00255 
00256                         /** @ Access the matrix, get, set elements, etc.
00257                             @{ */
00258 
00259                         /** ONLY for TRIPLET matrices: insert a new non-zero entry in the matrix.
00260                           *  This method cannot be used once the matrix is in column-compressed form.
00261                           *  The size of the matrix will be automatically extended if the indices are out of the current limits.
00262                           * \sa isTriplet, compressFromTriplet
00263                           */
00264                         void insert_entry(const size_t row, const size_t col, const double val );
00265 
00266                         /** This was an optimized version, but is now equivalent to insert_entry() due to the need to be compatible with unmodified CSparse system libraries. */
00267                         inline void insert_entry_fast(const size_t row, const size_t col, const double val )  { insert_entry(row,col,val); }
00268 
00269                         /** ONLY for TRIPLET matrices: insert a given matrix (in any of the MRPT formats) at a given location of the sparse matrix.
00270                           *  This method cannot be used once the matrix is in column-compressed form.
00271                           *  The size of the matrix will be automatically extended if the indices are out of the current limits.
00272                           *  Since this is inline, it can be very efficient for fixed-size MRPT matrices.
00273                           * \sa isTriplet, compressFromTriplet, insert_entry
00274                           */
00275                         template <class MATRIX>
00276                         inline void insert_submatrix(const size_t row, const size_t col, const MATRIX &M )
00277                         {
00278                                 if (!isTriplet()) THROW_EXCEPTION("insert_entry() is only available for sparse matrix in 'triplet' format.")
00279                                 const size_t nR = M.getRowCount();
00280                                 const size_t nC = M.getColCount();
00281                                 for (size_t r=0;r<nR;r++)
00282                                         for (size_t c=0;c<nC;c++)
00283                                                 insert_entry_fast(row+r,col+c, M.get_unsafe(r,c));
00284                                 // If needed, extend the size of the matrix:
00285                                 sparse_matrix.m = std::max(sparse_matrix.m, int(row+nR));
00286                                 sparse_matrix.n = std::max(sparse_matrix.n, int(col+nC));
00287                         }
00288 
00289 
00290                         /** ONLY for TRIPLET matrices: convert the matrix in a column-compressed form.
00291                           * \sa insert_entry
00292                           */
00293                         void compressFromTriplet();
00294 
00295                         /** Return a dense representation of the sparse matrix.
00296                           * \sa saveToTextFile_dense
00297                           */
00298                         void get_dense(CMatrixDouble &outMat) const;
00299 
00300                         /** Static method to convert a "cs" structure into a dense representation of the sparse matrix.
00301                           */
00302                         static void cs2dense(const cs& SM, CMatrixDouble &outMat);
00303 
00304                         /** save as a dense matrix to a text file \return False on any error.
00305                           */
00306                         bool saveToTextFile_dense(const std::string &filName);
00307 
00308                         // Very basic, standard methods that MRPT methods expect for any matrix:
00309                         inline size_t getRowCount() const { return sparse_matrix.m; }
00310                         inline size_t getColCount() const { return sparse_matrix.n; }
00311 
00312                         /** Change the number of rows in the matrix (can't be lower than current size) */
00313                         inline void setRowCount(const size_t nRows) { ASSERT_(nRows>=(size_t)sparse_matrix.m); sparse_matrix.m = nRows; }
00314                         inline void setColCount(const size_t nCols) { ASSERT_(nCols>=(size_t)sparse_matrix.n); sparse_matrix.n = nCols; }
00315 
00316                         /** Returns true if this sparse matrix is in "triplet" form. \sa isColumnCompressed */
00317                         inline bool isTriplet() const { return sparse_matrix.nz>=0; }  // <0 means "column compressed", ">=0" means triplet.
00318 
00319                         /** Returns true if this sparse matrix is in "column compressed" form. \sa isTriplet */
00320                         inline bool isColumnCompressed() const { return sparse_matrix.nz<0; }  // <0 means "column compressed", ">=0" means triplet.
00321 
00322                         /** @} */
00323 
00324 
00325                         /** @name Cholesky factorization
00326                             @{  */
00327 
00328                         /** Auxiliary class to hold the results of a Cholesky factorization of a sparse matrix.
00329                           *  Usage example:
00330                           *   \code
00331                           *     CSparseMatrix  SM(100,100);
00332                           *     SM.insert_entry(i,j, val); ...
00333                           *     SM.compressFromTriplet();
00334                           *
00335                           *     // Do Cholesky decomposition:
00336                           *             CSparseMatrix::CholeskyDecomp  CD(SM);
00337                           *     CD.get_inverse();
00338                           *     ...
00339                           *   \endcode
00340                           *
00341                           * \note Only the upper triangular part of the input matrix is accessed.
00342                           * \note This class was initially adapted from "robotvision", by Hauke Strasdat, Steven Lovegrove and Andrew J. Davison. See http://www.openslam.org/robotvision.html
00343                           * \note This class designed to be "uncopiable".
00344                           * \sa The main class: CSparseMatrix
00345                           */
00346                         class BASE_IMPEXP CholeskyDecomp  : public mrpt::utils::CUncopiable
00347                         {
00348                         private:
00349                                 css * m_symbolic_structure;
00350                                 csn * m_numeric_structure;
00351                                 const CSparseMatrix *m_originalSM;  //!< A const reference to the original matrix used to build this decomposition.
00352 
00353                         public:
00354                                 /** Constructor from a square definite-positive sparse matrix A, which can be use to solve Ax=b
00355                                   *   The actual Cholesky decomposition takes places in this constructor.
00356                                   *  \note Only the upper triangular part of the matrix is accessed.
00357                                   *  \exception std::runtime_error On non-square input matrix.
00358                                   *  \exception mrpt::math::CExceptionNotDefPos On non-definite-positive matrix as input.
00359                                   */
00360                                 CholeskyDecomp(const CSparseMatrix &A);
00361 
00362                                 /** Destructor */
00363                                 virtual ~CholeskyDecomp();
00364 
00365                                 /** Return the L matrix (L*L' = M), as a dense matrix. */
00366                                 inline CMatrixDouble get_L() const { CMatrixDouble L; get_L(L); return L; }
00367 
00368                                 /** Return the L matrix (L*L' = M), as a dense matrix. */
00369                                 void get_L(CMatrixDouble &out_L) const;
00370 
00371                                 /** Return the vector from a back-substitution step that solves: Ux=b   */
00372                                 inline mrpt::vector_double backsub(const mrpt::vector_double &b) const { mrpt::vector_double res; backsub(b,res); return res; }
00373 
00374                                 /** Return the vector from a back-substitution step that solves: Ux=b   */
00375                                 void backsub(const mrpt::vector_double &b, mrpt::vector_double &result_x) const;
00376 
00377                                 /** Update the Cholesky factorization from an updated vesion of the original input, square definite-positive sparse matrix.
00378                                   *  NOTE: This new matrix MUST HAVE exactly the same sparse structure than the original one.
00379                                   */
00380                                 void update(const CSparseMatrix &new_SM);
00381                         };
00382 
00383 
00384                         /** @} */
00385 
00386                 }; // end class CSparseMatrix
00387 
00388         }
00389 }
00390 #endif



Page generated by Doxygen 1.7.4 for MRPT 0.9.5 SVN:2717 at Sun Oct 16 16:08:03 PDT 2011 Hosted on:
SourceForge.net Logo