Started to move the SparseCore module to evaluators: implemented assignment and cwise-unary evaluator

This commit is contained in:
Gael Guennebaud 2014-06-20 15:42:13 +02:00
parent 78bb808337
commit c415b627a7
6 changed files with 508 additions and 81 deletions

View File

@ -35,14 +35,16 @@ struct Sparse {};
#include "src/SparseCore/SparseUtil.h"
#include "src/SparseCore/SparseMatrixBase.h"
#include "src/SparseCore/SparseAssign.h"
#include "src/SparseCore/CompressedStorage.h"
#include "src/SparseCore/AmbiVector.h"
#include "src/SparseCore/SparseMatrix.h"
#include "src/SparseCore/MappedSparseMatrix.h"
#include "src/SparseCore/SparseVector.h"
#include "src/SparseCore/SparseCwiseUnaryOp.h"
#ifndef EIGEN_TEST_EVALUATORS
#include "src/SparseCore/SparseBlock.h"
#include "src/SparseCore/SparseTranspose.h"
#include "src/SparseCore/SparseCwiseUnaryOp.h"
#include "src/SparseCore/SparseCwiseBinaryOp.h"
#include "src/SparseCore/SparseDot.h"
#include "src/SparseCore/SparsePermutation.h"
@ -57,6 +59,7 @@ struct Sparse {};
#include "src/SparseCore/SparseSelfAdjointView.h"
#include "src/SparseCore/TriangularSolver.h"
#include "src/SparseCore/SparseView.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"

View File

@ -0,0 +1,252 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2014 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/.
#ifndef EIGEN_SPARSEASSIGN_H
#define EIGEN_SPARSEASSIGN_H
namespace Eigen {
#ifndef EIGEN_TEST_EVALUATORS
template<typename Derived>
template<typename OtherDerived>
Derived& SparseMatrixBase<Derived>::operator=(const EigenBase<OtherDerived> &other)
{
other.derived().evalTo(derived());
return derived();
}
template<typename Derived>
template<typename OtherDerived>
Derived& SparseMatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
{
other.evalTo(derived());
return derived();
}
template<typename Derived>
template<typename OtherDerived>
inline Derived& SparseMatrixBase<Derived>::operator=(const SparseMatrixBase<OtherDerived>& other)
{
return assign(other.derived());
}
template<typename Derived>
inline Derived& SparseMatrixBase<Derived>::operator=(const Derived& other)
{
// if (other.isRValue())
// derived().swap(other.const_cast_derived());
// else
return assign(other.derived());
}
template<typename Derived>
template<typename OtherDerived>
inline Derived& SparseMatrixBase<Derived>::assign(const OtherDerived& other)
{
const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols();
if ((!transpose) && other.isRValue())
{
// eval without temporary
derived().resize(other.rows(), other.cols());
derived().setZero();
derived().reserve((std::max)(this->rows(),this->cols())*2);
for (Index j=0; j<outerSize; ++j)
{
derived().startVec(j);
for (typename OtherDerived::InnerIterator it(other, j); it; ++it)
{
Scalar v = it.value();
derived().insertBackByOuterInner(j,it.index()) = v;
}
}
derived().finalize();
}
else
{
assignGeneric(other);
}
return derived();
}
template<typename Derived>
template<typename OtherDerived>
inline void SparseMatrixBase<Derived>::assignGeneric(const OtherDerived& other)
{
//const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
eigen_assert(( ((internal::traits<Derived>::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) ||
(!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) &&
"the transpose operation is supposed to be handled in SparseMatrix::operator=");
enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) };
const Index outerSize = other.outerSize();
//typedef typename internal::conditional<transpose, LinkedVectorMatrix<Scalar,Flags&RowMajorBit>, Derived>::type TempType;
// thanks to shallow copies, we always eval to a tempary
Derived temp(other.rows(), other.cols());
temp.reserve((std::max)(this->rows(),this->cols())*2);
for (Index j=0; j<outerSize; ++j)
{
temp.startVec(j);
for (typename OtherDerived::InnerIterator it(other.derived(), j); it; ++it)
{
Scalar v = it.value();
temp.insertBackByOuterInner(Flip?it.index():j,Flip?j:it.index()) = v;
}
}
temp.finalize();
derived() = temp.markAsRValue();
}
// template<typename Lhs, typename Rhs>
// inline Derived& operator=(const SparseSparseProduct<Lhs,Rhs>& product);
//
// template<typename OtherDerived>
// Derived& operator+=(const SparseMatrixBase<OtherDerived>& other);
// template<typename OtherDerived>
// Derived& operator-=(const SparseMatrixBase<OtherDerived>& other);
//
// Derived& operator*=(const Scalar& other);
// Derived& operator/=(const Scalar& other);
//
// template<typename OtherDerived>
// Derived& operator*=(const SparseMatrixBase<OtherDerived>& other);
#else // EIGEN_TEST_EVALUATORS
template<typename Derived>
template<typename OtherDerived>
Derived& SparseMatrixBase<Derived>::operator=(const EigenBase<OtherDerived> &other)
{
other.derived().evalTo(derived());
return derived();
}
template<typename Derived>
template<typename OtherDerived>
Derived& SparseMatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
{
other.evalTo(derived());
return derived();
}
template<typename Derived>
template<typename OtherDerived>
inline Derived& SparseMatrixBase<Derived>::operator=(const SparseMatrixBase<OtherDerived>& other)
{
internal::call_assignment_no_alias(derived(), other.derived());
return derived();
}
template<typename Derived>
inline Derived& SparseMatrixBase<Derived>::operator=(const Derived& other)
{
internal::call_assignment_no_alias(derived(), other.derived());
return derived();
}
namespace internal {
template<>
struct storage_kind_to_evaluator_kind<Sparse> {
typedef IteratorBased Kind;
};
template<>
struct storage_kind_to_shape<Sparse> {
typedef SparseShape Shape;
};
struct Sparse2Sparse {};
template<> struct AssignmentKind<SparseShape,SparseShape> { typedef Sparse2Sparse Kind; };
template<typename DstXprType, typename SrcXprType>
void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src)
{
eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
typedef typename DstXprType::Index Index;
typedef typename DstXprType::Scalar Scalar;
typedef typename internal::evaluator<DstXprType>::type DstEvaluatorType;
typedef typename internal::evaluator<SrcXprType>::type SrcEvaluatorType;
DstEvaluatorType dstEvaluator(dst);
SrcEvaluatorType srcEvaluator(src);
const bool transpose = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit);
const Index outerSize = (int(SrcEvaluatorType::Flags) & RowMajorBit) ? src.rows() : src.cols();
if ((!transpose) && src.isRValue())
{
// eval without temporary
dst.resize(src.rows(), src.cols());
dst.setZero();
dst.reserve((std::max)(src.rows(),src.cols())*2);
for (Index j=0; j<outerSize; ++j)
{
dst.startVec(j);
for (typename SrcEvaluatorType::InnerIterator it(srcEvaluator, j); it; ++it)
{
Scalar v = it.value();
dst.insertBackByOuterInner(j,it.index()) = v;
}
}
dst.finalize();
}
else
{
// eval through a temporary
eigen_assert(( ((internal::traits<DstXprType>::SupportedAccessPatterns & OuterRandomAccessPattern)==OuterRandomAccessPattern) ||
(!((DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit)))) &&
"the transpose operation is supposed to be handled in SparseMatrix::operator=");
enum { Flip = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit) };
const Index outerSize = src.outerSize();
DstXprType temp(src.rows(), src.cols());
temp.reserve((std::max)(src.rows(),src.cols())*2);
for (Index j=0; j<outerSize; ++j)
{
temp.startVec(j);
for (typename SrcEvaluatorType::InnerIterator it(src, j); it; ++it)
{
Scalar v = it.value();
temp.insertBackByOuterInner(Flip?it.index():j,Flip?j:it.index()) = v;
}
}
temp.finalize();
dst = temp.markAsRValue();
}
}
// Generic Sparse to Sparse assignment
template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar>
struct Assignment<DstXprType, SrcXprType, Functor, Sparse2Sparse, Scalar>
{
static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar> &/*func*/)
{
eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
assign_sparse_to_sparse(dst.derived(), src.derived());
}
};
} // end namespace internal
#endif // EIGEN_TEST_EVALUATORS
} // end namespace Eigen
#endif // EIGEN_SPARSEASSIGN_H

View File

@ -11,6 +11,8 @@
#define EIGEN_SPARSE_CWISE_UNARY_OP_H
namespace Eigen {
#ifndef EIGEN_TEST_EVALUATORS
template<typename UnaryOp, typename MatrixType>
class CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>
@ -18,12 +20,12 @@ class CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>
{
public:
class InnerIterator;
class ReverseInnerIterator;
typedef CwiseUnaryOp<UnaryOp, MatrixType> Derived;
EIGEN_SPARSE_PUBLIC_INTERFACE(Derived)
class InnerIterator;
class ReverseInnerIterator;
protected:
typedef typename internal::traits<Derived>::_XprTypeNested _MatrixTypeNested;
typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
@ -138,6 +140,148 @@ class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::ReverseInnerIterator
const ViewOp m_functor;
};
#else // EIGEN_TEST_EVALUATORS
namespace internal {
template<typename UnaryOp, typename ArgType>
struct unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>
: public evaluator_base<CwiseUnaryOp<UnaryOp,ArgType> >
{
public:
typedef CwiseUnaryOp<UnaryOp, ArgType> XprType;
class InnerIterator;
class ReverseInnerIterator;
enum {
CoeffReadCost = evaluator<ArgType>::CoeffReadCost + functor_traits<UnaryOp>::Cost,
Flags = XprType::Flags
};
unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {}
protected:
typedef typename evaluator<ArgType>::InnerIterator EvalIterator;
typedef typename evaluator<ArgType>::ReverseInnerIterator EvalReverseIterator;
const UnaryOp m_functor;
typename evaluator<ArgType>::nestedType m_argImpl;
};
template<typename UnaryOp, typename ArgType>
class unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>::InnerIterator
: public unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>::EvalIterator
{
typedef typename XprType::Scalar Scalar;
typedef typename unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>::EvalIterator Base;
public:
EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, typename XprType::Index outer)
: Base(unaryOp.m_argImpl,outer), m_functor(unaryOp.m_functor)
{}
EIGEN_STRONG_INLINE InnerIterator& operator++()
{ Base::operator++(); return *this; }
EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); }
protected:
const UnaryOp m_functor;
private:
Scalar& valueRef();
};
template<typename UnaryOp, typename ArgType>
class unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>::ReverseInnerIterator
: public unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>::EvalReverseIterator
{
typedef typename XprType::Scalar Scalar;
typedef typename unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>::EvalReverseIterator Base;
public:
EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer)
: Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor())
{}
EIGEN_STRONG_INLINE ReverseInnerIterator& operator--()
{ Base::operator--(); return *this; }
EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); }
protected:
const UnaryOp m_functor;
private:
Scalar& valueRef();
};
// template<typename ViewOp, typename MatrixType>
// class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>
// : public SparseMatrixBase<CwiseUnaryView<ViewOp, MatrixType> >
// {
// public:
//
// class InnerIterator;
// class ReverseInnerIterator;
//
// typedef CwiseUnaryView<ViewOp, MatrixType> Derived;
// EIGEN_SPARSE_PUBLIC_INTERFACE(Derived)
//
// protected:
// typedef typename internal::traits<Derived>::_MatrixTypeNested _MatrixTypeNested;
// typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
// typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator;
// };
//
// template<typename ViewOp, typename MatrixType>
// class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::InnerIterator
// : public CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::MatrixTypeIterator
// {
// typedef typename CwiseUnaryViewImpl::Scalar Scalar;
// typedef typename CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::MatrixTypeIterator Base;
// public:
//
// EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer)
// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor())
// {}
//
// EIGEN_STRONG_INLINE InnerIterator& operator++()
// { Base::operator++(); return *this; }
//
// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); }
// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); }
//
// protected:
// const ViewOp m_functor;
// };
//
// template<typename ViewOp, typename MatrixType>
// class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::ReverseInnerIterator
// : public CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::MatrixTypeReverseIterator
// {
// typedef typename CwiseUnaryViewImpl::Scalar Scalar;
// typedef typename CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::MatrixTypeReverseIterator Base;
// public:
//
// EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer)
// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor())
// {}
//
// EIGEN_STRONG_INLINE ReverseInnerIterator& operator--()
// { Base::operator--(); return *this; }
//
// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); }
// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); }
//
// protected:
// const ViewOp m_functor;
// };
} // end namespace internal
#endif // EIGEN_TEST_EVALUATORS
template<typename Derived>
EIGEN_STRONG_INLINE Derived&
SparseMatrixBase<Derived>::operator*=(const Scalar& other)

View File

@ -1053,6 +1053,7 @@ void SparseMatrix<Scalar,_Options,_Index>::sumupDuplicates()
m_data.resize(m_outerIndex[m_outerSize]);
}
#ifndef EIGEN_TEST_EVALUATORS
template<typename Scalar, int _Options, typename _Index>
template<typename OtherDerived>
EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_Index>& SparseMatrix<Scalar,_Options,_Index>::operator=(const SparseMatrixBase<OtherDerived>& other)
@ -1114,6 +1115,71 @@ EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_Index>& SparseMatrix<Scalar,_Opt
return Base::operator=(other.derived());
}
}
#else
template<typename Scalar, int _Options, typename _Index>
template<typename OtherDerived>
EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_Index>& SparseMatrix<Scalar,_Options,_Index>::operator=(const SparseMatrixBase<OtherDerived>& other)
{
EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename OtherDerived::Scalar>::value),
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
if (needToTranspose)
{
// two passes algorithm:
// 1 - compute the number of coeffs per dest inner vector
// 2 - do the actual copy/eval
// Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed
typedef typename internal::nested_eval<OtherDerived,2>::type OtherCopy;
typedef typename internal::remove_all<OtherCopy>::type _OtherCopy;
typedef internal::evaluator<_OtherCopy> OtherCopyEval;
OtherCopy otherCopy(other.derived());
OtherCopyEval otherCopyEval(otherCopy);
SparseMatrix dest(other.rows(),other.cols());
Eigen::Map<Matrix<Index, Dynamic, 1> > (dest.m_outerIndex,dest.outerSize()).setZero();
// pass 1
// FIXME the above copy could be merged with that pass
for (Index j=0; j<otherCopy.outerSize(); ++j)
for (typename OtherCopyEval::InnerIterator it(otherCopyEval, j); it; ++it)
++dest.m_outerIndex[it.index()];
// prefix sum
Index count = 0;
Matrix<Index,Dynamic,1> positions(dest.outerSize());
for (Index j=0; j<dest.outerSize(); ++j)
{
Index tmp = dest.m_outerIndex[j];
dest.m_outerIndex[j] = count;
positions[j] = count;
count += tmp;
}
dest.m_outerIndex[dest.outerSize()] = count;
// alloc
dest.m_data.resize(count);
// pass 2
for (Index j=0; j<otherCopy.outerSize(); ++j)
{
for (typename OtherCopyEval::InnerIterator it(otherCopyEval, j); it; ++it)
{
Index pos = positions[it.index()]++;
dest.m_data.index(pos) = j;
dest.m_data.value(pos) = it.value();
}
}
this->swap(dest);
return *this;
}
else
{
if(other.isRValue())
initAssignment(other.derived());
// there is no special optimization
return Base::operator=(other.derived());
}
}
#endif
template<typename _Scalar, int _Options, typename _Index>
EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col)
@ -1254,6 +1320,33 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse
return (m_data.value(p) = 0);
}
#ifdef EIGEN_ENABLE_EVALUATORS
namespace internal {
template<typename _Scalar, int _Options, typename _Index>
struct evaluator<SparseMatrix<_Scalar,_Options,_Index> >
: evaluator_base<SparseMatrix<_Scalar,_Options,_Index> >
{
typedef SparseMatrix<_Scalar,_Options,_Index> SparseMatrixType;
typedef typename SparseMatrixType::InnerIterator InnerIterator;
typedef typename SparseMatrixType::ReverseInnerIterator ReverseInnerIterator;
enum {
CoeffReadCost = NumTraits<_Scalar>::ReadCost,
Flags = SparseMatrixType::Flags
};
evaluator(const SparseMatrixType &mat) : m_matrix(mat) {}
operator SparseMatrixType&() { return m_matrix.const_cast_derived(); }
operator const SparseMatrixType&() const { return m_matrix; }
const SparseMatrixType &m_matrix;
};
}
#endif
} // end namespace Eigen
#endif // EIGEN_SPARSEMATRIX_H

View File

@ -39,11 +39,7 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
typedef EigenBase<Derived> Base;
template<typename OtherDerived>
Derived& operator=(const EigenBase<OtherDerived> &other)
{
other.derived().evalTo(derived());
return derived();
}
Derived& operator=(const EigenBase<OtherDerived> &other);
enum {
@ -175,87 +171,20 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
template<typename OtherDerived>
Derived& operator=(const ReturnByValue<OtherDerived>& other)
{
other.evalTo(derived());
return derived();
}
Derived& operator=(const ReturnByValue<OtherDerived>& other);
template<typename OtherDerived>
inline Derived& operator=(const SparseMatrixBase<OtherDerived>& other)
{
return assign(other.derived());
}
inline Derived& operator=(const SparseMatrixBase<OtherDerived>& other);
inline Derived& operator=(const Derived& other)
{
// if (other.isRValue())
// derived().swap(other.const_cast_derived());
// else
return assign(other.derived());
}
inline Derived& operator=(const Derived& other);
protected:
template<typename OtherDerived>
inline Derived& assign(const OtherDerived& other)
{
const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols();
if ((!transpose) && other.isRValue())
{
// eval without temporary
derived().resize(other.rows(), other.cols());
derived().setZero();
derived().reserve((std::max)(this->rows(),this->cols())*2);
for (Index j=0; j<outerSize; ++j)
{
derived().startVec(j);
for (typename OtherDerived::InnerIterator it(other, j); it; ++it)
{
Scalar v = it.value();
derived().insertBackByOuterInner(j,it.index()) = v;
}
}
derived().finalize();
}
else
{
assignGeneric(other);
}
return derived();
}
inline Derived& assign(const OtherDerived& other);
template<typename OtherDerived>
inline void assignGeneric(const OtherDerived& other)
{
//const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
eigen_assert(( ((internal::traits<Derived>::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) ||
(!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) &&
"the transpose operation is supposed to be handled in SparseMatrix::operator=");
enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) };
const Index outerSize = other.outerSize();
//typedef typename internal::conditional<transpose, LinkedVectorMatrix<Scalar,Flags&RowMajorBit>, Derived>::type TempType;
// thanks to shallow copies, we always eval to a tempary
Derived temp(other.rows(), other.cols());
temp.reserve((std::max)(this->rows(),this->cols())*2);
for (Index j=0; j<outerSize; ++j)
{
temp.startVec(j);
for (typename OtherDerived::InnerIterator it(other.derived(), j); it; ++it)
{
Scalar v = it.value();
temp.insertBackByOuterInner(Flip?it.index():j,Flip?j:it.index()) = v;
}
}
temp.finalize();
derived() = temp.markAsRValue();
}
inline void assignGeneric(const OtherDerived& other);
public:

View File

@ -133,6 +133,12 @@ template<typename T> struct plain_matrix_type<T,Sparse>
typedef SparseMatrix<_Scalar, _Options, _Index> type;
};
template<typename Derived>
struct generic_xpr_base<Derived, MatrixXpr, Sparse>
{
typedef SparseMatrixBase<Derived> type;
};
} // end namespace internal
/** \ingroup SparseCore_Module