Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ ADD_REQUIRED_DEPENDENCY("eigen3 >= 3.0.5")
SET(BOOST_COMPONENTS python)
SEARCH_FOR_BOOST()
# Add Boost path to include directories.
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS})

FINDPYTHON(2.7 EXACT REQUIRED)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(SYSTEM ${PYTHON_INCLUDE_DIRS})
FIND_NUMPY()
INCLUDE_DIRECTORIES(${NUMPY_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(SYSTEM ${NUMPY_INCLUDE_DIRS})

# ----------------------------------------------------
# --- INCLUDE ----------------------------------------
Expand Down Expand Up @@ -103,6 +103,7 @@ SET(HEADERS
registration.hpp
angle-axis.hpp
quaternion.hpp
ref.hpp
)

MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy")
Expand Down
200 changes: 108 additions & 92 deletions src/details.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,13 @@
#ifndef __eigenpy_details_hpp__
#define __eigenpy_details_hpp__

#include <boost/python.hpp>
#include <Eigen/Core>

#include <numpy/numpyconfig.h>
#ifdef NPY_1_8_API_VERSION
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include "eigenpy/fwd.hpp"

#include <numpy/arrayobject.h>
#include <iostream>

#include "eigenpy/eigenpy.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/exception.hpp"
#include "eigenpy/map.hpp"


Expand Down Expand Up @@ -58,7 +51,7 @@ namespace eigenpy
{ return make((PyObject*)pyArray,copy); }
bp::object make(PyObject* pyObj, bool copy = false)
{
boost::python::object m
bp::object m
= pyMatrixType(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
Py_INCREF(m.ptr());
return m;
Expand All @@ -67,16 +60,50 @@ namespace eigenpy
protected:
PyMatrixType()
{
pyModule = boost::python::import("numpy");
pyModule = bp::import("numpy");
pyMatrixType = pyModule.attr("matrix");
}

bp::object pyMatrixType;
bp::object pyModule;
};

template<typename MatType>
struct EigenObjectAllocator
{
typedef MatType Type;

static void allocate(PyArrayObject * pyArray, void * storage)
{
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray);
new(storage) MatType(numpyMap);
}

static void convert(Type const & mat , PyArrayObject * pyArray)
{
MapNumpy<MatType>::map(pyArray) = mat;
}
};

template<typename MatType>
struct EigenObjectAllocator< eigenpy::Ref<MatType> >
{
typedef eigenpy::Ref<MatType> Type;

static void allocate(PyArrayObject * pyArray, void * storage)
{
typename MapNumpy<MatType>::EigenMap numpyMap = MapNumpy<MatType>::map(pyArray);
new(storage) Type(numpyMap);
}

static void convert(Type const & mat , PyArrayObject * pyArray)
{
MapNumpy<MatType>::map(pyArray) = mat;
}
};

/* --- TO PYTHON -------------------------------------------------------------- */
template< typename MatType,typename EquivalentEigenType >
template<typename MatType>
struct EigenToPy
{
static PyObject* convert(MatType const& mat)
Expand All @@ -88,139 +115,128 @@ namespace eigenpy

npy_intp shape[2] = { R,C };
PyArrayObject* pyArray = (PyArrayObject*)
PyArray_SimpleNew(2, shape, NumpyEquivalentType<T>::type_code);
PyArray_SimpleNew(2, shape, NumpyEquivalentType<T>::type_code);

MapNumpy<EquivalentEigenType>::map(pyArray) = mat;
EigenObjectAllocator<MatType>::convert(mat,pyArray);

return PyMatrixType::getInstance().make(pyArray).ptr();
}
};

/* --- FROM PYTHON ------------------------------------------------------------ */
namespace bp = boost::python;

template<typename MatType, int ROWS,int COLS>
struct TraitsMatrixConstructor
{
static MatType & construct(void*storage,int /*r*/,int /*c*/)
{
return * new(storage) MatType();
}
};

template<typename MatType>
struct TraitsMatrixConstructor<MatType,Eigen::Dynamic,Eigen::Dynamic>
{
static MatType & construct(void*storage,int r,int c)
{
return * new(storage) MatType(r,c);
}
};

template<typename MatType,int R>
struct TraitsMatrixConstructor<MatType,R,Eigen::Dynamic>
{
static MatType & construct(void*storage,int /*r*/,int c)
{
return * new(storage) MatType(R,c);
}
};

template<typename MatType,int C>
struct TraitsMatrixConstructor<MatType,Eigen::Dynamic,C>
{
static MatType & construct(void*storage,int r,int /*c*/)
{
return * new(storage) MatType(r,C);
}
};


template<typename MatType,typename EquivalentEigenType>
struct EigenFromPy
{
EigenFromPy()
{
bp::converter::registry::push_back
(reinterpret_cast<void *(*)(_object *)>(&convertible),
&construct,bp::type_id<MatType>());
(reinterpret_cast<void *(*)(_object *)>(&convertible),
&construct,bp::type_id<MatType>());
}

// Determine if obj_ptr can be converted in a Eigenvec
static void* convertible(PyArrayObject* obj_ptr)
{
typedef typename MatType::Scalar T;

if (!PyArray_Check(obj_ptr))
{
if (!PyArray_Check(obj_ptr))
{
#ifndef NDEBUG
std::cerr << "The python object is not a numpy array." << std::endl;
std::cerr << "The python object is not a numpy array." << std::endl;
#endif
return 0;
}

return 0;
}

if(MatType::IsVectorAtCompileTime)
{
if(PyArray_DIMS(obj_ptr)[0] > 1 && PyArray_DIMS(obj_ptr)[1] > 1)
{
#ifndef NDEBUG
std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
#endif
return 0;
}

if(((PyArray_DIMS(obj_ptr)[0] == 1) && (MatType::ColsAtCompileTime == 1))
|| ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
{
#ifndef NDEBUG
if(MatType::ColsAtCompileTime == 1)
std::cerr << "The object is not a column vector" << std::endl;
else
std::cerr << "The object is not a row vector" << std::endl;
#endif
return 0;
}
}

if (PyArray_NDIM(obj_ptr) != 2)
if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
{
{
if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
{
#ifndef NDEBUG
std::cerr << "The number of dimension of the object is not correct." << std::endl;
std::cerr << "The number of dimension of the object is not correct." << std::endl;
#endif
return 0;
}

if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) != NumpyEquivalentType<T>::type_code)
{
return 0;
}
}

if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
!= NumpyEquivalentType<typename MatType::Scalar>::type_code)
{
#ifndef NDEBUG
std::cerr << "The internal type as no Eigen equivalent." << std::endl;
std::cerr << "The internal type as no Eigen equivalent." << std::endl;
#endif
return 0;
}
return 0;
}
#ifdef NPY_1_8_API_VERSION
if (!(PyArray_FLAGS(obj_ptr)))
#else
if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
#endif
{
{
#ifndef NDEBUG
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
#endif
return 0;
}
return 0;
}

return obj_ptr;
}

// Convert obj_ptr into a Eigenvec
static void construct(PyObject* pyObj,
bp::converter::rvalue_from_python_stage1_data* memory)
bp::converter::rvalue_from_python_stage1_data* memory)
{
using namespace Eigen;

PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
typename MapNumpy<EquivalentEigenType>::EigenMap numpyMap = MapNumpy<EquivalentEigenType>::map(pyArray);

assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
void* storage = ((bp::converter::rvalue_from_python_storage<MatType>*)
((void*)memory))->storage.bytes;
assert( (numpyMap.rows()<INT_MAX) && (numpyMap.cols()<INT_MAX)
&& "Map range larger than int ... can never happen." );
int r=(int)numpyMap.rows(),c=(int)numpyMap.cols();
EquivalentEigenType & eigenMatrix = //* new(storage) MatType(numpyMap.rows(),numpyMap.cols());
TraitsMatrixConstructor<MatType,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime>::construct (storage,r,c);
memory->convertible = storage;
((void*)memory))->storage.bytes;

EigenObjectAllocator<MatType>::allocate(pyArray,storage);

eigenMatrix = numpyMap;
memory->convertible = storage;
}
};

#define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } }

template<typename MatType,typename EigenEquivalentType>
void enableEigenPySpecific()
{
enableEigenPySpecific<MatType>();
}

template<typename MatType>
void enableEigenPySpecific()
{
numpy_import_array();
if(check_registration<MatType>()) return;

boost::python::to_python_converter<MatType,EigenToPy<MatType,MatType> >();
EigenFromPy<MatType,MatType>();
bp::to_python_converter<MatType,EigenToPy<MatType> >();
EigenFromPy<MatType>();
}

} // namespace eigenpy
Expand Down
21 changes: 11 additions & 10 deletions src/eigenpy.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 LAAS-CNRS
* Copyright (c) 2015-2018 LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
Expand All @@ -22,17 +22,18 @@ namespace eigenpy
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */
void enableEigenPy()
{
using namespace Eigen;
Exception::registerException();

enableEigenPySpecific<Eigen::MatrixXd,Eigen::MatrixXd>();
enableEigenPySpecific<Eigen::Matrix2d,Eigen::Matrix2d>();
enableEigenPySpecific<Eigen::Matrix3d,Eigen::Matrix3d>();
enableEigenPySpecific<Eigen::Matrix4d,Eigen::Matrix4d>();

enableEigenPySpecific<Eigen::VectorXd,Eigen::VectorXd>();
enableEigenPySpecific<Eigen::Vector2d,Eigen::Vector2d>();
enableEigenPySpecific<Eigen::Vector3d,Eigen::Vector3d>();
enableEigenPySpecific<Eigen::Vector4d,Eigen::Vector4d>();
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2d);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3d);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4d);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXd);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2d);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3d);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4d);
}

} // namespace eigenpy
13 changes: 11 additions & 2 deletions src/eigenpy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,27 @@
#define __eigenpy_eigenpy_hpp__

#include "eigenpy/fwd.hpp"
#include "eigenpy/memory.hpp"
#include "eigenpy/deprecated.hh"
#include "eigenpy/ref.hpp"

#define ENABLE_SPECIFIC_MATRIX_TYPE(TYPE) \
enableEigenPySpecific<TYPE>(); \
enableEigenPySpecific< eigenpy::Ref<TYPE> >();

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

template<typename MatType>
void enableEigenPySpecific();

/* Enable the Eigen--Numpy serialization for the templated MatrixBase class.
* The second template argument is used for inheritance of Eigen classes. If
* using a native Eigen::MatrixBase, simply repeat the same arg twice. */
template<typename MatType,typename EigenEquivalentType>
void enableEigenPySpecific();
EIGENPY_DEPRECATED void enableEigenPySpecific();


} // namespace eigenpy

Expand Down
Loading