Browse Source

added conversion helpers between numpy/scipy and eigen types

Former-commit-id: 34503e8b7ec7e5301e259414eca31d35ccc5b76d
Daniele Panozzo 9 years ago
parent
commit
8bcef21ea7
4 changed files with 125 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 48 0
      python/001_BasicTypes.py
  3. 48 0
      python/iglhelpers.py
  4. 28 0
      python/py_vector.cpp

+ 1 - 0
.gitignore

@@ -83,3 +83,4 @@ python/.ipynb_checkpoints
 py_doc.cpp
 py_doc.h
 python/py_igl/todo
+python/__pycache__

+ 48 - 0
python/001_BasicTypes.py

@@ -0,0 +1,48 @@
+from iglhelpers import *
+
+############# Dense Matrix Types #############
+
+# Create a numpy dense array
+# 2 types are supported by the wrappers: float64 and int64
+dense_matrix = np.array( [ (1,2,3), (4,5,6) , (7,8,9) ], dtype='float64')
+
+# libigl wrappers uses Eigen as a matrix type, you can easily convert between numpy and Eigen using
+# the helper function p2e. This operation duplicates the data.
+dense_matrix_eigen = p2e(dense_matrix)
+
+# The Eigen wrappers allows you to do operations directly on this matrix,
+# without having to convert back to numpy
+dense_matrix_eigen_2 = dense_matrix_eigen * dense_matrix_eigen
+
+# You can also inspect the data without converting it ...
+print("Eigen Matrix: \n", dense_matrix_eigen_2, "\n", sep='')
+
+# and access single elements
+print("Eigen Matrix(0,0): ", dense_matrix_eigen_2[0,0], "\n")
+
+# To convert it back to a numpy array, use the helper function e2p
+dense_matrix_2 = e2p(dense_matrix_eigen_2)
+print("Numpy Array: \n", dense_matrix_2, "\n", sep='')
+
+############# Sparse Matrix Types #############
+
+# Sparse matrices are handled in a very similar way
+# 2 types are supported by the wrappers: float64 and int64
+sparse_matrix = sparse.rand(10, 10, 0.1)
+
+# To convert to the eigen forma use p2e
+sparse_matrix_eigen = p2e(sparse_matrix)
+
+# They can directly be used plotted or used in computations
+print("Sparse matrix Eigen: ", sparse_matrix_eigen, sep='')
+
+# And converted back with e2p
+sparse_matrix_2 = e2p(sparse_matrix_eigen)
+print("Sparse matrix Numpy: ", sparse_matrix_2.todense(), sep='')
+
+
+
+
+
+
+

+ 48 - 0
python/iglhelpers.py

@@ -0,0 +1,48 @@
+import numpy as np
+import scipy.sparse as sparse
+import igl
+
+def p2e(m):
+    if isinstance(m, np.ndarray):
+        if m.dtype.type == np.int64:
+            return igl.eigen.MatrixXi(m)
+        elif m.dtype.type == np.float64:
+            return igl.eigen.MatrixXd(m)
+        raise TypeError("p2e only support dtype float64 or int64")
+    if sparse.issparse(m):
+        # convert in a dense matrix with triples
+        coo = m.tocoo()
+        triplets = np.vstack((coo.row, coo.col, coo.data)).T
+
+        triples_eigen_wrapper = igl.eigen.MatrixXd(triplets)
+
+        if m.dtype.type == np.int64:
+            t = igl.eigen.SparseMatrixi()
+            t.fromcoo(triples_eigen_wrapper)
+            return t
+        elif m.dtype.type == np.float64:
+            t = igl.eigen.SparseMatrixd()
+            t.fromCOO(triples_eigen_wrapper)
+            return t
+
+
+    raise TypeError("p2e only support numpy.array or scipy.sparse")
+
+
+def e2p(m):
+    if isinstance(m, igl.eigen.MatrixXd):
+        return np.array(m, dtype='float64')
+    elif isinstance(m, igl.eigen.MatrixXi):
+        return np.array(m, dtype='int64')
+    elif isinstance(m, igl.eigen.SparseMatrixd):
+        coo = np.array(m.toCOO())
+        I = coo[:, 0]
+        J = coo[:, 1]
+        V = coo[:, 2]
+        return sparse.coo_matrix((V,(I,J)), shape=(m.rows(),m.cols()), dtype='float64')
+    elif isinstance(m, igl.eigen.SparseMatrixi):
+        coo = np.array(m.toCOO())
+        I = coo[:, 0]
+        J = coo[:, 1]
+        V = coo[:, 2]
+        return sparse.coo_matrix((V,(I,J)), shape=(m.rows(),m.cols()), dtype='int64')

+ 28 - 0
python/py_vector.cpp

@@ -505,6 +505,34 @@ py::class_<Type> bind_eigen_sparse_2(py::module &m, const char *name,
         // .def_static("Ones", [](size_t n, size_t m) { return Type(Type::Ones(n, m)); })
         // .def_static("Constant", [](size_t n, size_t m, Scalar value) { return Type(Type::Constant(n, m, value)); })
         // .def_static("Identity", [](size_t n, size_t m) { return Type(Type::Identity(n, m)); })
+        .def("toCOO",[](const Type& m)
+        {
+          Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> t(m.nonZeros(),3);
+          int count = 0;
+          for (int k=0; k<m.outerSize(); ++k)
+            for (typename Type::InnerIterator it(m,k); it; ++it)
+              t.row(count++) << it.row(), it.col(), it.value();
+          return t;
+        })
+
+        .def("fromCOO",[](Type& m, const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>& t, int rows, int cols)
+        {
+          typedef Eigen::Triplet<Scalar> T;
+          std::vector<T> tripletList;
+          tripletList.reserve(t.rows());
+          for(unsigned i=0;i<t.rows();++i)
+            tripletList.push_back(T(round(t(i,0)),round(t(i,1)),t(i,2)));
+
+          if (rows == -1)
+            rows = t.col(0).maxCoeff()+1;
+
+          if (cols == -1)
+            cols = t.col(1).maxCoeff()+1;
+
+          m.resize(rows,cols);
+          m.setFromTriplets(tripletList.begin(), tripletList.end());
+        }, py::arg("t"), py::arg("rows") = -1, py::arg("cols") = -1)
+
         ;
     return matrix;
 }