diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ec991bb415c4c82a25fb436fefee3ce3d2ea74d..1c261343b0b04559ee5691b6d305ac3257c52d1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,7 @@ SET(${PROJECT_NAME}_HEADERS include/eigenpy/expose.hpp include/eigenpy/details.hpp include/eigenpy/fwd.hpp + include/eigenpy/eigen-allocator.hpp include/eigenpy/map.hpp include/eigenpy/geometry.hpp include/eigenpy/geometry-conversion.hpp diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp index fddd6604b677beb40aeeaa41b4a9df034e30b63c..82ec077999768f56ccaa13872219b17a68ffad73 100644 --- a/include/eigenpy/details.hpp +++ b/include/eigenpy/details.hpp @@ -12,9 +12,12 @@ #include <patchlevel.h> // For PY_MAJOR_VERSION #include <iostream> +#include "eigenpy/numpy-type.hpp" #include "eigenpy/scalar-conversion.hpp" #include "eigenpy/eigenpy.hpp" -#include "eigenpy/numpy-type.hpp" + +#include "eigenpy/eigen-allocator.hpp" + #include "eigenpy/registration.hpp" #include "eigenpy/map.hpp" #include "eigenpy/exception.hpp" @@ -56,206 +59,8 @@ namespace boost { namespace python { namespace detail { namespace eigenpy { - - namespace bp = boost::python; - template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime> - struct initEigenObject - { - static MatType * run(PyArrayObject * pyArray, void * storage) - { - assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2); - - int rows = -1, cols = -1; - if(PyArray_NDIM(pyArray) == 2) - { - rows = (int)PyArray_DIMS(pyArray)[0]; - cols = (int)PyArray_DIMS(pyArray)[1]; - } - else if(PyArray_NDIM(pyArray) == 1) - { - rows = (int)PyArray_DIMS(pyArray)[0]; - cols = 1; - } - - return new (storage) MatType(rows,cols); - } - }; - - template<typename MatType> - struct initEigenObject<MatType,true> - { - static MatType * run(PyArrayObject * pyArray, void * storage) - { - if(PyArray_NDIM(pyArray) == 1) - { - const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0]; - return new (storage) MatType(rows_or_cols); - } - else - { - const int rows = (int)PyArray_DIMS(pyArray)[0]; - const int cols = (int)PyArray_DIMS(pyArray)[1]; - return new (storage) MatType(rows,cols); - } - } - }; - - template<typename Scalar, typename NewScalar, bool cast_is_valid = FromTypeToType<Scalar,NewScalar>::value > - struct CastMatToMat - { - template<typename MatrixIn, typename MatrixOut> - static void run(const Eigen::MatrixBase<MatrixIn> & input, - const Eigen::MatrixBase<MatrixOut> & dest) - { - MatrixOut & dest_ = const_cast<MatrixOut &>(dest.derived()); - if(dest.rows() == input.rows()) - dest_ = input.template cast<NewScalar>(); - else - dest_ = input.transpose().template cast<NewScalar>(); - } - }; - - template<typename Scalar, typename NewScalar> - struct CastMatToMat<Scalar,NewScalar,false> - { - template<typename MatrixIn, typename MatrixOut> - static void run(const Eigen::MatrixBase<MatrixIn> & /*input*/, - const Eigen::MatrixBase<MatrixOut> & /*dest*/) - { - // do nothing - assert("Must never happened"); - } - }; - -#define EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,Scalar,NewScalar,pyArray,mat) \ - CastMatToMat<Scalar,NewScalar>::run(MapNumpy<MatType,Scalar>::map(pyArray),mat) - -#define EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,NewScalar,mat,pyArray) \ - CastMatToMat<Scalar,NewScalar>::run(mat,MapNumpy<MatType,NewScalar>::map(pyArray)) - - template<typename MatType> - struct EigenObjectAllocator - { - typedef MatType Type; - typedef typename MatType::Scalar Scalar; - - static void allocate(PyArrayObject * pyArray, void * storage) - { - Type * mat_ptr = initEigenObject<Type>::run(pyArray,storage); - Type & mat = *mat_ptr; - - const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray); - if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code) - { - mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast - return; - } - - switch(pyArray_Type) - { - case NPY_INT: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat); - break; - case NPY_LONG: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat); - break; - case NPY_FLOAT: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat); - break; - case NPY_CFLOAT: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat); - break; - case NPY_DOUBLE: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat); - break; - case NPY_CDOUBLE: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat); - break; - case NPY_LONGDOUBLE: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat); - break; - case NPY_CLONGDOUBLE: - EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat); - break; - default: - throw Exception("You asked for a conversion which is not implemented."); - } - } - - /// \brief Copy mat into the Python array using Eigen::Map - template<typename MatrixDerived> - static void copy(const Eigen::MatrixBase<MatrixDerived> & mat_, - PyArrayObject * pyArray) - { - const MatrixDerived & mat = const_cast<const MatrixDerived &>(mat_.derived()); - const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray); - - typedef typename MapNumpy<MatType,Scalar>::EigenMap MapType; - - if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code) // no cast needed - { - MapType map_pyArray = MapNumpy<MatType,Scalar>::map(pyArray); - if(mat.rows() == map_pyArray.rows()) - map_pyArray = mat; - else - map_pyArray = mat.transpose(); - return; - } - - switch(pyArray_Type) - { - case NPY_INT: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,int,mat,pyArray); - break; - case NPY_LONG: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long,mat,pyArray); - break; - case NPY_FLOAT: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,float,mat,pyArray); - break; - case NPY_CFLOAT: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<float>,mat,pyArray); - break; - case NPY_DOUBLE: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,double,mat,pyArray); - break; - case NPY_CDOUBLE: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<double>,mat,pyArray); - break; - case NPY_LONGDOUBLE: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long double,mat,pyArray); - break; - case NPY_CLONGDOUBLE: - EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<long double>,mat,pyArray); - break; - default: - throw Exception("You asked for a conversion which is not implemented."); - } - } - }; - -#if EIGEN_VERSION_AT_LEAST(3,2,0) - template<typename MatType> - 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,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray); - new (storage) Type(numpyMap); - } - - static void copy(Type const & mat, PyArrayObject * pyArray) - { - EigenObjectAllocator<MatType>::copy(mat,pyArray); - } - }; -#endif - /* --- TO PYTHON -------------------------------------------------------------- */ template<typename MatType> diff --git a/include/eigenpy/eigen-allocator.hpp b/include/eigenpy/eigen-allocator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dbb6d11277d0acf61dd37b71b1bb6b5b6269b26e --- /dev/null +++ b/include/eigenpy/eigen-allocator.hpp @@ -0,0 +1,211 @@ +// +// Copyright (c) 2014-2020 CNRS INRIA +// + +#ifndef __eigenpy_eigen_allocator_hpp__ +#define __eigenpy_eigen_allocator_hpp__ + +#include "eigenpy/fwd.hpp" +#include "eigenpy/map.hpp" +#include "eigenpy/scalar-conversion.hpp" + +namespace eigenpy +{ + template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime> + struct initEigenObject + { + static MatType * run(PyArrayObject * pyArray, void * storage) + { + assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2); + + int rows = -1, cols = -1; + if(PyArray_NDIM(pyArray) == 2) + { + rows = (int)PyArray_DIMS(pyArray)[0]; + cols = (int)PyArray_DIMS(pyArray)[1]; + } + else if(PyArray_NDIM(pyArray) == 1) + { + rows = (int)PyArray_DIMS(pyArray)[0]; + cols = 1; + } + + return new (storage) MatType(rows,cols); + } + }; + + template<typename MatType> + struct initEigenObject<MatType,true> + { + static MatType * run(PyArrayObject * pyArray, void * storage) + { + if(PyArray_NDIM(pyArray) == 1) + { + const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0]; + return new (storage) MatType(rows_or_cols); + } + else + { + const int rows = (int)PyArray_DIMS(pyArray)[0]; + const int cols = (int)PyArray_DIMS(pyArray)[1]; + return new (storage) MatType(rows,cols); + } + } + }; + + template<typename Scalar, typename NewScalar, bool cast_is_valid = FromTypeToType<Scalar,NewScalar>::value > + struct CastMatToMat + { + template<typename MatrixIn, typename MatrixOut> + static void run(const Eigen::MatrixBase<MatrixIn> & input, + const Eigen::MatrixBase<MatrixOut> & dest) + { + MatrixOut & dest_ = const_cast<MatrixOut &>(dest.derived()); + if(dest.rows() == input.rows()) + dest_ = input.template cast<NewScalar>(); + else + dest_ = input.transpose().template cast<NewScalar>(); + } + }; + + template<typename Scalar, typename NewScalar> + struct CastMatToMat<Scalar,NewScalar,false> + { + template<typename MatrixIn, typename MatrixOut> + static void run(const Eigen::MatrixBase<MatrixIn> & /*input*/, + const Eigen::MatrixBase<MatrixOut> & /*dest*/) + { + // do nothing + assert("Must never happened"); + } + }; + +#define EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,Scalar,NewScalar,pyArray,mat) \ + CastMatToMat<Scalar,NewScalar>::run(MapNumpy<MatType,Scalar>::map(pyArray),mat) + +#define EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,NewScalar,mat,pyArray) \ + CastMatToMat<Scalar,NewScalar>::run(mat,MapNumpy<MatType,NewScalar>::map(pyArray)) + + template<typename MatType> + struct EigenObjectAllocator + { + typedef MatType Type; + typedef typename MatType::Scalar Scalar; + + static void allocate(PyArrayObject * pyArray, void * storage) + { + Type * mat_ptr = initEigenObject<Type>::run(pyArray,storage); + Type & mat = *mat_ptr; + + const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray); + if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code) + { + mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast + return; + } + + switch(pyArray_Type) + { + case NPY_INT: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat); + break; + case NPY_LONG: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat); + break; + case NPY_FLOAT: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat); + break; + case NPY_CFLOAT: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat); + break; + case NPY_DOUBLE: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat); + break; + case NPY_CDOUBLE: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat); + break; + case NPY_LONGDOUBLE: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat); + break; + case NPY_CLONGDOUBLE: + EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat); + break; + default: + throw Exception("You asked for a conversion which is not implemented."); + } + } + + /// \brief Copy mat into the Python array using Eigen::Map + template<typename MatrixDerived> + static void copy(const Eigen::MatrixBase<MatrixDerived> & mat_, + PyArrayObject * pyArray) + { + const MatrixDerived & mat = const_cast<const MatrixDerived &>(mat_.derived()); + const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray); + + typedef typename MapNumpy<MatType,Scalar>::EigenMap MapType; + + if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code) // no cast needed + { + MapType map_pyArray = MapNumpy<MatType,Scalar>::map(pyArray); + if(mat.rows() == map_pyArray.rows()) + map_pyArray = mat; + else + map_pyArray = mat.transpose(); + return; + } + + switch(pyArray_Type) + { + case NPY_INT: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,int,mat,pyArray); + break; + case NPY_LONG: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long,mat,pyArray); + break; + case NPY_FLOAT: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,float,mat,pyArray); + break; + case NPY_CFLOAT: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<float>,mat,pyArray); + break; + case NPY_DOUBLE: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,double,mat,pyArray); + break; + case NPY_CDOUBLE: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<double>,mat,pyArray); + break; + case NPY_LONGDOUBLE: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long double,mat,pyArray); + break; + case NPY_CLONGDOUBLE: + EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<long double>,mat,pyArray); + break; + default: + throw Exception("You asked for a conversion which is not implemented."); + } + } + }; + +#if EIGEN_VERSION_AT_LEAST(3,2,0) + template<typename MatType> + 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,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray); + new (storage) Type(numpyMap); + } + + static void copy(Type const & mat, PyArrayObject * pyArray) + { + EigenObjectAllocator<MatType>::copy(mat,pyArray); + } + }; +#endif +} + +#endif // __eigenpy_eigen_allocator_hpp__