// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr> // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
/** \internal * * A wrapper class for SuperLU matrices. It supports only compressed sparse matrices * and dense matrices. Supernodal and other fancy format are not supported by this wrapper. * * This wrapper class mainly aims to avoids the need of dynamic allocation of the storage structure.
*/ struct SluMatrix : SuperMatrix
{
SluMatrix()
{
Store = &storage;
}
// FIXME the following is not very accurate if (int(MatrixType::Flags) & int(Upper))
res.Mtype = SLU_TRU; if (int(MatrixType::Flags) & int(Lower))
res.Mtype = SLU_TRL;
eigen_assert(((int(MatrixType::Flags) & int(SelfAdjoint))==0) && "SelfAdjoint matrix shape not supported by SuperLU");
return res;
}
};
template<typename Scalar, int Rows, int Cols, int Options, int MRows, int MCols> struct SluMatrixMapHelper<Matrix<Scalar,Rows,Cols,Options,MRows,MCols> >
{ typedef Matrix<Scalar,Rows,Cols,Options,MRows,MCols> MatrixType; staticvoid run(MatrixType& mat, SluMatrix& res)
{
eigen_assert( ((Options&RowMajor)!=RowMajor) && "row-major dense matrices is not supported by SuperLU");
res.setStorageType(SLU_DN);
res.setScalarType<Scalar>();
res.Mtype = SLU_GE;
/** View a Super LU matrix as an Eigen expression */ template<typename Scalar, int Flags, typename Index>
MappedSparseMatrix<Scalar,Flags,Index> map_superlu(SluMatrix& sluMat)
{
eigen_assert(((Flags&RowMajor)==RowMajor && sluMat.Stype == SLU_NR)
|| ((Flags&ColMajor)==ColMajor && sluMat.Stype == SLU_NC));
Index outerSize = (Flags&RowMajor)==RowMajor ? sluMat.ncol : sluMat.nrow;
/** \ingroup SuperLUSupport_Module * \class SuperLUBase * \brief The base class for the direct and incomplete LU factorization of SuperLU
*/ template<typename _MatrixType, typename Derived> class SuperLUBase : public SparseSolverBase<Derived>
{ protected: typedef SparseSolverBase<Derived> Base; using Base::derived; using Base::m_isInitialized; public: typedef _MatrixType MatrixType; typedeftypename MatrixType::Scalar Scalar; typedeftypename MatrixType::RealScalar RealScalar; typedeftypename MatrixType::StorageIndex StorageIndex; typedef Matrix<Scalar,Dynamic,1> Vector; typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType; typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType; typedef Map<PermutationMatrix<Dynamic,Dynamic,int> > PermutationMap; typedef SparseMatrix<Scalar> LUMatrixType; enum {
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
};
public:
SuperLUBase() {}
~SuperLUBase()
{
clearFactors();
}
inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); }
/** \returns a reference to the Super LU option object to configure the Super LU algorithms. */ inline superlu_options_t& options() { return m_sluOptions; }
/** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was successful, * \c NumericalIssue if the matrix.appears to be negative.
*/
ComputationInfo info() const
{
eigen_assert(m_isInitialized && "Decomposition is not initialized."); return m_info;
}
/** Computes the sparse Cholesky decomposition of \a matrix */ void compute(const MatrixType& matrix)
{
derived().analyzePattern(matrix);
derived().factorize(matrix);
}
/** Performs a symbolic decomposition on the sparcity of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. * * \sa factorize()
*/ void analyzePattern(const MatrixType& /*matrix*/)
{
m_isInitialized = true;
m_info = Success;
m_analysisIsOk = true;
m_factorizationIsOk = false;
}
mutable ComputationInfo m_info; int m_factorizationIsOk; int m_analysisIsOk; mutablebool m_extractedDataAreDirty;
private:
SuperLUBase(SuperLUBase& ) { }
};
/** \ingroup SuperLUSupport_Module * \class SuperLU * \brief A sparse direct LU factorization and solver based on the SuperLU library * * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization * using the SuperLU library. The sparse matrix A must be squared and invertible. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * * \warning This class is only for the 4.x versions of SuperLU. The 3.x and 5.x versions are not supported. * * \implsparsesolverconcept * * \sa \ref TutorialSparseSolverConcept, class SparseLU
*/ template<typename _MatrixType> class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> >
{ public: typedef SuperLUBase<_MatrixType,SuperLU> Base; typedef _MatrixType MatrixType; typedeftypename Base::Scalar Scalar; typedeftypename Base::RealScalar RealScalar; typedeftypename Base::StorageIndex StorageIndex; typedeftypename Base::IntRowVectorType IntRowVectorType; typedeftypename Base::IntColVectorType IntColVectorType; typedeftypename Base::PermutationMap PermutationMap; typedeftypename Base::LUMatrixType LUMatrixType; typedef TriangularView<LUMatrixType, Lower|UnitDiag> LMatrixType; typedef TriangularView<LUMatrixType, Upper> UMatrixType;
/** Performs a symbolic decomposition on the sparcity of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. * * \sa factorize()
*/ void analyzePattern(const MatrixType& matrix)
{
m_info = InvalidInput;
m_isInitialized = false;
Base::analyzePattern(matrix);
}
/** Performs a numeric decomposition of \a matrix * * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. * * \sa analyzePattern()
*/ void factorize(const MatrixType& matrix);
using Base::m_matrix; using Base::m_sluOptions; using Base::m_sluA; using Base::m_sluB; using Base::m_sluX; using Base::m_p; using Base::m_q; using Base::m_sluEtree; using Base::m_sluEqued; using Base::m_sluRscale; using Base::m_sluCscale; using Base::m_sluL; using Base::m_sluU; using Base::m_sluStat; using Base::m_sluFerr; using Base::m_sluBerr; using Base::m_l; using Base::m_u;
using Base::m_analysisIsOk; using Base::m_factorizationIsOk; using Base::m_extractedDataAreDirty; using Base::m_isInitialized; using Base::m_info;
// FIXME how to better check for errors ???
m_info = info == 0 ? Success : NumericalIssue;
m_factorizationIsOk = true;
}
template<typename MatrixType> template<typename Rhs,typename Dest> void SuperLU<MatrixType>::_solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const
{
eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()");
const Index rhsCols = b.cols();
eigen_assert(m_matrix.rows()==b.rows());
// the code of this extractData() function has been adapted from the SuperLU's Matlab support code, // // Copyright (c) 1994 by Xerox Corporation. All rights reserved. // // THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY // EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. // template<typename MatrixType, typename Derived> void SuperLUBase<MatrixType,Derived>::extractData() const
{
eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for extracting factors, you must first call either compute() or analyzePattern()/factorize()"); if (m_extractedDataAreDirty)
{ int upper; int fsupc, istart, nsupr; int lastl = 0, lastu = 0;
SCformat *Lstore = static_cast<SCformat*>(m_sluL.Store);
NCformat *Ustore = static_cast<NCformat*>(m_sluU.Store);
Scalar *SNptr;
const Index size = m_matrix.rows();
m_l.resize(size,size);
m_l.resizeNonZeros(Lstore->nnz);
m_u.resize(size,size);
m_u.resizeNonZeros(Ustore->nnz);
/* for each supernode */ for (int k = 0; k <= Lstore->nsuper; ++k)
{
fsupc = L_FST_SUPC(k);
istart = L_SUB_START(fsupc);
nsupr = L_SUB_START(fsupc+1) - istart;
upper = 1;
/* for each column in the supernode */ for (int j = fsupc; j < L_FST_SUPC(k+1); ++j)
{
SNptr = &((Scalar*)Lstore->nzval)[L_NZ_START(j)];
/* Extract U */ for (int i = U_NZ_START(j); i < U_NZ_START(j+1); ++i)
{
Uval[lastu] = ((Scalar*)Ustore->nzval)[i]; /* Matlab doesn't like explicit zero. */ if (Uval[lastu] != 0.0)
Urow[lastu++] = U_SUB(i);
} for (int i = 0; i < upper; ++i)
{ /* upper triangle in the supernode */
Uval[lastu] = SNptr[i]; /* Matlab doesn't like explicit zero. */ if (Uval[lastu] != 0.0)
Urow[lastu++] = L_SUB(istart+i);
}
Ucol[j+1] = lastu;
/* Extract L */
Lval[lastl] = 1.0; /* unit diagonal */
Lrow[lastl++] = L_SUB(istart + upper - 1); for (int i = upper; i < nsupr; ++i)
{
Lval[lastl] = SNptr[i]; /* Matlab doesn't like explicit zero. */ if (Lval[lastl] != 0.0)
Lrow[lastl++] = L_SUB(istart+i);
}
Lcol[j+1] = lastl;
++upper;
} /* for j ... */
} /* for k ... */
// squeeze the matrices :
m_l.resizeNonZeros(lastl);
m_u.resizeNonZeros(lastu);
m_extractedDataAreDirty = false;
}
}
template<typename MatrixType> typename SuperLU<MatrixType>::Scalar SuperLU<MatrixType>::determinant() const
{
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()");
if (m_extractedDataAreDirty)
this->extractData();
Scalar det = Scalar(1); for (int j=0; j<m_u.cols(); ++j)
{ if (m_u.outerIndexPtr()[j+1]-m_u.outerIndexPtr()[j] > 0)
{ int lastId = m_u.outerIndexPtr()[j+1]-1;
eigen_assert(m_u.innerIndexPtr()[lastId]<=j); if (m_u.innerIndexPtr()[lastId]==j)
det *= m_u.valuePtr()[lastId];
}
} if(PermutationMap(m_p.data(),m_p.size()).determinant()*PermutationMap(m_q.data(),m_q.size()).determinant()<0)
det = -det; if(m_sluEqued!='N') return det/m_sluRscale.prod()/m_sluCscale.prod(); else return det;
}
/** \ingroup SuperLUSupport_Module * \class SuperILU * \brief A sparse direct \b incomplete LU factorization and solver based on the SuperLU library * * This class allows to solve for an approximate solution of A.X = B sparse linear problems via an incomplete LU factorization * using the SuperLU library. This class is aimed to be used as a preconditioner of the iterative linear solvers. * * \warning This class is only for the 4.x versions of SuperLU. The 3.x and 5.x versions are not supported. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * * \implsparsesolverconcept * * \sa \ref TutorialSparseSolverConcept, class IncompleteLUT, class ConjugateGradient, class BiCGSTAB
*/
/** Performs a symbolic decomposition on the sparcity of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. * * \sa factorize()
*/ void analyzePattern(const MatrixType& matrix)
{
Base::analyzePattern(matrix);
}
/** Performs a numeric decomposition of \a matrix * * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. * * \sa analyzePattern()
*/ void factorize(const MatrixType& matrix);
using Base::m_matrix; using Base::m_sluOptions; using Base::m_sluA; using Base::m_sluB; using Base::m_sluX; using Base::m_p; using Base::m_q; using Base::m_sluEtree; using Base::m_sluEqued; using Base::m_sluRscale; using Base::m_sluCscale; using Base::m_sluL; using Base::m_sluU; using Base::m_sluStat; using Base::m_sluFerr; using Base::m_sluBerr; using Base::m_l; using Base::m_u;
using Base::m_analysisIsOk; using Base::m_factorizationIsOk; using Base::m_extractedDataAreDirty; using Base::m_isInitialized; using Base::m_info;
// no attempt to preserve column sum
m_sluOptions.ILU_MILU = SILU; // only basic ILU(k) support -- no direct control over memory consumption // better to use ILU_DropRule = DROP_BASIC | DROP_AREA // and set ILU_FillFactor to max memory growth
m_sluOptions.ILU_DropRule = DROP_BASIC;
m_sluOptions.ILU_DropTol = NumTraits<Scalar>::dummy_precision()*10;
}
private:
SuperILU(SuperILU& ) { }
};
template<typename MatrixType> void SuperILU<MatrixType>::factorize(const MatrixType& a)
{
eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); if(!m_analysisIsOk)
{
m_info = InvalidInput; return;
}
this->initFactorization(a);
int info = 0;
RealScalar recip_pivot_growth, rcond;
// FIXME how to better check for errors ???
m_info = info == 0 ? Success : NumericalIssue;
m_factorizationIsOk = true;
}
#ifndef EIGEN_PARSED_BY_DOXYGEN template<typename MatrixType> template<typename Rhs,typename Dest> void SuperILU<MatrixType>::_solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const
{
eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.