SparseMatrix.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_SparseMatrix_H
21 #define MIRTK_SparseMatrix_H
22 
23 #include "mirtk/Config.h"
24 #include "mirtk/Object.h"
25 
26 #include "mirtk/Assert.h"
27 #include "mirtk/Memory.h"
28 #include "mirtk/Vector.h"
29 #include "mirtk/Matrix.h"
30 #include "mirtk/Math.h"
31 #include "mirtk/Pair.h"
32 #include "mirtk/Array.h"
33 #include "mirtk/Algorithm.h"
34 #include "mirtk/Profiling.h"
35 
36 #include "mirtk/NumericsConfig.h"
37 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
38 # include "mirtk/Matlab.h"
39 #endif
40 
41 #include <iterator> // distance
42 
43 
44 namespace mirtk {
45 
46 
47 /**
48  * Sparse matrix with generic non-zero value type
49  */
50 template <class TEntry>
52 {
53  mirtkObjectMacro(SparseMatrix);
54 
55  // ---------------------------------------------------------------------------
56  // Types
57 public:
58 
59  /// Enumeration of implemented storage layouts, i.e., either
60  /// compressed row storage (CRS) or compressed column storage (CCS)
61  enum StorageLayout { CRS, CCS };
62 
63  /// Type of matrix entry values
64  typedef TEntry EntryType;
65 
66  /// Type of non-zero entry
67  typedef Pair<int, TEntry> Entry;
68 
69  /// List of non-zero entries
70  typedef Array<Entry> Entries;
71 
72  // ---------------------------------------------------------------------------
73  // Attributes
74 
75  /// Storage layout
77 
78  /// Number of rows
79  mirtkReadOnlyAttributeMacro(int, Rows);
80 
81  /// Number of columns
82  mirtkReadOnlyAttributeMacro(int, Cols);
83 
84  /// Number of non-zero entries
86 
87  /// Number of allocated elements
88  mirtkAttributeMacro(int, Size);
89 
90  /// Maximum number of unused entries, i.e., (_Size - _NNZ)
91  mirtkPublicAttributeMacro(int, MaxNumberOfUnusedEntries);
92 
93 protected:
94 
95  /// CRS: Index of first non-zero entry in i-th row
96  /// CCS: Row indices of non-zero entries
97  int *_Row;
98 
99  /// CRS: Column indices of non-zero entries
100  /// CCS: Index of first non-zero entry in i-th column
101  int *_Col;
102 
103  /// Non-zero entries
104  EntryType *_Data;
105 
106  /// CRS: Indices of non-zero entries for each column
107  /// CCS: Indices of non-zero entries for each row
108  Array<int> *_Index;
109 
110  /// Copy other matrix, used by copy constructor and assignment operator only
111  template <class TOtherEntry>
113 
114  /// Check non-zero entries, sort them, remove zero entries, and sum up duplicates
115  void CheckEntries(Entries &) const;
116 
117  // ---------------------------------------------------------------------------
118  // Construction/Destruction
119 public:
120 
121  /// Default constructor
123 
124  /// Construct sparse m x n matrix
125  GenericSparseMatrix(int, int = 0, StorageLayout = CCS);
126 
127  /// Construct sparse m x n matrix with specified number of non-zero entries
128  GenericSparseMatrix(int, int, int, StorageLayout = CCS);
129 
130  /// Copy constructor
131  template <class TOtherEntry>
133 
134  /// Assignment operator
135  template <class TOtherEntry>
137 
138  /// Initialize sparse matrix
139  void Initialize(int, int = 0, int = 0);
140 
141  /// Initialize sparse matrix given compressed rows (CRS) or columns (CCS)
142  void Initialize(int, int, Array<Entries> &, bool = false);
143 
144  /// Initialize sparse matrix given compressed rows (CRS) or columns (CCS)
145  void Initialize(int, int, Entries [], bool = false);
146 
147 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
148 
149  /// Initialize sparse matrix from MATLAB array
150  ///
151  /// If the input MATLAB array is a sparse matrix, this function is most
152  /// efficient when also this sparse matrix uses the CCS layout.
153  ///
154  /// \note Use this function only when MIRTK_Numerics_WITH_MATLAB is 1.
155  void Initialize(const mxArray *);
156 
157 #endif
158 
159  /// Destructor
160  virtual ~GenericSparseMatrix();
161 
162  // ---------------------------------------------------------------------------
163  // Entries
164 
165  /// Change storage layout
166  void Layout(StorageLayout);
167 
168  /// Get raw access to index and data arrays
169  int GetRawData(int *&, int *&, TEntry *&) const;
170 
171  /// Get raw access to non-zero values
172  TEntry *RawPointer(int = 0);
173 
174  /// Get raw access to non-zero values
175  const TEntry *RawPointer(int = 0) const;
176 
177  /// Reserve more memory
178  void Reserve(int);
179 
180  /// Remove any zero entries
181  void RemoveZeros();
182 
183  /// Number of non-zero entries in specified row
184  int RowNNZ(int) const;
185 
186  /// Number of non-zero entries in specified column
187  int ColNNZ(int) const;
188 
189  /// Number of non-zero entries in specified submatrix
190  int SubNNZ(int, int, int, int) const;
191 
192  /// Precompute indices to speed up successive row and column operations.
193  /// Not required for operations that only act on entries of a given row in
194  /// case of the CRS layout or columns in case of CCS layout. Column (row)
195  /// operations on a matrix in CRS (CCS) layout are significantly more
196  /// efficient after a call to this function, which however requires O(NNZ)
197  /// more memory.
198  ///
199  /// \note The precomputed index is automatically cleared whenever a new
200  /// non-zero entry is inserted or an existing one is removed.
201  void Index();
202 
203  /// Free memory needed for precomputed indices
204  void ClearIndex();
205 
206  /// Get reference to (non-zero) matrix entry
207  ///
208  /// \attention This operator always inserts a new entry if none exists.
209  /// Use Put to set an entry to zero and remove the previous
210  /// non-zero entry from the sparse matrix. Do not use to iterate
211  /// over all matrix entries as otherwise a new entry is added for
212  /// each matrix row and column index pair! Use Get instead.
213  ///
214  /// \remarks This function is not thread-safe if non-zero entry does not exist.
215  EntryType &operator ()(int, int = -1);
216 
217  /// Set value
218  /// \remarks This function is not thread-safe if non-zero entry does not exist.
219  void Put(int, int, EntryType);
220 
221  /// Get value
222  EntryType Get(int, int = -1) const;
223 
224  /// Get non-zero entries of specified row
225  /// \note This function is most efficient when the CRS layout is used.
226  void GetRow(int, Entries &) const;
227 
228  /// Set non-zero entries of specified row
229  ///
230  /// \note More efficient then Put when the CRS layout is used.
231  /// Implicitly sorts the input entries.
232  ///
233  /// \remarks This function is not thread-safe.
234  void Row(int, Entries &, bool = false);
235 
236  /// Get non-zero entries of specified row
237  /// \note This function is most efficient when the CRS layout is used.
238  Entries Row(int) const;
239 
240  /// Get non-zero entries of specified column
241  /// \note This function is most efficient when the CCS layout is used.
242  void GetCol(int, Entries &) const;
243 
244  /// Set non-zero entries of specified column
245  ///
246  /// \note More efficient then Put when the CCS layout is used.
247  /// Implicitly sorts the input entries.
248  ///
249  /// \remarks This function is not thread-safe.
250  void Col(int, Entries &, bool = false);
251 
252  /// Get non-zero entries of specified column
253  /// \note This function is most efficient when the CCS layout is used.
254  Entries Col(int) const;
255 
256  /// Get non-zero entries of specified column
257  /// \note This function is most efficient when the CCS layout is used.
258  void GetColumn(int, Entries &) const;
259 
260  /// Set non-zero entries of specified column
261  /// \note More efficient then Put when the CCS layout is used.
262  /// Implicitly sorts the input entries.
263  void Column(int, Entries &, bool = false);
264 
265  /// Get non-zero entries of specified column
266  /// \note This function is most efficient when the CCS layout is used.
267  Entries Column(int) const;
268 
269  /// Get diagonal values
270  void GetDiag(Vector &d) const;
271 
272  /// Get diagonal values
273  Vector Diag() const;
274 
275  /// Set diagonal to specified (non-zero) values
276  void Diag(const Vector &d);
277 
278  /// Set diagonal to specified (non-zero) value
279  void Diag(TEntry d);
280 
281  /// Get non-zero entries of specified submatrix
282  GenericSparseMatrix Sub(int, int, int, int) const;
283 
284  /// Set non-zero entries of specified submatrix
285  void Sub(int, int, const GenericSparseMatrix &);
286 
287  /// Free all non-zero entries
288  virtual void Clear();
289 
290  /// Set all non-zero entries to zero (i.e., remove)
291  void Zero();
292 
293  // ---------------------------------------------------------------------------
294  // Common operations
295 
296  /// Transpose matrix
297  ///
298  /// \param[in] keep_layout Whether to keep the storage layout. If \c false,
299  /// transposing a CRS matrix is achieved by simply
300  /// changing to CCS and vice versa.
301  void Transpose(bool keep_layout = false);
302 
303  /// Calculate sum of all entries in specified row
304  /// \note This function is most efficient when the CRS layout is used.
305  EntryType RowSum(int) const;
306 
307  /// Calculate sum of all entries in specified column
308  /// \note This function is most efficient when the CCS layout is used.
309  EntryType ColSum(int) const;
310 
311  /// Calculate sum of all entries in specified column
312  /// \note This function is most efficient when the CCS layout is used.
313  EntryType ColumnSum(int) const;
314 
315  /// Multiply matrix by vector, used to interface with ARPACK
316  /// \note This function is most efficient when the CRS layout is used.
317  void MultAv(EntryType [], EntryType []) const;
318 
319  /// Multiply by a scalar in-place
320  GenericSparseMatrix &operator *=(EntryType);
321 
322  /// Divide by a scalar in-place
323  GenericSparseMatrix &operator /=(EntryType);
324 
325  /// Multiply by a scalar
326  GenericSparseMatrix operator *(EntryType) const;
327 
328  /// Divide by a scalar
329  GenericSparseMatrix operator /(EntryType) const;
330 
331  /// Multiply specified row by a scalar
332  /// \note This function is most efficient when the CRS layout is used.
333  GenericSparseMatrix &ScaleRow(int, EntryType);
334 
335  /// Multiply specified column by a scalar
336  /// \note This function is most efficient when the CCS layout is used.
337  GenericSparseMatrix &ScaleCol(int, EntryType);
338 
339  /// Multiply specified column by a scalar
340  /// \note This function is most efficient when the CCS layout is used.
341  GenericSparseMatrix &ScaleColumn(int, EntryType);
342 
343  /// Whether this matrix is symmetric
344  bool IsSymmetric() const;
345 
346  /// Make square matrix symmetric by adding its transpose and divide by 2
347  ///
348  /// \param[in] extent Whether to copy the entry of existing entries to their
349  /// respective transpose entries without dividing by two.
350  /// This option can be used to create a symmetric matrix
351  /// from a lower or upper triangular matrix by simply
352  /// adding the transpose of the triangular matrix to this
353  /// (while leaving the diagonal entries unmodified).
354  void MakeSymmetric(bool extent = false);
355 
356  // ---------------------------------------------------------------------------
357  // Eigen decomposition
358 
359  /// Largest/Smallest eigenvalues
360  ///
361  /// Uses an iterative eigen solver to compute the \p k eigenvalues
362  /// which have largest or smallest magnitude, respectively, or are closest in
363  /// magnitude to the specified \p sigma value. Uses the Implicitly Restarted
364  /// Arnoldi Method implemented by ARPACK. The LU factorization used for the
365  /// shift-and-invert mode is computed using UMFPACK.
366  ///
367  /// \param[out] v Converged eigenvalues.
368  /// \param[in] k Number of requested eigenvalues.
369  /// \param[in] sigma Which eigenvalues of the spectrum, i.e., 'LM', 'LA', 'SM', 'SA',
370  /// or numeric value sigma used for shift-and-invert mode.
371  /// \param[in] p Number of Lanczos basis vectors.
372  /// \param[in] tol Ritz estimate residual <= tol*norm(this).
373  /// \param[in] maxit Maximum number of iterations.
374  /// \param[in] v0 Starting vector. By default randomly generated.
375  ///
376  /// \returns Number of converged eigenvalues.
377  ///
378  /// \note Only implemented for real double precision sparse matrices.
379  /// Use only when MIRTK_Numerics_WITH_eigs is 1.
380  int Eigenvalues(Vector &v, int k, const char *sigma = "LM",
381  int p = 0, double tol = .0, int maxit = 0, Vector *v0 = NULL) const;
382 
383  /// Eigenvectors of largest/smallest eigenvalues
384  ///
385  /// Uses an iterative eigen solver to compute the eigenvectors corresponding
386  /// to the \p k eigenvalues which have largest or smallest magnitude,
387  /// respectively, or are closest in magnitude to the specified \p sigma value.
388  /// Uses the Implicitly Restarted Arnoldi Method (IRAM) implemented by ARPACK.
389  /// The LU factorization for the shift-and-invert mode is computed using UMFPACK.
390  ///
391  /// \param[out] E Matrix of eigenvectors in columns.
392  /// \param[in] k Number of requested eigenvalues.
393  /// \param[in] sigma Which eigenvalues of the spectrum, i.e., 'LM', 'LA', 'SM', 'SA',
394  /// or numeric value sigma used for shift-and-invert mode.
395  /// \param[in] p Number of Lanczos basis vectors.
396  /// \param[in] tol Ritz estimate residual <= tol*norm(this).
397  /// \param[in] maxit Maximum number of iterations.
398  /// \param[in,out] v0 Input: Starting vector. By default randomly generated.
399  /// Output: Final residual vector.
400  ///
401  /// \returns Number of converged eigenvalues.
402  ///
403  /// \note Only implemented for real double precision sparse matrices.
404  /// Use only when MIRTK_Numerics_WITH_eigs is 1.
405  int Eigenvectors(Matrix &E, int k, const char *sigma = "LM",
406  int p = 0, double tol = .0, int maxit = 0, Vector *v0 = NULL) const;
407 
408  /// Largest/Smallest eigenvalues and -vectors
409  ///
410  /// Uses an iterative eigen solver to compute the \p k eigenvalues
411  /// which have largest or smallest magnitude, respectively, or are closest in
412  /// magnitude to the specified \p sigma value. Uses the Implicitly Restarted
413  /// Arnoldi Method implemented by ARPACK. The LU factorization used for the
414  /// shift-and-invert mode is computed using UMFPACK.
415  ///
416  /// \param[out] E Matrix of eigenvectors in columns.
417  /// \param[out] v Converged eigenvalues.
418  /// \param[in] k Number of requested eigenvalues.
419  /// \param[in] sigma Which eigenvalues of the spectrum, i.e., 'LM', 'LA', 'SM', 'SA',
420  /// or numeric value sigma used for shift-and-invert mode.
421  /// \param[in] p Number of Lanczos basis vectors.
422  /// \param[in] tol Ritz estimate residual <= tol*norm(this).
423  /// \param[in] maxit Maximum number of iterations.
424  /// \param[in] v0 Starting vector. By default randomly generated.
425  ///
426  /// \returns Number of converged eigenvalues.
427  ///
428  /// \note Only implemented for real double precision sparse matrices.
429  /// Use only when MIRTK_Numerics_WITH_eigs is 1.
430  int Eigenvectors(Matrix &E, Vector &v, int k, const char *sigma = "LM",
431  int p = 0, double tol = .0, int maxit = 0, Vector *v0 = NULL) const;
432 
433  // ---------------------------------------------------------------------------
434  // I/O
435 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
436 
437  /// Create mxArray from sparse matrix
438  ///
439  /// This function is most efficient when the CCS layout is used.
440  ///
441  /// \note Use this function only when MIRTK_Numerics_WITH_MATLAB is 1.
442  ///
443  /// \returns Array created using mxCreateSparse.
444  /// Must be deleted by caller using mxDestroyArray.
445  mxArray *MxArray() const;
446 
447 #endif
448 
449  /// Read sparse matrix from MAT-file
450  ///
451  /// This function is most efficient when the CCS layout is used.
452  ///
453  /// \note Use this function only when MIRTK_Numerics_WITH_MATLAB is 1.
454  bool ReadMAT(const char *, const char * = "A");
455 
456  /// Write sparse matrix to MAT-file
457  ///
458  /// This function is most efficient when the CCS layout is used.
459  ///
460  /// \note Use this function only when MIRTK_Numerics_WITH_MATLAB is 1.
461  bool WriteMAT(const char *, const char * = "A") const;
462 
463  /// Write matrix to MATLAB script
464  ///
465  /// This function is most efficient when the CCS layout is used.
466  void WriteMFile(const char *, const char * = "A") const;
467 };
468 
469 ////////////////////////////////////////////////////////////////////////////////
470 // Template definitions
471 ////////////////////////////////////////////////////////////////////////////////
472 
473 // =============================================================================
474 // Auxiliary functions
475 // =============================================================================
476 
477 // -----------------------------------------------------------------------------
478 template <class TEntry>
480 {
481  const int n = (_Layout == CRS ? _Cols : _Rows);
482  // Remove zero entries and check indices
483  for (typename Entries::iterator i = entries.begin(); i != entries.end(); ++i) {
484  if (i->second == TEntry(0)) {
485  typename Entries::iterator j = i; --i;
486  entries.erase(j);
487  } else if (i->first < 0 || i->first >= n) {
488  cerr << "GenericSparseMatrix::CheckEntries: Invalid "
489  << (_Layout == CRS ? "column" : "row") << " index: "
490  << i->first << endl;
491  exit(1);
492  }
493  }
494  // Sort non-zero entries
495  sort(entries.begin(), entries.end());
496  // Sum up duplicate entries
497  for (typename Entries::iterator i = entries.begin(); i != entries.end(); ++i) {
498  typename Entries::iterator j = i + 1;
499  while (j != entries.end() && i->first == j->first) {
500  i->second += j->second, ++j;
501  }
502  entries.erase(i + 1, i + std::distance(i, j));
503  }
504 }
505 
506 // =============================================================================
507 // Construction/Destruction
508 // =============================================================================
509 
510 // -----------------------------------------------------------------------------
511 template <class TEntry> template <class TOtherEntry>
514 {
515  // Free this matrix
516  Deallocate(_Row);
517  Deallocate(_Col);
518  Deallocate(_Data);
520  // Copy attributes of other matrix
521  _Layout = other._Layout;
522  _Rows = other._Rows;
523  _Cols = other._Cols;
524  _NNZ = other._NNZ;
525  _Size = other._NNZ; // disregard unused entries
526  _MaxNumberOfUnusedEntries = other._MaxNumberOfUnusedEntries;
527  // Copy non-zero entries of other matrix
528  if (_Layout == CRS) {
529  _Row = Allocate<int> (_Rows + 1);
530  _Col = Allocate<int> (_Size);
531  _Data = Allocate<TEntry>(_Size);
532  for (int r = 0; r <= _Rows; ++r) _Row[r] = other._Row[r];
533  for (int i = 0; i <= _NNZ; ++i) {
534  _Col [i] = other._Col [i];
535  _Data[i] = other._Data[i];
536  }
537  } else {
538  _Row = Allocate<int> (_Size);
539  _Col = Allocate<int> (_Cols + 1);
540  _Data = Allocate<TEntry>(_Size);
541  for (int c = 0; c <= _Cols; ++c) _Col[c] = other._Col[c];
542  for (int i = 0; i <= _NNZ; ++i) {
543  _Row [i] = other._Row [i];
544  _Data[i] = other._Data[i];
545  }
546  }
547 }
548 
549 // -----------------------------------------------------------------------------
550 template <class TEntry>
552 :
553  _Layout(layout),
554  _Rows(0),
555  _Cols(0),
556  _NNZ(0),
557  _Size(0),
558  _MaxNumberOfUnusedEntries(100),
559  _Row(NULL),
560  _Col(NULL),
561  _Data(NULL),
562  _Index(NULL)
563 {
564 }
565 
566 // -----------------------------------------------------------------------------
567 template <class TEntry>
570 :
571  _Layout(layout),
572  _Rows(m),
573  _Cols(n ? n : m),
574  _NNZ(0),
575  _Size(0),
576  _MaxNumberOfUnusedEntries(100),
577  _Row(NULL),
578  _Col(NULL),
579  _Data(NULL),
580  _Index(NULL)
581 {
582  if (_Layout == CRS) _Row = CAllocate<int>(_Rows + 1);
583  else _Col = CAllocate<int>(_Cols + 1);
584 }
585 
586 // -----------------------------------------------------------------------------
587 template <class TEntry>
589 ::GenericSparseMatrix(int m, int n, int nnz, StorageLayout layout)
590 :
591  _Layout(layout),
592  _Rows(m),
593  _Cols(n ? n : m),
594  _NNZ(0),
595  _Size(nnz),
596  _MaxNumberOfUnusedEntries(100),
597  _Row(NULL),
598  _Col(NULL),
599  _Data(NULL),
600  _Index(NULL)
601 {
602  if (_Layout == CRS) {
603  _Row = CAllocate<int>(_Rows + 1);
604  _Col = Allocate<int>(nnz);
605  } else {
606  _Row = Allocate<int>(nnz);
607  _Col = CAllocate<int>(_Cols + 1);
608  }
609  _Data = Allocate<TEntry>(nnz);
610 }
611 
612 // -----------------------------------------------------------------------------
613 template <class TEntry> template <class TOtherEntry>
616 :
617  _Row(NULL), _Col(NULL), _Data(NULL), _Index(NULL)
618 {
619  CopyAttributes(other);
620 }
621 
622 // -----------------------------------------------------------------------------
623 template <class TEntry> template <class TOtherEntry>
626 {
627  if (this != &other) {
628  Object::operator =(other);
629  CopyAttributes(other);
630  }
631  return *this;
632 }
633 
634 // -----------------------------------------------------------------------------
635 template <class TEntry>
636 void GenericSparseMatrix<TEntry>::Initialize(int m, int n, int sz)
637 {
638  if (n == 0) n = m;
639  _Rows = m;
640  _Cols = n;
641  _NNZ = 0;
642  _Size = 0;
643  Deallocate(_Row);
644  Deallocate(_Col);
645  Deallocate(_Data);
646  Deallocate(_Index);
647  if (_Rows > 0 && _Cols > 0) {
648  if (_Layout == CRS) _Row = CAllocate<int>(_Rows + 1);
649  else _Col = CAllocate<int>(_Cols + 1);
650  } else {
651  _Rows = _Cols = 0;
652  }
653  if (sz > 0) {
654  if (_Layout == CRS) _Col = Allocate<int>(sz);
655  else _Row = Allocate<int>(sz);
656  _Data = Allocate<TEntry>(sz);
657  _Size = sz;
658  }
659 }
660 
661 // -----------------------------------------------------------------------------
662 template <class TEntry>
664 ::Initialize(int m, int n, Array<Entries> &entries, bool as_is)
665 {
666  // Free sparse matrix
667  Deallocate(_Row);
668  Deallocate(_Col);
669  Deallocate(_Data);
670  Deallocate(_Index);
671  // Set attributes
672  _Rows = m, _Cols = n;
673  if (_Layout == CCS) swap(m, n);
674  // Check/sort input entries
675  if (!as_is) {
676  for (int r = 0; r < m; ++r) CheckEntries(entries[r]);
677  }
678  _NNZ = 0;
679  for (int r = 0; r < m; ++r) {
680  _NNZ += static_cast<int>(entries[r].size());
681  }
682  // Allocate memory
683  _Row = Allocate<int>(m + 1);
684  _Col = Allocate<int>(_NNZ);
685  _Data = Allocate<EntryType>(_NNZ);
686  _Size = _NNZ;
687  // Copy non-zero entries
688  int i = 0;
689  for (int r = 0; r < m; ++r) {
690  _Row[r] = i;
691  typename Entries::const_iterator entry;
692  for (entry = entries[r].begin(); entry != entries[r].end(); ++entry, ++i) {
693  _Col [i] = entry->first;
694  _Data[i] = entry->second;
695  }
696  }
697  _Row[m] = _NNZ;
698  // Swap arrays in case of CCS
699  if (_Layout == CCS) swap(_Row, _Col);
700 }
701 
702 // -----------------------------------------------------------------------------
703 template <class TEntry>
705 ::Initialize(int m, int n, Entries entries[], bool as_is)
706 {
707  // Free sparse matrix
708  Deallocate(_Row);
709  Deallocate(_Col);
710  Deallocate(_Data);
711  Deallocate(_Index);
712  // Set attributes
713  _Rows = m, _Cols = n;
714  if (_Layout == CCS) swap(m, n);
715  if (!as_is) {
716  for (int r = 0; r < m; ++r) CheckEntries(entries[r]);
717  }
718  _NNZ = 0;
719  for (int r = 0; r < m; ++r) {
720  _NNZ += static_cast<int>(entries[r].size());
721  }
722  // Allocate memory
723  _Row = Allocate<int>(m + 1);
724  _Col = Allocate<int>(_NNZ);
725  _Data = Allocate<EntryType>(_NNZ);
726  _Size = _NNZ;
727  // Copy non-zero entries
728  int i = 0;
729  for (int r = 0; r < m; ++r) {
730  _Row[r] = i;
731  typename Entries::const_iterator entry;
732  for (entry = entries[r].begin(); entry != entries[r].end(); ++entry, ++i) {
733  _Col [i] = entry->first;
734  _Data[i] = entry->second;
735  }
736  }
737  _Row[m] = _NNZ;
738  // Swap arrays in case of CCS
739  if (_Layout == CCS) swap(_Row, _Col);
740 }
741 
742 // -----------------------------------------------------------------------------
743 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
744 template <class TEntry>
745 void GenericSparseMatrix<TEntry>::Initialize(const mxArray *pm)
746 {
747  // Free sparse matrix
748  Deallocate(_Row);
749  Deallocate(_Col);
750  Deallocate(_Data);
751  Deallocate(_Index);
752  // Set attributes
753  _Rows = static_cast<int>(mxGetM(pm));
754  _Cols = static_cast<int>(mxGetN(pm));
755  // Copy matrix elements
756  if (mxIsSparse(pm)) {
757  const StorageLayout layout = _Layout;
758  // Get pointers to sparse matrix data
759  const mwIndex *ir = mxGetIr(pm);
760  const mwIndex *jc = mxGetJc(pm);
761  const double *pr = mxGetPr(pm);
762  // Allocate memory
763  _Layout = CCS;
764  _Size = _NNZ = jc[_Cols];
765  _Col = Allocate<int>(_Cols + 1);
766  _Row = Allocate<int>(_Size);
767  _Data = Allocate<EntryType>(_Size);
768  // Copy sparse matrix entries
769  for (int c = 0; c <= _Cols; ++c) {
770  _Col[c] = jc[c];
771  }
772  for (int i = 0; i < _NNZ; ++i) {
773  _Row [i] = ir[i];
774  _Data[i] = pr[i];
775  }
776  // Change layout to CRS if necessary
777  Layout(layout);
778  } else {
779  cerr << "GenericSparseMatrix::Initialize: Initialization from non-sparse mxArray not implemented" << endl;
780  exit(1);
781  }
782 }
783 #endif // MIRTK_Numerics_WITH_MATLAB
784 
785 // -----------------------------------------------------------------------------
786 template <class TEntry>
788 {
789  Deallocate(_Row);
790  Deallocate(_Col);
791  Deallocate(_Data);
792  Deallocate(_Index);
793 }
794 
795 // =============================================================================
796 // Entries
797 // =============================================================================
798 
799 // -----------------------------------------------------------------------------
800 template <class TEntry>
802 {
803  if (layout != CRS && layout != CCS) {
804  cerr << "GenericSparseMatrix::Layout: Unknown storage layout: " << layout << endl;
805  exit(1);
806  }
807  if (layout != _Layout) {
808  if (_NNZ == 0) swap(_Row, _Col);
809  else Transpose(true);
810  _Layout = layout;
811  }
812 }
813 
814 // -----------------------------------------------------------------------------
815 template <class TEntry>
816 int GenericSparseMatrix<TEntry>::GetRawData(int *&row, int *&col, TEntry *&data) const
817 {
818  row = _Row;
819  col = _Col;
820  data = _Data;
821  return _NNZ;
822 }
823 
824 // -----------------------------------------------------------------------------
825 template <class TEntry>
827 {
828  return &_Data[i];
829 }
830 
831 // -----------------------------------------------------------------------------
832 template <class TEntry>
833 const TEntry *GenericSparseMatrix<TEntry>::RawPointer(int i) const
834 {
835  return &_Data[i];
836 }
837 
838 // -----------------------------------------------------------------------------
839 template <class TEntry>
841 {
842  if (sz < _NNZ) sz = _NNZ;
843  int *&old_idx = (_Layout == CRS ? _Col : _Row);
844  int *new_idx = Allocate<int> (sz);
845  TEntry *new_data = Allocate<TEntry>(sz);
846  memcpy(new_idx, old_idx, _NNZ * sizeof(int));
847  memcpy(new_data, _Data, _NNZ * sizeof(TEntry));
848  Deallocate(old_idx);
849  Deallocate(_Data);
850  old_idx = new_idx;
851  _Data = new_data;
852  _Size = sz;
853 }
854 
855 // -----------------------------------------------------------------------------
856 template <class TEntry>
858 {
859  // CCS is equivalent to CRS of transpose matrix
860  int rows, *col, *row;
861  if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
862  else rows = _Rows, row = _Row, col = _Col;
863  // Find zero entries and overwrite them by following non-zero entries
864  int i = 0; // new position
865  int j = 0; // old position
866  for (int r = 0; r < rows; ++r) {
867  row[r] = i;
868  while (j < row[r+1]) {
869  if (_Data[j] == .0) {
870  --_NNZ;
871  } else {
872  if (i < j) col[i] = col[j], _Data[i] = _Data[j];
873  ++i;
874  }
875  ++j;
876  }
877  }
878  row[rows] = _NNZ;
879  // Free memory if number of unused entries exceeds max buffer size
880  if (_Size > _NNZ + _MaxNumberOfUnusedEntries) Reserve(_NNZ);
881 }
882 
883 // -----------------------------------------------------------------------------
884 template <class TEntry>
886 {
887  int nnz = 0;
888  if (_Layout == CRS) {
889  nnz = _Row[r+1] - _Row[r];
890  } else {
891  for (int c = 0; c < _Cols; ++c) {
892  for (int i = _Col[c]; i != _Col[c+1]; ++i) {
893  if (_Row[i] == r) ++nnz;
894  }
895  }
896  }
897  return nnz;
898 }
899 
900 // -----------------------------------------------------------------------------
901 template <class TEntry>
903 {
904  int nnz = 0;
905  if (_Layout == CCS) {
906  nnz = _Col[c+1] - _Col[c];
907  } else {
908  for (int r = 0; r < _Rows; ++r) {
909  for (int i = _Row[r]; i != _Row[r+1]; ++i) {
910  if (_Col[i] == c) ++nnz;
911  }
912  }
913  }
914  return nnz;
915 }
916 
917 // -----------------------------------------------------------------------------
918 template <class TEntry>
919 int GenericSparseMatrix<TEntry>::SubNNZ(int r1, int c1, int r2, int c2) const
920 {
921  int i, j, nnz = 0;
922  if (_Layout == CRS) {
923  for (int r = r1; r <= r2; ++r) {
924  i = _Row[r];
925  while (i != _Row[r+1] && _Col[i] < c1) ++i;
926  j = i;
927  while (j != _Row[r+1] && _Col[j] <= c2) ++j;
928  nnz += j - i;
929  }
930  } else {
931  for (int c = c1; c <= c2; ++c) {
932  i = _Col[c];
933  while (i != _Col[c+1] && _Row[i] < r1) ++i;
934  j = i;
935  while (j != _Col[c+1] && _Row[j] <= r2) ++j;
936  nnz += j - i;
937  }
938  }
939  return nnz;
940 }
941 
942 // -----------------------------------------------------------------------------
943 template <class TEntry>
945 {
946  if (!_Index) {
947  MIRTK_START_TIMING();
948  int i, j;
949  if (_Layout == CRS) {
950  _Index = Allocate<Array<int> >(_Cols);
951  Array<int> count(_Cols, 0);
952  for (i = 0; i < _NNZ; ++i) {
953  ++count[_Col[i]];
954  }
955  for (j = 0; j < _Cols; ++j) {
956  _Index[j].resize(count[j]);
957  count [j] = 0;
958  }
959  for (i = 0; i < _NNZ; ++i) {
960  j = _Col[i];
961  _Index[j][count[j]++] = i;
962  }
963  } else {
964  _Index = Allocate<Array<int> >(_Rows);
965  Array<int> count(_Rows, 0);
966  for (i = 0; i < _NNZ; ++i) {
967  ++count[_Row[i]];
968  }
969  for (j = 0; j < _Rows; ++j) {
970  _Index[j].resize(count[j]);
971  count [j] = 0;
972  }
973  for (i = 0; i < _NNZ; ++i) {
974  j = _Row[i];
975  _Index[j][count[j]++] = i;
976  }
977  }
978  MIRTK_DEBUG_TIMING(10, "building sparse matrix index");
979  }
980 }
981 
982 // -----------------------------------------------------------------------------
983 template <class TEntry>
985 {
986  Deallocate(_Index);
987 }
988 
989 // -----------------------------------------------------------------------------
990 template <class TEntry>
992 {
993  if (c < 0) c = r;
994  // CCS is equivalent to CRS of transpose matrix
995  int rows, *col, *row;
996  if (_Layout == CCS) {
997  swap(r, c);
998  row = _Col;
999  col = _Row;
1000  rows = _Cols;
1001  } else {
1002  row = _Row;
1003  col = _Col;
1004  rows = _Rows;
1005  }
1006  // Find existing non-zero entry or insert position
1007  int i;
1008  for (i = row[r]; i != row[r+1]; ++i) {
1009  if (col[i] > c) break;
1010  if (col[i] == c) return _Data[i];
1011  }
1012  // Invalidate precomputed _Index
1013  Deallocate(_Index);
1014  // Reserve memory for new number of non-zero elements
1015  if (_NNZ == _Size) {
1016  Reserve(_Size + _MaxNumberOfUnusedEntries);
1017  if (_Layout == CCS) row = _Col, col = _Row;
1018  else row = _Row, col = _Col;
1019  }
1020  // Insert new non-zero element at i-th position
1021  for (int j = _NNZ; j > i; --j) {
1022  col [j] = col [j-1];
1023  _Data[j] = _Data[j-1];
1024  }
1025  col [i] = c;
1026  _Data[i] = TEntry(0);
1027  for (int j = r + 1; j < rows; ++j) ++row[j];
1028  row[rows] = ++_NNZ;
1029  return _Data[i];
1030 }
1031 
1032 // -----------------------------------------------------------------------------
1033 template <class TEntry>
1034 void GenericSparseMatrix<TEntry>::Put(int r, int c, TEntry v)
1035 {
1036  // Remove non-zero entry if set to zero
1037  if (v == TEntry(0)) {
1038  // CCS is equivalent to CRS of transpose matrix
1039  int rows, *col, *row;
1040  if (_Layout == CCS) {
1041  swap(r, c);
1042  row = _Col;
1043  col = _Row;
1044  rows = _Cols;
1045  } else {
1046  row = _Row;
1047  col = _Col;
1048  rows = _Rows;
1049  }
1050  // Remove existing non-zero entry
1051  for (int i = row[r]; i != row[r+1]; ++i) {
1052  if (col[i] < c) continue;
1053  if (col[i] == c) {
1054  Deallocate(_Index);
1055  for (int j = i + 1; j < _NNZ; ++j) {
1056  col [j-1] = col [j];
1057  _Data[j-1] = _Data[j];
1058  }
1059  for (int j = r + 1; j < rows; ++j) --row[j];
1060  row[rows] = (--_NNZ);
1061  if (_Size > _NNZ + _MaxNumberOfUnusedEntries) {
1062  Reserve(_NNZ + _MaxNumberOfUnusedEntries);
1063  }
1064  }
1065  break;
1066  }
1067  // Otherwise, set/add non-zero entry
1068  } else {
1069  this->operator ()(r, c) = v;
1070  }
1071 }
1072 
1073 // -----------------------------------------------------------------------------
1074 template <class TEntry>
1075 TEntry GenericSparseMatrix<TEntry>::Get(int r, int c) const
1076 {
1077  if (c < 0) c = r;
1078  if (_Layout == CRS) {
1079  for (int i = _Row[r]; i != _Row[r+1]; ++i) {
1080  if (_Col[i] == c) return _Data[i];
1081  if (_Col[i] > c) break;
1082  }
1083  } else {
1084  for (int i = _Col[c]; i != _Col[c+1]; ++i) {
1085  if (_Row[i] == r) return _Data[i];
1086  if (_Row[i] > r) break;
1087  }
1088  }
1089  return TEntry(0);
1090 }
1091 
1092 // -----------------------------------------------------------------------------
1093 template <class TEntry>
1094 void GenericSparseMatrix<TEntry>::Row(int r, Entries &row, bool as_is)
1095 {
1096  if (!as_is) {
1097  // Remove zero entries
1098  for (typename Entries::iterator i = row.begin(); i != row.end(); ++i) {
1099  if (i->second == TEntry(0)) {
1100  typename Entries::iterator j = i; --i;
1101  row.erase(j);
1102  }
1103  }
1104  // Sort non-zero entries
1105  sort(row.begin(), row.end());
1106  }
1107  // Set non-zero entries of r-th row
1108  if (_Layout == CRS) {
1109  // Number of additional (positive) or fewer (negative) row entries
1110  int dnnz = static_cast<int>(row.size()) - (_Row[r+1] - _Row[r]);
1111  // Allocate more memory if needed
1112  if (_NNZ + dnnz > _Size) Reserve(_NNZ + dnnz);
1113  // Increase/Decrease counter of non-zero entries
1114  _NNZ += dnnz;
1115  // Move non-zero entries of rows > r to leave just enough space for
1116  // the new non-zero entries of the r-th row
1117  if (dnnz != 0) {
1118  for (int j = r + 1; j < _Rows; ++j) _Row[j] += dnnz;
1119  }
1120  _Row[_Rows] = _NNZ;
1121  if (dnnz < 0) {
1122  for (int i = _Row[r+1], j = i - dnnz; i < _NNZ; ++i, ++j) {
1123  _Col [i] = _Col [j];
1124  _Data[i] = _Data[j];
1125  }
1126  } else if (dnnz > 0) {
1127  for (int i = _NNZ - 1, j = i - dnnz; i >= _Row[r+1]; --i, --j) {
1128  _Col [i] = _Col [j];
1129  _Data[i] = _Data[j];
1130  }
1131  }
1132  // Set non-zero entries of r-th row
1133  bool index_invalid = (dnnz != 0);
1134  typename Entries::const_iterator entry = row.begin();
1135  for (int i = _Row[r]; i != _Row[r+1]; ++i, ++entry) {
1136  if (_Col[i] != entry->first) {
1137  _Col[i] = entry->first;
1138  index_invalid = true;
1139  }
1140  _Data[i] = entry->second;
1141  }
1142  // Delete invalid precomputed index
1143  if (index_invalid) Deallocate(_Index);
1144  // Free memory if number of unused entries exceeds max buffer size
1145  if (_NNZ < _Size - _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1146  } else {
1147  // Preallocate more memory if needed
1148  if (_NNZ + static_cast<int>(row.size()) > _Size) {
1149  Reserve(_NNZ + static_cast<int>(row.size()));
1150  }
1151  // Insert new non-zero row entries
1152  typename Entries::const_iterator entry = row.begin();
1153  for (; entry != row.end(); ++entry) {
1154  this->operator ()(r, entry->first) = entry->second;
1155  }
1156  // Free memory if number of unused entries exceeds max buffer size
1157  if (_Size > _NNZ + _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1158  }
1159 }
1160 
1161 // -----------------------------------------------------------------------------
1162 template <class TEntry>
1164 {
1165  if (_Layout == CRS) {
1166  row.resize(_Row[r+1] - _Row[r]);
1167  for (int i = _Row[r], c = 0; i != _Row[r+1]; ++i, ++c) {
1168  row[c] = MakePair(_Col[i], _Data[i]);
1169  }
1170  } else {
1171  if (_Index) {
1172  int i, c = 0;
1173  row.resize(_Index[r].size());
1174  for (size_t j = 0; j < _Index[r].size(); ++j) {
1175  i = _Index[r][j];
1176  while (i >= _Col[c+1]) ++c;
1177  row[j] = MakePair(c, _Data[i]);
1178  }
1179  } else {
1180  row.clear();
1181  for (int c = 0; c < _Cols; ++c) {
1182  for (int i = _Col[c]; i != _Col[c+1]; ++i) {
1183  if (_Row[i] < r) continue;
1184  if (_Row[i] == r) row.push_back(MakePair(c, _Data[i]));
1185  break;
1186  }
1187  }
1188  }
1189  }
1190 }
1191 
1192 // -----------------------------------------------------------------------------
1193 template <class TEntry>
1196 {
1197  Entries row;
1198  GetRow(r, row);
1199  return row;
1200 }
1201 
1202 // -----------------------------------------------------------------------------
1203 template <class TEntry>
1204 void GenericSparseMatrix<TEntry>::Col(int c, Entries &col, bool as_is)
1205 {
1206  if (!as_is) {
1207  // Remove zero entries
1208  for (typename Entries::iterator i = col.begin(); i != col.end(); ++i) {
1209  if (i->second == TEntry(0)) {
1210  typename Entries::iterator j = i; --i;
1211  col.erase(j);
1212  }
1213  }
1214  // Sort non-zero entries
1215  sort(col.begin(), col.end());
1216  }
1217  // Set non-zero entries of c-th column
1218  if (_Layout == CCS) {
1219  // Number of additional (positive) or fewer (negative) column entries
1220  int dnnz = static_cast<int>(col.size()) - (_Col[c+1] - _Col[c]);
1221  // Allocate more memory if needed
1222  if (_NNZ + dnnz > _Size) Reserve(_NNZ + dnnz);
1223  // Increase/Decrease counter of non-zero entries
1224  _NNZ += dnnz;
1225  // Move non-zero entries of columns > c to leave just enough space for
1226  // the new non-zero entries of the c-th column
1227  if (dnnz != 0) {
1228  for (int j = c + 1; j < _Cols; ++j) _Col[j] += dnnz;
1229  }
1230  _Col[_Cols] = _NNZ;
1231  if (dnnz < 0) {
1232  for (int i = _Col[c+1], j = i - dnnz; i < _NNZ; ++i, ++j) {
1233  _Row [i] = _Row [j];
1234  _Data[i] = _Data[j];
1235  }
1236  } else if (dnnz > 0) {
1237  for (int i = _NNZ - 1, j = i - dnnz; i >= _Col[c+1]; --i, --j) {
1238  _Row [i] = _Row [j];
1239  _Data[i] = _Data[j];
1240  }
1241  }
1242  // Set non-zero entries of r-th row
1243  bool index_invalid = (dnnz != 0);
1244  typename Entries::const_iterator entry = col.begin();
1245  for (int i = _Col[c]; i != _Col[c+1]; ++i, ++entry) {
1246  if (_Row[i] != entry->first) {
1247  _Row[i] = entry->first;
1248  index_invalid = true;
1249  }
1250  _Data[i] = entry->second;
1251  }
1252  // Delete invalid precomputed _Index
1253  if (index_invalid) Deallocate(_Index);
1254  // Free memory if number of unused entries exceeds max buffer size
1255  if (_NNZ < _Size - _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1256  } else {
1257  // Preallocate more memory if needed
1258  if (_NNZ + static_cast<int>(col.size()) > _Size) {
1259  Reserve(_NNZ + static_cast<int>(col.size()));
1260  }
1261  // Insert new non-zero row entries
1262  typename Entries::const_iterator entry = col.begin();
1263  for (; entry != col.end(); ++entry) {
1264  this->operator ()(entry->first, c) = entry->second;
1265  }
1266  // Free memory if number of unused entries exceeds max buffer size
1267  if (_Size > _NNZ + _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1268  }
1269 }
1270 
1271 // -----------------------------------------------------------------------------
1272 template <class TEntry>
1273 void GenericSparseMatrix<TEntry>::Column(int c, Entries &col, bool as_is)
1274 {
1275  Col(c, col, as_is);
1276 }
1277 
1278 // -----------------------------------------------------------------------------
1279 template <class TEntry>
1281 {
1282  if (_Layout == CRS) {
1283  if (_Index) {
1284  int i, r = 0;
1285  col.resize(_Index[c].size());
1286  for (size_t j = 0; j < _Index[c].size(); ++j) {
1287  i = _Index[c][j];
1288  while (i >= _Row[r+1]) ++r;
1289  col[j] = MakePair(r, _Data[i]);
1290  }
1291  } else {
1292  col.clear();
1293  for (int r = 0; r < _Rows; ++r) {
1294  for (int i = _Row[r]; i != _Row[r+1]; ++i) {
1295  if (_Col[i] < c) continue;
1296  if (_Col[i] == c) col.push_back(MakePair(r, _Data[i]));
1297  break;
1298  }
1299  }
1300  }
1301  } else {
1302  col.resize(_Col[c+1] - _Col[c]);
1303  for (int i = _Col[c], r = 0; i != _Col[c+1]; ++i, ++r) {
1304  col[r] = MakePair(_Row[i], _Data[i]);
1305  }
1306  }
1307 }
1308 
1309 // -----------------------------------------------------------------------------
1310 template <class TEntry>
1312 {
1313  GetCol(c, col);
1314 }
1315 
1316 // -----------------------------------------------------------------------------
1317 template <class TEntry>
1320 {
1321  Entries col;
1322  GetCol(c, col);
1323  return col;
1324 }
1325 
1326 // -----------------------------------------------------------------------------
1327 template <class TEntry>
1330 {
1331  return Col(c);
1332 }
1333 
1334 // -----------------------------------------------------------------------------
1335 template <class TEntry>
1337 {
1338  if (_Rows != _Cols) {
1339  cerr << "GenericSparseMatrix::GetDiag: Matrix must be square" << endl;
1340  exit(1);
1341  }
1342  d.Initialize(_Rows);
1343  for (int i = 0; i < _Rows; ++i) d(i) = this->Get(i, i);
1344 }
1345 
1346 // -----------------------------------------------------------------------------
1347 template <class TEntry>
1349 {
1350  Vector d;
1351  GetDiag(d);
1352  return d;
1353 }
1354 
1355 // -----------------------------------------------------------------------------
1356 template <class TEntry>
1358 {
1359  if (_Rows != _Cols) {
1360  cerr << "GenericSparseMatrix::Diag: Matrix must be square" << endl;
1361  exit(1);
1362  }
1363  if (d.Rows() != _Rows) {
1364  cerr << "GenericSparseMatrix::Diag: Invalid vector size" << endl;
1365  exit(1);
1366  }
1367  // CCS is equivalent to CRS of transpose matrix
1368  int rows, *col, *row;
1369  if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
1370  else rows = _Rows, row = _Row, col = _Col;
1371  // Count number of missing diagonal entries
1372  int i, j, r, dnnz = 0;
1373  for (r = 0; r < rows; ++r) {
1374  if (d(r) != .0) {
1375  i = row[r];
1376  while (i < row[r+1] && col[i] < r) ++i;
1377  if (i == row[r+1] || col[i] != r) ++dnnz;
1378  }
1379  }
1380  // Reserve memory for missing diagonal entries
1381  if (_NNZ + dnnz > _Size) {
1382  Reserve(_NNZ + dnnz);
1383  if (_Layout == CCS) row = _Col, col = _Row;
1384  else row = _Row, col = _Col;
1385  }
1386  // Delete invalid precomputed _Index
1387  if (dnnz != 0) Deallocate(_Index);
1388  // Insert/set diagonal entries
1389  _NNZ += dnnz;
1390  row[rows] = _NNZ; // new nnz
1391  i = _NNZ - 1 - dnnz; // old position
1392  j = _NNZ - 1; // new position
1393  r = rows - 1; // iterate entries in reverse order
1394  while (r >= 0 && i < j) {
1395  // Move columns above diagonal to make space for new entries
1396  for (; i >= row[r] && col[i] > r; --i, --j) {
1397  col[j] = col[i], _Data[j] = _Data[i];
1398  }
1399  // Set/insert diagonal entry
1400  if (i >= row[r] && col[i] == r) {
1401  col[j] = r, _Data[j] = static_cast<TEntry>(d(r)), --i, --j;
1402  } else if (d(r) != .0) {
1403  col[j] = r, _Data[j] = static_cast<TEntry>(d(r)), --j;
1404  }
1405  // Move columns below diagonal to make space for new entries
1406  if (i < j) {
1407  for (; i >= row[r]; --i, --j) {
1408  col[j] = col[i], _Data[j] = _Data[i];
1409  }
1410  } else {
1411  i = j = row[r] - 1;
1412  }
1413  // Update row start index
1414  row[r] = j + 1;
1415  // Next row above this one
1416  --r;
1417  }
1418  // ...just copy remaining entries and modify the diagonal value in each row
1419  mirtkAssert(i == j, "no more missing diagonal entries");
1420  while (r >= 0) {
1421  if (d(r) != .0) {
1422  // Leave columns above diagonal untouched
1423  while (i >= row[r] && col[i] > r) --i;
1424  // Modify diagonal entry of this row
1425  mirtkAssert(i >= row[r] && col[i] == r, "diagonal entry must exist");
1426  _Data[i] = static_cast<TEntry>(d(r));
1427  // Leave columns below diagonal untouched
1428  }
1429  i = row[r] - 1;
1430  // Next row above this one
1431  --r;
1432  }
1433  // Discard previous diagonal entries which are now zero
1434  RemoveZeros();
1435 }
1436 
1437 // -----------------------------------------------------------------------------
1438 template <class TEntry>
1440 {
1441  Diag(Vector(_Rows, static_cast<double>(d)));
1442 }
1443 
1444 // -----------------------------------------------------------------------------
1445 template <class TEntry>
1447 GenericSparseMatrix<TEntry>::Sub(int r1, int c1, int r2, int c2) const
1448 {
1449  GenericSparseMatrix<TEntry> sub(r2 - r1 + 1, c2 - c1 + 1, _Layout);
1450  cerr << "GenericSparseMatrix::Sub (getter): Not implemented" << endl;
1451  exit(1);
1452  return sub;
1453 }
1454 
1455 // -----------------------------------------------------------------------------
1456 template <class TEntry>
1458 ::Sub(int r1, int c1, const GenericSparseMatrix &sub)
1459 {
1460  MIRTK_START_TIMING();
1461  int r2 = r1 + sub.Rows() - 1;
1462  int c2 = c1 + sub.Cols() - 1;
1463  if (r2 >= _Rows || c2 >= _Cols) {
1464  cerr << "GenericSparseMatrix::Sub (setter): " << sub.Rows() << " x " << sub.Cols()
1465  << " submatrix starting at (" << r1 << ", " << c1 << ") exceeds matrix index range [0, "
1466  << _Rows-1 << "] x [0, " << _Cols-1 << "]" << endl;
1467  exit(1);
1468  }
1469  if (_Layout != sub.Layout()) {
1470  // TODO: Accept also submatrix in different storage layout
1471  cerr << "GenericSparseMatrix::Sub (setter): Submatrix must have same layout as this matrix" << endl;
1472  exit(1);
1473  }
1474  // Determine new number of non-zero entries
1475  const int dif_nnz = sub._NNZ - this->SubNNZ(r1, c1, r2, c2);
1476  const int new_nnz = _NNZ + dif_nnz;
1477  // Allocate more memory if needed
1478  if (new_nnz > _Size) Reserve(new_nnz);
1479  // CCS is equivalent to CRS of transpose matrix
1480  int rows, *col, *row;
1481  const int *sub_col, *sub_row;
1482  if (_Layout == CCS) {
1483  swap(r1, c1);
1484  swap(r2, c2);
1485  row = _Col;
1486  col = _Row;
1487  rows = _Cols;
1488  sub_row = sub._Col;
1489  sub_col = sub._Row;
1490  } else {
1491  row = _Row;
1492  col = _Col;
1493  rows = _Rows;
1494  sub_row = sub._Row;
1495  sub_col = sub._Col;
1496  }
1497  // New position of new or existing i-th non-zero entry
1498  int i, k, k1, k2, j = new_nnz - 1;
1499  // Move non-zero entries below submatrix to the end
1500  for (i = _NNZ - 1; i >= row[r2 + 1]; --i, --j) {
1501  col [j] = col [i];
1502  _Data[j] = _Data[i];
1503  }
1504  for (int r = r2 + 1; r < rows; ++r) row[r] += dif_nnz;
1505  row[rows] = _NNZ = new_nnz;
1506  // Insert submatrix rows in reverse order
1507  for (int r = r2; r >= r1; --r) {
1508  // Existing non-zero entries with column index c > c2
1509  for (i = row[r+1] - 1; i >= row[r] && col[i] > c2; --i, --j) {
1510  col [j] = col [i];
1511  _Data[j] = _Data[i];
1512  }
1513  // Skip existing non-zero entries with column index c1 <= c <= c2
1514  while (i >= row[r] && col[i] >= c1) --i;
1515  // ...and replace them by new submatrix entries instead
1516  k1 = sub_row[r - r1];
1517  k2 = sub_row[r - r1 + 1] - 1;
1518  for (k = k2; k >= k1; --k, --j) {
1519  col [j] = c1 + sub_col[k];
1520  _Data[j] = sub._Data[k];
1521  }
1522  // Existing non-zero entries with column index c < c1
1523  for (; i >= row[r]; --i, --j) {
1524  col [j] = col [i];
1525  _Data[j] = _Data[i];
1526  }
1527  // Row start index
1528  row[r] = j + 1;
1529  }
1530  MIRTK_DEBUG_TIMING(7, "GenericSparseMatrix::Sub (setter)");
1531 }
1532 
1533 // -----------------------------------------------------------------------------
1534 template <class TEntry>
1536 {
1537  ClearIndex();
1538  if (_Layout == CRS) {
1539  if (_Row) memset(_Row, 0, (_Rows + 1) * sizeof(int));
1540  Deallocate(_Col);
1541  } else {
1542  Deallocate(_Row);
1543  if (_Col) memset(_Col, 0, (_Cols + 1) * sizeof(int));
1544  }
1545  Deallocate(_Data);
1546  _Rows = _Cols = _Size = _NNZ = 0;
1547 }
1548 
1549 // -----------------------------------------------------------------------------
1550 template <class TEntry>
1552 {
1553  _NNZ = 0;
1554  if (_Layout == CRS) {
1555  if (_Row) memset(_Row, 0, (_Rows + 1) * sizeof(int));
1556  } else {
1557  if (_Col) memset(_Col, 0, (_Cols + 1) * sizeof(int));
1558  }
1559  Deallocate(_Index);
1560 }
1561 
1562 // =============================================================================
1563 // Common operations
1564 // =============================================================================
1565 
1566 // -----------------------------------------------------------------------------
1567 template <class TEntry>
1569 {
1570  if (keep_layout) {
1571  Index(); // makes Col/Row retrieval efficient
1572  Array<Entries> entries;
1573  if (_Layout == CRS) {
1574  entries.resize(_Cols);
1575  for (int c = 0; c < _Cols; ++c) entries[c] = Col(c);
1576  _Layout = CCS; // *after* all columns are retrieved
1577  } else {
1578  entries.resize(_Rows);
1579  for (int r = 0; r < _Rows; ++r) entries[r] = Row(r);
1580  _Layout = CRS; // *after* all rows are retrieved
1581  }
1582  Initialize(_Cols, _Rows, entries);
1583  } else {
1584  if (_Layout == CRS) _Layout = CCS;
1585  else _Layout = CRS;
1586  swap(_Rows, _Cols);
1587  }
1588 }
1589 
1590 // -----------------------------------------------------------------------------
1591 template <class TEntry>
1593 {
1594  TEntry s = TEntry(0);
1595  if (_Layout == CRS) {
1596  for (int i = _Row[r]; i != _Row[r+1]; ++i) s += _Data[i];
1597  } else {
1598  if (_Index) {
1599  for (size_t c = 0; c < _Index[r].size(); ++c) {
1600  s += _Data[_Index[r][c]];
1601  }
1602  } else {
1603  for (int c = 0; c < _Cols; ++c) {
1604  for (int i = _Col[c]; i != _Col[c+1]; ++i) {
1605  if (_Row[i] < r) continue;
1606  if (_Row[i] == r) s += _Data[i];
1607  break;
1608  }
1609  }
1610  }
1611  }
1612  return s;
1613 }
1614 
1615 // -----------------------------------------------------------------------------
1616 template <class TEntry>
1618 {
1619  TEntry s = TEntry(0);
1620  if (_Layout == CRS) {
1621  if (_Index) {
1622  for (size_t r = 0; r < _Index[c].size(); ++r) {
1623  s += _Data[_Index[c][r]];
1624  }
1625  } else {
1626  for (int r = 0; r < _Rows; ++r) {
1627  for (int i = _Row[r]; i != _Row[r+1]; ++i) {
1628  if (_Col[i] < c) continue;
1629  if (_Col[i] == c) s += _Data[i];
1630  break;
1631  }
1632  }
1633  }
1634  } else {
1635  for (int i = _Col[c]; i != _Col[c+1]; ++i) s += _Data[i];
1636  }
1637  return s;
1638 }
1639 
1640 // -----------------------------------------------------------------------------
1641 template <class TEntry>
1643 {
1644  return ColSum(c);
1645 }
1646 
1647 // -----------------------------------------------------------------------------
1648 template <class TEntry>
1649 void GenericSparseMatrix<TEntry>::MultAv(TEntry v[], TEntry w[]) const
1650 {
1651  const TEntry zero(0);
1652  if (_Layout == CRS) {
1653  for (int r = 0; r < _Rows; ++r) {
1654  w[r] = zero;
1655  for (int i = _Row[r]; i != _Row[r+1]; ++i) w[r] += _Data[i] * v[_Col[i]];
1656  }
1657  } else {
1658  if (_Index) {
1659  int i;
1660  for (int r = 0; r < _Rows; ++r) {
1661  w[r] = zero;
1662  for (size_t c = 0; c < _Index[r].size(); ++c) {
1663  i = _Index[r][c];
1664  w[r] += _Data[i] * v[_Col[i]];
1665  }
1666  }
1667  } else {
1668  for (int r = 0; r < _Rows; ++r) w[r] = zero;
1669  for (int c = 0; c < _Cols; ++c) {
1670  for (int i = _Col[c]; i != _Col[c+1]; ++i) {
1671  w[_Row[c]] += _Data[i] * v[c];
1672  }
1673  }
1674  }
1675  }
1676 }
1677 
1678 // -----------------------------------------------------------------------------
1679 template <class TEntry>
1681 {
1682  for (int i = 0; i < _NNZ; ++i) _Data[i] *= s;
1683  return *this;
1684 }
1685 
1686 // -----------------------------------------------------------------------------
1687 template <class TEntry>
1689 {
1690  for (int i = 0; i < _NNZ; ++i) _Data[i] /= s;
1691  return *this;
1692 }
1693 
1694 // -----------------------------------------------------------------------------
1695 template <class TEntry>
1697 {
1698  GenericSparseMatrix<TEntry> m(*this);
1699  return m *= s;
1700 }
1701 
1702 // -----------------------------------------------------------------------------
1703 template <class TEntry>
1705 {
1706  GenericSparseMatrix<TEntry> m(*this);
1707  return m /= s;
1708 }
1709 
1710 // -----------------------------------------------------------------------------
1711 template <class TEntry>
1713 {
1714  if (_Layout == CRS) {
1715  for (int i = _Row[r]; i != _Row[r+1]; ++i) _Data[i] *= s;
1716  } else {
1717  if (_Index) {
1718  for (size_t c = 0; c < _Index[r].size(); ++c) {
1719  _Data[_Index[r][c]] *= s;
1720  }
1721  } else {
1722  for (int c = 0; c < _Cols; ++c) {
1723  for (int i = _Col[c]; i != _Col[c+1]; ++i) {
1724  if (_Row[i] < r) continue;
1725  if (_Row[i] == r) _Data[i] *= s;
1726  break;
1727  }
1728  }
1729  }
1730  }
1731  return *this;
1732 }
1733 
1734 // -----------------------------------------------------------------------------
1735 template <class TEntry>
1737 {
1738  if (_Layout == CRS) {
1739  if (_Index) {
1740  for (size_t r = 0; r < _Index[c].size(); ++r) {
1741  _Data[_Index[c][r]] *= s;
1742  }
1743  } else {
1744  for (int r = 0; r < _Rows; ++r) {
1745  for (int i = _Row[r]; i != _Row[r+1]; ++i) {
1746  if (_Col[i] < c) continue;
1747  if (_Col[i] == c) _Data[i] *= s;
1748  break;
1749  }
1750  }
1751  }
1752  } else {
1753  for (int i = _Col[c]; i != _Col[c+1]; ++i) _Data[i] *= s;
1754  }
1755  return *this;
1756 }
1757 
1758 // -----------------------------------------------------------------------------
1759 template <class TEntry>
1761 {
1762  return ScaleColumn(c, s);
1763 }
1764 
1765 // -----------------------------------------------------------------------------
1766 template <class TEntry>
1768 {
1769  if (_Rows != _Cols) return false;
1770  // CCS is equivalent to CRS of transpose matrix
1771  int rows, *col, *row;
1772  if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
1773  else rows = _Rows, row = _Row, col = _Col;
1774  // Compare transposed upper triangular submatrix to lower triangular submatrix
1775  int i, iend, j, jend, r, c;
1776  for (r = 0; r < rows-1; ++r) {
1777  i = row[r];
1778  iend = row[r+1];
1779  while (i < iend && col[i] < r) ++i;
1780  while (i < iend) {
1781  c = col[i];
1782  j = row[c];
1783  jend = row[c+1];
1784  while (j < jend && col[j] < r) ++j;
1785  if (j == jend || col[j] != r || !fequal(_Data[i], _Data[j])) {
1786  return false;
1787  }
1788  ++i;
1789  }
1790  }
1791  return true;
1792 }
1793 
1794 // -----------------------------------------------------------------------------
1795 template <class TEntry>
1797 {
1798  if (_Rows != _Cols) {
1799  cerr << "GenericSparseMatrix::MakeSymmetric: Matrix must be square" << endl;
1800  exit(1);
1801  }
1802  // CCS is equivalent to CRS of transpose matrix
1803  int rows, *col, *row;
1804  if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
1805  else rows = _Rows, row = _Row, col = _Col;
1806  // Count number of missing transposed entries
1807  int i, j, k, r, c, dnnz = 0;
1808  for (r = 0; r < rows; ++r) {
1809  for (i = row[r]; i < row[r+1]; ++i) {
1810  c = col[i];
1811  j = row[c];
1812  while (j < row[c+1] && col[j] < r) ++j;
1813  if (j < row[c+1] && col[j] != r) ++dnnz;
1814  }
1815  }
1816  // Reserve memory for missing transposed entries
1817  if (_NNZ + dnnz > _Size) {
1818  Reserve(_NNZ + dnnz);
1819  if (_Layout == CCS) row = _Col, col = _Row;
1820  else row = _Row, col = _Col;
1821  }
1822  // Add values above main diagonal to those below it and divide by two
1823  // Note that this way new elements are only added to rows below the current
1824  // one and therefore the current iteration bounds are not affected by it.
1825  for (r = 0; r < rows-1; ++r) {
1826  i = row[r];
1827  while (i < row[r+1] && col[i] < r) ++i;
1828  while (i < row[r+1]) {
1829  c = col[i];
1830  j = row[c];
1831  while (j < row[c+1] && col[j] < r) ++j;
1832  if (j < row[c+1] && col[j] == r) {
1833  _Data[i] = _Data[j] = (_Data[i] + _Data[j]) / 2;
1834  } else {
1835  if (!extent) _Data[i] = _Data[i] / 2;
1836  for (k = _NNZ; k > j; --k) {
1837  col [k] = col [k-1];
1838  _Data[k] = _Data[k-1];
1839  }
1840  col [j] = r;
1841  _Data[j] = _Data[i];
1842  for (k = c + 1; k < rows; ++k) ++row[k];
1843  row[rows] = ++_NNZ;
1844  }
1845  ++i;
1846  }
1847  }
1848 }
1849 
1850 // =============================================================================
1851 // I/O
1852 // =============================================================================
1853 
1854 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
1855 
1856 // -----------------------------------------------------------------------------
1857 template <class TEntry>
1858 mxArray *GenericSparseMatrix<TEntry>::MxArray() const
1859 {
1860  Matlab::Initialize();
1861  mxArray *sa = mxCreateSparse(_Rows, _Cols, _NNZ, mxREAL);
1862  mwIndex *ir = mxGetIr(sa);
1863  mwIndex *jc = mxGetJc(sa);
1864  double *pr = mxGetPr(sa);
1865  if (_Layout == CCS) {
1866  for (int c = 0; c < _Cols; ++c) {
1867  jc[c] = _Col[c];
1868  }
1869  for (int i = 0; i < _NNZ; ++i) {
1870  ir[i] = _Row [i];
1871  pr[i] = _Data[i];
1872  }
1873  } else {
1874  Entries col;
1875  int i = 0;
1876  for (int c = 0; c < _Cols; ++c) {
1877  jc[c] = i;
1878  GetCol(c, col);
1879  typename Entries::const_iterator entry;
1880  for (entry = col.begin(); entry != col.end(); ++entry, ++i) {
1881  ir[i] = entry->first;
1882  pr[i] = entry->second;
1883  }
1884  }
1885  }
1886  jc[_Cols] = _NNZ;
1887  return sa;
1888 }
1889 
1890 #endif // MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
1891 
1892 // -----------------------------------------------------------------------------
1893 template <class TEntry>
1894 bool GenericSparseMatrix<TEntry>::ReadMAT(const char *fname, const char *varname)
1895 {
1896 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
1897  Matlab::Initialize();
1898  MATFile *fp = matOpen(fname, "r");
1899  if (fp == NULL) return false;
1900  mxArray *pm = matGetVariable(fp, varname);
1901  if (pm == NULL) {
1902  matClose(fp);
1903  return false;
1904  }
1905  Initialize(pm);
1906  mxDestroyArray(pm);
1907  return (matClose(fp) == 0);
1908 #else
1909  cerr << "GenericSparseMatrix::ReadMAT: Must be compiled WITH_MATLAB enabled" << endl;
1910  return false;
1911 #endif
1912 }
1913 
1914 // -----------------------------------------------------------------------------
1915 template <class TEntry>
1916 bool GenericSparseMatrix<TEntry>::WriteMAT(const char *fname, const char *varname) const
1917 {
1918 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB)
1919  Matlab::Initialize();
1920  MATFile *fp = matOpen(fname, "w");
1921  if (fp == NULL) return false;
1922  mxArray *m = MxArray();
1923  if (matPutVariable(fp, varname, m) != 0) {
1924  mxDestroyArray(m);
1925  matClose(fp);
1926  return false;
1927  }
1928  mxDestroyArray(m);
1929  return (matClose(fp) == 0);
1930 #else
1931  cerr << "GenericSparseMatrix::WriteMAT: Must be compiled WITH_MATLAB enabled" << endl;
1932  return false;
1933 #endif
1934 }
1935 
1936 // -----------------------------------------------------------------------------
1937 template <class TEntry>
1939 ::WriteMFile(const char *fname, const char *varname) const
1940 {
1941  ofstream of(fname);
1942  // Row indices
1943  of << varname << "_r = [";
1944  if (_Layout == CRS) {
1945  for (int r = 1; r <= _Rows; ++r) {
1946  for (int i = _Row[r-1]; i != _Row[r]; ++i) {
1947  of << r << " ";
1948  }
1949  }
1950  } else {
1951  for (int i = 0; i < _NNZ; ++i) {
1952  of << (_Row[i] + 1) << " ";
1953  }
1954  }
1955  of << "];" << endl;
1956  // Column indices
1957  of << varname << "_c = [";
1958  if (_Layout == CCS) {
1959  for (int c = 1; c <= _Cols; ++c) {
1960  for (int i = _Col[c-1]; i != _Col[c]; ++i) {
1961  of << c << " ";
1962  }
1963  }
1964  } else {
1965  for (int i = 0; i < _NNZ; ++i) {
1966  of << (_Col[i] + 1) << " ";
1967  }
1968  }
1969  of << "];" << endl;
1970  // Non-zero values
1971  of << varname << "_v = [";
1972  for (int i = 0; i < _NNZ; ++i) {
1973  of << _Data[i] << " ";
1974  }
1975  of << "];" << endl;
1976  of << varname << " = sparse(" << varname << "_r, " << varname << "_c, " << varname << "_v, ";
1977  of << _Rows << ", " << _Cols << ", " << _NNZ << ");" << endl;
1978 }
1979 
1980 ////////////////////////////////////////////////////////////////////////////////
1981 // Sparse matrix types
1982 ////////////////////////////////////////////////////////////////////////////////
1983 
1984 /// Typically used template instantiations
1987 
1988 /// Sparse matrix with default entry value type
1989 #if MIRTK_USE_FLOAT_BY_DEFAULT
1990 typedef SparseFloatMatrix SparseMatrix;
1991 #else
1992 typedef SparseDoubleMatrix SparseMatrix;
1993 #endif
1994 
1995 
1996 } // namespace mirtk
1997 
1998 #endif // MIRTK_SparseMatrix_H
int GetRawData(int *&, int *&, TEntry *&) const
Get raw access to index and data arrays.
Definition: SparseMatrix.h:816
bool WriteMAT(const char *, const char *="A") const
virtual ~GenericSparseMatrix()
Destructor.
Definition: SparseMatrix.h:787
void Initialize(int, int=0, int=0)
Initialize sparse matrix.
Definition: SparseMatrix.h:636
void GetDiag(Vector &d) const
Get diagonal values.
void CopyAttributes(const GenericSparseMatrix< TOtherEntry > &)
Copy other matrix, used by copy constructor and assignment operator only.
Definition: SparseMatrix.h:513
bool IsSymmetric() const
Whether this matrix is symmetric.
void Zero()
Set all non-zero entries to zero (i.e., remove)
GenericSparseMatrix & ScaleCol(int, EntryType)
GenericSparseMatrix(StorageLayout=CCS)
Default constructor.
Definition: SparseMatrix.h:551
string Get(const ParameterList &params, string name)
Get parameter value from parameters list.
Definition: Object.h:202
GenericSparseMatrix operator*(EntryType) const
Multiply by a scalar.
GenericSparseMatrix & ScaleRow(int, EntryType)
mirtkAttributeMacro(int, Size)
Number of allocated elements.
mirtkPublicAttributeMacro(int, MaxNumberOfUnusedEntries)
Maximum number of unused entries, i.e., (_Size - _NNZ)
GenericSparseMatrix operator/(EntryType) const
Divide by a scalar.
GenericSparseMatrix Sub(int, int, int, int) const
Get non-zero entries of specified submatrix.
void GetRow(int, Entries &) const
GenericSparseMatrix & operator*=(EntryType)
Multiply by a scalar in-place.
void MultAv(EntryType [], EntryType []) const
void CheckEntries(Entries &) const
Check non-zero entries, sort them, remove zero entries, and sum up duplicates.
Definition: SparseMatrix.h:479
GenericSparseMatrix & operator=(const GenericSparseMatrix< TOtherEntry > &)
Assignment operator.
MIRTKCU_API bool fequal(double a, double b, double tol=1e-12)
Definition: Math.h:138
void Put(int, int, EntryType)
void Col(int, Entries &, bool=false)
GenericSparseMatrix & ScaleColumn(int, EntryType)
bool ReadMAT(const char *, const char *="A")
Definition: IOConfig.h:41
int Eigenvalues(Vector &v, int k, const char *sigma="LM", int p=0, double tol=.0, int maxit=0, Vector *v0=NULL) const
EntryType & operator()(int, int=-1)
Definition: SparseMatrix.h:991
EntryType Get(int, int=-1) const
Get value.
void Row(int, Entries &, bool=false)
int Rows() const
Returns number of rows.
Definition: Vector.h:438
void GetCol(int, Entries &) const
EntryType ColSum(int) const
void RemoveZeros()
Remove any zero entries.
Definition: SparseMatrix.h:857
TEntry EntryType
Type of matrix entry values.
Definition: SparseMatrix.h:64
int RowNNZ(int) const
Number of non-zero entries in specified row.
Definition: SparseMatrix.h:885
void Deallocate(Type *&p)
Deallocate 1D array.
Definition: Deallocate.h:36
EntryType * _Data
Non-zero entries.
Definition: SparseMatrix.h:104
void WriteMFile(const char *, const char *="A") const
void ClearIndex()
Free memory needed for precomputed indices.
Definition: SparseMatrix.h:984
void Reserve(int)
Reserve more memory.
Definition: SparseMatrix.h:840
int SubNNZ(int, int, int, int) const
Number of non-zero entries in specified submatrix.
Definition: SparseMatrix.h:919
int Eigenvectors(Matrix &E, int k, const char *sigma="LM", int p=0, double tol=.0, int maxit=0, Vector *v0=NULL) const
GenericSparseMatrix & operator/=(EntryType)
Divide by a scalar in-place.
EntryType ColumnSum(int) const
EntryType RowSum(int) const
void MakeSymmetric(bool extent=false)
int ColNNZ(int) const
Number of non-zero entries in specified column.
Definition: SparseMatrix.h:902
TEntry * RawPointer(int=0)
Get raw access to non-zero values.
Definition: SparseMatrix.h:826
Vector Diag() const
Get diagonal values.
Pair< int, TEntry > Entry
Type of non-zero entry.
Definition: SparseMatrix.h:67
void Column(int, Entries &, bool=false)
mirtkReadOnlyAttributeMacro(enum StorageLayout, Layout)
Storage layout.
Array< Entry > Entries
List of non-zero entries.
Definition: SparseMatrix.h:70
virtual void Clear()
Free all non-zero entries.
void Layout(StorageLayout)
Change storage layout.
Definition: SparseMatrix.h:801
void Transpose(bool keep_layout=false)
void GetColumn(int, Entries &) const
void Initialize(int)
Intialize matrix with number of rows.
Definition: Vector.h:371