From cae5ff227016a576cede8f70688a6a1fb0e42625 Mon Sep 17 00:00:00 2001
From: Mansard <nmansard@laas.fr>
Date: Fri, 11 Jul 2014 13:22:11 +0200
Subject: [PATCH] IVIGIT.

---
 CMakeLists.txt                       |   8 ++
 python/{unittest.py => test_unit.py} |  20 ++++
 src/eigenc.cpp                       | 132 ++++++++++++++++++++++++
 src/eigentemplate.cpp                | 144 +++++++++++++++++++++++++++
 src/simple.cpp                       |   2 +-
 5 files changed, 305 insertions(+), 1 deletion(-)
 rename python/{unittest.py => test_unit.py} (60%)
 create mode 100644 src/eigenc.cpp
 create mode 100644 src/eigentemplate.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7e3c24c..e99613ef 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,9 @@ IF(NOT BOOST_NUMPY_DIR)
 ENDIF()
 
 FIND_PACKAGE(Boost 1.45.0)
+
 IF(Boost_FOUND)
+
   INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}" "/usr/include/python2.7" "/usr/include/eigen3" "Boost.NumPy")
   LINK_DIRECTORIES(${BOOST_NUMPY_DIR})
 
@@ -29,6 +31,12 @@ IF(Boost_FOUND)
   ADD_LIBRARY(eigen SHARED src/eigen.cpp)
   TARGET_LINK_LIBRARIES(eigen ${Boost_LIBRARIES} libboost_numpy.so)
 
+  ADD_LIBRARY(eigenc SHARED src/eigenc.cpp)
+  TARGET_LINK_LIBRARIES(eigenc ${Boost_LIBRARIES})
+
+  ADD_LIBRARY(eigentemplate SHARED src/eigentemplate.cpp)
+  TARGET_LINK_LIBRARIES(eigentemplate ${Boost_LIBRARIES})
+
 ELSEIF(NOT Boost_FOUND)
   MESSAGE(FATAL_ERROR "Unable to find correct Boost version. Did you set BOOST_ROOT?")
 ENDIF()
diff --git a/python/unittest.py b/python/test_unit.py
similarity index 60%
rename from python/unittest.py
rename to python/test_unit.py
index c27daac8..143c8e71 100644
--- a/python/unittest.py
+++ b/python/test_unit.py
@@ -2,6 +2,7 @@
 
 import numpy as np
 
+'''
 import libsimple
 
 print libsimple.char()
@@ -28,6 +29,25 @@ print "matrix ===> "
 libeigen.test2(a)
 print "array ===> "
 libeigen.test2(b)
+'''
+
+import libeigentemplate
+print "===> From C++ to Py"
+print libeigentemplate.test()
+print "===> From Vec C++ to Py"
+print libeigentemplate.testVec()
+print "===> From Py to C++"
+a = np.random.random([5,5])
+for i in range(5):
+    for j in range(5):
+        a[i,j] = i*5+j
+#a = np.random.random([
+print a
+libeigentemplate.test2(a)
+print "===> From Py::slice to C++"
+b=a[1:5,1:3]
+print b
+libeigentemplate.test2(b)
 
 
 
diff --git a/src/eigenc.cpp b/src/eigenc.cpp
new file mode 100644
index 00000000..73620e64
--- /dev/null
+++ b/src/eigenc.cpp
@@ -0,0 +1,132 @@
+#include <Eigen/Core>
+#include <boost/python.hpp>
+#include <numpy/arrayobject.h>
+
+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;
+    }
+  };
+
+
+}
+
+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/src/eigentemplate.cpp b/src/eigentemplate.cpp
new file mode 100644
index 00000000..76072b29
--- /dev/null
+++ b/src/eigentemplate.cpp
@@ -0,0 +1,144 @@
+#include <Eigen/Core>
+#include <boost/python.hpp>
+#include <numpy/arrayobject.h>
+
+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 ------------------------------------------------------------ */
+  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 MatType;
+      typedef MatType::Scalar T;
+
+      if (!PyArray_Check(obj_ptr)) return 0;
+
+      if (PyArray_NDIM(obj_ptr) != 2)
+	if ( (PyArray_NDIM(obj_ptr) !=1) || (MatType::IsVectorAtCompileTime) )
+	  return 0;
+
+      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 Eigen::MatrixXd MatType;
+      typedef MatType::Scalar T;
+      using namespace Eigen;
+
+      PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
+      int ndims = PyArray_NDIM(pyArray);
+      assert(ndims == 2); // TODO: handle vectors
+
+      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;
+
+      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;
+    }
+  };
+
+
+}
+
+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 << mat << 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> >();
+  bp::to_python_converter<Eigen::VectorXd,
+			  boopy::EigenMatrix_to_python_matrix<Eigen::VectorXd> >();
+  boopy::EigenMatrix_from_python_array();
+
+  bp::def("test", test);
+  bp::def("testVec", testVec);
+  bp::def("test2", test2);
+}
diff --git a/src/simple.cpp b/src/simple.cpp
index 85b631a3..558e77b9 100644
--- a/src/simple.cpp
+++ b/src/simple.cpp
@@ -20,7 +20,7 @@ std::string teststr()
 
 Eigen::VectorXd testeigenvec()
 {
-  Eigen::VectorXd v(5);
+  Eigen::VectorXd v(555);
   return v;
 }
 
-- 
GitLab