Main MRPT website > C++ reference for MRPT 1.9.9
CSparseMatrix.cpp
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 
10 #include "base-precomp.h" // Precompiled headers
11 
13 
14 using std::string;
15 using std::cout;
16 using std::endl;
17 using namespace mrpt;
18 using namespace mrpt::math;
19 using namespace mrpt::utils;
20 
21 /** Copy constructor */
23 {
24  construct_from_existing_cs(other.sparse_matrix);
25  copy(&other.sparse_matrix);
26 }
27 
28 /** Copy constructor from an existing "cs" CSparse data structure */
29 CSparseMatrix::CSparseMatrix(const cs* const sm)
30 {
31  construct_from_existing_cs(*sm);
32  copy(sm);
33 }
34 
35 /** Copy the data from an existing "cs" CSparse data structure */
36 void CSparseMatrix::copy(const cs* const sm)
37 {
38  ASSERTMSG_(
39  sm->nz == -1,
40  "I expected a column-compressed sparse matrix, not a triplet form.")
41 
42  sparse_matrix.m = sm->m;
43  sparse_matrix.n = sm->n;
44  sparse_matrix.nz = sm->nz;
45  sparse_matrix.nzmax = sm->nzmax;
46 
47  // Do it in a different way depending on it being triplet or compressed
48  // format:
49  ::memcpy(sparse_matrix.i, sm->i, sizeof(int) * sm->nzmax);
50  ::memcpy(sparse_matrix.p, sm->p, sizeof(int) * (sm->n + 1));
51  ::memcpy(sparse_matrix.x, sm->x, sizeof(double) * sm->nzmax);
52 }
53 
54 /** Fast copy the data from an existing "cs" CSparse data structure, copying the
55  * pointers and leaving NULLs in the source structure. */
56 void CSparseMatrix::copy_fast(cs* const sm)
57 {
58  // This method will work for either triplet or compressed format:
59 
60  // Free previous contents, if any.
61  internal_free_mem();
62 
63  // Fast copy / Move:
64  sparse_matrix.m = sm->m;
65  sparse_matrix.n = sm->n;
66  sparse_matrix.nz = sm->nz;
67  sparse_matrix.nzmax = sm->nzmax;
68 
69  sparse_matrix.i = sm->i;
70  sparse_matrix.p = sm->p;
71  sparse_matrix.x = sm->x;
72 
73  // Mark source as empty:
74  sm->i = nullptr;
75  sm->p = nullptr;
76  sm->x = nullptr;
77 }
78 
79 /** Fast swap contents with another sparse matrix */
81 {
82  // Fast copy / Move:
83  std::swap(sparse_matrix.m, other.sparse_matrix.m);
84  std::swap(sparse_matrix.n, sparse_matrix.n);
85  std::swap(sparse_matrix.nz, other.sparse_matrix.nz);
86  std::swap(sparse_matrix.nzmax, other.sparse_matrix.nzmax);
87 
88  std::swap(sparse_matrix.i, other.sparse_matrix.i);
89  std::swap(sparse_matrix.p, other.sparse_matrix.p);
90  std::swap(sparse_matrix.x, other.sparse_matrix.x);
91 }
92 
93 // Dtor
94 CSparseMatrix::~CSparseMatrix() { internal_free_mem(); }
95 /** Erase all previous contents and leave the matrix as a "triplet" 1x1 matrix
96  * without any data. */
97 void CSparseMatrix::clear(const size_t nRows, const size_t nCols)
98 {
99  // Free old data:
100  internal_free_mem();
101 
102  // Init as 1x1 triplet:
103  sparse_matrix.nzmax = 1;
104  sparse_matrix.m = nRows;
105  sparse_matrix.n = nCols;
106  sparse_matrix.i = (int*)malloc(sizeof(int) * sparse_matrix.nzmax);
107  sparse_matrix.p = (int*)malloc(sizeof(int) * (sparse_matrix.n + 1));
108  sparse_matrix.x = (double*)malloc(sizeof(double) * sparse_matrix.nzmax);
109  sparse_matrix.nz = 0; // >=0 -> triplet format.
110 }
111 
112 /** free buffers (deallocate the memory of the i,p,x buffers) */
114 {
115  cs_free(sparse_matrix.i);
116  cs_free(sparse_matrix.p);
117  cs_free(sparse_matrix.x);
118 }
119 
120 /** Initialization from a triplet "cs", which is first compressed */
122 {
123  cs* sm = cs_compress(&triplet);
124  copy_fast(sm);
125  cs_spfree(sm); // This will release just the "cs" structure itself, not the
126  // internal buffers, by now set to NULL.
127 }
128 
129 // To be called by constructors only, assume previous pointers are trash and
130 // overwrite them:
131 // This ONLY allocate the memory, doesn't fill it.
133 {
134  ASSERTMSG_(
135  sm.nz == -1,
136  "I expected a column-compressed sparse matrix, not a triplet form.")
137  sparse_matrix.i = (int*)malloc(sizeof(int) * sm.nzmax);
138  sparse_matrix.p = (int*)malloc(sizeof(int) * (sm.n + 1));
139  sparse_matrix.x = (double*)malloc(sizeof(double) * sm.nzmax);
140 }
141 
142 /** Create an initially empty sparse matrix, in the "triplet" form.
143 * Notice that you must call "compressFromTriplet" after populating the matrix
144 * and before using the math operatons on this matrix.
145 * The initial size can be later on extended with insert_entry() or
146 * setRowCount() & setColCount().
147 */
148 CSparseMatrix::CSparseMatrix(const size_t nRows, const size_t nCols)
149 {
150  sparse_matrix.nzmax = 1;
151  sparse_matrix.m = nRows;
152  sparse_matrix.n = nCols;
153  sparse_matrix.i = (int*)malloc(sizeof(int) * sparse_matrix.nzmax);
154  sparse_matrix.p = (int*)malloc(sizeof(int) * (sparse_matrix.n + 1));
155  sparse_matrix.x = (double*)malloc(sizeof(double) * sparse_matrix.nzmax);
156  sparse_matrix.nz = 0;
157 }
158 
159 /** Insert an element into a "cs", return false on error. */
161  const size_t row, const size_t col, const double val)
162 {
163  if (!isTriplet())
165  "insert_entry() is only available for sparse matrix in 'triplet' "
166  "format.")
167  if (!cs_entry(&sparse_matrix, row, col, val))
169  "Error inserting element in sparse matrix (out of mem?)")
170 }
171 
172 /** Copy operator from another existing object */
174 {
175  if (&other == this) return;
176 
177  cs_free(sparse_matrix.i);
178  cs_free(sparse_matrix.p);
179  cs_free(sparse_matrix.x);
180 
181  sparse_matrix.i = (int*)malloc(sizeof(int) * other.sparse_matrix.nzmax);
182  sparse_matrix.p = (int*)malloc(sizeof(int) * (other.sparse_matrix.n + 1));
183  sparse_matrix.x =
184  (double*)malloc(sizeof(double) * other.sparse_matrix.nzmax);
185  copy(&other.sparse_matrix);
186 }
187 
189 {
190  ASSERT_(
191  A.getColCount() == B.getColCount() &&
192  A.getRowCount() == B.getRowCount())
193 
194  cs* sm = cs_add(&(A.sparse_matrix), &(B.sparse_matrix), 1, 1);
195  ASSERT_(sm)
196  this->copy_fast(sm);
197  cs_spfree(sm);
198 }
199 
201 {
202  ASSERT_(A.getColCount() == B.getRowCount())
203 
204  cs* sm = cs_multiply(&(A.sparse_matrix), &(B.sparse_matrix));
205  ASSERT_(sm)
206  this->copy_fast(sm);
207  cs_spfree(sm);
208 }
209 
212  mrpt::math::CVectorDouble& out_res) const
213 {
214  ASSERT_EQUAL_(int(b.size()), int(getColCount()))
215  out_res.resize(getRowCount());
216  const double* y = &(b[0]);
217  double* x = &(out_res[0]);
218  cs_gaxpy(&sparse_matrix, y, x);
219 }
220 
222 {
223  cs* sm = cs_transpose(&sparse_matrix, 1);
224  ASSERT_(sm)
225  CSparseMatrix SM(sm);
226  cs_spfree(sm);
227  return SM;
228 }
229 
230 /** Static method to convert a "cs" structure into a dense representation of the
231  * sparse matrix.
232 */
233 void CSparseMatrix::cs2dense(const cs& SM, CMatrixDouble& d_M)
234 {
235  d_M.zeros(SM.m, SM.n);
236  if (SM.nz >= 0) // isTriplet ??
237  { // It's in triplet form.
238  for (int idx = 0; idx < SM.nz; ++idx)
239  d_M(SM.i[idx], SM.p[idx]) +=
240  SM.x[idx]; // += since the convention is that duplicate (i,j)
241  // entries add to each other.
242  }
243  else
244  { // Column compressed format:
245  ASSERT_(SM.x) // JL: Could it be nullptr and be OK???
246 
247  for (int j = 0; j < SM.n; j++)
248  {
249  const int p0 = SM.p[j];
250  const int p1 = SM.p[j + 1];
251  for (int p = p0; p < p1; p++)
252  d_M(SM.i[p], j) += SM.x[p]; // += since the convention is that
253  // duplicate (i,j) entries add to
254  // each other.
255  }
256  }
257 }
258 
260 {
261  cs2dense(sparse_matrix, d_M);
262 }
263 
265 {
266  if (!isTriplet())
268  "compressFromTriplet(): Matrix is already in column-compressed "
269  "format.")
270 
271  cs* sm = cs_compress(&this->sparse_matrix);
272  copy_fast(sm);
273  cs_spfree(sm); // This will release just the "cs" structure itself, not the
274  // internal buffers, now set to NULL.
275 }
276 
277 /** save as a dense matrix to a text file \return False on any error.
278 */
280 {
281  CMatrixDouble dense;
282  this->get_dense(dense);
283  try
284  {
285  dense.saveToTextFile(filName);
286  return true;
287  }
288  catch (...)
289  {
290  return false;
291  }
292 }
293 
294 // Format:
295 // NUM_ROWS NUM_COLS NUM_NON_ZERO_MAX
296 // row_1 col_1 value_1
297 // row_2 col_2 value_2
299 {
300  FILE* f = fopen(filName.c_str(), "wt");
301  if (!f) return false;
302 
303  // Help notes:
304  fprintf(
305  f,
306  "\
307 # This sparse matrix can be loaded in Octave/Matlab as follows:\n\
308 # D=load('file.txt');\n\
309 # SM=spconvert(D(2:end,:));\n\
310 # or...\n\
311 # m=D(1,1); n=D(1,2); nzmax=D(1,3);\n\
312 # Di=D(2:end,1); Dj=D(2:end,2); Ds=D(2:end,3);\n\
313 # SM=sparse(Di,Dj,Ds, m,n, nzmax);\n\n");
314 
315  // First line:
316  fprintf(
317  f, "%i %i %i\n", sparse_matrix.m, sparse_matrix.n,
318  sparse_matrix.nzmax); // Rows, cols, nzmax
319 
320  // Data lines:
321  if (sparse_matrix.nz >= 0) // isTriplet ??
322  { // It's in triplet form.
323  for (int i = 0; i < sparse_matrix.nzmax; i++)
324  if (sparse_matrix.x[i] != 0)
325  fprintf(
326  f, "%4i %4i %e\n", 1 + sparse_matrix.i[i],
327  1 + sparse_matrix.p[i], sparse_matrix.x[i]);
328  }
329  else
330  { // Column compressed format:
331  ASSERT_(sparse_matrix.x) // JL: Could it be nullptr and be OK???
332 
333  for (int j = 0; j < sparse_matrix.n; j++)
334  {
335  const int p0 = sparse_matrix.p[j];
336  const int p1 = sparse_matrix.p[j + 1];
337  for (int p = p0; p < p1; p++)
338  fprintf(
339  f, "%4i %4i %e\n", 1 + sparse_matrix.i[p], 1 + j,
340  sparse_matrix.x[p]);
341  }
342  }
343 
344  fclose(f);
345  return true;
346 }
347 
348 // =============== START OF: CSparseMatrix::CholeskyDecomp inner class
349 // ==============================
350 
351 /** Constructor from a square semidefinite-positive sparse matrix.
352 * The actual Cholesky decomposition takes places in this constructor.
353 * \exception std::runtime_error On non-square input matrix.
354 * \exception mrpt::math::CExceptionNotDefPos On non-semidefinite-positive
355 * matrix as input.
356 */
358  : m_symbolic_structure(nullptr),
359  m_numeric_structure(nullptr),
360  m_originalSM(&SM)
361 {
362  ASSERT_(SM.getColCount() == SM.getRowCount())
364 
365  // symbolic decomposition:
367  cs_schol(1 /* order */, &m_originalSM->sparse_matrix);
368 
369  // numeric decomposition:
372 
373  if (!m_numeric_structure)
375  "CSparseMatrix::CholeskyDecomp: Not positive definite matrix.");
376 }
377 
378 // Destructor:
380 {
381  cs_nfree(m_numeric_structure);
382  cs_sfree(m_symbolic_structure);
383 }
384 
385 /** Return the L matrix (L*L' = M), as a dense matrix. */
387 {
388  CSparseMatrix::cs2dense(*m_numeric_structure->L, L);
389 }
390 
391 /** Return the vector from a back-substitution step that solves: Ux=b */
393  const Eigen::VectorXd& b, Eigen::VectorXd& sol) const
394 {
395  ASSERT_(b.size() > 0)
396  sol.resize(b.size());
397  this->backsub(&b[0], &sol[0], b.size());
398 }
399 
400 /** Return the vector from a back-substitution step that solves: Ux=b */
402  const double* b, double* sol, const size_t N) const
403 {
404  ASSERT_(N > 0)
405  std::vector<double> tmp(N);
406 
407  cs_ipvec(
408  m_symbolic_structure->pinv, &b[0], &tmp[0], N); /* tmp = PERMUT*b */
409  // permute con. pivoting
410  cs_lsolve(m_numeric_structure->L, &tmp[0]); /* tmp = L\tmp */
411  cs_ltsolve(m_numeric_structure->L, &tmp[0]); /* tmp = L'\tmp */
412  cs_pvec(
413  m_symbolic_structure->pinv, &tmp[0], &sol[0],
414  N); /* sol = PERMUT'*tmp */
415  // unpermute con. pivoting
416 
417  // Result is now in "sol".
418 }
419 
420 /** Update the Cholesky factorization from an updated vesion of the original
421 * input, square definite-positive sparse matrix.
422 * NOTE: This new matrix MUST HAVE exactly the same sparse structure than the
423 * original one.
424 */
426 {
427  ASSERTMSG_(
428  m_originalSM->sparse_matrix.nzmax == new_SM.sparse_matrix.nzmax,
429  "New matrix doesn't have the same sparse structure!");
430  ASSERTMSG_(
431  m_originalSM->sparse_matrix.n == new_SM.sparse_matrix.n,
432  "New matrix doesn't have the same sparse structure!");
433 
434  m_originalSM = &new_SM; // Just copy the reference.
435 
436  // Release old data:
437  cs_nfree(m_numeric_structure);
438  m_numeric_structure = nullptr;
439 
440  // numeric decomposition:
441  m_numeric_structure =
442  cs_chol(&m_originalSM->sparse_matrix, m_symbolic_structure);
443  if (!m_numeric_structure)
445  "CholeskyDecomp::update: Not positive definite matrix.");
446 }
447 
448 // =============== END OF: CSparseMatrix::CholeskyDecomp inner class
449 // ==============================
#define ASSERT_EQUAL_(__A, __B)
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
size_t getRowCount() const
const CSparseMatrix * m_originalSM
A const reference to the original matrix used to build this decomposition.
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:272
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
A sparse matrix structure, wrapping T.
void compressFromTriplet()
ONLY for TRIPLET matrices: convert the matrix in a column-compressed form.
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.
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.
EIGEN_STRONG_INLINE size_t getColCount() const
Get number of columns.
Definition: eigen_plugins.h:59
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
void multiply_AB(const CSparseMatrix &A, const CSparseMatrix &B)
this = A*B
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.
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
GLsizei const GLchar ** string
Definition: glext.h:4101
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...
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:405
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
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
virtual ~CSparseMatrix()
Destructor.
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)
GLenum GLint GLint y
Definition: glext.h:3538
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:254
size_t getColCount() const
EIGEN_STRONG_INLINE size_t getRowCount() const
Get number of rows.
Definition: eigen_plugins.h:57
VECTOR backsub(const VECTOR &b) const
Return the vector from a back-substitution step that solves: Ux=b.
GLenum GLint x
Definition: glext.h:3538
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)
GLfloat GLfloat p
Definition: glext.h:6305
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