Fix bugs and clean up SparseCore module

libeigen/eigen!2250

Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
Rasmus Munk Larsen
2026-03-21 06:31:12 -07:00
committed by Charles Schlosser
parent daecd28cd5
commit cc8c7cf0e6
7 changed files with 82 additions and 24 deletions

View File

@@ -1017,6 +1017,80 @@ void big_sparse_triplet(Index rows, Index cols, double density) {
VERIFY_IS_APPROX(sum, m.sum());
}
// Regression test: SparseMatrixBase::operator-=(const EigenBase&) must subtract, not overwrite.
// SparseSelfAdjointView inherits EigenBase (not SparseMatrixBase), so it exercises this overload.
template <int>
void sparse_sub_assign_eigenbase() {
Index n = 10;
SparseMatrix<double> A(n, n), B(n, n);
A.setIdentity();
B.setIdentity();
B *= 3.0;
// Make B symmetric so selfadjointView is valid
MatrixXd refA = MatrixXd(A);
MatrixXd refB = MatrixXd(B);
// operator-= going through the EigenBase<OtherDerived> overload
A -= B.selfadjointView<Lower>();
refA -= refB.selfadjointView<Lower>();
VERIFY_IS_APPROX(MatrixXd(A), refA);
// Also test operator+= for symmetry
A += B.selfadjointView<Lower>();
refA += refB.selfadjointView<Lower>();
VERIFY_IS_APPROX(MatrixXd(A), refA);
}
// Regression test: AmbiVector::coeff() must return the correct linked-list element.
template <int>
void ambivector_coeff() {
using namespace Eigen::internal;
const Index size = 20;
AmbiVector<double, int> vec(size);
vec.setBounds(0, size);
// Test in sparse (linked-list) mode
vec.init(IsSparse);
vec.restart();
// Insert elements out of order to stress linked-list traversal:
// Insert at indices 2, 5, 10, 15 with distinct values
vec.coeffRef(2) = 2.0;
vec.coeffRef(5) = 5.0;
vec.coeffRef(10) = 10.0;
vec.coeffRef(15) = 15.0;
// coeff() should return the correct value for each inserted element
VERIFY_IS_APPROX(vec.coeff(2), 2.0);
VERIFY_IS_APPROX(vec.coeff(5), 5.0);
VERIFY_IS_APPROX(vec.coeff(10), 10.0);
VERIFY_IS_APPROX(vec.coeff(15), 15.0);
// coeff() should return zero for non-inserted elements
VERIFY_IS_EQUAL(vec.coeff(0), 0.0);
VERIFY_IS_EQUAL(vec.coeff(3), 0.0);
VERIFY_IS_EQUAL(vec.coeff(7), 0.0);
VERIFY_IS_EQUAL(vec.coeff(18), 0.0);
// Verify coeff() still works after coeffRef() advances m_llCurrent.
// This is the specific scenario that triggered the bug: coeffRef(15)
// leaves m_llCurrent pointing at element 15, then coeff(2) should
// still return 2.0, not 15.0.
vec.restart();
vec.coeffRef(15) += 0.0; // advances m_llCurrent to element at index 15
VERIFY_IS_APPROX(vec.coeff(2), 2.0);
VERIFY_IS_APPROX(vec.coeff(5), 5.0);
// Test in dense mode as well (simpler, but for completeness)
vec.init(IsDense);
vec.setZero();
vec.coeffRef(3) = 3.0;
vec.coeffRef(7) = 7.0;
VERIFY_IS_APPROX(vec.coeff(3), 3.0);
VERIFY_IS_APPROX(vec.coeff(7), 7.0);
VERIFY_IS_EQUAL(vec.coeff(0), 0.0);
}
template <int>
void bug1105() {
// Regression test for bug 1105
@@ -1066,5 +1140,7 @@ EIGEN_DECLARE_TEST(sparse_basic) {
CALL_SUBTEST_5((big_sparse_triplet<SparseMatrix<double, ColMajor, long int>>(10000, 10000, 0.125)));
CALL_SUBTEST_5(bug1105<0>());
CALL_SUBTEST_1(sparse_sub_assign_eigenbase<0>());
CALL_SUBTEST_1(ambivector_coeff<0>());
}
#endif