From cfbd185f39e380ed84b817d2520b15ff01ee42c8 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Mon, 8 Jan 2018 19:16:12 +0100 Subject: [PATCH 01/15] [CMake] Add SYSTEM info to INCLUDE_DIRECTORIES macro This option avoid warnings comming from dependencies --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee134df06..fdb95312c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,12 +70,12 @@ ADD_REQUIRED_DEPENDENCY("eigen3 >= 3.0.5") SET(BOOST_COMPONENTS python) SEARCH_FOR_BOOST() # Add Boost path to include directories. -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS}) FINDPYTHON(2.7 EXACT REQUIRED) -INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${PYTHON_INCLUDE_DIRS}) FIND_NUMPY() -INCLUDE_DIRECTORIES(${NUMPY_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${NUMPY_INCLUDE_DIRS}) # ---------------------------------------------------- # --- INCLUDE ---------------------------------------- From 37f9b3b295554b343a84806612f9a318e006098a Mon Sep 17 00:00:00 2001 From: jcarpent Date: Mon, 8 Jan 2018 19:18:57 +0100 Subject: [PATCH 02/15] [All] Set deprecated enableEigenPySpecific with two template parameters --- src/details.hpp | 6 ++++++ src/eigenpy.cpp | 16 ++++++++-------- src/eigenpy.hpp | 8 +++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index 949ed0c21..26681c191 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -215,6 +215,12 @@ namespace eigenpy template void enableEigenPySpecific() + { + enableEigenPySpecific(); + } + + template + void enableEigenPySpecific() { numpy_import_array(); if(check_registration()) return; diff --git a/src/eigenpy.cpp b/src/eigenpy.cpp index d0b685eb1..a7e46423b 100644 --- a/src/eigenpy.cpp +++ b/src/eigenpy.cpp @@ -24,15 +24,15 @@ namespace eigenpy { Exception::registerException(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); + enableEigenPySpecific(); + enableEigenPySpecific(); + enableEigenPySpecific(); + enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); + enableEigenPySpecific(); + enableEigenPySpecific(); + enableEigenPySpecific(); + enableEigenPySpecific(); } } // namespace eigenpy diff --git a/src/eigenpy.hpp b/src/eigenpy.hpp index cd01d8bcc..40cf58782 100644 --- a/src/eigenpy.hpp +++ b/src/eigenpy.hpp @@ -19,17 +19,23 @@ #include "eigenpy/fwd.hpp" #include "eigenpy/memory.hpp" +#include "eigenpy/deprecated.hh" namespace eigenpy { /* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */ void enableEigenPy(); + + template + void enableEigenPySpecific(); + /* Enable the Eigen--Numpy serialization for the templated MatrixBase class. * The second template argument is used for inheritance of Eigen classes. If * using a native Eigen::MatrixBase, simply repeat the same arg twice. */ template - void enableEigenPySpecific(); + EIGENPY_DEPRECATED void enableEigenPySpecific(); + } // namespace eigenpy From 6cd3c0d5946a5763a4c3a26fc246e8e6d379261f Mon Sep 17 00:00:00 2001 From: jcarpent Date: Mon, 8 Jan 2018 19:32:27 +0100 Subject: [PATCH 03/15] [Memory] Remove useless warning --- src/memory.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memory.hpp b/src/memory.hpp index 6a0b5f26f..e63d5f425 100644 --- a/src/memory.hpp +++ b/src/memory.hpp @@ -79,7 +79,7 @@ namespace boost { namespace python { namespace objects { \ \ Py_ssize_t holder_offset = reinterpret_cast(holder) \ - reinterpret_cast(&instance->storage) \ - + offsetof(instance_t, storage); \ + + static_cast(offsetof(instance_t, storage)); \ Py_SIZE(instance) = holder_offset; \ \ protect.cancel(); \ From 7f92dd3c125382caa9f21be1a6afebe5074a68c8 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Mon, 8 Jan 2018 19:18:57 +0100 Subject: [PATCH 04/15] [All] Set deprecated enableEigenPySpecific with two template parameters --- src/details.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index 26681c191..9dc9d2dbe 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -76,7 +76,7 @@ namespace eigenpy }; /* --- TO PYTHON -------------------------------------------------------------- */ - template< typename MatType,typename EquivalentEigenType > + template struct EigenToPy { static PyObject* convert(MatType const& mat) @@ -88,9 +88,9 @@ namespace eigenpy npy_intp shape[2] = { R,C }; PyArrayObject* pyArray = (PyArrayObject*) - PyArray_SimpleNew(2, shape, NumpyEquivalentType::type_code); + PyArray_SimpleNew(2, shape, NumpyEquivalentType::type_code); - MapNumpy::map(pyArray) = mat; + MapNumpy::map(pyArray) = mat; return PyMatrixType::getInstance().make(pyArray).ptr(); } @@ -136,7 +136,7 @@ namespace eigenpy }; - template + template struct EigenFromPy { EigenFromPy() @@ -197,14 +197,14 @@ namespace eigenpy using namespace Eigen; PyArrayObject * pyArray = reinterpret_cast(pyObj); - typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); + typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); void* storage = ((bp::converter::rvalue_from_python_storage*) ((void*)memory))->storage.bytes; assert( (numpyMap.rows()::construct (storage,r,c); memory->convertible = storage; @@ -225,8 +225,8 @@ namespace eigenpy numpy_import_array(); if(check_registration()) return; - boost::python::to_python_converter >(); - EigenFromPy(); + boost::python::to_python_converter >(); + EigenFromPy(); } } // namespace eigenpy From 6f04d2338b279cdb3033fab5384b273c336d0245 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 10:12:09 +0100 Subject: [PATCH 05/15] [Conversion] Simplify building of Eigen matrices --- src/details.hpp | 55 +++++++------------------------------------------ 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index 9dc9d2dbe..b1bc4ee00 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -97,44 +97,6 @@ namespace eigenpy }; /* --- FROM PYTHON ------------------------------------------------------------ */ - namespace bp = boost::python; - - template - struct TraitsMatrixConstructor - { - static MatType & construct(void*storage,int /*r*/,int /*c*/) - { - return * new(storage) MatType(); - } - }; - - template - struct TraitsMatrixConstructor - { - static MatType & construct(void*storage,int r,int c) - { - return * new(storage) MatType(r,c); - } - }; - - template - struct TraitsMatrixConstructor - { - static MatType & construct(void*storage,int /*r*/,int c) - { - return * new(storage) MatType(R,c); - } - }; - - template - struct TraitsMatrixConstructor - { - static MatType & construct(void*storage,int r,int /*c*/) - { - return * new(storage) MatType(r,C); - } - }; - template struct EigenFromPy @@ -195,20 +157,17 @@ namespace eigenpy bp::converter::rvalue_from_python_stage1_data* memory) { using namespace Eigen; - + PyArrayObject * pyArray = reinterpret_cast(pyObj); typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); - + assert( (numpyMap.rows()*) - ((void*)memory))->storage.bytes; - assert( (numpyMap.rows()::construct (storage,r,c); + ((void*)memory))->storage.bytes; + + new(storage) MatType(numpyMap); memory->convertible = storage; - - eigenMatrix = numpyMap; } }; #define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } } From c1fdfe7990c154edbf517946a1d1df452a3b7776 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 10:16:34 +0100 Subject: [PATCH 06/15] Fix identation --- src/details.hpp | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index b1bc4ee00..95983b2c8 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -104,50 +104,50 @@ namespace eigenpy EigenFromPy() { bp::converter::registry::push_back - (reinterpret_cast(&convertible), - &construct,bp::type_id()); + (reinterpret_cast(&convertible), + &construct,bp::type_id()); } - + // Determine if obj_ptr can be converted in a Eigenvec static void* convertible(PyArrayObject* obj_ptr) { typedef typename MatType::Scalar T; - - if (!PyArray_Check(obj_ptr)) - { + + if (!PyArray_Check(obj_ptr)) + { #ifndef NDEBUG - std::cerr << "The python object is not a numpy array." << std::endl; + std::cerr << "The python object is not a numpy array." << std::endl; #endif - return 0; - } - + return 0; + } + if (PyArray_NDIM(obj_ptr) != 2) - if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) ) - { + if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) ) + { #ifndef NDEBUG - std::cerr << "The number of dimension of the object is not correct." << std::endl; + std::cerr << "The number of dimension of the object is not correct." << std::endl; #endif - return 0; - } - + return 0; + } + if ((PyArray_ObjectType(reinterpret_cast(obj_ptr), 0)) != NumpyEquivalentType::type_code) - { + { #ifndef NDEBUG - std::cerr << "The internal type as no Eigen equivalent." << std::endl; + std::cerr << "The internal type as no Eigen equivalent." << std::endl; #endif - return 0; - } + return 0; + } #ifdef NPY_1_8_API_VERSION if (!(PyArray_FLAGS(obj_ptr))) #else - if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED)) + if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED)) #endif - { + { #ifndef NDEBUG - std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; + std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; #endif - return 0; - } + return 0; + } return obj_ptr; } From cd37a2f613889bac03e527e253f840733326535e Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 10:32:22 +0100 Subject: [PATCH 07/15] [Core] Use bp namespace shortcut --- src/details.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index 95983b2c8..887880feb 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -58,7 +58,7 @@ namespace eigenpy { return make((PyObject*)pyArray,copy); } bp::object make(PyObject* pyObj, bool copy = false) { - boost::python::object m + bp::object m = pyMatrixType(bp::object(bp::handle<>(pyObj)), bp::object(), copy); Py_INCREF(m.ptr()); return m; @@ -67,7 +67,7 @@ namespace eigenpy protected: PyMatrixType() { - pyModule = boost::python::import("numpy"); + pyModule = bp::import("numpy"); pyMatrixType = pyModule.attr("matrix"); } @@ -154,7 +154,7 @@ namespace eigenpy // Convert obj_ptr into a Eigenvec static void construct(PyObject* pyObj, - bp::converter::rvalue_from_python_stage1_data* memory) + bp::converter::rvalue_from_python_stage1_data* memory) { using namespace Eigen; @@ -184,7 +184,7 @@ namespace eigenpy numpy_import_array(); if(check_registration()) return; - boost::python::to_python_converter >(); + bp::to_python_converter >(); EigenFromPy(); } From cfba28b46a26dccbc06dbdd400b6bf1fb66efe49 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 11:49:17 +0100 Subject: [PATCH 08/15] [Core] Introduce dedicated struct for allocation --- src/details.hpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index 887880feb..6e9816e65 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -98,6 +98,16 @@ namespace eigenpy /* --- FROM PYTHON ------------------------------------------------------------ */ + template + struct EigenObjectAllocator + { + static void allocate(PyArrayObject * pyArray, void * storage) + { + typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); + new(storage) MatType(numpyMap); + } + }; + template struct EigenFromPy { @@ -159,14 +169,13 @@ namespace eigenpy using namespace Eigen; PyArrayObject * pyArray = reinterpret_cast(pyObj); - typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); - assert( (numpyMap.rows()*) ((void*)memory))->storage.bytes; - new(storage) MatType(numpyMap); + EigenObjectAllocator::allocate(pyArray,storage); + memory->convertible = storage; } }; From 620f95b71b1a223f7b0311b908b8f2b6bc5053f4 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 13:04:11 +0100 Subject: [PATCH 09/15] [Core] Remove useless include --- src/details.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/details.hpp b/src/details.hpp index 6e9816e65..8beec912e 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -30,7 +30,6 @@ #include "eigenpy/eigenpy.hpp" #include "eigenpy/registration.hpp" -#include "eigenpy/exception.hpp" #include "eigenpy/map.hpp" From d9cf8d9f9e55b043cc491d518159846bef872d3e Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 19:24:27 +0100 Subject: [PATCH 10/15] [All] Add alignment EIGENPY_DEFAULT_ALIGNMENT_VALUE --- src/fwd.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/fwd.hpp b/src/fwd.hpp index ab9cf717f..d5d1f2e66 100644 --- a/src/fwd.hpp +++ b/src/fwd.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017, Nicolas Mansard and Justin Carpentier, LAAS-CNRS + * Copyright 2014-2018, Nicolas Mansard and Justin Carpentier, LAAS-CNRS * * This file is part of eigenpy. * eigenpy is free software: you can redistribute it and/or @@ -20,8 +20,17 @@ #include #include +#include #ifdef NPY_1_8_API_VERSION #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #endif +#include + +#ifdef NPY_ALIGNED +#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned16 +#else +#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Unaligned +#endif + #endif // ifndef __eigenpy_fwd_hpp__ From 3519a39bbb8ca70ee0c543eee741d134c2aaef83 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 19:25:05 +0100 Subject: [PATCH 11/15] [Core] Overload Eigen::Ref to comply with Numpy row-major --- CMakeLists.txt | 1 + src/ref.hpp | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/ref.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fdb95312c..8ae903e99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ SET(HEADERS registration.hpp angle-axis.hpp quaternion.hpp + ref.hpp ) MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy") diff --git a/src/ref.hpp b/src/ref.hpp new file mode 100644 index 000000000..ddeee580b --- /dev/null +++ b/src/ref.hpp @@ -0,0 +1,97 @@ +/* + * Copyright 2018, Justin Carpentier , LAAS-CNRS + * + * This file is part of eigenpy. + * eigenpy is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * eigenpy is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with eigenpy. If not, see . + */ + +#ifndef __eigenpy_ref_hpp__ +#define __eigenpy_ref_hpp__ + +#include "eigenpy/fwd.hpp" + +namespace eigenpy +{ + template + struct StrideType + { + typedef Eigen::Stride type; + }; + + template + struct StrideType + { + typedef Eigen::InnerStride type; + }; + + template + struct Ref : Eigen::Ref::type> + { + public: + typedef Eigen::Ref::type> Base; + + private: + typedef Eigen::internal::traits Traits; + template + EIGEN_DEVICE_FUNC inline Ref(const Eigen::PlainObjectBase& expr, + typename Eigen::internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); + + public: + + typedef typename Eigen::internal::traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ + typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ + typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ + typedef typename Eigen::internal::ref_selector::type Nested; \ + typedef typename Eigen::internal::traits::StorageKind StorageKind; \ + typedef typename Eigen::internal::traits::StorageIndex StorageIndex; \ + enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ + Flags = Eigen::internal::traits::Flags, \ + SizeAtCompileTime = Base::SizeAtCompileTime, \ + MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ + using Base::derived; \ + using Base::const_cast_derived; + typedef typename Base::PacketScalar PacketScalar; + + template + EIGEN_DEVICE_FUNC inline Ref(Eigen::PlainObjectBase& expr, + typename Eigen::internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + : Base(expr.derived()) + {} + + template + EIGEN_DEVICE_FUNC inline Ref(const Eigen::DenseBase& expr, + typename Eigen::internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + : Base(expr.derived()) + {} + +#if EIGEN_COMP_MSVC_STRICT && (EIGEN_COMP_MSVC < 1900 || defined(__CUDACC_VER__)) // for older MSVC versions, as well as 1900 && CUDA 8, using the base operator is sufficient (cf Bugs 1000, 1324) + using Base::operator =; +#elif EIGEN_COMP_CLANG // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653) + using Base::operator =; \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Ref& operator=(const Ref& other) { Base::operator=(other); return *this; } \ + template \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Ref& operator=(const Eigen::DenseBase& other) { Base::operator=(other.derived()); return *this; } +#else + using Base::operator =; \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Ref& operator=(const Ref& other) \ + { \ + Base::operator=(other); \ + return *this; \ + } +#endif + + }; // struct Ref +} + +#endif // ifndef __eigenpy_ref_hpp__ From 0ad69ef38ffd629ccb4c1f1747f87b37d10e3f9d Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 19:26:03 +0100 Subject: [PATCH 12/15] [Core] Update Map and Converter to be compatible with Eigen::Ref --- src/details.hpp | 85 +++++++++++++++++++++++++++++++++++++------------ src/map.hpp | 30 +++++++++-------- 2 files changed, 81 insertions(+), 34 deletions(-) diff --git a/src/details.hpp b/src/details.hpp index 8beec912e..6fe8295d2 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -17,13 +17,7 @@ #ifndef __eigenpy_details_hpp__ #define __eigenpy_details_hpp__ -#include -#include - -#include -#ifdef NPY_1_8_API_VERSION -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif +#include "eigenpy/fwd.hpp" #include #include @@ -73,6 +67,40 @@ namespace eigenpy bp::object pyMatrixType; bp::object pyModule; }; + + template + struct EigenObjectAllocator + { + typedef MatType Type; + + static void allocate(PyArrayObject * pyArray, void * storage) + { + typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); + new(storage) MatType(numpyMap); + } + + static void convert(Type const & mat , PyArrayObject * pyArray) + { + MapNumpy::map(pyArray) = mat; + } + }; + + template + struct EigenObjectAllocator< eigenpy::Ref > + { + typedef eigenpy::Ref Type; + + static void allocate(PyArrayObject * pyArray, void * storage) + { + typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); + new(storage) Type(numpyMap); + } + + static void convert(Type const & mat , PyArrayObject * pyArray) + { + MapNumpy::map(pyArray) = mat; + } + }; /* --- TO PYTHON -------------------------------------------------------------- */ template @@ -89,7 +117,7 @@ namespace eigenpy PyArrayObject* pyArray = (PyArrayObject*) PyArray_SimpleNew(2, shape, NumpyEquivalentType::type_code); - MapNumpy::map(pyArray) = mat; + EigenObjectAllocator::convert(mat,pyArray); return PyMatrixType::getInstance().make(pyArray).ptr(); } @@ -97,16 +125,6 @@ namespace eigenpy /* --- FROM PYTHON ------------------------------------------------------------ */ - template - struct EigenObjectAllocator - { - static void allocate(PyArrayObject * pyArray, void * storage) - { - typename MapNumpy::EigenMap numpyMap = MapNumpy::map(pyArray); - new(storage) MatType(numpyMap); - } - }; - template struct EigenFromPy { @@ -120,8 +138,6 @@ namespace eigenpy // Determine if obj_ptr can be converted in a Eigenvec static void* convertible(PyArrayObject* obj_ptr) { - typedef typename MatType::Scalar T; - if (!PyArray_Check(obj_ptr)) { #ifndef NDEBUG @@ -130,7 +146,31 @@ namespace eigenpy return 0; } + if(MatType::IsVectorAtCompileTime) + { + if(PyArray_DIMS(obj_ptr)[0] > 1 && PyArray_DIMS(obj_ptr)[1] > 1) + { +#ifndef NDEBUG + std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl; +#endif + return 0; + } + + if(((PyArray_DIMS(obj_ptr)[0] == 1) && (MatType::ColsAtCompileTime == 1)) + || ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1))) + { +#ifndef NDEBUG + if(MatType::ColsAtCompileTime == 1) + std::cerr << "The object is not a column vector" << std::endl; + else + std::cerr << "The object is not a row vector" << std::endl; +#endif + return 0; + } + } + if (PyArray_NDIM(obj_ptr) != 2) + { if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) ) { #ifndef NDEBUG @@ -138,8 +178,10 @@ namespace eigenpy #endif return 0; } + } - if ((PyArray_ObjectType(reinterpret_cast(obj_ptr), 0)) != NumpyEquivalentType::type_code) + if ((PyArray_ObjectType(reinterpret_cast(obj_ptr), 0)) + != NumpyEquivalentType::type_code) { #ifndef NDEBUG std::cerr << "The internal type as no Eigen equivalent." << std::endl; @@ -178,6 +220,7 @@ namespace eigenpy memory->convertible = storage; } }; + #define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } } template diff --git a/src/map.hpp b/src/map.hpp index 0c0b633d4..2a2fb4b27 100644 --- a/src/map.hpp +++ b/src/map.hpp @@ -14,10 +14,9 @@ * with eigenpy. If not, see . */ -#include -#include +#include "eigenpy/fwd.hpp" #include -#include +#include "eigenpy/exception.hpp" namespace eigenpy { @@ -30,6 +29,7 @@ namespace eigenpy { typedef MapNumpyTraits Impl; typedef typename Impl::EigenMap EigenMap; + typedef typename Impl::Stride Stride; static inline EigenMap map( PyArrayObject* pyArray ); }; @@ -45,9 +45,9 @@ namespace eigenpy template struct MapNumpyTraits { - typedef Eigen::Stride Stride; - typedef Eigen::Map EigenMap; - typedef typename MatType::Scalar T; + typedef typename StrideType::type Stride; + typedef Eigen::Map EigenMap; + typedef typename MatType::Scalar Scalar; static EigenMap mapImpl( PyArrayObject* pyArray ) { @@ -63,6 +63,9 @@ namespace eigenpy const long int itemsize = PyArray_ITEMSIZE(pyArray); const int stride1 = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize; const int stride2 = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize; + Stride stride(stride2,stride1); + + if( (MatType::RowsAtCompileTime!=R) && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) @@ -71,17 +74,18 @@ namespace eigenpy && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) { throw eigenpy::Exception("The number of columns does not fit with the matrix type."); } - T* pyData = reinterpret_cast(PyArray_DATA(pyArray)); - return EigenMap( pyData, R,C, Stride(stride2,stride1) ); + Scalar* pyData = reinterpret_cast(PyArray_DATA(pyArray)); + + return EigenMap( pyData, R,C, stride ); } }; template struct MapNumpyTraits { - typedef Eigen::InnerStride Stride; - typedef Eigen::Map EigenMap; - typedef typename MatType::Scalar T; + typedef typename StrideType::type Stride; + typedef Eigen::Map EigenMap; + typedef typename MatType::Scalar Scalar; static EigenMap mapImpl( PyArrayObject* pyArray ) { @@ -101,8 +105,8 @@ namespace eigenpy && (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) ) { throw eigenpy::Exception("The number of elements does not fit with the vector type."); } - T* pyData = reinterpret_cast(PyArray_DATA(pyArray)); - return EigenMap( pyData, R, 1, Stride(stride) ); + Scalar* pyData = reinterpret_cast(PyArray_DATA(pyArray)); + return EigenMap( pyData, R, Stride(stride) ); } }; From 02e96c2d05d6493212140082dd674441fa6495b7 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 19:27:38 +0100 Subject: [PATCH 13/15] [Core] Register by default both MatType and Ref --- src/eigenpy.cpp | 21 +++++++++++---------- src/eigenpy.hpp | 7 +++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/eigenpy.cpp b/src/eigenpy.cpp index a7e46423b..dae15e9d2 100644 --- a/src/eigenpy.cpp +++ b/src/eigenpy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 LAAS-CNRS + * Copyright (c) 2015-2018 LAAS-CNRS * * This file is part of eigenpy. * eigenpy is free software: you can redistribute it and/or @@ -22,17 +22,18 @@ namespace eigenpy /* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */ void enableEigenPy() { + using namespace Eigen; Exception::registerException(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); - - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); - enableEigenPySpecific(); + ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXd); + ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2d); + ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3d); + ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4d); + + ENABLE_SPECIFIC_MATRIX_TYPE(VectorXd); + ENABLE_SPECIFIC_MATRIX_TYPE(Vector2d); + ENABLE_SPECIFIC_MATRIX_TYPE(Vector3d); + ENABLE_SPECIFIC_MATRIX_TYPE(Vector4d); } } // namespace eigenpy diff --git a/src/eigenpy.hpp b/src/eigenpy.hpp index 40cf58782..9fcecc7ce 100644 --- a/src/eigenpy.hpp +++ b/src/eigenpy.hpp @@ -18,15 +18,18 @@ #define __eigenpy_eigenpy_hpp__ #include "eigenpy/fwd.hpp" -#include "eigenpy/memory.hpp" #include "eigenpy/deprecated.hh" +#include "eigenpy/ref.hpp" + +#define ENABLE_SPECIFIC_MATRIX_TYPE(TYPE) \ + enableEigenPySpecific(); \ + enableEigenPySpecific< eigenpy::Ref >(); namespace eigenpy { /* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */ void enableEigenPy(); - template void enableEigenPySpecific(); From b77b9aa1ae72ee6eea315a3bf0140463cda271db Mon Sep 17 00:00:00 2001 From: jcarpent Date: Tue, 9 Jan 2018 19:27:53 +0100 Subject: [PATCH 14/15] [Test] Add unit test for Ref --- unittest/CMakeLists.txt | 3 ++- unittest/ref.cpp | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 unittest/ref.cpp diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 8524a1d62..8b0a15c8e 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2016 CNRS +# Copyright (c) 2016-2018 CNRS # # This file is part of eigenpy # eigenpy is free software: you can redistribute it @@ -40,4 +40,5 @@ ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND}) ADD_LIB_UNIT_TEST(matrix "eigen3") ADD_LIB_UNIT_TEST(geometry "eigen3") +ADD_LIB_UNIT_TEST(ref "eigen3") diff --git a/unittest/ref.cpp b/unittest/ref.cpp new file mode 100644 index 000000000..0ca38fc05 --- /dev/null +++ b/unittest/ref.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2018, Justin Carpentier , LAAS-CNRS + * + * This file is part of eigenpy. + * eigenpy is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * eigenpy is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with eigenpy. If not, see . + */ + +#include "eigenpy/eigenpy.hpp" +#include + +using namespace Eigen; +using namespace eigenpy; + +template +void printMatrix(const eigenpy::Ref & mat) +{ + if(MatType::IsVectorAtCompileTime) + std::cout << "isVector" << std::endl; + std::cout << "size: cols " << mat.cols() << " rows " << mat.rows() << std::endl; + std::cout << mat << std::endl; +} + +template +void printVector(const eigenpy::Ref & mat) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(MatType); + printMatrix(mat); +} + +template +void setOnes(eigenpy::Ref mat) +{ + mat.setOnes(); +} + +BOOST_PYTHON_MODULE(ref) +{ + namespace bp = boost::python; + eigenpy::enableEigenPy(); + + bp::def("printMatrix", printMatrix); + bp::def("printMatrix", printMatrix); + bp::def("printMatrix", printMatrix); + + bp::def("printVector", printVector); + + bp::def("setOnes", setOnes); + bp::def("setOnes", setOnes); + bp::def("setOnes", setOnes); +} From 54ed4770d77b310c780497a7a4baab58ae6395c5 Mon Sep 17 00:00:00 2001 From: jcarpent Date: Wed, 10 Jan 2018 08:42:22 +0100 Subject: [PATCH 15/15] [Core] Fix compatibility with version of Eigen lower than 3.3.x --- src/ref.hpp | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/ref.hpp b/src/ref.hpp index ddeee580b..641228e18 100644 --- a/src/ref.hpp +++ b/src/ref.hpp @@ -19,6 +19,12 @@ #include "eigenpy/fwd.hpp" +// For old Eigen versions, EIGEN_DEVICE_FUNC is not defined. +// We must define it just in the scope of this file. +#if not EIGEN_VERSION_AT_LEAST(3,2,91) +#define EIGEN_DEVICE_FUNC +#endif + namespace eigenpy { template @@ -49,17 +55,21 @@ namespace eigenpy typedef typename Eigen::internal::traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ - typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ - typedef typename Eigen::internal::ref_selector::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::StorageIndex StorageIndex; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; \ + typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ + typedef typename Eigen::internal::ref_selector::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; +#if EIGEN_VERSION_AT_LEAST(3,2,91) + typedef typename Eigen::internal::traits::StorageIndex StorageIndex; +#else + typedef typename Eigen::internal::traits::Index StorageIndex; +#endif + enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, + ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, + Flags = Eigen::internal::traits::Flags, + SizeAtCompileTime = Base::SizeAtCompileTime, + MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; + using Base::derived; using Base::const_cast_derived; typedef typename Base::PacketScalar PacketScalar; @@ -94,4 +104,8 @@ namespace eigenpy }; // struct Ref } +#if not EIGEN_VERSION_AT_LEAST(3,2,91) +#undef EIGEN_DEVICE_FUNC +#endif + #endif // ifndef __eigenpy_ref_hpp__