• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@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_SPARSE_SELFADJOINTVIEW_H
11 #define EIGEN_SPARSE_SELFADJOINTVIEW_H
12 
13 namespace Eigen {
14 
15 /** \ingroup SparseCore_Module
16   * \class SparseSelfAdjointView
17   *
18   * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix.
19   *
20   * \param MatrixType the type of the dense matrix storing the coefficients
21   * \param UpLo can be either \c #Lower or \c #Upper
22   *
23   * This class is an expression of a sefladjoint matrix from a triangular part of a matrix
24   * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView()
25   * and most of the time this is the only way that it is used.
26   *
27   * \sa SparseMatrixBase::selfadjointView()
28   */
29 template<typename Lhs, typename Rhs, int UpLo>
30 class SparseSelfAdjointTimeDenseProduct;
31 
32 template<typename Lhs, typename Rhs, int UpLo>
33 class DenseTimeSparseSelfAdjointProduct;
34 
35 namespace internal {
36 
37 template<typename MatrixType, unsigned int UpLo>
38 struct traits<SparseSelfAdjointView<MatrixType,UpLo> > : traits<MatrixType> {
39 };
40 
41 template<int SrcUpLo,int DstUpLo,typename MatrixType,int DestOrder>
42 void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm = 0);
43 
44 template<int UpLo,typename MatrixType,int DestOrder>
45 void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm = 0);
46 
47 }
48 
49 template<typename MatrixType, unsigned int UpLo> class SparseSelfAdjointView
50   : public EigenBase<SparseSelfAdjointView<MatrixType,UpLo> >
51 {
52   public:
53 
54     typedef typename MatrixType::Scalar Scalar;
55     typedef typename MatrixType::Index Index;
56     typedef Matrix<Index,Dynamic,1> VectorI;
57     typedef typename MatrixType::Nested MatrixTypeNested;
58     typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
59 
60     inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix)
61     {
62       eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices");
63     }
64 
65     inline Index rows() const { return m_matrix.rows(); }
66     inline Index cols() const { return m_matrix.cols(); }
67 
68     /** \internal \returns a reference to the nested matrix */
69     const _MatrixTypeNested& matrix() const { return m_matrix; }
70     _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); }
71 
72     /** \returns an expression of the matrix product between a sparse self-adjoint matrix \c *this and a sparse matrix \a rhs.
73       *
74       * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product.
75       * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product.
76       */
77     template<typename OtherDerived>
78     SparseSparseProduct<typename OtherDerived::PlainObject, OtherDerived>
79     operator*(const SparseMatrixBase<OtherDerived>& rhs) const
80     {
81       return SparseSparseProduct<typename OtherDerived::PlainObject, OtherDerived>(*this, rhs.derived());
82     }
83 
84     /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs.
85       *
86       * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product.
87       * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product.
88       */
89     template<typename OtherDerived> friend
90     SparseSparseProduct<OtherDerived, typename OtherDerived::PlainObject >
91     operator*(const SparseMatrixBase<OtherDerived>& lhs, const SparseSelfAdjointView& rhs)
92     {
93       return SparseSparseProduct<OtherDerived, typename OtherDerived::PlainObject>(lhs.derived(), rhs);
94     }
95 
96     /** Efficient sparse self-adjoint matrix times dense vector/matrix product */
97     template<typename OtherDerived>
98     SparseSelfAdjointTimeDenseProduct<MatrixType,OtherDerived,UpLo>
99     operator*(const MatrixBase<OtherDerived>& rhs) const
100     {
101       return SparseSelfAdjointTimeDenseProduct<MatrixType,OtherDerived,UpLo>(m_matrix, rhs.derived());
102     }
103 
104     /** Efficient dense vector/matrix times sparse self-adjoint matrix product */
105     template<typename OtherDerived> friend
106     DenseTimeSparseSelfAdjointProduct<OtherDerived,MatrixType,UpLo>
107     operator*(const MatrixBase<OtherDerived>& lhs, const SparseSelfAdjointView& rhs)
108     {
109       return DenseTimeSparseSelfAdjointProduct<OtherDerived,_MatrixTypeNested,UpLo>(lhs.derived(), rhs.m_matrix);
110     }
111 
112     /** Perform a symmetric rank K update of the selfadjoint matrix \c *this:
113       * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix.
114       *
115       * \returns a reference to \c *this
116       *
117       * To perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply
118       * call this function with u.adjoint().
119       */
120     template<typename DerivedU>
121     SparseSelfAdjointView& rankUpdate(const SparseMatrixBase<DerivedU>& u, const Scalar& alpha = Scalar(1));
122 
123     /** \internal triggered by sparse_matrix = SparseSelfadjointView; */
124     template<typename DestScalar,int StorageOrder> void evalTo(SparseMatrix<DestScalar,StorageOrder,Index>& _dest) const
125     {
126       internal::permute_symm_to_fullsymm<UpLo>(m_matrix, _dest);
127     }
128 
129     template<typename DestScalar> void evalTo(DynamicSparseMatrix<DestScalar,ColMajor,Index>& _dest) const
130     {
131       // TODO directly evaluate into _dest;
132       SparseMatrix<DestScalar,ColMajor,Index> tmp(_dest.rows(),_dest.cols());
133       internal::permute_symm_to_fullsymm<UpLo>(m_matrix, tmp);
134       _dest = tmp;
135     }
136 
137     /** \returns an expression of P H P^-1 */
138     SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix<Dynamic,Dynamic,Index>& perm) const
139     {
140       return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm);
141     }
142 
143     template<typename SrcMatrixType,int SrcUpLo>
144     SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct<SrcMatrixType,SrcUpLo>& permutedMatrix)
145     {
146       permutedMatrix.evalTo(*this);
147       return *this;
148     }
149 
150 
151     SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src)
152     {
153       PermutationMatrix<Dynamic> pnull;
154       return *this = src.twistedBy(pnull);
155     }
156 
157     template<typename SrcMatrixType,unsigned int SrcUpLo>
158     SparseSelfAdjointView& operator=(const SparseSelfAdjointView<SrcMatrixType,SrcUpLo>& src)
159     {
160       PermutationMatrix<Dynamic> pnull;
161       return *this = src.twistedBy(pnull);
162     }
163 
164 
165     // const SparseLLT<PlainObject, UpLo> llt() const;
166     // const SparseLDLT<PlainObject, UpLo> ldlt() const;
167 
168   protected:
169 
170     typename MatrixType::Nested m_matrix;
171     mutable VectorI m_countPerRow;
172     mutable VectorI m_countPerCol;
173 };
174 
175 /***************************************************************************
176 * Implementation of SparseMatrixBase methods
177 ***************************************************************************/
178 
179 template<typename Derived>
180 template<unsigned int UpLo>
181 const SparseSelfAdjointView<Derived, UpLo> SparseMatrixBase<Derived>::selfadjointView() const
182 {
183   return derived();
184 }
185 
186 template<typename Derived>
187 template<unsigned int UpLo>
188 SparseSelfAdjointView<Derived, UpLo> SparseMatrixBase<Derived>::selfadjointView()
189 {
190   return derived();
191 }
192 
193 /***************************************************************************
194 * Implementation of SparseSelfAdjointView methods
195 ***************************************************************************/
196 
197 template<typename MatrixType, unsigned int UpLo>
198 template<typename DerivedU>
199 SparseSelfAdjointView<MatrixType,UpLo>&
200 SparseSelfAdjointView<MatrixType,UpLo>::rankUpdate(const SparseMatrixBase<DerivedU>& u, const Scalar& alpha)
201 {
202   SparseMatrix<Scalar,MatrixType::Flags&RowMajorBit?RowMajor:ColMajor> tmp = u * u.adjoint();
203   if(alpha==Scalar(0))
204     m_matrix.const_cast_derived() = tmp.template triangularView<UpLo>();
205   else
206     m_matrix.const_cast_derived() += alpha * tmp.template triangularView<UpLo>();
207 
208   return *this;
209 }
210 
211 /***************************************************************************
212 * Implementation of sparse self-adjoint time dense matrix
213 ***************************************************************************/
214 
215 namespace internal {
216 template<typename Lhs, typename Rhs, int UpLo>
217 struct traits<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo> >
218  : traits<ProductBase<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo>, Lhs, Rhs> >
219 {
220   typedef Dense StorageKind;
221 };
222 }
223 
224 template<typename Lhs, typename Rhs, int UpLo>
225 class SparseSelfAdjointTimeDenseProduct
226   : public ProductBase<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo>, Lhs, Rhs>
227 {
228   public:
229     EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct)
230 
231     SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
232     {}
233 
234     template<typename Dest> void scaleAndAddTo(Dest& dest, const Scalar& alpha) const
235     {
236       EIGEN_ONLY_USED_FOR_DEBUG(alpha);
237       // TODO use alpha
238       eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry");
239       typedef typename internal::remove_all<Lhs>::type _Lhs;
240       typedef typename _Lhs::InnerIterator LhsInnerIterator;
241       enum {
242         LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit,
243         ProcessFirstHalf =
244                  ((UpLo&(Upper|Lower))==(Upper|Lower))
245               || ( (UpLo&Upper) && !LhsIsRowMajor)
246               || ( (UpLo&Lower) && LhsIsRowMajor),
247         ProcessSecondHalf = !ProcessFirstHalf
248       };
249       for (Index j=0; j<m_lhs.outerSize(); ++j)
250       {
251         LhsInnerIterator i(m_lhs,j);
252         if (ProcessSecondHalf)
253         {
254           while (i && i.index()<j) ++i;
255           if(i && i.index()==j)
256           {
257             dest.row(j) += i.value() * m_rhs.row(j);
258             ++i;
259           }
260         }
261         for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i)
262         {
263           Index a = LhsIsRowMajor ? j : i.index();
264           Index b = LhsIsRowMajor ? i.index() : j;
265           typename Lhs::Scalar v = i.value();
266           dest.row(a) += (v) * m_rhs.row(b);
267           dest.row(b) += numext::conj(v) * m_rhs.row(a);
268         }
269         if (ProcessFirstHalf && i && (i.index()==j))
270           dest.row(j) += i.value() * m_rhs.row(j);
271       }
272     }
273 
274   private:
275     SparseSelfAdjointTimeDenseProduct& operator=(const SparseSelfAdjointTimeDenseProduct&);
276 };
277 
278 namespace internal {
279 template<typename Lhs, typename Rhs, int UpLo>
280 struct traits<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo> >
281  : traits<ProductBase<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo>, Lhs, Rhs> >
282 {};
283 }
284 
285 template<typename Lhs, typename Rhs, int UpLo>
286 class DenseTimeSparseSelfAdjointProduct
287   : public ProductBase<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo>, Lhs, Rhs>
288 {
289   public:
290     EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct)
291 
292     DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
293     {}
294 
295     template<typename Dest> void scaleAndAddTo(Dest& /*dest*/, const Scalar& /*alpha*/) const
296     {
297       // TODO
298     }
299 
300   private:
301     DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&);
302 };
303 
304 /***************************************************************************
305 * Implementation of symmetric copies and permutations
306 ***************************************************************************/
307 namespace internal {
308 
309 template<typename MatrixType, int UpLo>
310 struct traits<SparseSymmetricPermutationProduct<MatrixType,UpLo> > : traits<MatrixType> {
311 };
312 
313 template<int UpLo,typename MatrixType,int DestOrder>
314 void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm)
315 {
316   typedef typename MatrixType::Index Index;
317   typedef typename MatrixType::Scalar Scalar;
318   typedef SparseMatrix<Scalar,DestOrder,Index> Dest;
319   typedef Matrix<Index,Dynamic,1> VectorI;
320 
321   Dest& dest(_dest.derived());
322   enum {
323     StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor)
324   };
325 
326   Index size = mat.rows();
327   VectorI count;
328   count.resize(size);
329   count.setZero();
330   dest.resize(size,size);
331   for(Index j = 0; j<size; ++j)
332   {
333     Index jp = perm ? perm[j] : j;
334     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
335     {
336       Index i = it.index();
337       Index r = it.row();
338       Index c = it.col();
339       Index ip = perm ? perm[i] : i;
340       if(UpLo==(Upper|Lower))
341         count[StorageOrderMatch ? jp : ip]++;
342       else if(r==c)
343         count[ip]++;
344       else if(( UpLo==Lower && r>c) || ( UpLo==Upper && r<c))
345       {
346         count[ip]++;
347         count[jp]++;
348       }
349     }
350   }
351   Index nnz = count.sum();
352 
353   // reserve space
354   dest.resizeNonZeros(nnz);
355   dest.outerIndexPtr()[0] = 0;
356   for(Index j=0; j<size; ++j)
357     dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
358   for(Index j=0; j<size; ++j)
359     count[j] = dest.outerIndexPtr()[j];
360 
361   // copy data
362   for(Index j = 0; j<size; ++j)
363   {
364     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
365     {
366       Index i = it.index();
367       Index r = it.row();
368       Index c = it.col();
369 
370       Index jp = perm ? perm[j] : j;
371       Index ip = perm ? perm[i] : i;
372 
373       if(UpLo==(Upper|Lower))
374       {
375         Index k = count[StorageOrderMatch ? jp : ip]++;
376         dest.innerIndexPtr()[k] = StorageOrderMatch ? ip : jp;
377         dest.valuePtr()[k] = it.value();
378       }
379       else if(r==c)
380       {
381         Index k = count[ip]++;
382         dest.innerIndexPtr()[k] = ip;
383         dest.valuePtr()[k] = it.value();
384       }
385       else if(( (UpLo&Lower)==Lower && r>c) || ( (UpLo&Upper)==Upper && r<c))
386       {
387         if(!StorageOrderMatch)
388           std::swap(ip,jp);
389         Index k = count[jp]++;
390         dest.innerIndexPtr()[k] = ip;
391         dest.valuePtr()[k] = it.value();
392         k = count[ip]++;
393         dest.innerIndexPtr()[k] = jp;
394         dest.valuePtr()[k] = numext::conj(it.value());
395       }
396     }
397   }
398 }
399 
400 template<int _SrcUpLo,int _DstUpLo,typename MatrixType,int DstOrder>
401 void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DstOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm)
402 {
403   typedef typename MatrixType::Index Index;
404   typedef typename MatrixType::Scalar Scalar;
405   SparseMatrix<Scalar,DstOrder,Index>& dest(_dest.derived());
406   typedef Matrix<Index,Dynamic,1> VectorI;
407   enum {
408     SrcOrder = MatrixType::IsRowMajor ? RowMajor : ColMajor,
409     StorageOrderMatch = int(SrcOrder) == int(DstOrder),
410     DstUpLo = DstOrder==RowMajor ? (_DstUpLo==Upper ? Lower : Upper) : _DstUpLo,
411     SrcUpLo = SrcOrder==RowMajor ? (_SrcUpLo==Upper ? Lower : Upper) : _SrcUpLo
412   };
413 
414   Index size = mat.rows();
415   VectorI count(size);
416   count.setZero();
417   dest.resize(size,size);
418   for(Index j = 0; j<size; ++j)
419   {
420     Index jp = perm ? perm[j] : j;
421     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
422     {
423       Index i = it.index();
424       if((int(SrcUpLo)==int(Lower) && i<j) || (int(SrcUpLo)==int(Upper) && i>j))
425         continue;
426 
427       Index ip = perm ? perm[i] : i;
428       count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++;
429     }
430   }
431   dest.outerIndexPtr()[0] = 0;
432   for(Index j=0; j<size; ++j)
433     dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
434   dest.resizeNonZeros(dest.outerIndexPtr()[size]);
435   for(Index j=0; j<size; ++j)
436     count[j] = dest.outerIndexPtr()[j];
437 
438   for(Index j = 0; j<size; ++j)
439   {
440 
441     for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
442     {
443       Index i = it.index();
444       if((int(SrcUpLo)==int(Lower) && i<j) || (int(SrcUpLo)==int(Upper) && i>j))
445         continue;
446 
447       Index jp = perm ? perm[j] : j;
448       Index ip = perm? perm[i] : i;
449 
450       Index k = count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++;
451       dest.innerIndexPtr()[k] = int(DstUpLo)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp);
452 
453       if(!StorageOrderMatch) std::swap(ip,jp);
454       if( ((int(DstUpLo)==int(Lower) && ip<jp) || (int(DstUpLo)==int(Upper) && ip>jp)))
455         dest.valuePtr()[k] = numext::conj(it.value());
456       else
457         dest.valuePtr()[k] = it.value();
458     }
459   }
460 }
461 
462 }
463 
464 template<typename MatrixType,int UpLo>
465 class SparseSymmetricPermutationProduct
466   : public EigenBase<SparseSymmetricPermutationProduct<MatrixType,UpLo> >
467 {
468   public:
469     typedef typename MatrixType::Scalar Scalar;
470     typedef typename MatrixType::Index Index;
471   protected:
472     typedef PermutationMatrix<Dynamic,Dynamic,Index> Perm;
473   public:
474     typedef Matrix<Index,Dynamic,1> VectorI;
475     typedef typename MatrixType::Nested MatrixTypeNested;
476     typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
477 
478     SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm)
479       : m_matrix(mat), m_perm(perm)
480     {}
481 
482     inline Index rows() const { return m_matrix.rows(); }
483     inline Index cols() const { return m_matrix.cols(); }
484 
485     template<typename DestScalar, int Options, typename DstIndex>
486     void evalTo(SparseMatrix<DestScalar,Options,DstIndex>& _dest) const
487     {
488 //       internal::permute_symm_to_fullsymm<UpLo>(m_matrix,_dest,m_perm.indices().data());
489       SparseMatrix<DestScalar,(Options&RowMajor)==RowMajor ? ColMajor : RowMajor, DstIndex> tmp;
490       internal::permute_symm_to_fullsymm<UpLo>(m_matrix,tmp,m_perm.indices().data());
491       _dest = tmp;
492     }
493 
494     template<typename DestType,unsigned int DestUpLo> void evalTo(SparseSelfAdjointView<DestType,DestUpLo>& dest) const
495     {
496       internal::permute_symm_to_symm<UpLo,DestUpLo>(m_matrix,dest.matrix(),m_perm.indices().data());
497     }
498 
499   protected:
500     MatrixTypeNested m_matrix;
501     const Perm& m_perm;
502 
503 };
504 
505 } // end namespace Eigen
506 
507 #endif // EIGEN_SPARSE_SELFADJOINTVIEW_H
508