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