1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@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 Derived& derived() 161 { 162 return *static_cast<Derived*>(this); 163 } 164 const Derived& derived() const 165 { 166 return *static_cast<const Derived*>(this); 167 } 168 169 /** Returns a reference to the integer vector IPARM of PaStiX parameters 170 * to modify the default parameters. 171 * The statistics related to the different phases of factorization and solve are saved here as well 172 * \sa analyzePattern() factorize() 173 */ 174 Array<Index,IPARM_SIZE,1>& iparm() 175 { 176 return m_iparm; 177 } 178 179 /** Return a reference to a particular index parameter of the IPARM vector 180 * \sa iparm() 181 */ 182 183 int& iparm(int idxparam) 184 { 185 return m_iparm(idxparam); 186 } 187 188 /** Returns a reference to the double vector DPARM of PaStiX parameters 189 * The statistics related to the different phases of factorization and solve are saved here as well 190 * \sa analyzePattern() factorize() 191 */ 192 Array<RealScalar,IPARM_SIZE,1>& dparm() 193 { 194 return m_dparm; 195 } 196 197 198 /** Return a reference to a particular index parameter of the DPARM vector 199 * \sa dparm() 200 */ 201 double& dparm(int idxparam) 202 { 203 return m_dparm(idxparam); 204 } 205 206 inline Index cols() const { return m_size; } 207 inline Index rows() const { return m_size; } 208 209 /** \brief Reports whether previous computation was successful. 210 * 211 * \returns \c Success if computation was succesful, 212 * \c NumericalIssue if the PaStiX reports a problem 213 * \c InvalidInput if the input matrix is invalid 214 * 215 * \sa iparm() 216 */ 217 ComputationInfo info() const 218 { 219 eigen_assert(m_isInitialized && "Decomposition is not initialized."); 220 return m_info; 221 } 222 223 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 224 * 225 * \sa compute() 226 */ 227 template<typename Rhs> 228 inline const internal::sparse_solve_retval<PastixBase, Rhs> 229 solve(const SparseMatrixBase<Rhs>& b) const 230 { 231 eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized."); 232 eigen_assert(rows()==b.rows() 233 && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); 234 return internal::sparse_solve_retval<PastixBase, Rhs>(*this, b.derived()); 235 } 236 237 protected: 238 239 // Initialize the Pastix data structure, check the matrix 240 void init(); 241 242 // Compute the ordering and the symbolic factorization 243 void analyzePattern(ColSpMatrix& mat); 244 245 // Compute the numerical factorization 246 void factorize(ColSpMatrix& mat); 247 248 // Free all the data allocated by Pastix 249 void clean() 250 { 251 eigen_assert(m_initisOk && "The Pastix structure should be allocated first"); 252 m_iparm(IPARM_START_TASK) = API_TASK_CLEAN; 253 m_iparm(IPARM_END_TASK) = API_TASK_CLEAN; 254 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0, 255 m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); 256 } 257 258 void compute(ColSpMatrix& mat); 259 260 int m_initisOk; 261 int m_analysisIsOk; 262 int m_factorizationIsOk; 263 bool m_isInitialized; 264 mutable ComputationInfo m_info; 265 mutable pastix_data_t *m_pastixdata; // Data structure for pastix 266 mutable int m_comm; // The MPI communicator identifier 267 mutable Matrix<int,IPARM_SIZE,1> m_iparm; // integer vector for the input parameters 268 mutable Matrix<double,DPARM_SIZE,1> m_dparm; // Scalar vector for the input parameters 269 mutable Matrix<Index,Dynamic,1> m_perm; // Permutation vector 270 mutable Matrix<Index,Dynamic,1> m_invp; // Inverse permutation vector 271 mutable int m_size; // Size of the matrix 272 }; 273 274 /** Initialize the PaStiX data structure. 275 *A first call to this function fills iparm and dparm with the default PaStiX parameters 276 * \sa iparm() dparm() 277 */ 278 template <class Derived> 279 void PastixBase<Derived>::init() 280 { 281 m_size = 0; 282 m_iparm.setZero(IPARM_SIZE); 283 m_dparm.setZero(DPARM_SIZE); 284 285 m_iparm(IPARM_MODIFY_PARAMETER) = API_NO; 286 pastix(&m_pastixdata, MPI_COMM_WORLD, 287 0, 0, 0, 0, 288 0, 0, 0, 1, m_iparm.data(), m_dparm.data()); 289 290 m_iparm[IPARM_MATRIX_VERIFICATION] = API_NO; 291 m_iparm[IPARM_VERBOSE] = 2; 292 m_iparm[IPARM_ORDERING] = API_ORDER_SCOTCH; 293 m_iparm[IPARM_INCOMPLETE] = API_NO; 294 m_iparm[IPARM_OOC_LIMIT] = 2000; 295 m_iparm[IPARM_RHS_MAKING] = API_RHS_B; 296 m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; 297 298 m_iparm(IPARM_START_TASK) = API_TASK_INIT; 299 m_iparm(IPARM_END_TASK) = API_TASK_INIT; 300 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0, 301 0, 0, 0, 0, m_iparm.data(), m_dparm.data()); 302 303 // Check the returned error 304 if(m_iparm(IPARM_ERROR_NUMBER)) { 305 m_info = InvalidInput; 306 m_initisOk = false; 307 } 308 else { 309 m_info = Success; 310 m_initisOk = true; 311 } 312 } 313 314 template <class Derived> 315 void PastixBase<Derived>::compute(ColSpMatrix& mat) 316 { 317 eigen_assert(mat.rows() == mat.cols() && "The input matrix should be squared"); 318 319 analyzePattern(mat); 320 factorize(mat); 321 322 m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; 323 m_isInitialized = m_factorizationIsOk; 324 } 325 326 327 template <class Derived> 328 void PastixBase<Derived>::analyzePattern(ColSpMatrix& mat) 329 { 330 eigen_assert(m_initisOk && "The initialization of PaSTiX failed"); 331 332 // clean previous calls 333 if(m_size>0) 334 clean(); 335 336 m_size = mat.rows(); 337 m_perm.resize(m_size); 338 m_invp.resize(m_size); 339 340 m_iparm(IPARM_START_TASK) = API_TASK_ORDERING; 341 m_iparm(IPARM_END_TASK) = API_TASK_ANALYSE; 342 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(), 343 mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); 344 345 // Check the returned error 346 if(m_iparm(IPARM_ERROR_NUMBER)) 347 { 348 m_info = NumericalIssue; 349 m_analysisIsOk = false; 350 } 351 else 352 { 353 m_info = Success; 354 m_analysisIsOk = true; 355 } 356 } 357 358 template <class Derived> 359 void PastixBase<Derived>::factorize(ColSpMatrix& mat) 360 { 361 // if(&m_cpyMat != &mat) m_cpyMat = mat; 362 eigen_assert(m_analysisIsOk && "The analysis phase should be called before the factorization phase"); 363 m_iparm(IPARM_START_TASK) = API_TASK_NUMFACT; 364 m_iparm(IPARM_END_TASK) = API_TASK_NUMFACT; 365 m_size = mat.rows(); 366 367 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(), 368 mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); 369 370 // Check the returned error 371 if(m_iparm(IPARM_ERROR_NUMBER)) 372 { 373 m_info = NumericalIssue; 374 m_factorizationIsOk = false; 375 m_isInitialized = false; 376 } 377 else 378 { 379 m_info = Success; 380 m_factorizationIsOk = true; 381 m_isInitialized = true; 382 } 383 } 384 385 /* Solve the system */ 386 template<typename Base> 387 template<typename Rhs,typename Dest> 388 bool PastixBase<Base>::_solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const 389 { 390 eigen_assert(m_isInitialized && "The matrix should be factorized first"); 391 EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0, 392 THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); 393 int rhs = 1; 394 395 x = b; /* on return, x is overwritten by the computed solution */ 396 397 for (int i = 0; i < b.cols(); i++){ 398 m_iparm[IPARM_START_TASK] = API_TASK_SOLVE; 399 m_iparm[IPARM_END_TASK] = API_TASK_REFINE; 400 401 internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, x.rows(), 0, 0, 0, 402 m_perm.data(), m_invp.data(), &x(0, i), rhs, m_iparm.data(), m_dparm.data()); 403 } 404 405 // Check the returned error 406 m_info = m_iparm(IPARM_ERROR_NUMBER)==0 ? Success : NumericalIssue; 407 408 return m_iparm(IPARM_ERROR_NUMBER)==0; 409 } 410 411 /** \ingroup PaStiXSupport_Module 412 * \class PastixLU 413 * \brief Sparse direct LU solver based on PaStiX library 414 * 415 * This class is used to solve the linear systems A.X = B with a supernodal LU 416 * factorization in the PaStiX library. The matrix A should be squared and nonsingular 417 * PaStiX requires that the matrix A has a symmetric structural pattern. 418 * This interface can symmetrize the input matrix otherwise. 419 * The vectors or matrices 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 IsStrSym Indicates if the input matrix has a symmetric pattern, default is false 423 * NOTE : Note that if the analysis and factorization phase are called separately, 424 * the input matrix will be symmetrized at each call, hence it is advised to 425 * symmetrize the matrix in a end-user program and set \p IsStrSym to true 426 * 427 * \sa \ref TutorialSparseDirectSolvers 428 * 429 */ 430 template<typename _MatrixType, bool IsStrSym> 431 class PastixLU : public PastixBase< PastixLU<_MatrixType> > 432 { 433 public: 434 typedef _MatrixType MatrixType; 435 typedef PastixBase<PastixLU<MatrixType> > Base; 436 typedef typename Base::ColSpMatrix ColSpMatrix; 437 typedef typename MatrixType::Index Index; 438 439 public: 440 PastixLU() : Base() 441 { 442 init(); 443 } 444 445 PastixLU(const MatrixType& matrix):Base() 446 { 447 init(); 448 compute(matrix); 449 } 450 /** Compute the LU supernodal factorization of \p matrix. 451 * iparm and dparm can be used to tune the PaStiX parameters. 452 * see the PaStiX user's manual 453 * \sa analyzePattern() factorize() 454 */ 455 void compute (const MatrixType& matrix) 456 { 457 m_structureIsUptodate = false; 458 ColSpMatrix temp; 459 grabMatrix(matrix, temp); 460 Base::compute(temp); 461 } 462 /** Compute the LU symbolic factorization of \p matrix using its sparsity pattern. 463 * Several ordering methods can be used at this step. See the PaStiX user's manual. 464 * The result of this operation can be used with successive matrices having the same pattern as \p matrix 465 * \sa factorize() 466 */ 467 void analyzePattern(const MatrixType& matrix) 468 { 469 m_structureIsUptodate = false; 470 ColSpMatrix temp; 471 grabMatrix(matrix, temp); 472 Base::analyzePattern(temp); 473 } 474 475 /** Compute the LU supernodal factorization of \p matrix 476 * WARNING The matrix \p matrix should have the same structural pattern 477 * as the same used in the analysis phase. 478 * \sa analyzePattern() 479 */ 480 void factorize(const MatrixType& matrix) 481 { 482 ColSpMatrix temp; 483 grabMatrix(matrix, temp); 484 Base::factorize(temp); 485 } 486 protected: 487 488 void init() 489 { 490 m_structureIsUptodate = false; 491 m_iparm(IPARM_SYM) = API_SYM_NO; 492 m_iparm(IPARM_FACTORIZATION) = API_FACT_LU; 493 } 494 495 void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) 496 { 497 if(IsStrSym) 498 out = matrix; 499 else 500 { 501 if(!m_structureIsUptodate) 502 { 503 // update the transposed structure 504 m_transposedStructure = matrix.transpose(); 505 506 // Set the elements of the matrix to zero 507 for (Index j=0; j<m_transposedStructure.outerSize(); ++j) 508 for(typename ColSpMatrix::InnerIterator it(m_transposedStructure, j); it; ++it) 509 it.valueRef() = 0.0; 510 511 m_structureIsUptodate = true; 512 } 513 514 out = m_transposedStructure + matrix; 515 } 516 internal::c_to_fortran_numbering(out); 517 } 518 519 using Base::m_iparm; 520 using Base::m_dparm; 521 522 ColSpMatrix m_transposedStructure; 523 bool m_structureIsUptodate; 524 }; 525 526 /** \ingroup PaStiXSupport_Module 527 * \class PastixLLT 528 * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library 529 * 530 * This class is used to solve the linear systems A.X = B via a LL^T supernodal Cholesky factorization 531 * available in the PaStiX library. The matrix A should be symmetric and positive definite 532 * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX 533 * The vectors or matrices X and B can be either dense or sparse 534 * 535 * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 536 * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX 537 * 538 * \sa \ref TutorialSparseDirectSolvers 539 */ 540 template<typename _MatrixType, int _UpLo> 541 class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> > 542 { 543 public: 544 typedef _MatrixType MatrixType; 545 typedef PastixBase<PastixLLT<MatrixType, _UpLo> > Base; 546 typedef typename Base::ColSpMatrix ColSpMatrix; 547 548 public: 549 enum { UpLo = _UpLo }; 550 PastixLLT() : Base() 551 { 552 init(); 553 } 554 555 PastixLLT(const MatrixType& matrix):Base() 556 { 557 init(); 558 compute(matrix); 559 } 560 561 /** Compute the L factor of the LL^T supernodal factorization of \p matrix 562 * \sa analyzePattern() factorize() 563 */ 564 void compute (const MatrixType& matrix) 565 { 566 ColSpMatrix temp; 567 grabMatrix(matrix, temp); 568 Base::compute(temp); 569 } 570 571 /** Compute the LL^T symbolic factorization of \p matrix using its sparsity pattern 572 * The result of this operation can be used with successive matrices having the same pattern as \p matrix 573 * \sa factorize() 574 */ 575 void analyzePattern(const MatrixType& matrix) 576 { 577 ColSpMatrix temp; 578 grabMatrix(matrix, temp); 579 Base::analyzePattern(temp); 580 } 581 /** Compute the LL^T supernodal numerical factorization of \p matrix 582 * \sa analyzePattern() 583 */ 584 void factorize(const MatrixType& matrix) 585 { 586 ColSpMatrix temp; 587 grabMatrix(matrix, temp); 588 Base::factorize(temp); 589 } 590 protected: 591 using Base::m_iparm; 592 593 void init() 594 { 595 m_iparm(IPARM_SYM) = API_SYM_YES; 596 m_iparm(IPARM_FACTORIZATION) = API_FACT_LLT; 597 } 598 599 void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) 600 { 601 // Pastix supports only lower, column-major matrices 602 out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>(); 603 internal::c_to_fortran_numbering(out); 604 } 605 }; 606 607 /** \ingroup PaStiXSupport_Module 608 * \class PastixLDLT 609 * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library 610 * 611 * This class is used to solve the linear systems A.X = B via a LDL^T supernodal Cholesky factorization 612 * available in the PaStiX library. The matrix A should be symmetric and positive definite 613 * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX 614 * The vectors or matrices X and B can be either dense or sparse 615 * 616 * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 617 * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX 618 * 619 * \sa \ref TutorialSparseDirectSolvers 620 */ 621 template<typename _MatrixType, int _UpLo> 622 class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> > 623 { 624 public: 625 typedef _MatrixType MatrixType; 626 typedef PastixBase<PastixLDLT<MatrixType, _UpLo> > Base; 627 typedef typename Base::ColSpMatrix ColSpMatrix; 628 629 public: 630 enum { UpLo = _UpLo }; 631 PastixLDLT():Base() 632 { 633 init(); 634 } 635 636 PastixLDLT(const MatrixType& matrix):Base() 637 { 638 init(); 639 compute(matrix); 640 } 641 642 /** Compute the L and D factors of the LDL^T factorization of \p matrix 643 * \sa analyzePattern() factorize() 644 */ 645 void compute (const MatrixType& matrix) 646 { 647 ColSpMatrix temp; 648 grabMatrix(matrix, temp); 649 Base::compute(temp); 650 } 651 652 /** Compute the LDL^T symbolic factorization of \p matrix using its sparsity pattern 653 * The result of this operation can be used with successive matrices having the same pattern as \p matrix 654 * \sa factorize() 655 */ 656 void analyzePattern(const MatrixType& matrix) 657 { 658 ColSpMatrix temp; 659 grabMatrix(matrix, temp); 660 Base::analyzePattern(temp); 661 } 662 /** Compute the LDL^T supernodal numerical factorization of \p matrix 663 * 664 */ 665 void factorize(const MatrixType& matrix) 666 { 667 ColSpMatrix temp; 668 grabMatrix(matrix, temp); 669 Base::factorize(temp); 670 } 671 672 protected: 673 using Base::m_iparm; 674 675 void init() 676 { 677 m_iparm(IPARM_SYM) = API_SYM_YES; 678 m_iparm(IPARM_FACTORIZATION) = API_FACT_LDLT; 679 } 680 681 void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) 682 { 683 // Pastix supports only lower, column-major matrices 684 out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>(); 685 internal::c_to_fortran_numbering(out); 686 } 687 }; 688 689 namespace internal { 690 691 template<typename _MatrixType, typename Rhs> 692 struct solve_retval<PastixBase<_MatrixType>, Rhs> 693 : solve_retval_base<PastixBase<_MatrixType>, Rhs> 694 { 695 typedef PastixBase<_MatrixType> Dec; 696 EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) 697 698 template<typename Dest> void evalTo(Dest& dst) const 699 { 700 dec()._solve(rhs(),dst); 701 } 702 }; 703 704 template<typename _MatrixType, typename Rhs> 705 struct sparse_solve_retval<PastixBase<_MatrixType>, Rhs> 706 : sparse_solve_retval_base<PastixBase<_MatrixType>, Rhs> 707 { 708 typedef PastixBase<_MatrixType> Dec; 709 EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) 710 711 template<typename Dest> void evalTo(Dest& dst) const 712 { 713 this->defaultEvalTo(dst); 714 } 715 }; 716 717 } // end namespace internal 718 719 } // end namespace Eigen 720 721 #endif 722