1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2012 Dsir Nuentsa-Wakam <desire.nuentsa_wakam (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_PASTIXSUPPORT_H 11 #define EIGEN_PASTIXSUPPORT_H 12 13 namespace Eigen { 14 15 /** \ingroup PaStiXSupport_Module 16 * \brief Interface to the PaStix solver 17 * 18 * This class is used to solve the linear systems A.X = B via the PaStix library. 19 * The matrix can be either real or complex, symmetric or not. 20 * 21 * \sa TutorialSparseDirectSolvers 22 */ 23 template<typename _MatrixType, bool IsStrSym = false> class PastixLU; 24 template<typename _MatrixType, int Options> class PastixLLT; 25 template<typename _MatrixType, int Options> class PastixLDLT; 26 27 namespace internal 28 { 29 30 template<class Pastix> struct pastix_traits; 31 32 template<typename _MatrixType> 33 struct pastix_traits< PastixLU<_MatrixType> > 34 { 35 typedef _MatrixType MatrixType; 36 typedef typename _MatrixType::Scalar Scalar; 37 typedef typename _MatrixType::RealScalar RealScalar; 38 typedef typename _MatrixType::Index Index; 39 }; 40 41 template<typename _MatrixType, int Options> 42 struct pastix_traits< PastixLLT<_MatrixType,Options> > 43 { 44 typedef _MatrixType MatrixType; 45 typedef typename _MatrixType::Scalar Scalar; 46 typedef typename _MatrixType::RealScalar RealScalar; 47 typedef typename _MatrixType::Index Index; 48 }; 49 50 template<typename _MatrixType, int Options> 51 struct pastix_traits< PastixLDLT<_MatrixType,Options> > 52 { 53 typedef _MatrixType MatrixType; 54 typedef typename _MatrixType::Scalar Scalar; 55 typedef typename _MatrixType::RealScalar RealScalar; 56 typedef typename _MatrixType::Index Index; 57 }; 58 59 void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, float *vals, int *perm, int * invp, float *x, int nbrhs, int *iparm, double *dparm) 60 { 61 if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } 62 if (nbrhs == 0) {x = NULL; nbrhs=1;} 63 s_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm); 64 } 65 66 void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, double *vals, int *perm, int * invp, double *x, int nbrhs, int *iparm, double *dparm) 67 { 68 if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } 69 if (nbrhs == 0) {x = NULL; nbrhs=1;} 70 d_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm); 71 } 72 73 void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<float> *vals, int *perm, int * invp, std::complex<float> *x, int nbrhs, int *iparm, double *dparm) 74 { 75 if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } 76 if (nbrhs == 0) {x = NULL; nbrhs=1;} 77 c_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<COMPLEX*>(vals), perm, invp, reinterpret_cast<COMPLEX*>(x), nbrhs, iparm, dparm); 78 } 79 80 void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<double> *vals, int *perm, int * invp, std::complex<double> *x, int nbrhs, int *iparm, double *dparm) 81 { 82 if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } 83 if (nbrhs == 0) {x = NULL; nbrhs=1;} 84 z_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<DCOMPLEX*>(vals), perm, invp, reinterpret_cast<DCOMPLEX*>(x), nbrhs, iparm, dparm); 85 } 86 87 // Convert the matrix to Fortran-style Numbering 88 template <typename MatrixType> 89 void c_to_fortran_numbering (MatrixType& mat) 90 { 91 if ( !(mat.outerIndexPtr()[0]) ) 92 { 93 int i; 94 for(i = 0; i <= mat.rows(); ++i) 95 ++mat.outerIndexPtr()[i]; 96 for(i = 0; i < mat.nonZeros(); ++i) 97 ++mat.innerIndexPtr()[i]; 98 } 99 } 100 101 // Convert to C-style Numbering 102 template <typename MatrixType> 103 void fortran_to_c_numbering (MatrixType& mat) 104 { 105 // Check the Numbering 106 if ( mat.outerIndexPtr()[0] == 1 ) 107 { // Convert to C-style numbering 108 int i; 109 for(i = 0; i <= mat.rows(); ++i) 110 --mat.outerIndexPtr()[i]; 111 for(i = 0; i < mat.nonZeros(); ++i) 112 --mat.innerIndexPtr()[i]; 113 } 114 } 115 } 116 117 // This is the base class to interface with PaStiX functions. 118 // Users should not used this class directly. 119 template <class Derived> 120 class PastixBase : internal::noncopyable 121 { 122 public: 123 typedef typename internal::pastix_traits<Derived>::MatrixType _MatrixType; 124 typedef _MatrixType MatrixType; 125 typedef typename MatrixType::Scalar Scalar; 126 typedef typename MatrixType::RealScalar RealScalar; 127 typedef typename MatrixType::Index Index; 128 typedef Matrix<Scalar,Dynamic,1> Vector; 129 typedef SparseMatrix<Scalar, ColMajor> ColSpMatrix; 130 131 public: 132 133 PastixBase() : m_initisOk(false), m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false), m_pastixdata(0), m_size(0) 134 { 135 init(); 136 } 137 138 ~PastixBase() 139 { 140 clean(); 141 } 142 143 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 144 * 145 * \sa compute() 146 */ 147 template<typename Rhs> 148 inline const internal::solve_retval<PastixBase, Rhs> 149 solve(const MatrixBase<Rhs>& b) const 150 { 151 eigen_assert(m_isInitialized && "Pastix solver is not initialized."); 152 eigen_assert(rows()==b.rows() 153 && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); 154 return internal::solve_retval<PastixBase, Rhs>(*this, b.derived()); 155 } 156 157 template<typename Rhs,typename Dest> 158 bool _solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const; 159 160 /** \internal */ 161 template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex> 162 void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const 163 { 164 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); 165 eigen_assert(rows()==b.rows()); 166 167 // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. 168 static const int NbColsAtOnce = 1; 169 int rhsCols = b.cols(); 170 int size = b.rows(); 171 Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols); 172 for(int k=0; k<rhsCols; k+=NbColsAtOnce) 173 { 174 int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce); 175 tmp.leftCols(actualCols) = b.middleCols(k,actualCols); 176 tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols)); 177 dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView(); 178 } 179 } 180 181 Derived& derived() 182 { 183 return *static_cast<Derived*>(this); 184 } 185 const Derived& derived() const 186 { 187 return *static_cast<const Derived*>(this); 188 } 189 190 /** Returns a reference to the integer vector IPARM of PaStiX parameters 191 * to modify the default parameters. 192 * The statistics related to the different phases of factorization and solve are saved here as well 193 * \sa analyzePattern() factorize() 194 */ 195 Array<Index,IPARM_SIZE,1>& iparm() 196 { 197 return m_iparm; 198 } 199 200 /** Return a reference to a particular index parameter of the IPARM vector 201 * \sa iparm() 202 */ 203 204 int& iparm(int idxparam) 205 { 206 return m_iparm(idxparam); 207 } 208 209 /** Returns a reference to the double vector DPARM of PaStiX parameters 210 * The statistics related to the different phases of factorization and solve are saved here as well 211 * \sa analyzePattern() factorize() 212 */ 213 Array<RealScalar,IPARM_SIZE,1>& dparm() 214 { 215 return m_dparm; 216 } 217 218 219 /** Return a reference to a particular index parameter of the DPARM vector 220 * \sa dparm() 221 */ 222 double& dparm(int idxparam) 223 { 224 return m_dparm(idxparam); 225 } 226 227 inline Index cols() const { return m_size; } 228 inline Index rows() const { return m_size; } 229 230 /** \brief Reports whether previous computation was successful. 231 * 232 * \returns \c Success if computation was succesful, 233 * \c NumericalIssue if the PaStiX reports a problem 234 * \c InvalidInput if the input matrix is invalid 235 * 236 * \sa iparm() 237 */ 238 ComputationInfo info() const 239 { 240 eigen_assert(m_isInitialized && "Decomposition is not initialized."); 241 return m_info; 242 } 243 244 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 245 * 246 * \sa compute() 247 */ 248 template<typename Rhs> 249 inline const internal::sparse_solve_retval<PastixBase, Rhs> 250 solve(const SparseMatrixBase<Rhs>& b) const 251 { 252 eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized."); 253 eigen_assert(rows()==b.rows() 254 && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); 255 return internal::sparse_solve_retval<PastixBase, Rhs>(*this, b.derived()); 256 } 257 258 protected: 259 260 // Initialize the Pastix data structure, check the matrix 261 void init(); 262 263 // Compute the ordering and the symbolic factorization 264 void analyzePattern(ColSpMatrix& mat); 265 266 // Compute the numerical factorization 267 void factorize(ColSpMatrix& mat); 268 269 // Free all the data allocated by Pastix 270 void clean() 271 { 272 eigen_assert(m_initisOk && "The Pastix structure should be allocated first"); 273 m_iparm(IPARM_START_TASK) = API_TASK_CLEAN; 274 m_iparm(IPARM_END_TASK) = API_TASK_CLEAN; 275 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0, 276 m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); 277 } 278 279 void compute(ColSpMatrix& mat); 280 281 int m_initisOk; 282 int m_analysisIsOk; 283 int m_factorizationIsOk; 284 bool m_isInitialized; 285 mutable ComputationInfo m_info; 286 mutable pastix_data_t *m_pastixdata; // Data structure for pastix 287 mutable int m_comm; // The MPI communicator identifier 288 mutable Matrix<int,IPARM_SIZE,1> m_iparm; // integer vector for the input parameters 289 mutable Matrix<double,DPARM_SIZE,1> m_dparm; // Scalar vector for the input parameters 290 mutable Matrix<Index,Dynamic,1> m_perm; // Permutation vector 291 mutable Matrix<Index,Dynamic,1> m_invp; // Inverse permutation vector 292 mutable int m_size; // Size of the matrix 293 }; 294 295 /** Initialize the PaStiX data structure. 296 *A first call to this function fills iparm and dparm with the default PaStiX parameters 297 * \sa iparm() dparm() 298 */ 299 template <class Derived> 300 void PastixBase<Derived>::init() 301 { 302 m_size = 0; 303 m_iparm.setZero(IPARM_SIZE); 304 m_dparm.setZero(DPARM_SIZE); 305 306 m_iparm(IPARM_MODIFY_PARAMETER) = API_NO; 307 pastix(&m_pastixdata, MPI_COMM_WORLD, 308 0, 0, 0, 0, 309 0, 0, 0, 1, m_iparm.data(), m_dparm.data()); 310 311 m_iparm[IPARM_MATRIX_VERIFICATION] = API_NO; 312 m_iparm[IPARM_VERBOSE] = 2; 313 m_iparm[IPARM_ORDERING] = API_ORDER_SCOTCH; 314 m_iparm[IPARM_INCOMPLETE] = API_NO; 315 m_iparm[IPARM_OOC_LIMIT] = 2000; 316 m_iparm[IPARM_RHS_MAKING] = API_RHS_B; 317 m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; 318 319 m_iparm(IPARM_START_TASK) = API_TASK_INIT; 320 m_iparm(IPARM_END_TASK) = API_TASK_INIT; 321 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0, 322 0, 0, 0, 0, m_iparm.data(), m_dparm.data()); 323 324 // Check the returned error 325 if(m_iparm(IPARM_ERROR_NUMBER)) { 326 m_info = InvalidInput; 327 m_initisOk = false; 328 } 329 else { 330 m_info = Success; 331 m_initisOk = true; 332 } 333 } 334 335 template <class Derived> 336 void PastixBase<Derived>::compute(ColSpMatrix& mat) 337 { 338 eigen_assert(mat.rows() == mat.cols() && "The input matrix should be squared"); 339 340 analyzePattern(mat); 341 factorize(mat); 342 343 m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; 344 m_isInitialized = m_factorizationIsOk; 345 } 346 347 348 template <class Derived> 349 void PastixBase<Derived>::analyzePattern(ColSpMatrix& mat) 350 { 351 eigen_assert(m_initisOk && "The initialization of PaSTiX failed"); 352 353 // clean previous calls 354 if(m_size>0) 355 clean(); 356 357 m_size = mat.rows(); 358 m_perm.resize(m_size); 359 m_invp.resize(m_size); 360 361 m_iparm(IPARM_START_TASK) = API_TASK_ORDERING; 362 m_iparm(IPARM_END_TASK) = API_TASK_ANALYSE; 363 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(), 364 mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); 365 366 // Check the returned error 367 if(m_iparm(IPARM_ERROR_NUMBER)) 368 { 369 m_info = NumericalIssue; 370 m_analysisIsOk = false; 371 } 372 else 373 { 374 m_info = Success; 375 m_analysisIsOk = true; 376 } 377 } 378 379 template <class Derived> 380 void PastixBase<Derived>::factorize(ColSpMatrix& mat) 381 { 382 // if(&m_cpyMat != &mat) m_cpyMat = mat; 383 eigen_assert(m_analysisIsOk && "The analysis phase should be called before the factorization phase"); 384 m_iparm(IPARM_START_TASK) = API_TASK_NUMFACT; 385 m_iparm(IPARM_END_TASK) = API_TASK_NUMFACT; 386 m_size = mat.rows(); 387 388 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(), 389 mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); 390 391 // Check the returned error 392 if(m_iparm(IPARM_ERROR_NUMBER)) 393 { 394 m_info = NumericalIssue; 395 m_factorizationIsOk = false; 396 m_isInitialized = false; 397 } 398 else 399 { 400 m_info = Success; 401 m_factorizationIsOk = true; 402 m_isInitialized = true; 403 } 404 } 405 406 /* Solve the system */ 407 template<typename Base> 408 template<typename Rhs,typename Dest> 409 bool PastixBase<Base>::_solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const 410 { 411 eigen_assert(m_isInitialized && "The matrix should be factorized first"); 412 EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0, 413 THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); 414 int rhs = 1; 415 416 x = b; /* on return, x is overwritten by the computed solution */ 417 418 for (int i = 0; i < b.cols(); i++){ 419 m_iparm[IPARM_START_TASK] = API_TASK_SOLVE; 420 m_iparm[IPARM_END_TASK] = API_TASK_REFINE; 421 422 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, x.rows(), 0, 0, 0, 423 m_perm.data(), m_invp.data(), &x(0, i), rhs, m_iparm.data(), m_dparm.data()); 424 } 425 426 // Check the returned error 427 m_info = m_iparm(IPARM_ERROR_NUMBER)==0 ? Success : NumericalIssue; 428 429 return m_iparm(IPARM_ERROR_NUMBER)==0; 430 } 431 432 /** \ingroup PaStiXSupport_Module 433 * \class PastixLU 434 * \brief Sparse direct LU solver based on PaStiX library 435 * 436 * This class is used to solve the linear systems A.X = B with a supernodal LU 437 * factorization in the PaStiX library. The matrix A should be squared and nonsingular 438 * PaStiX requires that the matrix A has a symmetric structural pattern. 439 * This interface can symmetrize the input matrix otherwise. 440 * The vectors or matrices X and B can be either dense or sparse. 441 * 442 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 443 * \tparam IsStrSym Indicates if the input matrix has a symmetric pattern, default is false 444 * NOTE : Note that if the analysis and factorization phase are called separately, 445 * the input matrix will be symmetrized at each call, hence it is advised to 446 * symmetrize the matrix in a end-user program and set \p IsStrSym to true 447 * 448 * \sa \ref TutorialSparseDirectSolvers 449 * 450 */ 451 template<typename _MatrixType, bool IsStrSym> 452 class PastixLU : public PastixBase< PastixLU<_MatrixType> > 453 { 454 public: 455 typedef _MatrixType MatrixType; 456 typedef PastixBase<PastixLU<MatrixType> > Base; 457 typedef typename Base::ColSpMatrix ColSpMatrix; 458 typedef typename MatrixType::Index Index; 459 460 public: 461 PastixLU() : Base() 462 { 463 init(); 464 } 465 466 PastixLU(const MatrixType& matrix):Base() 467 { 468 init(); 469 compute(matrix); 470 } 471 /** Compute the LU supernodal factorization of \p matrix. 472 * iparm and dparm can be used to tune the PaStiX parameters. 473 * see the PaStiX user's manual 474 * \sa analyzePattern() factorize() 475 */ 476 void compute (const MatrixType& matrix) 477 { 478 m_structureIsUptodate = false; 479 ColSpMatrix temp; 480 grabMatrix(matrix, temp); 481 Base::compute(temp); 482 } 483 /** Compute the LU symbolic factorization of \p matrix using its sparsity pattern. 484 * Several ordering methods can be used at this step. See the PaStiX user's manual. 485 * The result of this operation can be used with successive matrices having the same pattern as \p matrix 486 * \sa factorize() 487 */ 488 void analyzePattern(const MatrixType& matrix) 489 { 490 m_structureIsUptodate = false; 491 ColSpMatrix temp; 492 grabMatrix(matrix, temp); 493 Base::analyzePattern(temp); 494 } 495 496 /** Compute the LU supernodal factorization of \p matrix 497 * WARNING The matrix \p matrix should have the same structural pattern 498 * as the same used in the analysis phase. 499 * \sa analyzePattern() 500 */ 501 void factorize(const MatrixType& matrix) 502 { 503 ColSpMatrix temp; 504 grabMatrix(matrix, temp); 505 Base::factorize(temp); 506 } 507 protected: 508 509 void init() 510 { 511 m_structureIsUptodate = false; 512 m_iparm(IPARM_SYM) = API_SYM_NO; 513 m_iparm(IPARM_FACTORIZATION) = API_FACT_LU; 514 } 515 516 void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) 517 { 518 if(IsStrSym) 519 out = matrix; 520 else 521 { 522 if(!m_structureIsUptodate) 523 { 524 // update the transposed structure 525 m_transposedStructure = matrix.transpose(); 526 527 // Set the elements of the matrix to zero 528 for (Index j=0; j<m_transposedStructure.outerSize(); ++j) 529 for(typename ColSpMatrix::InnerIterator it(m_transposedStructure, j); it; ++it) 530 it.valueRef() = 0.0; 531 532 m_structureIsUptodate = true; 533 } 534 535 out = m_transposedStructure + matrix; 536 } 537 internal::c_to_fortran_numbering(out); 538 } 539 540 using Base::m_iparm; 541 using Base::m_dparm; 542 543 ColSpMatrix m_transposedStructure; 544 bool m_structureIsUptodate; 545 }; 546 547 /** \ingroup PaStiXSupport_Module 548 * \class PastixLLT 549 * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library 550 * 551 * This class is used to solve the linear systems A.X = B via a LL^T supernodal Cholesky factorization 552 * available in the PaStiX library. The matrix A should be symmetric and positive definite 553 * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX 554 * The vectors or matrices X and B can be either dense or sparse 555 * 556 * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 557 * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX 558 * 559 * \sa \ref TutorialSparseDirectSolvers 560 */ 561 template<typename _MatrixType, int _UpLo> 562 class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> > 563 { 564 public: 565 typedef _MatrixType MatrixType; 566 typedef PastixBase<PastixLLT<MatrixType, _UpLo> > Base; 567 typedef typename Base::ColSpMatrix ColSpMatrix; 568 569 public: 570 enum { UpLo = _UpLo }; 571 PastixLLT() : Base() 572 { 573 init(); 574 } 575 576 PastixLLT(const MatrixType& matrix):Base() 577 { 578 init(); 579 compute(matrix); 580 } 581 582 /** Compute the L factor of the LL^T supernodal factorization of \p matrix 583 * \sa analyzePattern() factorize() 584 */ 585 void compute (const MatrixType& matrix) 586 { 587 ColSpMatrix temp; 588 grabMatrix(matrix, temp); 589 Base::compute(temp); 590 } 591 592 /** Compute the LL^T symbolic factorization of \p matrix using its sparsity pattern 593 * The result of this operation can be used with successive matrices having the same pattern as \p matrix 594 * \sa factorize() 595 */ 596 void analyzePattern(const MatrixType& matrix) 597 { 598 ColSpMatrix temp; 599 grabMatrix(matrix, temp); 600 Base::analyzePattern(temp); 601 } 602 /** Compute the LL^T supernodal numerical factorization of \p matrix 603 * \sa analyzePattern() 604 */ 605 void factorize(const MatrixType& matrix) 606 { 607 ColSpMatrix temp; 608 grabMatrix(matrix, temp); 609 Base::factorize(temp); 610 } 611 protected: 612 using Base::m_iparm; 613 614 void init() 615 { 616 m_iparm(IPARM_SYM) = API_SYM_YES; 617 m_iparm(IPARM_FACTORIZATION) = API_FACT_LLT; 618 } 619 620 void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) 621 { 622 // Pastix supports only lower, column-major matrices 623 out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>(); 624 internal::c_to_fortran_numbering(out); 625 } 626 }; 627 628 /** \ingroup PaStiXSupport_Module 629 * \class PastixLDLT 630 * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library 631 * 632 * This class is used to solve the linear systems A.X = B via a LDL^T supernodal Cholesky factorization 633 * available in the PaStiX library. The matrix A should be symmetric and positive definite 634 * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX 635 * The vectors or matrices X and B can be either dense or sparse 636 * 637 * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 638 * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX 639 * 640 * \sa \ref TutorialSparseDirectSolvers 641 */ 642 template<typename _MatrixType, int _UpLo> 643 class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> > 644 { 645 public: 646 typedef _MatrixType MatrixType; 647 typedef PastixBase<PastixLDLT<MatrixType, _UpLo> > Base; 648 typedef typename Base::ColSpMatrix ColSpMatrix; 649 650 public: 651 enum { UpLo = _UpLo }; 652 PastixLDLT():Base() 653 { 654 init(); 655 } 656 657 PastixLDLT(const MatrixType& matrix):Base() 658 { 659 init(); 660 compute(matrix); 661 } 662 663 /** Compute the L and D factors of the LDL^T factorization of \p matrix 664 * \sa analyzePattern() factorize() 665 */ 666 void compute (const MatrixType& matrix) 667 { 668 ColSpMatrix temp; 669 grabMatrix(matrix, temp); 670 Base::compute(temp); 671 } 672 673 /** Compute the LDL^T symbolic factorization of \p matrix using its sparsity pattern 674 * The result of this operation can be used with successive matrices having the same pattern as \p matrix 675 * \sa factorize() 676 */ 677 void analyzePattern(const MatrixType& matrix) 678 { 679 ColSpMatrix temp; 680 grabMatrix(matrix, temp); 681 Base::analyzePattern(temp); 682 } 683 /** Compute the LDL^T supernodal numerical factorization of \p matrix 684 * 685 */ 686 void factorize(const MatrixType& matrix) 687 { 688 ColSpMatrix temp; 689 grabMatrix(matrix, temp); 690 Base::factorize(temp); 691 } 692 693 protected: 694 using Base::m_iparm; 695 696 void init() 697 { 698 m_iparm(IPARM_SYM) = API_SYM_YES; 699 m_iparm(IPARM_FACTORIZATION) = API_FACT_LDLT; 700 } 701 702 void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) 703 { 704 // Pastix supports only lower, column-major matrices 705 out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>(); 706 internal::c_to_fortran_numbering(out); 707 } 708 }; 709 710 namespace internal { 711 712 template<typename _MatrixType, typename Rhs> 713 struct solve_retval<PastixBase<_MatrixType>, Rhs> 714 : solve_retval_base<PastixBase<_MatrixType>, Rhs> 715 { 716 typedef PastixBase<_MatrixType> Dec; 717 EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) 718 719 template<typename Dest> void evalTo(Dest& dst) const 720 { 721 dec()._solve(rhs(),dst); 722 } 723 }; 724 725 template<typename _MatrixType, typename Rhs> 726 struct sparse_solve_retval<PastixBase<_MatrixType>, Rhs> 727 : sparse_solve_retval_base<PastixBase<_MatrixType>, Rhs> 728 { 729 typedef PastixBase<_MatrixType> Dec; 730 EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) 731 732 template<typename Dest> void evalTo(Dest& dst) const 733 { 734 dec()._solve_sparse(rhs(),dst); 735 } 736 }; 737 738 } // end namespace internal 739 740 } // end namespace Eigen 741 742 #endif 743