SparseSelfAdjointView.h 25.1 KB
Newer Older
LM's avatar
LM committed
1 2 3
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
4
// Copyright (C) 2009-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
LM's avatar
LM committed
5
//
Don Gagne's avatar
Don Gagne committed
6 7 8
// 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/.
LM's avatar
LM committed
9 10 11 12

#ifndef EIGEN_SPARSE_SELFADJOINTVIEW_H
#define EIGEN_SPARSE_SELFADJOINTVIEW_H

Don Gagne's avatar
Don Gagne committed
13
namespace Eigen { 
14
  
Don Gagne's avatar
Don Gagne committed
15 16
/** \ingroup SparseCore_Module
  * \class SparseSelfAdjointView
LM's avatar
LM committed
17 18 19 20
  *
  * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix.
  *
  * \param MatrixType the type of the dense matrix storing the coefficients
21
  * \param Mode can be either \c #Lower or \c #Upper
LM's avatar
LM committed
22 23 24 25 26 27 28 29 30
  *
  * This class is an expression of a sefladjoint matrix from a triangular part of a matrix
  * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView()
  * and most of the time this is the only way that it is used.
  *
  * \sa SparseMatrixBase::selfadjointView()
  */
namespace internal {
  
31 32
template<typename MatrixType, unsigned int Mode>
struct traits<SparseSelfAdjointView<MatrixType,Mode> > : traits<MatrixType> {
LM's avatar
LM committed
33 34
};

35 36
template<int SrcMode,int DstMode,typename MatrixType,int DestOrder>
void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::StorageIndex>& _dest, const typename MatrixType::StorageIndex* perm = 0);
LM's avatar
LM committed
37

38 39
template<int Mode,typename MatrixType,int DestOrder>
void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::StorageIndex>& _dest, const typename MatrixType::StorageIndex* perm = 0);
LM's avatar
LM committed
40 41 42

}

43 44
template<typename MatrixType, unsigned int _Mode> class SparseSelfAdjointView
  : public EigenBase<SparseSelfAdjointView<MatrixType,_Mode> >
LM's avatar
LM committed
45 46
{
  public:
47 48 49 50 51 52 53 54 55
    
    enum {
      Mode = _Mode,
      TransposeMode = ((Mode & Upper) ? Lower : 0) | ((Mode & Lower) ? Upper : 0),
      RowsAtCompileTime = internal::traits<SparseSelfAdjointView>::RowsAtCompileTime,
      ColsAtCompileTime = internal::traits<SparseSelfAdjointView>::ColsAtCompileTime
    };

    typedef EigenBase<SparseSelfAdjointView> Base;
LM's avatar
LM committed
56
    typedef typename MatrixType::Scalar Scalar;
57 58 59
    typedef typename MatrixType::StorageIndex StorageIndex;
    typedef Matrix<StorageIndex,Dynamic,1> VectorI;
    typedef typename internal::ref_selector<MatrixType>::non_const_type MatrixTypeNested;
LM's avatar
LM committed
60
    typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
61 62
    
    explicit inline SparseSelfAdjointView(MatrixType& matrix) : m_matrix(matrix)
LM's avatar
LM committed
63 64 65 66 67 68 69 70 71
    {
      eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices");
    }

    inline Index rows() const { return m_matrix.rows(); }
    inline Index cols() const { return m_matrix.cols(); }

    /** \internal \returns a reference to the nested matrix */
    const _MatrixTypeNested& matrix() const { return m_matrix; }
72
    typename internal::remove_reference<MatrixTypeNested>::type& matrix() { return m_matrix; }
LM's avatar
LM committed
73

Don Gagne's avatar
Don Gagne committed
74 75 76 77 78 79
    /** \returns an expression of the matrix product between a sparse self-adjoint matrix \c *this and a sparse matrix \a rhs.
      *
      * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product.
      * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product.
      */
    template<typename OtherDerived>
80
    Product<SparseSelfAdjointView, OtherDerived>
Don Gagne's avatar
Don Gagne committed
81 82
    operator*(const SparseMatrixBase<OtherDerived>& rhs) const
    {
83
      return Product<SparseSelfAdjointView, OtherDerived>(*this, rhs.derived());
Don Gagne's avatar
Don Gagne committed
84 85 86 87 88 89 90 91
    }

    /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs.
      *
      * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product.
      * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product.
      */
    template<typename OtherDerived> friend
92
    Product<OtherDerived, SparseSelfAdjointView>
Don Gagne's avatar
Don Gagne committed
93 94
    operator*(const SparseMatrixBase<OtherDerived>& lhs, const SparseSelfAdjointView& rhs)
    {
95
      return Product<OtherDerived, SparseSelfAdjointView>(lhs.derived(), rhs);
Don Gagne's avatar
Don Gagne committed
96 97
    }
    
LM's avatar
LM committed
98 99
    /** Efficient sparse self-adjoint matrix times dense vector/matrix product */
    template<typename OtherDerived>
100
    Product<SparseSelfAdjointView,OtherDerived>
LM's avatar
LM committed
101 102
    operator*(const MatrixBase<OtherDerived>& rhs) const
    {
103
      return Product<SparseSelfAdjointView,OtherDerived>(*this, rhs.derived());
LM's avatar
LM committed
104 105 106 107
    }

    /** Efficient dense vector/matrix times sparse self-adjoint matrix product */
    template<typename OtherDerived> friend
108
    Product<OtherDerived,SparseSelfAdjointView>
LM's avatar
LM committed
109 110
    operator*(const MatrixBase<OtherDerived>& lhs, const SparseSelfAdjointView& rhs)
    {
111
      return Product<OtherDerived,SparseSelfAdjointView>(lhs.derived(), rhs);
LM's avatar
LM committed
112 113 114 115 116 117 118 119 120 121 122
    }

    /** Perform a symmetric rank K update of the selfadjoint matrix \c *this:
      * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix.
      *
      * \returns a reference to \c *this
      *
      * To perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply
      * call this function with u.adjoint().
      */
    template<typename DerivedU>
Don Gagne's avatar
Don Gagne committed
123
    SparseSelfAdjointView& rankUpdate(const SparseMatrixBase<DerivedU>& u, const Scalar& alpha = Scalar(1));
LM's avatar
LM committed
124
    
Don Gagne's avatar
Don Gagne committed
125
    /** \returns an expression of P H P^-1 */
126 127
    // TODO implement twists in a more evaluator friendly fashion
    SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode> twistedBy(const PermutationMatrix<Dynamic,Dynamic,StorageIndex>& perm) const
LM's avatar
LM committed
128
    {
129
      return SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode>(m_matrix, perm);
LM's avatar
LM committed
130
    }
131 132 133

    template<typename SrcMatrixType,int SrcMode>
    SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct<SrcMatrixType,SrcMode>& permutedMatrix)
LM's avatar
LM committed
134
    {
135
      internal::call_assignment_no_alias_no_transpose(*this, permutedMatrix);
LM's avatar
LM committed
136 137
      return *this;
    }
Don Gagne's avatar
Don Gagne committed
138 139 140

    SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src)
    {
141
      PermutationMatrix<Dynamic,Dynamic,StorageIndex> pnull;
Don Gagne's avatar
Don Gagne committed
142 143 144
      return *this = src.twistedBy(pnull);
    }

145 146
    template<typename SrcMatrixType,unsigned int SrcMode>
    SparseSelfAdjointView& operator=(const SparseSelfAdjointView<SrcMatrixType,SrcMode>& src)
Don Gagne's avatar
Don Gagne committed
147
    {
148
      PermutationMatrix<Dynamic,Dynamic,StorageIndex> pnull;
Don Gagne's avatar
Don Gagne committed
149 150
      return *this = src.twistedBy(pnull);
    }
LM's avatar
LM committed
151
    
152 153 154 155 156 157 158 159
    void resize(Index rows, Index cols)
    {
      EIGEN_ONLY_USED_FOR_DEBUG(rows);
      EIGEN_ONLY_USED_FOR_DEBUG(cols);
      eigen_assert(rows == this->rows() && cols == this->cols()
                && "SparseSelfadjointView::resize() does not actually allow to resize.");
    }
    
LM's avatar
LM committed
160 161
  protected:

162 163 164 165 166
    MatrixTypeNested m_matrix;
    //mutable VectorI m_countPerRow;
    //mutable VectorI m_countPerCol;
  private:
    template<typename Dest> void evalTo(Dest &) const;
LM's avatar
LM committed
167 168 169 170 171 172 173 174
};

/***************************************************************************
* Implementation of SparseMatrixBase methods
***************************************************************************/

template<typename Derived>
template<unsigned int UpLo>
175
typename SparseMatrixBase<Derived>::template ConstSelfAdjointViewReturnType<UpLo>::Type SparseMatrixBase<Derived>::selfadjointView() const
LM's avatar
LM committed
176
{
177
  return SparseSelfAdjointView<const Derived, UpLo>(derived());
LM's avatar
LM committed
178 179 180 181
}

template<typename Derived>
template<unsigned int UpLo>
182
typename SparseMatrixBase<Derived>::template SelfAdjointViewReturnType<UpLo>::Type SparseMatrixBase<Derived>::selfadjointView()
LM's avatar
LM committed
183
{
184
  return SparseSelfAdjointView<Derived, UpLo>(derived());
LM's avatar
LM committed
185 186 187 188 189 190
}

/***************************************************************************
* Implementation of SparseSelfAdjointView methods
***************************************************************************/

191
template<typename MatrixType, unsigned int Mode>
LM's avatar
LM committed
192
template<typename DerivedU>
193 194
SparseSelfAdjointView<MatrixType,Mode>&
SparseSelfAdjointView<MatrixType,Mode>::rankUpdate(const SparseMatrixBase<DerivedU>& u, const Scalar& alpha)
LM's avatar
LM committed
195
{
196
  SparseMatrix<Scalar,(MatrixType::Flags&RowMajorBit)?RowMajor:ColMajor> tmp = u * u.adjoint();
LM's avatar
LM committed
197
  if(alpha==Scalar(0))
198
    m_matrix = tmp.template triangularView<Mode>();
LM's avatar
LM committed
199
  else
200
    m_matrix += alpha * tmp.template triangularView<Mode>();
LM's avatar
LM committed
201 202 203 204

  return *this;
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
namespace internal {
  
// TODO currently a selfadjoint expression has the form SelfAdjointView<.,.>
//      in the future selfadjoint-ness should be defined by the expression traits
//      such that Transpose<SelfAdjointView<.,.> > is valid. (currently TriangularBase::transpose() is overloaded to make it work)
template<typename MatrixType, unsigned int Mode>
struct evaluator_traits<SparseSelfAdjointView<MatrixType,Mode> >
{
  typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
  typedef SparseSelfAdjointShape Shape;
};

struct SparseSelfAdjoint2Sparse {};

template<> struct AssignmentKind<SparseShape,SparseSelfAdjointShape> { typedef SparseSelfAdjoint2Sparse Kind; };
template<> struct AssignmentKind<SparseSelfAdjointShape,SparseShape> { typedef Sparse2Sparse Kind; };

template< typename DstXprType, typename SrcXprType, typename Functor>
struct Assignment<DstXprType, SrcXprType, Functor, SparseSelfAdjoint2Sparse>
{
  typedef typename DstXprType::StorageIndex StorageIndex;
  typedef internal::assign_op<typename DstXprType::Scalar,typename SrcXprType::Scalar> AssignOpType;

  template<typename DestScalar,int StorageOrder>
  static void run(SparseMatrix<DestScalar,StorageOrder,StorageIndex> &dst, const SrcXprType &src, const AssignOpType&/*func*/)
  {
    internal::permute_symm_to_fullsymm<SrcXprType::Mode>(src.matrix(), dst);
  }

  // FIXME: the handling of += and -= in sparse matrices should be cleanup so that next two overloads could be reduced to:
  template<typename DestScalar,int StorageOrder,typename AssignFunc>
  static void run(SparseMatrix<DestScalar,StorageOrder,StorageIndex> &dst, const SrcXprType &src, const AssignFunc& func)
  {
    SparseMatrix<DestScalar,StorageOrder,StorageIndex> tmp(src.rows(),src.cols());
    run(tmp, src, AssignOpType());
    call_assignment_no_alias_no_transpose(dst, tmp, func);
  }

  template<typename DestScalar,int StorageOrder>
  static void run(SparseMatrix<DestScalar,StorageOrder,StorageIndex> &dst, const SrcXprType &src,
                  const internal::add_assign_op<typename DstXprType::Scalar,typename SrcXprType::Scalar>& /* func */)
  {
    SparseMatrix<DestScalar,StorageOrder,StorageIndex> tmp(src.rows(),src.cols());
    run(tmp, src, AssignOpType());
    dst += tmp;
  }

  template<typename DestScalar,int StorageOrder>
  static void run(SparseMatrix<DestScalar,StorageOrder,StorageIndex> &dst, const SrcXprType &src,
                  const internal::sub_assign_op<typename DstXprType::Scalar,typename SrcXprType::Scalar>& /* func */)
  {
    SparseMatrix<DestScalar,StorageOrder,StorageIndex> tmp(src.rows(),src.cols());
    run(tmp, src, AssignOpType());
    dst -= tmp;
  }
  
  template<typename DestScalar>
  static void run(DynamicSparseMatrix<DestScalar,ColMajor,StorageIndex>& dst, const SrcXprType &src, const AssignOpType&/*func*/)
  {
    // TODO directly evaluate into dst;
    SparseMatrix<DestScalar,ColMajor,StorageIndex> tmp(dst.rows(),dst.cols());
    internal::permute_symm_to_fullsymm<SrcXprType::Mode>(src.matrix(), tmp);
    dst = tmp;
  }
};

} // end namespace internal

LM's avatar
LM committed
273 274 275 276 277 278
/***************************************************************************
* Implementation of sparse self-adjoint time dense matrix
***************************************************************************/

namespace internal {

279 280
template<int Mode, typename SparseLhsType, typename DenseRhsType, typename DenseResType, typename AlphaType>
inline void sparse_selfadjoint_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha)
LM's avatar
LM committed
281
{
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  EIGEN_ONLY_USED_FOR_DEBUG(alpha);
  
  typedef typename internal::nested_eval<SparseLhsType,DenseRhsType::MaxColsAtCompileTime>::type SparseLhsTypeNested;
  typedef typename internal::remove_all<SparseLhsTypeNested>::type SparseLhsTypeNestedCleaned;
  typedef evaluator<SparseLhsTypeNestedCleaned> LhsEval;
  typedef typename LhsEval::InnerIterator LhsIterator;
  typedef typename SparseLhsType::Scalar LhsScalar;
  
  enum {
    LhsIsRowMajor = (LhsEval::Flags&RowMajorBit)==RowMajorBit,
    ProcessFirstHalf =
              ((Mode&(Upper|Lower))==(Upper|Lower))
          || ( (Mode&Upper) && !LhsIsRowMajor)
          || ( (Mode&Lower) && LhsIsRowMajor),
    ProcessSecondHalf = !ProcessFirstHalf
  };
  
  SparseLhsTypeNested lhs_nested(lhs);
  LhsEval lhsEval(lhs_nested);
LM's avatar
LM committed
301

302 303 304 305
  // work on one column at once
  for (Index k=0; k<rhs.cols(); ++k)
  {
    for (Index j=0; j<lhs.outerSize(); ++j)
LM's avatar
LM committed
306
    {
307 308 309
      LhsIterator i(lhsEval,j);
      // handle diagonal coeff
      if (ProcessSecondHalf)
LM's avatar
LM committed
310
      {
311 312
        while (i && i.index()<j) ++i;
        if(i && i.index()==j)
LM's avatar
LM committed
313
        {
314 315
          res.coeffRef(j,k) += alpha * i.value() * rhs.coeff(j,k);
          ++i;
LM's avatar
LM committed
316 317
        }
      }
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334

      // premultiplied rhs for scatters
      typename ScalarBinaryOpTraits<AlphaType, typename DenseRhsType::Scalar>::ReturnType rhs_j(alpha*rhs(j,k));
      // accumulator for partial scalar product
      typename DenseResType::Scalar res_j(0);
      for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i)
      {
        LhsScalar lhs_ij = i.value();
        if(!LhsIsRowMajor) lhs_ij = numext::conj(lhs_ij);
        res_j += lhs_ij * rhs.coeff(i.index(),k);
        res(i.index(),k) += numext::conj(lhs_ij) * rhs_j;
      }
      res.coeffRef(j,k) += alpha * res_j;

      // handle diagonal coeff
      if (ProcessFirstHalf && i && (i.index()==j))
        res.coeffRef(j,k) += alpha * i.value() * rhs.coeff(j,k);
LM's avatar
LM committed
335
    }
336 337
  }
}
LM's avatar
LM committed
338

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354

template<typename LhsView, typename Rhs, int ProductType>
struct generic_product_impl<LhsView, Rhs, SparseSelfAdjointShape, DenseShape, ProductType>
: generic_product_impl_base<LhsView, Rhs, generic_product_impl<LhsView, Rhs, SparseSelfAdjointShape, DenseShape, ProductType> >
{
  template<typename Dest>
  static void scaleAndAddTo(Dest& dst, const LhsView& lhsView, const Rhs& rhs, const typename Dest::Scalar& alpha)
  {
    typedef typename LhsView::_MatrixTypeNested Lhs;
    typedef typename nested_eval<Lhs,Dynamic>::type LhsNested;
    typedef typename nested_eval<Rhs,Dynamic>::type RhsNested;
    LhsNested lhsNested(lhsView.matrix());
    RhsNested rhsNested(rhs);
    
    internal::sparse_selfadjoint_time_dense_product<LhsView::Mode>(lhsNested, rhsNested, dst, alpha);
  }
LM's avatar
LM committed
355 356
};

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
template<typename Lhs, typename RhsView, int ProductType>
struct generic_product_impl<Lhs, RhsView, DenseShape, SparseSelfAdjointShape, ProductType>
: generic_product_impl_base<Lhs, RhsView, generic_product_impl<Lhs, RhsView, DenseShape, SparseSelfAdjointShape, ProductType> >
{
  template<typename Dest>
  static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const RhsView& rhsView, const typename Dest::Scalar& alpha)
  {
    typedef typename RhsView::_MatrixTypeNested Rhs;
    typedef typename nested_eval<Lhs,Dynamic>::type LhsNested;
    typedef typename nested_eval<Rhs,Dynamic>::type RhsNested;
    LhsNested lhsNested(lhs);
    RhsNested rhsNested(rhsView.matrix());
    
    // transpose everything
    Transpose<Dest> dstT(dst);
    internal::sparse_selfadjoint_time_dense_product<RhsView::TransposeMode>(rhsNested.transpose(), lhsNested.transpose(), dstT, alpha);
  }
};
LM's avatar
LM committed
375

376 377 378 379 380 381
// NOTE: these two overloads are needed to evaluate the sparse selfadjoint view into a full sparse matrix
// TODO: maybe the copy could be handled by generic_product_impl so that these overloads would not be needed anymore

template<typename LhsView, typename Rhs, int ProductTag>
struct product_evaluator<Product<LhsView, Rhs, DefaultProduct>, ProductTag, SparseSelfAdjointShape, SparseShape>
  : public evaluator<typename Product<typename Rhs::PlainObject, Rhs, DefaultProduct>::PlainObject>
LM's avatar
LM committed
382
{
383 384 385
  typedef Product<LhsView, Rhs, DefaultProduct> XprType;
  typedef typename XprType::PlainObject PlainObject;
  typedef evaluator<PlainObject> Base;
LM's avatar
LM committed
386

387 388 389 390 391 392 393 394 395 396 397
  product_evaluator(const XprType& xpr)
    : m_lhs(xpr.lhs()), m_result(xpr.rows(), xpr.cols())
  {
    ::new (static_cast<Base*>(this)) Base(m_result);
    generic_product_impl<typename Rhs::PlainObject, Rhs, SparseShape, SparseShape, ProductTag>::evalTo(m_result, m_lhs, xpr.rhs());
  }
  
protected:
  typename Rhs::PlainObject m_lhs;
  PlainObject m_result;
};
LM's avatar
LM committed
398

399 400 401 402 403 404 405
template<typename Lhs, typename RhsView, int ProductTag>
struct product_evaluator<Product<Lhs, RhsView, DefaultProduct>, ProductTag, SparseShape, SparseSelfAdjointShape>
  : public evaluator<typename Product<Lhs, typename Lhs::PlainObject, DefaultProduct>::PlainObject>
{
  typedef Product<Lhs, RhsView, DefaultProduct> XprType;
  typedef typename XprType::PlainObject PlainObject;
  typedef evaluator<PlainObject> Base;
LM's avatar
LM committed
406

407 408 409 410 411 412 413 414 415 416
  product_evaluator(const XprType& xpr)
    : m_rhs(xpr.rhs()), m_result(xpr.rows(), xpr.cols())
  {
    ::new (static_cast<Base*>(this)) Base(m_result);
    generic_product_impl<Lhs, typename Lhs::PlainObject, SparseShape, SparseShape, ProductTag>::evalTo(m_result, xpr.lhs(), m_rhs);
  }
  
protected:
  typename Lhs::PlainObject m_rhs;
  PlainObject m_result;
LM's avatar
LM committed
417 418
};

419 420
} // namespace internal

LM's avatar
LM committed
421 422 423 424 425
/***************************************************************************
* Implementation of symmetric copies and permutations
***************************************************************************/
namespace internal {

426 427
template<int Mode,typename MatrixType,int DestOrder>
void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::StorageIndex>& _dest, const typename MatrixType::StorageIndex* perm)
LM's avatar
LM committed
428
{
429
  typedef typename MatrixType::StorageIndex StorageIndex;
LM's avatar
LM committed
430
  typedef typename MatrixType::Scalar Scalar;
431 432 433 434
  typedef SparseMatrix<Scalar,DestOrder,StorageIndex> Dest;
  typedef Matrix<StorageIndex,Dynamic,1> VectorI;
  typedef evaluator<MatrixType> MatEval;
  typedef typename evaluator<MatrixType>::InnerIterator MatIterator;
LM's avatar
LM committed
435
  
436
  MatEval matEval(mat);
LM's avatar
LM committed
437 438 439 440
  Dest& dest(_dest.derived());
  enum {
    StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor)
  };
Don Gagne's avatar
Don Gagne committed
441
  
LM's avatar
LM committed
442 443 444 445 446 447 448 449
  Index size = mat.rows();
  VectorI count;
  count.resize(size);
  count.setZero();
  dest.resize(size,size);
  for(Index j = 0; j<size; ++j)
  {
    Index jp = perm ? perm[j] : j;
450
    for(MatIterator it(matEval,j); it; ++it)
LM's avatar
LM committed
451 452
    {
      Index i = it.index();
Don Gagne's avatar
Don Gagne committed
453 454
      Index r = it.row();
      Index c = it.col();
LM's avatar
LM committed
455
      Index ip = perm ? perm[i] : i;
456
      if(Mode==(Upper|Lower))
Don Gagne's avatar
Don Gagne committed
457 458
        count[StorageOrderMatch ? jp : ip]++;
      else if(r==c)
LM's avatar
LM committed
459
        count[ip]++;
460
      else if(( Mode==Lower && r>c) || ( Mode==Upper && r<c))
LM's avatar
LM committed
461 462 463 464 465 466 467 468 469
      {
        count[ip]++;
        count[jp]++;
      }
    }
  }
  Index nnz = count.sum();
  
  // reserve space
Don Gagne's avatar
Don Gagne committed
470 471
  dest.resizeNonZeros(nnz);
  dest.outerIndexPtr()[0] = 0;
LM's avatar
LM committed
472
  for(Index j=0; j<size; ++j)
Don Gagne's avatar
Don Gagne committed
473
    dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
LM's avatar
LM committed
474
  for(Index j=0; j<size; ++j)
Don Gagne's avatar
Don Gagne committed
475
    count[j] = dest.outerIndexPtr()[j];
LM's avatar
LM committed
476 477
  
  // copy data
478
  for(StorageIndex j = 0; j<size; ++j)
LM's avatar
LM committed
479
  {
480
    for(MatIterator it(matEval,j); it; ++it)
LM's avatar
LM committed
481
    {
482
      StorageIndex i = internal::convert_index<StorageIndex>(it.index());
Don Gagne's avatar
Don Gagne committed
483 484 485
      Index r = it.row();
      Index c = it.col();
      
486 487
      StorageIndex jp = perm ? perm[j] : j;
      StorageIndex ip = perm ? perm[i] : i;
Don Gagne's avatar
Don Gagne committed
488
      
489
      if(Mode==(Upper|Lower))
LM's avatar
LM committed
490
      {
Don Gagne's avatar
Don Gagne committed
491 492 493
        Index k = count[StorageOrderMatch ? jp : ip]++;
        dest.innerIndexPtr()[k] = StorageOrderMatch ? ip : jp;
        dest.valuePtr()[k] = it.value();
LM's avatar
LM committed
494
      }
Don Gagne's avatar
Don Gagne committed
495
      else if(r==c)
LM's avatar
LM committed
496
      {
Don Gagne's avatar
Don Gagne committed
497 498 499 500
        Index k = count[ip]++;
        dest.innerIndexPtr()[k] = ip;
        dest.valuePtr()[k] = it.value();
      }
501
      else if(( (Mode&Lower)==Lower && r>c) || ( (Mode&Upper)==Upper && r<c))
Don Gagne's avatar
Don Gagne committed
502 503 504 505 506 507
      {
        if(!StorageOrderMatch)
          std::swap(ip,jp);
        Index k = count[jp]++;
        dest.innerIndexPtr()[k] = ip;
        dest.valuePtr()[k] = it.value();
LM's avatar
LM committed
508
        k = count[ip]++;
Don Gagne's avatar
Don Gagne committed
509 510
        dest.innerIndexPtr()[k] = jp;
        dest.valuePtr()[k] = numext::conj(it.value());
LM's avatar
LM committed
511 512 513 514 515
      }
    }
  }
}

516 517
template<int _SrcMode,int _DstMode,typename MatrixType,int DstOrder>
void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DstOrder,typename MatrixType::StorageIndex>& _dest, const typename MatrixType::StorageIndex* perm)
LM's avatar
LM committed
518
{
519
  typedef typename MatrixType::StorageIndex StorageIndex;
LM's avatar
LM committed
520
  typedef typename MatrixType::Scalar Scalar;
521 522 523 524 525
  SparseMatrix<Scalar,DstOrder,StorageIndex>& dest(_dest.derived());
  typedef Matrix<StorageIndex,Dynamic,1> VectorI;
  typedef evaluator<MatrixType> MatEval;
  typedef typename evaluator<MatrixType>::InnerIterator MatIterator;

Don Gagne's avatar
Don Gagne committed
526 527 528
  enum {
    SrcOrder = MatrixType::IsRowMajor ? RowMajor : ColMajor,
    StorageOrderMatch = int(SrcOrder) == int(DstOrder),
529 530
    DstMode = DstOrder==RowMajor ? (_DstMode==Upper ? Lower : Upper) : _DstMode,
    SrcMode = SrcOrder==RowMajor ? (_SrcMode==Upper ? Lower : Upper) : _SrcMode
Don Gagne's avatar
Don Gagne committed
531
  };
532 533

  MatEval matEval(mat);
LM's avatar
LM committed
534 535 536 537 538
  
  Index size = mat.rows();
  VectorI count(size);
  count.setZero();
  dest.resize(size,size);
539
  for(StorageIndex j = 0; j<size; ++j)
LM's avatar
LM committed
540
  {
541 542
    StorageIndex jp = perm ? perm[j] : j;
    for(MatIterator it(matEval,j); it; ++it)
LM's avatar
LM committed
543
    {
544 545
      StorageIndex i = it.index();
      if((int(SrcMode)==int(Lower) && i<j) || (int(SrcMode)==int(Upper) && i>j))
LM's avatar
LM committed
546 547
        continue;
                  
548 549
      StorageIndex ip = perm ? perm[i] : i;
      count[int(DstMode)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++;
LM's avatar
LM committed
550 551
    }
  }
Don Gagne's avatar
Don Gagne committed
552
  dest.outerIndexPtr()[0] = 0;
LM's avatar
LM committed
553
  for(Index j=0; j<size; ++j)
Don Gagne's avatar
Don Gagne committed
554 555
    dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
  dest.resizeNonZeros(dest.outerIndexPtr()[size]);
LM's avatar
LM committed
556
  for(Index j=0; j<size; ++j)
Don Gagne's avatar
Don Gagne committed
557
    count[j] = dest.outerIndexPtr()[j];
LM's avatar
LM committed
558
  
559
  for(StorageIndex j = 0; j<size; ++j)
LM's avatar
LM committed
560
  {
Don Gagne's avatar
Don Gagne committed
561
    
562
    for(MatIterator it(matEval,j); it; ++it)
LM's avatar
LM committed
563
    {
564 565
      StorageIndex i = it.index();
      if((int(SrcMode)==int(Lower) && i<j) || (int(SrcMode)==int(Upper) && i>j))
LM's avatar
LM committed
566 567
        continue;
                  
568 569
      StorageIndex jp = perm ? perm[j] : j;
      StorageIndex ip = perm? perm[i] : i;
LM's avatar
LM committed
570
      
571 572
      Index k = count[int(DstMode)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++;
      dest.innerIndexPtr()[k] = int(DstMode)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp);
Don Gagne's avatar
Don Gagne committed
573 574
      
      if(!StorageOrderMatch) std::swap(ip,jp);
575
      if( ((int(DstMode)==int(Lower) && ip<jp) || (int(DstMode)==int(Upper) && ip>jp)))
Don Gagne's avatar
Don Gagne committed
576
        dest.valuePtr()[k] = numext::conj(it.value());
LM's avatar
LM committed
577
      else
Don Gagne's avatar
Don Gagne committed
578
        dest.valuePtr()[k] = it.value();
LM's avatar
LM committed
579 580 581 582 583 584
    }
  }
}

}

585 586 587 588 589 590 591 592 593 594 595
// TODO implement twists in a more evaluator friendly fashion

namespace internal {

template<typename MatrixType, int Mode>
struct traits<SparseSymmetricPermutationProduct<MatrixType,Mode> > : traits<MatrixType> {
};

}

template<typename MatrixType,int Mode>
LM's avatar
LM committed
596
class SparseSymmetricPermutationProduct
597
  : public EigenBase<SparseSymmetricPermutationProduct<MatrixType,Mode> >
LM's avatar
LM committed
598 599 600
{
  public:
    typedef typename MatrixType::Scalar Scalar;
601 602 603 604 605
    typedef typename MatrixType::StorageIndex StorageIndex;
    enum {
      RowsAtCompileTime = internal::traits<SparseSymmetricPermutationProduct>::RowsAtCompileTime,
      ColsAtCompileTime = internal::traits<SparseSymmetricPermutationProduct>::ColsAtCompileTime
    };
Don Gagne's avatar
Don Gagne committed
606
  protected:
607
    typedef PermutationMatrix<Dynamic,Dynamic,StorageIndex> Perm;
Don Gagne's avatar
Don Gagne committed
608
  public:
609
    typedef Matrix<StorageIndex,Dynamic,1> VectorI;
LM's avatar
LM committed
610
    typedef typename MatrixType::Nested MatrixTypeNested;
611
    typedef typename internal::remove_all<MatrixTypeNested>::type NestedExpression;
LM's avatar
LM committed
612 613 614 615 616 617 618
    
    SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm)
      : m_matrix(mat), m_perm(perm)
    {}
    
    inline Index rows() const { return m_matrix.rows(); }
    inline Index cols() const { return m_matrix.cols(); }
619 620 621
        
    const NestedExpression& matrix() const { return m_matrix; }
    const Perm& perm() const { return m_perm; }
LM's avatar
LM committed
622 623
    
  protected:
Don Gagne's avatar
Don Gagne committed
624
    MatrixTypeNested m_matrix;
LM's avatar
LM committed
625 626 627 628
    const Perm& m_perm;

};

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
namespace internal {
  
template<typename DstXprType, typename MatrixType, int Mode, typename Scalar>
struct Assignment<DstXprType, SparseSymmetricPermutationProduct<MatrixType,Mode>, internal::assign_op<Scalar,typename MatrixType::Scalar>, Sparse2Sparse>
{
  typedef SparseSymmetricPermutationProduct<MatrixType,Mode> SrcXprType;
  typedef typename DstXprType::StorageIndex DstIndex;
  template<int Options>
  static void run(SparseMatrix<Scalar,Options,DstIndex> &dst, const SrcXprType &src, const internal::assign_op<Scalar,typename MatrixType::Scalar> &)
  {
    // internal::permute_symm_to_fullsymm<Mode>(m_matrix,_dest,m_perm.indices().data());
    SparseMatrix<Scalar,(Options&RowMajor)==RowMajor ? ColMajor : RowMajor, DstIndex> tmp;
    internal::permute_symm_to_fullsymm<Mode>(src.matrix(),tmp,src.perm().indices().data());
    dst = tmp;
  }
  
  template<typename DestType,unsigned int DestMode>
  static void run(SparseSelfAdjointView<DestType,DestMode>& dst, const SrcXprType &src, const internal::assign_op<Scalar,typename MatrixType::Scalar> &)
  {
    internal::permute_symm_to_symm<Mode,DestMode>(src.matrix(),dst.matrix(),src.perm().indices().data());
  }
};

} // end namespace internal

Don Gagne's avatar
Don Gagne committed
654 655
} // end namespace Eigen

LM's avatar
LM committed
656
#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H