mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Fix sparse product with entities that do not have direct access.
libeigen/eigen!2205
This commit is contained in:
committed by
Rasmus Munk Larsen
parent
00cc497d32
commit
2cd9bb7380
@@ -61,6 +61,12 @@ struct sparse_time_dense_product_impl<SparseLhsType, DenseRhsType, DenseResType,
|
||||
// Direct pointer path: works for both compressed and non-compressed storage.
|
||||
static void runCol(const LhsEval& /*lhsEval*/, const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res,
|
||||
const ResScalar& alpha, Index n, Index c, std::true_type /* has_compressed_storage */) {
|
||||
runColImpl(lhs, rhs, res, alpha, n, c, std::integral_constant<bool, bool(DenseRhsType::Flags & DirectAccessBit)>());
|
||||
}
|
||||
|
||||
template <typename RhsT>
|
||||
static void runColImpl(const SparseLhsType& lhs, const RhsT& rhs, DenseResType& res, const ResScalar& alpha, Index n,
|
||||
Index c, std::true_type) {
|
||||
const Lhs& mat = lhs;
|
||||
const auto* vals = mat.valuePtr();
|
||||
const auto* inds = mat.innerIndexPtr();
|
||||
@@ -105,20 +111,32 @@ struct sparse_time_dense_product_impl<SparseLhsType, DenseRhsType, DenseResType,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Non-unit rhs stride: use direct pointers for sparse side, coeff() for rhs
|
||||
for (Index i = 0; i < n; ++i) {
|
||||
Index k = outer[i];
|
||||
const Index end = innerNnz ? outer[i] + innerNnz[i] : outer[i + 1];
|
||||
ResScalar sum0(0), sum1(0);
|
||||
for (; k < end; ++k) {
|
||||
sum0 += vals[k] * rhs.coeff(inds[k], c);
|
||||
++k;
|
||||
if (k < end) {
|
||||
sum1 += vals[k] * rhs.coeff(inds[k], c);
|
||||
}
|
||||
runColImpl(lhs, rhs, res, alpha, n, c, std::false_type());
|
||||
}
|
||||
}
|
||||
|
||||
// Use fall-back path without direct access to rhs.
|
||||
template <typename RhsT>
|
||||
static void runColImpl(const SparseLhsType& lhs, const RhsT& rhs, DenseResType& res, const ResScalar& alpha, Index n,
|
||||
Index c, std::false_type) {
|
||||
const Lhs& mat = lhs;
|
||||
const auto* vals = mat.valuePtr();
|
||||
const auto* inds = mat.innerIndexPtr();
|
||||
const auto* outer = mat.outerIndexPtr();
|
||||
const auto* innerNnz = mat.innerNonZeroPtr();
|
||||
// Non-unit rhs stride (or no direct access): use direct pointers for sparse side, coeff() for rhs
|
||||
for (Index i = 0; i < n; ++i) {
|
||||
Index k = outer[i];
|
||||
const Index end = innerNnz ? outer[i] + innerNnz[i] : outer[i + 1];
|
||||
ResScalar sum0(0), sum1(0);
|
||||
for (; k < end; ++k) {
|
||||
sum0 += vals[k] * rhs.coeff(inds[k], c);
|
||||
++k;
|
||||
if (k < end) {
|
||||
sum1 += vals[k] * rhs.coeff(inds[k], c);
|
||||
}
|
||||
res.coeffRef(i, c) += alpha * (sum0 + sum1);
|
||||
}
|
||||
res.coeffRef(i, c) += alpha * (sum0 + sum1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,11 @@ void sparse_product() {
|
||||
VERIFY_IS_APPROX(dm4 = m2t.transpose() * (refMat3 + refMat5) * 0.5,
|
||||
refMat4 = refMat2t.transpose() * (refMat3 + refMat5) * 0.5);
|
||||
|
||||
// sparse * dense expression without DirectAccessBit (e.g. CwiseNullaryOp)
|
||||
VERIFY_IS_APPROX(dm4 = m2 * DenseMatrix::Constant(depth, cols, s1),
|
||||
refMat4 = refMat2 * DenseMatrix::Constant(depth, cols, s1));
|
||||
VERIFY_IS_APPROX(dm4 = m2 * DenseMatrix::Zero(depth, cols), refMat4 = refMat2 * DenseMatrix::Zero(depth, cols));
|
||||
|
||||
// sparse * dense vector
|
||||
VERIFY_IS_APPROX(dm4.col(0) = m2 * refMat3.col(0), refMat4.col(0) = refMat2 * refMat3.col(0));
|
||||
VERIFY_IS_APPROX(dm4.col(0) = m2 * refMat3t.transpose().col(0),
|
||||
|
||||
Reference in New Issue
Block a user