eigen-allocator.hpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2014-2020 CNRS INRIA
3 //
4 
5 #ifndef __eigenpy_eigen_allocator_hpp__
6 #define __eigenpy_eigen_allocator_hpp__
7 
8 #include "eigenpy/fwd.hpp"
9 #include "eigenpy/numpy-map.hpp"
10 #include "eigenpy/register.hpp"
13 
14 namespace eigenpy
15 {
16 
17  namespace details
18  {
19  template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
21  {
22  static MatType * run(int rows, int cols, void * storage)
23  {
24  if(storage)
25  return new (storage) MatType(rows,cols);
26  else
27  return new MatType(rows,cols);
28  }
29 
30  static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
31  {
32  assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2);
33 
34  int rows = -1, cols = -1;
35  const int ndim = PyArray_NDIM(pyArray);
36  if(ndim == 2)
37  {
38  rows = (int)PyArray_DIMS(pyArray)[0];
39  cols = (int)PyArray_DIMS(pyArray)[1];
40  }
41  else if(ndim == 1)
42  {
43  rows = (int)PyArray_DIMS(pyArray)[0];
44  cols = 1;
45  }
46 
47  return run(rows,cols,storage);
48  }
49  };
50 
51  template<typename MatType>
52  struct init_matrix_or_array<MatType,true>
53  {
54  static MatType * run(int rows, int cols, void * storage)
55  {
56  if(storage)
57  return new (storage) MatType(rows,cols);
58  else
59  return new MatType(rows,cols);
60  }
61 
62  static MatType * run(int size, void * storage)
63  {
64  if(storage)
65  return new (storage) MatType(size);
66  else
67  return new MatType(size);
68  }
69 
70  static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
71  {
72  const int ndim = PyArray_NDIM(pyArray);
73  if(ndim == 1)
74  {
75  const int size = (int)PyArray_DIMS(pyArray)[0];
76  return run(size,storage);
77  }
78  else
79  {
80  const int rows = (int)PyArray_DIMS(pyArray)[0];
81  const int cols = (int)PyArray_DIMS(pyArray)[1];
82  return run(rows,cols,storage);
83  }
84  }
85  };
86 
87  template<typename MatType>
88  bool check_swap(PyArrayObject * pyArray,
89  const Eigen::MatrixBase<MatType> & mat)
90  {
91  if(PyArray_NDIM(pyArray) == 0) return false;
92  if(mat.rows() == PyArray_DIMS(pyArray)[0])
93  return false;
94  else
95  return true;
96  }
97 
100  {
101  template<typename MatrixIn, typename MatrixOut>
102  static void run(const Eigen::MatrixBase<MatrixIn> & input,
103  const Eigen::MatrixBase<MatrixOut> & dest)
104  {
105  MatrixOut & dest_ = const_cast<MatrixOut &>(dest.derived());
106  dest_ = input.template cast<NewScalar>();
107  }
108  };
109 
110  template<typename Scalar, typename NewScalar>
111  struct cast_matrix_or_array<Scalar,NewScalar,false>
112  {
113  template<typename MatrixIn, typename MatrixOut>
114  static void run(const Eigen::MatrixBase<MatrixIn> & /*input*/,
115  const Eigen::MatrixBase<MatrixOut> & /*dest*/)
116  {
117  // do nothing
118  assert(false && "Must never happened");
119  }
120  };
121 
122  } // namespace details
123 
124 #define EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,Scalar,NewScalar,pyArray,mat) \
125  details::cast_matrix_or_array<Scalar,NewScalar>::run(NumpyMap<MatType,Scalar>::map(pyArray,details::check_swap(pyArray,mat)),mat)
126 
127 #define EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,NewScalar,mat,pyArray) \
128  details::cast_matrix_or_array<Scalar,NewScalar>::run(mat,NumpyMap<MatType,NewScalar>::map(pyArray,details::check_swap(pyArray,mat)))
129 
130  template<typename MatType>
132  {
133  typedef MatType Type;
134  typedef typename MatType::Scalar Scalar;
135 
136  static void allocate(PyArrayObject * pyArray,
137  bp::converter::rvalue_from_python_storage<MatType> * storage)
138  {
139  void * raw_ptr = storage->storage.bytes;
140  Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,raw_ptr);
141  Type & mat = *mat_ptr;
142 
143  const int pyArray_type_code = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
144  const int Scalar_type_code = Register::getTypeCode<Scalar>();
145  if(pyArray_type_code == Scalar_type_code)
146  {
147  mat = NumpyMap<MatType,Scalar>::map(pyArray,details::check_swap(pyArray,mat)); // avoid useless cast
148  return;
149  }
150 
151  switch(pyArray_type_code)
152  {
153  case NPY_INT:
154  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
155  break;
156  case NPY_LONG:
157  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
158  break;
159  case NPY_FLOAT:
160  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
161  break;
162  case NPY_CFLOAT:
163  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
164  break;
165  case NPY_DOUBLE:
166  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
167  break;
168  case NPY_CDOUBLE:
169  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
170  break;
171  case NPY_LONGDOUBLE:
172  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
173  break;
174  case NPY_CLONGDOUBLE:
175  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
176  break;
177  default:
178  throw Exception("You asked for a conversion which is not implemented.");
179  }
180  }
181 
183  template<typename MatrixDerived>
184  static void copy(const Eigen::MatrixBase<MatrixDerived> & mat_,
185  PyArrayObject * pyArray)
186  {
187  const MatrixDerived & mat = const_cast<const MatrixDerived &>(mat_.derived());
188  const int pyArray_type_code = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
189  const int Scalar_type_code = Register::getTypeCode<Scalar>();
190 
191  typedef typename NumpyMap<MatType,Scalar>::EigenMap MapType;
192 
193  if(pyArray_type_code == Scalar_type_code) // no cast needed
194  {
195  MapType map_pyArray = NumpyMap<MatType,Scalar>::map(pyArray,details::check_swap(pyArray,mat));
196  map_pyArray = mat;
197  return;
198  }
199 
200  switch(pyArray_type_code)
201  {
202  case NPY_INT:
203  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,int,mat,pyArray);
204  break;
205  case NPY_LONG:
206  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long,mat,pyArray);
207  break;
208  case NPY_FLOAT:
209  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,float,mat,pyArray);
210  break;
211  case NPY_CFLOAT:
212  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<float>,mat,pyArray);
213  break;
214  case NPY_DOUBLE:
215  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,double,mat,pyArray);
216  break;
217  case NPY_CDOUBLE:
218  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<double>,mat,pyArray);
219  break;
220  case NPY_LONGDOUBLE:
221  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long double,mat,pyArray);
222  break;
223  case NPY_CLONGDOUBLE:
224  EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<long double>,mat,pyArray);
225  break;
226  default:
227  throw Exception("You asked for a conversion which is not implemented.");
228  }
229  }
230  };
231 
232 #if EIGEN_VERSION_AT_LEAST(3,2,0)
233  template<typename MatType, int Options, typename Stride>
234  struct EigenAllocator<Eigen::Ref<MatType,Options,Stride> >
235  {
236  typedef Eigen::Ref<MatType,Options,Stride> RefType;
237  typedef typename MatType::Scalar Scalar;
238 
239  typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
240 
241  static void allocate(PyArrayObject * pyArray,
242  bp::converter::rvalue_from_python_storage<RefType> * storage)
243  {
244  typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
245 
246  bool need_to_allocate = false;
247  const int pyArray_type_code = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
248  const int Scalar_type_code = Register::getTypeCode<Scalar>();
249  if(pyArray_type_code != Scalar_type_code)
250  need_to_allocate |= true;
251  if( (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
252  || (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
253  || MatType::IsVectorAtCompileTime
254  || (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
255  need_to_allocate |= false;
256  else
257  need_to_allocate |= true;
258  if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
259  {
260  void * data_ptr = PyArray_DATA(pyArray);
261  if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
262  need_to_allocate |= true;
263  }
264 
265  void * raw_ptr = storage->storage.bytes;
266  if(need_to_allocate)
267  {
268  MatType * mat_ptr;
270  RefType mat_ref(*mat_ptr);
271 
272  new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
273 
274  RefType & mat = *reinterpret_cast<RefType*>(raw_ptr);
275  if(pyArray_type_code == Scalar_type_code)
276  {
277  mat = NumpyMap<MatType,Scalar>::map(pyArray,details::check_swap(pyArray,mat)); // avoid useless cast
278  return;
279  }
280 
281  switch(pyArray_type_code)
282  {
283  case NPY_INT:
284  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
285  break;
286  case NPY_LONG:
287  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
288  break;
289  case NPY_FLOAT:
290  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
291  break;
292  case NPY_CFLOAT:
293  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
294  break;
295  case NPY_DOUBLE:
296  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
297  break;
298  case NPY_CDOUBLE:
299  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
300  break;
301  case NPY_LONGDOUBLE:
302  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
303  break;
304  case NPY_CLONGDOUBLE:
305  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
306  break;
307  default:
308  throw Exception("You asked for a conversion which is not implemented.");
309  }
310  }
311  else
312  {
313  assert(pyArray_type_code == Scalar_type_code);
315  RefType mat_ref(numpyMap);
316  new (raw_ptr) StorageType(mat_ref,pyArray);
317  }
318  }
319 
320  static void copy(RefType const & ref, PyArrayObject * pyArray)
321  {
322  EigenAllocator<MatType>::copy(ref,pyArray);
323  }
324  };
325 
326  template<typename MatType, int Options, typename Stride>
327  struct EigenAllocator<const Eigen::Ref<const MatType,Options,Stride> >
328  {
329  typedef const Eigen::Ref<const MatType,Options,Stride> RefType;
330  typedef typename MatType::Scalar Scalar;
331 
332  typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
333 
334  static void allocate(PyArrayObject * pyArray,
335  bp::converter::rvalue_from_python_storage<RefType> * storage)
336  {
337  typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
338 
339  bool need_to_allocate = false;
340  const int pyArray_type_code = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
341  const int Scalar_type_code = Register::getTypeCode<Scalar>();
342 
343  if(pyArray_type_code != Scalar_type_code)
344  need_to_allocate |= true;
345  if( (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
346  || (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
347  || MatType::IsVectorAtCompileTime
348  || (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
349  need_to_allocate |= false;
350  else
351  need_to_allocate |= true;
352  if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
353  {
354  void * data_ptr = PyArray_DATA(pyArray);
355  if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
356  need_to_allocate |= true;
357  }
358 
359  void * raw_ptr = storage->storage.bytes;
360  if(need_to_allocate)
361  {
362  MatType * mat_ptr;
364  RefType mat_ref(*mat_ptr);
365 
366  new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
367 
368  MatType & mat = *mat_ptr;
369  if(pyArray_type_code == Scalar_type_code)
370  {
371  mat = NumpyMap<MatType,Scalar>::map(pyArray,details::check_swap(pyArray,mat)); // avoid useless cast
372  return;
373  }
374 
375  switch(pyArray_type_code)
376  {
377  case NPY_INT:
378  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
379  break;
380  case NPY_LONG:
381  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
382  break;
383  case NPY_FLOAT:
384  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
385  break;
386  case NPY_CFLOAT:
387  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
388  break;
389  case NPY_DOUBLE:
390  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
391  break;
392  case NPY_CDOUBLE:
393  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
394  break;
395  case NPY_LONGDOUBLE:
396  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
397  break;
398  case NPY_CLONGDOUBLE:
399  EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
400  break;
401  default:
402  throw Exception("You asked for a conversion which is not implemented.");
403  }
404  }
405  else
406  {
407  assert(pyArray_type_code == Scalar_type_code);
409  RefType mat_ref(numpyMap);
410  new (raw_ptr) StorageType(mat_ref,pyArray);
411  }
412  }
413 
414  static void copy(RefType const & ref, PyArrayObject * pyArray)
415  {
416  EigenAllocator<MatType>::copy(ref,pyArray);
417  }
418  };
419 #endif
420 }
421 
422 #endif // __eigenpy_eigen_allocator_hpp__
#define EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType, Scalar, NewScalar, mat, pyArray)
Impl::EigenMap EigenMap
Definition: numpy-map.hpp:23
static void run(const Eigen::MatrixBase< MatrixIn > &, const Eigen::MatrixBase< MatrixOut > &)
static void allocate(PyArrayObject *pyArray, bp::converter::rvalue_from_python_storage< MatType > *storage)
bool is_aligned(void *ptr, std::size_t alignment)
Definition: is-aligned.hpp:10
static MatType * run(int rows, int cols, void *storage)
#define EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType, Scalar, NewScalar, pyArray, mat)
std::size_t size(custom_string const &s)
Definition: mystring.cpp:24
static MatType * run(PyArrayObject *pyArray, void *storage=NULL)
static MatType * run(PyArrayObject *pyArray, void *storage=NULL)
static MatType * run(int size, void *storage)
static MatType * run(int rows, int cols, void *storage)
static void copy(const Eigen::MatrixBase< MatrixDerived > &mat_, PyArrayObject *pyArray)
Copy mat into the Python array using Eigen::Map.
static EigenMap map(PyArrayObject *pyArray, bool swap_dimensions=false)
Definition: numpy-map.hpp:156
#define EIGENPY_GET_PY_ARRAY_TYPE(array)
Definition: numpy.hpp:26
static void run(const Eigen::MatrixBase< MatrixIn > &input, const Eigen::MatrixBase< MatrixOut > &dest)
bool check_swap(PyArrayObject *pyArray, const Eigen::MatrixBase< MatType > &mat)


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