Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 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) { |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 22 | mat.xtype = CHOLMOD_REAL; |
| 23 | mat.dtype = CHOLMOD_DOUBLE; |
| 24 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 25 | }; |
| 26 | |
| 27 | template<> struct cholmod_configure_matrix<std::complex<double> > { |
| 28 | template<typename CholmodType> |
| 29 | static void run(CholmodType& mat) { |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 30 | mat.xtype = CHOLMOD_COMPLEX; |
| 31 | mat.dtype = CHOLMOD_DOUBLE; |
| 32 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 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 | // }; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 51 | |
| 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 Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 57 | template<typename _Scalar, int _Options, typename _StorageIndex> |
| 58 | cholmod_sparse viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_StorageIndex> > mat) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 59 | { |
| 60 | cholmod_sparse res; |
| 61 | res.nzmax = mat.nonZeros(); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 62 | res.nrow = mat.rows(); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 83 | if (internal::is_same<_StorageIndex,int>::value) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 84 | { |
| 85 | res.itype = CHOLMOD_INT; |
| 86 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 87 | else if (internal::is_same<_StorageIndex,long>::value) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 97 | internal::cholmod_configure_matrix<_Scalar>::run(res); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 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())); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 115 | 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. */ |
| 120 | template<typename _Scalar, int _Options, typename _Index, unsigned int UpLo> |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 121 | cholmod_sparse viewAsCholmod(const SparseSelfAdjointView<const SparseMatrix<_Scalar,_Options,_Index>, UpLo>& mat) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 122 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 123 | cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.matrix().const_cast_derived())); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 124 | |
| 125 | if(UpLo==Upper) res.stype = 1; |
| 126 | if(UpLo==Lower) res.stype = -1; |
| 127 | |
| 128 | return res; |
| 129 | } |
| 130 | |
| 131 | /** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix. |
| 132 | * The data are not copied but shared. */ |
| 133 | template<typename Derived> |
| 134 | cholmod_dense viewAsCholmod(MatrixBase<Derived>& mat) |
| 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 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 147 | internal::cholmod_configure_matrix<Scalar>::run(res); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 148 | |
| 149 | return res; |
| 150 | } |
| 151 | |
| 152 | /** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. |
| 153 | * The data are not copied but shared. */ |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 154 | template<typename Scalar, int Flags, typename StorageIndex> |
| 155 | MappedSparseMatrix<Scalar,Flags,StorageIndex> viewAsEigen(cholmod_sparse& cm) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 156 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 157 | return MappedSparseMatrix<Scalar,Flags,StorageIndex> |
| 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) ); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | enum CholmodMode { |
| 163 | CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt |
| 164 | }; |
| 165 | |
| 166 | |
| 167 | /** \ingroup CholmodSupport_Module |
| 168 | * \class CholmodBase |
| 169 | * \brief The base class for the direct Cholesky factorization of Cholmod |
| 170 | * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT |
| 171 | */ |
| 172 | template<typename _MatrixType, int _UpLo, typename Derived> |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 173 | class CholmodBase : public SparseSolverBase<Derived> |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 174 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 175 | protected: |
| 176 | typedef SparseSolverBase<Derived> Base; |
| 177 | using Base::derived; |
| 178 | using Base::m_isInitialized; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 185 | typedef typename MatrixType::StorageIndex StorageIndex; |
| 186 | enum { |
| 187 | ColsAtCompileTime = MatrixType::ColsAtCompileTime, |
| 188 | MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime |
| 189 | }; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 190 | |
| 191 | public: |
| 192 | |
| 193 | CholmodBase() |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 194 | : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 195 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 196 | EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); |
| 197 | m_shiftOffset[0] = m_shiftOffset[1] = 0.0; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 198 | cholmod_start(&m_cholmod); |
| 199 | } |
| 200 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 201 | explicit CholmodBase(const MatrixType& matrix) |
| 202 | : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 203 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 204 | EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); |
| 205 | m_shiftOffset[0] = m_shiftOffset[1] = 0.0; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 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); } |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 219 | |
| 220 | /** \brief Reports whether previous computation was successful. |
| 221 | * |
| 222 | * \returns \c Success if computation was succesful, |
| 223 | * \c NumericalIssue if the matrix.appears to be negative. |
| 224 | */ |
| 225 | ComputationInfo info() const |
| 226 | { |
| 227 | eigen_assert(m_isInitialized && "Decomposition is not initialized."); |
| 228 | return m_info; |
| 229 | } |
| 230 | |
| 231 | /** Computes the sparse Cholesky decomposition of \a matrix */ |
| 232 | Derived& compute(const MatrixType& matrix) |
| 233 | { |
| 234 | analyzePattern(matrix); |
| 235 | factorize(matrix); |
| 236 | return derived(); |
| 237 | } |
| 238 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 239 | /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. |
| 240 | * |
| 241 | * This function is particularly useful when solving for several problems having the same structure. |
| 242 | * |
| 243 | * \sa factorize() |
| 244 | */ |
| 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 | |
| 261 | /** Performs a numeric decomposition of \a matrix |
| 262 | * |
| 263 | * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed. |
| 264 | * |
| 265 | * \sa analyzePattern() |
| 266 | */ |
| 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); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 272 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 | |
| 278 | /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations. |
| 279 | * See the Cholmod user guide for details. */ |
| 280 | cholmod_common& cholmod() { return m_cholmod; } |
| 281 | |
| 282 | #ifndef EIGEN_PARSED_BY_DOXYGEN |
| 283 | /** \internal */ |
| 284 | template<typename Rhs,typename Dest> |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 285 | void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 291 | |
| 292 | // Cholmod needs column-major stoarge without inner-stride, which corresponds to the default behavior of Ref. |
| 293 | Ref<const Matrix<typename Rhs::Scalar,Dynamic,Dynamic,ColMajor> > b_ref(b.derived()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 294 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 300 | return; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 | |
| 307 | /** \internal */ |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 308 | template<typename RhsDerived, typename DestDerived> |
| 309 | void _solve_impl(const SparseMatrixBase<RhsDerived> &b, SparseMatrixBase<DestDerived> &dest) const |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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 |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 317 | Ref<SparseMatrix<typename RhsDerived::Scalar,ColMajor,typename RhsDerived::StorageIndex> > b_ref(b.const_cast_derived()); |
| 318 | cholmod_sparse b_cs = viewAsCholmod(b_ref); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 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; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 323 | return; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 324 | } |
| 325 | // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 326 | dest.derived() = viewAsEigen<typename DestDerived::Scalar,ColMajor,typename DestDerived::StorageIndex>(*x_cs); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 327 | cholmod_free_sparse(&x_cs, &m_cholmod); |
| 328 | } |
| 329 | #endif // EIGEN_PARSED_BY_DOXYGEN |
| 330 | |
| 331 | |
| 332 | /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization. |
| 333 | * |
| 334 | * During the numerical factorization, an offset term is added to the diagonal coefficients:\n |
| 335 | * \c d_ii = \a offset + \c d_ii |
| 336 | * |
| 337 | * The default is \a offset=0. |
| 338 | * |
| 339 | * \returns a reference to \c *this. |
| 340 | */ |
| 341 | Derived& setShift(const RealScalar& offset) |
| 342 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 343 | m_shiftOffset[0] = double(offset); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 344 | return derived(); |
| 345 | } |
| 346 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 347 | /** \returns the determinant of the underlying matrix from the current factorization */ |
| 348 | Scalar determinant() const |
| 349 | { |
| 350 | using std::exp; |
| 351 | return exp(logDeterminant()); |
| 352 | } |
| 353 | |
| 354 | /** \returns the log determinant of the underlying matrix from the current factorization */ |
| 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 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 398 | template<typename Stream> |
| 399 | void dumpMemory(Stream& /*s*/) |
| 400 | {} |
| 401 | |
| 402 | protected: |
| 403 | mutable cholmod_common m_cholmod; |
| 404 | cholmod_factor* m_cholmodFactor; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 405 | double m_shiftOffset[2]; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 406 | mutable ComputationInfo m_info; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 407 | int m_factorizationIsOk; |
| 408 | int m_analysisIsOk; |
| 409 | }; |
| 410 | |
| 411 | /** \ingroup CholmodSupport_Module |
| 412 | * \class CholmodSimplicialLLT |
| 413 | * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod |
| 414 | * |
| 415 | * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization |
| 416 | * using the Cholmod library. |
| 417 | * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest. |
| 418 | * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices |
| 419 | * X and B can be either dense or sparse. |
| 420 | * |
| 421 | * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> |
| 422 | * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower |
| 423 | * or Upper. Default is Lower. |
| 424 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 425 | * \implsparsesolverconcept |
| 426 | * |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 427 | * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. |
| 428 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 429 | * \warning Only double precision real and complex scalar types are supported by Cholmod. |
| 430 | * |
| 431 | * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 432 | */ |
| 433 | template<typename _MatrixType, int _UpLo = Lower> |
| 434 | class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > |
| 435 | { |
| 436 | typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base; |
| 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(); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 448 | this->compute(matrix); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 449 | } |
| 450 | |
| 451 | ~CholmodSimplicialLLT() {} |
| 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 | |
| 462 | /** \ingroup CholmodSupport_Module |
| 463 | * \class CholmodSimplicialLDLT |
| 464 | * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod |
| 465 | * |
| 466 | * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization |
| 467 | * using the Cholmod library. |
| 468 | * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest. |
| 469 | * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices |
| 470 | * X and B can be either dense or sparse. |
| 471 | * |
| 472 | * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> |
| 473 | * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower |
| 474 | * or Upper. Default is Lower. |
| 475 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 476 | * \implsparsesolverconcept |
| 477 | * |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 478 | * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. |
| 479 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 480 | * \warning Only double precision real and complex scalar types are supported by Cholmod. |
| 481 | * |
| 482 | * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 483 | */ |
| 484 | template<typename _MatrixType, int _UpLo = Lower> |
| 485 | class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > |
| 486 | { |
| 487 | typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base; |
| 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(); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 499 | this->compute(matrix); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 500 | } |
| 501 | |
| 502 | ~CholmodSimplicialLDLT() {} |
| 503 | protected: |
| 504 | void init() |
| 505 | { |
| 506 | m_cholmod.final_asis = 1; |
| 507 | m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; |
| 508 | } |
| 509 | }; |
| 510 | |
| 511 | /** \ingroup CholmodSupport_Module |
| 512 | * \class CholmodSupernodalLLT |
| 513 | * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod |
| 514 | * |
| 515 | * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization |
| 516 | * using the Cholmod library. |
| 517 | * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM. |
| 518 | * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices |
| 519 | * X and B can be either dense or sparse. |
| 520 | * |
| 521 | * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> |
| 522 | * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower |
| 523 | * or Upper. Default is Lower. |
| 524 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 525 | * \implsparsesolverconcept |
| 526 | * |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 527 | * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. |
| 528 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 529 | * \warning Only double precision real and complex scalar types are supported by Cholmod. |
| 530 | * |
| 531 | * \sa \ref TutorialSparseSolverConcept |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 532 | */ |
| 533 | template<typename _MatrixType, int _UpLo = Lower> |
| 534 | class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > |
| 535 | { |
| 536 | typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base; |
| 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(); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 548 | this->compute(matrix); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 549 | } |
| 550 | |
| 551 | ~CholmodSupernodalLLT() {} |
| 552 | protected: |
| 553 | void init() |
| 554 | { |
| 555 | m_cholmod.final_asis = 1; |
| 556 | m_cholmod.supernodal = CHOLMOD_SUPERNODAL; |
| 557 | } |
| 558 | }; |
| 559 | |
| 560 | /** \ingroup CholmodSupport_Module |
| 561 | * \class CholmodDecomposition |
| 562 | * \brief A general Cholesky factorization and solver based on Cholmod |
| 563 | * |
| 564 | * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization |
| 565 | * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices |
| 566 | * X and B can be either dense or sparse. |
| 567 | * |
| 568 | * This variant permits to change the underlying Cholesky method at runtime. |
| 569 | * On the other hand, it does not provide access to the result of the factorization. |
| 570 | * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization. |
| 571 | * |
| 572 | * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> |
| 573 | * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower |
| 574 | * or Upper. Default is Lower. |
| 575 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 576 | * \implsparsesolverconcept |
| 577 | * |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 578 | * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. |
| 579 | * |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 580 | * \warning Only double precision real and complex scalar types are supported by Cholmod. |
| 581 | * |
| 582 | * \sa \ref TutorialSparseSolverConcept |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 583 | */ |
| 584 | template<typename _MatrixType, int _UpLo = Lower> |
| 585 | class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > |
| 586 | { |
| 587 | typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base; |
| 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(); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame^] | 599 | this->compute(matrix); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 600 | } |
| 601 | |
| 602 | ~CholmodDecomposition() {} |
| 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 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 637 | } // end namespace Eigen |
| 638 | |
| 639 | #endif // EIGEN_CHOLMODSUPPORT_H |