Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
67bfeb19
Commit
67bfeb19
authored
Aug 04, 2016
by
Wenzel Jakob
Committed by
GitHub
Aug 04, 2016
Browse files
Merge pull request #316 from jagerman/eigen-base-types
Eigen support for special matrix objects
parents
19637536
38d5b456
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
85 additions
and
6 deletions
+85
-6
docs/advanced.rst
docs/advanced.rst
+15
-4
example/eigen.cpp
example/eigen.cpp
+16
-0
example/eigen.py
example/eigen.py
+18
-0
example/eigen.ref
example/eigen.ref
+3
-0
include/pybind11/eigen.h
include/pybind11/eigen.h
+33
-2
No files found.
docs/advanced.rst
View file @
67bfeb19
...
...
@@ -1098,7 +1098,15 @@ pybind11 will automatically and transparently convert
1. Static and dynamic Eigen dense vectors and matrices to instances of
``numpy.ndarray`` (and vice versa).
1. Eigen sparse vectors and matrices to instances of
1. Returned matrix expressions such as blocks (including columns or rows) and
diagonals will be converted to ``numpy.ndarray`` of the expression
values.
2. Returned matrix-like objects such as Eigen::DiagonalMatrix or
Eigen::SelfAdjointView will be converted to ``numpy.ndarray`` containing the
expressed value.
3. Eigen sparse vectors and matrices to instances of
``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` (and vice versa).
This makes it possible to bind most kinds of functions that rely on these types.
...
...
@@ -1107,10 +1115,13 @@ them somehow, in which case the information won't be propagated to the caller.
.. code-block:: cpp
/* The Python bindings of th
is
function won't replicate
the intended effect of modifying the function argument */
/* The Python bindings of th
ese
function
s
won't replicate
the intended effect of modifying the function argument
s
*/
void scale_by_2(Eigen::Vector3f &v) {
v *= 2;
v *= 2;
}
void scale_by_2(Eigen::Ref<Eigen::MatrixXd> &v) {
v *= 2;
}
To see why this is, refer to the section on :ref:`opaque` (although that
...
...
example/eigen.cpp
View file @
67bfeb19
...
...
@@ -66,6 +66,22 @@ void init_eigen(py::module &m) {
return
x
.
block
(
start_row
,
start_col
,
block_rows
,
block_cols
);
});
// Returns a DiagonalMatrix with diagonal (1,2,3,...)
m
.
def
(
"incr_diag"
,
[](
int
k
)
{
Eigen
::
DiagonalMatrix
<
int
,
Eigen
::
Dynamic
>
m
(
k
);
for
(
int
i
=
0
;
i
<
k
;
i
++
)
m
.
diagonal
()[
i
]
=
i
+
1
;
return
m
;
});
// Returns a SelfAdjointView referencing the lower triangle of m
m
.
def
(
"symmetric_lower"
,
[](
const
Eigen
::
MatrixXi
&
m
)
{
return
m
.
selfadjointView
<
Eigen
::
Lower
>
();
});
// Returns a SelfAdjointView referencing the lower triangle of m
m
.
def
(
"symmetric_upper"
,
[](
const
Eigen
::
MatrixXi
&
m
)
{
return
m
.
selfadjointView
<
Eigen
::
Upper
>
();
});
m
.
def
(
"fixed_r"
,
[
mat
]()
->
FixedMatrixR
{
return
FixedMatrixR
(
mat
);
});
...
...
example/eigen.py
View file @
67bfeb19
...
...
@@ -14,6 +14,7 @@ from example import double_mat_cm, double_mat_rm
from
example
import
cholesky1
,
cholesky2
,
cholesky3
,
cholesky4
,
cholesky5
,
cholesky6
from
example
import
diagonal
,
diagonal_1
,
diagonal_n
from
example
import
block
from
example
import
incr_diag
,
symmetric_upper
,
symmetric_lower
try
:
import
numpy
as
np
import
scipy
...
...
@@ -88,3 +89,20 @@ for i in range(-5, 7):
print
(
"block(2,1,3,3) %s"
%
(
"OK"
if
(
block
(
ref
,
2
,
1
,
3
,
3
)
==
ref
[
2
:
5
,
1
:
4
]).
all
()
else
"FAILED"
))
print
(
"block(1,4,4,2) %s"
%
(
"OK"
if
(
block
(
ref
,
1
,
4
,
4
,
2
)
==
ref
[
1
:,
4
:]).
all
()
else
"FAILED"
))
print
(
"block(1,4,3,2) %s"
%
(
"OK"
if
(
block
(
ref
,
1
,
4
,
3
,
2
)
==
ref
[
1
:
4
,
4
:]).
all
()
else
"FAILED"
))
print
(
"incr_diag %s"
%
(
"OK"
if
(
incr_diag
(
7
)
==
np
.
diag
([
1
,
2
,
3
,
4
,
5
,
6
,
7
])).
all
()
else
"FAILED"
))
asymm
=
np
.
array
([
[
1
,
2
,
3
,
4
],
[
5
,
6
,
7
,
8
],
[
9
,
10
,
11
,
12
],
[
13
,
14
,
15
,
16
]])
symm_lower
=
np
.
array
(
asymm
)
symm_upper
=
np
.
array
(
asymm
)
for
i
in
range
(
4
):
for
j
in
range
(
i
+
1
,
4
):
symm_lower
[
i
,
j
]
=
symm_lower
[
j
,
i
]
symm_upper
[
j
,
i
]
=
symm_upper
[
i
,
j
]
print
(
"symmetric_lower %s"
%
(
"OK"
if
(
symmetric_lower
(
asymm
)
==
symm_lower
).
all
()
else
"FAILED"
))
print
(
"symmetric_upper %s"
%
(
"OK"
if
(
symmetric_upper
(
asymm
)
==
symm_upper
).
all
()
else
"FAILED"
))
example/eigen.ref
View file @
67bfeb19
...
...
@@ -50,3 +50,6 @@ diagonal_n(6) OK
block(2,1,3,3) OK
block(1,4,4,2) OK
block(1,4,3,2) OK
incr_diag OK
symmetric_lower OK
symmetric_upper OK
include/pybind11/eigen.h
View file @
67bfeb19
...
...
@@ -61,6 +61,19 @@ public:
static
constexpr
bool
value
=
decltype
(
test
(
std
::
declval
<
T
>
()))
::
value
;
};
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
// SelfAdjointView fall into this category.
template
<
typename
T
>
class
is_eigen_base
{
private:
template
<
typename
Derived
>
static
std
::
true_type
test
(
const
Eigen
::
EigenBase
<
Derived
>
&
);
static
std
::
false_type
test
(...);
public:
static
constexpr
bool
value
=
!
is_eigen_dense
<
T
>::
value
&&
!
is_eigen_sparse
<
T
>::
value
&&
decltype
(
test
(
std
::
declval
<
T
>
()))
::
value
;
};
template
<
typename
Type
>
struct
type_caster
<
Type
,
typename
std
::
enable_if
<
is_eigen_dense
<
Type
>::
value
&&
!
is_eigen_ref
<
Type
>::
value
>::
type
>
{
typedef
typename
Type
::
Scalar
Scalar
;
...
...
@@ -164,11 +177,10 @@ protected:
template
<
typename
Type
>
struct
type_caster
<
Type
,
typename
std
::
enable_if
<
is_eigen_dense
<
Type
>::
value
&&
is_eigen_ref
<
Type
>::
value
>::
type
>
{
pr
ivate
:
pr
otected
:
using
Derived
=
typename
std
::
remove_const
<
typename
is_eigen_ref
<
Type
>::
Derived
>::
type
;
using
DerivedCaster
=
type_caster
<
Derived
>
;
DerivedCaster
derived_caster
;
protected:
std
::
unique_ptr
<
Type
>
value
;
public:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
derived_caster
.
load
(
src
,
convert
))
{
value
.
reset
(
new
Type
(
derived_caster
.
operator
Derived
&
()));
return
true
;
}
return
false
;
}
...
...
@@ -182,6 +194,25 @@ public:
template
<
typename
_T
>
using
cast_op_type
=
pybind11
::
detail
::
cast_op_type
<
_T
>
;
};
// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can
// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that.
template
<
typename
Type
>
struct
type_caster
<
Type
,
typename
std
::
enable_if
<
is_eigen_base
<
Type
>::
value
&&
!
is_eigen_ref
<
Type
>::
value
>::
type
>
{
protected:
using
Matrix
=
Eigen
::
Matrix
<
typename
Type
::
Scalar
,
Eigen
::
Dynamic
,
Eigen
::
Dynamic
>
;
using
MatrixCaster
=
type_caster
<
Matrix
>
;
public:
[[
noreturn
]]
bool
load
(
handle
,
bool
)
{
pybind11_fail
(
"Unable to load() into specialized EigenBase object"
);
}
static
handle
cast
(
const
Type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
MatrixCaster
::
cast
(
Matrix
(
src
),
policy
,
parent
);
}
static
handle
cast
(
const
Type
*
src
,
return_value_policy
policy
,
handle
parent
)
{
return
MatrixCaster
::
cast
(
Matrix
(
*
src
),
policy
,
parent
);
}
static
PYBIND11_DESCR
name
()
{
return
MatrixCaster
::
name
();
}
[[
noreturn
]]
operator
Type
*
()
{
pybind11_fail
(
"Loading not supported for specialized EigenBase object"
);
}
[[
noreturn
]]
operator
Type
&
()
{
pybind11_fail
(
"Loading not supported for specialized EigenBase object"
);
}
template
<
typename
_T
>
using
cast_op_type
=
pybind11
::
detail
::
cast_op_type
<
_T
>
;
};
template
<
typename
Type
>
struct
type_caster
<
Type
,
typename
std
::
enable_if
<
is_eigen_sparse
<
Type
>::
value
>::
type
>
{
typedef
typename
Type
::
Scalar
Scalar
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment