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


eigenpy
Author(s): Justin Carpentier, Nicolas Mansard
autogenerated on Fri Jun 2 2023 02:10:26