From ae3081b232359c7e763d6c3725eb79b6999b2551 Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Mon, 10 Jun 2024 12:16:05 +0200 Subject: [PATCH 1/6] core: add id helper --- CMakeLists.txt | 1 + include/eigenpy/fwd.hpp | 1 + include/eigenpy/id.hpp | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 include/eigenpy/id.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bcc8f9897..94bf5d85a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,6 +232,7 @@ set(${PROJECT_NAME}_HEADERS include/eigenpy/eigen-to-python.hpp include/eigenpy/eigen-from-python.hpp include/eigenpy/eigen-typedef.hpp + include/eigenpy/id.hpp include/eigenpy/numpy-map.hpp include/eigenpy/geometry.hpp include/eigenpy/geometry-conversion.hpp diff --git a/include/eigenpy/fwd.hpp b/include/eigenpy/fwd.hpp index c511b5690..acc8edc11 100644 --- a/include/eigenpy/fwd.hpp +++ b/include/eigenpy/fwd.hpp @@ -200,5 +200,6 @@ struct has_operator_equal : internal::has_operator_equal_impl::type {}; } // namespace eigenpy #include "eigenpy/alignment.hpp" +#include "eigenpy/id.hpp" #endif // ifndef __eigenpy_fwd_hpp__ diff --git a/include/eigenpy/id.hpp b/include/eigenpy/id.hpp new file mode 100644 index 000000000..af56d79f1 --- /dev/null +++ b/include/eigenpy/id.hpp @@ -0,0 +1,33 @@ +// +// Copyright (c) 2024 INRIA +// + +#ifndef __eigenpy_id_hpp__ +#define __eigenpy_id_hpp__ + +#include +#include + +namespace eigenpy { + +/// +/// \brief Add the Python method id to retrieving a unique id for a given object +/// exposed with Boost.Python +/// +template +struct IdVisitor : public bp::def_visitor > { + template + void visit(PyClass& cl) const { + cl.def("id", &id, bp::arg("self"), + "Returns the unique identity of an object.\n" + "For object held in C++, it corresponds to its memory address."); + } + + private: + static boost::int64_t id(const C& self) { + return boost::int64_t(reinterpret_cast(&self)); + } +}; +} // namespace eigenpy + +#endif // ifndef __eigenpy_id_hpp__ From 4c12269ec46d33bfe2bf64f40106bc4142b9bb8d Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Mon, 10 Jun 2024 12:21:49 +0200 Subject: [PATCH 2/6] all: add id() helper to all exposed classes --- include/eigenpy/angle-axis.hpp | 3 ++- include/eigenpy/decompositions/EigenSolver.hpp | 4 +++- include/eigenpy/decompositions/LDLT.hpp | 3 ++- include/eigenpy/decompositions/LLT.hpp | 3 ++- include/eigenpy/decompositions/PermutationMatrix.hpp | 1 + .../eigenpy/decompositions/SelfAdjointEigenSolver.hpp | 3 ++- include/eigenpy/decompositions/minres.hpp | 3 ++- include/eigenpy/decompositions/sparse/LDLT.hpp | 3 ++- include/eigenpy/decompositions/sparse/LLT.hpp | 3 ++- include/eigenpy/quaternion.hpp | 3 ++- include/eigenpy/solvers/BFGSPreconditioners.hpp | 3 +++ include/eigenpy/solvers/BasicPreconditioners.hpp | 10 +++++++--- include/eigenpy/solvers/ConjugateGradient.hpp | 3 ++- .../eigenpy/solvers/LeastSquaresConjugateGradient.hpp | 3 ++- include/eigenpy/std-array.hpp | 1 + include/eigenpy/std-vector.hpp | 1 + 16 files changed, 36 insertions(+), 14 deletions(-) diff --git a/include/eigenpy/angle-axis.hpp b/include/eigenpy/angle-axis.hpp index 3f0377c80..d0600c79b 100644 --- a/include/eigenpy/angle-axis.hpp +++ b/include/eigenpy/angle-axis.hpp @@ -118,7 +118,8 @@ class AngleAxisVisitor : public bp::def_visitor > { static void expose() { bp::class_( "AngleAxis", "AngleAxis representation of a rotation.\n\n", bp::no_init) - .def(AngleAxisVisitor()); + .def(AngleAxisVisitor()) + .def(IdVisitor()); // Cast to Eigen::RotationBase bp::implicitly_convertible(); diff --git a/include/eigenpy/decompositions/EigenSolver.hpp b/include/eigenpy/decompositions/EigenSolver.hpp index 3bc447d6a..14583b2e3 100644 --- a/include/eigenpy/decompositions/EigenSolver.hpp +++ b/include/eigenpy/decompositions/EigenSolver.hpp @@ -75,7 +75,9 @@ struct EigenSolverVisitor } static void expose(const std::string& name) { - bp::class_(name.c_str(), bp::no_init).def(EigenSolverVisitor()); + bp::class_(name.c_str(), bp::no_init) + .def(EigenSolverVisitor()) + .def(IdVisitor()); } private: diff --git a/include/eigenpy/decompositions/LDLT.hpp b/include/eigenpy/decompositions/LDLT.hpp index 2a635a217..b148a23a2 100644 --- a/include/eigenpy/decompositions/LDLT.hpp +++ b/include/eigenpy/decompositions/LDLT.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 INRIA + * Copyright 2020-2024 INRIA */ #ifndef __eigenpy_decomposition_ldlt_hpp__ @@ -119,6 +119,7 @@ struct LDLTSolverVisitor "have zeros in the bottom right rank(A) - n submatrix. Avoiding the " "square root on D also stabilizes the computation.", bp::no_init) + .def(IdVisitor()) .def(LDLTSolverVisitor()); } diff --git a/include/eigenpy/decompositions/LLT.hpp b/include/eigenpy/decompositions/LLT.hpp index 1996d6ccb..695c37300 100644 --- a/include/eigenpy/decompositions/LLT.hpp +++ b/include/eigenpy/decompositions/LLT.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 INRIA + * Copyright 2020-2024 INRIA */ #ifndef __eigenpy_decomposition_llt_hpp__ @@ -115,6 +115,7 @@ struct LLTSolverVisitor "remains useful in many other situations like generalised eigen " "problems with hermitian matrices.", bp::no_init) + .def(IdVisitor()) .def(LLTSolverVisitor()); } diff --git a/include/eigenpy/decompositions/PermutationMatrix.hpp b/include/eigenpy/decompositions/PermutationMatrix.hpp index 48d8ce7b8..094bdbaf1 100644 --- a/include/eigenpy/decompositions/PermutationMatrix.hpp +++ b/include/eigenpy/decompositions/PermutationMatrix.hpp @@ -97,6 +97,7 @@ struct PermutationMatrixVisitor "This class represents a permutation matrix, " "internally stored as a vector of integers.", bp::no_init) + .def(IdVisitor()) .def(PermutationMatrixVisitor()); } }; diff --git a/include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp b/include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp index cd1ddd42b..b2587a802 100644 --- a/include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp +++ b/include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2020 INRIA + * Copyright 2020-2024 INRIA */ #ifndef __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__ @@ -84,6 +84,7 @@ struct SelfAdjointEigenSolverVisitor static void expose(const std::string& name) { bp::class_(name.c_str(), bp::no_init) + .def(IdVisitor()) .def(SelfAdjointEigenSolverVisitor()); } diff --git a/include/eigenpy/decompositions/minres.hpp b/include/eigenpy/decompositions/minres.hpp index f2de4e0ca..7f5019c4b 100644 --- a/include/eigenpy/decompositions/minres.hpp +++ b/include/eigenpy/decompositions/minres.hpp @@ -165,7 +165,8 @@ struct MINRESSolverVisitor "defaults are the size of the problem for the maximal number of " "iterations and NumTraits::epsilon() for the tolerance.\n", bp::no_init) - .def(MINRESSolverVisitor()); + .def(MINRESSolverVisitor()) + .def(IdVisitor()); } private: diff --git a/include/eigenpy/decompositions/sparse/LDLT.hpp b/include/eigenpy/decompositions/sparse/LDLT.hpp index d282442cb..0d552e4e8 100644 --- a/include/eigenpy/decompositions/sparse/LDLT.hpp +++ b/include/eigenpy/decompositions/sparse/LDLT.hpp @@ -59,7 +59,8 @@ struct SimplicialLDLTVisitor "prior to the factorization such that the factorized matrix is P A " "P^-1.", bp::no_init) - .def(SimplicialLDLTVisitor()); + .def(SimplicialLDLTVisitor()) + .def(IdVisitor()); } private: diff --git a/include/eigenpy/decompositions/sparse/LLT.hpp b/include/eigenpy/decompositions/sparse/LLT.hpp index 199c25734..3d3fa0d56 100644 --- a/include/eigenpy/decompositions/sparse/LLT.hpp +++ b/include/eigenpy/decompositions/sparse/LLT.hpp @@ -57,7 +57,8 @@ struct SimplicialLLTVisitor "prior to the factorization such that the factorized matrix is P A " "P^-1.", bp::no_init) - .def(SimplicialLLTVisitor()); + .def(SimplicialLLTVisitor()) + .def(IdVisitor()); } }; diff --git a/include/eigenpy/quaternion.hpp b/include/eigenpy/quaternion.hpp index a5051c154..69a72b9ea 100644 --- a/include/eigenpy/quaternion.hpp +++ b/include/eigenpy/quaternion.hpp @@ -364,7 +364,8 @@ class QuaternionVisitor "'q*v' (rotating 'v' by 'q'), " "'q==q', 'q!=q', 'q[0..3]'.", bp::no_init) - .def(QuaternionVisitor()); + .def(QuaternionVisitor()) + .def(IdVisitor()); // Cast to Eigen::QuaternionBase and vice-versa bp::implicitly_convertible(); diff --git a/include/eigenpy/solvers/BFGSPreconditioners.hpp b/include/eigenpy/solvers/BFGSPreconditioners.hpp index 2fd368339..53c4ad433 100644 --- a/include/eigenpy/solvers/BFGSPreconditioners.hpp +++ b/include/eigenpy/solvers/BFGSPreconditioners.hpp @@ -1,5 +1,6 @@ /* * Copyright 2017 CNRS + * Copyright 2024 Inria */ #ifndef __eigenpy_bfgs_preconditioners_hpp__ @@ -37,6 +38,7 @@ struct BFGSPreconditionerBaseVisitor static void expose(const std::string& name) { bp::class_(name, bp::no_init) + .def(IdVisitor()) .def(BFGSPreconditionerBaseVisitor()); } }; @@ -56,6 +58,7 @@ struct LimitedBFGSPreconditionerBaseVisitor static void expose(const std::string& name) { bp::class_(name.c_str(), bp::no_init) + .def(IdVisitor()) .def(LimitedBFGSPreconditionerBaseVisitor()); } }; diff --git a/include/eigenpy/solvers/BasicPreconditioners.hpp b/include/eigenpy/solvers/BasicPreconditioners.hpp index d74ee3f22..d7c4f3c52 100644 --- a/include/eigenpy/solvers/BasicPreconditioners.hpp +++ b/include/eigenpy/solvers/BasicPreconditioners.hpp @@ -1,5 +1,6 @@ /* * Copyright 2017 CNRS + * Copyright 2014 Inria */ #ifndef __eigenpy_basic_preconditioners_hpp__ @@ -69,7 +70,8 @@ struct DiagonalPreconditionerVisitor "A preconditioner based on the digonal entrie.\n" "This class allows to approximately solve for A.x = b problems " "assuming A is a diagonal matrix.", - bp::no_init); + bp::no_init) + .def(IdVisitor()); } }; @@ -91,7 +93,8 @@ struct LeastSquareDiagonalPreconditionerVisitor "his class allows to approximately solve for A' A x = A' b problems " "assuming A' A is a diagonal matrix.", bp::no_init) - .def(DiagonalPreconditionerVisitor()); + .def(DiagonalPreconditionerVisitor()) + .def(IdVisitor()); } }; #endif @@ -105,7 +108,8 @@ struct IdentityPreconditionerVisitor static void expose() { bp::class_("IdentityPreconditioner", bp::no_init) - .def(PreconditionerBaseVisitor()); + .def(PreconditionerBaseVisitor()) + .def(IdVisitor()); } }; diff --git a/include/eigenpy/solvers/ConjugateGradient.hpp b/include/eigenpy/solvers/ConjugateGradient.hpp index 6f41e9d78..1d3d71aff 100644 --- a/include/eigenpy/solvers/ConjugateGradient.hpp +++ b/include/eigenpy/solvers/ConjugateGradient.hpp @@ -31,7 +31,8 @@ struct ConjugateGradientVisitor static void expose(const std::string& name = "ConjugateGradient") { bp::class_(name.c_str(), bp::no_init) - .def(ConjugateGradientVisitor()); + .def(ConjugateGradientVisitor()) + .def(IdVisitor()); } }; diff --git a/include/eigenpy/solvers/LeastSquaresConjugateGradient.hpp b/include/eigenpy/solvers/LeastSquaresConjugateGradient.hpp index 3107270e0..21464ae61 100644 --- a/include/eigenpy/solvers/LeastSquaresConjugateGradient.hpp +++ b/include/eigenpy/solvers/LeastSquaresConjugateGradient.hpp @@ -34,7 +34,8 @@ struct LeastSquaresConjugateGradientVisitor "LeastSquaresConjugateGradient", bp::no_init) .def(IterativeSolverVisitor()) .def(LeastSquaresConjugateGradientVisitor< - LeastSquaresConjugateGradient>()); + LeastSquaresConjugateGradient>()) + .def(IdVisitor()); } }; diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 492e00320..19ea821b4 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -135,6 +135,7 @@ struct StdArrayPythonVisitor { bp::class_ cl(class_name.c_str(), doc_string.c_str()); cl.def(bp::init(bp::args("self", "other"), "Copy constructor")); + cl.def(IdVisitor()); array_indexing_suite indexing_suite; cl.def(indexing_suite) diff --git a/include/eigenpy/std-vector.hpp b/include/eigenpy/std-vector.hpp index 0c5e3bf6e..2dbdabfd2 100644 --- a/include/eigenpy/std-vector.hpp +++ b/include/eigenpy/std-vector.hpp @@ -454,6 +454,7 @@ struct StdVectorPythonVisitor { if (!register_symbolic_link_to_registered_type( add_std_visitor)) { bp::class_ cl(class_name.c_str(), doc_string.c_str()); + cl.def(IdVisitor()); // Standard vector indexing definition boost::python::vector_indexing_suite< From 785502b9049858b9d449ee63e7bf556661f6849a Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Mon, 10 Jun 2024 12:27:03 +0200 Subject: [PATCH 3/6] test: add test of id helper --- unittest/CMakeLists.txt | 1 + unittest/python/test_id.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 unittest/python/test_id.py diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 72bfb1bb3..4453547a4 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -113,6 +113,7 @@ add_python_lib_unit_test("py-deprecation-policy" add_python_lib_unit_test("py-return-by-ref" "unittest/python/test_return_by_ref.py") add_python_lib_unit_test("py-eigen-ref" "unittest/python/test_eigen_ref.py") +add_python_lib_unit_test("py-id" "unittest/python/test_id.py") if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT) add_python_lib_unit_test("py-user-type" "unittest/python/test_user_type.py") diff --git a/unittest/python/test_id.py b/unittest/python/test_id.py new file mode 100644 index 000000000..c6d87bb5e --- /dev/null +++ b/unittest/python/test_id.py @@ -0,0 +1,11 @@ +import eigenpy + +ldlt1 = eigenpy.LDLT() +ldlt2 = eigenpy.LDLT() + +id1 = ldlt1.id() +id2 = ldlt2.id() + +assert id1 != id2 +assert id1 == ldlt1.id() +assert id2 == ldlt2.id() From b3c9d54d2fb8e28dbc4024dd7f453cd11b789c8d Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Mon, 10 Jun 2024 12:29:27 +0200 Subject: [PATCH 4/6] changelog: sync --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 156a578d9..0a38a1c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Added a deprecation call policy shortcut ([#466](https://github.com/stack-of-tasks/eigenpy/pull/466)) +- Added id() helper to retrieve unique object identifier in Python ([#477](https://github.com/stack-of-tasks/eigenpy/pull/477)) ### Fixed - Fix register_symbolic_link_to_registered_type() for multiple successive registrations ([#471](https://github.com/stack-of-tasks/eigenpy/pull/471)) From 66f2e3cb930e1a219263a983e056e4cf0c875019 Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Mon, 10 Jun 2024 12:38:35 +0200 Subject: [PATCH 5/6] core: fix copyright Co-authored-by: Guilhem Saurel --- include/eigenpy/solvers/BasicPreconditioners.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/eigenpy/solvers/BasicPreconditioners.hpp b/include/eigenpy/solvers/BasicPreconditioners.hpp index d7c4f3c52..fb65f2028 100644 --- a/include/eigenpy/solvers/BasicPreconditioners.hpp +++ b/include/eigenpy/solvers/BasicPreconditioners.hpp @@ -1,6 +1,6 @@ /* * Copyright 2017 CNRS - * Copyright 2014 Inria + * Copyright 2024 Inria */ #ifndef __eigenpy_basic_preconditioners_hpp__ From ee2748a039044bb4eac9e8a12c06171b91f54aee Mon Sep 17 00:00:00 2001 From: Justin Carpentier Date: Mon, 10 Jun 2024 14:56:17 +0200 Subject: [PATCH 6/6] cmake: fix eigenpy test --- unittest/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 4453547a4..38f75745f 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -113,7 +113,6 @@ add_python_lib_unit_test("py-deprecation-policy" add_python_lib_unit_test("py-return-by-ref" "unittest/python/test_return_by_ref.py") add_python_lib_unit_test("py-eigen-ref" "unittest/python/test_eigen_ref.py") -add_python_lib_unit_test("py-id" "unittest/python/test_id.py") if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT) add_python_lib_unit_test("py-user-type" "unittest/python/test_user_type.py") @@ -135,6 +134,8 @@ add_python_eigenpy_lib_unit_test("py-LLT" "unittest/python/test_LLT.py") add_python_eigenpy_lib_unit_test("py-LDLT" "unittest/python/test_LDLT.py") +add_python_eigenpy_lib_unit_test("py-id" "unittest/python/test_id.py") + if(NOT WIN32) add_python_eigenpy_lib_unit_test("py-MINRES" "unittest/python/test_MINRES.py") endif(NOT WIN32)