Skip to content

Commit 423191d

Browse files
authored
Merge pull request #79 from jcarpent/devel
Improve efficiency + fix bug in Eigen::MatrixBase
2 parents 48ff1fd + 02cdbf0 commit 423191d

File tree

9 files changed

+191
-61
lines changed

9 files changed

+191
-61
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ SET(${PROJECT_NAME}_HEADERS
103103
include/eigenpy/quaternion.hpp
104104
include/eigenpy/stride.hpp
105105
include/eigenpy/ref.hpp
106+
include/eigenpy/details/rvalue_from_python_data.hpp
106107
)
107108

108109
INCLUDE_DIRECTORIES(${${PROJECT_NAME}_BINARY_DIR}/include)

include/eigenpy/details.hpp

Lines changed: 120 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef __eigenpy_details_hpp__
77
#define __eigenpy_details_hpp__
88

9+
#include "eigenpy/details/rvalue_from_python_data.hpp"
910
#include "eigenpy/fwd.hpp"
1011

1112
#include <patchlevel.h> // For PY_MAJOR_VERSION
@@ -18,7 +19,6 @@
1819

1920
#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0)
2021

21-
2222
namespace eigenpy
2323
{
2424
template <typename SCALAR> struct NumpyEquivalentType {};
@@ -146,33 +146,75 @@ namespace eigenpy
146146
const int rows = (int)PyArray_DIMS(pyArray)[0];
147147
const int cols = (int)PyArray_DIMS(pyArray)[1];
148148

149-
Type * mat_ptr = new(storage) Type(rows,cols);
149+
Type * mat_ptr = new (storage) Type(rows,cols);
150+
151+
if(NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE(pyArray))
152+
{
153+
*mat_ptr = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
154+
return;
155+
}
156+
150157
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
158+
{
151159
*mat_ptr = MapNumpy<MatType,int>::map(pyArray).template cast<Scalar>();
160+
return;
161+
}
152162

153163
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
164+
{
154165
*mat_ptr = MapNumpy<MatType,long>::map(pyArray).template cast<Scalar>();
166+
return;
167+
}
155168

156169
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
170+
{
157171
*mat_ptr = MapNumpy<MatType,float>::map(pyArray).template cast<Scalar>();
172+
return;
173+
}
158174

159175
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
176+
{
160177
*mat_ptr = MapNumpy<MatType,double>::map(pyArray).template cast<Scalar>();
178+
return;
179+
}
161180
}
162181

163-
static void convert(Type const & mat , PyArrayObject * pyArray)
182+
/// \brief Copy mat into the Python array using Eigen::Map
183+
template<typename MatrixDerived>
184+
static void convert(const Eigen::MatrixBase<MatrixDerived> & mat_,
185+
PyArrayObject * pyArray)
164186
{
187+
const MatrixDerived & mat = const_cast<const MatrixDerived &>(mat_.derived());
188+
189+
if(NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE(pyArray))
190+
{
191+
MapNumpy<MatType,Scalar>::map(pyArray) = mat; // no cast needed
192+
return;
193+
}
194+
165195
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
196+
{
166197
MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();
198+
return;
199+
}
167200

168201
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
202+
{
169203
MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();
204+
return;
205+
}
170206

171207
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
208+
{
172209
MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();
210+
return;
211+
}
173212

174213
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
214+
{
175215
MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
216+
return;
217+
}
176218
}
177219
};
178220

@@ -186,51 +228,47 @@ namespace eigenpy
186228
static void allocate(PyArrayObject * pyArray, void * storage)
187229
{
188230
typename MapNumpy<MatType,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray);
189-
new(storage) Type(numpyMap);
231+
new (storage) Type(numpyMap);
190232
}
191233

192-
static void convert(Type const & mat , PyArrayObject * pyArray)
234+
static void convert(Type const & mat, PyArrayObject * pyArray)
193235
{
194-
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
195-
MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();
196-
197-
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
198-
MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();
199-
200-
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
201-
MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();
202-
203-
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
204-
MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
236+
EigenObjectAllocator<MatType>::convert(mat,pyArray);
205237
}
206238
};
207239
#endif
240+
208241
/* --- TO PYTHON -------------------------------------------------------------- */
242+
209243
template<typename MatType>
210244
struct EigenToPy
211245
{
212-
static PyObject* convert(MatType const& mat)
246+
static PyObject* convert(MatType const & mat)
213247
{
214-
typedef typename MatType::Scalar T;
248+
typedef typename MatType::Scalar Scalar;
215249
assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
216250
&& "Matrix range larger than int ... should never happen." );
217251
const int R = (int)mat.rows(), C = (int)mat.cols();
218252

219253
PyArrayObject* pyArray;
220-
if(C == 1 && NumpyType::getType() == ARRAY_TYPE)
254+
// Allocate Python memory
255+
if(C == 1 && NumpyType::getType() == ARRAY_TYPE) // Handle array with a single dimension
221256
{
222257
npy_intp shape[1] = { R };
223258
pyArray = (PyArrayObject*) PyArray_SimpleNew(1, shape,
224-
NumpyEquivalentType<T>::type_code);
259+
NumpyEquivalentType<Scalar>::type_code);
225260
}
226261
else
227262
{
228263
npy_intp shape[2] = { R,C };
229264
pyArray = (PyArrayObject*) PyArray_SimpleNew(2, shape,
230-
NumpyEquivalentType<T>::type_code);
265+
NumpyEquivalentType<Scalar>::type_code);
231266
}
232267

268+
// Allocate memory
233269
EigenObjectAllocator<MatType>::convert(mat,pyArray);
270+
271+
// Create an instance (either np.array or np.matrix)
234272
return NumpyType::getInstance().make(pyArray).ptr();
235273
}
236274
};
@@ -240,28 +278,28 @@ namespace eigenpy
240278
template<typename MatType>
241279
struct EigenFromPy
242280
{
243-
// Determine if obj_ptr can be converted in a Eigenvec
244-
static void* convertible(PyArrayObject* obj_ptr)
281+
/// \brief Determine if pyObj can be converted into a MatType object
282+
static void* convertible(PyArrayObject* pyObj)
245283
{
246-
if (!PyArray_Check(obj_ptr))
284+
if (!PyArray_Check(pyObj))
247285
return 0;
248286

249287
if(MatType::IsVectorAtCompileTime)
250288
{
251289
// Special care of scalar matrix of dimension 1x1.
252-
if(PyArray_DIMS(obj_ptr)[0] == 1 && PyArray_DIMS(obj_ptr)[1] == 1)
253-
return obj_ptr;
290+
if(PyArray_DIMS(pyObj)[0] == 1 && PyArray_DIMS(pyObj)[1] == 1)
291+
return pyObj;
254292

255-
if(PyArray_DIMS(obj_ptr)[0] > 1 && PyArray_DIMS(obj_ptr)[1] > 1)
293+
if(PyArray_DIMS(pyObj)[0] > 1 && PyArray_DIMS(pyObj)[1] > 1)
256294
{
257295
#ifndef NDEBUG
258296
std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
259297
#endif
260298
return 0;
261299
}
262300

263-
if(((PyArray_DIMS(obj_ptr)[0] == 1) && (MatType::ColsAtCompileTime == 1))
264-
|| ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
301+
if(((PyArray_DIMS(pyObj)[0] == 1) && (MatType::ColsAtCompileTime == 1))
302+
|| ((PyArray_DIMS(pyObj)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
265303
{
266304
#ifndef NDEBUG
267305
if(MatType::ColsAtCompileTime == 1)
@@ -273,9 +311,9 @@ namespace eigenpy
273311
}
274312
}
275313

276-
if (PyArray_NDIM(obj_ptr) != 2)
314+
if (PyArray_NDIM(pyObj) != 2)
277315
{
278-
if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
316+
if ( (PyArray_NDIM(pyObj) !=1) || (! MatType::IsVectorAtCompileTime) )
279317
{
280318
#ifndef NDEBUG
281319
std::cerr << "The number of dimension of the object is not correct." << std::endl;
@@ -284,10 +322,10 @@ namespace eigenpy
284322
}
285323
}
286324

287-
if (PyArray_NDIM(obj_ptr) == 2)
325+
if (PyArray_NDIM(pyObj) == 2)
288326
{
289-
const int R = (int)PyArray_DIMS(obj_ptr)[0];
290-
const int C = (int)PyArray_DIMS(obj_ptr)[1];
327+
const int R = (int)PyArray_DIMS(pyObj)[0];
328+
const int C = (int)PyArray_DIMS(pyObj)[1];
291329

292330
if( (MatType::RowsAtCompileTime!=R)
293331
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
@@ -298,7 +336,7 @@ namespace eigenpy
298336
}
299337

300338
// Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType
301-
if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_INT)
339+
if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(pyObj), 0)) == NPY_INT)
302340
{
303341
if(!FromTypeToType<int,typename MatType::Scalar>::value)
304342
{
@@ -308,7 +346,7 @@ namespace eigenpy
308346
return 0;
309347
}
310348
}
311-
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_LONG)
349+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(pyObj), 0)) == NPY_LONG)
312350
{
313351
if(!FromTypeToType<long,typename MatType::Scalar>::value)
314352
{
@@ -318,7 +356,7 @@ namespace eigenpy
318356
return 0;
319357
}
320358
}
321-
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_FLOAT)
359+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(pyObj), 0)) == NPY_FLOAT)
322360
{
323361
if(!FromTypeToType<float,typename MatType::Scalar>::value)
324362
{
@@ -328,7 +366,7 @@ namespace eigenpy
328366
return 0;
329367
}
330368
}
331-
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_DOUBLE)
369+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(pyObj), 0)) == NPY_DOUBLE)
332370
{
333371
if(!FromTypeToType<double,typename MatType::Scalar>::value)
334372
{
@@ -338,7 +376,7 @@ namespace eigenpy
338376
return 0;
339377
}
340378
}
341-
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
379+
else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(pyObj), 0))
342380
!= NumpyEquivalentType<typename MatType::Scalar>::type_code)
343381
{
344382
#ifndef NDEBUG
@@ -349,7 +387,7 @@ namespace eigenpy
349387
}
350388

351389
#ifdef NPY_1_8_API_VERSION
352-
if (!(PyArray_FLAGS(obj_ptr)))
390+
if (!(PyArray_FLAGS(pyObj)))
353391
#else
354392
if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
355393
#endif
@@ -360,15 +398,13 @@ namespace eigenpy
360398
return 0;
361399
}
362400

363-
return obj_ptr;
401+
return pyObj;
364402
}
365403

366-
// Convert obj_ptr into an Eigen::Vector
404+
/// \brief Allocate memory and copy pyObj in the new storage
367405
static void construct(PyObject* pyObj,
368406
bp::converter::rvalue_from_python_stage1_data* memory)
369407
{
370-
using namespace Eigen;
371-
372408
PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
373409
assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
374410

@@ -379,6 +415,42 @@ namespace eigenpy
379415

380416
memory->convertible = storage;
381417
}
418+
419+
static void registration()
420+
{
421+
bp::converter::registry::push_back
422+
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
423+
&EigenFromPy::construct,bp::type_id<MatType>());
424+
}
425+
};
426+
427+
template<typename MatType>
428+
struct EigenFromPy< Eigen::MatrixBase<MatType> >
429+
{
430+
typedef EigenFromPy<MatType> EigenFromPyDerived;
431+
typedef Eigen::MatrixBase<MatType> Base;
432+
433+
/// \brief Determine if pyObj can be converted into a MatType object
434+
static void* convertible(PyArrayObject* pyObj)
435+
{
436+
std::cout << "call: EigenFromPy< Eigen::MatrixBase<MatType> >::convertible" << std::endl;
437+
return EigenFromPyDerived::convertible(pyObj);
438+
}
439+
440+
/// \brief Allocate memory and copy pyObj in the new storage
441+
static void construct(PyObject* pyObj,
442+
bp::converter::rvalue_from_python_stage1_data* memory)
443+
{
444+
std::cout << "call: EigenFromPy< Eigen::MatrixBase<MatType> >::construct" << std::endl;
445+
EigenFromPyDerived::construct(pyObj,memory);
446+
}
447+
448+
static void registration()
449+
{
450+
bp::converter::registry::push_back
451+
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
452+
&EigenFromPy::construct,bp::type_id<Base>());
453+
}
382454
};
383455

384456
#define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } }
@@ -394,14 +466,11 @@ namespace eigenpy
394466
{
395467
static void registration()
396468
{
397-
bp::converter::registry::push_back
398-
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
399-
&EigenFromPy<MatType>::construct,bp::type_id<MatType>());
400-
469+
EigenFromPy<MatType>::registration();
470+
401471
// Add also conversion to Eigen::MatrixBase<MatType>
402-
bp::converter::registry::push_back
403-
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
404-
&EigenFromPy<MatType>::construct,bp::type_id< Eigen::MatrixBase<MatType> >());
472+
typedef Eigen::MatrixBase<MatType> MatTypeBase;
473+
EigenFromPy<MatTypeBase>::registration();
405474
}
406475
};
407476

@@ -419,7 +488,6 @@ namespace eigenpy
419488
};
420489
#endif
421490

422-
423491
template<typename MatType>
424492
void enableEigenPySpecific()
425493
{

0 commit comments

Comments
 (0)