Skip to content

Commit 32b3ae6

Browse files
authored
Merge pull request #22 from jcarpent/devel
Add support to Eigen::Ref
2 parents e8ef831 + 54ed477 commit 32b3ae6

File tree

10 files changed

+334
-123
lines changed

10 files changed

+334
-123
lines changed

CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ ADD_REQUIRED_DEPENDENCY("eigen3 >= 3.0.5")
7070
SET(BOOST_COMPONENTS python)
7171
SEARCH_FOR_BOOST()
7272
# Add Boost path to include directories.
73-
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
73+
INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS})
7474

7575
FINDPYTHON(2.7 EXACT REQUIRED)
76-
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})
76+
INCLUDE_DIRECTORIES(SYSTEM ${PYTHON_INCLUDE_DIRS})
7777
FIND_NUMPY()
78-
INCLUDE_DIRECTORIES(${NUMPY_INCLUDE_DIRS})
78+
INCLUDE_DIRECTORIES(SYSTEM ${NUMPY_INCLUDE_DIRS})
7979

8080
# ----------------------------------------------------
8181
# --- INCLUDE ----------------------------------------
@@ -103,6 +103,7 @@ SET(HEADERS
103103
registration.hpp
104104
angle-axis.hpp
105105
quaternion.hpp
106+
ref.hpp
106107
)
107108

108109
MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy")

src/details.hpp

Lines changed: 108 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,13 @@
1717
#ifndef __eigenpy_details_hpp__
1818
#define __eigenpy_details_hpp__
1919

20-
#include <boost/python.hpp>
21-
#include <Eigen/Core>
22-
23-
#include <numpy/numpyconfig.h>
24-
#ifdef NPY_1_8_API_VERSION
25-
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
26-
#endif
20+
#include "eigenpy/fwd.hpp"
2721

2822
#include <numpy/arrayobject.h>
2923
#include <iostream>
3024

3125
#include "eigenpy/eigenpy.hpp"
3226
#include "eigenpy/registration.hpp"
33-
#include "eigenpy/exception.hpp"
3427
#include "eigenpy/map.hpp"
3528

3629

@@ -58,7 +51,7 @@ namespace eigenpy
5851
{ return make((PyObject*)pyArray,copy); }
5952
bp::object make(PyObject* pyObj, bool copy = false)
6053
{
61-
boost::python::object m
54+
bp::object m
6255
= pyMatrixType(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
6356
Py_INCREF(m.ptr());
6457
return m;
@@ -67,16 +60,50 @@ namespace eigenpy
6760
protected:
6861
PyMatrixType()
6962
{
70-
pyModule = boost::python::import("numpy");
63+
pyModule = bp::import("numpy");
7164
pyMatrixType = pyModule.attr("matrix");
7265
}
7366

7467
bp::object pyMatrixType;
7568
bp::object pyModule;
7669
};
70+
71+
template<typename MatType>
72+
struct EigenObjectAllocator
73+
{
74+
typedef MatType Type;
75+
76+
static void allocate(PyArrayObject * pyArray, void * storage)
77+
{
78+
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray);
79+
new(storage) MatType(numpyMap);
80+
}
81+
82+
static void convert(Type const & mat , PyArrayObject * pyArray)
83+
{
84+
MapNumpy<MatType>::map(pyArray) = mat;
85+
}
86+
};
87+
88+
template<typename MatType>
89+
struct EigenObjectAllocator< eigenpy::Ref<MatType> >
90+
{
91+
typedef eigenpy::Ref<MatType> Type;
92+
93+
static void allocate(PyArrayObject * pyArray, void * storage)
94+
{
95+
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray);
96+
new(storage) Type(numpyMap);
97+
}
98+
99+
static void convert(Type const & mat , PyArrayObject * pyArray)
100+
{
101+
MapNumpy<MatType>::map(pyArray) = mat;
102+
}
103+
};
77104

78105
/* --- TO PYTHON -------------------------------------------------------------- */
79-
template< typename MatType,typename EquivalentEigenType >
106+
template<typename MatType>
80107
struct EigenToPy
81108
{
82109
static PyObject* convert(MatType const& mat)
@@ -88,139 +115,128 @@ namespace eigenpy
88115

89116
npy_intp shape[2] = { R,C };
90117
PyArrayObject* pyArray = (PyArrayObject*)
91-
PyArray_SimpleNew(2, shape, NumpyEquivalentType<T>::type_code);
118+
PyArray_SimpleNew(2, shape, NumpyEquivalentType<T>::type_code);
92119

93-
MapNumpy<EquivalentEigenType>::map(pyArray) = mat;
120+
EigenObjectAllocator<MatType>::convert(mat,pyArray);
94121

95122
return PyMatrixType::getInstance().make(pyArray).ptr();
96123
}
97124
};
98125

99126
/* --- FROM PYTHON ------------------------------------------------------------ */
100-
namespace bp = boost::python;
101-
102-
template<typename MatType, int ROWS,int COLS>
103-
struct TraitsMatrixConstructor
104-
{
105-
static MatType & construct(void*storage,int /*r*/,int /*c*/)
106-
{
107-
return * new(storage) MatType();
108-
}
109-
};
110127

111128
template<typename MatType>
112-
struct TraitsMatrixConstructor<MatType,Eigen::Dynamic,Eigen::Dynamic>
113-
{
114-
static MatType & construct(void*storage,int r,int c)
115-
{
116-
return * new(storage) MatType(r,c);
117-
}
118-
};
119-
120-
template<typename MatType,int R>
121-
struct TraitsMatrixConstructor<MatType,R,Eigen::Dynamic>
122-
{
123-
static MatType & construct(void*storage,int /*r*/,int c)
124-
{
125-
return * new(storage) MatType(R,c);
126-
}
127-
};
128-
129-
template<typename MatType,int C>
130-
struct TraitsMatrixConstructor<MatType,Eigen::Dynamic,C>
131-
{
132-
static MatType & construct(void*storage,int r,int /*c*/)
133-
{
134-
return * new(storage) MatType(r,C);
135-
}
136-
};
137-
138-
139-
template<typename MatType,typename EquivalentEigenType>
140129
struct EigenFromPy
141130
{
142131
EigenFromPy()
143132
{
144133
bp::converter::registry::push_back
145-
(reinterpret_cast<void *(*)(_object *)>(&convertible),
146-
&construct,bp::type_id<MatType>());
134+
(reinterpret_cast<void *(*)(_object *)>(&convertible),
135+
&construct,bp::type_id<MatType>());
147136
}
148-
137+
149138
// Determine if obj_ptr can be converted in a Eigenvec
150139
static void* convertible(PyArrayObject* obj_ptr)
151140
{
152-
typedef typename MatType::Scalar T;
153-
154-
if (!PyArray_Check(obj_ptr))
155-
{
141+
if (!PyArray_Check(obj_ptr))
142+
{
156143
#ifndef NDEBUG
157-
std::cerr << "The python object is not a numpy array." << std::endl;
144+
std::cerr << "The python object is not a numpy array." << std::endl;
158145
#endif
159-
return 0;
160-
}
161-
146+
return 0;
147+
}
148+
149+
if(MatType::IsVectorAtCompileTime)
150+
{
151+
if(PyArray_DIMS(obj_ptr)[0] > 1 && PyArray_DIMS(obj_ptr)[1] > 1)
152+
{
153+
#ifndef NDEBUG
154+
std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
155+
#endif
156+
return 0;
157+
}
158+
159+
if(((PyArray_DIMS(obj_ptr)[0] == 1) && (MatType::ColsAtCompileTime == 1))
160+
|| ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
161+
{
162+
#ifndef NDEBUG
163+
if(MatType::ColsAtCompileTime == 1)
164+
std::cerr << "The object is not a column vector" << std::endl;
165+
else
166+
std::cerr << "The object is not a row vector" << std::endl;
167+
#endif
168+
return 0;
169+
}
170+
}
171+
162172
if (PyArray_NDIM(obj_ptr) != 2)
163-
if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
164-
{
173+
{
174+
if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
175+
{
165176
#ifndef NDEBUG
166-
std::cerr << "The number of dimension of the object is not correct." << std::endl;
177+
std::cerr << "The number of dimension of the object is not correct." << std::endl;
167178
#endif
168-
return 0;
169-
}
170-
171-
if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) != NumpyEquivalentType<T>::type_code)
172-
{
179+
return 0;
180+
}
181+
}
182+
183+
if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
184+
!= NumpyEquivalentType<typename MatType::Scalar>::type_code)
185+
{
173186
#ifndef NDEBUG
174-
std::cerr << "The internal type as no Eigen equivalent." << std::endl;
187+
std::cerr << "The internal type as no Eigen equivalent." << std::endl;
175188
#endif
176-
return 0;
177-
}
189+
return 0;
190+
}
178191
#ifdef NPY_1_8_API_VERSION
179192
if (!(PyArray_FLAGS(obj_ptr)))
180193
#else
181-
if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
194+
if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
182195
#endif
183-
{
196+
{
184197
#ifndef NDEBUG
185-
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
198+
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
186199
#endif
187-
return 0;
188-
}
200+
return 0;
201+
}
189202

190203
return obj_ptr;
191204
}
192205

193206
// Convert obj_ptr into a Eigenvec
194207
static void construct(PyObject* pyObj,
195-
bp::converter::rvalue_from_python_stage1_data* memory)
208+
bp::converter::rvalue_from_python_stage1_data* memory)
196209
{
197210
using namespace Eigen;
198-
211+
199212
PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
200-
typename MapNumpy<EquivalentEigenType>::EigenMap numpyMap = MapNumpy<EquivalentEigenType>::map(pyArray);
201-
213+
assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
214+
202215
void* storage = ((bp::converter::rvalue_from_python_storage<MatType>*)
203-
((void*)memory))->storage.bytes;
204-
assert( (numpyMap.rows()<INT_MAX) && (numpyMap.cols()<INT_MAX)
205-
&& "Map range larger than int ... can never happen." );
206-
int r=(int)numpyMap.rows(),c=(int)numpyMap.cols();
207-
EquivalentEigenType & eigenMatrix = //* new(storage) MatType(numpyMap.rows(),numpyMap.cols());
208-
TraitsMatrixConstructor<MatType,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime>::construct (storage,r,c);
209-
memory->convertible = storage;
216+
((void*)memory))->storage.bytes;
217+
218+
EigenObjectAllocator<MatType>::allocate(pyArray,storage);
210219

211-
eigenMatrix = numpyMap;
220+
memory->convertible = storage;
212221
}
213222
};
223+
214224
#define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } }
215225

216226
template<typename MatType,typename EigenEquivalentType>
217227
void enableEigenPySpecific()
228+
{
229+
enableEigenPySpecific<MatType>();
230+
}
231+
232+
template<typename MatType>
233+
void enableEigenPySpecific()
218234
{
219235
numpy_import_array();
220236
if(check_registration<MatType>()) return;
221237

222-
boost::python::to_python_converter<MatType,EigenToPy<MatType,MatType> >();
223-
EigenFromPy<MatType,MatType>();
238+
bp::to_python_converter<MatType,EigenToPy<MatType> >();
239+
EigenFromPy<MatType>();
224240
}
225241

226242
} // namespace eigenpy

src/eigenpy.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015 LAAS-CNRS
2+
* Copyright (c) 2015-2018 LAAS-CNRS
33
*
44
* This file is part of eigenpy.
55
* eigenpy is free software: you can redistribute it and/or
@@ -22,17 +22,18 @@ namespace eigenpy
2222
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */
2323
void enableEigenPy()
2424
{
25+
using namespace Eigen;
2526
Exception::registerException();
2627

27-
enableEigenPySpecific<Eigen::MatrixXd,Eigen::MatrixXd>();
28-
enableEigenPySpecific<Eigen::Matrix2d,Eigen::Matrix2d>();
29-
enableEigenPySpecific<Eigen::Matrix3d,Eigen::Matrix3d>();
30-
enableEigenPySpecific<Eigen::Matrix4d,Eigen::Matrix4d>();
31-
32-
enableEigenPySpecific<Eigen::VectorXd,Eigen::VectorXd>();
33-
enableEigenPySpecific<Eigen::Vector2d,Eigen::Vector2d>();
34-
enableEigenPySpecific<Eigen::Vector3d,Eigen::Vector3d>();
35-
enableEigenPySpecific<Eigen::Vector4d,Eigen::Vector4d>();
28+
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXd);
29+
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2d);
30+
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3d);
31+
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4d);
32+
33+
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXd);
34+
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2d);
35+
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3d);
36+
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4d);
3637
}
3738

3839
} // namespace eigenpy

src/eigenpy.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,27 @@
1818
#define __eigenpy_eigenpy_hpp__
1919

2020
#include "eigenpy/fwd.hpp"
21-
#include "eigenpy/memory.hpp"
21+
#include "eigenpy/deprecated.hh"
22+
#include "eigenpy/ref.hpp"
23+
24+
#define ENABLE_SPECIFIC_MATRIX_TYPE(TYPE) \
25+
enableEigenPySpecific<TYPE>(); \
26+
enableEigenPySpecific< eigenpy::Ref<TYPE> >();
2227

2328
namespace eigenpy
2429
{
2530
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */
2631
void enableEigenPy();
2732

33+
template<typename MatType>
34+
void enableEigenPySpecific();
35+
2836
/* Enable the Eigen--Numpy serialization for the templated MatrixBase class.
2937
* The second template argument is used for inheritance of Eigen classes. If
3038
* using a native Eigen::MatrixBase, simply repeat the same arg twice. */
3139
template<typename MatType,typename EigenEquivalentType>
32-
void enableEigenPySpecific();
40+
EIGENPY_DEPRECATED void enableEigenPySpecific();
41+
3342

3443
} // namespace eigenpy
3544

0 commit comments

Comments
 (0)