diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 47437ec0..af3db8fd 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -16,6 +16,7 @@ jobs: fail-fast: false matrix: os: [ubuntu, macos] + eigen: [3, 5] steps: - uses: actions/checkout@v5 - uses: cachix/install-nix-action@v31 @@ -23,7 +24,7 @@ jobs: with: name: gepetto authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - run: nix build -L + - run: nix build -L ".#eigenpy-eigen${{ matrix.eigen }}" check: if: always() diff --git a/CHANGELOG.md b/CHANGELOG.md index ebe0519e..e89b3114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - Fix partly the support of the change of API of GeneralizedEigenSolver in Eigen 5+ ([#594](https://github.com/stack-of-tasks/eigenpy/pull/594)) +- Fix Eigen decompositions and solvers for Eigen 5 ([#596](https://github.com/stack-of-tasks/eigenpy/pull/596)) ## [3.12.0] - 2025-08-12 diff --git a/flake.nix b/flake.nix index a0b48c61..7d038298 100644 --- a/flake.nix +++ b/flake.nix @@ -19,16 +19,27 @@ }; devShells.default = pkgs.mkShell { inputsFrom = [ self'.packages.default ]; }; packages = { - default = self'.packages.eigenpy; - eigen = pkgs.eigen.overrideAttrs { - # Apply https://gitlab.com/libeigen/eigen/-/merge_requests/977 - postPatch = '' - substituteInPlace Eigen/src/SVD/BDCSVD.h \ - --replace-fail "if (l == 0) {" "if (i >= k && l == 0) {" - ''; - }; - eigenpy = - (pkgs.python3Packages.eigenpy.override { inherit (self'.packages) eigen; }).overrideAttrs + default = self'.packages.eigenpy-eigen5; + eigen3 = pkgs.eigen.overrideAttrs (super: rec { + version = "3.4.1"; + src = pkgs.fetchFromGitLab { + inherit (super.src) owner repo; + tag = version; + hash = "sha256-NSq1tUfy2thz5gtsyASsKeYE4vMf71aSG4uXfrX86rk="; + }; + patches = [ ]; + postPatch = ""; + }); + eigen5 = self'.packages.eigen3.overrideAttrs (super: rec { + version = "5.0.0"; + src = pkgs.fetchFromGitLab { + inherit (super.src) owner repo; + tag = version; + hash = "sha256-L1KUFZsaibC/FD6abTXrT3pvaFhbYnw+GaWsxM2gaxM="; + }; + }); + eigenpy-eigen3 = + (pkgs.python3Packages.eigenpy.override { eigen = self'.packages.eigen3; }).overrideAttrs (_: { src = pkgs.lib.fileset.toSource { root = ./.; @@ -43,6 +54,7 @@ ]; }; }); + eigenpy-eigen5 = self'.packages.eigenpy-eigen3.override { eigen = self'.packages.eigen5; }; }; }; }; diff --git a/include/eigenpy/decompositions/BDCSVD.hpp b/include/eigenpy/decompositions/BDCSVD.hpp index 9f9eb75e..564372df 100644 --- a/include/eigenpy/decompositions/BDCSVD.hpp +++ b/include/eigenpy/decompositions/BDCSVD.hpp @@ -35,22 +35,27 @@ struct BDCSVDVisitor .def("cols", &Solver::cols, bp::arg("self"), "Returns the number of columns. ") - .def("compute", - (Solver & (Solver::*)(const MatrixType &matrix)) & Solver::compute, - bp::args("self", "matrix"), - "Method performing the decomposition of given matrix. Computes " - "Thin/Full " - "unitaries U/V if specified using the Options template parameter " - "or the class constructor. ", - bp::return_self<>()) - .def("compute", - (Solver & (Solver::*)(const MatrixType &matrix, - unsigned int computationOptions)) & - Solver::compute, - bp::args("self", "matrix", "computationOptions"), - "Method performing the decomposition of given matrix, as " - "specified by the computationOptions parameter. ", - bp::return_self<>()) + .def( + "compute", + +[](Solver &self, const MatrixType &matrix) -> Solver & { + return self.compute(matrix); + }, + bp::args("self", "matrix"), + "Method performing the decomposition of given matrix. Computes " + "Thin/Full " + "unitaries U/V if specified using the Options template parameter " + "or the class constructor. ", + bp::return_self<>()) + .def( + "compute", + +[](Solver &self, const MatrixType &matrix, + unsigned int computationOptions) -> Solver & { + return self.compute(matrix, computationOptions); + }, + bp::args("self", "matrix", "computationOptions"), + "Method performing the decomposition of given matrix, as " + "specified by the computationOptions parameter. ", + bp::return_self<>()) .def("rows", &Solver::rows, bp::arg("self"), "Returns the number of rows. ") .def("setSwitchSize", &Solver::setSwitchSize, bp::args("self", "s")) diff --git a/include/eigenpy/decompositions/JacobiSVD.hpp b/include/eigenpy/decompositions/JacobiSVD.hpp index 1ea45ed1..3580f15a 100644 --- a/include/eigenpy/decompositions/JacobiSVD.hpp +++ b/include/eigenpy/decompositions/JacobiSVD.hpp @@ -18,7 +18,9 @@ namespace eigenpy { template struct JacobiSVDVisitor : public boost::python::def_visitor> { + typedef JacobiSVD Solver; typedef typename JacobiSVD::MatrixType MatrixType; + typedef Eigen::MatrixBase MatrixBaseType; typedef typename MatrixType::Scalar Scalar; template @@ -34,23 +36,27 @@ struct JacobiSVDVisitor .def("cols", &JacobiSVD::cols, bp::arg("self"), "Returns the number of columns. ") - .def("compute", - (JacobiSVD & (JacobiSVD::*)(const MatrixType &matrix)) & - JacobiSVD::compute, - bp::args("self", "matrix"), - "Method performing the decomposition of given matrix. Computes " - "Thin/Full " - "unitaries U/V if specified using the Options template parameter " - "or the class constructor. ", - bp::return_self<>()) - .def("compute", - (JacobiSVD & (JacobiSVD::*)(const MatrixType &matrix, - unsigned int computationOptions)) & - JacobiSVD::compute, - bp::args("self", "matrix", "computationOptions"), - "Method performing the decomposition of given matrix, as " - "specified by the computationOptions parameter. ", - bp::return_self<>()) + .def( + "compute", + +[](Solver &self, const MatrixType &matrix) -> Solver & { + return self.compute(matrix); + }, + bp::args("self", "matrix"), + "Method performing the decomposition of given matrix. Computes " + "Thin/Full " + "unitaries U/V if specified using the Options template parameter " + "or the class constructor. ", + bp::return_self<>()) + .def( + "compute", + +[](Solver &self, const MatrixType &matrix, + unsigned int computationOptions) -> Solver & { + return self.compute(matrix, computationOptions); + }, + bp::args("self", "matrix", "computation_options"), + "Method performing the decomposition of given matrix, as " + "specified by the computationOptions parameter. ", + bp::return_self<>()) .def("rows", &JacobiSVD::rows, bp::arg("self"), "Returns the number of rows.") diff --git a/include/eigenpy/decompositions/sparse/SparseLU.hpp b/include/eigenpy/decompositions/sparse/SparseLU.hpp index 045b3f44..3b7ed3af 100644 --- a/include/eigenpy/decompositions/sparse/SparseLU.hpp +++ b/include/eigenpy/decompositions/sparse/SparseLU.hpp @@ -98,8 +98,14 @@ struct SparseLUVisitor : public boost::python::def_visitor< typedef typename Solver::SCMatrix SCMatrix; typedef typename MatrixType::StorageIndex StorageIndex; + +#if EIGEN_VERSION_AT_LEAST(3, 4, 90) + typedef Eigen::Map> + MappedSparseMatrix; +#else typedef Eigen::MappedSparseMatrix MappedSparseMatrix; +#endif typedef Eigen::SparseLUMatrixLReturnType LType; typedef Eigen::SparseLUMatrixUReturnType UType; diff --git a/src/decompositions/sparse-lu-solver.cpp b/src/decompositions/sparse-lu-solver.cpp index 763a7559..44eca4fa 100644 --- a/src/decompositions/sparse-lu-solver.cpp +++ b/src/decompositions/sparse-lu-solver.cpp @@ -15,8 +15,14 @@ void exposeSparseLUSolver() { typedef typename SparseLUType::Scalar Scalar; typedef typename SparseLUType::SCMatrix SCMatrix; - typedef Eigen::MappedSparseMatrix + +#if EIGEN_VERSION_AT_LEAST(3, 4, 90) + typedef Eigen::Map> + MappedSparseMatrix; +#else + typedef Eigen::MappedSparseMatrix MappedSparseMatrix; +#endif SparseLUMatrixLReturnTypeVisitor::expose( ("SparseLUMatrixLReturnType"));