- add diagonal * sparse product as an expression

- split sparse_basic unit test
- various fixes in sparse module
This commit is contained in:
Gael Guennebaud 2009-02-09 09:59:30 +00:00
parent e0be020622
commit a9688f0b71
18 changed files with 423 additions and 93 deletions

View File

@ -103,6 +103,7 @@ namespace Eigen {
#include "src/Sparse/SparseFuzzy.h"
#include "src/Sparse/SparseFlagged.h"
#include "src/Sparse/SparseProduct.h"
#include "src/Sparse/SparseDiagonalProduct.h"
#include "src/Sparse/TriangularSolver.h"
#include "src/Sparse/SparseLLT.h"
#include "src/Sparse/SparseLDLT.h"

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -91,9 +91,9 @@ class SparseInnerVectorSet : ei_no_assignment_operator,
};
//----------
// specialisation for DynamicSparseMatrix
//----------
/***************************************************************************
* specialisation for DynamicSparseMatrix
***************************************************************************/
template<typename _Scalar, int _Options, int Size>
class SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options>, Size>
@ -169,6 +169,89 @@ class SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options>, Size>
};
/***************************************************************************
* specialisation for SparseMatrix
***************************************************************************/
/*
template<typename _Scalar, int _Options, int Size>
class SparseInnerVectorSet<SparseMatrix<_Scalar, _Options>, Size>
: public SparseMatrixBase<SparseInnerVectorSet<SparseMatrix<_Scalar, _Options>, Size> >
{
typedef DynamicSparseMatrix<_Scalar, _Options> MatrixType;
enum { IsRowMajor = ei_traits<SparseInnerVectorSet>::IsRowMajor };
public:
EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet)
class InnerIterator: public MatrixType::InnerIterator
{
public:
inline InnerIterator(const SparseInnerVectorSet& xpr, int outer)
: MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer)
{}
};
inline SparseInnerVectorSet(const MatrixType& matrix, int outerStart, int outerSize)
: m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize)
{
ei_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) );
}
inline SparseInnerVectorSet(const MatrixType& matrix, int outer)
: m_matrix(matrix), m_outerStart(outer)
{
ei_assert(Size==1);
ei_assert( (outer>=0) && (outer<matrix.outerSize()) );
}
template<typename OtherDerived>
inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
{
if (IsRowMajor != ((OtherDerived::Flags&RowMajorBit)==RowMajorBit))
{
// need to transpose => perform a block evaluation followed by a big swap
DynamicSparseMatrix<Scalar,IsRowMajor?RowMajorBit:0> aux(other);
*this = aux.markAsRValue();
}
else
{
// evaluate/copy vector per vector
for (int j=0; j<m_outerSize.value(); ++j)
{
SparseVector<Scalar,IsRowMajor ? RowMajorBit : 0> aux(other.innerVector(j));
m_matrix.const_cast_derived()._data()[m_outerStart+j].swap(aux._data());
}
}
return *this;
}
inline SparseInnerVectorSet& operator=(const SparseInnerVectorSet& other)
{
return operator=<SparseInnerVectorSet>(other);
}
inline const Scalar* _valuePtr() const
{ return m_matrix._valuePtr() + m_matrix._outerIndexPtr()[m_outerStart]; }
inline const int* _innerIndexPtr() const
{ return m_matrix._innerIndexPtr() + m_matrix._outerIndexPtr()[m_outerStart]; }
inline const int* _outerIndexPtr() const { return m_matrix._outerIndexPtr() + m_outerStart; }
// template<typename Sparse>
// inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
// {
// return *this;
// }
EIGEN_STRONG_INLINE int rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
EIGEN_STRONG_INLINE int cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
protected:
const typename MatrixType::Nested m_matrix;
int m_outerStart;
const ei_int_if_dynamic<Size> m_outerSize;
};
*/
//----------
/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */
@ -192,7 +275,7 @@ const SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::row(int i) cons
template<typename Derived>
SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::col(int i)
{
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COL_MAJOR_MATRICES);
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
return innerVector(i);
}
@ -201,7 +284,7 @@ SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::col(int i)
template<typename Derived>
const SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::col(int i) const
{
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COL_MAJOR_MATRICES);
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
return innerVector(i);
}
@ -242,7 +325,7 @@ const SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::subrows(i
template<typename Derived>
SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::subcols(int start, int size)
{
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COL_MAJOR_MATRICES);
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
return innerVectors(start, size);
}
@ -251,7 +334,7 @@ SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::subcols(int sta
template<typename Derived>
const SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::subcols(int start, int size) const
{
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COL_MAJOR_MATRICES);
EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
return innerVectors(start, size);
}

View File

@ -132,11 +132,10 @@ class SparseCwiseBinaryOp<BinaryOp,Lhs,Rhs>::InnerIterator
* Implementation of inner-iterators
***************************************************************************/
// template<typename T> struct ei_is_scalar_product { enum { ret = false }; };
// template<typename T> struct ei_is_scalar_product<ei_scalar_product_op<T> > { enum { ret = true }; };
// helper class
// template<typename T> struct ei_func_is_conjunction { enum { ret = false }; };
// template<typename T> struct ei_func_is_conjunction<ei_scalar_product_op<T> > { enum { ret = true }; };
// TODO generalize the ei_scalar_product_op specialization to all conjunctions if any !
// sparse - sparse (generic)
template<typename BinaryOp, typename Lhs, typename Rhs, typename Derived>
@ -261,12 +260,13 @@ class ei_sparse_cwise_binary_op_inner_iterator_selector<ei_scalar_product_op<T>,
typedef SparseCwiseBinaryOp<BinaryFunc, Lhs, Rhs> CwiseBinaryXpr;
typedef typename CwiseBinaryXpr::Scalar Scalar;
typedef typename ei_traits<CwiseBinaryXpr>::_LhsNested _LhsNested;
typedef typename ei_traits<CwiseBinaryXpr>::RhsNested RhsNested;
typedef typename _LhsNested::InnerIterator LhsIterator;
enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit };
public:
EIGEN_STRONG_INLINE ei_sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, int outer)
: m_xpr(xpr), m_lhsIter(xpr.lhs(),outer), m_functor(xpr.functor()), m_outer(outer)
: m_rhs(xpr.rhs()), m_lhsIter(xpr.lhs(),outer), m_functor(xpr.functor()), m_outer(outer)
{}
EIGEN_STRONG_INLINE Derived& operator++()
@ -277,7 +277,7 @@ class ei_sparse_cwise_binary_op_inner_iterator_selector<ei_scalar_product_op<T>,
EIGEN_STRONG_INLINE Scalar value() const
{ return m_functor(m_lhsIter.value(),
m_xpr.rhs().coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); }
m_rhs.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); }
EIGEN_STRONG_INLINE int index() const { return m_lhsIter.index(); }
EIGEN_STRONG_INLINE int row() const { return m_lhsIter.row(); }
@ -286,9 +286,9 @@ class ei_sparse_cwise_binary_op_inner_iterator_selector<ei_scalar_product_op<T>,
EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; }
protected:
const CwiseBinaryXpr& m_xpr;
const RhsNested m_rhs;
LhsIterator m_lhsIter;
const BinaryFunc& m_functor;
const BinaryFunc m_functor;
const int m_outer;
};
@ -331,6 +331,10 @@ class ei_sparse_cwise_binary_op_inner_iterator_selector<ei_scalar_product_op<T>,
};
/***************************************************************************
* Implementation of SparseMatrixBase and SparseCwise functions/operators
***************************************************************************/
template<typename Derived>
template<typename OtherDerived>
EIGEN_STRONG_INLINE const SparseCwiseBinaryOp<ei_scalar_difference_op<typename ei_traits<Derived>::Scalar>,

View File

@ -89,7 +89,7 @@ class SparseCwiseUnaryOp<UnaryOp,MatrixType>::InnerIterator
protected:
MatrixTypeIterator m_iter;
const UnaryOp& m_functor;
const UnaryOp m_functor;
};
template<typename Derived>

View File

@ -0,0 +1,157 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.
#ifndef EIGEN_SPARSE_DIAGONAL_PRODUCT_H
#define EIGEN_SPARSE_DIAGONAL_PRODUCT_H
// the product a diagonal matrix with a sparse matrix can be easily
// implemented using expression template. We have two very different cases:
// 1 - diag * row-major sparse
// => each inner vector <=> scalar * sparse vector product
// => so we can reuse CwiseUnaryOp::InnerIterator
// 2 - diag * col-major sparse
// => each inner vector <=> densevector * sparse vector cwise product
// => again, we can reuse specialization of CwiseBinaryOp::InnerIterator
// for that particular case
// The two other cases are symmetric.
template<typename Lhs, typename Rhs>
struct ei_traits<SparseDiagonalProduct<Lhs, Rhs> > : ei_traits<SparseProduct<Lhs, Rhs, DiagonalProduct> >
{
typedef typename ei_cleantype<Lhs>::type _Lhs;
typedef typename ei_cleantype<Rhs>::type _Rhs;
enum {
SparseFlags = ((int(_Lhs::Flags)&Diagonal)==Diagonal) ? _Rhs::Flags : _Lhs::Flags,
Flags = SparseBit | (SparseFlags&RowMajorBit)
};
};
enum {SDP_IsDiagonal, SDP_IsSparseRowMajor, SDP_IsSparseColMajor};
template<typename Lhs, typename Rhs, typename SparseDiagonalProductType, int RhsMode, int LhsMode>
class ei_sparse_diagonal_product_inner_iterator_selector;
template<typename LhsNested, typename RhsNested>
class SparseDiagonalProduct : public SparseMatrixBase<SparseDiagonalProduct<LhsNested,RhsNested> >, ei_no_assignment_operator
{
typedef typename ei_traits<SparseDiagonalProduct>::_LhsNested _LhsNested;
typedef typename ei_traits<SparseDiagonalProduct>::_RhsNested _RhsNested;
enum {
LhsMode = (_LhsNested::Flags&Diagonal)==Diagonal ? SDP_IsDiagonal
: (_LhsNested::Flags&RowMajorBit) ? SDP_IsSparseRowMajor : SDP_IsSparseColMajor,
RhsMode = (_RhsNested::Flags&Diagonal)==Diagonal ? SDP_IsDiagonal
: (_RhsNested::Flags&RowMajorBit) ? SDP_IsSparseRowMajor : SDP_IsSparseColMajor
};
public:
EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseDiagonalProduct)
typedef ei_sparse_diagonal_product_inner_iterator_selector
<_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator;
template<typename Lhs, typename Rhs>
EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs)
: m_lhs(lhs), m_rhs(rhs)
{
ei_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product");
}
EIGEN_STRONG_INLINE int rows() const { return m_lhs.rows(); }
EIGEN_STRONG_INLINE int cols() const { return m_rhs.cols(); }
EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; }
EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; }
protected:
LhsNested m_lhs;
RhsNested m_rhs;
};
template<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
class ei_sparse_diagonal_product_inner_iterator_selector
<Lhs,Rhs,SparseDiagonalProductType,SDP_IsDiagonal,SDP_IsSparseRowMajor>
: public SparseCwiseUnaryOp<ei_scalar_multiple_op<typename Lhs::Scalar>,Rhs>::InnerIterator
{
typedef typename SparseCwiseUnaryOp<ei_scalar_multiple_op<typename Lhs::Scalar>,Rhs>::InnerIterator Base;
public:
inline ei_sparse_diagonal_product_inner_iterator_selector(
const SparseDiagonalProductType& expr, int outer)
: Base(expr.rhs()*(expr.lhs().diagonal().coeff(outer)), outer)
{}
};
template<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
class ei_sparse_diagonal_product_inner_iterator_selector
<Lhs,Rhs,SparseDiagonalProductType,SDP_IsDiagonal,SDP_IsSparseColMajor>
: public SparseCwiseBinaryOp<
ei_scalar_product_op<typename Lhs::Scalar>,
SparseInnerVectorSet<Rhs,1>,
typename Lhs::_CoeffsVectorType>::InnerIterator
{
typedef typename SparseCwiseBinaryOp<
ei_scalar_product_op<typename Lhs::Scalar>,
SparseInnerVectorSet<Rhs,1>,
typename Lhs::_CoeffsVectorType>::InnerIterator Base;
public:
inline ei_sparse_diagonal_product_inner_iterator_selector(
const SparseDiagonalProductType& expr, int outer)
: Base(expr.rhs().innerVector(outer) .cwise()* expr.lhs().diagonal(), 0)
{}
};
template<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
class ei_sparse_diagonal_product_inner_iterator_selector
<Lhs,Rhs,SparseDiagonalProductType,SDP_IsSparseColMajor,SDP_IsDiagonal>
: public SparseCwiseUnaryOp<ei_scalar_multiple_op<typename Rhs::Scalar>,Lhs>::InnerIterator
{
typedef typename SparseCwiseUnaryOp<ei_scalar_multiple_op<typename Rhs::Scalar>,Lhs>::InnerIterator Base;
public:
inline ei_sparse_diagonal_product_inner_iterator_selector(
const SparseDiagonalProductType& expr, int outer)
: Base(expr.lhs()*expr.rhs().diagonal().coeff(outer), outer)
{}
};
template<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
class ei_sparse_diagonal_product_inner_iterator_selector
<Lhs,Rhs,SparseDiagonalProductType,SDP_IsSparseRowMajor,SDP_IsDiagonal>
: public SparseCwiseBinaryOp<
ei_scalar_product_op<typename Rhs::Scalar>,
SparseInnerVectorSet<Lhs,1>,
NestByValue<Transpose<typename Rhs::_CoeffsVectorType> > >::InnerIterator
{
typedef typename SparseCwiseBinaryOp<
ei_scalar_product_op<typename Rhs::Scalar>,
SparseInnerVectorSet<Lhs,1>,
NestByValue<Transpose<typename Rhs::_CoeffsVectorType> > >::InnerIterator Base;
public:
inline ei_sparse_diagonal_product_inner_iterator_selector(
const SparseDiagonalProductType& expr, int outer)
: Base(expr.lhs().innerVector(outer) .cwise()* expr.rhs().diagonal().transpose().nestByValue(), 0)
{}
};
#endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -29,7 +29,9 @@ template<typename Lhs, typename Rhs> struct ei_sparse_product_mode
{
enum {
value = (Rhs::Flags&Lhs::Flags&SparseBit)==SparseBit
value = ((Lhs::Flags&Diagonal)==Diagonal || (Rhs::Flags&Diagonal)==Diagonal)
? DiagonalProduct
: (Rhs::Flags&Lhs::Flags&SparseBit)==SparseBit
? SparseTimeSparseProduct
: (Lhs::Flags&SparseBit)==SparseBit
? SparseTimeDenseProduct
@ -45,6 +47,15 @@ struct SparseProductReturnType
typedef SparseProduct<LhsNested, RhsNested, ProductMode> Type;
};
template<typename Lhs, typename Rhs>
struct SparseProductReturnType<Lhs,Rhs,DiagonalProduct>
{
typedef const typename ei_nested<Lhs,Rhs::RowsAtCompileTime>::type LhsNested;
typedef const typename ei_nested<Rhs,Lhs::RowsAtCompileTime>::type RhsNested;
typedef SparseDiagonalProduct<LhsNested, RhsNested> Type;
};
// sparse product return type specialization
template<typename Lhs, typename Rhs>
struct SparseProductReturnType<Lhs,Rhs,SparseTimeSparseProduct>
@ -95,7 +106,7 @@ struct ei_traits<SparseProduct<LhsNested, RhsNested, ProductMode> >
// RhsIsRowMajor = (RhsFlags & RowMajorBit)==RowMajorBit,
EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit),
ResultIsSparse = ProductMode==SparseTimeSparseProduct,
ResultIsSparse = ProductMode==SparseTimeSparseProduct || ProductMode==DiagonalProduct,
RemovedBits = ~( (EvalToRowMajor ? 0 : RowMajorBit) | (ResultIsSparse ? 0 : SparseBit) ),
@ -112,7 +123,8 @@ struct ei_traits<SparseProduct<LhsNested, RhsNested, ProductMode> >
};
template<typename LhsNested, typename RhsNested, int ProductMode>
class SparseProduct : ei_no_assignment_operator, public ei_traits<SparseProduct<LhsNested, RhsNested, ProductMode> >::Base
class SparseProduct : ei_no_assignment_operator,
public ei_traits<SparseProduct<LhsNested, RhsNested, ProductMode> >::Base
{
public:
@ -285,7 +297,6 @@ template<typename Derived>
template<typename Lhs, typename Rhs>
inline Derived& SparseMatrixBase<Derived>::operator=(const SparseProduct<Lhs,Rhs,SparseTimeSparseProduct>& product)
{
// std::cout << "sparse product to sparse\n";
ei_sparse_product_selector<
typename ei_cleantype<Lhs>::type,
typename ei_cleantype<Rhs>::type,
@ -311,7 +322,7 @@ inline Derived& SparseMatrixBase<Derived>::operator=(const SparseProduct<Lhs,Rhs
template<typename Derived>
template<typename Lhs, typename Rhs>
Derived& MatrixBase<Derived>::lazyAssign(const SparseProduct<Lhs,Rhs,SparseTimeDenseProduct>& product)
{
{
typedef typename ei_cleantype<Lhs>::type _Lhs;
typedef typename ei_cleantype<Rhs>::type _Rhs;
typedef typename _Lhs::InnerIterator LhsInnerIterator;
@ -333,7 +344,7 @@ Derived& MatrixBase<Derived>::lazyAssign(const SparseProduct<Lhs,Rhs,SparseTimeD
derived().row(j) += i.value() * product.rhs().row(j);
++i;
}
Block<Derived,1,Derived::ColsAtCompileTime> foo = derived().row(j);
Block<Derived,1,Derived::ColsAtCompileTime> res(derived().row(LhsIsRowMajor ? j : 0));
for (; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i)
{
if (LhsIsSelfAdjoint)
@ -345,7 +356,7 @@ Derived& MatrixBase<Derived>::lazyAssign(const SparseProduct<Lhs,Rhs,SparseTimeD
derived().row(b) += ei_conj(v) * product.rhs().row(a);
}
else if (LhsIsRowMajor)
foo += i.value() * product.rhs().row(i.index());
res += i.value() * product.rhs().row(i.index());
else
derived().row(i.index()) += i.value() * product.rhs().row(j);
}

View File

@ -113,6 +113,7 @@ template<typename UnaryOp, typename MatrixType> class SparseCwiseUnaryO
template<typename BinaryOp, typename Lhs, typename Rhs> class SparseCwiseBinaryOp;
template<typename ExpressionType,
unsigned int Added, unsigned int Removed> class SparseFlagged;
template<typename Lhs, typename Rhs> class SparseDiagonalProduct;
template<typename Lhs, typename Rhs> struct ei_sparse_product_mode;
template<typename Lhs, typename Rhs, int ProductMode = ei_sparse_product_mode<Lhs,Rhs>::value> struct SparseProductReturnType;

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -146,6 +146,7 @@ if(QT4_FOUND)
endif(QT4_FOUND)
ei_add_test(sparse_vector)
ei_add_test(sparse_basic)
ei_add_test(sparse_product)
ei_add_test(sparse_solvers " " "${SPARSE_LIBS}")
ei_add_test(reverse)

View File

@ -238,6 +238,8 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
VERIFY_IS_APPROX(m1.col(0).dot(refM2.row(0)), refM1.col(0).dot(refM2.row(0)));
refM4.setRandom();
// sparse cwise* dense
VERIFY_IS_APPROX(m3.cwise()*refM4, refM3.cwise()*refM4);
@ -281,69 +283,6 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());
}
// test matrix product
{
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
DenseMatrix refMat3 = DenseMatrix::Zero(rows, rows);
DenseMatrix refMat4 = DenseMatrix::Zero(rows, rows);
DenseMatrix dm4 = DenseMatrix::Zero(rows, rows);
SparseMatrixType m2(rows, rows);
SparseMatrixType m3(rows, rows);
SparseMatrixType m4(rows, rows);
initSparse<Scalar>(density, refMat2, m2);
initSparse<Scalar>(density, refMat3, m3);
initSparse<Scalar>(density, refMat4, m4);
VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3);
VERIFY_IS_APPROX(m4=m2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
VERIFY_IS_APPROX(m4=m2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
VERIFY_IS_APPROX(m4=m2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
// sparse * dense
VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
VERIFY_IS_APPROX(dm4=m2*refMat3.transpose(), refMat4=refMat2*refMat3.transpose());
VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3, refMat4=refMat2.transpose()*refMat3);
VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
// dense * sparse
VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3);
VERIFY_IS_APPROX(dm4=refMat2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
}
// test self adjoint products
{
DenseMatrix b = DenseMatrix::Random(rows, rows);
DenseMatrix x = DenseMatrix::Random(rows, rows);
DenseMatrix refX = DenseMatrix::Random(rows, rows);
DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
DenseMatrix refS = DenseMatrix::Zero(rows, rows);
SparseMatrixType mUp(rows, rows);
SparseMatrixType mLo(rows, rows);
SparseMatrixType mS(rows, rows);
do {
initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
} while (refUp.isZero());
refLo = refUp.transpose().conjugate();
mLo = mUp.transpose().conjugate();
refS = refUp + refLo;
refS.diagonal() *= 0.5;
mS = mUp + mLo;
for (int k=0; k<mS.outerSize(); ++k)
for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it)
if (it.index() == k)
it.valueRef() *= 0.5;
VERIFY_IS_APPROX(refS.adjoint(), refS);
VERIFY_IS_APPROX(mS.transpose().conjugate(), mS);
VERIFY_IS_APPROX(mS, refS);
VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
VERIFY_IS_APPROX(x=mUp.template marked<UpperTriangular|SelfAdjoint>()*b, refX=refS*b);
VERIFY_IS_APPROX(x=mLo.template marked<LowerTriangular|SelfAdjoint>()*b, refX=refS*b);
VERIFY_IS_APPROX(x=mS.template marked<SelfAdjoint>()*b, refX=refS*b);
}
// test prune
{

132
test/sparse_product.cpp Normal file
View File

@ -0,0 +1,132 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.
#include "sparse.h"
template<typename SparseMatrixType> void sparse_product(const SparseMatrixType& ref)
{
const int rows = ref.rows();
const int cols = ref.cols();
typedef typename SparseMatrixType::Scalar Scalar;
enum { Flags = SparseMatrixType::Flags };
double density = std::max(8./(rows*cols), 0.01);
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
typedef Matrix<Scalar,Dynamic,1> DenseVector;
Scalar eps = 1e-6;
// test matrix-matrix product
/*
{
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
DenseMatrix refMat3 = DenseMatrix::Zero(rows, rows);
DenseMatrix refMat4 = DenseMatrix::Zero(rows, rows);
DenseMatrix dm4 = DenseMatrix::Zero(rows, rows);
SparseMatrixType m2(rows, rows);
SparseMatrixType m3(rows, rows);
SparseMatrixType m4(rows, rows);
initSparse<Scalar>(density, refMat2, m2);
initSparse<Scalar>(density, refMat3, m3);
initSparse<Scalar>(density, refMat4, m4);
VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3);
VERIFY_IS_APPROX(m4=m2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
VERIFY_IS_APPROX(m4=m2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
VERIFY_IS_APPROX(m4=m2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
// sparse * dense
VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
VERIFY_IS_APPROX(dm4=m2*refMat3.transpose(), refMat4=refMat2*refMat3.transpose());
VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3, refMat4=refMat2.transpose()*refMat3);
VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
// dense * sparse
VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3);
VERIFY_IS_APPROX(dm4=refMat2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
}
*/
// test matrix - diagonal product
{
DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
DiagonalMatrix<Scalar,Dynamic> d1(DenseVector::Random(rows));
SparseMatrixType m2(rows, rows);
SparseMatrixType m3(rows, rows);
initSparse<Scalar>(density, refM2, m2);
initSparse<Scalar>(density, refM3, m3);
// std::cerr << "foo\n" << (m2*d1).toDense() << "\n\n" << refM2*d1 << "\n\n";
VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1);
VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1);
VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2);
// std::cerr << "foo\n" << (d1*m2.transpose()).toDense() << "\n\n" << d1 * refM2.transpose() << "\n\n";
VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose());
}
// test self adjoint products
// {
// DenseMatrix b = DenseMatrix::Random(rows, rows);
// DenseMatrix x = DenseMatrix::Random(rows, rows);
// DenseMatrix refX = DenseMatrix::Random(rows, rows);
// DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
// DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
// DenseMatrix refS = DenseMatrix::Zero(rows, rows);
// SparseMatrixType mUp(rows, rows);
// SparseMatrixType mLo(rows, rows);
// SparseMatrixType mS(rows, rows);
// do {
// initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
// } while (refUp.isZero());
// refLo = refUp.transpose().conjugate();
// mLo = mUp.transpose().conjugate();
// refS = refUp + refLo;
// refS.diagonal() *= 0.5;
// mS = mUp + mLo;
// for (int k=0; k<mS.outerSize(); ++k)
// for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it)
// if (it.index() == k)
// it.valueRef() *= 0.5;
//
// VERIFY_IS_APPROX(refS.adjoint(), refS);
// VERIFY_IS_APPROX(mS.transpose().conjugate(), mS);
// VERIFY_IS_APPROX(mS, refS);
// VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
// VERIFY_IS_APPROX(x=mUp.template marked<UpperTriangular|SelfAdjoint>()*b, refX=refS*b);
// VERIFY_IS_APPROX(x=mLo.template marked<LowerTriangular|SelfAdjoint>()*b, refX=refS*b);
// VERIFY_IS_APPROX(x=mS.template marked<SelfAdjoint>()*b, refX=refS*b);
// }
}
void test_sparse_product()
{
for(int i = 0; i < g_repeat; i++) {
CALL_SUBTEST( sparse_product(SparseMatrix<double>(8, 8)) );
CALL_SUBTEST( sparse_product(SparseMatrix<std::complex<double> >(16, 16)) );
CALL_SUBTEST( sparse_product(SparseMatrix<double>(33, 33)) );
CALL_SUBTEST( sparse_product(DynamicSparseMatrix<double>(8, 8)) );
}
}

View File

@ -84,6 +84,7 @@ template<typename Scalar> void sparse_vector(int rows, int cols)
VERIFY_IS_APPROX(v1-=v2, refV1-=refV2);
VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2));
VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2));
}