1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2012 Gael Guennebaud <gael.guennebaud (at) 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_SIMPLICIAL_CHOLESKY_H 11 #define EIGEN_SIMPLICIAL_CHOLESKY_H 12 13 namespace Eigen { 14 15 enum SimplicialCholeskyMode { 16 SimplicialCholeskyLLT, 17 SimplicialCholeskyLDLT 18 }; 19 20 namespace internal { 21 template<typename CholMatrixType, typename InputMatrixType> 22 struct simplicial_cholesky_grab_input { 23 typedef CholMatrixType const * ConstCholMatrixPtr; 24 static void run(const InputMatrixType& input, ConstCholMatrixPtr &pmat, CholMatrixType &tmp) 25 { 26 tmp = input; 27 pmat = &tmp; 28 } 29 }; 30 31 template<typename MatrixType> 32 struct simplicial_cholesky_grab_input<MatrixType,MatrixType> { 33 typedef MatrixType const * ConstMatrixPtr; 34 static void run(const MatrixType& input, ConstMatrixPtr &pmat, MatrixType &/*tmp*/) 35 { 36 pmat = &input; 37 } 38 }; 39 } // end namespace internal 40 41 /** \ingroup SparseCholesky_Module 42 * \brief A base class for direct sparse Cholesky factorizations 43 * 44 * This is a base class for LL^T and LDL^T Cholesky factorizations of sparse matrices that are 45 * selfadjoint and positive definite. These factorizations allow for solving A.X = B where 46 * X and B can be either dense or sparse. 47 * 48 * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization 49 * such that the factorized matrix is P A P^-1. 50 * 51 * \tparam Derived the type of the derived class, that is the actual factorization type. 52 * 53 */ 54 template<typename Derived> 55 class SimplicialCholeskyBase : public SparseSolverBase<Derived> 56 { 57 typedef SparseSolverBase<Derived> Base; 58 using Base::m_isInitialized; 59 60 public: 61 typedef typename internal::traits<Derived>::MatrixType MatrixType; 62 typedef typename internal::traits<Derived>::OrderingType OrderingType; 63 enum { UpLo = internal::traits<Derived>::UpLo }; 64 typedef typename MatrixType::Scalar Scalar; 65 typedef typename MatrixType::RealScalar RealScalar; 66 typedef typename MatrixType::StorageIndex StorageIndex; 67 typedef SparseMatrix<Scalar,ColMajor,StorageIndex> CholMatrixType; 68 typedef CholMatrixType const * ConstCholMatrixPtr; 69 typedef Matrix<Scalar,Dynamic,1> VectorType; 70 typedef Matrix<StorageIndex,Dynamic,1> VectorI; 71 72 enum { 73 ColsAtCompileTime = MatrixType::ColsAtCompileTime, 74 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime 75 }; 76 77 public: 78 79 using Base::derived; 80 81 /** Default constructor */ 82 SimplicialCholeskyBase() 83 : m_info(Success), m_shiftOffset(0), m_shiftScale(1) 84 {} 85 86 explicit SimplicialCholeskyBase(const MatrixType& matrix) 87 : m_info(Success), m_shiftOffset(0), m_shiftScale(1) 88 { 89 derived().compute(matrix); 90 } 91 92 ~SimplicialCholeskyBase() 93 { 94 } 95 96 Derived& derived() { return *static_cast<Derived*>(this); } 97 const Derived& derived() const { return *static_cast<const Derived*>(this); } 98 99 inline Index cols() const { return m_matrix.cols(); } 100 inline Index rows() const { return m_matrix.rows(); } 101 102 /** \brief Reports whether previous computation was successful. 103 * 104 * \returns \c Success if computation was succesful, 105 * \c NumericalIssue if the matrix.appears to be negative. 106 */ 107 ComputationInfo info() const 108 { 109 eigen_assert(m_isInitialized && "Decomposition is not initialized."); 110 return m_info; 111 } 112 113 /** \returns the permutation P 114 * \sa permutationPinv() */ 115 const PermutationMatrix<Dynamic,Dynamic,StorageIndex>& permutationP() const 116 { return m_P; } 117 118 /** \returns the inverse P^-1 of the permutation P 119 * \sa permutationP() */ 120 const PermutationMatrix<Dynamic,Dynamic,StorageIndex>& permutationPinv() const 121 { return m_Pinv; } 122 123 /** Sets the shift parameters that will be used to adjust the diagonal coefficients during the numerical factorization. 124 * 125 * During the numerical factorization, the diagonal coefficients are transformed by the following linear model:\n 126 * \c d_ii = \a offset + \a scale * \c d_ii 127 * 128 * The default is the identity transformation with \a offset=0, and \a scale=1. 129 * 130 * \returns a reference to \c *this. 131 */ 132 Derived& setShift(const RealScalar& offset, const RealScalar& scale = 1) 133 { 134 m_shiftOffset = offset; 135 m_shiftScale = scale; 136 return derived(); 137 } 138 139 #ifndef EIGEN_PARSED_BY_DOXYGEN 140 /** \internal */ 141 template<typename Stream> 142 void dumpMemory(Stream& s) 143 { 144 int total = 0; 145 s << " L: " << ((total+=(m_matrix.cols()+1) * sizeof(int) + m_matrix.nonZeros()*(sizeof(int)+sizeof(Scalar))) >> 20) << "Mb" << "\n"; 146 s << " diag: " << ((total+=m_diag.size() * sizeof(Scalar)) >> 20) << "Mb" << "\n"; 147 s << " tree: " << ((total+=m_parent.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 148 s << " nonzeros: " << ((total+=m_nonZerosPerCol.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 149 s << " perm: " << ((total+=m_P.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 150 s << " perm^-1: " << ((total+=m_Pinv.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 151 s << " TOTAL: " << (total>> 20) << "Mb" << "\n"; 152 } 153 154 /** \internal */ 155 template<typename Rhs,typename Dest> 156 void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const 157 { 158 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); 159 eigen_assert(m_matrix.rows()==b.rows()); 160 161 if(m_info!=Success) 162 return; 163 164 if(m_P.size()>0) 165 dest = m_P * b; 166 else 167 dest = b; 168 169 if(m_matrix.nonZeros()>0) // otherwise L==I 170 derived().matrixL().solveInPlace(dest); 171 172 if(m_diag.size()>0) 173 dest = m_diag.asDiagonal().inverse() * dest; 174 175 if (m_matrix.nonZeros()>0) // otherwise U==I 176 derived().matrixU().solveInPlace(dest); 177 178 if(m_P.size()>0) 179 dest = m_Pinv * dest; 180 } 181 182 template<typename Rhs,typename Dest> 183 void _solve_impl(const SparseMatrixBase<Rhs> &b, SparseMatrixBase<Dest> &dest) const 184 { 185 internal::solve_sparse_through_dense_panels(derived(), b, dest); 186 } 187 188 #endif // EIGEN_PARSED_BY_DOXYGEN 189 190 protected: 191 192 /** Computes the sparse Cholesky decomposition of \a matrix */ 193 template<bool DoLDLT> 194 void compute(const MatrixType& matrix) 195 { 196 eigen_assert(matrix.rows()==matrix.cols()); 197 Index size = matrix.cols(); 198 CholMatrixType tmp(size,size); 199 ConstCholMatrixPtr pmat; 200 ordering(matrix, pmat, tmp); 201 analyzePattern_preordered(*pmat, DoLDLT); 202 factorize_preordered<DoLDLT>(*pmat); 203 } 204 205 template<bool DoLDLT> 206 void factorize(const MatrixType& a) 207 { 208 eigen_assert(a.rows()==a.cols()); 209 Index size = a.cols(); 210 CholMatrixType tmp(size,size); 211 ConstCholMatrixPtr pmat; 212 213 if(m_P.size()==0 && (UpLo&Upper)==Upper) 214 { 215 // If there is no ordering, try to directly use the input matrix without any copy 216 internal::simplicial_cholesky_grab_input<CholMatrixType,MatrixType>::run(a, pmat, tmp); 217 } 218 else 219 { 220 tmp.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P); 221 pmat = &tmp; 222 } 223 224 factorize_preordered<DoLDLT>(*pmat); 225 } 226 227 template<bool DoLDLT> 228 void factorize_preordered(const CholMatrixType& a); 229 230 void analyzePattern(const MatrixType& a, bool doLDLT) 231 { 232 eigen_assert(a.rows()==a.cols()); 233 Index size = a.cols(); 234 CholMatrixType tmp(size,size); 235 ConstCholMatrixPtr pmat; 236 ordering(a, pmat, tmp); 237 analyzePattern_preordered(*pmat,doLDLT); 238 } 239 void analyzePattern_preordered(const CholMatrixType& a, bool doLDLT); 240 241 void ordering(const MatrixType& a, ConstCholMatrixPtr &pmat, CholMatrixType& ap); 242 243 /** keeps off-diagonal entries; drops diagonal entries */ 244 struct keep_diag { 245 inline bool operator() (const Index& row, const Index& col, const Scalar&) const 246 { 247 return row!=col; 248 } 249 }; 250 251 mutable ComputationInfo m_info; 252 bool m_factorizationIsOk; 253 bool m_analysisIsOk; 254 255 CholMatrixType m_matrix; 256 VectorType m_diag; // the diagonal coefficients (LDLT mode) 257 VectorI m_parent; // elimination tree 258 VectorI m_nonZerosPerCol; 259 PermutationMatrix<Dynamic,Dynamic,StorageIndex> m_P; // the permutation 260 PermutationMatrix<Dynamic,Dynamic,StorageIndex> m_Pinv; // the inverse permutation 261 262 RealScalar m_shiftOffset; 263 RealScalar m_shiftScale; 264 }; 265 266 template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::StorageIndex> > class SimplicialLLT; 267 template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::StorageIndex> > class SimplicialLDLT; 268 template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::StorageIndex> > class SimplicialCholesky; 269 270 namespace internal { 271 272 template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialLLT<_MatrixType,_UpLo,_Ordering> > 273 { 274 typedef _MatrixType MatrixType; 275 typedef _Ordering OrderingType; 276 enum { UpLo = _UpLo }; 277 typedef typename MatrixType::Scalar Scalar; 278 typedef typename MatrixType::StorageIndex StorageIndex; 279 typedef SparseMatrix<Scalar, ColMajor, StorageIndex> CholMatrixType; 280 typedef TriangularView<const CholMatrixType, Eigen::Lower> MatrixL; 281 typedef TriangularView<const typename CholMatrixType::AdjointReturnType, Eigen::Upper> MatrixU; 282 static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } 283 static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } 284 }; 285 286 template<typename _MatrixType,int _UpLo, typename _Ordering> struct traits<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> > 287 { 288 typedef _MatrixType MatrixType; 289 typedef _Ordering OrderingType; 290 enum { UpLo = _UpLo }; 291 typedef typename MatrixType::Scalar Scalar; 292 typedef typename MatrixType::StorageIndex StorageIndex; 293 typedef SparseMatrix<Scalar, ColMajor, StorageIndex> CholMatrixType; 294 typedef TriangularView<const CholMatrixType, Eigen::UnitLower> MatrixL; 295 typedef TriangularView<const typename CholMatrixType::AdjointReturnType, Eigen::UnitUpper> MatrixU; 296 static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } 297 static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } 298 }; 299 300 template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> > 301 { 302 typedef _MatrixType MatrixType; 303 typedef _Ordering OrderingType; 304 enum { UpLo = _UpLo }; 305 }; 306 307 } 308 309 /** \ingroup SparseCholesky_Module 310 * \class SimplicialLLT 311 * \brief A direct sparse LLT Cholesky factorizations 312 * 313 * This class provides a LL^T Cholesky factorizations of sparse matrices that are 314 * selfadjoint and positive definite. The factorization allows for solving A.X = B where 315 * X and B can be either dense or sparse. 316 * 317 * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization 318 * such that the factorized matrix is P A P^-1. 319 * 320 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 321 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower 322 * or Upper. Default is Lower. 323 * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<> 324 * 325 * \implsparsesolverconcept 326 * 327 * \sa class SimplicialLDLT, class AMDOrdering, class NaturalOrdering 328 */ 329 template<typename _MatrixType, int _UpLo, typename _Ordering> 330 class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo,_Ordering> > 331 { 332 public: 333 typedef _MatrixType MatrixType; 334 enum { UpLo = _UpLo }; 335 typedef SimplicialCholeskyBase<SimplicialLLT> Base; 336 typedef typename MatrixType::Scalar Scalar; 337 typedef typename MatrixType::RealScalar RealScalar; 338 typedef typename MatrixType::StorageIndex StorageIndex; 339 typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType; 340 typedef Matrix<Scalar,Dynamic,1> VectorType; 341 typedef internal::traits<SimplicialLLT> Traits; 342 typedef typename Traits::MatrixL MatrixL; 343 typedef typename Traits::MatrixU MatrixU; 344 public: 345 /** Default constructor */ 346 SimplicialLLT() : Base() {} 347 /** Constructs and performs the LLT factorization of \a matrix */ 348 explicit SimplicialLLT(const MatrixType& matrix) 349 : Base(matrix) {} 350 351 /** \returns an expression of the factor L */ 352 inline const MatrixL matrixL() const { 353 eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized"); 354 return Traits::getL(Base::m_matrix); 355 } 356 357 /** \returns an expression of the factor U (= L^*) */ 358 inline const MatrixU matrixU() const { 359 eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized"); 360 return Traits::getU(Base::m_matrix); 361 } 362 363 /** Computes the sparse Cholesky decomposition of \a matrix */ 364 SimplicialLLT& compute(const MatrixType& matrix) 365 { 366 Base::template compute<false>(matrix); 367 return *this; 368 } 369 370 /** Performs a symbolic decomposition on the sparcity of \a matrix. 371 * 372 * This function is particularly useful when solving for several problems having the same structure. 373 * 374 * \sa factorize() 375 */ 376 void analyzePattern(const MatrixType& a) 377 { 378 Base::analyzePattern(a, false); 379 } 380 381 /** Performs a numeric decomposition of \a matrix 382 * 383 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 384 * 385 * \sa analyzePattern() 386 */ 387 void factorize(const MatrixType& a) 388 { 389 Base::template factorize<false>(a); 390 } 391 392 /** \returns the determinant of the underlying matrix from the current factorization */ 393 Scalar determinant() const 394 { 395 Scalar detL = Base::m_matrix.diagonal().prod(); 396 return numext::abs2(detL); 397 } 398 }; 399 400 /** \ingroup SparseCholesky_Module 401 * \class SimplicialLDLT 402 * \brief A direct sparse LDLT Cholesky factorizations without square root. 403 * 404 * This class provides a LDL^T Cholesky factorizations without square root of sparse matrices that are 405 * selfadjoint and positive definite. The factorization allows for solving A.X = B where 406 * X and B can be either dense or sparse. 407 * 408 * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization 409 * such that the factorized matrix is P A P^-1. 410 * 411 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 412 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower 413 * or Upper. Default is Lower. 414 * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<> 415 * 416 * \implsparsesolverconcept 417 * 418 * \sa class SimplicialLLT, class AMDOrdering, class NaturalOrdering 419 */ 420 template<typename _MatrixType, int _UpLo, typename _Ordering> 421 class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> > 422 { 423 public: 424 typedef _MatrixType MatrixType; 425 enum { UpLo = _UpLo }; 426 typedef SimplicialCholeskyBase<SimplicialLDLT> Base; 427 typedef typename MatrixType::Scalar Scalar; 428 typedef typename MatrixType::RealScalar RealScalar; 429 typedef typename MatrixType::StorageIndex StorageIndex; 430 typedef SparseMatrix<Scalar,ColMajor,StorageIndex> CholMatrixType; 431 typedef Matrix<Scalar,Dynamic,1> VectorType; 432 typedef internal::traits<SimplicialLDLT> Traits; 433 typedef typename Traits::MatrixL MatrixL; 434 typedef typename Traits::MatrixU MatrixU; 435 public: 436 /** Default constructor */ 437 SimplicialLDLT() : Base() {} 438 439 /** Constructs and performs the LLT factorization of \a matrix */ 440 explicit SimplicialLDLT(const MatrixType& matrix) 441 : Base(matrix) {} 442 443 /** \returns a vector expression of the diagonal D */ 444 inline const VectorType vectorD() const { 445 eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); 446 return Base::m_diag; 447 } 448 /** \returns an expression of the factor L */ 449 inline const MatrixL matrixL() const { 450 eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); 451 return Traits::getL(Base::m_matrix); 452 } 453 454 /** \returns an expression of the factor U (= L^*) */ 455 inline const MatrixU matrixU() const { 456 eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); 457 return Traits::getU(Base::m_matrix); 458 } 459 460 /** Computes the sparse Cholesky decomposition of \a matrix */ 461 SimplicialLDLT& compute(const MatrixType& matrix) 462 { 463 Base::template compute<true>(matrix); 464 return *this; 465 } 466 467 /** Performs a symbolic decomposition on the sparcity of \a matrix. 468 * 469 * This function is particularly useful when solving for several problems having the same structure. 470 * 471 * \sa factorize() 472 */ 473 void analyzePattern(const MatrixType& a) 474 { 475 Base::analyzePattern(a, true); 476 } 477 478 /** Performs a numeric decomposition of \a matrix 479 * 480 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 481 * 482 * \sa analyzePattern() 483 */ 484 void factorize(const MatrixType& a) 485 { 486 Base::template factorize<true>(a); 487 } 488 489 /** \returns the determinant of the underlying matrix from the current factorization */ 490 Scalar determinant() const 491 { 492 return Base::m_diag.prod(); 493 } 494 }; 495 496 /** \deprecated use SimplicialLDLT or class SimplicialLLT 497 * \ingroup SparseCholesky_Module 498 * \class SimplicialCholesky 499 * 500 * \sa class SimplicialLDLT, class SimplicialLLT 501 */ 502 template<typename _MatrixType, int _UpLo, typename _Ordering> 503 class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> > 504 { 505 public: 506 typedef _MatrixType MatrixType; 507 enum { UpLo = _UpLo }; 508 typedef SimplicialCholeskyBase<SimplicialCholesky> Base; 509 typedef typename MatrixType::Scalar Scalar; 510 typedef typename MatrixType::RealScalar RealScalar; 511 typedef typename MatrixType::StorageIndex StorageIndex; 512 typedef SparseMatrix<Scalar,ColMajor,StorageIndex> CholMatrixType; 513 typedef Matrix<Scalar,Dynamic,1> VectorType; 514 typedef internal::traits<SimplicialCholesky> Traits; 515 typedef internal::traits<SimplicialLDLT<MatrixType,UpLo> > LDLTTraits; 516 typedef internal::traits<SimplicialLLT<MatrixType,UpLo> > LLTTraits; 517 public: 518 SimplicialCholesky() : Base(), m_LDLT(true) {} 519 520 explicit SimplicialCholesky(const MatrixType& matrix) 521 : Base(), m_LDLT(true) 522 { 523 compute(matrix); 524 } 525 526 SimplicialCholesky& setMode(SimplicialCholeskyMode mode) 527 { 528 switch(mode) 529 { 530 case SimplicialCholeskyLLT: 531 m_LDLT = false; 532 break; 533 case SimplicialCholeskyLDLT: 534 m_LDLT = true; 535 break; 536 default: 537 break; 538 } 539 540 return *this; 541 } 542 543 inline const VectorType vectorD() const { 544 eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized"); 545 return Base::m_diag; 546 } 547 inline const CholMatrixType rawMatrix() const { 548 eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized"); 549 return Base::m_matrix; 550 } 551 552 /** Computes the sparse Cholesky decomposition of \a matrix */ 553 SimplicialCholesky& compute(const MatrixType& matrix) 554 { 555 if(m_LDLT) 556 Base::template compute<true>(matrix); 557 else 558 Base::template compute<false>(matrix); 559 return *this; 560 } 561 562 /** Performs a symbolic decomposition on the sparcity of \a matrix. 563 * 564 * This function is particularly useful when solving for several problems having the same structure. 565 * 566 * \sa factorize() 567 */ 568 void analyzePattern(const MatrixType& a) 569 { 570 Base::analyzePattern(a, m_LDLT); 571 } 572 573 /** Performs a numeric decomposition of \a matrix 574 * 575 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 576 * 577 * \sa analyzePattern() 578 */ 579 void factorize(const MatrixType& a) 580 { 581 if(m_LDLT) 582 Base::template factorize<true>(a); 583 else 584 Base::template factorize<false>(a); 585 } 586 587 /** \internal */ 588 template<typename Rhs,typename Dest> 589 void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const 590 { 591 eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); 592 eigen_assert(Base::m_matrix.rows()==b.rows()); 593 594 if(Base::m_info!=Success) 595 return; 596 597 if(Base::m_P.size()>0) 598 dest = Base::m_P * b; 599 else 600 dest = b; 601 602 if(Base::m_matrix.nonZeros()>0) // otherwise L==I 603 { 604 if(m_LDLT) 605 LDLTTraits::getL(Base::m_matrix).solveInPlace(dest); 606 else 607 LLTTraits::getL(Base::m_matrix).solveInPlace(dest); 608 } 609 610 if(Base::m_diag.size()>0) 611 dest = Base::m_diag.asDiagonal().inverse() * dest; 612 613 if (Base::m_matrix.nonZeros()>0) // otherwise I==I 614 { 615 if(m_LDLT) 616 LDLTTraits::getU(Base::m_matrix).solveInPlace(dest); 617 else 618 LLTTraits::getU(Base::m_matrix).solveInPlace(dest); 619 } 620 621 if(Base::m_P.size()>0) 622 dest = Base::m_Pinv * dest; 623 } 624 625 /** \internal */ 626 template<typename Rhs,typename Dest> 627 void _solve_impl(const SparseMatrixBase<Rhs> &b, SparseMatrixBase<Dest> &dest) const 628 { 629 internal::solve_sparse_through_dense_panels(*this, b, dest); 630 } 631 632 Scalar determinant() const 633 { 634 if(m_LDLT) 635 { 636 return Base::m_diag.prod(); 637 } 638 else 639 { 640 Scalar detL = Diagonal<const CholMatrixType>(Base::m_matrix).prod(); 641 return numext::abs2(detL); 642 } 643 } 644 645 protected: 646 bool m_LDLT; 647 }; 648 649 template<typename Derived> 650 void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, ConstCholMatrixPtr &pmat, CholMatrixType& ap) 651 { 652 eigen_assert(a.rows()==a.cols()); 653 const Index size = a.rows(); 654 pmat = ≈ 655 // Note that ordering methods compute the inverse permutation 656 if(!internal::is_same<OrderingType,NaturalOrdering<Index> >::value) 657 { 658 { 659 CholMatrixType C; 660 C = a.template selfadjointView<UpLo>(); 661 662 OrderingType ordering; 663 ordering(C,m_Pinv); 664 } 665 666 if(m_Pinv.size()>0) m_P = m_Pinv.inverse(); 667 else m_P.resize(0); 668 669 ap.resize(size,size); 670 ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P); 671 } 672 else 673 { 674 m_Pinv.resize(0); 675 m_P.resize(0); 676 if(int(UpLo)==int(Lower) || MatrixType::IsRowMajor) 677 { 678 // we have to transpose the lower part to to the upper one 679 ap.resize(size,size); 680 ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>(); 681 } 682 else 683 internal::simplicial_cholesky_grab_input<CholMatrixType,MatrixType>::run(a, pmat, ap); 684 } 685 } 686 687 } // end namespace Eigen 688 689 #endif // EIGEN_SIMPLICIAL_CHOLESKY_H 690