bug #1381: fix sparse.diagonal() used as a rvalue.

The problem was that is "sparse" is not const, then sparse.diagonal() must have the
LValueBit flag meaning that sparse.diagonal().coeff(i) must returns a const reference,
const Scalar&. However, sparse::coeff() cannot returns a reference for a non-existing
zero coefficient. The trick is to return a reference to a local member of
evaluator<SparseMatrix>.
This commit is contained in:
Gael Guennebaud 2017-01-25 17:39:01 +01:00
parent d06a48959a
commit 296d24be4d
4 changed files with 33 additions and 15 deletions

View File

@ -1613,9 +1613,7 @@ struct evaluator<Diagonal<ArgType, DiagIndex> >
{ }
typedef typename XprType::Scalar Scalar;
// FIXME having to check whether ArgType is sparse here i not very nice.
typedef typename internal::conditional<!internal::is_same<typename ArgType::StorageKind,Sparse>::value,
typename XprType::CoeffReturnType,Scalar>::type CoeffReturnType;
typedef typename XprType::CoeffReturnType CoeffReturnType;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
CoeffReturnType coeff(Index row, Index) const

View File

@ -638,7 +638,7 @@ struct plain_constant_type
template<typename ExpressionType>
struct is_lvalue
{
enum { value = !bool(is_const<ExpressionType>::value) &&
enum { value = (!bool(is_const<ExpressionType>::value)) &&
bool(traits<ExpressionType>::Flags & LvalueBit) };
};

View File

@ -295,11 +295,11 @@ struct evaluator<SparseCompressedBase<Derived> >
Flags = Derived::Flags
};
evaluator() : m_matrix(0)
evaluator() : m_matrix(0), m_zero(0)
{
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
explicit evaluator(const Derived &mat) : m_matrix(&mat)
explicit evaluator(const Derived &mat) : m_matrix(&mat), m_zero(0)
{
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
@ -312,26 +312,42 @@ struct evaluator<SparseCompressedBase<Derived> >
operator const Derived&() const { return *m_matrix; }
typedef typename DenseCoeffsBase<Derived,ReadOnlyAccessors>::CoeffReturnType CoeffReturnType;
Scalar coeff(Index row, Index col) const
{ return m_matrix->coeff(row,col); }
const Scalar& coeff(Index row, Index col) const
{
Index p = find(row,col);
if(p==Dynamic)
return m_zero;
else
return m_matrix->const_cast_derived().valuePtr()[p];
}
Scalar& coeffRef(Index row, Index col)
{
Index p = find(row,col);
eigen_assert(p!=Dynamic && "written coefficient does not exist");
return m_matrix->const_cast_derived().valuePtr()[p];
}
protected:
Index find(Index row, Index col) const
{
eigen_internal_assert(row>=0 && row<m_matrix->rows() && col>=0 && col<m_matrix->cols());
const Index outer = Derived::IsRowMajor ? row : col;
const Index inner = Derived::IsRowMajor ? col : row;
Index start = m_matrix->outerIndexPtr()[outer];
Index end = m_matrix->isCompressed() ? m_matrix->outerIndexPtr()[outer+1] : m_matrix->outerIndexPtr()[outer] + m_matrix->innerNonZeroPtr()[outer];
eigen_assert(end>start && "you are using a non finalized sparse matrix or written coefficient does not exist");
const Index p = std::lower_bound(m_matrix->innerIndexPtr()+start, m_matrix->innerIndexPtr()+end,inner)
- m_matrix->innerIndexPtr();
eigen_assert((p<end) && (m_matrix->innerIndexPtr()[p]==inner) && "written coefficient does not exist");
return m_matrix->const_cast_derived().valuePtr()[p];
eigen_assert(end>=start && "you are using a non finalized sparse matrix or written coefficient does not exist");
const Index p = std::lower_bound(m_matrix->innerIndexPtr()+start, m_matrix->innerIndexPtr()+end,inner) - m_matrix->innerIndexPtr();
return ((p<end) && (m_matrix->innerIndexPtr()[p]==inner)) ? p : Dynamic;
}
const Derived *m_matrix;
const Scalar m_zero;
};
}

View File

@ -485,6 +485,10 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
SparseMatrixType m2(rows, cols);
initSparse<Scalar>(density, refMat2, m2);
VERIFY_IS_APPROX(m2.diagonal(), refMat2.diagonal().eval());
DenseVector d = m2.diagonal();
VERIFY_IS_APPROX(d, refMat2.diagonal().eval());
d = m2.diagonal().array();
VERIFY_IS_APPROX(d, refMat2.diagonal().eval());
VERIFY_IS_APPROX(const_cast<const SparseMatrixType&>(m2).diagonal(), refMat2.diagonal().eval());
initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag);