1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud (at) inria.fr> 5 // 6 // This Source Code Form is subject to the terms of the Mozilla 7 // Public License v. 2.0. If a copy of the MPL was not distributed 8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10 #ifndef EIGEN_SUPERLUSUPPORT_H 11 #define EIGEN_SUPERLUSUPPORT_H 12 13 namespace Eigen { 14 15 #define DECL_GSSVX(PREFIX,FLOATTYPE,KEYTYPE) \ 16 extern "C" { \ 17 typedef struct { FLOATTYPE for_lu; FLOATTYPE total_needed; int expansions; } PREFIX##mem_usage_t; \ 18 extern void PREFIX##gssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, \ 19 char *, FLOATTYPE *, FLOATTYPE *, SuperMatrix *, SuperMatrix *, \ 20 void *, int, SuperMatrix *, SuperMatrix *, \ 21 FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, \ 22 PREFIX##mem_usage_t *, SuperLUStat_t *, int *); \ 23 } \ 24 inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, \ 25 int *perm_c, int *perm_r, int *etree, char *equed, \ 26 FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \ 27 SuperMatrix *U, void *work, int lwork, \ 28 SuperMatrix *B, SuperMatrix *X, \ 29 FLOATTYPE *recip_pivot_growth, \ 30 FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \ 31 SuperLUStat_t *stats, int *info, KEYTYPE) { \ 32 PREFIX##mem_usage_t mem_usage; \ 33 PREFIX##gssvx(options, A, perm_c, perm_r, etree, equed, R, C, L, \ 34 U, work, lwork, B, X, recip_pivot_growth, rcond, \ 35 ferr, berr, &mem_usage, stats, info); \ 36 return mem_usage.for_lu; /* bytes used by the factor storage */ \ 37 } 38 39 DECL_GSSVX(s,float,float) 40 DECL_GSSVX(c,float,std::complex<float>) 41 DECL_GSSVX(d,double,double) 42 DECL_GSSVX(z,double,std::complex<double>) 43 44 #ifdef MILU_ALPHA 45 #define EIGEN_SUPERLU_HAS_ILU 46 #endif 47 48 #ifdef EIGEN_SUPERLU_HAS_ILU 49 50 // similarly for the incomplete factorization using gsisx 51 #define DECL_GSISX(PREFIX,FLOATTYPE,KEYTYPE) \ 52 extern "C" { \ 53 extern void PREFIX##gsisx(superlu_options_t *, SuperMatrix *, int *, int *, int *, \ 54 char *, FLOATTYPE *, FLOATTYPE *, SuperMatrix *, SuperMatrix *, \ 55 void *, int, SuperMatrix *, SuperMatrix *, FLOATTYPE *, FLOATTYPE *, \ 56 PREFIX##mem_usage_t *, SuperLUStat_t *, int *); \ 57 } \ 58 inline float SuperLU_gsisx(superlu_options_t *options, SuperMatrix *A, \ 59 int *perm_c, int *perm_r, int *etree, char *equed, \ 60 FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \ 61 SuperMatrix *U, void *work, int lwork, \ 62 SuperMatrix *B, SuperMatrix *X, \ 63 FLOATTYPE *recip_pivot_growth, \ 64 FLOATTYPE *rcond, \ 65 SuperLUStat_t *stats, int *info, KEYTYPE) { \ 66 PREFIX##mem_usage_t mem_usage; \ 67 PREFIX##gsisx(options, A, perm_c, perm_r, etree, equed, R, C, L, \ 68 U, work, lwork, B, X, recip_pivot_growth, rcond, \ 69 &mem_usage, stats, info); \ 70 return mem_usage.for_lu; /* bytes used by the factor storage */ \ 71 } 72 73 DECL_GSISX(s,float,float) 74 DECL_GSISX(c,float,std::complex<float>) 75 DECL_GSISX(d,double,double) 76 DECL_GSISX(z,double,std::complex<double>) 77 78 #endif 79 80 template<typename MatrixType> 81 struct SluMatrixMapHelper; 82 83 /** \internal 84 * 85 * A wrapper class for SuperLU matrices. It supports only compressed sparse matrices 86 * and dense matrices. Supernodal and other fancy format are not supported by this wrapper. 87 * 88 * This wrapper class mainly aims to avoids the need of dynamic allocation of the storage structure. 89 */ 90 struct SluMatrix : SuperMatrix 91 { 92 SluMatrix() 93 { 94 Store = &storage; 95 } 96 97 SluMatrix(const SluMatrix& other) 98 : SuperMatrix(other) 99 { 100 Store = &storage; 101 storage = other.storage; 102 } 103 104 SluMatrix& operator=(const SluMatrix& other) 105 { 106 SuperMatrix::operator=(static_cast<const SuperMatrix&>(other)); 107 Store = &storage; 108 storage = other.storage; 109 return *this; 110 } 111 112 struct 113 { 114 union {int nnz;int lda;}; 115 void *values; 116 int *innerInd; 117 int *outerInd; 118 } storage; 119 120 void setStorageType(Stype_t t) 121 { 122 Stype = t; 123 if (t==SLU_NC || t==SLU_NR || t==SLU_DN) 124 Store = &storage; 125 else 126 { 127 eigen_assert(false && "storage type not supported"); 128 Store = 0; 129 } 130 } 131 132 template<typename Scalar> 133 void setScalarType() 134 { 135 if (internal::is_same<Scalar,float>::value) 136 Dtype = SLU_S; 137 else if (internal::is_same<Scalar,double>::value) 138 Dtype = SLU_D; 139 else if (internal::is_same<Scalar,std::complex<float> >::value) 140 Dtype = SLU_C; 141 else if (internal::is_same<Scalar,std::complex<double> >::value) 142 Dtype = SLU_Z; 143 else 144 { 145 eigen_assert(false && "Scalar type not supported by SuperLU"); 146 } 147 } 148 149 template<typename MatrixType> 150 static SluMatrix Map(MatrixBase<MatrixType>& _mat) 151 { 152 MatrixType& mat(_mat.derived()); 153 eigen_assert( ((MatrixType::Flags&RowMajorBit)!=RowMajorBit) && "row-major dense matrices are not supported by SuperLU"); 154 SluMatrix res; 155 res.setStorageType(SLU_DN); 156 res.setScalarType<typename MatrixType::Scalar>(); 157 res.Mtype = SLU_GE; 158 159 res.nrow = mat.rows(); 160 res.ncol = mat.cols(); 161 162 res.storage.lda = MatrixType::IsVectorAtCompileTime ? mat.size() : mat.outerStride(); 163 res.storage.values = mat.data(); 164 return res; 165 } 166 167 template<typename MatrixType> 168 static SluMatrix Map(SparseMatrixBase<MatrixType>& mat) 169 { 170 SluMatrix res; 171 if ((MatrixType::Flags&RowMajorBit)==RowMajorBit) 172 { 173 res.setStorageType(SLU_NR); 174 res.nrow = mat.cols(); 175 res.ncol = mat.rows(); 176 } 177 else 178 { 179 res.setStorageType(SLU_NC); 180 res.nrow = mat.rows(); 181 res.ncol = mat.cols(); 182 } 183 184 res.Mtype = SLU_GE; 185 186 res.storage.nnz = mat.nonZeros(); 187 res.storage.values = mat.derived().valuePtr(); 188 res.storage.innerInd = mat.derived().innerIndexPtr(); 189 res.storage.outerInd = mat.derived().outerIndexPtr(); 190 191 res.setScalarType<typename MatrixType::Scalar>(); 192 193 // FIXME the following is not very accurate 194 if (MatrixType::Flags & Upper) 195 res.Mtype = SLU_TRU; 196 if (MatrixType::Flags & Lower) 197 res.Mtype = SLU_TRL; 198 199 eigen_assert(((MatrixType::Flags & SelfAdjoint)==0) && "SelfAdjoint matrix shape not supported by SuperLU"); 200 201 return res; 202 } 203 }; 204 205 template<typename Scalar, int Rows, int Cols, int Options, int MRows, int MCols> 206 struct SluMatrixMapHelper<Matrix<Scalar,Rows,Cols,Options,MRows,MCols> > 207 { 208 typedef Matrix<Scalar,Rows,Cols,Options,MRows,MCols> MatrixType; 209 static void run(MatrixType& mat, SluMatrix& res) 210 { 211 eigen_assert( ((Options&RowMajor)!=RowMajor) && "row-major dense matrices is not supported by SuperLU"); 212 res.setStorageType(SLU_DN); 213 res.setScalarType<Scalar>(); 214 res.Mtype = SLU_GE; 215 216 res.nrow = mat.rows(); 217 res.ncol = mat.cols(); 218 219 res.storage.lda = mat.outerStride(); 220 res.storage.values = mat.data(); 221 } 222 }; 223 224 template<typename Derived> 225 struct SluMatrixMapHelper<SparseMatrixBase<Derived> > 226 { 227 typedef Derived MatrixType; 228 static void run(MatrixType& mat, SluMatrix& res) 229 { 230 if ((MatrixType::Flags&RowMajorBit)==RowMajorBit) 231 { 232 res.setStorageType(SLU_NR); 233 res.nrow = mat.cols(); 234 res.ncol = mat.rows(); 235 } 236 else 237 { 238 res.setStorageType(SLU_NC); 239 res.nrow = mat.rows(); 240 res.ncol = mat.cols(); 241 } 242 243 res.Mtype = SLU_GE; 244 245 res.storage.nnz = mat.nonZeros(); 246 res.storage.values = mat.valuePtr(); 247 res.storage.innerInd = mat.innerIndexPtr(); 248 res.storage.outerInd = mat.outerIndexPtr(); 249 250 res.setScalarType<typename MatrixType::Scalar>(); 251 252 // FIXME the following is not very accurate 253 if (MatrixType::Flags & Upper) 254 res.Mtype = SLU_TRU; 255 if (MatrixType::Flags & Lower) 256 res.Mtype = SLU_TRL; 257 258 eigen_assert(((MatrixType::Flags & SelfAdjoint)==0) && "SelfAdjoint matrix shape not supported by SuperLU"); 259 } 260 }; 261 262 namespace internal { 263 264 template<typename MatrixType> 265 SluMatrix asSluMatrix(MatrixType& mat) 266 { 267 return SluMatrix::Map(mat); 268 } 269 270 /** View a Super LU matrix as an Eigen expression */ 271 template<typename Scalar, int Flags, typename Index> 272 MappedSparseMatrix<Scalar,Flags,Index> map_superlu(SluMatrix& sluMat) 273 { 274 eigen_assert((Flags&RowMajor)==RowMajor && sluMat.Stype == SLU_NR 275 || (Flags&ColMajor)==ColMajor && sluMat.Stype == SLU_NC); 276 277 Index outerSize = (Flags&RowMajor)==RowMajor ? sluMat.ncol : sluMat.nrow; 278 279 return MappedSparseMatrix<Scalar,Flags,Index>( 280 sluMat.nrow, sluMat.ncol, sluMat.storage.outerInd[outerSize], 281 sluMat.storage.outerInd, sluMat.storage.innerInd, reinterpret_cast<Scalar*>(sluMat.storage.values) ); 282 } 283 284 } // end namespace internal 285 286 /** \ingroup SuperLUSupport_Module 287 * \class SuperLUBase 288 * \brief The base class for the direct and incomplete LU factorization of SuperLU 289 */ 290 template<typename _MatrixType, typename Derived> 291 class SuperLUBase : internal::noncopyable 292 { 293 public: 294 typedef _MatrixType MatrixType; 295 typedef typename MatrixType::Scalar Scalar; 296 typedef typename MatrixType::RealScalar RealScalar; 297 typedef typename MatrixType::Index Index; 298 typedef Matrix<Scalar,Dynamic,1> Vector; 299 typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType; 300 typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType; 301 typedef SparseMatrix<Scalar> LUMatrixType; 302 303 public: 304 305 SuperLUBase() {} 306 307 ~SuperLUBase() 308 { 309 clearFactors(); 310 } 311 312 Derived& derived() { return *static_cast<Derived*>(this); } 313 const Derived& derived() const { return *static_cast<const Derived*>(this); } 314 315 inline Index rows() const { return m_matrix.rows(); } 316 inline Index cols() const { return m_matrix.cols(); } 317 318 /** \returns a reference to the Super LU option object to configure the Super LU algorithms. */ 319 inline superlu_options_t& options() { return m_sluOptions; } 320 321 /** \brief Reports whether previous computation was successful. 322 * 323 * \returns \c Success if computation was succesful, 324 * \c NumericalIssue if the matrix.appears to be negative. 325 */ 326 ComputationInfo info() const 327 { 328 eigen_assert(m_isInitialized && "Decomposition is not initialized."); 329 return m_info; 330 } 331 332 /** Computes the sparse Cholesky decomposition of \a matrix */ 333 void compute(const MatrixType& matrix) 334 { 335 derived().analyzePattern(matrix); 336 derived().factorize(matrix); 337 } 338 339 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 340 * 341 * \sa compute() 342 */ 343 template<typename Rhs> 344 inline const internal::solve_retval<SuperLUBase, Rhs> solve(const MatrixBase<Rhs>& b) const 345 { 346 eigen_assert(m_isInitialized && "SuperLU is not initialized."); 347 eigen_assert(rows()==b.rows() 348 && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); 349 return internal::solve_retval<SuperLUBase, Rhs>(*this, b.derived()); 350 } 351 352 /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. 353 * 354 * \sa compute() 355 */ 356 // template<typename Rhs> 357 // inline const internal::sparse_solve_retval<SuperLU, Rhs> solve(const SparseMatrixBase<Rhs>& b) const 358 // { 359 // eigen_assert(m_isInitialized && "SuperLU is not initialized."); 360 // eigen_assert(rows()==b.rows() 361 // && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); 362 // return internal::sparse_solve_retval<SuperLU, Rhs>(*this, b.derived()); 363 // } 364 365 /** Performs a symbolic decomposition on the sparcity of \a matrix. 366 * 367 * This function is particularly useful when solving for several problems having the same structure. 368 * 369 * \sa factorize() 370 */ 371 void analyzePattern(const MatrixType& /*matrix*/) 372 { 373 m_isInitialized = true; 374 m_info = Success; 375 m_analysisIsOk = true; 376 m_factorizationIsOk = false; 377 } 378 379 template<typename Stream> 380 void dumpMemory(Stream& s) 381 {} 382 383 protected: 384 385 void initFactorization(const MatrixType& a) 386 { 387 set_default_options(&this->m_sluOptions); 388 389 const int size = a.rows(); 390 m_matrix = a; 391 392 m_sluA = internal::asSluMatrix(m_matrix); 393 clearFactors(); 394 395 m_p.resize(size); 396 m_q.resize(size); 397 m_sluRscale.resize(size); 398 m_sluCscale.resize(size); 399 m_sluEtree.resize(size); 400 401 // set empty B and X 402 m_sluB.setStorageType(SLU_DN); 403 m_sluB.setScalarType<Scalar>(); 404 m_sluB.Mtype = SLU_GE; 405 m_sluB.storage.values = 0; 406 m_sluB.nrow = 0; 407 m_sluB.ncol = 0; 408 m_sluB.storage.lda = size; 409 m_sluX = m_sluB; 410 411 m_extractedDataAreDirty = true; 412 } 413 414 void init() 415 { 416 m_info = InvalidInput; 417 m_isInitialized = false; 418 m_sluL.Store = 0; 419 m_sluU.Store = 0; 420 } 421 422 void extractData() const; 423 424 void clearFactors() 425 { 426 if(m_sluL.Store) 427 Destroy_SuperNode_Matrix(&m_sluL); 428 if(m_sluU.Store) 429 Destroy_CompCol_Matrix(&m_sluU); 430 431 m_sluL.Store = 0; 432 m_sluU.Store = 0; 433 434 memset(&m_sluL,0,sizeof m_sluL); 435 memset(&m_sluU,0,sizeof m_sluU); 436 } 437 438 // cached data to reduce reallocation, etc. 439 mutable LUMatrixType m_l; 440 mutable LUMatrixType m_u; 441 mutable IntColVectorType m_p; 442 mutable IntRowVectorType m_q; 443 444 mutable LUMatrixType m_matrix; // copy of the factorized matrix 445 mutable SluMatrix m_sluA; 446 mutable SuperMatrix m_sluL, m_sluU; 447 mutable SluMatrix m_sluB, m_sluX; 448 mutable SuperLUStat_t m_sluStat; 449 mutable superlu_options_t m_sluOptions; 450 mutable std::vector<int> m_sluEtree; 451 mutable Matrix<RealScalar,Dynamic,1> m_sluRscale, m_sluCscale; 452 mutable Matrix<RealScalar,Dynamic,1> m_sluFerr, m_sluBerr; 453 mutable char m_sluEqued; 454 455 mutable ComputationInfo m_info; 456 bool m_isInitialized; 457 int m_factorizationIsOk; 458 int m_analysisIsOk; 459 mutable bool m_extractedDataAreDirty; 460 461 private: 462 SuperLUBase(SuperLUBase& ) { } 463 }; 464 465 466 /** \ingroup SuperLUSupport_Module 467 * \class SuperLU 468 * \brief A sparse direct LU factorization and solver based on the SuperLU library 469 * 470 * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization 471 * using the SuperLU library. The sparse matrix A must be squared and invertible. The vectors or matrices 472 * X and B can be either dense or sparse. 473 * 474 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 475 * 476 * \sa \ref TutorialSparseDirectSolvers 477 */ 478 template<typename _MatrixType> 479 class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> > 480 { 481 public: 482 typedef SuperLUBase<_MatrixType,SuperLU> Base; 483 typedef _MatrixType MatrixType; 484 typedef typename Base::Scalar Scalar; 485 typedef typename Base::RealScalar RealScalar; 486 typedef typename Base::Index Index; 487 typedef typename Base::IntRowVectorType IntRowVectorType; 488 typedef typename Base::IntColVectorType IntColVectorType; 489 typedef typename Base::LUMatrixType LUMatrixType; 490 typedef TriangularView<LUMatrixType, Lower|UnitDiag> LMatrixType; 491 typedef TriangularView<LUMatrixType, Upper> UMatrixType; 492 493 public: 494 495 SuperLU() : Base() { init(); } 496 497 SuperLU(const MatrixType& matrix) : Base() 498 { 499 Base::init(); 500 compute(matrix); 501 } 502 503 ~SuperLU() 504 { 505 } 506 507 /** Performs a symbolic decomposition on the sparcity of \a matrix. 508 * 509 * This function is particularly useful when solving for several problems having the same structure. 510 * 511 * \sa factorize() 512 */ 513 void analyzePattern(const MatrixType& matrix) 514 { 515 m_info = InvalidInput; 516 m_isInitialized = false; 517 Base::analyzePattern(matrix); 518 } 519 520 /** Performs a numeric decomposition of \a matrix 521 * 522 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 523 * 524 * \sa analyzePattern() 525 */ 526 void factorize(const MatrixType& matrix); 527 528 #ifndef EIGEN_PARSED_BY_DOXYGEN 529 /** \internal */ 530 template<typename Rhs,typename Dest> 531 void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const; 532 #endif // EIGEN_PARSED_BY_DOXYGEN 533 534 inline const LMatrixType& matrixL() const 535 { 536 if (m_extractedDataAreDirty) this->extractData(); 537 return m_l; 538 } 539 540 inline const UMatrixType& matrixU() const 541 { 542 if (m_extractedDataAreDirty) this->extractData(); 543 return m_u; 544 } 545 546 inline const IntColVectorType& permutationP() const 547 { 548 if (m_extractedDataAreDirty) this->extractData(); 549 return m_p; 550 } 551 552 inline const IntRowVectorType& permutationQ() const 553 { 554 if (m_extractedDataAreDirty) this->extractData(); 555 return m_q; 556 } 557 558 Scalar determinant() const; 559 560 protected: 561 562 using Base::m_matrix; 563 using Base::m_sluOptions; 564 using Base::m_sluA; 565 using Base::m_sluB; 566 using Base::m_sluX; 567 using Base::m_p; 568 using Base::m_q; 569 using Base::m_sluEtree; 570 using Base::m_sluEqued; 571 using Base::m_sluRscale; 572 using Base::m_sluCscale; 573 using Base::m_sluL; 574 using Base::m_sluU; 575 using Base::m_sluStat; 576 using Base::m_sluFerr; 577 using Base::m_sluBerr; 578 using Base::m_l; 579 using Base::m_u; 580 581 using Base::m_analysisIsOk; 582 using Base::m_factorizationIsOk; 583 using Base::m_extractedDataAreDirty; 584 using Base::m_isInitialized; 585 using Base::m_info; 586 587 void init() 588 { 589 Base::init(); 590 591 set_default_options(&this->m_sluOptions); 592 m_sluOptions.PrintStat = NO; 593 m_sluOptions.ConditionNumber = NO; 594 m_sluOptions.Trans = NOTRANS; 595 m_sluOptions.ColPerm = COLAMD; 596 } 597 598 599 private: 600 SuperLU(SuperLU& ) { } 601 }; 602 603 template<typename MatrixType> 604 void SuperLU<MatrixType>::factorize(const MatrixType& a) 605 { 606 eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); 607 if(!m_analysisIsOk) 608 { 609 m_info = InvalidInput; 610 return; 611 } 612 613 this->initFactorization(a); 614 615 int info = 0; 616 RealScalar recip_pivot_growth, rcond; 617 RealScalar ferr, berr; 618 619 StatInit(&m_sluStat); 620 SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], 621 &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], 622 &m_sluL, &m_sluU, 623 NULL, 0, 624 &m_sluB, &m_sluX, 625 &recip_pivot_growth, &rcond, 626 &ferr, &berr, 627 &m_sluStat, &info, Scalar()); 628 StatFree(&m_sluStat); 629 630 m_extractedDataAreDirty = true; 631 632 // FIXME how to better check for errors ??? 633 m_info = info == 0 ? Success : NumericalIssue; 634 m_factorizationIsOk = true; 635 } 636 637 template<typename MatrixType> 638 template<typename Rhs,typename Dest> 639 void SuperLU<MatrixType>::_solve(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const 640 { 641 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()"); 642 643 const int size = m_matrix.rows(); 644 const int rhsCols = b.cols(); 645 eigen_assert(size==b.rows()); 646 647 m_sluOptions.Trans = NOTRANS; 648 m_sluOptions.Fact = FACTORED; 649 m_sluOptions.IterRefine = NOREFINE; 650 651 652 m_sluFerr.resize(rhsCols); 653 m_sluBerr.resize(rhsCols); 654 m_sluB = SluMatrix::Map(b.const_cast_derived()); 655 m_sluX = SluMatrix::Map(x.derived()); 656 657 typename Rhs::PlainObject b_cpy; 658 if(m_sluEqued!='N') 659 { 660 b_cpy = b; 661 m_sluB = SluMatrix::Map(b_cpy.const_cast_derived()); 662 } 663 664 StatInit(&m_sluStat); 665 int info = 0; 666 RealScalar recip_pivot_growth, rcond; 667 SuperLU_gssvx(&m_sluOptions, &m_sluA, 668 m_q.data(), m_p.data(), 669 &m_sluEtree[0], &m_sluEqued, 670 &m_sluRscale[0], &m_sluCscale[0], 671 &m_sluL, &m_sluU, 672 NULL, 0, 673 &m_sluB, &m_sluX, 674 &recip_pivot_growth, &rcond, 675 &m_sluFerr[0], &m_sluBerr[0], 676 &m_sluStat, &info, Scalar()); 677 StatFree(&m_sluStat); 678 m_info = info==0 ? Success : NumericalIssue; 679 } 680 681 // the code of this extractData() function has been adapted from the SuperLU's Matlab support code, 682 // 683 // Copyright (c) 1994 by Xerox Corporation. All rights reserved. 684 // 685 // THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY 686 // EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. 687 // 688 template<typename MatrixType, typename Derived> 689 void SuperLUBase<MatrixType,Derived>::extractData() const 690 { 691 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for extracting factors, you must first call either compute() or analyzePattern()/factorize()"); 692 if (m_extractedDataAreDirty) 693 { 694 int upper; 695 int fsupc, istart, nsupr; 696 int lastl = 0, lastu = 0; 697 SCformat *Lstore = static_cast<SCformat*>(m_sluL.Store); 698 NCformat *Ustore = static_cast<NCformat*>(m_sluU.Store); 699 Scalar *SNptr; 700 701 const int size = m_matrix.rows(); 702 m_l.resize(size,size); 703 m_l.resizeNonZeros(Lstore->nnz); 704 m_u.resize(size,size); 705 m_u.resizeNonZeros(Ustore->nnz); 706 707 int* Lcol = m_l.outerIndexPtr(); 708 int* Lrow = m_l.innerIndexPtr(); 709 Scalar* Lval = m_l.valuePtr(); 710 711 int* Ucol = m_u.outerIndexPtr(); 712 int* Urow = m_u.innerIndexPtr(); 713 Scalar* Uval = m_u.valuePtr(); 714 715 Ucol[0] = 0; 716 Ucol[0] = 0; 717 718 /* for each supernode */ 719 for (int k = 0; k <= Lstore->nsuper; ++k) 720 { 721 fsupc = L_FST_SUPC(k); 722 istart = L_SUB_START(fsupc); 723 nsupr = L_SUB_START(fsupc+1) - istart; 724 upper = 1; 725 726 /* for each column in the supernode */ 727 for (int j = fsupc; j < L_FST_SUPC(k+1); ++j) 728 { 729 SNptr = &((Scalar*)Lstore->nzval)[L_NZ_START(j)]; 730 731 /* Extract U */ 732 for (int i = U_NZ_START(j); i < U_NZ_START(j+1); ++i) 733 { 734 Uval[lastu] = ((Scalar*)Ustore->nzval)[i]; 735 /* Matlab doesn't like explicit zero. */ 736 if (Uval[lastu] != 0.0) 737 Urow[lastu++] = U_SUB(i); 738 } 739 for (int i = 0; i < upper; ++i) 740 { 741 /* upper triangle in the supernode */ 742 Uval[lastu] = SNptr[i]; 743 /* Matlab doesn't like explicit zero. */ 744 if (Uval[lastu] != 0.0) 745 Urow[lastu++] = L_SUB(istart+i); 746 } 747 Ucol[j+1] = lastu; 748 749 /* Extract L */ 750 Lval[lastl] = 1.0; /* unit diagonal */ 751 Lrow[lastl++] = L_SUB(istart + upper - 1); 752 for (int i = upper; i < nsupr; ++i) 753 { 754 Lval[lastl] = SNptr[i]; 755 /* Matlab doesn't like explicit zero. */ 756 if (Lval[lastl] != 0.0) 757 Lrow[lastl++] = L_SUB(istart+i); 758 } 759 Lcol[j+1] = lastl; 760 761 ++upper; 762 } /* for j ... */ 763 764 } /* for k ... */ 765 766 // squeeze the matrices : 767 m_l.resizeNonZeros(lastl); 768 m_u.resizeNonZeros(lastu); 769 770 m_extractedDataAreDirty = false; 771 } 772 } 773 774 template<typename MatrixType> 775 typename SuperLU<MatrixType>::Scalar SuperLU<MatrixType>::determinant() const 776 { 777 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for computing the determinant, you must first call either compute() or analyzePattern()/factorize()"); 778 779 if (m_extractedDataAreDirty) 780 this->extractData(); 781 782 Scalar det = Scalar(1); 783 for (int j=0; j<m_u.cols(); ++j) 784 { 785 if (m_u.outerIndexPtr()[j+1]-m_u.outerIndexPtr()[j] > 0) 786 { 787 int lastId = m_u.outerIndexPtr()[j+1]-1; 788 eigen_assert(m_u.innerIndexPtr()[lastId]<=j); 789 if (m_u.innerIndexPtr()[lastId]==j) 790 det *= m_u.valuePtr()[lastId]; 791 } 792 } 793 if(m_sluEqued!='N') 794 return det/m_sluRscale.prod()/m_sluCscale.prod(); 795 else 796 return det; 797 } 798 799 #ifdef EIGEN_PARSED_BY_DOXYGEN 800 #define EIGEN_SUPERLU_HAS_ILU 801 #endif 802 803 #ifdef EIGEN_SUPERLU_HAS_ILU 804 805 /** \ingroup SuperLUSupport_Module 806 * \class SuperILU 807 * \brief A sparse direct \b incomplete LU factorization and solver based on the SuperLU library 808 * 809 * This class allows to solve for an approximate solution of A.X = B sparse linear problems via an incomplete LU factorization 810 * using the SuperLU library. This class is aimed to be used as a preconditioner of the iterative linear solvers. 811 * 812 * \warning This class requires SuperLU 4 or later. 813 * 814 * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> 815 * 816 * \sa \ref TutorialSparseDirectSolvers, class ConjugateGradient, class BiCGSTAB 817 */ 818 819 template<typename _MatrixType> 820 class SuperILU : public SuperLUBase<_MatrixType,SuperILU<_MatrixType> > 821 { 822 public: 823 typedef SuperLUBase<_MatrixType,SuperILU> Base; 824 typedef _MatrixType MatrixType; 825 typedef typename Base::Scalar Scalar; 826 typedef typename Base::RealScalar RealScalar; 827 typedef typename Base::Index Index; 828 829 public: 830 831 SuperILU() : Base() { init(); } 832 833 SuperILU(const MatrixType& matrix) : Base() 834 { 835 init(); 836 compute(matrix); 837 } 838 839 ~SuperILU() 840 { 841 } 842 843 /** Performs a symbolic decomposition on the sparcity of \a matrix. 844 * 845 * This function is particularly useful when solving for several problems having the same structure. 846 * 847 * \sa factorize() 848 */ 849 void analyzePattern(const MatrixType& matrix) 850 { 851 Base::analyzePattern(matrix); 852 } 853 854 /** Performs a numeric decomposition of \a matrix 855 * 856 * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. 857 * 858 * \sa analyzePattern() 859 */ 860 void factorize(const MatrixType& matrix); 861 862 #ifndef EIGEN_PARSED_BY_DOXYGEN 863 /** \internal */ 864 template<typename Rhs,typename Dest> 865 void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const; 866 #endif // EIGEN_PARSED_BY_DOXYGEN 867 868 protected: 869 870 using Base::m_matrix; 871 using Base::m_sluOptions; 872 using Base::m_sluA; 873 using Base::m_sluB; 874 using Base::m_sluX; 875 using Base::m_p; 876 using Base::m_q; 877 using Base::m_sluEtree; 878 using Base::m_sluEqued; 879 using Base::m_sluRscale; 880 using Base::m_sluCscale; 881 using Base::m_sluL; 882 using Base::m_sluU; 883 using Base::m_sluStat; 884 using Base::m_sluFerr; 885 using Base::m_sluBerr; 886 using Base::m_l; 887 using Base::m_u; 888 889 using Base::m_analysisIsOk; 890 using Base::m_factorizationIsOk; 891 using Base::m_extractedDataAreDirty; 892 using Base::m_isInitialized; 893 using Base::m_info; 894 895 void init() 896 { 897 Base::init(); 898 899 ilu_set_default_options(&m_sluOptions); 900 m_sluOptions.PrintStat = NO; 901 m_sluOptions.ConditionNumber = NO; 902 m_sluOptions.Trans = NOTRANS; 903 m_sluOptions.ColPerm = MMD_AT_PLUS_A; 904 905 // no attempt to preserve column sum 906 m_sluOptions.ILU_MILU = SILU; 907 // only basic ILU(k) support -- no direct control over memory consumption 908 // better to use ILU_DropRule = DROP_BASIC | DROP_AREA 909 // and set ILU_FillFactor to max memory growth 910 m_sluOptions.ILU_DropRule = DROP_BASIC; 911 m_sluOptions.ILU_DropTol = NumTraits<Scalar>::dummy_precision()*10; 912 } 913 914 private: 915 SuperILU(SuperILU& ) { } 916 }; 917 918 template<typename MatrixType> 919 void SuperILU<MatrixType>::factorize(const MatrixType& a) 920 { 921 eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); 922 if(!m_analysisIsOk) 923 { 924 m_info = InvalidInput; 925 return; 926 } 927 928 this->initFactorization(a); 929 930 int info = 0; 931 RealScalar recip_pivot_growth, rcond; 932 933 StatInit(&m_sluStat); 934 SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], 935 &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], 936 &m_sluL, &m_sluU, 937 NULL, 0, 938 &m_sluB, &m_sluX, 939 &recip_pivot_growth, &rcond, 940 &m_sluStat, &info, Scalar()); 941 StatFree(&m_sluStat); 942 943 // FIXME how to better check for errors ??? 944 m_info = info == 0 ? Success : NumericalIssue; 945 m_factorizationIsOk = true; 946 } 947 948 template<typename MatrixType> 949 template<typename Rhs,typename Dest> 950 void SuperILU<MatrixType>::_solve(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const 951 { 952 eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()"); 953 954 const int size = m_matrix.rows(); 955 const int rhsCols = b.cols(); 956 eigen_assert(size==b.rows()); 957 958 m_sluOptions.Trans = NOTRANS; 959 m_sluOptions.Fact = FACTORED; 960 m_sluOptions.IterRefine = NOREFINE; 961 962 m_sluFerr.resize(rhsCols); 963 m_sluBerr.resize(rhsCols); 964 m_sluB = SluMatrix::Map(b.const_cast_derived()); 965 m_sluX = SluMatrix::Map(x.derived()); 966 967 typename Rhs::PlainObject b_cpy; 968 if(m_sluEqued!='N') 969 { 970 b_cpy = b; 971 m_sluB = SluMatrix::Map(b_cpy.const_cast_derived()); 972 } 973 974 int info = 0; 975 RealScalar recip_pivot_growth, rcond; 976 977 StatInit(&m_sluStat); 978 SuperLU_gsisx(&m_sluOptions, &m_sluA, 979 m_q.data(), m_p.data(), 980 &m_sluEtree[0], &m_sluEqued, 981 &m_sluRscale[0], &m_sluCscale[0], 982 &m_sluL, &m_sluU, 983 NULL, 0, 984 &m_sluB, &m_sluX, 985 &recip_pivot_growth, &rcond, 986 &m_sluStat, &info, Scalar()); 987 StatFree(&m_sluStat); 988 989 m_info = info==0 ? Success : NumericalIssue; 990 } 991 #endif 992 993 namespace internal { 994 995 template<typename _MatrixType, typename Derived, typename Rhs> 996 struct solve_retval<SuperLUBase<_MatrixType,Derived>, Rhs> 997 : solve_retval_base<SuperLUBase<_MatrixType,Derived>, Rhs> 998 { 999 typedef SuperLUBase<_MatrixType,Derived> Dec; 1000 EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) 1001 1002 template<typename Dest> void evalTo(Dest& dst) const 1003 { 1004 dec().derived()._solve(rhs(),dst); 1005 } 1006 }; 1007 1008 template<typename _MatrixType, typename Derived, typename Rhs> 1009 struct sparse_solve_retval<SuperLUBase<_MatrixType,Derived>, Rhs> 1010 : sparse_solve_retval_base<SuperLUBase<_MatrixType,Derived>, Rhs> 1011 { 1012 typedef SuperLUBase<_MatrixType,Derived> Dec; 1013 EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) 1014 1015 template<typename Dest> void evalTo(Dest& dst) const 1016 { 1017 dec().derived()._solve(rhs(),dst); 1018 } 1019 }; 1020 1021 } // end namespace internal 1022 1023 } // end namespace Eigen 1024 1025 #endif // EIGEN_SUPERLUSUPPORT_H 1026