From a2b653ab53898e1486e83d988be8f3081acf4294 Mon Sep 17 00:00:00 2001 From: Justin Carpentier <justin.carpentier@inria.fr> Date: Fri, 21 Feb 2020 18:40:08 +0100 Subject: [PATCH] core: move EigenFromPy to a dedicated file --- include/eigenpy/details.hpp | 249 +------------------------ include/eigenpy/eigen-from-python.hpp | 259 ++++++++++++++++++++++++++ 2 files changed, 260 insertions(+), 248 deletions(-) create mode 100644 include/eigenpy/eigen-from-python.hpp diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp index 699afb41..c676733e 100644 --- a/include/eigenpy/details.hpp +++ b/include/eigenpy/details.hpp @@ -18,6 +18,7 @@ #include "eigenpy/eigen-allocator.hpp" #include "eigenpy/eigen-to-python.hpp" +#include "eigenpy/eigen-from-python.hpp" #include "eigenpy/registration.hpp" #include "eigenpy/map.hpp" @@ -58,254 +59,6 @@ namespace boost { namespace python { namespace detail { namespace eigenpy { - - - - /* --- FROM PYTHON ------------------------------------------------------------ */ - - template<typename MatType> - struct EigenFromPy - { - - static bool isScalarConvertible(const int np_type) - { - if(NumpyEquivalentType<typename MatType::Scalar>::type_code == np_type) - return true; - - switch(np_type) - { - case NPY_INT: - return FromTypeToType<int,typename MatType::Scalar>::value; - case NPY_LONG: - return FromTypeToType<long,typename MatType::Scalar>::value; - case NPY_FLOAT: - return FromTypeToType<float,typename MatType::Scalar>::value; - case NPY_CFLOAT: - return FromTypeToType<std::complex<float>,typename MatType::Scalar>::value; - case NPY_DOUBLE: - return FromTypeToType<double,typename MatType::Scalar>::value; - case NPY_CDOUBLE: - return FromTypeToType<std::complex<double>,typename MatType::Scalar>::value; - case NPY_LONGDOUBLE: - return FromTypeToType<long double,typename MatType::Scalar>::value; - case NPY_CLONGDOUBLE: - return FromTypeToType<std::complex<long double>,typename MatType::Scalar>::value; - default: - return false; - } - } - - /// \brief Determine if pyObj can be converted into a MatType object - static void* convertible(PyArrayObject* pyArray) - { - if(!PyArray_Check(pyArray)) - return 0; - - if(!isScalarConvertible(EIGENPY_GET_PY_ARRAY_TYPE(pyArray))) - return 0; - - if(MatType::IsVectorAtCompileTime) - { - const Eigen::DenseIndex size_at_compile_time - = MatType::IsRowMajor - ? MatType::ColsAtCompileTime - : MatType::RowsAtCompileTime; - - switch(PyArray_NDIM(pyArray)) - { - case 0: - return 0; - case 1: - { - if(size_at_compile_time != Eigen::Dynamic) - { - // check that the sizes at compile time matche - if(PyArray_DIMS(pyArray)[0] == size_at_compile_time) - return pyArray; - else - return 0; - } - else // This is a dynamic MatType - return pyArray; - } - case 2: - { - // Special care of scalar matrix of dimension 1x1. - if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1) - { - if(size_at_compile_time != Eigen::Dynamic) - { - if(size_at_compile_time == 1) - return pyArray; - else - return 0; - } - else // This is a dynamic MatType - return pyArray; - } - - if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[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(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1)) - || ((PyArray_DIMS(pyArray)[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(size_at_compile_time != Eigen::Dynamic) - { // This is a fixe size vector - const Eigen::DenseIndex pyArray_size - = PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1] - ? PyArray_DIMS(pyArray)[0] - : PyArray_DIMS(pyArray)[1]; - if(size_at_compile_time != pyArray_size) - return 0; - } - break; - } - default: - return 0; - } - } - else // this is a matrix - { - if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix - { - return pyArray; - } - - if(PyArray_NDIM(pyArray) != 2) - { -#ifndef NDEBUG - std::cerr << "The number of dimension of the object is not correct." << std::endl; -#endif - return 0; - } - - if(PyArray_NDIM(pyArray) == 2) - { - const int R = (int)PyArray_DIMS(pyArray)[0]; - const int C = (int)PyArray_DIMS(pyArray)[1]; - - if( (MatType::RowsAtCompileTime!=R) - && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) - return 0; - if( (MatType::ColsAtCompileTime!=C) - && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) - return 0; - } - } - -#ifdef NPY_1_8_API_VERSION - if(!(PyArray_FLAGS(pyArray))) -#else - if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED)) -#endif - { -#ifndef NDEBUG - std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; -#endif - return 0; - } - - return pyArray; - } - - /// \brief Allocate memory and copy pyObj in the new storage - static void construct(PyObject* pyObj, - bp::converter::rvalue_from_python_stage1_data* memory) - { - PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj); - assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX)); - - void* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatType>*> - (reinterpret_cast<void*>(memory))->storage.bytes; - - EigenAllocator<MatType>::allocate(pyArray,storage); - - memory->convertible = storage; - } - - static void registration() - { - bp::converter::registry::push_back - (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), - &EigenFromPy::construct,bp::type_id<MatType>()); - } - }; - - template<typename MatType> - struct EigenFromPyConverter - { - static void registration() - { - EigenFromPy<MatType>::registration(); - - // Add also conversion to Eigen::MatrixBase<MatType> - typedef Eigen::MatrixBase<MatType> MatrixBase; - EigenFromPy<MatrixBase>::registration(); - - // Add also conversion to Eigen::EigenBase<MatType> - typedef Eigen::EigenBase<MatType> EigenBase; - EigenFromPy<EigenBase>::registration(); - } - }; - - template<typename MatType> - struct EigenFromPy< Eigen::MatrixBase<MatType> > : EigenFromPy<MatType> - { - typedef EigenFromPy<MatType> EigenFromPyDerived; - typedef Eigen::MatrixBase<MatType> Base; - - static void registration() - { - bp::converter::registry::push_back - (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), - &EigenFromPy::construct,bp::type_id<Base>()); - } - }; - - template<typename MatType> - struct EigenFromPy< Eigen::EigenBase<MatType> > : EigenFromPy<MatType> - { - typedef EigenFromPy<MatType> EigenFromPyDerived; - typedef Eigen::EigenBase<MatType> Base; - - static void registration() - { - bp::converter::registry::push_back - (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), - &EigenFromPy::construct,bp::type_id<Base>()); - } - }; - -#if EIGEN_VERSION_AT_LEAST(3,2,0) - // Template specialization for Eigen::Ref - template<typename MatType> - struct EigenFromPyConverter< eigenpy::Ref<MatType> > - { - static void registration() - { - bp::converter::registry::push_back - (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible), - &EigenFromPy<MatType>::construct,bp::type_id<MatType>()); - } - }; - -#endif - template<typename MatType,typename EigenEquivalentType> EIGENPY_DEPRECATED void enableEigenPySpecific() diff --git a/include/eigenpy/eigen-from-python.hpp b/include/eigenpy/eigen-from-python.hpp new file mode 100644 index 00000000..07482697 --- /dev/null +++ b/include/eigenpy/eigen-from-python.hpp @@ -0,0 +1,259 @@ +// +// Copyright (c) 2014-2020 CNRS INRIA +// + +#ifndef __eigenpy_eigen_from_python_hpp__ +#define __eigenpy_eigen_from_python_hpp__ + +#include "eigenpy/fwd.hpp" +#include "eigenpy/numpy-type.hpp" +#include "eigenpy/eigen-allocator.hpp" +#include "eigenpy/scalar-conversion.hpp" + +namespace eigenpy +{ + template<typename MatType> + struct EigenFromPy + { + + static bool isScalarConvertible(const int np_type) + { + if(NumpyEquivalentType<typename MatType::Scalar>::type_code == np_type) + return true; + + switch(np_type) + { + case NPY_INT: + return FromTypeToType<int,typename MatType::Scalar>::value; + case NPY_LONG: + return FromTypeToType<long,typename MatType::Scalar>::value; + case NPY_FLOAT: + return FromTypeToType<float,typename MatType::Scalar>::value; + case NPY_CFLOAT: + return FromTypeToType<std::complex<float>,typename MatType::Scalar>::value; + case NPY_DOUBLE: + return FromTypeToType<double,typename MatType::Scalar>::value; + case NPY_CDOUBLE: + return FromTypeToType<std::complex<double>,typename MatType::Scalar>::value; + case NPY_LONGDOUBLE: + return FromTypeToType<long double,typename MatType::Scalar>::value; + case NPY_CLONGDOUBLE: + return FromTypeToType<std::complex<long double>,typename MatType::Scalar>::value; + default: + return false; + } + } + + /// \brief Determine if pyObj can be converted into a MatType object + static void* convertible(PyArrayObject* pyArray) + { + if(!PyArray_Check(pyArray)) + return 0; + + if(!isScalarConvertible(EIGENPY_GET_PY_ARRAY_TYPE(pyArray))) + return 0; + + if(MatType::IsVectorAtCompileTime) + { + const Eigen::DenseIndex size_at_compile_time + = MatType::IsRowMajor + ? MatType::ColsAtCompileTime + : MatType::RowsAtCompileTime; + + switch(PyArray_NDIM(pyArray)) + { + case 0: + return 0; + case 1: + { + if(size_at_compile_time != Eigen::Dynamic) + { + // check that the sizes at compile time matche + if(PyArray_DIMS(pyArray)[0] == size_at_compile_time) + return pyArray; + else + return 0; + } + else // This is a dynamic MatType + return pyArray; + } + case 2: + { + // Special care of scalar matrix of dimension 1x1. + if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1) + { + if(size_at_compile_time != Eigen::Dynamic) + { + if(size_at_compile_time == 1) + return pyArray; + else + return 0; + } + else // This is a dynamic MatType + return pyArray; + } + + if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[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(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1)) + || ((PyArray_DIMS(pyArray)[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(size_at_compile_time != Eigen::Dynamic) + { // This is a fixe size vector + const Eigen::DenseIndex pyArray_size + = PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1] + ? PyArray_DIMS(pyArray)[0] + : PyArray_DIMS(pyArray)[1]; + if(size_at_compile_time != pyArray_size) + return 0; + } + break; + } + default: + return 0; + } + } + else // this is a matrix + { + if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix + { + return pyArray; + } + + if(PyArray_NDIM(pyArray) != 2) + { +#ifndef NDEBUG + std::cerr << "The number of dimension of the object is not correct." << std::endl; +#endif + return 0; + } + + if(PyArray_NDIM(pyArray) == 2) + { + const int R = (int)PyArray_DIMS(pyArray)[0]; + const int C = (int)PyArray_DIMS(pyArray)[1]; + + if( (MatType::RowsAtCompileTime!=R) + && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) + return 0; + if( (MatType::ColsAtCompileTime!=C) + && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) + return 0; + } + } + +#ifdef NPY_1_8_API_VERSION + if(!(PyArray_FLAGS(pyArray))) +#else + if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED)) +#endif + { +#ifndef NDEBUG + std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; +#endif + return 0; + } + + return pyArray; + } + + /// \brief Allocate memory and copy pyObj in the new storage + static void construct(PyObject* pyObj, + bp::converter::rvalue_from_python_stage1_data* memory) + { + PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj); + assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX)); + + void* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatType>*> + (reinterpret_cast<void*>(memory))->storage.bytes; + + EigenAllocator<MatType>::allocate(pyArray,storage); + + memory->convertible = storage; + } + + static void registration() + { + bp::converter::registry::push_back + (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), + &EigenFromPy::construct,bp::type_id<MatType>()); + } + }; + + template<typename MatType> + struct EigenFromPyConverter + { + static void registration() + { + EigenFromPy<MatType>::registration(); + + // Add also conversion to Eigen::MatrixBase<MatType> + typedef Eigen::MatrixBase<MatType> MatrixBase; + EigenFromPy<MatrixBase>::registration(); + + // Add also conversion to Eigen::EigenBase<MatType> + typedef Eigen::EigenBase<MatType> EigenBase; + EigenFromPy<EigenBase>::registration(); + } + }; + + template<typename MatType> + struct EigenFromPy< Eigen::MatrixBase<MatType> > : EigenFromPy<MatType> + { + typedef EigenFromPy<MatType> EigenFromPyDerived; + typedef Eigen::MatrixBase<MatType> Base; + + static void registration() + { + bp::converter::registry::push_back + (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), + &EigenFromPy::construct,bp::type_id<Base>()); + } + }; + + template<typename MatType> + struct EigenFromPy< Eigen::EigenBase<MatType> > : EigenFromPy<MatType> + { + typedef EigenFromPy<MatType> EigenFromPyDerived; + typedef Eigen::EigenBase<MatType> Base; + + static void registration() + { + bp::converter::registry::push_back + (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), + &EigenFromPy::construct,bp::type_id<Base>()); + } + }; + +#if EIGEN_VERSION_AT_LEAST(3,2,0) + // Template specialization for Eigen::Ref + template<typename MatType> + struct EigenFromPyConverter< eigenpy::Ref<MatType> > + { + static void registration() + { + bp::converter::registry::push_back + (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible), + &EigenFromPy<MatType>::construct,bp::type_id<MatType>()); + } + }; + +#endif +} + +#endif // __eigenpy_eigen_from_python_hpp__ -- GitLab