Skip to content

Commit 10da260

Browse files
authored
Merge pull request #45 from jcarpent/topic/conversion
Handle conversion from Eigen::Matrix to numpy.array or numpy.matrix
2 parents 935d313 + b409c63 commit 10da260

File tree

5 files changed

+139
-15
lines changed

5 files changed

+139
-15
lines changed

benchmarks/bench-switch.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from __future__ import print_function
2+
3+
import eigenpy
4+
import numpy as np
5+
6+
import time
7+
import timeit
8+
9+
from IPython import get_ipython
10+
ipython = get_ipython()
11+
12+
quat = eigenpy.Quaternion()
13+
a = [0., 0., 0.]
14+
15+
cmd1 = "timeit np.array(a)"
16+
print("\n")
17+
print(cmd1)
18+
ipython.magic(cmd1)
19+
print("\n")
20+
21+
cmd2 = "timeit np.matrix(a)"
22+
print(cmd2)
23+
ipython.magic(cmd2)
24+
print("\n")
25+
26+
eigenpy.switchToNumpyMatrix()
27+
print("----------------------")
28+
print("switch to numpy matrix")
29+
print("----------------------")
30+
print("\n")
31+
32+
cmd3 = "timeit quat.coeffs()"
33+
print(cmd3)
34+
ipython.magic(cmd3)
35+
print("\n")
36+
37+
eigenpy.switchToNumpyArray()
38+
print("---------------------")
39+
print("switch to numpy array")
40+
print("---------------------")
41+
print("\n")
42+
43+
cmd4 = "timeit quat.coeffs()"
44+
print(cmd4)
45+
ipython.magic(cmd4)
46+
print("\n")
47+
48+
cmd5 = "timeit np.asmatrix(quat.coeffs())"
49+
print(cmd5)
50+
ipython.magic(cmd5)
51+
print("\n")
52+
53+
a_matrix = np.matrix(a);
54+
cmd6 = "timeit np.asarray(a_matrix)"
55+
print(cmd6)
56+
ipython.magic(cmd6)
57+
print("\n")

include/eigenpy/details.hpp

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,36 +54,74 @@ namespace eigenpy
5454

5555
namespace bp = boost::python;
5656

57-
struct PyMatrixType
57+
struct NumpyType
5858
{
59-
60-
static PyMatrixType & getInstance()
59+
60+
static NumpyType & getInstance()
6161
{
62-
static PyMatrixType instance;
62+
static NumpyType instance;
6363
return instance;
6464
}
6565

66-
operator bp::object () { return pyMatrixType; }
66+
operator bp::object () { return CurrentNumpyType; }
6767

6868
bp::object make(PyArrayObject* pyArray, bool copy = false)
6969
{ return make((PyObject*)pyArray,copy); }
70+
7071
bp::object make(PyObject* pyObj, bool copy = false)
7172
{
72-
bp::object m
73-
= pyMatrixType(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
73+
bp::object m;
74+
if(PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(CurrentNumpyType.ptr()),NumpyMatrixType))
75+
m = NumpyMatrixObject(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
76+
// m = NumpyAsMatrixObject(bp::object(bp::handle<>(pyObj)));
77+
else if(PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(CurrentNumpyType.ptr()),NumpyArrayType))
78+
m = bp::object(bp::handle<>(pyObj)); // nothing to do here
79+
7480
Py_INCREF(m.ptr());
7581
return m;
7682
}
83+
84+
static void setNumpyType(bp::object & obj)
85+
{
86+
PyTypeObject * obj_type = PyType_Check(obj.ptr()) ? reinterpret_cast<PyTypeObject*>(obj.ptr()) : obj.ptr()->ob_type;
87+
if(PyType_IsSubtype(obj_type,getInstance().NumpyMatrixType))
88+
getInstance().CurrentNumpyType = getInstance().NumpyMatrixObject;
89+
else if(PyType_IsSubtype(obj_type,getInstance().NumpyArrayType))
90+
getInstance().CurrentNumpyType = getInstance().NumpyArrayObject;
91+
}
92+
93+
static void switchToNumpyArray()
94+
{
95+
getInstance().CurrentNumpyType = getInstance().NumpyArrayObject;
96+
}
97+
98+
static void switchToNumpyMatrix()
99+
{
100+
getInstance().CurrentNumpyType = getInstance().NumpyMatrixObject;
101+
}
77102

78103
protected:
79-
PyMatrixType()
104+
NumpyType()
80105
{
81106
pyModule = bp::import("numpy");
82-
pyMatrixType = pyModule.attr("matrix");
107+
108+
NumpyMatrixObject = pyModule.attr("matrix");
109+
NumpyMatrixType = reinterpret_cast<PyTypeObject*>(NumpyMatrixObject.ptr());
110+
NumpyAsMatrixObject = pyModule.attr("asmatrix");
111+
NumpyAsMatrixType = reinterpret_cast<PyTypeObject*>(NumpyAsMatrixObject.ptr());
112+
NumpyArrayObject = pyModule.attr("ndarray");
113+
NumpyArrayType = reinterpret_cast<PyTypeObject*>(NumpyArrayObject.ptr());
114+
115+
CurrentNumpyType = NumpyMatrixObject; // default conversion
83116
}
84117

85-
bp::object pyMatrixType;
118+
bp::object CurrentNumpyType;
86119
bp::object pyModule;
120+
121+
// Numpy types
122+
bp::object NumpyMatrixObject; PyTypeObject * NumpyMatrixType;
123+
bp::object NumpyAsMatrixObject; PyTypeObject * NumpyAsMatrixType;
124+
bp::object NumpyArrayObject; PyTypeObject * NumpyArrayType;
87125
};
88126

89127
template<typename MatType>
@@ -174,7 +212,7 @@ namespace eigenpy
174212

175213
EigenObjectAllocator<MatType>::convert(mat,pyArray);
176214

177-
return PyMatrixType::getInstance().make(pyArray).ptr();
215+
return NumpyType::getInstance().make(pyArray).ptr();
178216
}
179217
};
180218

@@ -293,7 +331,7 @@ namespace eigenpy
293331
return obj_ptr;
294332
}
295333

296-
// Convert obj_ptr into a Eigenvec
334+
// Convert obj_ptr into an Eigen::Vector
297335
static void construct(PyObject* pyObj,
298336
bp::converter::rvalue_from_python_stage1_data* memory)
299337
{

src/eigenpy.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015-2018 LAAS-CNRS
2+
* Copyright (c) 2015-2018 LAAS-CNRS, INRIA
33
*
44
* This file is part of eigenpy.
55
* eigenpy is free software: you can redistribute it and/or
@@ -19,11 +19,21 @@
1919
namespace eigenpy
2020
{
2121

22-
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */
22+
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instances. */
2323
void enableEigenPy()
2424
{
2525
using namespace Eigen;
2626
Exception::registerException();
27+
28+
bp::def("setNumpyType",&NumpyType::setNumpyType,
29+
bp::arg("Numpy type (np.ndarray or np.matrix)"),
30+
"Change the type returned by the converters from an Eigen object.");
31+
32+
bp::def("switchToNumpyArray",&NumpyType::switchToNumpyArray,
33+
"Set the conversion from Eigen::Matrix to numpy.ndarray.");
34+
35+
bp::def("switchToNumpyMatrix",&NumpyType::switchToNumpyMatrix,
36+
"Set the conversion from Eigen::Matrix to numpy.matrix.");
2737

2838
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXd);
2939
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2d);

unittest/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2016-2018 CNRS
2+
# Copyright (c) 2016-2018 CNRS INRIA
33
#
44
# This file is part of eigenpy
55
# eigenpy is free software: you can redistribute it
@@ -46,3 +46,4 @@ ENDIF()
4646

4747
ADD_PYTHON_UNIT_TEST("py-matrix" "unittest/python/test_matrix.py" "unittest")
4848
ADD_PYTHON_UNIT_TEST("py-geometry" "unittest/python/test_geometry.py" "unittest")
49+
ADD_PYTHON_UNIT_TEST("py-switch" "unittest/python/test_switch.py" "unittest")

unittest/python/test_switch.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from __future__ import print_function
2+
3+
import eigenpy
4+
import numpy as np
5+
6+
quat = eigenpy.Quaternion()
7+
# By default, we convert as numpy.matrix
8+
coeffs_vector = quat.coeffs()
9+
print(type(coeffs_vector))
10+
11+
assert isinstance(coeffs_vector,np.matrixlib.defmatrix.matrix)
12+
13+
# Switch to numpy.array
14+
eigenpy.switchToNumpyArray()
15+
coeffs_array = quat.coeffs()
16+
print(type(coeffs_array))
17+
18+
assert isinstance(coeffs_vector,np.ndarray)

0 commit comments

Comments
 (0)