bug #1359: fix compilation of col_major_sparse.row() *= scalar

(used to work in 3.2.9 though the expression is not really writable)
This commit is contained in:
Gael Guennebaud 2016-12-14 17:05:26 +01:00
parent 98d7458275
commit e67397bfa7
2 changed files with 59 additions and 23 deletions

View File

@ -531,22 +531,24 @@ class unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBas
enum { IsRowMajor = unary_evaluator::IsRowMajor };
const unary_evaluator& m_eval;
Index m_outerPos;
Index m_innerIndex;
Scalar m_value;
const Index m_innerIndex;
Index m_end;
EvalIterator m_it;
public:
EIGEN_STRONG_INLINE OuterVectorInnerIterator(const unary_evaluator& aEval, Index outer)
: m_eval(aEval),
m_outerPos( (IsRowMajor ? aEval.m_block.startCol() : aEval.m_block.startRow()) - 1), // -1 so that operator++ finds the first non-zero entry
m_outerPos( (IsRowMajor ? aEval.m_block.startCol() : aEval.m_block.startRow()) ),
m_innerIndex(IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol()),
m_value(0),
m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows())
m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()),
m_it(m_eval.m_argImpl, m_outerPos)
{
EIGEN_UNUSED_VARIABLE(outer);
eigen_assert(outer==0);
++(*this);
while(m_it && m_it.index() < m_innerIndex) ++m_it;
if((!m_it) || (m_it.index()!=m_innerIndex))
++(*this);
}
inline StorageIndex index() const { return convert_index<StorageIndex>(m_outerPos - (IsRowMajor ? m_eval.m_block.startCol() : m_eval.m_block.startRow())); }
@ -554,21 +556,20 @@ public:
inline Index row() const { return IsRowMajor ? 0 : index(); }
inline Index col() const { return IsRowMajor ? index() : 0; }
inline Scalar value() const { return m_value; }
inline Scalar value() const { return m_it.value(); }
inline Scalar& valueRef() { return m_it.valueRef(); }
inline OuterVectorInnerIterator& operator++()
{
// search next non-zero entry
while(++m_outerPos<m_end)
{
EvalIterator it(m_eval.m_argImpl, m_outerPos);
// Restart iterator at the next inner-vector:
m_it.~EvalIterator();
::new (&m_it) EvalIterator(m_eval.m_argImpl, m_outerPos);
// search for the key m_innerIndex in the current outer-vector
while(it && it.index() < m_innerIndex) ++it;
if(it && it.index()==m_innerIndex)
{
m_value = it.value();
break;
}
while(m_it && m_it.index() < m_innerIndex) ++m_it;
if(m_it && m_it.index()==m_innerIndex) break;
}
return *this;
}

View File

@ -9,6 +9,20 @@
#include "sparse.h"
template<typename T>
typename Eigen::internal::enable_if<(T::Flags&RowMajorBit)==RowMajorBit, typename T::RowXpr>::type
innervec(T& A, Index i)
{
return A.row(i);
}
template<typename T>
typename Eigen::internal::enable_if<(T::Flags&RowMajorBit)==0, typename T::ColXpr>::type
innervec(T& A, Index i)
{
return A.col(i);
}
template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& ref)
{
const Index rows = ref.rows();
@ -20,9 +34,10 @@ template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& re
typedef typename SparseMatrixType::StorageIndex StorageIndex;
double density = (std::max)(8./(rows*cols), 0.01);
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
typedef Matrix<Scalar,Dynamic,Dynamic,SparseMatrixType::IsRowMajor?RowMajor:ColMajor> DenseMatrix;
typedef Matrix<Scalar,Dynamic,1> DenseVector;
typedef Matrix<Scalar,1,Dynamic> RowDenseVector;
typedef SparseVector<Scalar> SparseVectorType;
Scalar s1 = internal::random<Scalar>();
{
@ -110,15 +125,35 @@ template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& re
initSparse<Scalar>(density, refMat2, m2);
Index j0 = internal::random<Index>(0,outer-1);
Index j1 = internal::random<Index>(0,outer-1);
if(SparseMatrixType::IsRowMajor)
VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.row(j0));
else
VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
Index r0 = internal::random<Index>(0,rows-1);
Index c0 = internal::random<Index>(0,cols-1);
if(SparseMatrixType::IsRowMajor)
VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.row(j0)+refMat2.row(j1));
else
VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
VERIFY_IS_APPROX(m2.innerVector(j0), innervec(refMat2,j0));
VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), innervec(refMat2,j0)+innervec(refMat2,j1));
m2.innerVector(j0) *= Scalar(2);
innervec(refMat2,j0) *= Scalar(2);
VERIFY_IS_APPROX(m2, refMat2);
m2.row(r0) *= Scalar(3);
refMat2.row(r0) *= Scalar(3);
VERIFY_IS_APPROX(m2, refMat2);
m2.col(c0) *= Scalar(4);
refMat2.col(c0) *= Scalar(4);
VERIFY_IS_APPROX(m2, refMat2);
m2.row(r0) /= Scalar(3);
refMat2.row(r0) /= Scalar(3);
VERIFY_IS_APPROX(m2, refMat2);
m2.col(c0) /= Scalar(4);
refMat2.col(c0) /= Scalar(4);
VERIFY_IS_APPROX(m2, refMat2);
SparseVectorType v1;
VERIFY_IS_APPROX(v1 = m2.col(c0) * 4, refMat2.col(c0)*4);
VERIFY_IS_APPROX(v1 = m2.row(r0) * 4, refMat2.row(r0).transpose()*4);
SparseMatrixType m3(rows,cols);
m3.reserve(VectorXi::Constant(outer,int(inner/2)));