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 |