diff --git a/CHANGELOG.md b/CHANGELOG.md index d26778bf2..0bb810a01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Fixed + +- Fix handling of non sorted sparse matrix ([#538](https://github.com/stack-of-tasks/eigenpy/pull/538)) + ## [3.10.3] - 2025-02-11 ### Added diff --git a/include/eigenpy/sparse/eigen-from-python.hpp b/include/eigenpy/sparse/eigen-from-python.hpp index 13c20f779..40da5e2eb 100644 --- a/include/eigenpy/sparse/eigen-from-python.hpp +++ b/include/eigenpy/sparse/eigen-from-python.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2024 INRIA +// Copyright (c) 2024-2025 INRIA // #ifndef __eigenpy_sparse_eigen_from_python_hpp__ @@ -156,6 +156,10 @@ void eigen_sparse_matrix_from_py_construct( } MapMatOrRefType sparse_map(m, n, nnz, indptr.data(), indices_ptr, data_ptr); +#if EIGEN_VERSION_AT_LEAST(3, 4, 90) + sparse_map.sortInnerIndices(); +#endif + new (raw_ptr) MatOrRefType(sparse_map); } diff --git a/unittest/python/decompositions/sparse/test_SimplicialLLT.py b/unittest/python/decompositions/sparse/test_SimplicialLLT.py index 10d6a5e66..161411344 100644 --- a/unittest/python/decompositions/sparse/test_SimplicialLLT.py +++ b/unittest/python/decompositions/sparse/test_SimplicialLLT.py @@ -1,4 +1,5 @@ import numpy as np +import scipy from scipy.sparse import csc_matrix import eigenpy @@ -30,3 +31,14 @@ llt.analyzePattern(A) llt.factorize(A) permutation = llt.permutationP() + +X_sparse = scipy.sparse.random(dim, 10) +B_sparse = A.dot(X_sparse) +B_sparse = B_sparse.tocsc(True) + +if not B_sparse.has_sorted_indices: + B_sparse.sort_indices() + +X_est = llt.solve(B_sparse) +assert eigenpy.is_approx(X_est.toarray(), X_sparse.toarray()) +assert eigenpy.is_approx(A.dot(X_est.toarray()), B_sparse.toarray())