| // This file is part of Eigen, a lightweight C++ template library | 
 | // for linear algebra. | 
 | // | 
 | // Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr> | 
 | // | 
 | // Eigen is free software; you can redistribute it and/or | 
 | // modify it under the terms of the GNU Lesser General Public | 
 | // License as published by the Free Software Foundation; either | 
 | // version 3 of the License, or (at your option) any later version. | 
 | // | 
 | // Alternatively, you can redistribute it and/or | 
 | // modify it under the terms of the GNU General Public License as | 
 | // published by the Free Software Foundation; either version 2 of | 
 | // the License, or (at your option) any later version. | 
 | // | 
 | // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY | 
 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
 | // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the | 
 | // GNU General Public License for more details. | 
 | // | 
 | // You should have received a copy of the GNU Lesser General Public | 
 | // License and a copy of the GNU General Public License along with | 
 | // Eigen. If not, see <http://www.gnu.org/licenses/>. | 
 |  | 
 | #ifndef EIGEN_TAUCSSUPPORT_H | 
 | #define EIGEN_TAUCSSUPPORT_H | 
 |  | 
 | template<typename MatrixType> | 
 | taucs_ccs_matrix ei_asTaucsMatrix(MatrixType& mat) | 
 | { | 
 |   typedef typename MatrixType::Scalar Scalar; | 
 | enum { Flags = MatrixType::Flags }; | 
 |   taucs_ccs_matrix res; | 
 |   res.n         = mat.cols(); | 
 |   res.m         = mat.rows(); | 
 |   res.flags     = 0; | 
 |   res.colptr    = mat._outerIndexPtr(); | 
 |   res.rowind    = mat._innerIndexPtr(); | 
 |   res.values.v  = mat._valuePtr(); | 
 |   if (ei_is_same_type<Scalar,int>::ret) | 
 |     res.flags |= TAUCS_INT; | 
 |   else if (ei_is_same_type<Scalar,float>::ret) | 
 |     res.flags |= TAUCS_SINGLE; | 
 |   else if (ei_is_same_type<Scalar,double>::ret) | 
 |     res.flags |= TAUCS_DOUBLE; | 
 |   else if (ei_is_same_type<Scalar,std::complex<float> >::ret) | 
 |     res.flags |= TAUCS_SCOMPLEX; | 
 |   else if (ei_is_same_type<Scalar,std::complex<double> >::ret) | 
 |     res.flags |= TAUCS_DCOMPLEX; | 
 |   else | 
 |   { | 
 |     ei_assert(false && "Scalar type not supported by TAUCS"); | 
 |   } | 
 |  | 
 |   // FIXME 1) shapes are not in the Flags and 2) it seems Taucs ignores these flags anyway and only accept lower symmetric matrices | 
 |   if (Flags & Upper) | 
 |     res.flags |= TAUCS_UPPER; | 
 |   if (Flags & Lower) | 
 |     res.flags |= TAUCS_LOWER; | 
 |   if (Flags & SelfAdjoint) | 
 |     res.flags |= (NumTraits<Scalar>::IsComplex ? TAUCS_HERMITIAN : TAUCS_SYMMETRIC); | 
 |   else if ((Flags & Upper) || (Flags & Lower)) | 
 |     res.flags |= TAUCS_TRIANGULAR; | 
 |  | 
 |   return res; | 
 | } | 
 |  | 
 | template<typename Scalar, int Flags, typename Index> | 
 | MappedSparseMatrix<Scalar,Flags,Index> ei_map_taucs(taucs_ccs_matrix& taucsMat) | 
 | { | 
 |   return MappedSparseMatrix<Scalar,Flags,Index> | 
 |     (taucsMat.m, taucsMat.n, taucsMat.colptr[taucsMat.n], | 
 |      taucsMat.colptr, taucsMat.rowind, reinterpret_cast<Scalar*>(taucsMat.values.v)); | 
 | } | 
 |  | 
 | template<typename MatrixType> | 
 | class SparseLLT<MatrixType,Taucs> : public SparseLLT<MatrixType> | 
 | { | 
 |   protected: | 
 |     typedef SparseLLT<MatrixType> Base; | 
 |     typedef typename Base::Index Index; | 
 |     typedef typename Base::Scalar Scalar; | 
 |     typedef typename Base::RealScalar RealScalar; | 
 |     typedef typename Base::CholMatrixType CholMatrixType; | 
 |     using Base::MatrixLIsDirty; | 
 |     using Base::SupernodalFactorIsDirty; | 
 |     using Base::m_flags; | 
 |     using Base::m_matrix; | 
 |     using Base::m_status; | 
 |     using Base::m_succeeded; | 
 |  | 
 |   public: | 
 |  | 
 |     SparseLLT(int flags = SupernodalMultifrontal) | 
 |       : Base(flags), m_taucsSupernodalFactor(0) | 
 |     { | 
 |     } | 
 |  | 
 |     SparseLLT(const MatrixType& matrix, int flags = SupernodalMultifrontal) | 
 |       : Base(flags), m_taucsSupernodalFactor(0) | 
 |     { | 
 |       compute(matrix); | 
 |     } | 
 |  | 
 |     ~SparseLLT() | 
 |     { | 
 |       if (m_taucsSupernodalFactor) | 
 |         taucs_supernodal_factor_free(m_taucsSupernodalFactor); | 
 |     } | 
 |  | 
 |     inline const CholMatrixType& matrixL() const; | 
 |  | 
 |     template<typename Derived> | 
 |     void solveInPlace(MatrixBase<Derived> &b) const; | 
 |  | 
 |     void compute(const MatrixType& matrix); | 
 |  | 
 |   protected: | 
 |     void* m_taucsSupernodalFactor; | 
 | }; | 
 |  | 
 | template<typename MatrixType> | 
 | void SparseLLT<MatrixType,Taucs>::compute(const MatrixType& a) | 
 | { | 
 |   if (m_taucsSupernodalFactor) | 
 |   { | 
 |     taucs_supernodal_factor_free(m_taucsSupernodalFactor); | 
 |     m_taucsSupernodalFactor = 0; | 
 |   } | 
 |  | 
 |   taucs_ccs_matrix taucsMatA = ei_asTaucsMatrix(const_cast<MatrixType&>(a)); | 
 |  | 
 |   if (m_flags & IncompleteFactorization) | 
 |   { | 
 |     taucs_ccs_matrix* taucsRes = taucs_ccs_factor_llt(&taucsMatA, Base::m_precision, 0); | 
 |     if(!taucsRes) | 
 |     { | 
 |       m_succeeded = false; | 
 |       return; | 
 |     } | 
 |     // the matrix returned by Taucs is not necessarily sorted, | 
 |     // so let's copy it in two steps | 
 |     DynamicSparseMatrix<Scalar,RowMajor> tmp = ei_map_taucs<Scalar,ColMajor,Index>(*taucsRes); | 
 |     m_matrix = tmp; | 
 |     free(taucsRes); | 
 |     m_status = (m_status & ~(CompleteFactorization|MatrixLIsDirty)) | 
 |              | IncompleteFactorization | 
 |              | SupernodalFactorIsDirty; | 
 |   } | 
 |   else | 
 |   { | 
 |     if ( (m_flags & SupernodalLeftLooking) | 
 |       || ((!(m_flags & SupernodalMultifrontal)) && (m_flags & MemoryEfficient)) ) | 
 |     { | 
 |       m_taucsSupernodalFactor = taucs_ccs_factor_llt_ll(&taucsMatA); | 
 |     } | 
 |     else | 
 |     { | 
 |       // use the faster Multifrontal routine | 
 |       m_taucsSupernodalFactor = taucs_ccs_factor_llt_mf(&taucsMatA); | 
 |     } | 
 |     m_status = (m_status & ~IncompleteFactorization) | CompleteFactorization | MatrixLIsDirty; | 
 |   } | 
 |   m_succeeded = true; | 
 | } | 
 |  | 
 | template<typename MatrixType> | 
 | inline const typename SparseLLT<MatrixType,Taucs>::CholMatrixType& | 
 | SparseLLT<MatrixType,Taucs>::matrixL() const | 
 | { | 
 |   if (m_status & MatrixLIsDirty) | 
 |   { | 
 |     ei_assert(!(m_status & SupernodalFactorIsDirty)); | 
 |  | 
 |     taucs_ccs_matrix* taucsL = taucs_supernodal_factor_to_ccs(m_taucsSupernodalFactor); | 
 |  | 
 |     // the matrix returned by Taucs is not necessarily sorted, | 
 |     // so let's copy it in two steps | 
 |     DynamicSparseMatrix<Scalar,RowMajor> tmp = ei_map_taucs<Scalar,ColMajor,Index>(*taucsL); | 
 |     const_cast<typename Base::CholMatrixType&>(m_matrix) = tmp; | 
 |     free(taucsL); | 
 |     m_status = (m_status & ~MatrixLIsDirty); | 
 |   } | 
 |   return m_matrix; | 
 | } | 
 |  | 
 | template<typename MatrixType> | 
 | template<typename Derived> | 
 | void SparseLLT<MatrixType,Taucs>::solveInPlace(MatrixBase<Derived> &b) const | 
 | { | 
 |   bool inputIsCompatibleWithTaucs = (Derived::Flags&RowMajorBit)==0; | 
 |  | 
 |   if (!inputIsCompatibleWithTaucs) | 
 |   { | 
 |     matrixL(); | 
 |     Base::solveInPlace(b); | 
 |   } | 
 |   else if (m_flags & IncompleteFactorization) | 
 |   { | 
 |     taucs_ccs_matrix taucsLLT = ei_asTaucsMatrix(const_cast<typename Base::CholMatrixType&>(m_matrix)); | 
 |     typename ei_plain_matrix_type<Derived>::type x(b.rows()); | 
 |     for (int j=0; j<b.cols(); ++j) | 
 |     { | 
 |       taucs_ccs_solve_llt(&taucsLLT,x.data(),&b.col(j).coeffRef(0)); | 
 |       b.col(j) = x; | 
 |     } | 
 |   } | 
 |   else | 
 |   { | 
 |     typename ei_plain_matrix_type<Derived>::type x(b.rows()); | 
 |     for (int j=0; j<b.cols(); ++j) | 
 |     { | 
 |       taucs_supernodal_solve_llt(m_taucsSupernodalFactor,x.data(),&b.col(j).coeffRef(0)); | 
 |       b.col(j) = x; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | #endif // EIGEN_TAUCSSUPPORT_H |