Skip to content

Commit b19c481

Browse files
authored
Merge pull request #29 from jcarpent/devel
Handle conversion between compatible scalar types
2 parents 3c49a00 + bb71dc9 commit b19c481

File tree

2 files changed

+127
-37
lines changed

2 files changed

+127
-37
lines changed

src/details.hpp

Lines changed: 102 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,31 @@
2626
#include "eigenpy/registration.hpp"
2727
#include "eigenpy/map.hpp"
2828

29+
#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0)
30+
2931

3032
namespace eigenpy
3133
{
3234
template <typename SCALAR> struct NumpyEquivalentType {};
3335
template <> struct NumpyEquivalentType<double> { enum { type_code = NPY_DOUBLE };};
3436
template <> struct NumpyEquivalentType<int> { enum { type_code = NPY_INT };};
37+
template <> struct NumpyEquivalentType<long> { enum { type_code = NPY_LONG };};
3538
template <> struct NumpyEquivalentType<float> { enum { type_code = NPY_FLOAT };};
39+
40+
template <typename SCALAR1, typename SCALAR2>
41+
struct FromTypeToType : public boost::false_type {};
42+
43+
template <typename SCALAR>
44+
struct FromTypeToType<SCALAR,SCALAR> : public boost::true_type {};
45+
46+
template <> struct FromTypeToType<int,long> : public boost::true_type {};
47+
template <> struct FromTypeToType<int,float> : public boost::true_type {};
48+
template <> struct FromTypeToType<int,double> : public boost::true_type {};
49+
50+
template <> struct FromTypeToType<long,float> : public boost::true_type {};
51+
template <> struct FromTypeToType<long,double> : public boost::true_type {};
52+
53+
template <> struct FromTypeToType<float,double> : public boost::true_type {};
3654

3755
namespace bp = boost::python;
3856

@@ -72,16 +90,40 @@ namespace eigenpy
7290
struct EigenObjectAllocator
7391
{
7492
typedef MatType Type;
93+
typedef typename MatType::Scalar Scalar;
7594

7695
static void allocate(PyArrayObject * pyArray, void * storage)
7796
{
78-
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray);
79-
new(storage) MatType(numpyMap);
97+
const int rows = (int)PyArray_DIMS(pyArray)[0];
98+
const int cols = (int)PyArray_DIMS(pyArray)[1];
99+
100+
Type * mat_ptr = new(storage) Type(rows,cols);
101+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
102+
*mat_ptr = MapNumpy<MatType,int>::map(pyArray).template cast<Scalar>();
103+
104+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
105+
*mat_ptr = MapNumpy<MatType,long>::map(pyArray).template cast<Scalar>();
106+
107+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
108+
*mat_ptr = MapNumpy<MatType,float>::map(pyArray).template cast<Scalar>();
109+
110+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
111+
*mat_ptr = MapNumpy<MatType,double>::map(pyArray).template cast<Scalar>();
80112
}
81113

82114
static void convert(Type const & mat , PyArrayObject * pyArray)
83115
{
84-
MapNumpy<MatType>::map(pyArray) = mat;
116+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
117+
MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();
118+
119+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
120+
MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();
121+
122+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
123+
MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();
124+
125+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
126+
MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
85127
}
86128
};
87129

@@ -90,16 +132,27 @@ namespace eigenpy
90132
struct EigenObjectAllocator< eigenpy::Ref<MatType> >
91133
{
92134
typedef eigenpy::Ref<MatType> Type;
135+
typedef typename MatType::Scalar Scalar;
93136

94137
static void allocate(PyArrayObject * pyArray, void * storage)
95138
{
96-
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray);
139+
typename MapNumpy<MatType,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray);
97140
new(storage) Type(numpyMap);
98141
}
99142

100143
static void convert(Type const & mat , PyArrayObject * pyArray)
101144
{
102-
MapNumpy<MatType>::map(pyArray) = mat;
145+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
146+
MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();
147+
148+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
149+
MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();
150+
151+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
152+
MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();
153+
154+
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
155+
MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
103156
}
104157
};
105158
#endif
@@ -140,19 +193,13 @@ namespace eigenpy
140193
// Determine if obj_ptr can be converted in a Eigenvec
141194
static void* convertible(PyArrayObject* obj_ptr)
142195
{
143-
std::cout << "call convertible" << std::endl;
144-
145196
if (!PyArray_Check(obj_ptr))
146197
{
147198
#ifndef NDEBUG
148199
std::cerr << "The python object is not a numpy array." << std::endl;
149200
#endif
150201
return 0;
151202
}
152-
153-
std::cout << "PyArray_DIMS(obj_ptr)[0]: " << PyArray_DIMS(obj_ptr)[0] << std::endl;
154-
std::cout << "PyArray_DIMS(obj_ptr)[1]: " << PyArray_DIMS(obj_ptr)[1] << std::endl;
155-
156203
if(MatType::IsVectorAtCompileTime)
157204
{
158205
// Special care of scalar matrix of dimension 1x1.
@@ -171,7 +218,6 @@ namespace eigenpy
171218
|| ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
172219
{
173220
#ifndef NDEBUG
174-
std::cout << "MatType::ColsAtCompileTime: " << MatType::ColsAtCompileTime << std::endl;
175221
if(MatType::ColsAtCompileTime == 1)
176222
std::cerr << "The object is not a column vector" << std::endl;
177223
else
@@ -192,14 +238,57 @@ namespace eigenpy
192238
}
193239
}
194240

195-
if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
241+
// Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType
242+
if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_INT)
243+
{
244+
if(not FromTypeToType<int,typename MatType::Scalar>::value)
245+
{
246+
#ifndef NDEBUG
247+
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;
248+
#endif
249+
return 0;
250+
}
251+
}
252+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_LONG)
253+
{
254+
if(not FromTypeToType<long,typename MatType::Scalar>::value)
255+
{
256+
#ifndef NDEBUG
257+
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;
258+
#endif
259+
return 0;
260+
}
261+
}
262+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_FLOAT)
263+
{
264+
if(not FromTypeToType<float,typename MatType::Scalar>::value)
265+
{
266+
#ifndef NDEBUG
267+
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;
268+
#endif
269+
return 0;
270+
}
271+
}
272+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_DOUBLE)
273+
{
274+
if(not FromTypeToType<double,typename MatType::Scalar>::value)
275+
{
276+
#ifndef NDEBUG
277+
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;
278+
#endif
279+
return 0;
280+
}
281+
}
282+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
196283
!= NumpyEquivalentType<typename MatType::Scalar>::type_code)
197284
{
198285
#ifndef NDEBUG
199286
std::cerr << "The internal type as no Eigen equivalent." << std::endl;
200287
#endif
288+
201289
return 0;
202290
}
291+
203292
#ifdef NPY_1_8_API_VERSION
204293
if (!(PyArray_FLAGS(obj_ptr)))
205294
#else

src/map.hpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014, Nicolas Mansard, LAAS-CNRS
2+
* Copyright 2014-2018, Nicolas Mansard and Justin Carpentier, LAAS-CNRS
33
*
44
* This file is part of eigenpy.
55
* eigenpy is free software: you can redistribute it and/or
@@ -21,14 +21,14 @@
2121

2222
namespace eigenpy
2323
{
24-
template< typename MatType, int IsVector>
24+
template<typename MatType, typename InputScalar, int IsVector>
2525
struct MapNumpyTraits {};
2626

2727
/* Wrap a numpy::array with an Eigen::Map. No memory copy. */
28-
template< typename MatType >
28+
template<typename MatType, typename InputScalar>
2929
struct MapNumpy
3030
{
31-
typedef MapNumpyTraits<MatType, MatType::IsVectorAtCompileTime> Impl;
31+
typedef MapNumpyTraits<MatType, InputScalar, MatType::IsVectorAtCompileTime> Impl;
3232
typedef typename Impl::EigenMap EigenMap;
3333
typedef typename Impl::Stride Stride;
3434

@@ -43,12 +43,12 @@ namespace eigenpy
4343

4444
namespace eigenpy
4545
{
46-
template<typename MatType>
47-
struct MapNumpyTraits<MatType,0>
46+
template<typename MatType, typename InputScalar>
47+
struct MapNumpyTraits<MatType,InputScalar,0>
4848
{
4949
typedef typename StrideType<MatType>::type Stride;
50-
typedef Eigen::Map<MatType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
51-
typedef typename MatType::Scalar Scalar;
50+
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
51+
typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
5252

5353
static EigenMap mapImpl( PyArrayObject* pyArray )
5454
{
@@ -69,24 +69,24 @@ namespace eigenpy
6969

7070

7171
if( (MatType::RowsAtCompileTime!=R)
72-
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
73-
{ throw eigenpy::Exception("The number of rows does not fit with the matrix type."); }
72+
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
73+
{ throw eigenpy::Exception("The number of rows does not fit with the matrix type."); }
7474
if( (MatType::ColsAtCompileTime!=C)
75-
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
76-
{ throw eigenpy::Exception("The number of columns does not fit with the matrix type."); }
77-
78-
Scalar* pyData = reinterpret_cast<Scalar*>(PyArray_DATA(pyArray));
75+
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
76+
{ throw eigenpy::Exception("The number of columns does not fit with the matrix type."); }
77+
78+
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
7979

8080
return EigenMap( pyData, R,C, stride );
8181
}
8282
};
8383

84-
template<typename MatType>
85-
struct MapNumpyTraits<MatType,1>
84+
template<typename MatType, typename InputScalar>
85+
struct MapNumpyTraits<MatType,InputScalar,1>
8686
{
8787
typedef typename StrideType<MatType>::type Stride;
88-
typedef Eigen::Map<MatType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
89-
typedef typename MatType::Scalar Scalar;
88+
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
89+
typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
9090

9191
static EigenMap mapImpl( PyArrayObject* pyArray )
9292
{
@@ -97,22 +97,23 @@ namespace eigenpy
9797
else rowMajor = (PyArray_DIMS(pyArray)[0]>PyArray_DIMS(pyArray)[1])?0:1;
9898

9999
assert( (PyArray_DIMS(pyArray)[rowMajor]< INT_MAX)
100-
&& (PyArray_STRIDE(pyArray, rowMajor) ));
100+
&& (PyArray_STRIDE(pyArray, rowMajor) ));
101101
const int R = (int)PyArray_DIMS(pyArray)[rowMajor];
102102
const long int itemsize = PyArray_ITEMSIZE(pyArray);
103103
const int stride = (int) PyArray_STRIDE(pyArray, rowMajor) / (int) itemsize;;
104104

105105
if( (MatType::MaxSizeAtCompileTime!=R)
106-
&& (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) )
107-
{ throw eigenpy::Exception("The number of elements does not fit with the vector type."); }
106+
&& (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) )
107+
{ throw eigenpy::Exception("The number of elements does not fit with the vector type."); }
108108

109-
Scalar* pyData = reinterpret_cast<Scalar*>(PyArray_DATA(pyArray));
109+
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
110+
110111
return EigenMap( pyData, R, Stride(stride) );
111112
}
112113
};
113114

114-
template< typename MatType >
115-
typename MapNumpy<MatType>::EigenMap MapNumpy<MatType>::map( PyArrayObject* pyArray )
115+
template<typename MatType, typename InputScalar>
116+
typename MapNumpy<MatType,InputScalar>::EigenMap MapNumpy<MatType,InputScalar>::map( PyArrayObject* pyArray )
116117
{
117118
return Impl::mapImpl(pyArray);
118119
}

0 commit comments

Comments
 (0)