blob: adaf52858e4ccf4ae5cd1f3c233257a0f1859e63 [file] [log] [blame]
Brian Silverman72890c22015-09-19 14:37:37 -04001// 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
Austin Schuhc55b0172022-02-20 17:52:35 -080013namespace Eigen {
Brian Silverman72890c22015-09-19 14:37:37 -040014
15namespace internal {
16
Austin Schuh189376f2018-12-20 22:11:15 +110017template<typename Scalar> struct cholmod_configure_matrix;
18
19template<> struct cholmod_configure_matrix<double> {
20 template<typename CholmodType>
21 static void run(CholmodType& mat) {
Brian Silverman72890c22015-09-19 14:37:37 -040022 mat.xtype = CHOLMOD_REAL;
23 mat.dtype = CHOLMOD_DOUBLE;
24 }
Austin Schuh189376f2018-12-20 22:11:15 +110025};
26
27template<> struct cholmod_configure_matrix<std::complex<double> > {
28 template<typename CholmodType>
29 static void run(CholmodType& mat) {
Brian Silverman72890c22015-09-19 14:37:37 -040030 mat.xtype = CHOLMOD_COMPLEX;
31 mat.dtype = CHOLMOD_DOUBLE;
32 }
Austin Schuh189376f2018-12-20 22:11:15 +110033};
34
Austin Schuhc55b0172022-02-20 17:52:35 -080035// Other scalar types are not yet supported by Cholmod
Austin Schuh189376f2018-12-20 22:11:15 +110036// 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// };
Brian Silverman72890c22015-09-19 14:37:37 -040051
52} // namespace internal
53
54/** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object.
55 * Note that the data are shared.
56 */
Austin Schuh189376f2018-12-20 22:11:15 +110057template<typename _Scalar, int _Options, typename _StorageIndex>
58cholmod_sparse viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_StorageIndex> > mat)
Brian Silverman72890c22015-09-19 14:37:37 -040059{
60 cholmod_sparse res;
61 res.nzmax = mat.nonZeros();
Austin Schuh189376f2018-12-20 22:11:15 +110062 res.nrow = mat.rows();
Brian Silverman72890c22015-09-19 14:37:37 -040063 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;
Austin Schuhc55b0172022-02-20 17:52:35 -080082
Austin Schuh189376f2018-12-20 22:11:15 +110083 if (internal::is_same<_StorageIndex,int>::value)
Brian Silverman72890c22015-09-19 14:37:37 -040084 {
85 res.itype = CHOLMOD_INT;
86 }
Austin Schuhc55b0172022-02-20 17:52:35 -080087 else if (internal::is_same<_StorageIndex,SuiteSparse_long>::value)
Brian Silverman72890c22015-09-19 14:37:37 -040088 {
89 res.itype = CHOLMOD_LONG;
90 }
91 else
92 {
93 eigen_assert(false && "Index type not supported yet");
94 }
95
96 // setup res.xtype
Austin Schuh189376f2018-12-20 22:11:15 +110097 internal::cholmod_configure_matrix<_Scalar>::run(res);
Austin Schuhc55b0172022-02-20 17:52:35 -080098
Brian Silverman72890c22015-09-19 14:37:37 -040099 res.stype = 0;
Austin Schuhc55b0172022-02-20 17:52:35 -0800100
Brian Silverman72890c22015-09-19 14:37:37 -0400101 return res;
102}
103
104template<typename _Scalar, int _Options, typename _Index>
105const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat)
106{
Austin Schuh189376f2018-12-20 22:11:15 +1100107 cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.const_cast_derived()));
108 return res;
109}
110
111template<typename _Scalar, int _Options, typename _Index>
112const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat)
113{
114 cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.const_cast_derived()));
Brian Silverman72890c22015-09-19 14:37:37 -0400115 return res;
116}
117
118/** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix.
119 * The data are not copied but shared. */
120template<typename _Scalar, int _Options, typename _Index, unsigned int UpLo>
Austin Schuh189376f2018-12-20 22:11:15 +1100121cholmod_sparse viewAsCholmod(const SparseSelfAdjointView<const SparseMatrix<_Scalar,_Options,_Index>, UpLo>& mat)
Brian Silverman72890c22015-09-19 14:37:37 -0400122{
Austin Schuh189376f2018-12-20 22:11:15 +1100123 cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.matrix().const_cast_derived()));
Austin Schuhc55b0172022-02-20 17:52:35 -0800124
Brian Silverman72890c22015-09-19 14:37:37 -0400125 if(UpLo==Upper) res.stype = 1;
126 if(UpLo==Lower) res.stype = -1;
Austin Schuhc55b0172022-02-20 17:52:35 -0800127 // swap stype for rowmajor matrices (only works for real matrices)
128 EIGEN_STATIC_ASSERT((_Options & RowMajorBit) == 0 || NumTraits<_Scalar>::IsComplex == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
129 if(_Options & RowMajorBit) res.stype *=-1;
Brian Silverman72890c22015-09-19 14:37:37 -0400130
131 return res;
132}
133
134/** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix.
135 * The data are not copied but shared. */
136template<typename Derived>
137cholmod_dense viewAsCholmod(MatrixBase<Derived>& mat)
138{
139 EIGEN_STATIC_ASSERT((internal::traits<Derived>::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
140 typedef typename Derived::Scalar Scalar;
141
142 cholmod_dense res;
143 res.nrow = mat.rows();
144 res.ncol = mat.cols();
145 res.nzmax = res.nrow * res.ncol;
146 res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride();
147 res.x = (void*)(mat.derived().data());
148 res.z = 0;
149
Austin Schuh189376f2018-12-20 22:11:15 +1100150 internal::cholmod_configure_matrix<Scalar>::run(res);
Brian Silverman72890c22015-09-19 14:37:37 -0400151
152 return res;
153}
154
155/** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix.
156 * The data are not copied but shared. */
Austin Schuh189376f2018-12-20 22:11:15 +1100157template<typename Scalar, int Flags, typename StorageIndex>
158MappedSparseMatrix<Scalar,Flags,StorageIndex> viewAsEigen(cholmod_sparse& cm)
Brian Silverman72890c22015-09-19 14:37:37 -0400159{
Austin Schuh189376f2018-12-20 22:11:15 +1100160 return MappedSparseMatrix<Scalar,Flags,StorageIndex>
161 (cm.nrow, cm.ncol, static_cast<StorageIndex*>(cm.p)[cm.ncol],
162 static_cast<StorageIndex*>(cm.p), static_cast<StorageIndex*>(cm.i),static_cast<Scalar*>(cm.x) );
Brian Silverman72890c22015-09-19 14:37:37 -0400163}
164
Austin Schuhc55b0172022-02-20 17:52:35 -0800165namespace internal {
166
167// template specializations for int and long that call the correct cholmod method
168
169#define EIGEN_CHOLMOD_SPECIALIZE0(ret, name) \
170 template<typename _StorageIndex> inline ret cm_ ## name (cholmod_common &Common) { return cholmod_ ## name (&Common); } \
171 template<> inline ret cm_ ## name<SuiteSparse_long> (cholmod_common &Common) { return cholmod_l_ ## name (&Common); }
172
173#define EIGEN_CHOLMOD_SPECIALIZE1(ret, name, t1, a1) \
174 template<typename _StorageIndex> inline ret cm_ ## name (t1& a1, cholmod_common &Common) { return cholmod_ ## name (&a1, &Common); } \
175 template<> inline ret cm_ ## name<SuiteSparse_long> (t1& a1, cholmod_common &Common) { return cholmod_l_ ## name (&a1, &Common); }
176
177EIGEN_CHOLMOD_SPECIALIZE0(int, start)
178EIGEN_CHOLMOD_SPECIALIZE0(int, finish)
179
180EIGEN_CHOLMOD_SPECIALIZE1(int, free_factor, cholmod_factor*, L)
181EIGEN_CHOLMOD_SPECIALIZE1(int, free_dense, cholmod_dense*, X)
182EIGEN_CHOLMOD_SPECIALIZE1(int, free_sparse, cholmod_sparse*, A)
183
184EIGEN_CHOLMOD_SPECIALIZE1(cholmod_factor*, analyze, cholmod_sparse, A)
185
186template<typename _StorageIndex> inline cholmod_dense* cm_solve (int sys, cholmod_factor& L, cholmod_dense& B, cholmod_common &Common) { return cholmod_solve (sys, &L, &B, &Common); }
187template<> inline cholmod_dense* cm_solve<SuiteSparse_long> (int sys, cholmod_factor& L, cholmod_dense& B, cholmod_common &Common) { return cholmod_l_solve (sys, &L, &B, &Common); }
188
189template<typename _StorageIndex> inline cholmod_sparse* cm_spsolve (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_spsolve (sys, &L, &B, &Common); }
190template<> inline cholmod_sparse* cm_spsolve<SuiteSparse_long> (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_l_spsolve (sys, &L, &B, &Common); }
191
192template<typename _StorageIndex>
193inline int cm_factorize_p (cholmod_sparse* A, double beta[2], _StorageIndex* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_factorize_p (A, beta, fset, fsize, L, &Common); }
194template<>
195inline int cm_factorize_p<SuiteSparse_long> (cholmod_sparse* A, double beta[2], SuiteSparse_long* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_l_factorize_p (A, beta, fset, fsize, L, &Common); }
196
197#undef EIGEN_CHOLMOD_SPECIALIZE0
198#undef EIGEN_CHOLMOD_SPECIALIZE1
199
200} // namespace internal
201
202
Brian Silverman72890c22015-09-19 14:37:37 -0400203enum CholmodMode {
204 CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt
205};
206
207
208/** \ingroup CholmodSupport_Module
209 * \class CholmodBase
210 * \brief The base class for the direct Cholesky factorization of Cholmod
211 * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT
212 */
213template<typename _MatrixType, int _UpLo, typename Derived>
Austin Schuh189376f2018-12-20 22:11:15 +1100214class CholmodBase : public SparseSolverBase<Derived>
Brian Silverman72890c22015-09-19 14:37:37 -0400215{
Austin Schuh189376f2018-12-20 22:11:15 +1100216 protected:
217 typedef SparseSolverBase<Derived> Base;
218 using Base::derived;
219 using Base::m_isInitialized;
Brian Silverman72890c22015-09-19 14:37:37 -0400220 public:
221 typedef _MatrixType MatrixType;
222 enum { UpLo = _UpLo };
223 typedef typename MatrixType::Scalar Scalar;
224 typedef typename MatrixType::RealScalar RealScalar;
225 typedef MatrixType CholMatrixType;
Austin Schuh189376f2018-12-20 22:11:15 +1100226 typedef typename MatrixType::StorageIndex StorageIndex;
227 enum {
228 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
229 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
230 };
Brian Silverman72890c22015-09-19 14:37:37 -0400231
232 public:
233
234 CholmodBase()
Austin Schuh189376f2018-12-20 22:11:15 +1100235 : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
Brian Silverman72890c22015-09-19 14:37:37 -0400236 {
Austin Schuh189376f2018-12-20 22:11:15 +1100237 EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
238 m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
Austin Schuhc55b0172022-02-20 17:52:35 -0800239 internal::cm_start<StorageIndex>(m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400240 }
241
Austin Schuh189376f2018-12-20 22:11:15 +1100242 explicit CholmodBase(const MatrixType& matrix)
243 : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
Brian Silverman72890c22015-09-19 14:37:37 -0400244 {
Austin Schuh189376f2018-12-20 22:11:15 +1100245 EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
246 m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
Austin Schuhc55b0172022-02-20 17:52:35 -0800247 internal::cm_start<StorageIndex>(m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400248 compute(matrix);
249 }
250
251 ~CholmodBase()
252 {
253 if(m_cholmodFactor)
Austin Schuhc55b0172022-02-20 17:52:35 -0800254 internal::cm_free_factor<StorageIndex>(m_cholmodFactor, m_cholmod);
255 internal::cm_finish<StorageIndex>(m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400256 }
Austin Schuhc55b0172022-02-20 17:52:35 -0800257
Austin Schuh189376f2018-12-20 22:11:15 +1100258 inline StorageIndex cols() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
259 inline StorageIndex rows() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
Austin Schuhc55b0172022-02-20 17:52:35 -0800260
Brian Silverman72890c22015-09-19 14:37:37 -0400261 /** \brief Reports whether previous computation was successful.
262 *
Austin Schuhc55b0172022-02-20 17:52:35 -0800263 * \returns \c Success if computation was successful,
Brian Silverman72890c22015-09-19 14:37:37 -0400264 * \c NumericalIssue if the matrix.appears to be negative.
265 */
266 ComputationInfo info() const
267 {
268 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
269 return m_info;
270 }
271
272 /** Computes the sparse Cholesky decomposition of \a matrix */
273 Derived& compute(const MatrixType& matrix)
274 {
275 analyzePattern(matrix);
276 factorize(matrix);
277 return derived();
278 }
Austin Schuhc55b0172022-02-20 17:52:35 -0800279
Brian Silverman72890c22015-09-19 14:37:37 -0400280 /** Performs a symbolic decomposition on the sparsity pattern of \a matrix.
281 *
282 * This function is particularly useful when solving for several problems having the same structure.
Austin Schuhc55b0172022-02-20 17:52:35 -0800283 *
Brian Silverman72890c22015-09-19 14:37:37 -0400284 * \sa factorize()
285 */
286 void analyzePattern(const MatrixType& matrix)
287 {
288 if(m_cholmodFactor)
289 {
Austin Schuhc55b0172022-02-20 17:52:35 -0800290 internal::cm_free_factor<StorageIndex>(m_cholmodFactor, m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400291 m_cholmodFactor = 0;
292 }
293 cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
Austin Schuhc55b0172022-02-20 17:52:35 -0800294 m_cholmodFactor = internal::cm_analyze<StorageIndex>(A, m_cholmod);
295
Brian Silverman72890c22015-09-19 14:37:37 -0400296 this->m_isInitialized = true;
297 this->m_info = Success;
298 m_analysisIsOk = true;
299 m_factorizationIsOk = false;
300 }
Austin Schuhc55b0172022-02-20 17:52:35 -0800301
Brian Silverman72890c22015-09-19 14:37:37 -0400302 /** Performs a numeric decomposition of \a matrix
303 *
304 * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed.
305 *
306 * \sa analyzePattern()
307 */
308 void factorize(const MatrixType& matrix)
309 {
310 eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
311 cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
Austin Schuhc55b0172022-02-20 17:52:35 -0800312 internal::cm_factorize_p<StorageIndex>(&A, m_shiftOffset, 0, 0, m_cholmodFactor, m_cholmod);
Austin Schuh189376f2018-12-20 22:11:15 +1100313
Brian Silverman72890c22015-09-19 14:37:37 -0400314 // If the factorization failed, minor is the column at which it did. On success minor == n.
315 this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue);
316 m_factorizationIsOk = true;
317 }
Austin Schuhc55b0172022-02-20 17:52:35 -0800318
Brian Silverman72890c22015-09-19 14:37:37 -0400319 /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations.
320 * See the Cholmod user guide for details. */
321 cholmod_common& cholmod() { return m_cholmod; }
Austin Schuhc55b0172022-02-20 17:52:35 -0800322
Brian Silverman72890c22015-09-19 14:37:37 -0400323 #ifndef EIGEN_PARSED_BY_DOXYGEN
324 /** \internal */
325 template<typename Rhs,typename Dest>
Austin Schuh189376f2018-12-20 22:11:15 +1100326 void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
Brian Silverman72890c22015-09-19 14:37:37 -0400327 {
328 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
329 const Index size = m_cholmodFactor->n;
330 EIGEN_UNUSED_VARIABLE(size);
331 eigen_assert(size==b.rows());
Austin Schuhc55b0172022-02-20 17:52:35 -0800332
333 // Cholmod needs column-major storage without inner-stride, which corresponds to the default behavior of Ref.
Austin Schuh189376f2018-12-20 22:11:15 +1100334 Ref<const Matrix<typename Rhs::Scalar,Dynamic,Dynamic,ColMajor> > b_ref(b.derived());
Brian Silverman72890c22015-09-19 14:37:37 -0400335
Brian Silverman72890c22015-09-19 14:37:37 -0400336 cholmod_dense b_cd = viewAsCholmod(b_ref);
Austin Schuhc55b0172022-02-20 17:52:35 -0800337 cholmod_dense* x_cd = internal::cm_solve<StorageIndex>(CHOLMOD_A, *m_cholmodFactor, b_cd, m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400338 if(!x_cd)
339 {
340 this->m_info = NumericalIssue;
Austin Schuh189376f2018-12-20 22:11:15 +1100341 return;
Brian Silverman72890c22015-09-19 14:37:37 -0400342 }
343 // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
Austin Schuhc55b0172022-02-20 17:52:35 -0800344 // NOTE Actually, the copy can be avoided by calling cholmod_solve2 instead of cholmod_solve
Brian Silverman72890c22015-09-19 14:37:37 -0400345 dest = Matrix<Scalar,Dest::RowsAtCompileTime,Dest::ColsAtCompileTime>::Map(reinterpret_cast<Scalar*>(x_cd->x),b.rows(),b.cols());
Austin Schuhc55b0172022-02-20 17:52:35 -0800346 internal::cm_free_dense<StorageIndex>(x_cd, m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400347 }
Austin Schuhc55b0172022-02-20 17:52:35 -0800348
Brian Silverman72890c22015-09-19 14:37:37 -0400349 /** \internal */
Austin Schuh189376f2018-12-20 22:11:15 +1100350 template<typename RhsDerived, typename DestDerived>
351 void _solve_impl(const SparseMatrixBase<RhsDerived> &b, SparseMatrixBase<DestDerived> &dest) const
Brian Silverman72890c22015-09-19 14:37:37 -0400352 {
353 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
354 const Index size = m_cholmodFactor->n;
355 EIGEN_UNUSED_VARIABLE(size);
356 eigen_assert(size==b.rows());
357
358 // note: cs stands for Cholmod Sparse
Austin Schuh189376f2018-12-20 22:11:15 +1100359 Ref<SparseMatrix<typename RhsDerived::Scalar,ColMajor,typename RhsDerived::StorageIndex> > b_ref(b.const_cast_derived());
360 cholmod_sparse b_cs = viewAsCholmod(b_ref);
Austin Schuhc55b0172022-02-20 17:52:35 -0800361 cholmod_sparse* x_cs = internal::cm_spsolve<StorageIndex>(CHOLMOD_A, *m_cholmodFactor, b_cs, m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400362 if(!x_cs)
363 {
364 this->m_info = NumericalIssue;
Austin Schuh189376f2018-12-20 22:11:15 +1100365 return;
Brian Silverman72890c22015-09-19 14:37:37 -0400366 }
367 // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
Austin Schuhc55b0172022-02-20 17:52:35 -0800368 // NOTE cholmod_spsolve in fact just calls the dense solver for blocks of 4 columns at a time (similar to Eigen's sparse solver)
Austin Schuh189376f2018-12-20 22:11:15 +1100369 dest.derived() = viewAsEigen<typename DestDerived::Scalar,ColMajor,typename DestDerived::StorageIndex>(*x_cs);
Austin Schuhc55b0172022-02-20 17:52:35 -0800370 internal::cm_free_sparse<StorageIndex>(x_cs, m_cholmod);
Brian Silverman72890c22015-09-19 14:37:37 -0400371 }
372 #endif // EIGEN_PARSED_BY_DOXYGEN
Austin Schuhc55b0172022-02-20 17:52:35 -0800373
374
Brian Silverman72890c22015-09-19 14:37:37 -0400375 /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization.
376 *
377 * During the numerical factorization, an offset term is added to the diagonal coefficients:\n
378 * \c d_ii = \a offset + \c d_ii
379 *
380 * The default is \a offset=0.
381 *
382 * \returns a reference to \c *this.
383 */
384 Derived& setShift(const RealScalar& offset)
385 {
Austin Schuh189376f2018-12-20 22:11:15 +1100386 m_shiftOffset[0] = double(offset);
Brian Silverman72890c22015-09-19 14:37:37 -0400387 return derived();
388 }
Austin Schuhc55b0172022-02-20 17:52:35 -0800389
Austin Schuh189376f2018-12-20 22:11:15 +1100390 /** \returns the determinant of the underlying matrix from the current factorization */
391 Scalar determinant() const
392 {
393 using std::exp;
394 return exp(logDeterminant());
395 }
396
397 /** \returns the log determinant of the underlying matrix from the current factorization */
398 Scalar logDeterminant() const
399 {
400 using std::log;
401 using numext::real;
402 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
403
404 RealScalar logDet = 0;
405 Scalar *x = static_cast<Scalar*>(m_cholmodFactor->x);
406 if (m_cholmodFactor->is_super)
407 {
408 // Supernodal factorization stored as a packed list of dense column-major blocs,
409 // as described by the following structure:
410
411 // super[k] == index of the first column of the j-th super node
412 StorageIndex *super = static_cast<StorageIndex*>(m_cholmodFactor->super);
413 // pi[k] == offset to the description of row indices
414 StorageIndex *pi = static_cast<StorageIndex*>(m_cholmodFactor->pi);
415 // px[k] == offset to the respective dense block
416 StorageIndex *px = static_cast<StorageIndex*>(m_cholmodFactor->px);
417
418 Index nb_super_nodes = m_cholmodFactor->nsuper;
419 for (Index k=0; k < nb_super_nodes; ++k)
420 {
421 StorageIndex ncols = super[k + 1] - super[k];
422 StorageIndex nrows = pi[k + 1] - pi[k];
423
424 Map<const Array<Scalar,1,Dynamic>, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1));
425 logDet += sk.real().log().sum();
426 }
427 }
428 else
429 {
430 // Simplicial factorization stored as standard CSC matrix.
431 StorageIndex *p = static_cast<StorageIndex*>(m_cholmodFactor->p);
432 Index size = m_cholmodFactor->n;
433 for (Index k=0; k<size; ++k)
434 logDet += log(real( x[p[k]] ));
435 }
436 if (m_cholmodFactor->is_ll)
437 logDet *= 2.0;
438 return logDet;
439 };
440
Brian Silverman72890c22015-09-19 14:37:37 -0400441 template<typename Stream>
442 void dumpMemory(Stream& /*s*/)
443 {}
Austin Schuhc55b0172022-02-20 17:52:35 -0800444
Brian Silverman72890c22015-09-19 14:37:37 -0400445 protected:
446 mutable cholmod_common m_cholmod;
447 cholmod_factor* m_cholmodFactor;
Austin Schuh189376f2018-12-20 22:11:15 +1100448 double m_shiftOffset[2];
Brian Silverman72890c22015-09-19 14:37:37 -0400449 mutable ComputationInfo m_info;
Brian Silverman72890c22015-09-19 14:37:37 -0400450 int m_factorizationIsOk;
451 int m_analysisIsOk;
452};
453
454/** \ingroup CholmodSupport_Module
455 * \class CholmodSimplicialLLT
456 * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod
457 *
458 * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization
459 * using the Cholmod library.
460 * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest.
461 * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
462 * X and B can be either dense or sparse.
463 *
464 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
465 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
466 * or Upper. Default is Lower.
467 *
Austin Schuh189376f2018-12-20 22:11:15 +1100468 * \implsparsesolverconcept
469 *
Brian Silverman72890c22015-09-19 14:37:37 -0400470 * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
471 *
Austin Schuh189376f2018-12-20 22:11:15 +1100472 * \warning Only double precision real and complex scalar types are supported by Cholmod.
473 *
474 * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT
Brian Silverman72890c22015-09-19 14:37:37 -0400475 */
476template<typename _MatrixType, int _UpLo = Lower>
477class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> >
478{
479 typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base;
480 using Base::m_cholmod;
Austin Schuhc55b0172022-02-20 17:52:35 -0800481
Brian Silverman72890c22015-09-19 14:37:37 -0400482 public:
Austin Schuhc55b0172022-02-20 17:52:35 -0800483
Brian Silverman72890c22015-09-19 14:37:37 -0400484 typedef _MatrixType MatrixType;
Austin Schuhc55b0172022-02-20 17:52:35 -0800485
Brian Silverman72890c22015-09-19 14:37:37 -0400486 CholmodSimplicialLLT() : Base() { init(); }
487
488 CholmodSimplicialLLT(const MatrixType& matrix) : Base()
489 {
490 init();
Austin Schuh189376f2018-12-20 22:11:15 +1100491 this->compute(matrix);
Brian Silverman72890c22015-09-19 14:37:37 -0400492 }
493
494 ~CholmodSimplicialLLT() {}
495 protected:
496 void init()
497 {
498 m_cholmod.final_asis = 0;
499 m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
500 m_cholmod.final_ll = 1;
501 }
502};
503
504
505/** \ingroup CholmodSupport_Module
506 * \class CholmodSimplicialLDLT
507 * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod
508 *
509 * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization
510 * using the Cholmod library.
511 * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest.
512 * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
513 * X and B can be either dense or sparse.
514 *
515 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
516 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
517 * or Upper. Default is Lower.
518 *
Austin Schuh189376f2018-12-20 22:11:15 +1100519 * \implsparsesolverconcept
520 *
Brian Silverman72890c22015-09-19 14:37:37 -0400521 * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
522 *
Austin Schuh189376f2018-12-20 22:11:15 +1100523 * \warning Only double precision real and complex scalar types are supported by Cholmod.
524 *
525 * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT
Brian Silverman72890c22015-09-19 14:37:37 -0400526 */
527template<typename _MatrixType, int _UpLo = Lower>
528class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> >
529{
530 typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base;
531 using Base::m_cholmod;
Austin Schuhc55b0172022-02-20 17:52:35 -0800532
Brian Silverman72890c22015-09-19 14:37:37 -0400533 public:
Austin Schuhc55b0172022-02-20 17:52:35 -0800534
Brian Silverman72890c22015-09-19 14:37:37 -0400535 typedef _MatrixType MatrixType;
Austin Schuhc55b0172022-02-20 17:52:35 -0800536
Brian Silverman72890c22015-09-19 14:37:37 -0400537 CholmodSimplicialLDLT() : Base() { init(); }
538
539 CholmodSimplicialLDLT(const MatrixType& matrix) : Base()
540 {
541 init();
Austin Schuh189376f2018-12-20 22:11:15 +1100542 this->compute(matrix);
Brian Silverman72890c22015-09-19 14:37:37 -0400543 }
544
545 ~CholmodSimplicialLDLT() {}
546 protected:
547 void init()
548 {
549 m_cholmod.final_asis = 1;
550 m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
551 }
552};
553
554/** \ingroup CholmodSupport_Module
555 * \class CholmodSupernodalLLT
556 * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod
557 *
558 * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization
559 * using the Cholmod library.
560 * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM.
561 * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
562 * X and B can be either dense or sparse.
563 *
564 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
565 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
566 * or Upper. Default is Lower.
567 *
Austin Schuh189376f2018-12-20 22:11:15 +1100568 * \implsparsesolverconcept
569 *
Brian Silverman72890c22015-09-19 14:37:37 -0400570 * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
571 *
Austin Schuh189376f2018-12-20 22:11:15 +1100572 * \warning Only double precision real and complex scalar types are supported by Cholmod.
573 *
574 * \sa \ref TutorialSparseSolverConcept
Brian Silverman72890c22015-09-19 14:37:37 -0400575 */
576template<typename _MatrixType, int _UpLo = Lower>
577class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> >
578{
579 typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base;
580 using Base::m_cholmod;
Austin Schuhc55b0172022-02-20 17:52:35 -0800581
Brian Silverman72890c22015-09-19 14:37:37 -0400582 public:
Austin Schuhc55b0172022-02-20 17:52:35 -0800583
Brian Silverman72890c22015-09-19 14:37:37 -0400584 typedef _MatrixType MatrixType;
Austin Schuhc55b0172022-02-20 17:52:35 -0800585
Brian Silverman72890c22015-09-19 14:37:37 -0400586 CholmodSupernodalLLT() : Base() { init(); }
587
588 CholmodSupernodalLLT(const MatrixType& matrix) : Base()
589 {
590 init();
Austin Schuh189376f2018-12-20 22:11:15 +1100591 this->compute(matrix);
Brian Silverman72890c22015-09-19 14:37:37 -0400592 }
593
594 ~CholmodSupernodalLLT() {}
595 protected:
596 void init()
597 {
598 m_cholmod.final_asis = 1;
599 m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
600 }
601};
602
603/** \ingroup CholmodSupport_Module
604 * \class CholmodDecomposition
605 * \brief A general Cholesky factorization and solver based on Cholmod
606 *
607 * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization
608 * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
609 * X and B can be either dense or sparse.
610 *
611 * This variant permits to change the underlying Cholesky method at runtime.
612 * On the other hand, it does not provide access to the result of the factorization.
613 * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization.
614 *
615 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
616 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
617 * or Upper. Default is Lower.
618 *
Austin Schuh189376f2018-12-20 22:11:15 +1100619 * \implsparsesolverconcept
620 *
Brian Silverman72890c22015-09-19 14:37:37 -0400621 * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
622 *
Austin Schuh189376f2018-12-20 22:11:15 +1100623 * \warning Only double precision real and complex scalar types are supported by Cholmod.
624 *
625 * \sa \ref TutorialSparseSolverConcept
Brian Silverman72890c22015-09-19 14:37:37 -0400626 */
627template<typename _MatrixType, int _UpLo = Lower>
628class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> >
629{
630 typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base;
631 using Base::m_cholmod;
Austin Schuhc55b0172022-02-20 17:52:35 -0800632
Brian Silverman72890c22015-09-19 14:37:37 -0400633 public:
Austin Schuhc55b0172022-02-20 17:52:35 -0800634
Brian Silverman72890c22015-09-19 14:37:37 -0400635 typedef _MatrixType MatrixType;
Austin Schuhc55b0172022-02-20 17:52:35 -0800636
Brian Silverman72890c22015-09-19 14:37:37 -0400637 CholmodDecomposition() : Base() { init(); }
638
639 CholmodDecomposition(const MatrixType& matrix) : Base()
640 {
641 init();
Austin Schuh189376f2018-12-20 22:11:15 +1100642 this->compute(matrix);
Brian Silverman72890c22015-09-19 14:37:37 -0400643 }
644
645 ~CholmodDecomposition() {}
Austin Schuhc55b0172022-02-20 17:52:35 -0800646
Brian Silverman72890c22015-09-19 14:37:37 -0400647 void setMode(CholmodMode mode)
648 {
649 switch(mode)
650 {
651 case CholmodAuto:
652 m_cholmod.final_asis = 1;
653 m_cholmod.supernodal = CHOLMOD_AUTO;
654 break;
655 case CholmodSimplicialLLt:
656 m_cholmod.final_asis = 0;
657 m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
658 m_cholmod.final_ll = 1;
659 break;
660 case CholmodSupernodalLLt:
661 m_cholmod.final_asis = 1;
662 m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
663 break;
664 case CholmodLDLt:
665 m_cholmod.final_asis = 1;
666 m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
667 break;
668 default:
669 break;
670 }
671 }
672 protected:
673 void init()
674 {
675 m_cholmod.final_asis = 1;
676 m_cholmod.supernodal = CHOLMOD_AUTO;
677 }
678};
679
Brian Silverman72890c22015-09-19 14:37:37 -0400680} // end namespace Eigen
681
682#endif // EIGEN_CHOLMODSUPPORT_H