mirror of
https://gitlab.com/libeigen/eigen.git
synced 2024-11-21 03:11:25 +08:00
- add diagonal * sparse product as an expression
- split sparse_basic unit test - various fixes in sparse module
This commit is contained in:
parent
e0be020622
commit
a9688f0b71
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -89,7 +89,7 @@ class SparseCwiseUnaryOp<UnaryOp,MatrixType>::InnerIterator
|
||||
|
||||
protected:
|
||||
MatrixTypeIterator m_iter;
|
||||
const UnaryOp& m_functor;
|
||||
const UnaryOp m_functor;
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
|
157
Eigen/src/Sparse/SparseDiagonalProduct.h
Normal file
157
Eigen/src/Sparse/SparseDiagonalProduct.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
132
test/sparse_product.cpp
Normal 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)) );
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user