Skip to content

Commit 56fe46a

Browse files
authored
Merge pull request #163 from jcarpent/devel
Implement full support of Eigen::Ref
2 parents bb8df99 + 9e60650 commit 56fe46a

File tree

14 files changed

+627
-71
lines changed

14 files changed

+627
-71
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ SEARCH_FOR_BOOST()
7474
SET(${PROJECT_NAME}_UTILS_HEADERS
7575
include/eigenpy/utils/scalar-name.hpp
7676
include/eigenpy/utils/is-approx.hpp
77+
include/eigenpy/utils/is-aligned.hpp
7778
)
7879

7980
SET(${PROJECT_NAME}_SOLVERS_HEADERS

include/eigenpy/eigen-allocator.hpp

Lines changed: 204 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "eigenpy/fwd.hpp"
99
#include "eigenpy/map.hpp"
1010
#include "eigenpy/scalar-conversion.hpp"
11+
#include "eigenpy/utils/is-aligned.hpp"
1112

1213
namespace eigenpy
1314
{
@@ -17,7 +18,7 @@ namespace eigenpy
1718
template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
1819
struct init_matrix_or_array
1920
{
20-
static MatType * run(PyArrayObject * pyArray, void * storage)
21+
static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
2122
{
2223
assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2);
2324

@@ -33,25 +34,34 @@ namespace eigenpy
3334
cols = 1;
3435
}
3536

36-
return new (storage) MatType(rows,cols);
37+
if(storage)
38+
return new (storage) MatType(rows,cols);
39+
else
40+
return new MatType(rows,cols);
3741
}
3842
};
3943

4044
template<typename MatType>
4145
struct init_matrix_or_array<MatType,true>
4246
{
43-
static MatType * run(PyArrayObject * pyArray, void * storage)
47+
static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
4448
{
4549
if(PyArray_NDIM(pyArray) == 1)
4650
{
4751
const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0];
48-
return new (storage) MatType(rows_or_cols);
52+
if(storage)
53+
return new (storage) MatType(rows_or_cols);
54+
else
55+
return new MatType(rows_or_cols);
4956
}
5057
else
5158
{
5259
const int rows = (int)PyArray_DIMS(pyArray)[0];
5360
const int cols = (int)PyArray_DIMS(pyArray)[1];
54-
return new (storage) MatType(rows,cols);
61+
if(storage)
62+
return new (storage) MatType(rows,cols);
63+
else
64+
return new MatType(rows,cols);
5565
}
5666
}
5767
};
@@ -79,7 +89,7 @@ namespace eigenpy
7989
const Eigen::MatrixBase<MatrixOut> & /*dest*/)
8090
{
8191
// do nothing
82-
assert("Must never happened");
92+
assert(false && "Must never happened");
8393
}
8494
};
8595

@@ -97,9 +107,11 @@ namespace eigenpy
97107
typedef MatType Type;
98108
typedef typename MatType::Scalar Scalar;
99109

100-
static void allocate(PyArrayObject * pyArray, void * storage)
110+
static void allocate(PyArrayObject * pyArray,
111+
bp::converter::rvalue_from_python_storage<MatType> * storage)
101112
{
102-
Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,storage);
113+
void * raw_ptr = storage->storage.bytes;
114+
Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,raw_ptr);
103115
Type & mat = *mat_ptr;
104116

105117
const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
@@ -193,6 +205,190 @@ namespace eigenpy
193205
};
194206

195207
#if EIGEN_VERSION_AT_LEAST(3,2,0)
208+
template<typename MatType, int Options, typename Stride>
209+
struct EigenAllocator<Eigen::Ref<MatType,Options,Stride> >
210+
{
211+
typedef Eigen::Ref<MatType,Options,Stride> RefType;
212+
typedef typename MatType::Scalar Scalar;
213+
214+
typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
215+
216+
static void allocate(PyArrayObject * pyArray,
217+
bp::converter::rvalue_from_python_storage<RefType> * storage)
218+
{
219+
typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
220+
221+
bool need_to_allocate = false;
222+
const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
223+
if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
224+
need_to_allocate |= true;
225+
if( (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
226+
|| (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
227+
|| MatType::IsVectorAtCompileTime
228+
|| (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
229+
need_to_allocate |= false;
230+
else
231+
need_to_allocate |= true;
232+
if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
233+
{
234+
void * data_ptr = PyArray_DATA(pyArray);
235+
if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
236+
need_to_allocate |= true;
237+
}
238+
239+
void * raw_ptr = storage->storage.bytes;
240+
if(need_to_allocate)
241+
{
242+
MatType * mat_ptr;
243+
mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
244+
RefType mat_ref(*mat_ptr);
245+
246+
new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
247+
248+
RefType & mat = *reinterpret_cast<RefType*>(raw_ptr);
249+
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
250+
{
251+
mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
252+
return;
253+
}
254+
255+
switch(pyArray_Type)
256+
{
257+
case NPY_INT:
258+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
259+
break;
260+
case NPY_LONG:
261+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
262+
break;
263+
case NPY_FLOAT:
264+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
265+
break;
266+
case NPY_CFLOAT:
267+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
268+
break;
269+
case NPY_DOUBLE:
270+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
271+
break;
272+
case NPY_CDOUBLE:
273+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
274+
break;
275+
case NPY_LONGDOUBLE:
276+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
277+
break;
278+
case NPY_CLONGDOUBLE:
279+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
280+
break;
281+
default:
282+
throw Exception("You asked for a conversion which is not implemented.");
283+
}
284+
}
285+
else
286+
{
287+
assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
288+
typename MapNumpy<MatType,Scalar,Options,NumpyMapStride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Options,NumpyMapStride>::map(pyArray);
289+
RefType mat_ref(numpyMap);
290+
new (raw_ptr) StorageType(mat_ref,pyArray);
291+
}
292+
}
293+
294+
static void copy(RefType const & ref, PyArrayObject * pyArray)
295+
{
296+
EigenAllocator<MatType>::copy(ref,pyArray);
297+
}
298+
};
299+
300+
template<typename MatType, int Options, typename Stride>
301+
struct EigenAllocator<const Eigen::Ref<const MatType,Options,Stride> >
302+
{
303+
typedef const Eigen::Ref<const MatType,Options,Stride> RefType;
304+
typedef typename MatType::Scalar Scalar;
305+
306+
typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
307+
308+
static void allocate(PyArrayObject * pyArray,
309+
bp::converter::rvalue_from_python_storage<RefType> * storage)
310+
{
311+
typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
312+
313+
bool need_to_allocate = false;
314+
const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
315+
if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
316+
need_to_allocate |= true;
317+
if( (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
318+
|| (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
319+
|| MatType::IsVectorAtCompileTime
320+
|| (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
321+
need_to_allocate |= false;
322+
else
323+
need_to_allocate |= true;
324+
if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
325+
{
326+
void * data_ptr = PyArray_DATA(pyArray);
327+
if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
328+
need_to_allocate |= true;
329+
}
330+
331+
void * raw_ptr = storage->storage.bytes;
332+
if(need_to_allocate)
333+
{
334+
MatType * mat_ptr;
335+
mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
336+
RefType mat_ref(*mat_ptr);
337+
338+
new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
339+
340+
MatType & mat = *mat_ptr;
341+
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
342+
{
343+
mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
344+
return;
345+
}
346+
347+
switch(pyArray_Type)
348+
{
349+
case NPY_INT:
350+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
351+
break;
352+
case NPY_LONG:
353+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
354+
break;
355+
case NPY_FLOAT:
356+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
357+
break;
358+
case NPY_CFLOAT:
359+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
360+
break;
361+
case NPY_DOUBLE:
362+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
363+
break;
364+
case NPY_CDOUBLE:
365+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
366+
break;
367+
case NPY_LONGDOUBLE:
368+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
369+
break;
370+
case NPY_CLONGDOUBLE:
371+
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
372+
break;
373+
default:
374+
throw Exception("You asked for a conversion which is not implemented.");
375+
}
376+
}
377+
else
378+
{
379+
assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
380+
typename MapNumpy<MatType,Scalar,Options,NumpyMapStride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Options,NumpyMapStride>::map(pyArray);
381+
RefType mat_ref(numpyMap);
382+
new (raw_ptr) StorageType(mat_ref,pyArray);
383+
}
384+
}
385+
386+
static void copy(RefType const & ref, PyArrayObject * pyArray)
387+
{
388+
EigenAllocator<MatType>::copy(ref,pyArray);
389+
}
390+
};
391+
196392
template<typename MatType>
197393
struct EigenAllocator< eigenpy::Ref<MatType> >
198394
{

0 commit comments

Comments
 (0)