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
20 changes: 20 additions & 0 deletions include/eigenpy/details.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ namespace boost { namespace python { namespace detail {
std::size_t, value = sizeof(MatType));
};

template<class MatType>
struct referent_size<Eigen::PlainObjectBase<MatType>&>
{
BOOST_STATIC_CONSTANT(
std::size_t, value = sizeof(MatType));
};

template<class MatType>
struct referent_size<Eigen::PlainObjectBase<MatType> >
{
BOOST_STATIC_CONSTANT(
std::size_t, value = sizeof(MatType));
};

}}}

namespace eigenpy
Expand All @@ -65,7 +79,13 @@ namespace eigenpy
{
if(check_registration<MatType>()) return;

// to-python
EigenToPyConverter<MatType>::registration();
#if EIGEN_VERSION_AT_LEAST(3,2,0)
EigenToPyConverter< Eigen::Ref<MatType> >::registration();
#endif

// from-python
EigenFromPyConverter<MatType>::registration();
}

Expand Down
26 changes: 26 additions & 0 deletions include/eigenpy/eigen-from-python.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ namespace boost { namespace python { namespace converter {
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
};

/// \brief Template specialization of rvalue_from_python_data
template<typename Derived>
struct rvalue_from_python_data<Eigen::PlainObjectBase<Derived> const &>
: rvalue_from_python_data_eigen<Derived const &>
{
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
};

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> &>
Expand Down Expand Up @@ -425,6 +433,10 @@ namespace eigenpy
typedef Eigen::EigenBase<MatType> EigenBase;
EigenFromPy<EigenBase>::registration();

// Add conversion to Eigen::PlainObjectBase<MatType>
typedef Eigen::PlainObjectBase<MatType> PlainObjectBase;
EigenFromPy<PlainObjectBase>::registration();

#if EIGEN_VERSION_AT_LEAST(3,2,0)
// Add conversion to Eigen::Ref<MatType>
typedef Eigen::Ref<MatType> RefType;
Expand Down Expand Up @@ -464,6 +476,20 @@ namespace eigenpy
&EigenFromPy::construct,bp::type_id<Base>());
}
};

template<typename MatType>
struct EigenFromPy< Eigen::PlainObjectBase<MatType> > : EigenFromPy<MatType>
{
typedef EigenFromPy<MatType> EigenFromPyDerived;
typedef Eigen::PlainObjectBase<MatType> Base;

static void registration()
{
bp::converter::registry::push_back
(reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&EigenFromPy::construct,bp::type_id<Base>());
}
};

#if EIGEN_VERSION_AT_LEAST(3,2,0)

Expand Down
30 changes: 30 additions & 0 deletions include/eigenpy/eigen-to-python.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,36 @@ namespace eigenpy
}
};

template<typename MatType, int Options, typename Stride>
struct EigenToPy< Eigen::Ref<MatType,Options,Stride> >
{
static PyObject* convert(const Eigen::Ref<MatType,Options,Stride> & mat)
{
typedef Eigen::Ref<MatType,Options,Stride> EigenRef;

assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
&& "Matrix range larger than int ... should never happen." );
const npy_intp R = (npy_intp)mat.rows(), C = (npy_intp)mat.cols();

PyArrayObject* pyArray;
// Allocate Python memory
if( ( ((!(C == 1) != !(R == 1)) && !MatType::IsVectorAtCompileTime) || MatType::IsVectorAtCompileTime)
&& NumpyType::getType() == ARRAY_TYPE) // Handle array with a single dimension
{
npy_intp shape[1] = { C == 1 ? R : C };
pyArray = NumpyAllocator<EigenRef>::allocate(const_cast<EigenRef &>(mat),1,shape);
}
else
{
npy_intp shape[2] = { R,C };
pyArray = NumpyAllocator<EigenRef>::allocate(const_cast<EigenRef &>(mat),2,shape);
}

// Create an instance (either np.array or np.matrix)
return NumpyType::make(pyArray).ptr();
}
};

template<typename MatType>
struct EigenToPyConverter
{
Expand Down
61 changes: 56 additions & 5 deletions include/eigenpy/numpy-allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,41 @@ namespace eigenpy
}
else
{
return NumpyAllocator<MatType>::allocate(mat.derived(),nd,shape);
return NumpyAllocator<MatType>::allocate(mat,nd,shape);
}
}
};

#if EIGEN_VERSION_AT_LEAST(3,2,0)

template<typename MatType, int Options, typename Stride>
struct NumpyAllocator<Eigen::Ref<MatType,Options,Stride> > : NumpyAllocator<MatType &>
struct NumpyAllocator<Eigen::Ref<MatType,Options,Stride> >
{
typedef Eigen::Ref<MatType,Options,Stride> RefType;

static PyArrayObject * allocate(RefType & mat,
npy_intp nd, npy_intp * shape)
{
typedef typename RefType::Scalar Scalar;
enum { NPY_ARRAY_MEMORY_CONTIGUOUS = RefType::IsRowMajor ? NPY_ARRAY_CARRAY : NPY_ARRAY_FARRAY };

if(NumpyType::sharedMemory())
{
const int Scalar_type_code = Register::getTypeCode<Scalar>();
PyArrayObject * pyArray = (PyArrayObject*) call_PyArray_New(getPyArrayType(),
static_cast<int>(nd),
shape,
Scalar_type_code,
mat.data(),
NPY_ARRAY_MEMORY_CONTIGUOUS | NPY_ARRAY_ALIGNED);

return pyArray;
}
else
{
return NumpyAllocator<MatType>::allocate(mat,nd,shape);
}
}
};

#endif
Expand All @@ -88,23 +113,49 @@ namespace eigenpy
static_cast<int>(nd),
shape,
Scalar_type_code,
const_cast<SimilarMatrixType &>(mat.derived()).data(),
const_cast<Scalar *>(mat.data()),
NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED);

return pyArray;
}
else
{
return NumpyAllocator<MatType>::allocate(mat.derived(),nd,shape);
return NumpyAllocator<MatType>::allocate(mat,nd,shape);
}
}
};

#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 &>
struct NumpyAllocator<const Eigen::Ref<const MatType,Options,Stride> >
{
typedef const Eigen::Ref<const MatType,Options,Stride> RefType;

template<typename SimilarMatrixType>
static PyArrayObject * allocate(RefType & mat,
npy_intp nd, npy_intp * shape)
{
typedef typename SimilarMatrixType::Scalar Scalar;
enum { NPY_ARRAY_MEMORY_CONTIGUOUS_RO = SimilarMatrixType::IsRowMajor ? NPY_ARRAY_CARRAY_RO : NPY_ARRAY_FARRAY_RO };

if(NumpyType::sharedMemory())
{
const int Scalar_type_code = Register::getTypeCode<Scalar>();
PyArrayObject * pyArray = (PyArrayObject*) call_PyArray_New(getPyArrayType(),
static_cast<int>(nd),
shape,
Scalar_type_code,
const_cast<Scalar *>(mat.data()),
NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED);

return pyArray;
}
else
{
return NumpyAllocator<MatType>::allocate(mat,nd,shape);
}
}
};

#endif
Expand Down
10 changes: 10 additions & 0 deletions unittest/eigen_ref.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ void fill(Eigen::Ref<MatType> mat, const typename MatType::Scalar & value)
mat.fill(value);
}

template<typename MatType>
Eigen::Ref<MatType> asRef(const int rows, const int cols)
{
static MatType mat(rows,cols);
std::cout << "mat:\n" << mat << std::endl;
return mat;
}

BOOST_PYTHON_MODULE(eigen_ref)
{
namespace bp = boost::python;
Expand All @@ -56,4 +64,6 @@ BOOST_PYTHON_MODULE(eigen_ref)
bp::def("fillVec3", fill<Vector3d>);
bp::def("fillVec", fill<VectorXd>);
bp::def("fill", fill<MatrixXd>);

bp::def("asRef", asRef<MatrixXd>);
}
9 changes: 9 additions & 0 deletions unittest/matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ MatrixDerived base(const Eigen::MatrixBase<MatrixDerived> & m)
return m.derived();
}

template<typename MatrixDerived>
MatrixDerived plain(const Eigen::PlainObjectBase<MatrixDerived> & m)
{
return m.derived();
}

template<typename Scalar>
Eigen::Matrix<Scalar,6,6> matrix6(const Scalar & value)
{
Expand Down Expand Up @@ -123,6 +129,9 @@ BOOST_PYTHON_MODULE(matrix)

bp::def("base", base<VectorXd>);
bp::def("base", base<MatrixXd>);

bp::def("plain", plain<VectorXd>);
bp::def("plain", plain<MatrixXd>);

bp::def("matrix6", matrix6<double>);
}
10 changes: 10 additions & 0 deletions unittest/python/test_eigen_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ def test(mat):
printMatrix(mat)
assert np.array_equal(mat,np.full(mat.shape,1.))

A_ref = asRef(mat.shape[0],mat.shape[1])
A_ref.fill(1.)
A_ref2 = asRef(mat.shape[0],mat.shape[1])

assert np.array_equal(A_ref,A_ref2)

A_ref2.fill(0)
assert np.array_equal(A_ref,A_ref2)


rows = 10
cols = 30

Expand Down
4 changes: 4 additions & 0 deletions unittest/python/test_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
Mref_from_base = eigenpy.base(Mref)
assert( np.array_equal(Mref,Mref_from_base) );

# Test plain function
Mref_from_plain = eigenpy.plain(Mref)
assert( np.array_equal(Mref,Mref_from_plain) );

if verbose: print("===> Matrix 8x8")
M = Mref
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
Expand Down