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



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011