diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp index 58ed6ad06..dadfe458e 100644 --- a/include/eigenpy/details.hpp +++ b/include/eigenpy/details.hpp @@ -49,6 +49,20 @@ namespace boost { namespace python { namespace detail { std::size_t, value = sizeof(MatType)); }; + template + struct referent_size&> + { + BOOST_STATIC_CONSTANT( + std::size_t, value = sizeof(MatType)); + }; + + template + struct referent_size > + { + BOOST_STATIC_CONSTANT( + std::size_t, value = sizeof(MatType)); + }; + }}} namespace eigenpy @@ -65,7 +79,13 @@ namespace eigenpy { if(check_registration()) return; + // to-python EigenToPyConverter::registration(); +#if EIGEN_VERSION_AT_LEAST(3,2,0) + EigenToPyConverter< Eigen::Ref >::registration(); +#endif + + // from-python EigenFromPyConverter::registration(); } diff --git a/include/eigenpy/eigen-from-python.hpp b/include/eigenpy/eigen-from-python.hpp index 83beda216..1a55bcbab 100644 --- a/include/eigenpy/eigen-from-python.hpp +++ b/include/eigenpy/eigen-from-python.hpp @@ -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 + struct rvalue_from_python_data const &> + : rvalue_from_python_data_eigen + { + EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &) + }; + template struct rvalue_from_python_data &> : rvalue_from_python_storage &> @@ -425,6 +433,10 @@ namespace eigenpy typedef Eigen::EigenBase EigenBase; EigenFromPy::registration(); + // Add conversion to Eigen::PlainObjectBase + typedef Eigen::PlainObjectBase PlainObjectBase; + EigenFromPy::registration(); + #if EIGEN_VERSION_AT_LEAST(3,2,0) // Add conversion to Eigen::Ref typedef Eigen::Ref RefType; @@ -464,6 +476,20 @@ namespace eigenpy &EigenFromPy::construct,bp::type_id()); } }; + + template + struct EigenFromPy< Eigen::PlainObjectBase > : EigenFromPy + { + typedef EigenFromPy EigenFromPyDerived; + typedef Eigen::PlainObjectBase Base; + + static void registration() + { + bp::converter::registry::push_back + (reinterpret_cast(&EigenFromPy::convertible), + &EigenFromPy::construct,bp::type_id()); + } + }; #if EIGEN_VERSION_AT_LEAST(3,2,0) diff --git a/include/eigenpy/eigen-to-python.hpp b/include/eigenpy/eigen-to-python.hpp index fac253712..bd89fec52 100644 --- a/include/eigenpy/eigen-to-python.hpp +++ b/include/eigenpy/eigen-to-python.hpp @@ -82,6 +82,36 @@ namespace eigenpy } }; + template + struct EigenToPy< Eigen::Ref > + { + static PyObject* convert(const Eigen::Ref & mat) + { + typedef Eigen::Ref EigenRef; + + assert( (mat.rows()::allocate(const_cast(mat),1,shape); + } + else + { + npy_intp shape[2] = { R,C }; + pyArray = NumpyAllocator::allocate(const_cast(mat),2,shape); + } + + // Create an instance (either np.array or np.matrix) + return NumpyType::make(pyArray).ptr(); + } + }; + template struct EigenToPyConverter { diff --git a/include/eigenpy/numpy-allocator.hpp b/include/eigenpy/numpy-allocator.hpp index a627c8abb..9cbeb8a04 100644 --- a/include/eigenpy/numpy-allocator.hpp +++ b/include/eigenpy/numpy-allocator.hpp @@ -57,7 +57,7 @@ namespace eigenpy } else { - return NumpyAllocator::allocate(mat.derived(),nd,shape); + return NumpyAllocator::allocate(mat,nd,shape); } } }; @@ -65,8 +65,33 @@ namespace eigenpy #if EIGEN_VERSION_AT_LEAST(3,2,0) template - struct NumpyAllocator > : NumpyAllocator + struct NumpyAllocator > { + typedef Eigen::Ref 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(); + PyArrayObject * pyArray = (PyArrayObject*) call_PyArray_New(getPyArrayType(), + static_cast(nd), + shape, + Scalar_type_code, + mat.data(), + NPY_ARRAY_MEMORY_CONTIGUOUS | NPY_ARRAY_ALIGNED); + + return pyArray; + } + else + { + return NumpyAllocator::allocate(mat,nd,shape); + } + } }; #endif @@ -88,14 +113,14 @@ namespace eigenpy static_cast(nd), shape, Scalar_type_code, - const_cast(mat.derived()).data(), + const_cast(mat.data()), NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED); return pyArray; } else { - return NumpyAllocator::allocate(mat.derived(),nd,shape); + return NumpyAllocator::allocate(mat,nd,shape); } } }; @@ -103,8 +128,34 @@ namespace eigenpy #if EIGEN_VERSION_AT_LEAST(3,2,0) template - struct NumpyAllocator > : NumpyAllocator + struct NumpyAllocator > { + typedef const Eigen::Ref RefType; + + template + 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(); + PyArrayObject * pyArray = (PyArrayObject*) call_PyArray_New(getPyArrayType(), + static_cast(nd), + shape, + Scalar_type_code, + const_cast(mat.data()), + NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED); + + return pyArray; + } + else + { + return NumpyAllocator::allocate(mat,nd,shape); + } + } }; #endif diff --git a/unittest/eigen_ref.cpp b/unittest/eigen_ref.cpp index 1e58cfee4..267f4a006 100644 --- a/unittest/eigen_ref.cpp +++ b/unittest/eigen_ref.cpp @@ -37,6 +37,14 @@ void fill(Eigen::Ref mat, const typename MatType::Scalar & value) mat.fill(value); } +template +Eigen::Ref 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; @@ -56,4 +64,6 @@ BOOST_PYTHON_MODULE(eigen_ref) bp::def("fillVec3", fill); bp::def("fillVec", fill); bp::def("fill", fill); + + bp::def("asRef", asRef); } diff --git a/unittest/matrix.cpp b/unittest/matrix.cpp index ce8a1c191..fd4ebae04 100644 --- a/unittest/matrix.cpp +++ b/unittest/matrix.cpp @@ -81,6 +81,12 @@ MatrixDerived base(const Eigen::MatrixBase & m) return m.derived(); } +template +MatrixDerived plain(const Eigen::PlainObjectBase & m) +{ + return m.derived(); +} + template Eigen::Matrix matrix6(const Scalar & value) { @@ -123,6 +129,9 @@ BOOST_PYTHON_MODULE(matrix) bp::def("base", base); bp::def("base", base); + + bp::def("plain", plain); + bp::def("plain", plain); bp::def("matrix6", matrix6); } diff --git a/unittest/python/test_eigen_ref.py b/unittest/python/test_eigen_ref.py index fe8cd29e3..76721a3f2 100644 --- a/unittest/python/test_eigen_ref.py +++ b/unittest/python/test_eigen_ref.py @@ -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 diff --git a/unittest/python/test_matrix.py b/unittest/python/test_matrix.py index 5734eb92a..1b1ea6e73 100644 --- a/unittest/python/test_matrix.py +++ b/unittest/python/test_matrix.py @@ -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)) );