diff --git a/src/details.hpp b/src/details.hpp index 3fedf9c7e3bc656822f811ea87e8c94d71c52984..dfaef06f1b45a4fe0b407f34039fd3ea62203ebf 100644 --- a/src/details.hpp +++ b/src/details.hpp @@ -26,13 +26,31 @@ #include "eigenpy/registration.hpp" #include "eigenpy/map.hpp" +#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0) + namespace eigenpy { template <typename SCALAR> struct NumpyEquivalentType {}; template <> struct NumpyEquivalentType<double> { enum { type_code = NPY_DOUBLE };}; template <> struct NumpyEquivalentType<int> { enum { type_code = NPY_INT };}; + template <> struct NumpyEquivalentType<long> { enum { type_code = NPY_LONG };}; template <> struct NumpyEquivalentType<float> { enum { type_code = NPY_FLOAT };}; + + template <typename SCALAR1, typename SCALAR2> + struct FromTypeToType : public boost::false_type {}; + + template <typename SCALAR> + struct FromTypeToType<SCALAR,SCALAR> : public boost::true_type {}; + + template <> struct FromTypeToType<int,long> : public boost::true_type {}; + template <> struct FromTypeToType<int,float> : public boost::true_type {}; + template <> struct FromTypeToType<int,double> : public boost::true_type {}; + + template <> struct FromTypeToType<long,float> : public boost::true_type {}; + template <> struct FromTypeToType<long,double> : public boost::true_type {}; + + template <> struct FromTypeToType<float,double> : public boost::true_type {}; namespace bp = boost::python; @@ -72,16 +90,40 @@ namespace eigenpy struct EigenObjectAllocator { typedef MatType Type; + typedef typename MatType::Scalar Scalar; static void allocate(PyArrayObject * pyArray, void * storage) { - typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray); - new(storage) MatType(numpyMap); + const int rows = (int)PyArray_DIMS(pyArray)[0]; + const int cols = (int)PyArray_DIMS(pyArray)[1]; + + Type * mat_ptr = new(storage) Type(rows,cols); + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT) + *mat_ptr = MapNumpy<MatType,int>::map(pyArray).template cast<Scalar>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG) + *mat_ptr = MapNumpy<MatType,long>::map(pyArray).template cast<Scalar>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT) + *mat_ptr = MapNumpy<MatType,float>::map(pyArray).template cast<Scalar>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE) + *mat_ptr = MapNumpy<MatType,double>::map(pyArray).template cast<Scalar>(); } static void convert(Type const & mat , PyArrayObject * pyArray) { - MapNumpy<MatType>::map(pyArray) = mat; + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT) + MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG) + MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT) + MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE) + MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>(); } }; @@ -90,16 +132,27 @@ namespace eigenpy struct EigenObjectAllocator< eigenpy::Ref<MatType> > { typedef eigenpy::Ref<MatType> Type; + typedef typename MatType::Scalar Scalar; static void allocate(PyArrayObject * pyArray, void * storage) { - typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray); + typename MapNumpy<MatType,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray); new(storage) Type(numpyMap); } static void convert(Type const & mat , PyArrayObject * pyArray) { - MapNumpy<MatType>::map(pyArray) = mat; + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT) + MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG) + MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT) + MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>(); + + if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE) + MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>(); } }; #endif @@ -140,8 +193,6 @@ namespace eigenpy // Determine if obj_ptr can be converted in a Eigenvec static void* convertible(PyArrayObject* obj_ptr) { - std::cout << "call convertible" << std::endl; - if (!PyArray_Check(obj_ptr)) { #ifndef NDEBUG @@ -149,10 +200,6 @@ namespace eigenpy #endif return 0; } - - std::cout << "PyArray_DIMS(obj_ptr)[0]: " << PyArray_DIMS(obj_ptr)[0] << std::endl; - std::cout << "PyArray_DIMS(obj_ptr)[1]: " << PyArray_DIMS(obj_ptr)[1] << std::endl; - if(MatType::IsVectorAtCompileTime) { // Special care of scalar matrix of dimension 1x1. @@ -171,7 +218,6 @@ namespace eigenpy || ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1))) { #ifndef NDEBUG - std::cout << "MatType::ColsAtCompileTime: " << MatType::ColsAtCompileTime << std::endl; if(MatType::ColsAtCompileTime == 1) std::cerr << "The object is not a column vector" << std::endl; else @@ -192,14 +238,57 @@ namespace eigenpy } } - if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) + // Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType + if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_INT) + { + if(not FromTypeToType<int,typename MatType::Scalar>::value) + { +#ifndef NDEBUG + std::cerr << "The Python matrix scalar type (int) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl; +#endif + return 0; + } + } + else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_LONG) + { + if(not FromTypeToType<long,typename MatType::Scalar>::value) + { +#ifndef NDEBUG + std::cerr << "The Python matrix scalar type (long) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl; +#endif + return 0; + } + } + else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_FLOAT) + { + if(not FromTypeToType<float,typename MatType::Scalar>::value) + { +#ifndef NDEBUG + std::cerr << "The Python matrix scalar type (float) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl; +#endif + return 0; + } + } + else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_DOUBLE) + { + if(not FromTypeToType<double,typename MatType::Scalar>::value) + { +#ifndef NDEBUG + std::cerr << "The Python matrix scalar (double) type cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision." << std::endl; +#endif + return 0; + } + } + else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) != NumpyEquivalentType<typename MatType::Scalar>::type_code) { #ifndef NDEBUG std::cerr << "The internal type as no Eigen equivalent." << std::endl; #endif + return 0; } + #ifdef NPY_1_8_API_VERSION if (!(PyArray_FLAGS(obj_ptr))) #else diff --git a/src/map.hpp b/src/map.hpp index c7414355db270b60f4b7a203fbd9685ea378e95c..71e6c4d26ce36f9e1079caf2d1572dc35e39ad0c 100644 --- a/src/map.hpp +++ b/src/map.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2014, Nicolas Mansard, 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 @@ -21,14 +21,14 @@ namespace eigenpy { - template< typename MatType, int IsVector> + template<typename MatType, typename InputScalar, int IsVector> struct MapNumpyTraits {}; /* Wrap a numpy::array with an Eigen::Map. No memory copy. */ - template< typename MatType > + template<typename MatType, typename InputScalar> struct MapNumpy { - typedef MapNumpyTraits<MatType, MatType::IsVectorAtCompileTime> Impl; + typedef MapNumpyTraits<MatType, InputScalar, MatType::IsVectorAtCompileTime> Impl; typedef typename Impl::EigenMap EigenMap; typedef typename Impl::Stride Stride; @@ -43,12 +43,12 @@ namespace eigenpy namespace eigenpy { - template<typename MatType> - struct MapNumpyTraits<MatType,0> + template<typename MatType, typename InputScalar> + struct MapNumpyTraits<MatType,InputScalar,0> { typedef typename StrideType<MatType>::type Stride; - typedef Eigen::Map<MatType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap; - typedef typename MatType::Scalar Scalar; + typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType; + typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap; static EigenMap mapImpl( PyArrayObject* pyArray ) { @@ -69,24 +69,24 @@ namespace eigenpy if( (MatType::RowsAtCompileTime!=R) - && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) - { throw eigenpy::Exception("The number of rows does not fit with the matrix type."); } + && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) + { throw eigenpy::Exception("The number of rows does not fit with the matrix type."); } if( (MatType::ColsAtCompileTime!=C) - && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) - { throw eigenpy::Exception("The number of columns does not fit with the matrix type."); } - - Scalar* pyData = reinterpret_cast<Scalar*>(PyArray_DATA(pyArray)); + && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) + { throw eigenpy::Exception("The number of columns does not fit with the matrix type."); } + + InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray)); return EigenMap( pyData, R,C, stride ); } }; - template<typename MatType> - struct MapNumpyTraits<MatType,1> + template<typename MatType, typename InputScalar> + struct MapNumpyTraits<MatType,InputScalar,1> { typedef typename StrideType<MatType>::type Stride; - typedef Eigen::Map<MatType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap; - typedef typename MatType::Scalar Scalar; + typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType; + typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap; static EigenMap mapImpl( PyArrayObject* pyArray ) { @@ -97,22 +97,23 @@ namespace eigenpy else rowMajor = (PyArray_DIMS(pyArray)[0]>PyArray_DIMS(pyArray)[1])?0:1; assert( (PyArray_DIMS(pyArray)[rowMajor]< INT_MAX) - && (PyArray_STRIDE(pyArray, rowMajor) )); + && (PyArray_STRIDE(pyArray, rowMajor) )); const int R = (int)PyArray_DIMS(pyArray)[rowMajor]; const long int itemsize = PyArray_ITEMSIZE(pyArray); const int stride = (int) PyArray_STRIDE(pyArray, rowMajor) / (int) itemsize;; if( (MatType::MaxSizeAtCompileTime!=R) - && (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) ) - { throw eigenpy::Exception("The number of elements does not fit with the vector type."); } + && (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) ) + { throw eigenpy::Exception("The number of elements does not fit with the vector type."); } - Scalar* pyData = reinterpret_cast<Scalar*>(PyArray_DATA(pyArray)); + InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray)); + return EigenMap( pyData, R, Stride(stride) ); } }; - template< typename MatType > - typename MapNumpy<MatType>::EigenMap MapNumpy<MatType>::map( PyArrayObject* pyArray ) + template<typename MatType, typename InputScalar> + typename MapNumpy<MatType,InputScalar>::EigenMap MapNumpy<MatType,InputScalar>::map( PyArrayObject* pyArray ) { return Impl::mapImpl(pyArray); }