diff --git a/README.md b/README.md index 96eca4786bc4756cc16bd428bd775c19e65f29ad..44a1e2dbdb24f20a15142c6efa27a459771ed2b4 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,17 @@ EigenPy — Efficient Python bindings between Numpy/Eigen <a href="https://github.com/psf/black"><img src="https://img.shields.io/badge/code%20style-black-000000.svg" alt="Code style: black"></a> </p> -**EigenPy** is an open source framework which allows to bind the famous [Eigen](http://eigen.tuxfamily.org) C++ library in Python. +**EigenPy** is an open source framework which allows to bind the famous [Eigen](http://eigen.tuxfamily.org) C++ library in Python via Boost.Python. **EigenPy** provides: - full memory sharing between Numpy and Eigen avoiding memory allocation - full support Eigen::Ref avoiding memory allocation + - full support of the Eigen::Tensor module - exposition of the Geometry module of Eigen for easy code prototyping - standard matrix decomposion routines of Eigen such as the Cholesky decomposition, SVD decomposition, QR decomposition, and etc. - full support of SWIG objects + - full support of runtime declaration of Numpy scalar types + - extended API to expose std::vector types ## Setup @@ -26,9 +29,10 @@ The installation of **EigenPy** on your computer is made easy for Linux/BSD, Mac ### The Conda approach You simply need this simple line: -``` +```bash conda install eigenpy -c conda-forge ``` + ### Ubuntu You can easily install **EigenPy** from binairies. @@ -43,18 +47,14 @@ sudo sh -c "echo 'deb [arch=amd64] http://robotpkg.openrobots.org/packages/debia curl http://robotpkg.openrobots.org/packages/debian/robotpkg.key | sudo apt-key add - ``` 3. You need to run at least once apt update to fetch the package descriptions: -``` +```bash sudo apt-get update ``` + #### Install EigenPy 4. The installation of **EigenPy** and its dependencies is made through the line: -For Python 2.7 -``` -sudo apt install robotpkg-py27-eigenpy -``` -or for Python 3.{5,6,7} -``` +```bash sudo apt install robotpkg-py35-eigenpy ``` where 35 should be replaced by the python 3 you want to work this (e.g. `robotpkg-py36-eigenpy` to work with Python 3.6). @@ -81,6 +81,7 @@ The following people have been involved in the development of **EigenPy**: - [Wolfgang Merkt](http://www.wolfgangmerkt.com/) (University of Edinburgh): ROS integration and support - [Sean Yen](https://www.linkedin.com/in/seanyentw) (Microsoft): Windows integration - [Loïc Estève](https://github.com/lesteve) (INRIA): Conda integration +- [Wilson Jallet](https://manifoldfr.github.io/) (INRIA/LAAS-CNRS): core developer If you have taken part to the development of **EigenPy**, feel free to add your name and contribution here. diff --git a/benchmarks/bench-switch.py b/benchmarks/bench-switch.py index 19e1ec75fe2af09590c838b2ee14ef0034e4f7b8..38a8dc2b5ac6cda6beb75578e561cc4035a786cb 100644 --- a/benchmarks/bench-switch.py +++ b/benchmarks/bench-switch.py @@ -24,23 +24,6 @@ print(cmd2) ipython.magic(cmd2) print("\n") -eigenpy.switchToNumpyMatrix() -print("----------------------") -print("switch to numpy matrix") -print("----------------------") -print("\n") - -cmd3 = "timeit quat.coeffs()" -print(cmd3) -ipython.magic(cmd3) -print("\n") - -eigenpy.switchToNumpyArray() -print("---------------------") -print("switch to numpy array") -print("---------------------") -print("\n") - cmd4 = "timeit quat.coeffs()" print(cmd4) ipython.magic(cmd4) diff --git a/include/eigenpy/eigen-to-python.hpp b/include/eigenpy/eigen-to-python.hpp index d7084ddf232cc70a494264672af4a3fc66aef8f1..2b5e039bcba0f9e203b36c53e5aa197270ab72ec 100644 --- a/include/eigenpy/eigen-to-python.hpp +++ b/include/eigenpy/eigen-to-python.hpp @@ -101,9 +101,8 @@ struct eigen_to_py_impl_matrix { PyArrayObject* pyArray; // Allocate Python memory if ((((!(C == 1) != !(R == 1)) && !MatrixDerived::IsVectorAtCompileTime) || - MatrixDerived::IsVectorAtCompileTime) && - NumpyType::getType() == - ARRAY_TYPE) // Handle array with a single dimension + MatrixDerived::IsVectorAtCompileTime)) // Handle array with a single + // dimension { npy_intp shape[1] = {C == 1 ? R : C}; pyArray = NumpyAllocator<MatType>::allocate( diff --git a/include/eigenpy/numpy-type.hpp b/include/eigenpy/numpy-type.hpp index 96086854f0d4eaea39bf10081aae597661aa054f..816390b47a400aa133784b26450d12fbefc46c38 100644 --- a/include/eigenpy/numpy-type.hpp +++ b/include/eigenpy/numpy-type.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 INRIA + * Copyright 2018-2023 INRIA */ #ifndef __eigenpy_numpy_type_hpp__ @@ -45,54 +45,30 @@ bool np_type_is_convertible_into_scalar(const int np_type) { } } -enum NP_TYPE { MATRIX_TYPE, ARRAY_TYPE }; - struct EIGENPY_DLLAPI NumpyType { static NumpyType& getInstance(); - operator bp::object() { return getInstance().CurrentNumpyType; } - static bp::object make(PyArrayObject* pyArray, bool copy = false); static bp::object make(PyObject* pyObj, bool copy = false); - static void setNumpyType(bp::object& obj); - static void sharedMemory(const bool value); static bool sharedMemory(); - static void switchToNumpyArray(); - - static void switchToNumpyMatrix(); - - static NP_TYPE& getType(); - static bp::object getNumpyType(); - static const PyTypeObject* getNumpyMatrixType(); - static const PyTypeObject* getNumpyArrayType(); - static bool isMatrix(); - - static bool isArray(); - protected: NumpyType(); - bp::object CurrentNumpyType; bp::object pyModule; // Numpy types - bp::object NumpyMatrixObject; - PyTypeObject* NumpyMatrixType; - // bp::object NumpyAsMatrixObject; PyTypeObject * NumpyAsMatrixType; bp::object NumpyArrayObject; PyTypeObject* NumpyArrayType; - NP_TYPE np_type; - bool shared_memory; }; } // namespace eigenpy diff --git a/src/eigenpy.cpp b/src/eigenpy.cpp index 8e5b1a37a040bf892a22a79357eb6a8652522710..62b9f88c8b5302476dc2f54613ddf663d0b3c885 100644 --- a/src/eigenpy.cpp +++ b/src/eigenpy.cpp @@ -1,6 +1,6 @@ /* * Copyright 2014-2019, CNRS - * Copyright 2018-2021, INRIA + * Copyright 2018-2023, INRIA */ #include "eigenpy/eigenpy.hpp" @@ -30,20 +30,6 @@ void enableEigenPy() { Exception::registerException(); - bp::def( - "setNumpyType", &NumpyType::setNumpyType, bp::arg("numpy_type"), - "Change the Numpy type returned by the converters from an Eigen object."); - - bp::def( - "getNumpyType", &NumpyType::getNumpyType, - "Get the Numpy type returned by the converters from an Eigen object."); - - bp::def("switchToNumpyArray", &NumpyType::switchToNumpyArray, - "Set the conversion from Eigen::Matrix to numpy.ndarray."); - - bp::def("switchToNumpyMatrix", &NumpyType::switchToNumpyMatrix, - "Set the conversion from Eigen::Matrix to numpy.matrix."); - bp::def("sharedMemory", (void (*)(const bool))NumpyType::sharedMemory, bp::arg("value"), "Share the memory when converting from Eigen to Numpy."); diff --git a/src/numpy-type.cpp b/src/numpy-type.cpp index 148319b84492e633cff1f89b7b1f7733e511337e..92411b2d69844e61d75a729b15d7147a46b724e5 100644 --- a/src/numpy-type.cpp +++ b/src/numpy-type.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 INRIA + * Copyright 2018-2023 INRIA */ #include "eigenpy/numpy-type.hpp" @@ -17,70 +17,24 @@ bp::object NumpyType::make(PyArrayObject* pyArray, bool copy) { return make((PyObject*)pyArray, copy); } -bp::object NumpyType::make(PyObject* pyObj, bool copy) { +bp::object NumpyType::make(PyObject* pyObj, bool /*copy*/) { bp::object m; - if (isMatrix()) - m = getInstance().NumpyMatrixObject(bp::object(bp::handle<>(pyObj)), - bp::object(), copy); - // m = NumpyAsMatrixObject(bp::object(bp::handle<>(pyObj))); - else if (isArray()) - m = bp::object(bp::handle<>(pyObj)); // nothing to do here + m = bp::object(bp::handle<>(pyObj)); // nothing to do here Py_INCREF(m.ptr()); return m; } -void NumpyType::setNumpyType(bp::object& obj) { - PyTypeObject* obj_type = PyType_Check(obj.ptr()) - ? reinterpret_cast<PyTypeObject*>(obj.ptr()) - : obj.ptr()->ob_type; - if (PyType_IsSubtype(obj_type, getInstance().NumpyMatrixType)) - switchToNumpyMatrix(); - else if (PyType_IsSubtype(obj_type, getInstance().NumpyArrayType)) - switchToNumpyArray(); -} - void NumpyType::sharedMemory(const bool value) { getInstance().shared_memory = value; } bool NumpyType::sharedMemory() { return getInstance().shared_memory; } -void NumpyType::switchToNumpyArray() { - getInstance().CurrentNumpyType = getInstance().NumpyArrayObject; - getInstance().getType() = ARRAY_TYPE; -} - -void NumpyType::switchToNumpyMatrix() { - getInstance().CurrentNumpyType = getInstance().NumpyMatrixObject; - getInstance().getType() = MATRIX_TYPE; -} - -NP_TYPE& NumpyType::getType() { return getInstance().np_type; } - -bp::object NumpyType::getNumpyType() { return getInstance().CurrentNumpyType; } - -const PyTypeObject* NumpyType::getNumpyMatrixType() { - return getInstance().NumpyMatrixType; -} - const PyTypeObject* NumpyType::getNumpyArrayType() { return getInstance().NumpyArrayType; } -bool NumpyType::isMatrix() { - return PyType_IsSubtype( - reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()), - getInstance().NumpyMatrixType); -} - -bool NumpyType::isArray() { - if (getInstance().isMatrix()) return false; - return PyType_IsSubtype( - reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()), - getInstance().NumpyArrayType); -} - NumpyType::NumpyType() { pyModule = bp::import("numpy"); @@ -90,16 +44,8 @@ NumpyType::NumpyType() { Py_INCREF(pyModule.ptr()); #endif - NumpyMatrixObject = pyModule.attr("matrix"); - NumpyMatrixType = reinterpret_cast<PyTypeObject*>(NumpyMatrixObject.ptr()); NumpyArrayObject = pyModule.attr("ndarray"); NumpyArrayType = reinterpret_cast<PyTypeObject*>(NumpyArrayObject.ptr()); - // NumpyAsMatrixObject = pyModule.attr("asmatrix"); - // NumpyAsMatrixType = - // reinterpret_cast<PyTypeObject*>(NumpyAsMatrixObject.ptr()); - - CurrentNumpyType = NumpyArrayObject; // default conversion - np_type = ARRAY_TYPE; shared_memory = true; } diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index c2643a29660831a07ae4a14055ffc108cb102457..8ad0fc573921e0f7a80b71415f0a92539fc5c8eb 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -80,10 +80,6 @@ if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT) "unittest") endif() -add_python_unit_test("py-switch" "unittest/python/test_switch.py" - "python;unittest") -set_tests_properties("py-switch" PROPERTIES DEPENDS ${PYWRAP}) - add_python_unit_test("py-dimensions" "unittest/python/test_dimensions.py" "python;unittest") set_tests_properties("py-dimensions" PROPERTIES DEPENDS ${PYWRAP}) diff --git a/unittest/alpha/bnpy.cpp b/unittest/alpha/bnpy.cpp deleted file mode 100644 index 9f4e3ea9b9def7b6a9d2f6c2de04cc08924eafd7..0000000000000000000000000000000000000000 --- a/unittest/alpha/bnpy.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* Simple test using the boost::numpy interface: return an array and a matrix. - */ - -#include "boost/numpy.hpp" -#include "eigenpy/fwd.hpp" - -namespace bp = boost::python; -namespace bn = boost::numpy; - -/* Return an dim-1 array with 5 elements. */ -bn::ndarray array() { - std::vector<double> v(5); - v[0] = 56; - Py_intptr_t shape[1] = {v.size()}; - bn::ndarray result = bn::zeros(1, shape, bn::dtype::get_builtin<double>()); - std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data())); - return result; -} - -/* Return a dim-1 matrix with five elements. */ -boost::python::object matrix() { - std::vector<double> v(5); - v[0] = 56; - Py_intptr_t shape[1] = {v.size()}; - bn::matrix t(bn::zeros(1, shape, bn::dtype::get_builtin<double>())); - std::copy(v.begin(), v.end(), reinterpret_cast<double*>(t.get_data())); - - return t; -} - -BOOST_PYTHON_MODULE(libbnpy) { - bn::initialize(); - bp::def("array", array); - bp::def("matrix", matrix); -} diff --git a/unittest/alpha/eigen.cpp b/unittest/alpha/eigen.cpp deleted file mode 100644 index 0e856f7249541edd038bb66e0924c0cf823ae46f..0000000000000000000000000000000000000000 --- a/unittest/alpha/eigen.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include <boost/numpy.hpp> - -#include "eigenpy/fwd.hpp" - -namespace boopy { -namespace bpn = boost::numpy; -namespace bp = boost::python; - -struct Eigenvec_to_python_matrix { - static PyObject* convert(Eigen::VectorXd const& v) { - Py_intptr_t shape[1] = {v.size()}; - bpn::matrix result(bpn::zeros(1, shape, bpn::dtype::get_builtin<double>())); - std::copy(v.data(), v.data() + v.size(), - reinterpret_cast<double*>(result.get_data())); - return bp::incref(result.ptr()); - } -}; - -struct Eigenvec_from_python_array { - Eigenvec_from_python_array() { - bp::converter::registry ::push_back(&convertible, &construct, - bp::type_id<Eigen::VectorXd>()); - } - - // Determine if obj_ptr can be converted in a Eigenvec - static void* convertible(PyObject* obj_ptr) { - try { - bp::object obj(bp::handle<>(bp::borrowed(obj_ptr))); - std::auto_ptr<bpn::ndarray> array(new bpn::ndarray(bpn::from_object( - obj, bpn::dtype::get_builtin<double>(), bpn::ndarray::V_CONTIGUOUS))); - - if ((array->get_nd() == 1) || - ((array->get_nd() == 2) && (array->get_shape()[1] == 1))) - return array.release(); - else - return 0; - } catch (bp::error_already_set& err) { - bp::handle_exception(); - return 0; - } - } - - // Convert obj_ptr into a Eigenvec - static void construct(PyObject*, - bp::converter::rvalue_from_python_stage1_data* memory) { - // Recover the pointer created in <convertible> - std::auto_ptr<bpn::ndarray> array( - reinterpret_cast<bpn::ndarray*>(memory->convertible)); - const int nrow = array->get_shape()[0]; - std::cout << "nrow = " << nrow << std::endl; - - // Get the memory where to create the vector - void* storage = - ((bp::converter::rvalue_from_python_storage<Eigen::VectorXd>*)memory) - ->storage.bytes; - - // Create the vector - Eigen::VectorXd& res = *new (storage) Eigen::VectorXd(nrow); - - // Copy the data - double* data = (double*)array->get_data(); - for (int i = 0; i < nrow; ++i) res[i] = data[i]; - - // Stash the memory chunk pointer for later use by boost.python - memory->convertible = storage; - } -}; -} // namespace boopy - -Eigen::VectorXd test() { - Eigen::VectorXd v = Eigen::VectorXd::Random(5); - std::cout << v.transpose() << std::endl; - return v; -} - -void test2(Eigen::VectorXd v) { - std::cout << "test2: dim = " << v.size() << " ||| v[0] = " << v[0] - << std::endl; -} - -BOOST_PYTHON_MODULE(libeigen) { - namespace bpn = boost::numpy; - namespace bp = boost::python; - - bpn::initialize(); - bp::to_python_converter<Eigen::VectorXd, boopy::Eigenvec_to_python_matrix>(); - boopy::Eigenvec_from_python_array(); - - bp::def("test", test); - bp::def("test2", test2); -} diff --git a/unittest/alpha/eigenc.cpp b/unittest/alpha/eigenc.cpp deleted file mode 100644 index ad4fdf261a16f85572aa02158b846ed788ebbead..0000000000000000000000000000000000000000 --- a/unittest/alpha/eigenc.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include <numpy/arrayobject.h> - -#include "eigenpy/fwd.hpp" - -namespace boopy { -namespace bp = boost::python; - -template <typename SCALAR> -struct NumpyEquivalentType {}; -template <> -struct NumpyEquivalentType<double> { - enum { type_code = NPY_DOUBLE }; -}; -template <> -struct NumpyEquivalentType<int> { - enum { type_code = NPY_INT }; -}; -template <> -struct NumpyEquivalentType<float> { - enum { type_code = NPY_FLOAT }; -}; - -struct EigenMatrix_to_python_matrix { - static PyObject* convert(Eigen::MatrixXd const& mat) { - typedef Eigen::MatrixXd::Scalar T; - - npy_intp shape[2] = {mat.rows(), mat.cols()}; - PyArrayObject* pyArray = (PyArrayObject*)PyArray_SimpleNew( - 2, shape, NumpyEquivalentType<T>::type_code); - - T* pyData = (T*)PyArray_DATA(pyArray); - for (int i = 0; i < mat.rows(); ++i) - for (int j = 0; j < mat.cols(); ++j) - pyData[i * mat.cols() + j] = mat(i, j); - - return ((PyObject*)pyArray); - } -}; - -struct EigenMatrix_from_python_array { - EigenMatrix_from_python_array() { - bp::converter::registry ::push_back(&convertible, &construct, - bp::type_id<Eigen::MatrixXd>()); - } - - // Determine if obj_ptr can be converted in a Eigenvec - static void* convertible(PyObject* obj_ptr) { - typedef Eigen::MatrixXd::Scalar T; - - if (!PyArray_Check(obj_ptr)) { - return 0; - } - if (PyArray_NDIM(obj_ptr) > 2) { - return 0; - } - if (PyArray_ObjectType(obj_ptr, 0) != NumpyEquivalentType<T>::type_code) { - return 0; - } - int flags = PyArray_FLAGS(obj_ptr); - if (!(flags & NPY_C_CONTIGUOUS)) { - return 0; - } - if (!(flags & NPY_ALIGNED)) { - return 0; - } - - return obj_ptr; - } - - // Convert obj_ptr into a Eigenvec - static void construct(PyObject* pyObj, - bp::converter::rvalue_from_python_stage1_data* memory) { - typedef Eigen::MatrixXd::Scalar T; - using namespace Eigen; - - PyArrayObject* pyArray = reinterpret_cast<PyArrayObject*>(pyObj); - int ndims = PyArray_NDIM(pyArray); - assert(ndims == 2); - - int dtype_size = (PyArray_DESCR(pyArray))->elsize; - int s1 = PyArray_STRIDE(pyArray, 0); - assert(s1 % dtype_size == 0); - - int R = MatrixXd::RowsAtCompileTime; - int C = MatrixXd::ColsAtCompileTime; - if (R == Eigen::Dynamic) - R = PyArray_DIMS(pyArray)[0]; - else - assert(PyArray_DIMS(pyArray)[0] == R); - - if (C == Eigen::Dynamic) - C = PyArray_DIMS(pyArray)[1]; - else - assert(PyArray_DIMS(pyArray)[1] == C); - - T* pyData = reinterpret_cast<T*>(PyArray_DATA(pyArray)); - - void* storage = - ((bp::converter::rvalue_from_python_storage<MatrixXd>*)(memory)) - ->storage.bytes; - MatrixXd& mat = *new (storage) MatrixXd(R, C); - for (int i = 0; i < R; ++i) - for (int j = 0; j < C; ++j) mat(i, j) = pyData[i * C + j]; - - memory->convertible = storage; - } -}; - -} // namespace boopy - -Eigen::MatrixXd test() { - Eigen::MatrixXd mat = Eigen::MatrixXd::Random(5, 5); - std::cout << "EigenMAt = " << mat << std::endl; - return mat; -} - -void test2(Eigen::MatrixXd mat) { - std::cout << "test2: dim = " << mat.rows() << " ||| m[0,0] = " << mat(0, 0) - << std::endl; -} - -BOOST_PYTHON_MODULE(libeigenc) { - import_array(); - namespace bp = boost::python; - bp::to_python_converter<Eigen::MatrixXd, - boopy::EigenMatrix_to_python_matrix>(); - boopy::EigenMatrix_from_python_array(); - - bp::def("test", test); - bp::def("test2", test2); -} diff --git a/unittest/alpha/eigentemplate.cpp b/unittest/alpha/eigentemplate.cpp deleted file mode 100644 index 408e3d5c1c4929fec8d63dc3625c81260487ad14..0000000000000000000000000000000000000000 --- a/unittest/alpha/eigentemplate.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include <numpy/arrayobject.h> - -#include "eigenpy/fwd.hpp" - -namespace boopy { -namespace bp = boost::python; - -template <typename SCALAR> -struct NumpyEquivalentType {}; -template <> -struct NumpyEquivalentType<double> { - enum { type_code = NPY_DOUBLE }; -}; -template <> -struct NumpyEquivalentType<int> { - enum { type_code = NPY_INT }; -}; -template <> -struct NumpyEquivalentType<float> { - enum { type_code = NPY_FLOAT }; -}; - -/* --- TO PYTHON -------------------------------------------------------------- - */ -template <typename MatType> -struct EigenMatrix_to_python_matrix { - static PyObject* convert(MatType const& mat) { - typedef typename MatType::Scalar T; - const int R = mat.rows(), C = mat.cols(); - - npy_intp shape[2] = {R, C}; - PyArrayObject* pyArray = (PyArrayObject*)PyArray_SimpleNew( - 2, shape, NumpyEquivalentType<T>::type_code); - - T* pyData = (T*)PyArray_DATA(pyArray); - Eigen::Map< - Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > - pyMatrix(pyData, R, C); - pyMatrix = mat; - - return (PyObject*)pyArray; - } -}; - -/* --- FROM PYTHON ------------------------------------------------------------ - */ -template <typename MatType> -struct EigenMatrix_from_python_array { - EigenMatrix_from_python_array() { - bp::converter::registry ::push_back(&convertible, &construct, - bp::type_id<MatType>()); - } - - // Determine if obj_ptr can be converted in a Eigenvec - static void* convertible(PyObject* obj_ptr) { - typedef typename MatType::Scalar T; - - if (!PyArray_Check(obj_ptr)) return 0; - - std::cout << "Until here ok. ndim = " << PyArray_NDIM(obj_ptr) - << " isvec " << MatType::IsVectorAtCompileTime << std::endl; - if (PyArray_NDIM(obj_ptr) != 2) - if ((PyArray_NDIM(obj_ptr) != 1) || (!MatType::IsVectorAtCompileTime)) - return 0; - std::cout << "Until here ok." << std::endl; - - if (PyArray_ObjectType(obj_ptr, 0) != NumpyEquivalentType<T>::type_code) - return 0; - - if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED)) { - std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; - return 0; - } - - return obj_ptr; - } - - // Convert obj_ptr into a Eigenvec - static void construct(PyObject* pyObj, - bp::converter::rvalue_from_python_stage1_data* memory) { - typedef typename MatType::Scalar T; - using namespace Eigen; - - std::cout << "Until here ok. Constructing..." << std::endl; - PyArrayObject* pyArray = reinterpret_cast<PyArrayObject*>(pyObj); - - if (PyArray_NDIM(pyArray) == 2) { - int R = MatType::RowsAtCompileTime; - int C = MatType::ColsAtCompileTime; - if (R == Eigen::Dynamic) - R = PyArray_DIMS(pyArray)[0]; - else - assert(PyArray_DIMS(pyArray)[0] == R); - - if (C == Eigen::Dynamic) - C = PyArray_DIMS(pyArray)[1]; - else - assert(PyArray_DIMS(pyArray)[1] == C); - - T* pyData = reinterpret_cast<T*>(PyArray_DATA(pyArray)); - - int itemsize = PyArray_ITEMSIZE(pyArray); - int stride1 = PyArray_STRIDE(pyArray, 0) / itemsize; - int stride2 = PyArray_STRIDE(pyArray, 1) / itemsize; - std::cout << "STRIDE = " << stride1 << " x " << stride2 << std::endl; - Eigen::Map<MatType, 0, Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> > - pyMap( - pyData, R, C, - Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>(stride2, stride1)); - std::cout << "Map = " << pyMap << std::endl; - - void* storage = - ((bp::converter::rvalue_from_python_storage<MatType>*)(memory)) - ->storage.bytes; - MatType& mat = *new (storage) MatType(R, C); - mat = pyMap; - - memory->convertible = storage; - } else { - int R = MatType::MaxSizeAtCompileTime, C = 1; - if (R == Eigen::Dynamic) - R = PyArray_DIMS(pyArray)[0]; - else - assert(PyArray_DIMS(pyArray)[0] == R); - - T* pyData = reinterpret_cast<T*>(PyArray_DATA(pyArray)); - - int itemsize = PyArray_ITEMSIZE(pyArray); - int stride = PyArray_STRIDE(pyArray, 0) / itemsize; - Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> s(stride, 0); - Eigen::Map<MatType, 0, Eigen::InnerStride<Eigen::Dynamic> > pyMap( - pyData, R, 1, Eigen::InnerStride<Eigen::Dynamic>(stride)); - std::cout << "Map = " << pyMap << std::endl; - - void* storage = - ((bp::converter::rvalue_from_python_storage<MatType>*)(memory)) - ->storage.bytes; - MatType& mat = *new (storage) MatType(R, C); - mat = pyMap; - - memory->convertible = storage; - } - } -}; - -} // namespace boopy - -Eigen::MatrixXd test() { - Eigen::MatrixXd mat = Eigen::MatrixXd::Random(3, 6); - std::cout << "EigenMAt = " << mat << std::endl; - return mat; -} -Eigen::VectorXd testVec() { - Eigen::VectorXd mat = Eigen::VectorXd::Random(6); - std::cout << "EigenVec = " << mat << std::endl; - return mat; -} - -void test2(Eigen::MatrixXd mat) { - std::cout << "Test2 mat = " << mat << std::endl; -} -void test2Vec(Eigen::VectorXd v) { - std::cout << "Test2 vec = " << v << std::endl; -} - -BOOST_PYTHON_MODULE(libeigentemplate) { - import_array(); - namespace bp = boost::python; - bp::to_python_converter< - Eigen::MatrixXd, boopy::EigenMatrix_to_python_matrix<Eigen::MatrixXd> >(); - boopy::EigenMatrix_from_python_array<Eigen::MatrixXd>(); - - bp::to_python_converter< - Eigen::VectorXd, boopy::EigenMatrix_to_python_matrix<Eigen::VectorXd> >(); - boopy::EigenMatrix_from_python_array<Eigen::VectorXd>(); - - bp::def("test", test); - bp::def("testVec", testVec); - bp::def("test2", test2); - bp::def("test2Vec", test2Vec); -} diff --git a/unittest/alpha/mystring.cpp b/unittest/alpha/mystring.cpp deleted file mode 100644 index 843e553cf567ceff72be881bbf1763180464faf6..0000000000000000000000000000000000000000 --- a/unittest/alpha/mystring.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* Tutorial with boost::python. Using the converter to access a home-made - * string class and bind it to the python strings. */ - -#include <boost/python/def.hpp> -#include <boost/python/module.hpp> -#include <boost/python/to_python_converter.hpp> - -namespace homemadestring { - -/* This is the home-made string class. */ -class custom_string { - public: - custom_string() {} - custom_string(std::string const& value) : value_(value) {} - std::string const& value() const { return value_; } - - private: - std::string value_; -}; - -/* Two simple functions with this class */ -custom_string hello() { return custom_string("Hello world."); } -std::size_t size(custom_string const& s) { return s.value().size(); } - -/* From c to python converter */ -struct custom_string_to_python_str { - static PyObject* convert(custom_string const& s) { - return boost::python::incref(boost::python::object(s.value()).ptr()); - } -}; - -struct custom_string_from_python_str { - custom_string_from_python_str() { - boost::python::converter::registry ::push_back( - &convertible, &construct, boost::python::type_id<custom_string>()); - } - - static void* convertible(PyObject* obj_ptr) { - if (!PyString_Check(obj_ptr)) return 0; - return obj_ptr; - } - - static void construct( - PyObject* obj_ptr, - boost::python::converter::rvalue_from_python_stage1_data* data) { - const char* value = PyString_AsString(obj_ptr); - if (value == 0) boost::python::throw_error_already_set(); - void* storage = - ((boost::python::converter::rvalue_from_python_storage<custom_string>*) - data) - ->storage.bytes; - new (storage) custom_string(value); - data->convertible = storage; - } -}; - -void init_module() { - using namespace boost::python; - - boost::python::to_python_converter<custom_string, - custom_string_to_python_str>(); - custom_string_from_python_str(); - - def("hello", hello); - def("size", size); -} - -} // namespace homemadestring - -BOOST_PYTHON_MODULE(libmystring) { homemadestring::init_module(); } diff --git a/unittest/alpha/simple.cpp b/unittest/alpha/simple.cpp deleted file mode 100644 index 02c21aa7854da36a5ae50b5bc95102f38b434d63..0000000000000000000000000000000000000000 --- a/unittest/alpha/simple.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* Simple test with boost::python. - * Declare and bind three function, returning char*, string, and Eigen::Vector. - * The last function raises and error at runtime due to inadequate binding. - */ - -#include <string> - -#include "eigenpy/fwd.hpp" - -char const* testchar() { return "Yay char!"; } - -std::string teststr() { return "Yay str!"; } - -Eigen::VectorXd testeigenvec() { - Eigen::VectorXd v(555); - return v; -} - -BOOST_PYTHON_MODULE(libsimple) { - using namespace boost::python; - def("char", testchar); - def("str", teststr); - def("eigenvec", testeigenvec); -} diff --git a/unittest/python/test_complex.py b/unittest/python/test_complex.py index cbe8032b078a6c1099614e8c03e06d59091c10f6..a7043582ec40c489fdbb7118f76629c1fe18909f 100644 --- a/unittest/python/test_complex.py +++ b/unittest/python/test_complex.py @@ -1,9 +1,7 @@ from __future__ import print_function import numpy as np -from complex import switchToNumpyArray, real, imag, ascomplex - -switchToNumpyArray() +from complex import real, imag, ascomplex rows = 10 cols = 20 diff --git a/unittest/python/test_dimensions.py b/unittest/python/test_dimensions.py index 97312dcc93c9917c5f1fabf41dde18ea9806a346..4bfa38d0862f557df6e182a5ee68b4760b114e28 100644 --- a/unittest/python/test_dimensions.py +++ b/unittest/python/test_dimensions.py @@ -3,12 +3,7 @@ from __future__ import print_function import eigenpy quat = eigenpy.Quaternion() -# By default, we convert as numpy.matrix -eigenpy.switchToNumpyMatrix() -coeffs_vector = quat.coeffs() -assert len(coeffs_vector.shape) == 2 # Switch to numpy.array -eigenpy.switchToNumpyArray() coeffs_vector = quat.coeffs() assert len(coeffs_vector.shape) == 1 diff --git a/unittest/python/test_eigen_solver.py b/unittest/python/test_eigen_solver.py index af3a95ab02a4348b0accbd7611a1e983db88e780..ad0c2fdfebc5e43d3a19d0a802fc17acb4f8abc3 100644 --- a/unittest/python/test_eigen_solver.py +++ b/unittest/python/test_eigen_solver.py @@ -1,8 +1,6 @@ import numpy as np import eigenpy -eigenpy.switchToNumpyArray() - dim = 100 A = np.random.rand(dim, dim) diff --git a/unittest/python/test_self_adjoint_eigen_solver.py b/unittest/python/test_self_adjoint_eigen_solver.py index 7e5ff1b86598640da530548c8cc053bf198abb5c..a76666337784bc9449146d6b5f6bb6039d0ed476 100644 --- a/unittest/python/test_self_adjoint_eigen_solver.py +++ b/unittest/python/test_self_adjoint_eigen_solver.py @@ -2,8 +2,6 @@ import eigenpy import numpy as np -eigenpy.switchToNumpyArray() - dim = 100 A = np.random.rand(dim, dim) A = (A + A.T) * 0.5 diff --git a/unittest/python/test_switch.py b/unittest/python/test_switch.py deleted file mode 100644 index a5d8a97b68d285a5a69d69022d7e2af4ec1e5f88..0000000000000000000000000000000000000000 --- a/unittest/python/test_switch.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import print_function - -import eigenpy -import numpy as np - -eigenpy.switchToNumpyMatrix() -quat = eigenpy.Quaternion() -# By default, we convert as numpy.matrix -coeffs_vector = quat.coeffs() -print(type(coeffs_vector)) - -assert isinstance(coeffs_vector, np.matrixlib.defmatrix.matrix) -assert eigenpy.getNumpyType() == np.matrix - -# Switch to numpy.array -eigenpy.switchToNumpyArray() -coeffs_array = quat.coeffs() -print(type(coeffs_array)) - -assert isinstance(coeffs_vector, np.ndarray) -assert eigenpy.getNumpyType() == np.ndarray