dellaert 2016-01-20 09:28:30 -08:00
parent c77997fbb1
commit eb5d026a4a
3 changed files with 82 additions and 50 deletions

View File

@ -12,8 +12,17 @@
#ifndef NUMPY_EIGEN_CONVERTER_HPP #ifndef NUMPY_EIGEN_CONVERTER_HPP
#define NUMPY_EIGEN_CONVERTER_HPP #define NUMPY_EIGEN_CONVERTER_HPP
#include "boost_python_headers.hpp" #include <numpy_eigen/boost_python_headers.hpp>
#include <iostream> //#include <iostream>
#include "numpy/numpyconfig.h"
#ifdef NPY_1_7_API_VERSION
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#define NPE_PY_ARRAY_OBJECT PyArrayObject
#else
//TODO Remove this as soon as support for Numpy version before 1.7 is dropped
#define NPE_PY_ARRAY_OBJECT PyObject
#endif
#define PY_ARRAY_UNIQUE_SYMBOL NP_Eigen_AS #define PY_ARRAY_UNIQUE_SYMBOL NP_Eigen_AS
#include <numpy/arrayobject.h> #include <numpy/arrayobject.h>
@ -92,8 +101,8 @@ struct NumpyEigenConverter
// Create a 1D array // Create a 1D array
npy_intp dimensions[1]; npy_intp dimensions[1];
dimensions[0] = M.size(); dimensions[0] = M.size();
P = PyArray_SimpleNew(1, dimensions, TypeToNumPy<scalar_t>::NpyType); P = PyArray_SimpleNew(1, dimensions, TypeToNumPy<scalar_t>::NpyType);
numpyTypeDemuxer< CopyEigenToNumpyVector<const matrix_t> >(&M,P); numpyTypeDemuxer< CopyEigenToNumpyVector<const matrix_t> >(&M, reinterpret_cast<NPE_PY_ARRAY_OBJECT*>(P));
} }
else else
{ {
@ -102,7 +111,7 @@ struct NumpyEigenConverter
dimensions[0] = M.rows(); dimensions[0] = M.rows();
dimensions[1] = M.cols(); dimensions[1] = M.cols();
P = PyArray_SimpleNew(2, dimensions, TypeToNumPy<scalar_t>::NpyType); P = PyArray_SimpleNew(2, dimensions, TypeToNumPy<scalar_t>::NpyType);
numpyTypeDemuxer< CopyEigenToNumpyMatrix<const matrix_t> >(&M,P); numpyTypeDemuxer< CopyEigenToNumpyMatrix<const matrix_t> >(&M, reinterpret_cast<NPE_PY_ARRAY_OBJECT*>(P));
} }
// incrementing the reference seems to cause a memory leak. // incrementing the reference seems to cause a memory leak.
@ -131,7 +140,7 @@ struct NumpyEigenConverter
return valid; return valid;
} }
static void checkMatrixSizes(PyObject * obj_ptr) static void checkMatrixSizes(NPE_PY_ARRAY_OBJECT * obj_ptr)
{ {
int rows = PyArray_DIM(obj_ptr, 0); int rows = PyArray_DIM(obj_ptr, 0);
int cols = PyArray_DIM(obj_ptr, 1); int cols = PyArray_DIM(obj_ptr, 1);
@ -145,7 +154,7 @@ struct NumpyEigenConverter
} }
} }
static void checkRowVectorSizes(PyObject * obj_ptr, int cols) static void checkRowVectorSizes(NPE_PY_ARRAY_OBJECT * obj_ptr, int cols)
{ {
if(!isDimensionValid(cols, ColsAtCompileTime, MaxColsAtCompileTime)) if(!isDimensionValid(cols, ColsAtCompileTime, MaxColsAtCompileTime))
{ {
@ -154,7 +163,7 @@ struct NumpyEigenConverter
} }
} }
static void checkColumnVectorSizes(PyObject * obj_ptr, int rows) static void checkColumnVectorSizes(NPE_PY_ARRAY_OBJECT * obj_ptr, int rows)
{ {
// Check if the type can accomidate one column. // Check if the type can accomidate one column.
if(ColsAtCompileTime == Eigen::Dynamic || ColsAtCompileTime == 1) if(ColsAtCompileTime == Eigen::Dynamic || ColsAtCompileTime == 1)
@ -173,7 +182,7 @@ struct NumpyEigenConverter
} }
static void checkVectorSizes(PyObject * obj_ptr) static void checkVectorSizes(NPE_PY_ARRAY_OBJECT * obj_ptr)
{ {
int size = PyArray_DIM(obj_ptr, 0); int size = PyArray_DIM(obj_ptr, 0);
@ -206,8 +215,10 @@ struct NumpyEigenConverter
return 0; return 0;
} }
NPE_PY_ARRAY_OBJECT * array_ptr = reinterpret_cast<NPE_PY_ARRAY_OBJECT*>(obj_ptr);
// Check the type of the array. // Check the type of the array.
int npyType = PyArray_ObjectType(obj_ptr, 0); int npyType = getNpyType(array_ptr);
if(!TypeToNumPy<scalar_t>::canConvert(npyType)) if(!TypeToNumPy<scalar_t>::canConvert(npyType))
{ {
@ -219,7 +230,7 @@ struct NumpyEigenConverter
// Check the array dimensions. // Check the array dimensions.
int nd = PyArray_NDIM(obj_ptr); int nd = PyArray_NDIM(array_ptr);
if(nd != 1 && nd != 2) if(nd != 1 && nd != 2)
{ {
@ -228,12 +239,12 @@ struct NumpyEigenConverter
if(nd == 1) if(nd == 1)
{ {
checkVectorSizes(obj_ptr); checkVectorSizes(array_ptr);
} }
else else
{ {
// Two-dimensional matrix type. // Two-dimensional matrix type.
checkMatrixSizes(obj_ptr); checkMatrixSizes(array_ptr);
} }
@ -265,10 +276,17 @@ struct NumpyEigenConverter
matrix_t & M = *Mp; matrix_t & M = *Mp;
int nd = PyArray_NDIM(obj_ptr); if (!PyArray_Check(obj_ptr))
{
THROW_TYPE_ERROR("construct is only defined for numpy array and matrix types");
}
NPE_PY_ARRAY_OBJECT * array_ptr = reinterpret_cast<NPE_PY_ARRAY_OBJECT*>(obj_ptr);
int nd = PyArray_NDIM(array_ptr);
if(nd == 1) if(nd == 1)
{ {
int size = PyArray_DIM(obj_ptr, 0); int size = PyArray_DIM(array_ptr, 0);
// This is a vector type // This is a vector type
if(RowsAtCompileTime == 1) if(RowsAtCompileTime == 1)
{ {
@ -280,15 +298,15 @@ struct NumpyEigenConverter
// Column Vector // Column Vector
M.resize(size,1); M.resize(size,1);
} }
numpyTypeDemuxer< CopyNumpyToEigenVector<matrix_t> >(&M,obj_ptr); numpyTypeDemuxer< CopyNumpyToEigenVector<matrix_t> >(&M, array_ptr);
} }
else else
{ {
int rows = PyArray_DIM(obj_ptr, 0); int rows = PyArray_DIM(array_ptr, 0);
int cols = PyArray_DIM(obj_ptr, 1); int cols = PyArray_DIM(array_ptr, 1);
M.resize(rows,cols); M.resize(rows,cols);
numpyTypeDemuxer< CopyNumpyToEigenMatrix<matrix_t> >(&M,obj_ptr); numpyTypeDemuxer< CopyNumpyToEigenMatrix<matrix_t> >(&M, array_ptr);
} }

View File

@ -9,16 +9,16 @@ struct CopyNumpyToEigenMatrix
typedef typename matrix_t::Scalar scalar_t; typedef typename matrix_t::Scalar scalar_t;
template<typename T> template<typename T>
void exec(EIGEN_T * M_, PyObject * P_) void exec(EIGEN_T * M_, NPE_PY_ARRAY_OBJECT * P_)
{ {
// Assumes M is already initialized. // Assumes M is already initialized.
for(int r = 0; r < M_->rows(); r++) for(int r = 0; r < M_->rows(); r++)
{ {
for(int c = 0; c < M_->cols(); c++) for(int c = 0; c < M_->cols(); c++)
{ {
T * p = static_cast<T*>(PyArray_GETPTR2(P_, r, c)); T * p = static_cast<T*>(PyArray_GETPTR2(P_, r, c));
(*M_)(r,c) = static_cast<scalar_t>(*p); (*M_)(r,c) = static_cast<scalar_t>(*p);
} }
} }
} }
@ -31,16 +31,16 @@ struct CopyEigenToNumpyMatrix
typedef typename matrix_t::Scalar scalar_t; typedef typename matrix_t::Scalar scalar_t;
template<typename T> template<typename T>
void exec(EIGEN_T * M_, PyObject * P_) void exec(EIGEN_T * M_, NPE_PY_ARRAY_OBJECT * P_)
{ {
// Assumes M is already initialized. // Assumes M is already initialized.
for(int r = 0; r < M_->rows(); r++) for(int r = 0; r < M_->rows(); r++)
{ {
for(int c = 0; c < M_->cols(); c++) for(int c = 0; c < M_->cols(); c++)
{ {
T * p = static_cast<T*>(PyArray_GETPTR2(P_, r, c)); T * p = static_cast<T*>(PyArray_GETPTR2(P_, r, c));
*p = static_cast<T>((*M_)(r,c)); *p = static_cast<T>((*M_)(r,c));
} }
} }
} }
@ -53,13 +53,13 @@ struct CopyEigenToNumpyVector
typedef typename matrix_t::Scalar scalar_t; typedef typename matrix_t::Scalar scalar_t;
template<typename T> template<typename T>
void exec(EIGEN_T * M_, PyObject * P_) void exec(EIGEN_T * M_, NPE_PY_ARRAY_OBJECT * P_)
{ {
// Assumes M is already initialized. // Assumes M is already initialized.
for(int i = 0; i < M_->size(); i++) for(int i = 0; i < M_->size(); i++)
{ {
T * p = static_cast<T*>(PyArray_GETPTR1(P_, i)); T * p = static_cast<T*>(PyArray_GETPTR1(P_, i));
*p = static_cast<T>((*M_)(i)); *p = static_cast<T>((*M_)(i));
} }
} }
@ -73,13 +73,13 @@ struct CopyNumpyToEigenVector
typedef typename matrix_t::Scalar scalar_t; typedef typename matrix_t::Scalar scalar_t;
template<typename T> template<typename T>
void exec(EIGEN_T * M_, PyObject * P_) void exec(EIGEN_T * M_, NPE_PY_ARRAY_OBJECT * P_)
{ {
// Assumes M is already initialized. // Assumes M is already initialized.
for(int i = 0; i < M_->size(); i++) for(int i = 0; i < M_->size(); i++)
{ {
T * p = static_cast<T*>(PyArray_GETPTR1(P_, i)); T * p = static_cast<T*>(PyArray_GETPTR1(P_, i));
(*M_)(i) = static_cast<scalar_t>(*p); (*M_)(i) = static_cast<scalar_t>(*p);
} }
} }
@ -91,10 +91,11 @@ struct CopyNumpyToEigenVector
// Crazy syntax in this function was found here: // Crazy syntax in this function was found here:
// http://stackoverflow.com/questions/1840253/c-template-member-function-of-template-class-called-from-template-function/1840318#1840318 // http://stackoverflow.com/questions/1840253/c-template-member-function-of-template-class-called-from-template-function/1840318#1840318
template< typename FUNCTOR_T> template< typename FUNCTOR_T>
inline void numpyTypeDemuxer(typename FUNCTOR_T::matrix_t * M, PyObject * P) inline void numpyTypeDemuxer(typename FUNCTOR_T::matrix_t * M, NPE_PY_ARRAY_OBJECT * P)
{ {
FUNCTOR_T f; FUNCTOR_T f;
int npyType = PyArray_ObjectType(P, 0);
int npyType = getNpyType(P);
switch(npyType) switch(npyType)
{ {
case NPY_BOOL: case NPY_BOOL:

View File

@ -1,12 +1,12 @@
#ifndef NUMPY_EIGEN_TYPE_TRAITS_HPP #ifndef NUMPY_EIGEN_TYPE_TRAITS_HPP
#define NUMPY_EIGEN_TYPE_TRAITS_HPP #define NUMPY_EIGEN_TYPE_TRAITS_HPP
#define THROW_TYPE_ERROR(msg) \ #define THROW_TYPE_ERROR(msg) \
{ \ { \
std::stringstream type_error_ss; \ std::stringstream type_error_ss; \
type_error_ss << msg; \ type_error_ss << msg; \
PyErr_SetString(PyExc_TypeError, type_error_ss.str().c_str()); \ PyErr_SetString(PyExc_TypeError, type_error_ss.str().c_str()); \
throw boost::python::error_already_set(); \ throw boost::python::error_already_set(); \
} }
@ -99,6 +99,19 @@ template<> struct TypeToNumPy<double>
}; };
inline int getNpyType(PyObject * obj_ptr){
return PyArray_ObjectType(obj_ptr, 0);
}
#ifdef NPY_1_7_API_VERSION
inline int getNpyType(PyArrayObject * obj_ptr){
PyArray_Descr * descr = PyArray_MinScalarType(obj_ptr);
if (descr == NULL){
THROW_TYPE_ERROR("Unsupported type: PyArray_MinScalarType returned null!");
}
return descr->type_num;
}
#endif
inline const char * npyTypeToString(int npyType) inline const char * npyTypeToString(int npyType)
{ {
@ -157,18 +170,18 @@ inline const char * npyTypeToString(int npyType)
} }
} }
inline std::string npyArrayTypeString(PyObject * obj_ptr) inline std::string npyArrayTypeString(NPE_PY_ARRAY_OBJECT * obj_ptr)
{ {
std::stringstream ss; std::stringstream ss;
int nd = PyArray_NDIM(obj_ptr); int nd = PyArray_NDIM(obj_ptr);
ss << "numpy.array<" << npyTypeToString(PyArray_ObjectType(obj_ptr, 0)) << ">["; ss << "numpy.array<" << npyTypeToString(getNpyType(obj_ptr)) << ">[";
if(nd > 0) if(nd > 0)
{ {
ss << PyArray_DIM(obj_ptr, 0); ss << PyArray_DIM(obj_ptr, 0);
for(int i = 1; i < nd; i++) for(int i = 1; i < nd; i++)
{ {
ss << ", " << PyArray_DIM(obj_ptr, i); ss << ", " << PyArray_DIM(obj_ptr, i);
} }
} }
ss << "]"; ss << "]";
return ss.str(); return ss.str();