eigen-from-python.hpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2014-2020 CNRS INRIA
3 //
4 
5 #ifndef __eigenpy_eigen_from_python_hpp__
6 #define __eigenpy_eigen_from_python_hpp__
7 
8 #include "eigenpy/fwd.hpp"
9 #include "eigenpy/numpy-type.hpp"
12 
13 #include <boost/python/converter/rvalue_from_python_data.hpp>
14 
15 namespace eigenpy
16 {
17  namespace details
18  {
21  {
22  static void run(const Eigen::MatrixBase<MatType> & input,
23  PyArrayObject * pyArray)
24  {
25  EigenAllocator<MatType>::copy(input,pyArray);
26  }
27  };
28 
29  template<typename MatType>
30  struct copy_if_non_const<const MatType,true>
31  {
32  static void run(const Eigen::MatrixBase<MatType> & /*input*/,
33  PyArrayObject * /*pyArray*/)
34  {}
35  };
36 
37 #if EIGEN_VERSION_AT_LEAST(3,2,0)
38  template<typename MatType, int Options, typename Stride> struct referent_storage_eigen_ref;
39 
40  template<typename MatType, int Options, typename Stride>
41  struct referent_storage_eigen_ref
42  {
43  typedef Eigen::Ref<MatType,Options,Stride> RefType;
44 
45  typedef ::boost::python::detail::aligned_storage<
47  > AlignedStorage;
48 
49  referent_storage_eigen_ref()
50  : pyArray(NULL)
51  , mat_ptr(NULL)
52  , ref_ptr(reinterpret_cast<RefType*>(ref_storage.bytes))
53  {
54  }
55 
56  referent_storage_eigen_ref(const RefType & ref,
57  PyArrayObject * pyArray,
58  MatType * mat_ptr = NULL)
59  : pyArray(pyArray)
60  , mat_ptr(mat_ptr)
61  , ref_ptr(reinterpret_cast<RefType*>(ref_storage.bytes))
62  {
63  Py_INCREF(pyArray);
64  new (ref_storage.bytes) RefType(ref);
65  }
66 
67  ~referent_storage_eigen_ref()
68  {
69  if(mat_ptr != NULL && PyArray_ISWRITEABLE(pyArray))
70  copy_if_non_const<MatType>::run(*mat_ptr,pyArray);
71 
72  Py_DECREF(pyArray);
73 
74  if(mat_ptr != NULL)
75  mat_ptr->~MatType();
76 
77  ref_ptr->~RefType();
78  }
79 
80  AlignedStorage ref_storage;
81  PyArrayObject * pyArray;
82  MatType * mat_ptr;
83  RefType * ref_ptr;
84  };
85 #endif
86 
87  }
88 }
89 
90 namespace boost { namespace python { namespace detail {
91 #if EIGEN_VERSION_AT_LEAST(3,2,0)
92  template<typename MatType, int Options, typename Stride>
93  struct referent_storage<Eigen::Ref<MatType,Options,Stride> &>
94  {
95  typedef ::eigenpy::details::referent_storage_eigen_ref<MatType,Options,Stride> StorageType;
96  typedef aligned_storage<
98  > type;
99  };
100 
101  template<typename MatType, int Options, typename Stride>
102  struct referent_storage<const Eigen::Ref<const MatType,Options,Stride> &>
103  {
104  typedef ::eigenpy::details::referent_storage_eigen_ref<const MatType,Options,Stride> StorageType;
105  typedef aligned_storage<
107  > type;
108  };
109 #endif
110 }}}
111 
112 namespace boost { namespace python { namespace converter {
113 
114  template<typename MatrixReference>
116  : rvalue_from_python_storage<MatrixReference>
117  {
118  typedef MatrixReference T;
119 
120 # if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
121 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
122 && (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
123 && !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
124  // This must always be a POD struct with m_data its first member.
125  BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
126 # endif
127 
128  // The usual constructor
129  rvalue_from_python_data_eigen(rvalue_from_python_stage1_data const & _stage1)
130  {
131  this->stage1 = _stage1;
132  }
133 
134  // This constructor just sets m_convertible -- used by
135  // implicitly_convertible<> to perform the final step of the
136  // conversion, where the construct() function is already known.
137  rvalue_from_python_data_eigen(void* convertible)
138  {
139  this->stage1.convertible = convertible;
140  }
141 
142  // Destroys any object constructed in the storage.
144  {
145  typedef typename boost::remove_const<typename boost::remove_reference<MatrixReference>::type>::type MatrixType;
146  if (this->stage1.convertible == this->storage.bytes)
147  static_cast<MatrixType *>((void *)this->storage.bytes)->~MatrixType();
148  }
149  };
150 
151 #define EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(type) \
152  typedef rvalue_from_python_data_eigen<type> Base; \
153  \
154  rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1) \
155  : Base(_stage1) \
156  {} \
157  \
158  rvalue_from_python_data(void* convertible) : Base(convertible) {};
159 
161  template<typename Derived>
162  struct rvalue_from_python_data<Eigen::MatrixBase<Derived> const &>
163  : rvalue_from_python_data_eigen<Derived const &>
164  {
165  EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
166  };
167 
169  template<typename Derived>
170  struct rvalue_from_python_data<Eigen::EigenBase<Derived> const &>
171  : rvalue_from_python_data_eigen<Derived const &>
172  {
173  EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
174  };
175 
177  template<typename Derived>
178  struct rvalue_from_python_data<Eigen::PlainObjectBase<Derived> const &>
179  : rvalue_from_python_data_eigen<Derived const &>
180  {
181  EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
182  };
183 
184  template<typename MatType, int Options, typename Stride>
185  struct rvalue_from_python_data<Eigen::Ref<MatType,Options,Stride> &>
186  : rvalue_from_python_storage<Eigen::Ref<MatType,Options,Stride> &>
187  {
188  typedef Eigen::Ref<MatType,Options,Stride> T;
189 
190 # if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
191 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
192 && (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
193 && !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
194  // This must always be a POD struct with m_data its first member.
195  BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
196 # endif
197 
198  // The usual constructor
199  rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
200  {
201  this->stage1 = _stage1;
202  }
203 
204  // This constructor just sets m_convertible -- used by
205  // implicitly_convertible<> to perform the final step of the
206  // conversion, where the construct() function is already known.
207  rvalue_from_python_data(void* convertible)
208  {
209  this->stage1.convertible = convertible;
210  }
211 
212  // Destroys any object constructed in the storage.
214  {
215  typedef ::eigenpy::details::referent_storage_eigen_ref<MatType, Options,Stride> StorageType;
216  if (this->stage1.convertible == this->storage.bytes)
217  static_cast<StorageType *>((void *)this->storage.bytes)->~StorageType();
218  }
219  };
220 
221  template<typename MatType, int Options, typename Stride>
222  struct rvalue_from_python_data<const Eigen::Ref<const MatType,Options,Stride> &>
223  : rvalue_from_python_storage<const Eigen::Ref<const MatType,Options,Stride> &>
224  {
225  typedef const Eigen::Ref<const MatType,Options,Stride> T;
226 
227 # if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
228 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
229 && (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
230 && !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
231  // This must always be a POD struct with m_data its first member.
232  BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
233 # endif
234 
235  // The usual constructor
236  rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
237  {
238  this->stage1 = _stage1;
239  }
240 
241  // This constructor just sets m_convertible -- used by
242  // implicitly_convertible<> to perform the final step of the
243  // conversion, where the construct() function is already known.
244  rvalue_from_python_data(void* convertible)
245  {
246  this->stage1.convertible = convertible;
247  }
248 
249  // Destroys any object constructed in the storage.
251  {
252  typedef ::eigenpy::details::referent_storage_eigen_ref<const MatType, Options,Stride> StorageType;
253  if (this->stage1.convertible == this->storage.bytes)
254  static_cast<StorageType *>((void *)this->storage.bytes)->~StorageType();
255  }
256  };
257 
258 } } }
259 
260 namespace eigenpy
261 {
262 
263  template<typename MatOrRefType>
264  void eigen_from_py_construct(PyObject* pyObj,
265  bp::converter::rvalue_from_python_stage1_data* memory)
266  {
267  PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
268  assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
269 
270  bp::converter::rvalue_from_python_storage<MatOrRefType>* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatOrRefType>*>
271  (reinterpret_cast<void*>(memory));
272 
274 
275  memory->convertible = storage->storage.bytes;
276  }
277 
278  template<typename MatType, typename _Scalar>
279  struct EigenFromPy
280  {
281  typedef typename MatType::Scalar Scalar;
282 
284  static void* convertible(PyObject* pyObj);
285 
287  static void construct(PyObject* pyObj,
288  bp::converter::rvalue_from_python_stage1_data* memory);
289 
290  static void registration();
291  };
292 
293  template<typename MatType, typename _Scalar>
295  {
296  if(!call_PyArray_Check(reinterpret_cast<PyObject*>(pyObj)))
297  return 0;
298 
299  PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
300 
301  if(!np_type_is_convertible_into_scalar<Scalar>(EIGENPY_GET_PY_ARRAY_TYPE(pyArray)))
302  return 0;
303 
304  if(MatType::IsVectorAtCompileTime)
305  {
306  const Eigen::DenseIndex size_at_compile_time
307  = MatType::IsRowMajor
308  ? MatType::ColsAtCompileTime
309  : MatType::RowsAtCompileTime;
310 
311  switch(PyArray_NDIM(pyArray))
312  {
313  case 0:
314  return 0;
315  case 1:
316  {
317  if(size_at_compile_time != Eigen::Dynamic)
318  {
319  // check that the sizes at compile time matche
320  if(PyArray_DIMS(pyArray)[0] == size_at_compile_time)
321  return pyArray;
322  else
323  return 0;
324  }
325  else // This is a dynamic MatType
326  return pyArray;
327  }
328  case 2:
329  {
330  // Special care of scalar matrix of dimension 1x1.
331  if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1)
332  {
333  if(size_at_compile_time != Eigen::Dynamic)
334  {
335  if(size_at_compile_time == 1)
336  return pyArray;
337  else
338  return 0;
339  }
340  else // This is a dynamic MatType
341  return pyArray;
342  }
343 
344  if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1)
345  {
346  return 0;
347  }
348 
349  if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1))
350  || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
351  {
352  return 0;
353  }
354 
355  if(size_at_compile_time != Eigen::Dynamic)
356  { // This is a fixe size vector
357  const Eigen::DenseIndex pyArray_size
358  = PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1]
359  ? PyArray_DIMS(pyArray)[0]
360  : PyArray_DIMS(pyArray)[1];
361  if(size_at_compile_time != pyArray_size)
362  return 0;
363  }
364  break;
365  }
366  default:
367  return 0;
368  }
369  }
370  else // this is a matrix
371  {
372  if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix
373  {
374  return pyArray;
375  }
376 
377  if(PyArray_NDIM(pyArray) != 2)
378  {
379  return 0;
380  }
381 
382  if(PyArray_NDIM(pyArray) == 2)
383  {
384  const int R = (int)PyArray_DIMS(pyArray)[0];
385  const int C = (int)PyArray_DIMS(pyArray)[1];
386 
387  if( (MatType::RowsAtCompileTime!=R)
388  && (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
389  return 0;
390  if( (MatType::ColsAtCompileTime!=C)
391  && (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
392  return 0;
393  }
394  }
395 
396 #ifdef NPY_1_8_API_VERSION
397  if(!(PyArray_FLAGS(pyArray)))
398 #else
399  if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED))
400 #endif
401  {
402  return 0;
403  }
404 
405  return pyArray;
406  }
407 
408  template<typename MatType, typename _Scalar>
410  bp::converter::rvalue_from_python_stage1_data* memory)
411  {
412  eigen_from_py_construct<MatType>(pyObj,memory);
413  }
414 
415  template<typename MatType, typename _Scalar>
417  {
418  bp::converter::registry::push_back
419  (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
420  &EigenFromPy::construct,bp::type_id<MatType>());
421  }
422 
423  template<typename MatType>
425  {
426  static void registration()
427  {
429 
430  // Add conversion to Eigen::MatrixBase<MatType>
431  typedef Eigen::MatrixBase<MatType> MatrixBase;
433 
434  // Add conversion to Eigen::EigenBase<MatType>
435  typedef Eigen::EigenBase<MatType> EigenBase;
437 
438  // Add conversion to Eigen::PlainObjectBase<MatType>
439  typedef Eigen::PlainObjectBase<MatType> PlainObjectBase;
441 
442 #if EIGEN_VERSION_AT_LEAST(3,2,0)
443  // Add conversion to Eigen::Ref<MatType>
444  typedef Eigen::Ref<MatType> RefType;
446 
447  // Add conversion to Eigen::Ref<MatType>
448  typedef const Eigen::Ref<const MatType> ConstRefType;
450 #endif
451  }
452  };
453 
454  template<typename MatType>
455  struct EigenFromPy< Eigen::MatrixBase<MatType> > : EigenFromPy<MatType>
456  {
458  typedef Eigen::MatrixBase<MatType> Base;
459 
460  static void registration()
461  {
462  bp::converter::registry::push_back
463  (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
464  &EigenFromPy::construct,bp::type_id<Base>());
465  }
466  };
467 
468  template<typename MatType>
469  struct EigenFromPy< Eigen::EigenBase<MatType>, typename MatType::Scalar > : EigenFromPy<MatType>
470  {
472  typedef Eigen::EigenBase<MatType> Base;
473 
474  static void registration()
475  {
476  bp::converter::registry::push_back
477  (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
478  &EigenFromPy::construct,bp::type_id<Base>());
479  }
480  };
481 
482  template<typename MatType>
483  struct EigenFromPy< Eigen::PlainObjectBase<MatType> > : EigenFromPy<MatType>
484  {
486  typedef Eigen::PlainObjectBase<MatType> Base;
487 
488  static void registration()
489  {
490  bp::converter::registry::push_back
491  (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
492  &EigenFromPy::construct,bp::type_id<Base>());
493  }
494  };
495 
496 #if EIGEN_VERSION_AT_LEAST(3,2,0)
497 
498  template<typename MatType, int Options, typename Stride>
499  struct EigenFromPy<Eigen::Ref<MatType,Options,Stride> >
500  {
501  typedef Eigen::Ref<MatType,Options,Stride> RefType;
502  typedef typename MatType::Scalar Scalar;
503 
505  static void* convertible(PyObject * pyObj)
506  {
507  if(!call_PyArray_Check(pyObj))
508  return 0;
509  PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
510  if(!PyArray_ISWRITEABLE(pyArray))
511  return 0;
512  return EigenFromPy<MatType>::convertible(pyObj);
513  }
514 
515  static void registration()
516  {
517  bp::converter::registry::push_back
518  (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
519  &eigen_from_py_construct<RefType>,bp::type_id<RefType>());
520  }
521  };
522 
523  template<typename MatType, int Options, typename Stride>
524  struct EigenFromPy<const Eigen::Ref<const MatType,Options,Stride> >
525  {
526  typedef const Eigen::Ref<const MatType,Options,Stride> ConstRefType;
527  typedef typename MatType::Scalar Scalar;
528 
530  static void* convertible(PyObject * pyObj)
531  {
532  return EigenFromPy<MatType>::convertible(pyObj);
533  }
534 
535  static void registration()
536  {
537  bp::converter::registry::push_back
538  (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
539  &eigen_from_py_construct<ConstRefType>,bp::type_id<ConstRefType>());
540  }
541  };
542 #endif
543 
544 }
545 
546 #endif // __eigenpy_eigen_from_python_hpp__
#define EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(type)
static void allocate(PyArrayObject *pyArray, bp::converter::rvalue_from_python_storage< MatType > *storage)
Definition: complex.cpp:7
void eigen_from_py_construct(PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory)
#define call_PyArray_Check(py_obj)
Definition: numpy.hpp:60
static void * convertible(PyObject *pyObj)
Determine if pyObj can be converted into a MatType object.
static void copy(const Eigen::MatrixBase< MatrixDerived > &mat_, PyArrayObject *pyArray)
Copy mat into the Python array using Eigen::Map.
rvalue_from_python_data_eigen(rvalue_from_python_stage1_data const &_stage1)
#define EIGENPY_GET_PY_ARRAY_TYPE(array)
Definition: numpy.hpp:26
static void run(const Eigen::MatrixBase< MatType > &input, PyArrayObject *pyArray)
static void construct(PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory)
Allocate memory and copy pyObj in the new storage.
static void run(const Eigen::MatrixBase< MatType > &, PyArrayObject *)
Definition: python.py:1


eigenpy
Author(s): Justin Carpentier, Nicolas Mansard
autogenerated on Sat Apr 17 2021 02:37:59