Skip to content
Snippets Groups Projects
Unverified Commit 56fe46a2 authored by Justin Carpentier's avatar Justin Carpentier Committed by GitHub
Browse files

Merge pull request #163 from jcarpent/devel

Implement full support of Eigen::Ref
parents bb8df999 9e606508
No related branches found
No related tags found
No related merge requests found
......@@ -74,6 +74,7 @@ SEARCH_FOR_BOOST()
SET(${PROJECT_NAME}_UTILS_HEADERS
include/eigenpy/utils/scalar-name.hpp
include/eigenpy/utils/is-approx.hpp
include/eigenpy/utils/is-aligned.hpp
)
SET(${PROJECT_NAME}_SOLVERS_HEADERS
......
......@@ -8,6 +8,7 @@
#include "eigenpy/fwd.hpp"
#include "eigenpy/map.hpp"
#include "eigenpy/scalar-conversion.hpp"
#include "eigenpy/utils/is-aligned.hpp"
namespace eigenpy
{
......@@ -17,7 +18,7 @@ namespace eigenpy
template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
struct init_matrix_or_array
{
static MatType * run(PyArrayObject * pyArray, void * storage)
static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
{
assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2);
......@@ -33,25 +34,34 @@ namespace eigenpy
cols = 1;
}
return new (storage) MatType(rows,cols);
if(storage)
return new (storage) MatType(rows,cols);
else
return new MatType(rows,cols);
}
};
template<typename MatType>
struct init_matrix_or_array<MatType,true>
{
static MatType * run(PyArrayObject * pyArray, void * storage)
static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
{
if(PyArray_NDIM(pyArray) == 1)
{
const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0];
return new (storage) MatType(rows_or_cols);
if(storage)
return new (storage) MatType(rows_or_cols);
else
return new MatType(rows_or_cols);
}
else
{
const int rows = (int)PyArray_DIMS(pyArray)[0];
const int cols = (int)PyArray_DIMS(pyArray)[1];
return new (storage) MatType(rows,cols);
if(storage)
return new (storage) MatType(rows,cols);
else
return new MatType(rows,cols);
}
}
};
......@@ -79,7 +89,7 @@ namespace eigenpy
const Eigen::MatrixBase<MatrixOut> & /*dest*/)
{
// do nothing
assert("Must never happened");
assert(false && "Must never happened");
}
};
......@@ -97,9 +107,11 @@ namespace eigenpy
typedef MatType Type;
typedef typename MatType::Scalar Scalar;
static void allocate(PyArrayObject * pyArray, void * storage)
static void allocate(PyArrayObject * pyArray,
bp::converter::rvalue_from_python_storage<MatType> * storage)
{
Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,storage);
void * raw_ptr = storage->storage.bytes;
Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,raw_ptr);
Type & mat = *mat_ptr;
const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
......@@ -193,6 +205,190 @@ namespace eigenpy
};
#if EIGEN_VERSION_AT_LEAST(3,2,0)
template<typename MatType, int Options, typename Stride>
struct EigenAllocator<Eigen::Ref<MatType,Options,Stride> >
{
typedef Eigen::Ref<MatType,Options,Stride> RefType;
typedef typename MatType::Scalar Scalar;
typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
static void allocate(PyArrayObject * pyArray,
bp::converter::rvalue_from_python_storage<RefType> * storage)
{
typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
bool need_to_allocate = false;
const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
need_to_allocate |= true;
if( (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
|| (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
|| MatType::IsVectorAtCompileTime
|| (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
need_to_allocate |= false;
else
need_to_allocate |= true;
if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
{
void * data_ptr = PyArray_DATA(pyArray);
if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
need_to_allocate |= true;
}
void * raw_ptr = storage->storage.bytes;
if(need_to_allocate)
{
MatType * mat_ptr;
mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
RefType mat_ref(*mat_ptr);
new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
RefType & mat = *reinterpret_cast<RefType*>(raw_ptr);
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
{
mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
return;
}
switch(pyArray_Type)
{
case NPY_INT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
break;
case NPY_LONG:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
break;
case NPY_FLOAT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
break;
case NPY_CFLOAT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
break;
case NPY_DOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
break;
case NPY_CDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
break;
case NPY_LONGDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
break;
case NPY_CLONGDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
break;
default:
throw Exception("You asked for a conversion which is not implemented.");
}
}
else
{
assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
typename MapNumpy<MatType,Scalar,Options,NumpyMapStride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Options,NumpyMapStride>::map(pyArray);
RefType mat_ref(numpyMap);
new (raw_ptr) StorageType(mat_ref,pyArray);
}
}
static void copy(RefType const & ref, PyArrayObject * pyArray)
{
EigenAllocator<MatType>::copy(ref,pyArray);
}
};
template<typename MatType, int Options, typename Stride>
struct EigenAllocator<const Eigen::Ref<const MatType,Options,Stride> >
{
typedef const Eigen::Ref<const MatType,Options,Stride> RefType;
typedef typename MatType::Scalar Scalar;
typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
static void allocate(PyArrayObject * pyArray,
bp::converter::rvalue_from_python_storage<RefType> * storage)
{
typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
bool need_to_allocate = false;
const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
need_to_allocate |= true;
if( (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
|| (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
|| MatType::IsVectorAtCompileTime
|| (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
need_to_allocate |= false;
else
need_to_allocate |= true;
if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
{
void * data_ptr = PyArray_DATA(pyArray);
if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
need_to_allocate |= true;
}
void * raw_ptr = storage->storage.bytes;
if(need_to_allocate)
{
MatType * mat_ptr;
mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
RefType mat_ref(*mat_ptr);
new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
MatType & mat = *mat_ptr;
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
{
mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
return;
}
switch(pyArray_Type)
{
case NPY_INT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
break;
case NPY_LONG:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
break;
case NPY_FLOAT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
break;
case NPY_CFLOAT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
break;
case NPY_DOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
break;
case NPY_CDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
break;
case NPY_LONGDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
break;
case NPY_CLONGDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
break;
default:
throw Exception("You asked for a conversion which is not implemented.");
}
}
else
{
assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
typename MapNumpy<MatType,Scalar,Options,NumpyMapStride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Options,NumpyMapStride>::map(pyArray);
RefType mat_ref(numpyMap);
new (raw_ptr) StorageType(mat_ref,pyArray);
}
}
static void copy(RefType const & ref, PyArrayObject * pyArray)
{
EigenAllocator<MatType>::copy(ref,pyArray);
}
};
template<typename MatType>
struct EigenAllocator< eigenpy::Ref<MatType> >
{
......
......@@ -12,6 +12,103 @@
#include <boost/python/converter/rvalue_from_python_data.hpp>
namespace eigenpy
{
namespace details
{
template<typename MatType, bool is_const = boost::is_const<MatType>::value>
struct copy_if_non_const
{
static void run(const Eigen::MatrixBase<MatType> & input,
PyArrayObject * pyArray)
{
EigenAllocator<MatType>::copy(input,pyArray);
}
};
template<typename MatType>
struct copy_if_non_const<const MatType,true>
{
static void run(const Eigen::MatrixBase<MatType> & /*input*/,
PyArrayObject * /*pyArray*/)
{}
};
#if EIGEN_VERSION_AT_LEAST(3,2,0)
template<typename MatType, int Options, typename Stride> struct referent_storage_eigen_ref;
template<typename MatType, int Options, typename Stride>
struct referent_storage_eigen_ref
{
typedef Eigen::Ref<MatType,Options,Stride> RefType;
typedef ::boost::python::detail::aligned_storage<
::boost::python::detail::referent_size<RefType&>::value
> AlignedStorage;
referent_storage_eigen_ref()
: pyArray(NULL)
, mat_ptr(NULL)
, ref_ptr(reinterpret_cast<RefType*>(ref_storage.bytes))
{
}
referent_storage_eigen_ref(const RefType & ref,
PyArrayObject * pyArray,
MatType * mat_ptr = NULL)
: pyArray(pyArray)
, mat_ptr(mat_ptr)
, ref_ptr(reinterpret_cast<RefType*>(ref_storage.bytes))
{
Py_INCREF(pyArray);
new (ref_storage.bytes) RefType(ref);
}
~referent_storage_eigen_ref()
{
if(mat_ptr != NULL && PyArray_ISWRITEABLE(pyArray))
copy_if_non_const<MatType>::run(*mat_ptr,pyArray);
Py_DECREF(pyArray);
if(mat_ptr != NULL)
mat_ptr->~MatType();
ref_ptr->~RefType();
}
AlignedStorage ref_storage;
PyArrayObject * pyArray;
MatType * mat_ptr;
RefType * ref_ptr;
};
#endif
}
}
namespace boost { namespace python { namespace detail {
#if EIGEN_VERSION_AT_LEAST(3,2,0)
template<typename MatType, int Options, typename Stride>
struct referent_storage<Eigen::Ref<MatType,Options,Stride> &>
{
typedef ::eigenpy::details::referent_storage_eigen_ref<MatType,Options,Stride> StorageType;
typedef aligned_storage<
::boost::python::detail::referent_size<StorageType&>::value
> type;
};
template<typename MatType, int Options, typename Stride>
struct referent_storage<const Eigen::Ref<const MatType,Options,Stride> &>
{
typedef ::eigenpy::details::referent_storage_eigen_ref<const MatType,Options,Stride> StorageType;
typedef aligned_storage<
::boost::python::detail::referent_size<StorageType&>::value
> type;
};
#endif
}}}
namespace boost { namespace python { namespace converter {
template<typename MatrixReference>
......@@ -51,7 +148,6 @@ namespace boost { namespace python { namespace converter {
}
};
#define RVALUE_FROM_PYTHON_DATA_INIT(type) \
typedef rvalue_from_python_data_eigen<type> Base; \
\
......@@ -79,10 +175,100 @@ namespace boost { namespace python { namespace converter {
#undef RVALUE_FROM_PYTHON_DATA_INIT
template<typename MatType, int Options, typename Stride>
struct rvalue_from_python_data<Eigen::Ref<MatType,Options,Stride> &>
: rvalue_from_python_storage<Eigen::Ref<MatType,Options,Stride> &>
{
typedef Eigen::Ref<MatType,Options,Stride> T;
# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
&& (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
&& (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
&& !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
// This must always be a POD struct with m_data its first member.
BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
# endif
// The usual constructor
rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
{
this->stage1 = _stage1;
}
// This constructor just sets m_convertible -- used by
// implicitly_convertible<> to perform the final step of the
// conversion, where the construct() function is already known.
rvalue_from_python_data(void* convertible)
{
this->stage1.convertible = convertible;
}
// Destroys any object constructed in the storage.
~rvalue_from_python_data()
{
typedef ::eigenpy::details::referent_storage_eigen_ref<MatType, Options,Stride> StorageType;
if (this->stage1.convertible == this->storage.bytes)
static_cast<StorageType *>((void *)this->storage.bytes)->~StorageType();
}
};
template<typename MatType, int Options, typename Stride>
struct rvalue_from_python_data<const Eigen::Ref<const MatType,Options,Stride> &>
: rvalue_from_python_storage<const Eigen::Ref<const MatType,Options,Stride> &>
{
typedef const Eigen::Ref<const MatType,Options,Stride> T;
# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
&& (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
&& (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
&& !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
// This must always be a POD struct with m_data its first member.
BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
# endif
// The usual constructor
rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
{
this->stage1 = _stage1;
}
// This constructor just sets m_convertible -- used by
// implicitly_convertible<> to perform the final step of the
// conversion, where the construct() function is already known.
rvalue_from_python_data(void* convertible)
{
this->stage1.convertible = convertible;
}
// Destroys any object constructed in the storage.
~rvalue_from_python_data()
{
typedef ::eigenpy::details::referent_storage_eigen_ref<const MatType, Options,Stride> StorageType;
if (this->stage1.convertible == this->storage.bytes)
static_cast<StorageType *>((void *)this->storage.bytes)->~StorageType();
}
};
} } }
namespace eigenpy
{
template<typename MatOrRefType>
void eigen_from_py_construct(PyObject* pyObj,
bp::converter::rvalue_from_python_stage1_data* memory)
{
PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
bp::converter::rvalue_from_python_storage<MatOrRefType>* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatOrRefType>*>
(reinterpret_cast<void*>(memory));
EigenAllocator<MatOrRefType>::allocate(pyArray,storage);
memory->convertible = storage->storage.bytes;
}
template<typename MatType>
struct EigenFromPy
{
......@@ -215,15 +401,7 @@ namespace eigenpy
void EigenFromPy<MatType>::construct(PyObject* pyObj,
bp::converter::rvalue_from_python_stage1_data* memory)
{
PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
void* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatType>*>
(reinterpret_cast<void*>(memory))->storage.bytes;
EigenAllocator<MatType>::allocate(pyArray,storage);
memory->convertible = storage;
eigen_from_py_construct<MatType>(pyObj,memory);
}
template<typename MatType>
......@@ -241,13 +419,23 @@ namespace eigenpy
{
EigenFromPy<MatType>::registration();
// Add also conversion to Eigen::MatrixBase<MatType>
// Add conversion to Eigen::MatrixBase<MatType>
typedef Eigen::MatrixBase<MatType> MatrixBase;
EigenFromPy<MatrixBase>::registration();
// Add also conversion to Eigen::EigenBase<MatType>
// Add conversion to Eigen::EigenBase<MatType>
typedef Eigen::EigenBase<MatType> EigenBase;
EigenFromPy<EigenBase>::registration();
#if EIGEN_VERSION_AT_LEAST(3,2,0)
// Add conversion to Eigen::Ref<MatType>
typedef Eigen::Ref<MatType> RefType;
EigenFromPy<RefType>::registration();
// Add conversion to Eigen::Ref<MatType>
typedef const Eigen::Ref<const MatType> ConstRefType;
EigenFromPy<ConstRefType>::registration();
#endif
}
};
......@@ -280,6 +468,51 @@ namespace eigenpy
};
#if EIGEN_VERSION_AT_LEAST(3,2,0)
template<typename MatType, int Options, typename Stride>
struct EigenFromPy<Eigen::Ref<MatType,Options,Stride> >
{
typedef Eigen::Ref<MatType,Options,Stride> RefType;
typedef typename MatType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void* convertible(PyArrayObject * pyArray)
{
if(!PyArray_Check(pyArray))
return 0;
if(!PyArray_ISWRITEABLE(pyArray))
return 0;
return EigenFromPy<MatType>::convertible(pyArray);
}
static void registration()
{
bp::converter::registry::push_back
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&eigen_from_py_construct<RefType>,bp::type_id<RefType>());
}
};
template<typename MatType, int Options, typename Stride>
struct EigenFromPy<const Eigen::Ref<const MatType,Options,Stride> >
{
typedef const Eigen::Ref<const MatType,Options,Stride> ConstRefType;
typedef typename MatType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void* convertible(PyArrayObject * pyArray)
{
return EigenFromPy<MatType>::convertible(pyArray);
}
static void registration()
{
bp::converter::registry::push_back
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&eigen_from_py_construct<ConstRefType>,bp::type_id<ConstRefType>());
}
};
// Template specialization for Eigen::Ref
template<typename MatType>
struct EigenFromPyConverter< eigenpy::Ref<MatType> >
......
......@@ -14,15 +14,13 @@
#include "eigenpy/numpy.hpp"
#undef NO_IMPORT_ARRAY
#ifdef NPY_ALIGNED
#if EIGEN_VERSION_AT_LEAST(3,2,90)
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned16
#else
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned
#endif
#else
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Unaligned
#endif
#define EIGENPY_NO_ALIGNMENT_VALUE Eigen::Unaligned
#include "eigenpy/expose.hpp"
......
......@@ -12,18 +12,17 @@
namespace eigenpy
{
template<typename MatType, typename InputScalar, bool IsVector>
template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride, bool IsVector = MatType::IsVectorAtCompileTime>
struct MapNumpyTraits {};
/* Wrap a numpy::array with an Eigen::Map. No memory copy. */
template<typename MatType, typename InputScalar>
template<typename MatType, typename InputScalar, int AlignmentValue = EIGENPY_NO_ALIGNMENT_VALUE, typename Stride = typename StrideType<MatType>::type>
struct MapNumpy
{
typedef MapNumpyTraits<MatType, InputScalar, MatType::IsVectorAtCompileTime> Impl;
typedef MapNumpyTraits<MatType, InputScalar, AlignmentValue, Stride> Impl;
typedef typename Impl::EigenMap EigenMap;
typedef typename Impl::Stride Stride;
static inline EigenMap map( PyArrayObject* pyArray );
static EigenMap map(PyArrayObject* pyArray);
};
} // namespace eigenpy
......@@ -34,19 +33,23 @@ namespace eigenpy
namespace eigenpy
{
template<typename MatType, typename InputScalar>
struct MapNumpyTraits<MatType,InputScalar,false>
template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride>
struct MapNumpyTraits<MatType,InputScalar,AlignmentValue,Stride,false>
{
typedef typename StrideType<MatType>::type Stride;
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime,MatType::Options> EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType,AlignmentValue,Stride> EigenMap;
static EigenMap mapImpl( PyArrayObject* pyArray )
static EigenMap mapImpl(PyArrayObject* pyArray)
{
enum {
OuterStrideAtCompileTime = Stride::OuterStrideAtCompileTime,
InnerStrideAtCompileTime = Stride::InnerStrideAtCompileTime,
};
assert(PyArray_NDIM(pyArray) == 2 || PyArray_NDIM(pyArray) == 1);
const long int itemsize = PyArray_ITEMSIZE(pyArray);
int stride1 = -1, stride2 = -1;
int inner_stride = -1, outer_stride = -1;
int rows = -1, cols = -1;
if(PyArray_NDIM(pyArray) == 2)
{
......@@ -57,8 +60,17 @@ namespace eigenpy
rows = (int)PyArray_DIMS(pyArray)[0];
cols = (int)PyArray_DIMS(pyArray)[1];
stride1 = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
stride2 = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
if(EquivalentInputMatrixType::IsRowMajor)
{
inner_stride = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
}
else
{
inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
outer_stride = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
}
}
else if(PyArray_NDIM(pyArray) == 1)
{
......@@ -68,33 +80,40 @@ namespace eigenpy
rows = (int)PyArray_DIMS(pyArray)[0];
cols = 1;
stride1 = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
stride2 = 0;
inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
outer_stride = 0;
}
Stride stride(stride2,stride1);
// Specific care for Eigen::Stride<-1,0>
if(InnerStrideAtCompileTime==0 && OuterStrideAtCompileTime==Eigen::Dynamic)
{
outer_stride = std::max(inner_stride,outer_stride); inner_stride = 0;
}
if( (MatType::RowsAtCompileTime!=rows)
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
Stride stride(OuterStrideAtCompileTime==Eigen::Dynamic?outer_stride:OuterStrideAtCompileTime,
InnerStrideAtCompileTime==Eigen::Dynamic?inner_stride:InnerStrideAtCompileTime);
if( (MatType::RowsAtCompileTime != rows)
&& (MatType::RowsAtCompileTime != Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of rows does not fit with the matrix type."); }
if( (MatType::ColsAtCompileTime!=cols)
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
if( (MatType::ColsAtCompileTime != cols)
&& (MatType::ColsAtCompileTime != Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of columns does not fit with the matrix type."); }
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
return EigenMap( pyData, rows, cols, stride );
return EigenMap(pyData, rows, cols, stride);
}
};
template<typename MatType, typename InputScalar>
struct MapNumpyTraits<MatType,InputScalar,true>
template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride>
struct MapNumpyTraits<MatType,InputScalar,AlignmentValue,Stride,true>
{
typedef typename StrideType<MatType>::type Stride;
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime,MatType::Options> EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType,AlignmentValue,Stride> EigenMap;
static EigenMap mapImpl( PyArrayObject* pyArray )
static EigenMap mapImpl(PyArrayObject* pyArray)
{
assert( PyArray_NDIM(pyArray) <= 2 );
......@@ -110,8 +129,8 @@ namespace eigenpy
const long int itemsize = PyArray_ITEMSIZE(pyArray);
const int stride = (int) PyArray_STRIDE(pyArray, rowMajor) / (int) itemsize;;
if( (MatType::MaxSizeAtCompileTime!=R)
&& (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) )
if( (MatType::MaxSizeAtCompileTime != R)
&& (MatType::MaxSizeAtCompileTime != Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of elements does not fit with the vector type."); }
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
......@@ -120,11 +139,11 @@ namespace eigenpy
}
};
template<typename MatType, typename InputScalar>
typename MapNumpy<MatType,InputScalar>::EigenMap
MapNumpy<MatType,InputScalar>::map(PyArrayObject * pyArray)
template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride>
typename MapNumpy<MatType,InputScalar,AlignmentValue,Stride>::EigenMap
MapNumpy<MatType,InputScalar,AlignmentValue,Stride>::map(PyArrayObject * pyArray)
{
return Impl::mapImpl(pyArray);
return Impl::mapImpl(pyArray);
}
} // namespace eigenpy
......
......@@ -50,6 +50,15 @@ namespace eigenpy
}
};
#if EIGEN_VERSION_AT_LEAST(3,2,0)
template<typename MatType, int Options, typename Stride>
struct NumpyAllocator<Eigen::Ref<MatType,Options,Stride> > : NumpyAllocator<MatType &>
{
};
#endif
template<typename MatType>
struct NumpyAllocator<const MatType &>
{
......@@ -69,6 +78,15 @@ namespace eigenpy
return pyArray;
}
};
#if EIGEN_VERSION_AT_LEAST(3,2,0)
template<typename MatType, int Options, typename Stride>
struct NumpyAllocator<const Eigen::Ref<const MatType,Options,Stride> > : NumpyAllocator<const MatType &>
{
};
#endif
}
#endif // ifndef __eigenpy_numpy_allocator_hpp__
......@@ -20,10 +20,10 @@ namespace eigenpy
template<typename PlainObjectTypeT>
struct Ref
: Eigen::Ref<PlainObjectTypeT,EIGENPY_DEFAULT_ALIGNMENT_VALUE,typename StrideType<PlainObjectTypeT>::type>
: Eigen::Ref<PlainObjectTypeT,EIGENPY_NO_ALIGNMENT_VALUE,typename StrideType<PlainObjectTypeT>::type>
{
public:
typedef Eigen::Ref<PlainObjectTypeT,EIGENPY_DEFAULT_ALIGNMENT_VALUE,typename eigenpy::template StrideType<PlainObjectTypeT>::type> Base;
typedef Eigen::Ref<PlainObjectTypeT,EIGENPY_NO_ALIGNMENT_VALUE,typename eigenpy::template StrideType<PlainObjectTypeT>::type> Base;
private:
typedef Eigen::internal::traits<Base> Traits;
......
......@@ -10,17 +10,18 @@
namespace eigenpy
{
template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
template<typename MatType, int InnerStride = Eigen::Dynamic, int OuterStride = Eigen::Dynamic, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
struct StrideType
{
typedef Eigen::Stride<Eigen::Dynamic,Eigen::Dynamic> type;
typedef Eigen::Stride<OuterStride,InnerStride> type;
};
template<typename MatType>
struct StrideType<MatType,true>
template<typename MatType, int InnerStride, int OuterStride>
struct StrideType<MatType,InnerStride,OuterStride,true>
{
typedef Eigen::InnerStride<Eigen::Dynamic> type;
typedef Eigen::InnerStride<InnerStride> type;
};
}
#endif // ifndef __eigenpy_stride_hpp__
//
// Copyright (c) 2020 INRIA
//
#ifndef __eigenpy_utils_is_aligned_hpp__
#define __eigenpy_utils_is_aligned_hpp__
namespace eigenpy
{
inline bool is_aligned(void * ptr, std::size_t alignment)
{
return (reinterpret_cast<std::size_t>(ptr) & (alignment - 1)) == 0;
}
}
#endif
......@@ -13,6 +13,5 @@ namespace eigenpy
PyErr_Print();
PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import");
}
// std::cout << "init _import_array " << std::endl;
}
}
......@@ -34,13 +34,15 @@ ADD_LIB_UNIT_TEST(geometry "eigen3")
ADD_LIB_UNIT_TEST(complex "eigen3")
ADD_LIB_UNIT_TEST(return_by_ref "eigen3")
IF(NOT ${EIGEN3_VERSION} VERSION_LESS "3.2.0")
ADD_LIB_UNIT_TEST(ref "eigen3")
ADD_LIB_UNIT_TEST(eigen_ref "eigen3")
ADD_LIB_UNIT_TEST(eigenpy_ref "eigen3")
ENDIF()
ADD_PYTHON_UNIT_TEST("py-matrix" "unittest/python/test_matrix.py" "unittest")
ADD_PYTHON_UNIT_TEST("py-geometry" "unittest/python/test_geometry.py" "unittest")
ADD_PYTHON_UNIT_TEST("py-complex" "unittest/python/test_complex.py" "unittest")
ADD_PYTHON_UNIT_TEST("py-return-by-ref" "unittest/python/test_return_by_ref.py" "unittest")
ADD_PYTHON_UNIT_TEST("py-eigen-ref" "unittest/python/test_eigen_ref.py" "unittest")
ADD_PYTHON_UNIT_TEST("py-switch" "unittest/python/test_switch.py" "python/eigenpy")
SET_TESTS_PROPERTIES("py-switch" PROPERTIES DEPENDS ${PYWRAP})
......
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2020, INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <iostream>
using namespace Eigen;
using namespace eigenpy;
template<typename MatType>
void printMatrix(const Eigen::Ref<const MatType> mat)
{
if(MatType::IsVectorAtCompileTime)
std::cout << "isVector" << std::endl;
std::cout << "size: cols " << mat.cols() << " rows " << mat.rows() << std::endl;
std::cout << mat << std::endl;
}
template<typename VecType>
void printVector(const Eigen::Ref<const VecType> & vec)
{
EIGEN_STATIC_ASSERT_VECTOR_ONLY(VecType);
printMatrix(vec);
}
template<typename MatType>
void setOnes(Eigen::Ref<MatType> mat)
{
mat.setOnes();
}
template<typename MatType>
void fill(Eigen::Ref<MatType> mat, const typename MatType::Scalar & value)
{
mat.fill(value);
}
BOOST_PYTHON_MODULE(eigen_ref)
{
namespace bp = boost::python;
eigenpy::enableEigenPy();
bp::def("printMatrix", printMatrix<Vector3d>);
bp::def("printMatrix", printMatrix<VectorXd>);
bp::def("printMatrix", printMatrix<MatrixXd>);
bp::def("printVector", printVector<VectorXd>);
bp::def("printRowVector", printVector<RowVectorXd>);
bp::def("setOnes", setOnes<Vector3d>);
bp::def("setOnes", setOnes<VectorXd>);
bp::def("setOnes", setOnes<MatrixXd>);
bp::def("fillVec3", fill<Vector3d>);
bp::def("fillVec", fill<VectorXd>);
bp::def("fill", fill<MatrixXd>);
}
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2020, INRIA
*/
#include "eigenpy/eigenpy.hpp"
......@@ -37,9 +37,7 @@ void setOnes_wrap(eigenpy::Ref<MatType> mat)
setOnes(mat);
}
BOOST_PYTHON_MODULE(ref)
BOOST_PYTHON_MODULE(eigenpy_ref)
{
namespace bp = boost::python;
eigenpy::enableEigenPy();
......
import numpy as np
from eigen_ref import *
def test(mat):
printMatrix(mat)
fill(mat,1.)
printMatrix(mat)
assert np.array_equal(mat,np.full(mat.shape,1.))
rows = 10
cols = 30
mat = np.array(np.zeros((rows,cols)))
test(mat)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment