Main MRPT website > C++ reference for MRPT 1.9.9
CSparseMatrix.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #ifndef CSparseMatrix_H
10 #define CSparseMatrix_H
11 
12 #include <mrpt/utils/utils_defs.h>
13 #include <mrpt/utils/exceptions.h>
14 
15 #include <mrpt/math/math_frwds.h>
16 #include <mrpt/utils/types_math.h>
20 #include <cstring> // memcpy
21 
22 // Include CSparse lib headers, either from the system or embedded:
23 extern "C" {
24 #if MRPT_HAS_SUITESPARSE
25 #define NCOMPLEX // In MRPT we don't need complex numbers, so avoid the
26 // annoying warning: 'cs_ci_house' has C-linkage specified,
27 // but returns UDT 'std::complex<double>' which is
28 // incompatible with C
29 #include "cs.h"
30 #else
31 #include <mrpt/otherlibs/CSparse/cs.h>
32 #endif
33 }
34 
35 namespace mrpt
36 {
37 namespace math
38 {
39 /** Used in mrpt::math::CSparseMatrix */
41 {
42  public:
44 };
45 
46 /** A sparse matrix structure, wrapping T. Davis' CSparse library (part of
47  *suitesparse)
48  * The type of the matrix entries is fixed to "double".
49  *
50  * There are two formats for the non-zero entries in this matrix:
51  * - A "triplet" matrix: a set of (r,c)=val triplet entries.
52  * - A column-compressed sparse (CCS) matrix.
53  *
54  * The latter is the "normal" format, which is expected by all mathematical
55  *operations defined
56  * in this class. There're three ways of initializing and populating a sparse
57  *matrix:
58  *
59  * <ol>
60  * <li> <b>As a triplet (empty), then add entries, then compress:</b>
61  * \code
62  * CSparseMatrix SM(100,100);
63  * SM.insert_entry(i,j, val); // or
64  * SM.insert_submatrix(i,j, MAT); // ...
65  * SM.compressFromTriplet();
66  * \endcode
67  * </li>
68  * <li> <b>As a triplet from a CSparseMatrixTemplate<double>:</b>
69  * \code
70  * CSparseMatrixTemplate<double> data;
71  * data(row,col) = val;
72  * ...
73  * CSparseMatrix SM(data);
74  * \endcode
75  * </li>
76  * <li> <b>From an existing dense matrix:</b>
77  * \code
78  * CMatrixDouble data(100,100); // or
79  * CMatrixFloat data(100,100); // or
80  * CMatrixFixedNumeric<double,4,6> data; // etc...
81  * CSparseMatrix SM(data);
82  * \endcode
83  * </li>
84  *
85  * </ol>
86  *
87  * Due to its practical utility, there is a special inner class
88  *CSparseMatrix::CholeskyDecomp to handle Cholesky-related methods and data.
89  *
90  * \note This class was initially adapted from "robotvision", by Hauke
91  *Strasdat, Steven Lovegrove and Andrew J. Davison. See
92  *http://www.openslam.org/robotvision.html
93  * \note CSparse is maintained by Timothy Davis:
94  *http://people.sc.fsu.edu/~jburkardt/c_src/csparse/csparse.html .
95  * \note See also his book "Direct methods for sparse linear systems".
96  *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
97  *
98  * \sa mrpt::math::MatrixBlockSparseCols, mrpt::math::CMatrixFixedNumeric,
99  *mrpt::math::CMatrixTemplateNumeric, etc.
100  * \ingroup mrpt_base_grp
101  */
103 {
104  private:
106 
107  /** Initialization from a dense matrix of any kind existing in MRPT. */
108  template <class MATRIX>
109  void construct_from_mrpt_mat(const MATRIX& C)
110  {
111  std::vector<int> row_list, col_list; // Use "int" for convenience so we
112  // can do a memcpy below...
113  std::vector<double> content_list;
114  const int nCol = C.getColCount();
115  const int nRow = C.getRowCount();
116  for (int c = 0; c < nCol; ++c)
117  {
118  col_list.push_back(row_list.size());
119  for (int r = 0; r < nRow; ++r)
120  if (C.get_unsafe(r, c) != 0)
121  {
122  row_list.push_back(r);
123  content_list.push_back(C(r, c));
124  }
125  }
126  col_list.push_back(row_list.size());
127 
128  sparse_matrix.m = nRow;
129  sparse_matrix.n = nCol;
130  sparse_matrix.nzmax = content_list.size();
131  sparse_matrix.i = (int*)malloc(sizeof(int) * row_list.size());
132  sparse_matrix.p = (int*)malloc(sizeof(int) * col_list.size());
133  sparse_matrix.x = (double*)malloc(sizeof(double) * content_list.size());
134 
135  ::memcpy(
136  sparse_matrix.i, &row_list[0],
137  sizeof(row_list[0]) * row_list.size());
138  ::memcpy(
139  sparse_matrix.p, &col_list[0],
140  sizeof(col_list[0]) * col_list.size());
141  ::memcpy(
142  sparse_matrix.x, &content_list[0],
143  sizeof(content_list[0]) * content_list.size());
144 
145  sparse_matrix.nz =
146  -1; // <0 means "column compressed", ">=0" means triplet.
147  }
148 
149  /** Initialization from a triplet "cs", which is first compressed */
150  void construct_from_triplet(const cs& triplet);
151 
152  /** To be called by constructors only, assume previous pointers are trash
153  * and overwrite them */
154  void construct_from_existing_cs(const cs& sm);
155 
156  /** free buffers (deallocate the memory of the i,p,x buffers) */
157  void internal_free_mem();
158 
159  /** Copy the data from an existing "cs" CSparse data structure */
160  void copy(const cs* const sm);
161 
162  /** Fast copy the data from an existing "cs" CSparse data structure, copying
163  * the pointers and leaving NULLs in the source structure. */
164  void copy_fast(cs* const sm);
165 
166  public:
167  /** @name Constructors, destructor & copy operations
168  @{ */
169 
170  /** Create an initially empty sparse matrix, in the "triplet" form.
171  * Notice that you must call "compressFromTriplet" after populating the
172  * matrix and before using the math operatons on this matrix.
173  * The initial size can be later on extended with insert_entry() or
174  * setRowCount() & setColCount().
175  * \sa insert_entry, setRowCount, setColCount
176  */
177  CSparseMatrix(const size_t nRows = 0, const size_t nCols = 0);
178 
179  /** A good way to initialize a sparse matrix from a list of non nullptr
180  * elements.
181  * This constructor takes all the non-zero entries in "data" and builds a
182  * column-compressed sparse representation.
183  */
184  template <typename T>
186  {
187  ASSERTMSG_(
188  !data.empty(),
189  "Input data must contain at least one non-zero element.")
190  sparse_matrix.i =
191  nullptr; // This is to know they shouldn't be tried to free()
192  sparse_matrix.p = nullptr;
193  sparse_matrix.x = nullptr;
194 
195  // 1) Create triplet matrix
196  CSparseMatrix triplet(data.getRowCount(), data.getColCount());
197  // 2) Put data in:
199  data.begin();
200  it != data.end(); ++it)
201  triplet.insert_entry_fast(
202  it->first.first, it->first.second, it->second);
203 
204  // 3) Compress:
205  construct_from_triplet(triplet.sparse_matrix);
206  }
207 
208  // We can't do a simple "template <class ANYMATRIX>" since it would be tried
209  // to match against "cs*"...
210 
211  /** Constructor from a dense matrix of any kind existing in MRPT, creating a
212  * "column-compressed" sparse matrix. */
213  template <typename T, size_t N, size_t M>
214  inline explicit CSparseMatrix(const CMatrixFixedNumeric<T, N, M>& MAT)
215  {
217  }
218 
219  /** Constructor from a dense matrix of any kind existing in MRPT, creating a
220  * "column-compressed" sparse matrix. */
221  template <typename T>
222  inline explicit CSparseMatrix(const CMatrixTemplateNumeric<T>& MAT)
223  {
225  }
226 
227  /** Copy constructor */
228  CSparseMatrix(const CSparseMatrix& other);
229 
230  /** Copy constructor from an existing "cs" CSparse data structure */
231  explicit CSparseMatrix(const cs* const sm);
232 
233  /** Destructor */
234  virtual ~CSparseMatrix();
235 
236  /** Copy operator from another existing object */
237  void operator=(const CSparseMatrix& other);
238 
239  /** Fast swap contents with another sparse matrix */
240  void swap(CSparseMatrix& other);
241 
242  /** Erase all previous contents and leave the matrix as a "triplet" ROWS x
243  * COLS matrix without any nonzero entry. */
244  void clear(const size_t nRows = 1, const size_t nCols = 1);
245 
246  /** @} */
247 
248  /** @name Math operations (the interesting stuff...)
249  @{ */
250 
251  /** this = A+B */
252  void add_AB(const CSparseMatrix& A, const CSparseMatrix& B);
253  /** this = A*B */
254  void multiply_AB(const CSparseMatrix& A, const CSparseMatrix& B);
255  /** out_res = this * b */
256  void multiply_Ab(
258  mrpt::math::CVectorDouble& out_res) const;
259 
260  inline CSparseMatrix operator+(const CSparseMatrix& other) const
261  {
262  CSparseMatrix RES;
263  RES.add_AB(*this, other);
264  return RES;
265  }
266  inline CSparseMatrix operator*(const CSparseMatrix& other) const
267  {
268  CSparseMatrix RES;
269  RES.multiply_AB(*this, other);
270  return RES;
271  }
273  const mrpt::math::CVectorDouble& other) const
274  {
276  multiply_Ab(other, res);
277  return res;
278  }
279  inline void operator+=(const CSparseMatrix& other)
280  {
281  this->add_AB(*this, other);
282  }
283  inline void operator*=(const CSparseMatrix& other)
284  {
285  this->multiply_AB(*this, other);
286  }
287  CSparseMatrix transpose() const;
288 
289  /** @} */
290 
291  /** @ Access the matrix, get, set elements, etc.
292  @{ */
293 
294  /** ONLY for TRIPLET matrices: insert a new non-zero entry in the matrix.
295  * This method cannot be used once the matrix is in column-compressed
296  * form.
297  * The size of the matrix will be automatically extended if the indices
298  * are out of the current limits.
299  * \sa isTriplet, compressFromTriplet
300  */
301  void insert_entry(const size_t row, const size_t col, const double val);
302 
303  /** This was an optimized version, but is now equivalent to insert_entry()
304  * due to the need to be compatible with unmodified CSparse system
305  * libraries. */
306  inline void insert_entry_fast(
307  const size_t row, const size_t col, const double val)
308  {
309  insert_entry(row, col, val);
310  }
311 
312  /** ONLY for TRIPLET matrices: insert a given matrix (in any of the MRPT
313  * formats) at a given location of the sparse matrix.
314  * This method cannot be used once the matrix is in column-compressed
315  * form.
316  * The size of the matrix will be automatically extended if the indices
317  * are out of the current limits.
318  * Since this is inline, it can be very efficient for fixed-size MRPT
319  * matrices.
320  * \sa isTriplet, compressFromTriplet, insert_entry
321  */
322  template <class MATRIX>
323  inline void insert_submatrix(
324  const size_t row, const size_t col, const MATRIX& M)
325  {
326  if (!isTriplet())
328  "insert_entry() is only available for sparse matrix in "
329  "'triplet' format.")
330  const size_t nR = M.getRowCount();
331  const size_t nC = M.getColCount();
332  for (size_t r = 0; r < nR; r++)
333  for (size_t c = 0; c < nC; c++)
334  insert_entry_fast(row + r, col + c, M.get_unsafe(r, c));
335  // If needed, extend the size of the matrix:
336  sparse_matrix.m = std::max(sparse_matrix.m, int(row + nR));
337  sparse_matrix.n = std::max(sparse_matrix.n, int(col + nC));
338  }
339 
340  /** ONLY for TRIPLET matrices: convert the matrix in a column-compressed
341  * form.
342  * \sa insert_entry
343  */
344  void compressFromTriplet();
345 
346  /** Return a dense representation of the sparse matrix.
347  * \sa saveToTextFile_dense
348  */
349  void get_dense(CMatrixDouble& outMat) const;
350 
351  /** Static method to convert a "cs" structure into a dense representation of
352  * the sparse matrix.
353  */
354  static void cs2dense(const cs& SM, CMatrixDouble& outMat);
355 
356  /** save as a dense matrix to a text file \return False on any error.
357  */
358  bool saveToTextFile_dense(const std::string& filName);
359 
360  /** Save sparse structure to a text file loadable from MATLAB (can be called
361  * on triplet or CCS matrices).
362  *
363  * The format of the text file is:
364  * \code
365  * NUM_ROWS NUM_COLS NUM_NON_ZERO_MAX
366  * row_1 col_1 value_1
367  * row_2 col_2 value_2
368  * ...
369  * \endcode
370  *
371  * Instructions for loading from MATLAB in triplet form will be
372  * automatically writen to the
373  * output file as comments in th first lines:
374  *
375  * \code
376  * D=load('file.txt');
377  * SM=spconvert(D(2:end,:));
378  * or, to always preserve the actual matrix size m x n:
379  * m=D(1,1); n=D(1,2); nzmax=D(1,3);
380  * Di=D(2:end,1); Dj=D(2:end,2); Ds=D(2:end,3);
381  * M=sparse(Di,Dj,Ds, m,n, nzmax);
382  * \endcode
383  * \return False on any error.
384  */
385  bool saveToTextFile_sparse(const std::string& filName);
386 
387  // Very basic, standard methods that MRPT methods expect for any matrix:
388  inline size_t getRowCount() const { return sparse_matrix.m; }
389  inline size_t getColCount() const { return sparse_matrix.n; }
390  /** Change the number of rows in the matrix (can't be lower than current
391  * size) */
392  inline void setRowCount(const size_t nRows)
393  {
394  ASSERT_(nRows >= (size_t)sparse_matrix.m);
395  sparse_matrix.m = nRows;
396  }
397  inline void setColCount(const size_t nCols)
398  {
399  ASSERT_(nCols >= (size_t)sparse_matrix.n);
400  sparse_matrix.n = nCols;
401  }
402 
403  /** Returns true if this sparse matrix is in "triplet" form. \sa
404  * isColumnCompressed */
405  inline bool isTriplet() const
406  {
407  return sparse_matrix.nz >= 0;
408  } // <0 means "column compressed", ">=0" means triplet.
409 
410  /** Returns true if this sparse matrix is in "column compressed" form. \sa
411  * isTriplet */
412  inline bool isColumnCompressed() const
413  {
414  return sparse_matrix.nz < 0;
415  } // <0 means "column compressed", ">=0" means triplet.
416 
417  /** @} */
418 
419  /** @name Cholesky factorization
420  @{ */
421 
422  /** Auxiliary class to hold the results of a Cholesky factorization of a
423  *sparse matrix.
424  * This implementation does not allow updating/downdating.
425  *
426  * Usage example:
427  * \code
428  * CSparseMatrix SM(100,100);
429  * SM.insert_entry(i,j, val); ...
430  * SM.compressFromTriplet();
431  *
432  * // Do Cholesky decomposition:
433  * CSparseMatrix::CholeskyDecomp CD(SM);
434  * CD.get_inverse();
435  * ...
436  * \endcode
437  *
438  * \note Only the upper triangular part of the input matrix is accessed.
439  * \note This class was initially adapted from "robotvision", by Hauke
440  *Strasdat, Steven Lovegrove and Andrew J. Davison. See
441  *http://www.openslam.org/robotvision.html
442  * \note This class designed to be "uncopiable".
443  * \sa The main class: CSparseMatrix
444  */
446  {
447  private:
450  /** A const reference to the original matrix used to build this
451  * decomposition. */
453 
454  public:
455  /** Constructor from a square definite-positive sparse matrix A, which
456  * can be use to solve Ax=b
457  * The actual Cholesky decomposition takes places in this
458  * constructor.
459  * \note Only the upper triangular part of the matrix is accessed.
460  * \exception std::runtime_error On non-square input matrix.
461  * \exception mrpt::math::CExceptionNotDefPos On non-definite-positive
462  * matrix as input.
463  */
464  CholeskyDecomp(const CSparseMatrix& A);
465  CholeskyDecomp(const CholeskyDecomp& A) = delete;
466 
467  CholeskyDecomp& operator=(const CholeskyDecomp&) = delete;
468 
469  /** Destructor */
470  virtual ~CholeskyDecomp();
471 
472  /** Return the L matrix (L*L' = M), as a dense matrix. */
473  inline CMatrixDouble get_L() const
474  {
475  CMatrixDouble L;
476  get_L(L);
477  return L;
478  }
479 
480  /** Return the L matrix (L*L' = M), as a dense matrix. */
481  void get_L(CMatrixDouble& out_L) const;
482 
483  /** Return the vector from a back-substitution step that solves: Ux=b */
484  template <class VECTOR>
485  inline VECTOR backsub(const VECTOR& b) const
486  {
487  VECTOR res;
488  backsub(b, res);
489  return res;
490  }
491 
492  /** Return the vector from a back-substitution step that solves: Ux=b.
493  * Vectors can be Eigen::VectorXd or mrpt::math::CVectorDouble */
494  void backsub(const Eigen::VectorXd& b, Eigen::VectorXd& result_x) const;
495 
496  /** overload for double pointers which assume the user has reserved the
497  * output memory for \a result */
498  void backsub(const double* b, double* result, const size_t N) const;
499 
500  /** Update the Cholesky factorization from an updated vesion of the
501  * original input, square definite-positive sparse matrix.
502  * NOTE: This new matrix MUST HAVE exactly the same sparse structure
503  * than the original one.
504  */
505  void update(const CSparseMatrix& new_SM);
506  };
507  static_assert(
510  "Copy Check");
511 
512  /** @} */
513 
514 }; // end class CSparseMatrix
515 }
516 }
517 #endif
void setColCount(const size_t nCols)
size_t getRowCount() const
const CSparseMatrix * m_originalSM
A const reference to the original matrix used to build this decomposition.
void insert_entry_fast(const size_t row, const size_t col, const double val)
This was an optimized version, but is now equivalent to insert_entry() due to the need to be compatib...
void construct_from_triplet(const cs &triplet)
Initialization from a triplet "cs", which is first compressed.
#define THROW_EXCEPTION(msg)
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
Definition: eigen_frwds.h:42
Auxiliary class to hold the results of a Cholesky factorization of a sparse matrix.
A sparse matrix structure, wrapping T.
void compressFromTriplet()
ONLY for TRIPLET matrices: convert the matrix in a column-compressed form.
void construct_from_mrpt_mat(const MATRIX &C)
Initialization from a dense matrix of any kind existing in MRPT.
SparseMatrixMap::const_iterator const_iterator
Const iterator to move through the matrix.
CExceptionNotDefPos(const std::string &s)
Definition: CSparseMatrix.h:43
GLdouble s
Definition: glext.h:3676
void swap(CSparseMatrix &other)
Fast swap contents with another sparse matrix.
void insert_entry(const size_t row, const size_t col, const double val)
@ Access the matrix, get, set elements, etc.
A sparse matrix container (with cells of any type), with iterators.
CMatrixDouble get_L() const
Return the L matrix (L*L&#39; = M), as a dense matrix.
Used in mrpt::math::CSparseMatrix.
Definition: CSparseMatrix.h:40
void get_dense(CMatrixDouble &outMat) const
Return a dense representation of the sparse matrix.
A numeric matrix of compile-time fixed size.
CSparseMatrix operator*(const CSparseMatrix &other) const
void multiply_AB(const CSparseMatrix &A, const CSparseMatrix &B)
this = A*B
CSparseMatrix(const CMatrixTemplateNumeric< T > &MAT)
Constructor from a dense matrix of any kind existing in MRPT, creating a "column-compressed" sparse m...
void construct_from_existing_cs(const cs &sm)
To be called by constructors only, assume previous pointers are trash and overwrite them...
CSparseMatrix(const size_t nRows=0, const size_t nCols=0)
Create an initially empty sparse matrix, in the "triplet" form.
const GLubyte * c
Definition: glext.h:6313
void add_AB(const CSparseMatrix &A, const CSparseMatrix &B)
this = A+B
int val
Definition: mrpt_jpeglib.h:955
void operator=(const CSparseMatrix &other)
Copy operator from another existing object.
GLubyte GLubyte b
Definition: glext.h:6279
void multiply_Ab(const mrpt::math::CVectorDouble &b, mrpt::math::CVectorDouble &out_res) const
out_res = this * b
The base for MRPT-especific exceptions.
Definition: exceptions.h:25
void setRowCount(const size_t nRows)
Change the number of rows in the matrix (can&#39;t be lower than current size)
GLsizei const GLchar ** string
Definition: glext.h:4101
CSparseMatrix operator+(const CSparseMatrix &other) const
void clear(const size_t nRows=1, const size_t nCols=1)
Erase all previous contents and leave the matrix as a "triplet" ROWS x COLS matrix without any nonzer...
bool isTriplet() const
Returns true if this sparse matrix is in "triplet" form.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
CholeskyDecomp & operator=(const CholeskyDecomp &)=delete
CSparseMatrix(const CMatrixFixedNumeric< T, N, M > &MAT)
Constructor from a dense matrix of any kind existing in MRPT, creating a "column-compressed" sparse m...
GLdouble GLdouble GLdouble r
Definition: glext.h:3705
mrpt::math::CVectorDouble operator*(const mrpt::math::CVectorDouble &other) const
void operator*=(const CSparseMatrix &other)
CholeskyDecomp(const CSparseMatrix &A)
Constructor from a square definite-positive sparse matrix A, which can be use to solve Ax=b The actua...
bool saveToTextFile_dense(const std::string &filName)
save as a dense matrix to a text file
void update(const CSparseMatrix &new_SM)
Update the Cholesky factorization from an updated vesion of the original input, square definite-posit...
GLenum GLenum GLvoid * row
Definition: glext.h:3576
void operator+=(const CSparseMatrix &other)
virtual ~CSparseMatrix()
Destructor.
void insert_submatrix(const size_t row, const size_t col, const MATRIX &M)
ONLY for TRIPLET matrices: insert a given matrix (in any of the MRPT formats) at a given location of ...
CSparseMatrix transpose() const
bool saveToTextFile_sparse(const std::string &filName)
Save sparse structure to a text file loadable from MATLAB (can be called on triplet or CCS matrices)...
static void cs2dense(const cs &SM, CMatrixDouble &outMat)
Static method to convert a "cs" structure into a dense representation of the sparse matrix...
#define ASSERT_(f)
CMRPTException(const std::string &s)
Definition: exceptions.h:28
GLsizei const GLfloat * value
Definition: glext.h:4117
size_t getColCount() const
GLuint res
Definition: glext.h:7268
VECTOR backsub(const VECTOR &b) const
Return the vector from a back-substitution step that solves: Ux=b.
CSparseMatrix(const CSparseMatrixTemplate< T > &data)
A good way to initialize a sparse matrix from a list of non nullptr elements.
bool isColumnCompressed() const
Returns true if this sparse matrix is in "column compressed" form.
void copy(const cs *const sm)
Copy the data from an existing "cs" CSparse data structure.
#define ASSERTMSG_(f, __ERROR_MSG)
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
void copy_fast(cs *const sm)
Fast copy the data from an existing "cs" CSparse data structure, copying the pointers and leaving NUL...
void internal_free_mem()
free buffers (deallocate the memory of the i,p,x buffers)
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:355



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019