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 (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 /* 11 12 NOTE: the _symbolic, and _numeric functions has been adapted from 13 the LDL library: 14 15 LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved. 16 17 LDL License: 18 19 Your use or distribution of LDL or any modified version of 20 LDL implies that you agree to this License. 21 22 This library is free software; you can redistribute it and/or 23 modify it under the terms of the GNU Lesser General Public 24 License as published by the Free Software Foundation; either 25 version 2.1 of the License, or (at your option) any later version. 26 27 This library is distributed in the hope that it will be useful, 28 but WITHOUT ANY WARRANTY; without even the implied warranty of 29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 Lesser General Public License for more details. 31 32 You should have received a copy of the GNU Lesser General Public 33 License along with this library; if not, write to the Free Software 34 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 35 USA 36 37 Permission is hereby granted to use or copy this program under the 38 terms of the GNU LGPL, provided that the Copyright, this License, 39 and the Availability of the original version is retained on all copies. 40 User documentation of any code that uses this code or any modified 41 version of this code must cite the Copyright, this License, the 42 Availability note, and "Used by permission." Permission to modify 43 the code and to distribute modified code is granted, provided the 44 Copyright, this License, and the Availability note are retained, 45 and a notice that the code was modified is included. 46 */ 47 48 #include "../Core/util/NonMPL2.h" 49 50 #ifndef EIGEN_SIMPLICIAL_CHOLESKY_H 51 #define EIGEN_SIMPLICIAL_CHOLESKY_H 52 53 namespace Eigen { 54 55 enum SimplicialCholeskyMode { 56 SimplicialCholeskyLLT, 57 SimplicialCholeskyLDLT 58 }; 59 60 /** \ingroup SparseCholesky_Module 61 * \brief A direct sparse Cholesky factorizations 62 * 63 * These classes provide LL^T and LDL^T Cholesky factorizations of sparse matrices that are 64 * selfadjoint and positive definite. The factorization allows for solving A.X = B where 65 * X and B can be either dense or sparse. 66 * 67 * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization 68 * such that the factorized matrix is P A P^-1. 69 * 70 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 71 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower 72 * or Upper. Default is Lower. 73 * 74 */ 75 template<typename Derived> 76 class SimplicialCholeskyBase : internal::noncopyable 77 { 78 public: 79 typedef typename internal::traits<Derived>::MatrixType MatrixType; 80 enum { UpLo = internal::traits<Derived>::UpLo }; 81 typedef typename MatrixType::Scalar Scalar; 82 typedef typename MatrixType::RealScalar RealScalar; 83 typedef typename MatrixType::Index Index; 84 typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType; 85 typedef Matrix<Scalar,Dynamic,1> VectorType; 86 87 public: 88 89 /** Default constructor */ 90 SimplicialCholeskyBase() 91 : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1) 92 {} 93 94 SimplicialCholeskyBase(const MatrixType& matrix) 95 : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1) 96 { 97 derived().compute(matrix); 98 } 99 100 ~SimplicialCholeskyBase() 101 { 102 } 103 104 Derived& derived() { return *static_cast<Derived*>(this); } 105 const Derived& derived() const { return *static_cast<const Derived*>(this); } 106 107 inline Index cols() const { return m_matrix.cols(); } 108 inline Index rows() const { return m_matrix.rows(); } 109 110 /** \brief Reports whether previous computation was successful. 111 * 112 * \returns \c Success if computation was succesful, 113 * \c NumericalIssue if the matrix.appears to be negative. 114 */ 115 ComputationInfo info() const 116 { 117 eigen_assert(m_isInitialized && "Decomposition is not initialized."); 118 return m_info; 119 } 120 121 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 122 * 123 * \sa compute() 124 */ 125 template<typename Rhs> 126 inline const internal::solve_retval<SimplicialCholeskyBase, Rhs> 127 solve(const MatrixBase<Rhs>& b) const 128 { 129 eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized."); 130 eigen_assert(rows()==b.rows() 131 && "SimplicialCholeskyBase::solve(): invalid number of rows of the right hand side matrix b"); 132 return internal::solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived()); 133 } 134 135 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 136 * 137 * \sa compute() 138 */ 139 template<typename Rhs> 140 inline const internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs> 141 solve(const SparseMatrixBase<Rhs>& b) const 142 { 143 eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized."); 144 eigen_assert(rows()==b.rows() 145 && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b"); 146 return internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived()); 147 } 148 149 /** \returns the permutation P 150 * \sa permutationPinv() */ 151 const PermutationMatrix<Dynamic,Dynamic,Index>& permutationP() const 152 { return m_P; } 153 154 /** \returns the inverse P^-1 of the permutation P 155 * \sa permutationP() */ 156 const PermutationMatrix<Dynamic,Dynamic,Index>& permutationPinv() const 157 { return m_Pinv; } 158 159 /** Sets the shift parameters that will be used to adjust the diagonal coefficients during the numerical factorization. 160 * 161 * During the numerical factorization, the diagonal coefficients are transformed by the following linear model:\n 162 * \c d_ii = \a offset + \a scale * \c d_ii 163 * 164 * The default is the identity transformation with \a offset=0, and \a scale=1. 165 * 166 * \returns a reference to \c *this. 167 */ 168 Derived& setShift(const RealScalar& offset, const RealScalar& scale = 1) 169 { 170 m_shiftOffset = offset; 171 m_shiftScale = scale; 172 return derived(); 173 } 174 175 #ifndef EIGEN_PARSED_BY_DOXYGEN 176 /** \internal */ 177 template<typename Stream> 178 void dumpMemory(Stream& s) 179 { 180 int total = 0; 181 s << " L: " << ((total+=(m_matrix.cols()+1) * sizeof(int) + m_matrix.nonZeros()*(sizeof(int)+sizeof(Scalar))) >> 20) << "Mb" << "\n"; 182 s << " diag: " << ((total+=m_diag.size() * sizeof(Scalar)) >> 20) << "Mb" << "\n"; 183 s << " tree: " << ((total+=m_parent.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 184 s << " nonzeros: " << ((total+=m_nonZerosPerCol.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 185 s << " perm: " << ((total+=m_P.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 186 s << " perm^-1: " << ((total+=m_Pinv.size() * sizeof(int)) >> 20) << "Mb" << "\n"; 187 s << " TOTAL: " << (total>> 20) << "Mb" << "\n"; 188 } 189 190 /** \internal */ 191 template<typename Rhs,typename Dest> 192 void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const 193 { 194 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); 195 eigen_assert(m_matrix.rows()==b.rows()); 196 197 if(m_info!=Success) 198 return; 199 200 if(m_P.size()>0) 201 dest = m_P * b; 202 else 203 dest = b; 204 205 if(m_matrix.nonZeros()>0) // otherwise L==I 206 derived().matrixL().solveInPlace(dest); 207 208 if(m_diag.size()>0) 209 dest = m_diag.asDiagonal().inverse() * dest; 210 211 if (m_matrix.nonZeros()>0) // otherwise U==I 212 derived().matrixU().solveInPlace(dest); 213 214 if(m_P.size()>0) 215 dest = m_Pinv * dest; 216 } 217 218 /** \internal */ 219 template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex> 220 void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const 221 { 222 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); 223 eigen_assert(m_matrix.rows()==b.rows()); 224 225 // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. 226 static const int NbColsAtOnce = 4; 227 int rhsCols = b.cols(); 228 int size = b.rows(); 229 Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols); 230 for(int k=0; k<rhsCols; k+=NbColsAtOnce) 231 { 232 int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce); 233 tmp.leftCols(actualCols) = b.middleCols(k,actualCols); 234 tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols)); 235 dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView(); 236 } 237 } 238 239 #endif // EIGEN_PARSED_BY_DOXYGEN 240 241 protected: 242 243 /** Computes the sparse Cholesky decomposition of \a matrix */ 244 template<bool DoLDLT> 245 void compute(const MatrixType& matrix) 246 { 247 eigen_assert(matrix.rows()==matrix.cols()); 248 Index size = matrix.cols(); 249 CholMatrixType ap(size,size); 250 ordering(matrix, ap); 251 analyzePattern_preordered(ap, DoLDLT); 252 factorize_preordered<DoLDLT>(ap); 253 } 254 255 template<bool DoLDLT> 256 void factorize(const MatrixType& a) 257 { 258 eigen_assert(a.rows()==a.cols()); 259 int size = a.cols(); 260 CholMatrixType ap(size,size); 261 ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P); 262 factorize_preordered<DoLDLT>(ap); 263 } 264 265 template<bool DoLDLT> 266 void factorize_preordered(const CholMatrixType& a); 267 268 void analyzePattern(const MatrixType& a, bool doLDLT) 269 { 270 eigen_assert(a.rows()==a.cols()); 271 int size = a.cols(); 272 CholMatrixType ap(size,size); 273 ordering(a, ap); 274 analyzePattern_preordered(ap,doLDLT); 275 } 276 void analyzePattern_preordered(const CholMatrixType& a, bool doLDLT); 277 278 void ordering(const MatrixType& a, CholMatrixType& ap); 279 280 /** keeps off-diagonal entries; drops diagonal entries */ 281 struct keep_diag { 282 inline bool operator() (const Index& row, const Index& col, const Scalar&) const 283 { 284 return row!=col; 285 } 286 }; 287 288 mutable ComputationInfo m_info; 289 bool m_isInitialized; 290 bool m_factorizationIsOk; 291 bool m_analysisIsOk; 292 293 CholMatrixType m_matrix; 294 VectorType m_diag; // the diagonal coefficients (LDLT mode) 295 VectorXi m_parent; // elimination tree 296 VectorXi m_nonZerosPerCol; 297 PermutationMatrix<Dynamic,Dynamic,Index> m_P; // the permutation 298 PermutationMatrix<Dynamic,Dynamic,Index> m_Pinv; // the inverse permutation 299 300 RealScalar m_shiftOffset; 301 RealScalar m_shiftScale; 302 }; 303 304 template<typename _MatrixType, int _UpLo = Lower> class SimplicialLLT; 305 template<typename _MatrixType, int _UpLo = Lower> class SimplicialLDLT; 306 template<typename _MatrixType, int _UpLo = Lower> class SimplicialCholesky; 307 308 namespace internal { 309 310 template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixType,_UpLo> > 311 { 312 typedef _MatrixType MatrixType; 313 enum { UpLo = _UpLo }; 314 typedef typename MatrixType::Scalar Scalar; 315 typedef typename MatrixType::Index Index; 316 typedef SparseMatrix<Scalar, ColMajor, Index> CholMatrixType; 317 typedef SparseTriangularView<CholMatrixType, Eigen::Lower> MatrixL; 318 typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::Upper> MatrixU; 319 static inline MatrixL getL(const MatrixType& m) { return m; } 320 static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } 321 }; 322 323 template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixType,_UpLo> > 324 { 325 typedef _MatrixType MatrixType; 326 enum { UpLo = _UpLo }; 327 typedef typename MatrixType::Scalar Scalar; 328 typedef typename MatrixType::Index Index; 329 typedef SparseMatrix<Scalar, ColMajor, Index> CholMatrixType; 330 typedef SparseTriangularView<CholMatrixType, Eigen::UnitLower> MatrixL; 331 typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::UnitUpper> MatrixU; 332 static inline MatrixL getL(const MatrixType& m) { return m; } 333 static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } 334 }; 335 336 template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_MatrixType,_UpLo> > 337 { 338 typedef _MatrixType MatrixType; 339 enum { UpLo = _UpLo }; 340 }; 341 342 } 343 344 /** \ingroup SparseCholesky_Module 345 * \class SimplicialLLT 346 * \brief A direct sparse LLT Cholesky factorizations 347 * 348 * This class provides a LL^T Cholesky factorizations of sparse matrices that are 349 * selfadjoint and positive definite. The factorization allows for solving A.X = B where 350 * X and B can be either dense or sparse. 351 * 352 * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization 353 * such that the factorized matrix is P A P^-1. 354 * 355 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 356 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower 357 * or Upper. Default is Lower. 358 * 359 * \sa class SimplicialLDLT 360 */ 361 template<typename _MatrixType, int _UpLo> 362 class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo> > 363 { 364 public: 365 typedef _MatrixType MatrixType; 366 enum { UpLo = _UpLo }; 367 typedef SimplicialCholeskyBase<SimplicialLLT> Base; 368 typedef typename MatrixType::Scalar Scalar; 369 typedef typename MatrixType::RealScalar RealScalar; 370 typedef typename MatrixType::Index Index; 371 typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType; 372 typedef Matrix<Scalar,Dynamic,1> VectorType; 373 typedef internal::traits<SimplicialLLT> Traits; 374 typedef typename Traits::MatrixL MatrixL; 375 typedef typename Traits::MatrixU MatrixU; 376 public: 377 /** Default constructor */ 378 SimplicialLLT() : Base() {} 379 /** Constructs and performs the LLT factorization of \a matrix */ 380 SimplicialLLT(const MatrixType& matrix) 381 : Base(matrix) {} 382 383 /** \returns an expression of the factor L */ 384 inline const MatrixL matrixL() const { 385 eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized"); 386 return Traits::getL(Base::m_matrix); 387 } 388 389 /** \returns an expression of the factor U (= L^*) */ 390 inline const MatrixU matrixU() const { 391 eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized"); 392 return Traits::getU(Base::m_matrix); 393 } 394 395 /** Computes the sparse Cholesky decomposition of \a matrix */ 396 SimplicialLLT& compute(const MatrixType& matrix) 397 { 398 Base::template compute<false>(matrix); 399 return *this; 400 } 401 402 /** Performs a symbolic decomposition on the sparcity of \a matrix. 403 * 404 * This function is particularly useful when solving for several problems having the same structure. 405 * 406 * \sa factorize() 407 */ 408 void analyzePattern(const MatrixType& a) 409 { 410 Base::analyzePattern(a, false); 411 } 412 413 /** Performs a numeric decomposition of \a matrix 414 * 415 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 416 * 417 * \sa analyzePattern() 418 */ 419 void factorize(const MatrixType& a) 420 { 421 Base::template factorize<false>(a); 422 } 423 424 /** \returns the determinant of the underlying matrix from the current factorization */ 425 Scalar determinant() const 426 { 427 Scalar detL = Base::m_matrix.diagonal().prod(); 428 return internal::abs2(detL); 429 } 430 }; 431 432 /** \ingroup SparseCholesky_Module 433 * \class SimplicialLDLT 434 * \brief A direct sparse LDLT Cholesky factorizations without square root. 435 * 436 * This class provides a LDL^T Cholesky factorizations without square root of sparse matrices that are 437 * selfadjoint and positive definite. The factorization allows for solving A.X = B where 438 * X and B can be either dense or sparse. 439 * 440 * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization 441 * such that the factorized matrix is P A P^-1. 442 * 443 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 444 * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower 445 * or Upper. Default is Lower. 446 * 447 * \sa class SimplicialLLT 448 */ 449 template<typename _MatrixType, int _UpLo> 450 class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo> > 451 { 452 public: 453 typedef _MatrixType MatrixType; 454 enum { UpLo = _UpLo }; 455 typedef SimplicialCholeskyBase<SimplicialLDLT> Base; 456 typedef typename MatrixType::Scalar Scalar; 457 typedef typename MatrixType::RealScalar RealScalar; 458 typedef typename MatrixType::Index Index; 459 typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType; 460 typedef Matrix<Scalar,Dynamic,1> VectorType; 461 typedef internal::traits<SimplicialLDLT> Traits; 462 typedef typename Traits::MatrixL MatrixL; 463 typedef typename Traits::MatrixU MatrixU; 464 public: 465 /** Default constructor */ 466 SimplicialLDLT() : Base() {} 467 468 /** Constructs and performs the LLT factorization of \a matrix */ 469 SimplicialLDLT(const MatrixType& matrix) 470 : Base(matrix) {} 471 472 /** \returns a vector expression of the diagonal D */ 473 inline const VectorType vectorD() const { 474 eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); 475 return Base::m_diag; 476 } 477 /** \returns an expression of the factor L */ 478 inline const MatrixL matrixL() const { 479 eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); 480 return Traits::getL(Base::m_matrix); 481 } 482 483 /** \returns an expression of the factor U (= L^*) */ 484 inline const MatrixU matrixU() const { 485 eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); 486 return Traits::getU(Base::m_matrix); 487 } 488 489 /** Computes the sparse Cholesky decomposition of \a matrix */ 490 SimplicialLDLT& compute(const MatrixType& matrix) 491 { 492 Base::template compute<true>(matrix); 493 return *this; 494 } 495 496 /** Performs a symbolic decomposition on the sparcity of \a matrix. 497 * 498 * This function is particularly useful when solving for several problems having the same structure. 499 * 500 * \sa factorize() 501 */ 502 void analyzePattern(const MatrixType& a) 503 { 504 Base::analyzePattern(a, true); 505 } 506 507 /** Performs a numeric decomposition of \a matrix 508 * 509 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 510 * 511 * \sa analyzePattern() 512 */ 513 void factorize(const MatrixType& a) 514 { 515 Base::template factorize<true>(a); 516 } 517 518 /** \returns the determinant of the underlying matrix from the current factorization */ 519 Scalar determinant() const 520 { 521 return Base::m_diag.prod(); 522 } 523 }; 524 525 /** \deprecated use SimplicialLDLT or class SimplicialLLT 526 * \ingroup SparseCholesky_Module 527 * \class SimplicialCholesky 528 * 529 * \sa class SimplicialLDLT, class SimplicialLLT 530 */ 531 template<typename _MatrixType, int _UpLo> 532 class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo> > 533 { 534 public: 535 typedef _MatrixType MatrixType; 536 enum { UpLo = _UpLo }; 537 typedef SimplicialCholeskyBase<SimplicialCholesky> Base; 538 typedef typename MatrixType::Scalar Scalar; 539 typedef typename MatrixType::RealScalar RealScalar; 540 typedef typename MatrixType::Index Index; 541 typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType; 542 typedef Matrix<Scalar,Dynamic,1> VectorType; 543 typedef internal::traits<SimplicialCholesky> Traits; 544 typedef internal::traits<SimplicialLDLT<MatrixType,UpLo> > LDLTTraits; 545 typedef internal::traits<SimplicialLLT<MatrixType,UpLo> > LLTTraits; 546 public: 547 SimplicialCholesky() : Base(), m_LDLT(true) {} 548 549 SimplicialCholesky(const MatrixType& matrix) 550 : Base(), m_LDLT(true) 551 { 552 compute(matrix); 553 } 554 555 SimplicialCholesky& setMode(SimplicialCholeskyMode mode) 556 { 557 switch(mode) 558 { 559 case SimplicialCholeskyLLT: 560 m_LDLT = false; 561 break; 562 case SimplicialCholeskyLDLT: 563 m_LDLT = true; 564 break; 565 default: 566 break; 567 } 568 569 return *this; 570 } 571 572 inline const VectorType vectorD() const { 573 eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized"); 574 return Base::m_diag; 575 } 576 inline const CholMatrixType rawMatrix() const { 577 eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized"); 578 return Base::m_matrix; 579 } 580 581 /** Computes the sparse Cholesky decomposition of \a matrix */ 582 SimplicialCholesky& compute(const MatrixType& matrix) 583 { 584 if(m_LDLT) 585 Base::template compute<true>(matrix); 586 else 587 Base::template compute<false>(matrix); 588 return *this; 589 } 590 591 /** Performs a symbolic decomposition on the sparcity of \a matrix. 592 * 593 * This function is particularly useful when solving for several problems having the same structure. 594 * 595 * \sa factorize() 596 */ 597 void analyzePattern(const MatrixType& a) 598 { 599 Base::analyzePattern(a, m_LDLT); 600 } 601 602 /** Performs a numeric decomposition of \a matrix 603 * 604 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 605 * 606 * \sa analyzePattern() 607 */ 608 void factorize(const MatrixType& a) 609 { 610 if(m_LDLT) 611 Base::template factorize<true>(a); 612 else 613 Base::template factorize<false>(a); 614 } 615 616 /** \internal */ 617 template<typename Rhs,typename Dest> 618 void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const 619 { 620 eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); 621 eigen_assert(Base::m_matrix.rows()==b.rows()); 622 623 if(Base::m_info!=Success) 624 return; 625 626 if(Base::m_P.size()>0) 627 dest = Base::m_P * b; 628 else 629 dest = b; 630 631 if(Base::m_matrix.nonZeros()>0) // otherwise L==I 632 { 633 if(m_LDLT) 634 LDLTTraits::getL(Base::m_matrix).solveInPlace(dest); 635 else 636 LLTTraits::getL(Base::m_matrix).solveInPlace(dest); 637 } 638 639 if(Base::m_diag.size()>0) 640 dest = Base::m_diag.asDiagonal().inverse() * dest; 641 642 if (Base::m_matrix.nonZeros()>0) // otherwise I==I 643 { 644 if(m_LDLT) 645 LDLTTraits::getU(Base::m_matrix).solveInPlace(dest); 646 else 647 LLTTraits::getU(Base::m_matrix).solveInPlace(dest); 648 } 649 650 if(Base::m_P.size()>0) 651 dest = Base::m_Pinv * dest; 652 } 653 654 Scalar determinant() const 655 { 656 if(m_LDLT) 657 { 658 return Base::m_diag.prod(); 659 } 660 else 661 { 662 Scalar detL = Diagonal<const CholMatrixType>(Base::m_matrix).prod(); 663 return internal::abs2(detL); 664 } 665 } 666 667 protected: 668 bool m_LDLT; 669 }; 670 671 template<typename Derived> 672 void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, CholMatrixType& ap) 673 { 674 eigen_assert(a.rows()==a.cols()); 675 const Index size = a.rows(); 676 // TODO allows to configure the permutation 677 // Note that amd compute the inverse permutation 678 { 679 CholMatrixType C; 680 C = a.template selfadjointView<UpLo>(); 681 // remove diagonal entries: 682 // seems not to be needed 683 // C.prune(keep_diag()); 684 internal::minimum_degree_ordering(C, m_Pinv); 685 } 686 687 if(m_Pinv.size()>0) 688 m_P = m_Pinv.inverse(); 689 else 690 m_P.resize(0); 691 692 ap.resize(size,size); 693 ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P); 694 } 695 696 template<typename Derived> 697 void SimplicialCholeskyBase<Derived>::analyzePattern_preordered(const CholMatrixType& ap, bool doLDLT) 698 { 699 const Index size = ap.rows(); 700 m_matrix.resize(size, size); 701 m_parent.resize(size); 702 m_nonZerosPerCol.resize(size); 703 704 ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0); 705 706 for(Index k = 0; k < size; ++k) 707 { 708 /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */ 709 m_parent[k] = -1; /* parent of k is not yet known */ 710 tags[k] = k; /* mark node k as visited */ 711 m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ 712 for(typename CholMatrixType::InnerIterator it(ap,k); it; ++it) 713 { 714 Index i = it.index(); 715 if(i < k) 716 { 717 /* follow path from i to root of etree, stop at flagged node */ 718 for(; tags[i] != k; i = m_parent[i]) 719 { 720 /* find parent of i if not yet determined */ 721 if (m_parent[i] == -1) 722 m_parent[i] = k; 723 m_nonZerosPerCol[i]++; /* L (k,i) is nonzero */ 724 tags[i] = k; /* mark i as visited */ 725 } 726 } 727 } 728 } 729 730 /* construct Lp index array from m_nonZerosPerCol column counts */ 731 Index* Lp = m_matrix.outerIndexPtr(); 732 Lp[0] = 0; 733 for(Index k = 0; k < size; ++k) 734 Lp[k+1] = Lp[k] + m_nonZerosPerCol[k] + (doLDLT ? 0 : 1); 735 736 m_matrix.resizeNonZeros(Lp[size]); 737 738 m_isInitialized = true; 739 m_info = Success; 740 m_analysisIsOk = true; 741 m_factorizationIsOk = false; 742 } 743 744 745 template<typename Derived> 746 template<bool DoLDLT> 747 void SimplicialCholeskyBase<Derived>::factorize_preordered(const CholMatrixType& ap) 748 { 749 eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); 750 eigen_assert(ap.rows()==ap.cols()); 751 const Index size = ap.rows(); 752 eigen_assert(m_parent.size()==size); 753 eigen_assert(m_nonZerosPerCol.size()==size); 754 755 const Index* Lp = m_matrix.outerIndexPtr(); 756 Index* Li = m_matrix.innerIndexPtr(); 757 Scalar* Lx = m_matrix.valuePtr(); 758 759 ei_declare_aligned_stack_constructed_variable(Scalar, y, size, 0); 760 ei_declare_aligned_stack_constructed_variable(Index, pattern, size, 0); 761 ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0); 762 763 bool ok = true; 764 m_diag.resize(DoLDLT ? size : 0); 765 766 for(Index k = 0; k < size; ++k) 767 { 768 // compute nonzero pattern of kth row of L, in topological order 769 y[k] = 0.0; // Y(0:k) is now all zero 770 Index top = size; // stack for pattern is empty 771 tags[k] = k; // mark node k as visited 772 m_nonZerosPerCol[k] = 0; // count of nonzeros in column k of L 773 for(typename MatrixType::InnerIterator it(ap,k); it; ++it) 774 { 775 Index i = it.index(); 776 if(i <= k) 777 { 778 y[i] += internal::conj(it.value()); /* scatter A(i,k) into Y (sum duplicates) */ 779 Index len; 780 for(len = 0; tags[i] != k; i = m_parent[i]) 781 { 782 pattern[len++] = i; /* L(k,i) is nonzero */ 783 tags[i] = k; /* mark i as visited */ 784 } 785 while(len > 0) 786 pattern[--top] = pattern[--len]; 787 } 788 } 789 790 /* compute numerical values kth row of L (a sparse triangular solve) */ 791 792 RealScalar d = internal::real(y[k]) * m_shiftScale + m_shiftOffset; // get D(k,k), apply the shift function, and clear Y(k) 793 y[k] = 0.0; 794 for(; top < size; ++top) 795 { 796 Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */ 797 Scalar yi = y[i]; /* get and clear Y(i) */ 798 y[i] = 0.0; 799 800 /* the nonzero entry L(k,i) */ 801 Scalar l_ki; 802 if(DoLDLT) 803 l_ki = yi / m_diag[i]; 804 else 805 yi = l_ki = yi / Lx[Lp[i]]; 806 807 Index p2 = Lp[i] + m_nonZerosPerCol[i]; 808 Index p; 809 for(p = Lp[i] + (DoLDLT ? 0 : 1); p < p2; ++p) 810 y[Li[p]] -= internal::conj(Lx[p]) * yi; 811 d -= internal::real(l_ki * internal::conj(yi)); 812 Li[p] = k; /* store L(k,i) in column form of L */ 813 Lx[p] = l_ki; 814 ++m_nonZerosPerCol[i]; /* increment count of nonzeros in col i */ 815 } 816 if(DoLDLT) 817 { 818 m_diag[k] = d; 819 if(d == RealScalar(0)) 820 { 821 ok = false; /* failure, D(k,k) is zero */ 822 break; 823 } 824 } 825 else 826 { 827 Index p = Lp[k] + m_nonZerosPerCol[k]++; 828 Li[p] = k ; /* store L(k,k) = sqrt (d) in column k */ 829 if(d <= RealScalar(0)) { 830 ok = false; /* failure, matrix is not positive definite */ 831 break; 832 } 833 Lx[p] = internal::sqrt(d) ; 834 } 835 } 836 837 m_info = ok ? Success : NumericalIssue; 838 m_factorizationIsOk = true; 839 } 840 841 namespace internal { 842 843 template<typename Derived, typename Rhs> 844 struct solve_retval<SimplicialCholeskyBase<Derived>, Rhs> 845 : solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs> 846 { 847 typedef SimplicialCholeskyBase<Derived> Dec; 848 EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) 849 850 template<typename Dest> void evalTo(Dest& dst) const 851 { 852 dec().derived()._solve(rhs(),dst); 853 } 854 }; 855 856 template<typename Derived, typename Rhs> 857 struct sparse_solve_retval<SimplicialCholeskyBase<Derived>, Rhs> 858 : sparse_solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs> 859 { 860 typedef SimplicialCholeskyBase<Derived> Dec; 861 EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) 862 863 template<typename Dest> void evalTo(Dest& dst) const 864 { 865 dec().derived()._solve_sparse(rhs(),dst); 866 } 867 }; 868 869 } // end namespace internal 870 871 } // end namespace Eigen 872 873 #endif // EIGEN_SIMPLICIAL_CHOLESKY_H 874