Skip to content
Snippets Groups Projects
Commit bb71dc94 authored by jcarpent's avatar jcarpent
Browse files

[Matrix] Handle conversion between compatible scalar types

parent 3c49a008
Branches
Tags
No related merge requests found
...@@ -26,13 +26,31 @@ ...@@ -26,13 +26,31 @@
#include "eigenpy/registration.hpp" #include "eigenpy/registration.hpp"
#include "eigenpy/map.hpp" #include "eigenpy/map.hpp"
#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0)
namespace eigenpy namespace eigenpy
{ {
template <typename SCALAR> struct NumpyEquivalentType {}; template <typename SCALAR> struct NumpyEquivalentType {};
template <> struct NumpyEquivalentType<double> { enum { type_code = NPY_DOUBLE };}; template <> struct NumpyEquivalentType<double> { enum { type_code = NPY_DOUBLE };};
template <> struct NumpyEquivalentType<int> { enum { type_code = NPY_INT };}; 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 <> 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; namespace bp = boost::python;
...@@ -72,16 +90,40 @@ namespace eigenpy ...@@ -72,16 +90,40 @@ namespace eigenpy
struct EigenObjectAllocator struct EigenObjectAllocator
{ {
typedef MatType Type; typedef MatType Type;
typedef typename MatType::Scalar Scalar;
static void allocate(PyArrayObject * pyArray, void * storage) static void allocate(PyArrayObject * pyArray, void * storage)
{ {
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray); const int rows = (int)PyArray_DIMS(pyArray)[0];
new(storage) MatType(numpyMap); 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) 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 ...@@ -90,16 +132,27 @@ namespace eigenpy
struct EigenObjectAllocator< eigenpy::Ref<MatType> > struct EigenObjectAllocator< eigenpy::Ref<MatType> >
{ {
typedef eigenpy::Ref<MatType> Type; typedef eigenpy::Ref<MatType> Type;
typedef typename MatType::Scalar Scalar;
static void allocate(PyArrayObject * pyArray, void * storage) 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); new(storage) Type(numpyMap);
} }
static void convert(Type const & mat , PyArrayObject * pyArray) 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 #endif
...@@ -140,8 +193,6 @@ namespace eigenpy ...@@ -140,8 +193,6 @@ namespace eigenpy
// Determine if obj_ptr can be converted in a Eigenvec // Determine if obj_ptr can be converted in a Eigenvec
static void* convertible(PyArrayObject* obj_ptr) static void* convertible(PyArrayObject* obj_ptr)
{ {
std::cout << "call convertible" << std::endl;
if (!PyArray_Check(obj_ptr)) if (!PyArray_Check(obj_ptr))
{ {
#ifndef NDEBUG #ifndef NDEBUG
...@@ -149,10 +200,6 @@ namespace eigenpy ...@@ -149,10 +200,6 @@ namespace eigenpy
#endif #endif
return 0; 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) if(MatType::IsVectorAtCompileTime)
{ {
// Special care of scalar matrix of dimension 1x1. // Special care of scalar matrix of dimension 1x1.
...@@ -171,7 +218,6 @@ namespace eigenpy ...@@ -171,7 +218,6 @@ namespace eigenpy
|| ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1))) || ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
{ {
#ifndef NDEBUG #ifndef NDEBUG
std::cout << "MatType::ColsAtCompileTime: " << MatType::ColsAtCompileTime << std::endl;
if(MatType::ColsAtCompileTime == 1) if(MatType::ColsAtCompileTime == 1)
std::cerr << "The object is not a column vector" << std::endl; std::cerr << "The object is not a column vector" << std::endl;
else else
...@@ -192,14 +238,57 @@ namespace eigenpy ...@@ -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) != NumpyEquivalentType<typename MatType::Scalar>::type_code)
{ {
#ifndef NDEBUG #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 #endif
return 0; return 0;
} }
#ifdef NPY_1_8_API_VERSION #ifdef NPY_1_8_API_VERSION
if (!(PyArray_FLAGS(obj_ptr))) if (!(PyArray_FLAGS(obj_ptr)))
#else #else
......
/* /*
* Copyright 2014, Nicolas Mansard, LAAS-CNRS * Copyright 2014-2018, Nicolas Mansard and Justin Carpentier, LAAS-CNRS
* *
* This file is part of eigenpy. * This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or * eigenpy is free software: you can redistribute it and/or
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
namespace eigenpy namespace eigenpy
{ {
template< typename MatType, int IsVector> template<typename MatType, typename InputScalar, int IsVector>
struct MapNumpyTraits {}; struct MapNumpyTraits {};
/* Wrap a numpy::array with an Eigen::Map. No memory copy. */ /* Wrap a numpy::array with an Eigen::Map. No memory copy. */
template< typename MatType > template<typename MatType, typename InputScalar>
struct MapNumpy struct MapNumpy
{ {
typedef MapNumpyTraits<MatType, MatType::IsVectorAtCompileTime> Impl; typedef MapNumpyTraits<MatType, InputScalar, MatType::IsVectorAtCompileTime> Impl;
typedef typename Impl::EigenMap EigenMap; typedef typename Impl::EigenMap EigenMap;
typedef typename Impl::Stride Stride; typedef typename Impl::Stride Stride;
...@@ -43,12 +43,12 @@ namespace eigenpy ...@@ -43,12 +43,12 @@ namespace eigenpy
namespace eigenpy namespace eigenpy
{ {
template<typename MatType> template<typename MatType, typename InputScalar>
struct MapNumpyTraits<MatType,0> struct MapNumpyTraits<MatType,InputScalar,0>
{ {
typedef typename StrideType<MatType>::type Stride; typedef typename StrideType<MatType>::type Stride;
typedef Eigen::Map<MatType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap; typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
typedef typename MatType::Scalar Scalar; typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
static EigenMap mapImpl( PyArrayObject* pyArray ) static EigenMap mapImpl( PyArrayObject* pyArray )
{ {
...@@ -69,24 +69,24 @@ namespace eigenpy ...@@ -69,24 +69,24 @@ namespace eigenpy
if( (MatType::RowsAtCompileTime!=R) if( (MatType::RowsAtCompileTime!=R)
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) && (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of rows does not fit with the matrix type."); } { throw eigenpy::Exception("The number of rows does not fit with the matrix type."); }
if( (MatType::ColsAtCompileTime!=C) if( (MatType::ColsAtCompileTime!=C)
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) && (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of columns does not fit with the matrix type."); } { throw eigenpy::Exception("The number of columns does not fit with the matrix type."); }
Scalar* pyData = reinterpret_cast<Scalar*>(PyArray_DATA(pyArray)); InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
return EigenMap( pyData, R,C, stride ); return EigenMap( pyData, R,C, stride );
} }
}; };
template<typename MatType> template<typename MatType, typename InputScalar>
struct MapNumpyTraits<MatType,1> struct MapNumpyTraits<MatType,InputScalar,1>
{ {
typedef typename StrideType<MatType>::type Stride; typedef typename StrideType<MatType>::type Stride;
typedef Eigen::Map<MatType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap; typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
typedef typename MatType::Scalar Scalar; typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
static EigenMap mapImpl( PyArrayObject* pyArray ) static EigenMap mapImpl( PyArrayObject* pyArray )
{ {
...@@ -97,22 +97,23 @@ namespace eigenpy ...@@ -97,22 +97,23 @@ namespace eigenpy
else rowMajor = (PyArray_DIMS(pyArray)[0]>PyArray_DIMS(pyArray)[1])?0:1; else rowMajor = (PyArray_DIMS(pyArray)[0]>PyArray_DIMS(pyArray)[1])?0:1;
assert( (PyArray_DIMS(pyArray)[rowMajor]< INT_MAX) assert( (PyArray_DIMS(pyArray)[rowMajor]< INT_MAX)
&& (PyArray_STRIDE(pyArray, rowMajor) )); && (PyArray_STRIDE(pyArray, rowMajor) ));
const int R = (int)PyArray_DIMS(pyArray)[rowMajor]; const int R = (int)PyArray_DIMS(pyArray)[rowMajor];
const long int itemsize = PyArray_ITEMSIZE(pyArray); const long int itemsize = PyArray_ITEMSIZE(pyArray);
const int stride = (int) PyArray_STRIDE(pyArray, rowMajor) / (int) itemsize;; const int stride = (int) PyArray_STRIDE(pyArray, rowMajor) / (int) itemsize;;
if( (MatType::MaxSizeAtCompileTime!=R) if( (MatType::MaxSizeAtCompileTime!=R)
&& (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) ) && (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of elements does not fit with the vector type."); } { 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) ); return EigenMap( pyData, R, Stride(stride) );
} }
}; };
template< typename MatType > template<typename MatType, typename InputScalar>
typename MapNumpy<MatType>::EigenMap MapNumpy<MatType>::map( PyArrayObject* pyArray ) typename MapNumpy<MatType,InputScalar>::EigenMap MapNumpy<MatType,InputScalar>::map( PyArrayObject* pyArray )
{ {
return Impl::mapImpl(pyArray); return Impl::mapImpl(pyArray);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment