From bf02d84a4a2aa2b174dcf79e0240c63aab16266d Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 18:55:47 +0100 Subject: [PATCH 01/27] [std-vector] StdContainerFromPythonList : remove Allocator typedef + does not exist on all container types --- include/eigenpy/std-vector.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/eigenpy/std-vector.hpp b/include/eigenpy/std-vector.hpp index c69887b85..ea2f91a17 100644 --- a/include/eigenpy/std-vector.hpp +++ b/include/eigenpy/std-vector.hpp @@ -242,7 +242,6 @@ namespace eigenpy { template struct StdContainerFromPythonList { typedef typename vector_type::value_type T; - typedef typename vector_type::allocator_type Allocator; /// \brief Check if obj_ptr can be converted static void *convertible(PyObject *obj_ptr) { From 4f0756553f35b283bc3e0bacbb5482288f952927 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:03:14 +0100 Subject: [PATCH 02/27] Add header eigenpy/std-array.hpp + add eigenpy::array_indexing_suite + add eigenpy::StdArrayPythonVisitor + add function template exposeStdArrayEigenSpecificType --- include/eigenpy/std-array.hpp | 128 ++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 include/eigenpy/std-array.hpp diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp new file mode 100644 index 000000000..5ad2b54b5 --- /dev/null +++ b/include/eigenpy/std-array.hpp @@ -0,0 +1,128 @@ +/// Copyright (c) 2023 CNRS INRIA + +#ifndef __eigenpy_utils_std_array_hpp__ +#define __eigenpy_utils_std_array_hpp__ + +#include +#include "eigenpy/std-vector.hpp" + +#include + +namespace eigenpy { + +template +class array_indexing_suite; +namespace details { + +template +class final_array_derived_policies + : public array_indexing_suite< + Container, NoProxy, + final_array_derived_policies > {}; +} // namespace details + +template > +class array_indexing_suite + : public bp::vector_indexing_suite { + public: + typedef typename Container::value_type data_type; + typedef typename Container::value_type key_type; + typedef typename Container::size_type index_type; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + + template + static void extension_def(Class &) {} + + template + static void extend(Container &, Iter, Iter) {} + + static void append(Container &, data_type const &) {} + // no-op + static void delete_item(Container &, index_type) {} + // no-op + // no-op + static void delete_slice(Container &, index_type, + index_type) {} + + static void set_slice(Container &container, index_type from, index_type to, + data_type const &v) { + if (from > to) { + return; + } else { + std::fill(container.begin() + from, container.begin() + to, v); + } + } + + template + static void set_slice(Container &container, index_type from, index_type to, + Iter first, Iter last) { + if (from > to) { + // container.insert(container.begin() + from, first, last); + return; + } else { + // container.erase(container.begin() + from, container.begin() + to); + // container.insert(container.begin() + from, first, last); + } + } + + static bp::object get_slice(Container &container, index_type from, + index_type to) { + if (from > to) return bp::object(Container()); + + Container out; + std::copy(container.begin() + from, container.begin() + to, out.begin()); + return bp::object(std::move(out)); + } +}; + + +template +struct StdArrayPythonVisitor { + typedef typename array_type::value_type value_type; + /// Fixed size of the array, known at compile time + static constexpr std::size_t Size = std::tuple_size{}; + + static void expose(const std::string &class_name, + const std::string &doc_string = "") { + expose(class_name, doc_string, EmptyPythonVisitor()); + } + + template + static void expose(const std::string &class_name, + const bp::def_visitor &visitor) { + expose(class_name, "", visitor); + } + + template + static void expose(const std::string &class_name, + const std::string &doc_string, + const bp::def_visitor &) { + if (!register_symbolic_link_to_registered_type()) { + bp::class_ cl(class_name.c_str(), doc_string.c_str()); + cl.def(bp::init(bp::args("self", "other"), + "Copy constructor")); + + array_indexing_suite indexing_suite; + cl.def(indexing_suite); + } + } +}; + +/// Exposes std::array +template +void exposeStdArrayEigenSpecificType(const char *name) { + std::ostringstream oss; + oss << "StdArr"; + oss << Size << "_" << name; + typedef std::array array_type; + StdArrayPythonVisitor::expose( + oss.str(), details::overload_base_get_item_for_std_vector()); +} + +} // namespace eigenpy + +#endif // ifndef __eigenpy_utils_std_array_hpp__ From dd8071d4948c6b2b6752f2e7ab0d596c8eb2ee8b Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:04:08 +0100 Subject: [PATCH 03/27] [std-array] array_indexing_suite: fix up set_sice from iterators --- include/eigenpy/std-array.hpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 5ad2b54b5..187b31f70 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -10,8 +10,7 @@ namespace eigenpy { -template +template class array_indexing_suite; namespace details { @@ -45,8 +44,7 @@ class array_indexing_suite static void delete_item(Container &, index_type) {} // no-op // no-op - static void delete_slice(Container &, index_type, - index_type) {} + static void delete_slice(Container &, index_type, index_type) {} static void set_slice(Container &container, index_type from, index_type to, data_type const &v) { @@ -61,11 +59,9 @@ class array_indexing_suite static void set_slice(Container &container, index_type from, index_type to, Iter first, Iter last) { if (from > to) { - // container.insert(container.begin() + from, first, last); return; } else { - // container.erase(container.begin() + from, container.begin() + to); - // container.insert(container.begin() + from, first, last); + std::copy(first, last, container.begin() + from); } } @@ -79,7 +75,6 @@ class array_indexing_suite } }; - template struct StdArrayPythonVisitor { typedef typename array_type::value_type value_type; From d0f7674ae8041da399861b23a6d9e66e43034d3a Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:04:28 +0100 Subject: [PATCH 04/27] [unittest] add unit tests for std::array --- unittest/CMakeLists.txt | 5 +++++ unittest/python/test_std_array.py | 13 +++++++++++++ unittest/std_array.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 unittest/python/test_std_array.py create mode 100644 unittest/std_array.cpp diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 7da4556f6..7737f07ed 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -38,6 +38,7 @@ if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT) add_lib_unit_test(user_type) endif() add_lib_unit_test(std_vector) +add_lib_unit_test(std_array) add_lib_unit_test(user_struct) function(config_bind_optional tagname opttype) @@ -110,6 +111,10 @@ add_python_unit_test("py-std-vector" "unittest/python/test_std_vector.py" "python;unittest") set_tests_properties("py-std-vector" PROPERTIES DEPENDS ${PYWRAP}) +add_python_unit_test("py-std-array" "unittest/python/test_std_array.py" + "python;unittest") +set_tests_properties("py-std-array" PROPERTIES DEPENDS ${PYWRAP}) + add_python_unit_test("py-user-struct" "unittest/python/test_user_struct.py" "python;unittest") set_tests_properties("py-user-struct" PROPERTIES DEPENDS ${PYWRAP}) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py new file mode 100644 index 000000000..d2a414462 --- /dev/null +++ b/unittest/python/test_std_array.py @@ -0,0 +1,13 @@ +import std_array + + +ints = std_array.get_arr_3_ints() +print(ints[0]) +print(ints[1]) +print(ints[2]) +print(ints.tolist()) + +vecs = std_array.get_arr_3_vecs() +print(vecs[0]) +print(vecs[1]) +print(vecs[2]) diff --git a/unittest/std_array.cpp b/unittest/std_array.cpp new file mode 100644 index 000000000..a662a28f1 --- /dev/null +++ b/unittest/std_array.cpp @@ -0,0 +1,28 @@ +/// @file +/// @copyright Copyright 2023 CNRS INRIA + +#include "eigenpy/std-array.hpp" + +using Eigen::VectorXd; + +std::array get_arr_3_ints() { return {1, 2, 3}; } + +std::array get_arr_3_vecs() { + std::array out; + out[0].setOnes(4); + out[1].setZero(2); + out[2].setRandom(10); + return out; +} + +BOOST_PYTHON_MODULE(std_array) { + using namespace eigenpy; + + enableEigenPy(); + + StdArrayPythonVisitor >::expose("StdArr3_int"); + exposeStdArrayEigenSpecificType("VectorXd"); + + bp::def("get_arr_3_ints", get_arr_3_ints); + bp::def("get_arr_3_vecs", get_arr_3_vecs); +} From 6211cf547d61abd42640050cb4461d6474bb8af0 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:18:25 +0100 Subject: [PATCH 05/27] [std-array] array_indexing_suite: get_slice returns std::vector --- include/eigenpy/std-array.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 187b31f70..299f884c1 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -32,6 +32,7 @@ class array_indexing_suite typedef typename Container::size_type index_type; typedef typename Container::size_type size_type; typedef typename Container::difference_type difference_type; + static constexpr std::size_t Size = std::tuple_size{}; template static void extension_def(Class &) {} @@ -67,10 +68,12 @@ class array_indexing_suite static bp::object get_slice(Container &container, index_type from, index_type to) { - if (from > to) return bp::object(Container()); - - Container out; - std::copy(container.begin() + from, container.begin() + to, out.begin()); + if (from > to) return bp::object(std::array()); + size_t size = to - from + 1; // will be >= 0 + std::vector out; + for (size_t i = 0; i < size; i++) { + out.push_back(container[i]); + } return bp::object(std::move(out)); } }; From 153ba3e93370ac3df2cb45f66ee9e4ab53398a98 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:21:22 +0100 Subject: [PATCH 06/27] [unittest] std::array test: test for size of _ints_slice --- unittest/python/test_std_array.py | 6 ++++++ unittest/std_array.cpp | 1 + 2 files changed, 7 insertions(+) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index d2a414462..b97ae3881 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -5,6 +5,12 @@ print(ints[0]) print(ints[1]) print(ints[2]) + +_ints_slice = ints[1:2] +assert len(_ints_slice) == 2, "Slice size should be 2, got %d" % len(_ints_slice) +assert _ints_slice[0] == 1 +assert _ints_slice[1] == 2 + print(ints.tolist()) vecs = std_array.get_arr_3_vecs() diff --git a/unittest/std_array.cpp b/unittest/std_array.cpp index a662a28f1..05174581d 100644 --- a/unittest/std_array.cpp +++ b/unittest/std_array.cpp @@ -21,6 +21,7 @@ BOOST_PYTHON_MODULE(std_array) { enableEigenPy(); StdArrayPythonVisitor >::expose("StdArr3_int"); + StdVectorPythonVisitor, true>::expose("StdVec_int"); exposeStdArrayEigenSpecificType("VectorXd"); bp::def("get_arr_3_ints", get_arr_3_ints); From f9e84ec626e1a3a55534d5d2d298820b8ae35bb9 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:30:52 +0100 Subject: [PATCH 07/27] [std-array] add SliceAllocator template parameter + sets allocator for the std::vector returned by get_slice --- include/eigenpy/std-array.hpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 299f884c1..aa9ff868a 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -10,20 +10,22 @@ namespace eigenpy { -template +template class array_indexing_suite; namespace details { -template +template class final_array_derived_policies : public array_indexing_suite< - Container, NoProxy, - final_array_derived_policies > {}; + Container, NoProxy, SliceAllocator, + final_array_derived_policies > {}; } // namespace details template > + class SliceAllocator = std::allocator, + class DerivedPolicies = details::final_array_derived_policies< + Container, NoProxy, SliceAllocator> > class array_indexing_suite : public bp::vector_indexing_suite { public: @@ -32,6 +34,7 @@ class array_indexing_suite typedef typename Container::size_type index_type; typedef typename Container::size_type size_type; typedef typename Container::difference_type difference_type; + typedef std::vector slice_vector_type; static constexpr std::size_t Size = std::tuple_size{}; template @@ -70,7 +73,7 @@ class array_indexing_suite index_type to) { if (from > to) return bp::object(std::array()); size_t size = to - from + 1; // will be >= 0 - std::vector out; + slice_vector_type out; for (size_t i = 0; i < size; i++) { out.push_back(container[i]); } From a9903adda0af68260de23a3db4937e22032cc5ea Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:31:56 +0100 Subject: [PATCH 08/27] [std-array] add SliceAllocator template parameter to StdArrayPythonVisitor + shortcut function exposeStdArrayEigenSpecificType now uses Eigen::aligned_allocator for the slice vector --- include/eigenpy/std-array.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index aa9ff868a..77cf76c15 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -81,7 +81,9 @@ class array_indexing_suite } }; -template +template > struct StdArrayPythonVisitor { typedef typename array_type::value_type value_type; /// Fixed size of the array, known at compile time @@ -107,7 +109,7 @@ struct StdArrayPythonVisitor { cl.def(bp::init(bp::args("self", "other"), "Copy constructor")); - array_indexing_suite indexing_suite; + array_indexing_suite indexing_suite; cl.def(indexing_suite); } } @@ -120,8 +122,10 @@ void exposeStdArrayEigenSpecificType(const char *name) { oss << "StdArr"; oss << Size << "_" << name; typedef std::array array_type; - StdArrayPythonVisitor::expose( - oss.str(), details::overload_base_get_item_for_std_vector()); + StdArrayPythonVisitor >:: + expose(oss.str(), + details::overload_base_get_item_for_std_vector()); } } // namespace eigenpy From 2cbf10edf724f5eff7cd7e553562c510ae4070c0 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:42:34 +0100 Subject: [PATCH 09/27] [std-array] fix size of returned slice --- include/eigenpy/std-array.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 77cf76c15..58033cd87 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -72,9 +72,8 @@ class array_indexing_suite static bp::object get_slice(Container &container, index_type from, index_type to) { if (from > to) return bp::object(std::array()); - size_t size = to - from + 1; // will be >= 0 slice_vector_type out; - for (size_t i = 0; i < size; i++) { + for (size_t i = from; i < to; i++) { out.push_back(container[i]); } return bp::object(std::move(out)); From 5e601842fc0fe8bbc34208335cda35cf14c7a857 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:42:56 +0100 Subject: [PATCH 10/27] [unittest] expose std::vector for use in slices --- unittest/std_array.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unittest/std_array.cpp b/unittest/std_array.cpp index 05174581d..035b4b9c9 100644 --- a/unittest/std_array.cpp +++ b/unittest/std_array.cpp @@ -22,7 +22,9 @@ BOOST_PYTHON_MODULE(std_array) { StdArrayPythonVisitor >::expose("StdArr3_int"); StdVectorPythonVisitor, true>::expose("StdVec_int"); + exposeStdArrayEigenSpecificType("VectorXd"); + exposeStdVectorEigenSpecificType("VectorXd"); bp::def("get_arr_3_ints", get_arr_3_ints); bp::def("get_arr_3_vecs", get_arr_3_vecs); From ced90028e42a94079581b53ac746fa9714670f90 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:43:07 +0100 Subject: [PATCH 11/27] [unittest/python] update test_std_array.py --- unittest/python/test_std_array.py | 32 +++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index b97ae3881..8124e3e26 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -6,14 +6,30 @@ print(ints[1]) print(ints[2]) -_ints_slice = ints[1:2] -assert len(_ints_slice) == 2, "Slice size should be 2, got %d" % len(_ints_slice) -assert _ints_slice[0] == 1 -assert _ints_slice[1] == 2 +_ints_slice = ints[1:3] +print("Printing slice...") +for el in _ints_slice: + print(el) -print(ints.tolist()) +ref = [1, 2, 3] +assert len(ref[1:2]) == 1 # sanity check + +assert len(_ints_slice) == 2, "Slice size should be 1, got %d" % len(_ints_slice) +assert _ints_slice[0] == 2 +assert _ints_slice[1] == 3 + +# print(ints.tolist()) vecs = std_array.get_arr_3_vecs() -print(vecs[0]) -print(vecs[1]) -print(vecs[2]) +assert len(vecs) == 3 +# print(vecs[0]) +# print(vecs[1]) +# print(vecs[2]) + +## Tests for the full-size slice + +v2 = vecs[:] +assert isinstance(v2, std_array.StdVec_VectorXd) +assert len(v2) == 3 +print(v2.tolist()) +print(v2[0]) From 82ec7849d5e6928e774c8d177285feae371f46ca Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:47:12 +0100 Subject: [PATCH 12/27] [std-array] use visitor in StdArrayPythonVisitor::expose() --- include/eigenpy/std-array.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 58033cd87..426598e5b 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -102,7 +102,7 @@ struct StdArrayPythonVisitor { template static void expose(const std::string &class_name, const std::string &doc_string, - const bp::def_visitor &) { + const bp::def_visitor &visitor) { if (!register_symbolic_link_to_registered_type()) { bp::class_ cl(class_name.c_str(), doc_string.c_str()); cl.def(bp::init(bp::args("self", "other"), @@ -110,6 +110,7 @@ struct StdArrayPythonVisitor { array_indexing_suite indexing_suite; cl.def(indexing_suite); + cl.def(visitor); } } }; From 5d487e88671e8654af3e03b41666f5dca18efc7c Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:50:20 +0100 Subject: [PATCH 13/27] [unittest/python] update test_std_array.py + do not test slice for std::array --- unittest/python/test_std_array.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index 8124e3e26..ca7c404dc 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -22,14 +22,14 @@ vecs = std_array.get_arr_3_vecs() assert len(vecs) == 3 -# print(vecs[0]) -# print(vecs[1]) -# print(vecs[2]) +print(vecs[0]) +print(vecs[1]) +print(vecs[2]) -## Tests for the full-size slice +# slices do not work for Eigen objects... -v2 = vecs[:] -assert isinstance(v2, std_array.StdVec_VectorXd) -assert len(v2) == 3 -print(v2.tolist()) -print(v2[0]) +# v2 = vecs[:] +# assert isinstance(v2, std_array.StdVec_VectorXd) +# assert len(v2) == 3 +# print(v2.tolist()) +# print(v2[0]) From ba6751b3e3ded35786b7f5806395977bd239b82a Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:56:36 +0100 Subject: [PATCH 14/27] [unittest] std_array : add test_struct [unittest/python] add test_struct --- unittest/python/test_std_array.py | 12 ++++++++++++ unittest/std_array.cpp | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index ca7c404dc..8419cd3c2 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -33,3 +33,15 @@ # assert len(v2) == 3 # print(v2.tolist()) # print(v2[0]) + +ts = std_array.test_struct() +assert len(ts.integs) == 3 +assert len(ts.vecs) == 2 +print(ts.integs[:].tolist()) +print(ts.vecs[0]) +print(ts.vecs[1]) + +ts.vecs[0][0] = 0. +ts.vecs[1][0] = -243 +print(ts.vecs[0]) +print(ts.vecs[1]) diff --git a/unittest/std_array.cpp b/unittest/std_array.cpp index 035b4b9c9..d1f03e216 100644 --- a/unittest/std_array.cpp +++ b/unittest/std_array.cpp @@ -15,6 +15,17 @@ std::array get_arr_3_vecs() { return out; } +struct test_struct { + std::array integs; + std::array vecs; + test_struct() { + integs = {42, 3, -1}; + vecs[0].setRandom(4); // 4 randoms between [-1,1] + vecs[1].setZero(11); // 11 zeroes + } +}; + + BOOST_PYTHON_MODULE(std_array) { using namespace eigenpy; @@ -23,9 +34,14 @@ BOOST_PYTHON_MODULE(std_array) { StdArrayPythonVisitor >::expose("StdArr3_int"); StdVectorPythonVisitor, true>::expose("StdVec_int"); + exposeStdArrayEigenSpecificType("VectorXd"); exposeStdArrayEigenSpecificType("VectorXd"); exposeStdVectorEigenSpecificType("VectorXd"); bp::def("get_arr_3_ints", get_arr_3_ints); bp::def("get_arr_3_vecs", get_arr_3_vecs); + + bp::class_("test_struct", bp::init<>(bp::args("self"))) + .def_readwrite("integs", &test_struct::integs) + .def_readwrite("vecs", &test_struct::vecs); } From a03deb80fc16fa6f48f5ee2e5339ec9bd4bad74d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:56:49 +0000 Subject: [PATCH 15/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- unittest/python/test_std_array.py | 2 +- unittest/std_array.cpp | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index 8419cd3c2..149a65841 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -41,7 +41,7 @@ print(ts.vecs[0]) print(ts.vecs[1]) -ts.vecs[0][0] = 0. +ts.vecs[0][0] = 0.0 ts.vecs[1][0] = -243 print(ts.vecs[0]) print(ts.vecs[1]) diff --git a/unittest/std_array.cpp b/unittest/std_array.cpp index d1f03e216..df276ad75 100644 --- a/unittest/std_array.cpp +++ b/unittest/std_array.cpp @@ -21,11 +21,10 @@ struct test_struct { test_struct() { integs = {42, 3, -1}; vecs[0].setRandom(4); // 4 randoms between [-1,1] - vecs[1].setZero(11); // 11 zeroes + vecs[1].setZero(11); // 11 zeroes } }; - BOOST_PYTHON_MODULE(std_array) { using namespace eigenpy; @@ -42,6 +41,6 @@ BOOST_PYTHON_MODULE(std_array) { bp::def("get_arr_3_vecs", get_arr_3_vecs); bp::class_("test_struct", bp::init<>(bp::args("self"))) - .def_readwrite("integs", &test_struct::integs) - .def_readwrite("vecs", &test_struct::vecs); + .def_readwrite("integs", &test_struct::integs) + .def_readwrite("vecs", &test_struct::vecs); } From 70bae63af128ad94c3406588cbe164e10bd27612 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 19:59:15 +0100 Subject: [PATCH 16/27] [std-array] add docstring for StdArrayPythonVisitor --- include/eigenpy/std-array.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 426598e5b..e84f1bd8f 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -80,6 +80,13 @@ class array_indexing_suite } }; +/// \brief Expose an std::array (a C++11 fixed-size array) from a given type +/// \tparam array_type std::array type to expose +/// \tparam NoProxy When set to false, the elements will be copied when +/// returned to Python. +/// \tparam SliceAllocator Allocator type to use for slices of std::array type +/// accessed using e.g. __getitem__[0:4] in Python. These slices are returned as +/// std::vector (dynamic size). template > From 384c19346cea9f54dac2720d2b9729cbb9b14044 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 20:05:32 +0100 Subject: [PATCH 17/27] [unittest/python] test set_slice on std::array --- unittest/python/test_std_array.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index 149a65841..c367111b9 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -41,6 +41,11 @@ print(ts.vecs[0]) print(ts.vecs[1]) +ts.integs[:] = 111 +print("Test of set_slice for std::array:", ts.integs[:].tolist()) +for el in ts.integs: + assert el == 111 + ts.vecs[0][0] = 0.0 ts.vecs[1][0] = -243 print(ts.vecs[0]) From 36d2ba383345c5df24fef3d14ab4ba35d85fbad0 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Thu, 30 Nov 2023 20:16:53 +0100 Subject: [PATCH 18/27] [cmake] I forgot to add the std-array.hpp header... --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96a80995f..3d06700a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ set(${PROJECT_NAME}_HEADERS include/eigenpy/user-type.hpp include/eigenpy/ufunc.hpp include/eigenpy/register.hpp + include/eigenpy/std-array.hpp include/eigenpy/std-map.hpp include/eigenpy/std-vector.hpp include/eigenpy/optional.hpp From 58571e5303bf4b151e91b704acd0d9ab4488f599 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Fri, 1 Dec 2023 00:15:19 +0100 Subject: [PATCH 19/27] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea829eca..2411a6827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Added +- Support for C++11 `std::array` types + ## [3.1.4] - 2023-11-27 ### Added From dc9789e27b8bdec1f1f0e539269254f9dc605878 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 12:03:43 +0100 Subject: [PATCH 20/27] [std-vector] add container_traits struct + use ::allocator_type typedef by default, set as void for std::array --- include/eigenpy/std-vector.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/eigenpy/std-vector.hpp b/include/eigenpy/std-vector.hpp index ea2f91a17..783307465 100644 --- a/include/eigenpy/std-vector.hpp +++ b/include/eigenpy/std-vector.hpp @@ -234,6 +234,20 @@ struct reference_arg_from_python &> namespace eigenpy { +namespace details { +/// Defines traits for the container, used in \struct StdContainerFromPythonList +template +struct container_traits { + // default behavior expects allocators + typedef typename Container::allocator_type Allocator; +}; + +template +struct container_traits > { + typedef void Allocator; +}; +}; // namespace details + /// /// \brief Register the conversion from a Python list to a std::vector /// @@ -242,6 +256,7 @@ namespace eigenpy { template struct StdContainerFromPythonList { typedef typename vector_type::value_type T; + typedef typename details::container_traits::Allocator Allocator; /// \brief Check if obj_ptr can be converted static void *convertible(PyObject *obj_ptr) { From f4d61ccc8e132c55268e203c18e789b33e0bfb60 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 12:09:25 +0100 Subject: [PATCH 21/27] [std-array] defining array_indexing_suite::extend and ::append not required --- include/eigenpy/std-array.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index e84f1bd8f..96ea2ef7e 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -40,10 +40,6 @@ class array_indexing_suite template static void extension_def(Class &) {} - template - static void extend(Container &, Iter, Iter) {} - - static void append(Container &, data_type const &) {} // no-op static void delete_item(Container &, index_type) {} // no-op From 2c180895840de07912e2a009377926447014751d Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 12:12:45 +0100 Subject: [PATCH 22/27] [std-array] array_indexing_suite::delete_item and ::delete_slice will throw Python exceptions --- include/eigenpy/std-array.hpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 96ea2ef7e..14889da6e 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -40,11 +40,19 @@ class array_indexing_suite template static void extension_def(Class &) {} - // no-op - static void delete_item(Container &, index_type) {} - // no-op - // no-op - static void delete_slice(Container &, index_type, index_type) {} + // throws exception + static void delete_item(Container &, index_type) { + PyErr_SetString(PyExc_NotImplementedError, + "Cannot delete item from std::array type."); + bp::throw_error_already_set(); + } + + // throws exception + static void delete_slice(Container &, index_type, index_type) { + PyErr_SetString(PyExc_NotImplementedError, + "Cannot delete slice from std::array type."); + bp::throw_error_already_set(); + } static void set_slice(Container &container, index_type from, index_type to, data_type const &v) { From 70e518dce1a3de3b57a14ad20a3f2506ac15098b Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 15:42:29 +0100 Subject: [PATCH 23/27] [std-array] various fixes + empty get_slice should return the slice type StdVec + set_slice with from >= to should throw + set_slice with incompatible iterator and slice sizes should throw --- include/eigenpy/std-array.hpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index 14889da6e..e35710e1b 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -56,8 +56,11 @@ class array_indexing_suite static void set_slice(Container &container, index_type from, index_type to, data_type const &v) { - if (from > to) { - return; + if (from >= to) { + PyErr_SetString(PyExc_NotImplementedError, + "Setting this slice would insert into an std::array, " + "which is not supported."); + bp::throw_error_already_set(); } else { std::fill(container.begin() + from, container.begin() + to, v); } @@ -66,16 +69,26 @@ class array_indexing_suite template static void set_slice(Container &container, index_type from, index_type to, Iter first, Iter last) { - if (from > to) { - return; + if (from >= to) { + PyErr_SetString(PyExc_NotImplementedError, + "Setting this slice would insert into an std::array, " + "which is not supported."); + bp::throw_error_already_set(); } else { - std::copy(first, last, container.begin() + from); + if (long(to - from) == std::distance(first, last)) { + std::copy(first, last, container.begin() + from); + } else { + PyErr_SetString(PyExc_NotImplementedError, + "Size of std::array slice and size of right-hand side " + "iterator are incompatible."); + bp::throw_error_already_set(); + } } } static bp::object get_slice(Container &container, index_type from, index_type to) { - if (from > to) return bp::object(std::array()); + if (from > to) return bp::object(slice_vector_type()); slice_vector_type out; for (size_t i = from; i < to; i++) { out.push_back(container[i]); From 6ad644872ba786eccac7b4eb00c1c72e9ecd7af8 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 15:55:17 +0100 Subject: [PATCH 24/27] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2411a6827..188e37fac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Added -- Support for C++11 `std::array` types +- Support for C++11 `std::array` types ([#412](https://github.com/stack-of-tasks/pull/412)) ## [3.1.4] - 2023-11-27 From cc30e4643dd124f02d10e5b399a2ecde843bdab4 Mon Sep 17 00:00:00 2001 From: Joris Vaillant Date: Mon, 4 Dec 2023 16:19:42 +0100 Subject: [PATCH 25/27] [std-array] Test array edge cases --- unittest/python/test_std_array.py | 89 +++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index c367111b9..505f57850 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -18,6 +18,95 @@ assert _ints_slice[0] == 2 assert _ints_slice[1] == 3 +# Test that insert/delete is impossible with the slice operator + +# prepend +try: + ints[0:0] = [0, 1] +except NotImplementedError: + pass +else: + assert False, "Insert value with slice operator should be impossible" + +# append +try: + ints[10:12] = [0] +except NotImplementedError: + pass +else: + assert False, "Insert value with slice operator should be impossible" + +# append +try: + ints[3:3] = [0] +except NotImplementedError: + pass +else: + assert False, "Insert value with slice operator should be impossible" + +# Erase two elements and replace by one +try: + ints[1:3] = [0] +except NotImplementedError: + pass +else: + assert False, "Insert value with slice operator should be impossible" + +# Erase two elements and replace by three +try: + ints[1:3] = [0, 1, 2] +except NotImplementedError: + pass +else: + assert False, "Insert value with slice operator should be impossible" + +# Test that delete operator is not implemented +# Index delete +try: + del ints[0] +except NotImplementedError: + pass +else: + assert False, "del is not implemented" + +# Slice delete +try: + del ints[1:3] +except NotImplementedError: + pass +else: + assert False, "del is not implemented" + +# Slice delete +try: + del ints[1:3] +except NotImplementedError: + pass +else: + assert False, "del is not implemented" + +# Test that append/extend are not implemented +# append +try: + ints.append(4) +except AttributeError: + pass +else: + assert False, "append is not implemented" + +# extend +try: + ints.extend([4, 5]) +except AttributeError: + pass +else: + assert False, "extend is not implemented" + +# Test set_slice nominal case +ints[1:3] = [10, 20] +assert ints[1] == 10 +assert ints[2] == 20 + # print(ints.tolist()) vecs = std_array.get_arr_3_vecs() From 44f8bdcd120deaefc243cb656a64f26e0f31d560 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 17:08:51 +0100 Subject: [PATCH 26/27] [std-array] implement tolist() for std::array --- include/eigenpy/std-array.hpp | 12 ++++++++---- unittest/std_array.cpp | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/eigenpy/std-array.hpp b/include/eigenpy/std-array.hpp index e35710e1b..c6261de7e 100644 --- a/include/eigenpy/std-array.hpp +++ b/include/eigenpy/std-array.hpp @@ -109,8 +109,10 @@ template > struct StdArrayPythonVisitor { typedef typename array_type::value_type value_type; - /// Fixed size of the array, known at compile time - static constexpr std::size_t Size = std::tuple_size{}; + + static ::boost::python::list tolist(array_type &self) { + return details::build_list::run(self); + } static void expose(const std::string &class_name, const std::string &doc_string = "") { @@ -133,8 +135,10 @@ struct StdArrayPythonVisitor { "Copy constructor")); array_indexing_suite indexing_suite; - cl.def(indexing_suite); - cl.def(visitor); + cl.def(indexing_suite) + .def(visitor) + .def("tolist", tolist, bp::arg("self"), + "Returns the std::array as a Python list."); } } }; diff --git a/unittest/std_array.cpp b/unittest/std_array.cpp index df276ad75..fb753b520 100644 --- a/unittest/std_array.cpp +++ b/unittest/std_array.cpp @@ -30,7 +30,7 @@ BOOST_PYTHON_MODULE(std_array) { enableEigenPy(); - StdArrayPythonVisitor >::expose("StdArr3_int"); + StdArrayPythonVisitor, true>::expose("StdArr3_int"); StdVectorPythonVisitor, true>::expose("StdVec_int"); exposeStdArrayEigenSpecificType("VectorXd"); From ff7517ab24f9cf85c441cc5e67eea1a868382319 Mon Sep 17 00:00:00 2001 From: ManifoldFR Date: Mon, 4 Dec 2023 17:22:29 +0100 Subject: [PATCH 27/27] [unittest/python] test .tolist() --- unittest/python/test_std_array.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unittest/python/test_std_array.py b/unittest/python/test_std_array.py index 505f57850..20d366e27 100644 --- a/unittest/python/test_std_array.py +++ b/unittest/python/test_std_array.py @@ -5,6 +5,8 @@ print(ints[0]) print(ints[1]) print(ints[2]) +print(ints.tolist()) +assert ints.tolist() == [1, 2, 3] _ints_slice = ints[1:3] print("Printing slice...")