SparseSelfAdjointView.h
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #ifndef EIGEN_SPARSE_SELFADJOINTVIEW_H
00011 #define EIGEN_SPARSE_SELFADJOINTVIEW_H
00012 
00013 namespace Eigen { 
00014 
00029 template<typename Lhs, typename Rhs, int UpLo>
00030 class SparseSelfAdjointTimeDenseProduct;
00031 
00032 template<typename Lhs, typename Rhs, int UpLo>
00033 class DenseTimeSparseSelfAdjointProduct;
00034 
00035 namespace internal {
00036   
00037 template<typename MatrixType, unsigned int UpLo>
00038 struct traits<SparseSelfAdjointView<MatrixType,UpLo> > : traits<MatrixType> {
00039 };
00040 
00041 template<int SrcUpLo,int DstUpLo,typename MatrixType,int DestOrder>
00042 void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm = 0);
00043 
00044 template<int UpLo,typename MatrixType,int DestOrder>
00045 void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm = 0);
00046 
00047 }
00048 
00049 template<typename MatrixType, unsigned int UpLo> class SparseSelfAdjointView
00050   : public EigenBase<SparseSelfAdjointView<MatrixType,UpLo> >
00051 {
00052   public:
00053 
00054     typedef typename MatrixType::Scalar Scalar;
00055     typedef typename MatrixType::Index Index;
00056     typedef Matrix<Index,Dynamic,1> VectorI;
00057     typedef typename MatrixType::Nested MatrixTypeNested;
00058     typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
00059 
00060     inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix)
00061     {
00062       eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices");
00063     }
00064 
00065     inline Index rows() const { return m_matrix.rows(); }
00066     inline Index cols() const { return m_matrix.cols(); }
00067 
00069     const _MatrixTypeNested& matrix() const { return m_matrix; }
00070     _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); }
00071 
00073     template<typename OtherDerived>
00074     SparseSelfAdjointTimeDenseProduct<MatrixType,OtherDerived,UpLo>
00075     operator*(const MatrixBase<OtherDerived>& rhs) const
00076     {
00077       return SparseSelfAdjointTimeDenseProduct<MatrixType,OtherDerived,UpLo>(m_matrix, rhs.derived());
00078     }
00079 
00081     template<typename OtherDerived> friend
00082     DenseTimeSparseSelfAdjointProduct<OtherDerived,MatrixType,UpLo>
00083     operator*(const MatrixBase<OtherDerived>& lhs, const SparseSelfAdjointView& rhs)
00084     {
00085       return DenseTimeSparseSelfAdjointProduct<OtherDerived,_MatrixTypeNested,UpLo>(lhs.derived(), rhs.m_matrix);
00086     }
00087 
00096     template<typename DerivedU>
00097     SparseSelfAdjointView& rankUpdate(const SparseMatrixBase<DerivedU>& u, Scalar alpha = Scalar(1));
00098     
00100     template<typename DestScalar,int StorageOrder> void evalTo(SparseMatrix<DestScalar,StorageOrder,Index>& _dest) const
00101     {
00102       internal::permute_symm_to_fullsymm<UpLo>(m_matrix, _dest);
00103     }
00104     
00105     template<typename DestScalar> void evalTo(DynamicSparseMatrix<DestScalar,ColMajor,Index>& _dest) const
00106     {
00107       // TODO directly evaluate into _dest;
00108       SparseMatrix<DestScalar,ColMajor,Index> tmp(_dest.rows(),_dest.cols());
00109       internal::permute_symm_to_fullsymm<UpLo>(m_matrix, tmp);
00110       _dest = tmp;
00111     }
00112     
00114     SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix<Dynamic,Dynamic,Index>& perm) const
00115     {
00116       return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm);
00117     }
00118     
00119     template<typename SrcMatrixType,int SrcUpLo>
00120     SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct<SrcMatrixType,SrcUpLo>& permutedMatrix)
00121     {
00122       permutedMatrix.evalTo(*this);
00123       return *this;
00124     }
00125 
00126 
00127     SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src)
00128     {
00129       PermutationMatrix<Dynamic> pnull;
00130       return *this = src.twistedBy(pnull);
00131     }
00132 
00133     template<typename SrcMatrixType,unsigned int SrcUpLo>
00134     SparseSelfAdjointView& operator=(const SparseSelfAdjointView<SrcMatrixType,SrcUpLo>& src)
00135     {
00136       PermutationMatrix<Dynamic> pnull;
00137       return *this = src.twistedBy(pnull);
00138     }
00139     
00140 
00141     // const SparseLLT<PlainObject, UpLo> llt() const;
00142     // const SparseLDLT<PlainObject, UpLo> ldlt() const;
00143 
00144   protected:
00145 
00146     typename MatrixType::Nested m_matrix;
00147     mutable VectorI m_countPerRow;
00148     mutable VectorI m_countPerCol;
00149 };
00150 
00151 /***************************************************************************
00152 * Implementation of SparseMatrixBase methods
00153 ***************************************************************************/
00154 
00155 template<typename Derived>
00156 template<unsigned int UpLo>
00157 const SparseSelfAdjointView<Derived, UpLo> SparseMatrixBase<Derived>::selfadjointView() const
00158 {
00159   return derived();
00160 }
00161 
00162 template<typename Derived>
00163 template<unsigned int UpLo>
00164 SparseSelfAdjointView<Derived, UpLo> SparseMatrixBase<Derived>::selfadjointView()
00165 {
00166   return derived();
00167 }
00168 
00169 /***************************************************************************
00170 * Implementation of SparseSelfAdjointView methods
00171 ***************************************************************************/
00172 
00173 template<typename MatrixType, unsigned int UpLo>
00174 template<typename DerivedU>
00175 SparseSelfAdjointView<MatrixType,UpLo>&
00176 SparseSelfAdjointView<MatrixType,UpLo>::rankUpdate(const SparseMatrixBase<DerivedU>& u, Scalar alpha)
00177 {
00178   SparseMatrix<Scalar,MatrixType::Flags&RowMajorBit?RowMajor:ColMajor> tmp = u * u.adjoint();
00179   if(alpha==Scalar(0))
00180     m_matrix.const_cast_derived() = tmp.template triangularView<UpLo>();
00181   else
00182     m_matrix.const_cast_derived() += alpha * tmp.template triangularView<UpLo>();
00183 
00184   return *this;
00185 }
00186 
00187 /***************************************************************************
00188 * Implementation of sparse self-adjoint time dense matrix
00189 ***************************************************************************/
00190 
00191 namespace internal {
00192 template<typename Lhs, typename Rhs, int UpLo>
00193 struct traits<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo> >
00194  : traits<ProductBase<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo>, Lhs, Rhs> >
00195 {
00196   typedef Dense StorageKind;
00197 };
00198 }
00199 
00200 template<typename Lhs, typename Rhs, int UpLo>
00201 class SparseSelfAdjointTimeDenseProduct
00202   : public ProductBase<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo>, Lhs, Rhs>
00203 {
00204   public:
00205     EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct)
00206 
00207     SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
00208     {}
00209 
00210     template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
00211     {
00212       EIGEN_ONLY_USED_FOR_DEBUG(alpha);
00213       // TODO use alpha
00214       eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry");
00215       typedef typename internal::remove_all<Lhs>::type _Lhs;
00216       typedef typename internal::remove_all<Rhs>::type _Rhs;
00217       typedef typename _Lhs::InnerIterator LhsInnerIterator;
00218       enum {
00219         LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit,
00220         ProcessFirstHalf =
00221                  ((UpLo&(Upper|Lower))==(Upper|Lower))
00222               || ( (UpLo&Upper) && !LhsIsRowMajor)
00223               || ( (UpLo&Lower) && LhsIsRowMajor),
00224         ProcessSecondHalf = !ProcessFirstHalf
00225       };
00226       for (Index j=0; j<m_lhs.outerSize(); ++j)
00227       {
00228         LhsInnerIterator i(m_lhs,j);
00229         if (ProcessSecondHalf)
00230         {
00231           while (i && i.index()<j) ++i;
00232           if(i && i.index()==j)
00233           {
00234             dest.row(j) += i.value() * m_rhs.row(j);
00235             ++i;
00236           }
00237         }
00238         for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i)
00239         {
00240           Index a = LhsIsRowMajor ? j : i.index();
00241           Index b = LhsIsRowMajor ? i.index() : j;
00242           typename Lhs::Scalar v = i.value();
00243           dest.row(a) += (v) * m_rhs.row(b);
00244           dest.row(b) += internal::conj(v) * m_rhs.row(a);
00245         }
00246         if (ProcessFirstHalf && i && (i.index()==j))
00247           dest.row(j) += i.value() * m_rhs.row(j);
00248       }
00249     }
00250 
00251   private:
00252     SparseSelfAdjointTimeDenseProduct& operator=(const SparseSelfAdjointTimeDenseProduct&);
00253 };
00254 
00255 namespace internal {
00256 template<typename Lhs, typename Rhs, int UpLo>
00257 struct traits<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo> >
00258  : traits<ProductBase<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo>, Lhs, Rhs> >
00259 {};
00260 }
00261 
00262 template<typename Lhs, typename Rhs, int UpLo>
00263 class DenseTimeSparseSelfAdjointProduct
00264   : public ProductBase<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo>, Lhs, Rhs>
00265 {
00266   public:
00267     EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct)
00268 
00269     DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
00270     {}
00271 
00272     template<typename Dest> void scaleAndAddTo(Dest& /*dest*/, Scalar /*alpha*/) const
00273     {
00274       // TODO
00275     }
00276 
00277   private:
00278     DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&);
00279 };
00280 
00281 /***************************************************************************
00282 * Implementation of symmetric copies and permutations
00283 ***************************************************************************/
00284 namespace internal {
00285   
00286 template<typename MatrixType, int UpLo>
00287 struct traits<SparseSymmetricPermutationProduct<MatrixType,UpLo> > : traits<MatrixType> {
00288 };
00289 
00290 template<int UpLo,typename MatrixType,int DestOrder>
00291 void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm)
00292 {
00293   typedef typename MatrixType::Index Index;
00294   typedef typename MatrixType::Scalar Scalar;
00295   typedef SparseMatrix<Scalar,DestOrder,Index> Dest;
00296   typedef Matrix<Index,Dynamic,1> VectorI;
00297   
00298   Dest& dest(_dest.derived());
00299   enum {
00300     StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor)
00301   };
00302   
00303   Index size = mat.rows();
00304   VectorI count;
00305   count.resize(size);
00306   count.setZero();
00307   dest.resize(size,size);
00308   for(Index j = 0; j<size; ++j)
00309   {
00310     Index jp = perm ? perm[j] : j;
00311     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
00312     {
00313       Index i = it.index();
00314       Index r = it.row();
00315       Index c = it.col();
00316       Index ip = perm ? perm[i] : i;
00317       if(UpLo==(Upper|Lower))
00318         count[StorageOrderMatch ? jp : ip]++;
00319       else if(r==c)
00320         count[ip]++;
00321       else if(( UpLo==Lower && r>c) || ( UpLo==Upper && r<c))
00322       {
00323         count[ip]++;
00324         count[jp]++;
00325       }
00326     }
00327   }
00328   Index nnz = count.sum();
00329   
00330   // reserve space
00331   dest.resizeNonZeros(nnz);
00332   dest.outerIndexPtr()[0] = 0;
00333   for(Index j=0; j<size; ++j)
00334     dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
00335   for(Index j=0; j<size; ++j)
00336     count[j] = dest.outerIndexPtr()[j];
00337   
00338   // copy data
00339   for(Index j = 0; j<size; ++j)
00340   {
00341     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
00342     {
00343       Index i = it.index();
00344       Index r = it.row();
00345       Index c = it.col();
00346       
00347       Index jp = perm ? perm[j] : j;
00348       Index ip = perm ? perm[i] : i;
00349       
00350       if(UpLo==(Upper|Lower))
00351       {
00352         Index k = count[StorageOrderMatch ? jp : ip]++;
00353         dest.innerIndexPtr()[k] = StorageOrderMatch ? ip : jp;
00354         dest.valuePtr()[k] = it.value();
00355       }
00356       else if(r==c)
00357       {
00358         Index k = count[ip]++;
00359         dest.innerIndexPtr()[k] = ip;
00360         dest.valuePtr()[k] = it.value();
00361       }
00362       else if(( (UpLo&Lower)==Lower && r>c) || ( (UpLo&Upper)==Upper && r<c))
00363       {
00364         if(!StorageOrderMatch)
00365           std::swap(ip,jp);
00366         Index k = count[jp]++;
00367         dest.innerIndexPtr()[k] = ip;
00368         dest.valuePtr()[k] = it.value();
00369         k = count[ip]++;
00370         dest.innerIndexPtr()[k] = jp;
00371         dest.valuePtr()[k] = internal::conj(it.value());
00372       }
00373     }
00374   }
00375 }
00376 
00377 template<int _SrcUpLo,int _DstUpLo,typename MatrixType,int DstOrder>
00378 void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DstOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm)
00379 {
00380   typedef typename MatrixType::Index Index;
00381   typedef typename MatrixType::Scalar Scalar;
00382   SparseMatrix<Scalar,DstOrder,Index>& dest(_dest.derived());
00383   typedef Matrix<Index,Dynamic,1> VectorI;
00384   enum {
00385     SrcOrder = MatrixType::IsRowMajor ? RowMajor : ColMajor,
00386     StorageOrderMatch = int(SrcOrder) == int(DstOrder),
00387     DstUpLo = DstOrder==RowMajor ? (_DstUpLo==Upper ? Lower : Upper) : _DstUpLo,
00388     SrcUpLo = SrcOrder==RowMajor ? (_SrcUpLo==Upper ? Lower : Upper) : _SrcUpLo
00389   };
00390   
00391   Index size = mat.rows();
00392   VectorI count(size);
00393   count.setZero();
00394   dest.resize(size,size);
00395   for(Index j = 0; j<size; ++j)
00396   {
00397     Index jp = perm ? perm[j] : j;
00398     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
00399     {
00400       Index i = it.index();
00401       if((int(SrcUpLo)==int(Lower) && i<j) || (int(SrcUpLo)==int(Upper) && i>j))
00402         continue;
00403                   
00404       Index ip = perm ? perm[i] : i;
00405       count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++;
00406     }
00407   }
00408   dest.outerIndexPtr()[0] = 0;
00409   for(Index j=0; j<size; ++j)
00410     dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
00411   dest.resizeNonZeros(dest.outerIndexPtr()[size]);
00412   for(Index j=0; j<size; ++j)
00413     count[j] = dest.outerIndexPtr()[j];
00414   
00415   for(Index j = 0; j<size; ++j)
00416   {
00417     
00418     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
00419     {
00420       Index i = it.index();
00421       if((int(SrcUpLo)==int(Lower) && i<j) || (int(SrcUpLo)==int(Upper) && i>j))
00422         continue;
00423                   
00424       Index jp = perm ? perm[j] : j;
00425       Index ip = perm? perm[i] : i;
00426       
00427       Index k = count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++;
00428       dest.innerIndexPtr()[k] = int(DstUpLo)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp);
00429       
00430       if(!StorageOrderMatch) std::swap(ip,jp);
00431       if( ((int(DstUpLo)==int(Lower) && ip<jp) || (int(DstUpLo)==int(Upper) && ip>jp)))
00432         dest.valuePtr()[k] = conj(it.value());
00433       else
00434         dest.valuePtr()[k] = it.value();
00435     }
00436   }
00437 }
00438 
00439 }
00440 
00441 template<typename MatrixType,int UpLo>
00442 class SparseSymmetricPermutationProduct
00443   : public EigenBase<SparseSymmetricPermutationProduct<MatrixType,UpLo> >
00444 {
00445   public:
00446     typedef typename MatrixType::Scalar Scalar;
00447     typedef typename MatrixType::Index Index;
00448   protected:
00449     typedef PermutationMatrix<Dynamic,Dynamic,Index> Perm;
00450   public:
00451     typedef Matrix<Index,Dynamic,1> VectorI;
00452     typedef typename MatrixType::Nested MatrixTypeNested;
00453     typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
00454     
00455     SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm)
00456       : m_matrix(mat), m_perm(perm)
00457     {}
00458     
00459     inline Index rows() const { return m_matrix.rows(); }
00460     inline Index cols() const { return m_matrix.cols(); }
00461     
00462     template<typename DestScalar, int Options, typename DstIndex>
00463     void evalTo(SparseMatrix<DestScalar,Options,DstIndex>& _dest) const
00464     {
00465       internal::permute_symm_to_fullsymm<UpLo>(m_matrix,_dest,m_perm.indices().data());
00466     }
00467     
00468     template<typename DestType,unsigned int DestUpLo> void evalTo(SparseSelfAdjointView<DestType,DestUpLo>& dest) const
00469     {
00470       internal::permute_symm_to_symm<UpLo,DestUpLo>(m_matrix,dest.matrix(),m_perm.indices().data());
00471     }
00472     
00473   protected:
00474     MatrixTypeNested m_matrix;
00475     const Perm& m_perm;
00476 
00477 };
00478 
00479 } // end namespace Eigen
00480 
00481 #endif // EIGEN_SPARSE_SELFADJOINTVIEW_H