compbio
CholmodSupport.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_CHOLMODSUPPORT_H
11 #define EIGEN_CHOLMODSUPPORT_H
12 
13 namespace Eigen {
14 
15 namespace internal {
16 
17 template<typename Scalar> struct cholmod_configure_matrix;
18 
19 template<> struct cholmod_configure_matrix<double> {
20  template<typename CholmodType>
21  static void run(CholmodType& mat) {
22  mat.xtype = CHOLMOD_REAL;
23  mat.dtype = CHOLMOD_DOUBLE;
24  }
25 };
26 
27 template<> struct cholmod_configure_matrix<std::complex<double> > {
28  template<typename CholmodType>
29  static void run(CholmodType& mat) {
30  mat.xtype = CHOLMOD_COMPLEX;
31  mat.dtype = CHOLMOD_DOUBLE;
32  }
33 };
34 
35 // Other scalar types are not yet suppotred by Cholmod
36 // template<> struct cholmod_configure_matrix<float> {
37 // template<typename CholmodType>
38 // static void run(CholmodType& mat) {
39 // mat.xtype = CHOLMOD_REAL;
40 // mat.dtype = CHOLMOD_SINGLE;
41 // }
42 // };
43 //
44 // template<> struct cholmod_configure_matrix<std::complex<float> > {
45 // template<typename CholmodType>
46 // static void run(CholmodType& mat) {
47 // mat.xtype = CHOLMOD_COMPLEX;
48 // mat.dtype = CHOLMOD_SINGLE;
49 // }
50 // };
51 
52 } // namespace internal
53 
57 template<typename _Scalar, int _Options, typename _StorageIndex>
59 {
60  cholmod_sparse res;
61  res.nzmax = mat.nonZeros();
62  res.nrow = mat.rows();
63  res.ncol = mat.cols();
64  res.p = mat.outerIndexPtr();
65  res.i = mat.innerIndexPtr();
66  res.x = mat.valuePtr();
67  res.z = 0;
68  res.sorted = 1;
69  if(mat.isCompressed())
70  {
71  res.packed = 1;
72  res.nz = 0;
73  }
74  else
75  {
76  res.packed = 0;
77  res.nz = mat.innerNonZeroPtr();
78  }
79 
80  res.dtype = 0;
81  res.stype = -1;
82 
84  {
85  res.itype = CHOLMOD_INT;
86  }
88  {
89  res.itype = CHOLMOD_LONG;
90  }
91  else
92  {
93  eigen_assert(false && "Index type not supported yet");
94  }
95 
96  // setup res.xtype
98 
99  res.stype = 0;
100 
101  return res;
102 }
103 
104 template<typename _Scalar, int _Options, typename _Index>
105 const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat)
106 {
107  cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.const_cast_derived()));
108  return res;
109 }
110 
111 template<typename _Scalar, int _Options, typename _Index>
112 const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat)
113 {
114  cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.const_cast_derived()));
115  return res;
116 }
117 
120 template<typename _Scalar, int _Options, typename _Index, unsigned int UpLo>
122 {
123  cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.matrix().const_cast_derived()));
124 
125  if(UpLo==Upper) res.stype = 1;
126  if(UpLo==Lower) res.stype = -1;
127 
128  return res;
129 }
130 
133 template<typename Derived>
135 {
136  EIGEN_STATIC_ASSERT((internal::traits<Derived>::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
137  typedef typename Derived::Scalar Scalar;
138 
139  cholmod_dense res;
140  res.nrow = mat.rows();
141  res.ncol = mat.cols();
142  res.nzmax = res.nrow * res.ncol;
143  res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride();
144  res.x = (void*)(mat.derived().data());
145  res.z = 0;
146 
148 
149  return res;
150 }
151 
154 template<typename Scalar, int Flags, typename StorageIndex>
156 {
158  (cm.nrow, cm.ncol, static_cast<StorageIndex*>(cm.p)[cm.ncol],
159  static_cast<StorageIndex*>(cm.p), static_cast<StorageIndex*>(cm.i),static_cast<Scalar*>(cm.x) );
160 }
161 
162 enum CholmodMode {
163  CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt
164 };
165 
166 
172 template<typename _MatrixType, int _UpLo, typename Derived>
173 class CholmodBase : public SparseSolverBase<Derived>
174 {
175  protected:
177  using Base::derived;
178  using Base::m_isInitialized;
179  public:
180  typedef _MatrixType MatrixType;
181  enum { UpLo = _UpLo };
182  typedef typename MatrixType::Scalar Scalar;
183  typedef typename MatrixType::RealScalar RealScalar;
184  typedef MatrixType CholMatrixType;
185  typedef typename MatrixType::StorageIndex StorageIndex;
186  enum {
187  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
188  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
189  };
190 
191  public:
192 
193  CholmodBase()
194  : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
195  {
196  EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
197  m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
198  cholmod_start(&m_cholmod);
199  }
200 
201  explicit CholmodBase(const MatrixType& matrix)
202  : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
203  {
204  EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
205  m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
206  cholmod_start(&m_cholmod);
207  compute(matrix);
208  }
209 
210  ~CholmodBase()
211  {
212  if(m_cholmodFactor)
213  cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
214  cholmod_finish(&m_cholmod);
215  }
216 
217  inline StorageIndex cols() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
218  inline StorageIndex rows() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
219 
226  {
227  eigen_assert(m_isInitialized && "Decomposition is not initialized.");
228  return m_info;
229  }
230 
232  Derived& compute(const MatrixType& matrix)
233  {
234  analyzePattern(matrix);
235  factorize(matrix);
236  return derived();
237  }
238 
245  void analyzePattern(const MatrixType& matrix)
246  {
247  if(m_cholmodFactor)
248  {
249  cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
250  m_cholmodFactor = 0;
251  }
252  cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
253  m_cholmodFactor = cholmod_analyze(&A, &m_cholmod);
254 
255  this->m_isInitialized = true;
256  this->m_info = Success;
257  m_analysisIsOk = true;
258  m_factorizationIsOk = false;
259  }
260 
267  void factorize(const MatrixType& matrix)
268  {
269  eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
270  cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
271  cholmod_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, &m_cholmod);
272 
273  // If the factorization failed, minor is the column at which it did. On success minor == n.
274  this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue);
275  m_factorizationIsOk = true;
276  }
277 
280  cholmod_common& cholmod() { return m_cholmod; }
281 
282  #ifndef EIGEN_PARSED_BY_DOXYGEN
283 
284  template<typename Rhs,typename Dest>
285  void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
286  {
287  eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
288  const Index size = m_cholmodFactor->n;
289  EIGEN_UNUSED_VARIABLE(size);
290  eigen_assert(size==b.rows());
291 
292  // Cholmod needs column-major stoarge without inner-stride, which corresponds to the default behavior of Ref.
294 
295  cholmod_dense b_cd = viewAsCholmod(b_ref);
296  cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod);
297  if(!x_cd)
298  {
299  this->m_info = NumericalIssue;
300  return;
301  }
302  // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
303  dest = Matrix<Scalar,Dest::RowsAtCompileTime,Dest::ColsAtCompileTime>::Map(reinterpret_cast<Scalar*>(x_cd->x),b.rows(),b.cols());
304  cholmod_free_dense(&x_cd, &m_cholmod);
305  }
306 
308  template<typename RhsDerived, typename DestDerived>
309  void _solve_impl(const SparseMatrixBase<RhsDerived> &b, SparseMatrixBase<DestDerived> &dest) const
310  {
311  eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
312  const Index size = m_cholmodFactor->n;
313  EIGEN_UNUSED_VARIABLE(size);
314  eigen_assert(size==b.rows());
315 
316  // note: cs stands for Cholmod Sparse
318  cholmod_sparse b_cs = viewAsCholmod(b_ref);
319  cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod);
320  if(!x_cs)
321  {
322  this->m_info = NumericalIssue;
323  return;
324  }
325  // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
326  dest.derived() = viewAsEigen<typename DestDerived::Scalar,ColMajor,typename DestDerived::StorageIndex>(*x_cs);
327  cholmod_free_sparse(&x_cs, &m_cholmod);
328  }
329  #endif // EIGEN_PARSED_BY_DOXYGEN
330 
331 
341  Derived& setShift(const RealScalar& offset)
342  {
343  m_shiftOffset[0] = double(offset);
344  return derived();
345  }
346 
348  Scalar determinant() const
349  {
350  using std::exp;
351  return exp(logDeterminant());
352  }
353 
355  Scalar logDeterminant() const
356  {
357  using std::log;
358  using numext::real;
359  eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
360 
361  RealScalar logDet = 0;
362  Scalar *x = static_cast<Scalar*>(m_cholmodFactor->x);
363  if (m_cholmodFactor->is_super)
364  {
365  // Supernodal factorization stored as a packed list of dense column-major blocs,
366  // as described by the following structure:
367 
368  // super[k] == index of the first column of the j-th super node
369  StorageIndex *super = static_cast<StorageIndex*>(m_cholmodFactor->super);
370  // pi[k] == offset to the description of row indices
371  StorageIndex *pi = static_cast<StorageIndex*>(m_cholmodFactor->pi);
372  // px[k] == offset to the respective dense block
373  StorageIndex *px = static_cast<StorageIndex*>(m_cholmodFactor->px);
374 
375  Index nb_super_nodes = m_cholmodFactor->nsuper;
376  for (Index k=0; k < nb_super_nodes; ++k)
377  {
378  StorageIndex ncols = super[k + 1] - super[k];
379  StorageIndex nrows = pi[k + 1] - pi[k];
380 
381  Map<const Array<Scalar,1,Dynamic>, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1));
382  logDet += sk.real().log().sum();
383  }
384  }
385  else
386  {
387  // Simplicial factorization stored as standard CSC matrix.
388  StorageIndex *p = static_cast<StorageIndex*>(m_cholmodFactor->p);
389  Index size = m_cholmodFactor->n;
390  for (Index k=0; k<size; ++k)
391  logDet += log(real( x[p[k]] ));
392  }
393  if (m_cholmodFactor->is_ll)
394  logDet *= 2.0;
395  return logDet;
396  };
397 
398  template<typename Stream>
399  void dumpMemory(Stream& /*s*/)
400  {}
401 
402  protected:
403  mutable cholmod_common m_cholmod;
404  cholmod_factor* m_cholmodFactor;
405  double m_shiftOffset[2];
406  mutable ComputationInfo m_info;
407  int m_factorizationIsOk;
408  int m_analysisIsOk;
409 };
410 
433 template<typename _MatrixType, int _UpLo = Lower>
434 class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> >
435 {
437  using Base::m_cholmod;
438 
439  public:
440 
441  typedef _MatrixType MatrixType;
442 
443  CholmodSimplicialLLT() : Base() { init(); }
444 
445  CholmodSimplicialLLT(const MatrixType& matrix) : Base()
446  {
447  init();
448  this->compute(matrix);
449  }
450 
452  protected:
453  void init()
454  {
455  m_cholmod.final_asis = 0;
456  m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
457  m_cholmod.final_ll = 1;
458  }
459 };
460 
461 
484 template<typename _MatrixType, int _UpLo = Lower>
485 class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> >
486 {
488  using Base::m_cholmod;
489 
490  public:
491 
492  typedef _MatrixType MatrixType;
493 
494  CholmodSimplicialLDLT() : Base() { init(); }
495 
496  CholmodSimplicialLDLT(const MatrixType& matrix) : Base()
497  {
498  init();
499  this->compute(matrix);
500  }
501 
503  protected:
504  void init()
505  {
506  m_cholmod.final_asis = 1;
507  m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
508  }
509 };
510 
533 template<typename _MatrixType, int _UpLo = Lower>
534 class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> >
535 {
537  using Base::m_cholmod;
538 
539  public:
540 
541  typedef _MatrixType MatrixType;
542 
543  CholmodSupernodalLLT() : Base() { init(); }
544 
545  CholmodSupernodalLLT(const MatrixType& matrix) : Base()
546  {
547  init();
548  this->compute(matrix);
549  }
550 
552  protected:
553  void init()
554  {
555  m_cholmod.final_asis = 1;
556  m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
557  }
558 };
559 
584 template<typename _MatrixType, int _UpLo = Lower>
585 class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> >
586 {
588  using Base::m_cholmod;
589 
590  public:
591 
592  typedef _MatrixType MatrixType;
593 
594  CholmodDecomposition() : Base() { init(); }
595 
596  CholmodDecomposition(const MatrixType& matrix) : Base()
597  {
598  init();
599  this->compute(matrix);
600  }
601 
603 
604  void setMode(CholmodMode mode)
605  {
606  switch(mode)
607  {
608  case CholmodAuto:
609  m_cholmod.final_asis = 1;
610  m_cholmod.supernodal = CHOLMOD_AUTO;
611  break;
612  case CholmodSimplicialLLt:
613  m_cholmod.final_asis = 0;
614  m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
615  m_cholmod.final_ll = 1;
616  break;
617  case CholmodSupernodalLLt:
618  m_cholmod.final_asis = 1;
619  m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
620  break;
621  case CholmodLDLt:
622  m_cholmod.final_asis = 1;
623  m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
624  break;
625  default:
626  break;
627  }
628  }
629  protected:
630  void init()
631  {
632  m_cholmod.final_asis = 1;
633  m_cholmod.supernodal = CHOLMOD_AUTO;
634  }
635 };
636 
637 } // end namespace Eigen
638 
639 #endif // EIGEN_CHOLMODSUPPORT_H
Scalar logDeterminant() const
Definition: CholmodSupport.h:355
A versatible sparse matrix representation.
Definition: SparseMatrix.h:92
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:88
Definition: Meta.h:63
void factorize(const MatrixType &matrix)
Performs a numeric decomposition of matrix.
Definition: CholmodSupport.h:267
A base class for sparse solvers.
Definition: SparseSolverBase.h:67
MappedSparseMatrix< Scalar, Flags, StorageIndex > viewAsEigen(cholmod_sparse &cm)
Returns a view of the Cholmod sparse matrix cm as an Eigen sparse matrix.
Definition: CholmodSupport.h:155
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:85
Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix.
Definition: SparseSelfAdjointView.h:43
Definition: Half.h:529
A supernodal Cholesky (LLT) factorization and solver based on Cholmod.
Definition: CholmodSupport.h:534
const unsigned int RowMajorBit
for a matrix, this means that the storage order is row-major.
Definition: Constants.h:61
Definition: CholmodSupport.h:17
cholmod_common & cholmod()
Returns a reference to the Cholmod&#39;s configuration structure to get a full control over the performed...
Definition: CholmodSupport.h:280
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: CholmodSupport.h:225
Scalar determinant() const
Definition: CholmodSupport.h:348
Index rows() const
Definition: SparseMatrixBase.h:167
Base class of any sparse matrices or sparse expressions.
Definition: ForwardDeclarations.h:281
View matrix as a lower triangular matrix.
Definition: Constants.h:204
The provided data did not satisfy the prerequisites.
Definition: Constants.h:434
a sparse vector class
Definition: SparseUtil.h:54
Convenience specialization of Stride to specify only an inner stride See class Map for some examples...
Definition: Stride.h:90
void analyzePattern(const MatrixType &matrix)
Performs a symbolic decomposition on the sparsity pattern of matrix.
Definition: CholmodSupport.h:245
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
A general Cholesky factorization and solver based on Cholmod.
Definition: CholmodSupport.h:585
cholmod_sparse viewAsCholmod(Ref< SparseMatrix< _Scalar, _Options, _StorageIndex > > mat)
Wraps the Eigen sparse matrix mat into a Cholmod sparse matrix object.
Definition: CholmodSupport.h:58
View matrix as an upper triangular matrix.
Definition: Constants.h:206
The base class for the direct Cholesky factorization of Cholmod.
Definition: CholmodSupport.h:173
Computation was successful.
Definition: Constants.h:432
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:190
A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod.
Definition: CholmodSupport.h:434
Definition: BandTriangularSolver.h:13
Definition: TutorialInplaceLU.cpp:2
A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod.
Definition: CholmodSupport.h:485
Derived & compute(const MatrixType &matrix)
Computes the sparse Cholesky decomposition of matrix.
Definition: CholmodSupport.h:232
Derived & setShift(const RealScalar &offset)
Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical f...
Definition: CholmodSupport.h:341
Definition: datatypes.h:12
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:178
ComputationInfo
Enum for reporting the status of a computation.
Definition: Constants.h:430
Sparse matrix.
Definition: MappedSparseMatrix.h:32
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:48
Definition: ForwardDeclarations.h:17