From 115ed938e22e38b15936e30dc127a0f0bc1ec168 Mon Sep 17 00:00:00 2001 From: Justin Carpentier <justin.carpentier@inria.fr> Date: Mon, 24 Aug 2020 19:39:57 +0200 Subject: [PATCH] core: add support of Eigen::Ref to Python --- include/eigenpy/details.hpp | 6 +++ include/eigenpy/eigen-to-python.hpp | 30 ++++++++++++++ include/eigenpy/numpy-allocator.hpp | 61 ++++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp index f431c91d..dadfe458 100644 --- a/include/eigenpy/details.hpp +++ b/include/eigenpy/details.hpp @@ -79,7 +79,13 @@ namespace eigenpy { if(check_registration<MatType>()) return; + // to-python EigenToPyConverter<MatType>::registration(); +#if EIGEN_VERSION_AT_LEAST(3,2,0) + EigenToPyConverter< Eigen::Ref<MatType> >::registration(); +#endif + + // from-python EigenFromPyConverter<MatType>::registration(); } diff --git a/include/eigenpy/eigen-to-python.hpp b/include/eigenpy/eigen-to-python.hpp index fac25371..bd89fec5 100644 --- a/include/eigenpy/eigen-to-python.hpp +++ b/include/eigenpy/eigen-to-python.hpp @@ -82,6 +82,36 @@ namespace eigenpy } }; + template<typename MatType, int Options, typename Stride> + struct EigenToPy< Eigen::Ref<MatType,Options,Stride> > + { + static PyObject* convert(const Eigen::Ref<MatType,Options,Stride> & mat) + { + typedef Eigen::Ref<MatType,Options,Stride> EigenRef; + + assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX) + && "Matrix range larger than int ... should never happen." ); + const npy_intp R = (npy_intp)mat.rows(), C = (npy_intp)mat.cols(); + + PyArrayObject* pyArray; + // Allocate Python memory + if( ( ((!(C == 1) != !(R == 1)) && !MatType::IsVectorAtCompileTime) || MatType::IsVectorAtCompileTime) + && NumpyType::getType() == ARRAY_TYPE) // Handle array with a single dimension + { + npy_intp shape[1] = { C == 1 ? R : C }; + pyArray = NumpyAllocator<EigenRef>::allocate(const_cast<EigenRef &>(mat),1,shape); + } + else + { + npy_intp shape[2] = { R,C }; + pyArray = NumpyAllocator<EigenRef>::allocate(const_cast<EigenRef &>(mat),2,shape); + } + + // Create an instance (either np.array or np.matrix) + return NumpyType::make(pyArray).ptr(); + } + }; + template<typename MatType> struct EigenToPyConverter { diff --git a/include/eigenpy/numpy-allocator.hpp b/include/eigenpy/numpy-allocator.hpp index a627c8ab..9cbeb8a0 100644 --- a/include/eigenpy/numpy-allocator.hpp +++ b/include/eigenpy/numpy-allocator.hpp @@ -57,7 +57,7 @@ namespace eigenpy } else { - return NumpyAllocator<MatType>::allocate(mat.derived(),nd,shape); + return NumpyAllocator<MatType>::allocate(mat,nd,shape); } } }; @@ -65,8 +65,33 @@ namespace eigenpy #if EIGEN_VERSION_AT_LEAST(3,2,0) template<typename MatType, int Options, typename Stride> - struct NumpyAllocator<Eigen::Ref<MatType,Options,Stride> > : NumpyAllocator<MatType &> + struct NumpyAllocator<Eigen::Ref<MatType,Options,Stride> > { + typedef Eigen::Ref<MatType,Options,Stride> RefType; + + static PyArrayObject * allocate(RefType & mat, + npy_intp nd, npy_intp * shape) + { + typedef typename RefType::Scalar Scalar; + enum { NPY_ARRAY_MEMORY_CONTIGUOUS = RefType::IsRowMajor ? NPY_ARRAY_CARRAY : NPY_ARRAY_FARRAY }; + + if(NumpyType::sharedMemory()) + { + const int Scalar_type_code = Register::getTypeCode<Scalar>(); + PyArrayObject * pyArray = (PyArrayObject*) call_PyArray_New(getPyArrayType(), + static_cast<int>(nd), + shape, + Scalar_type_code, + mat.data(), + NPY_ARRAY_MEMORY_CONTIGUOUS | NPY_ARRAY_ALIGNED); + + return pyArray; + } + else + { + return NumpyAllocator<MatType>::allocate(mat,nd,shape); + } + } }; #endif @@ -88,14 +113,14 @@ namespace eigenpy static_cast<int>(nd), shape, Scalar_type_code, - const_cast<SimilarMatrixType &>(mat.derived()).data(), + const_cast<Scalar *>(mat.data()), NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED); return pyArray; } else { - return NumpyAllocator<MatType>::allocate(mat.derived(),nd,shape); + return NumpyAllocator<MatType>::allocate(mat,nd,shape); } } }; @@ -103,8 +128,34 @@ namespace eigenpy #if EIGEN_VERSION_AT_LEAST(3,2,0) template<typename MatType, int Options, typename Stride> - struct NumpyAllocator<const Eigen::Ref<const MatType,Options,Stride> > : NumpyAllocator<const MatType &> + struct NumpyAllocator<const Eigen::Ref<const MatType,Options,Stride> > { + typedef const Eigen::Ref<const MatType,Options,Stride> RefType; + + template<typename SimilarMatrixType> + static PyArrayObject * allocate(RefType & mat, + npy_intp nd, npy_intp * shape) + { + typedef typename SimilarMatrixType::Scalar Scalar; + enum { NPY_ARRAY_MEMORY_CONTIGUOUS_RO = SimilarMatrixType::IsRowMajor ? NPY_ARRAY_CARRAY_RO : NPY_ARRAY_FARRAY_RO }; + + if(NumpyType::sharedMemory()) + { + const int Scalar_type_code = Register::getTypeCode<Scalar>(); + PyArrayObject * pyArray = (PyArrayObject*) call_PyArray_New(getPyArrayType(), + static_cast<int>(nd), + shape, + Scalar_type_code, + const_cast<Scalar *>(mat.data()), + NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED); + + return pyArray; + } + else + { + return NumpyAllocator<MatType>::allocate(mat,nd,shape); + } + } }; #endif -- GitLab