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: |