Skip to content

Commit 77211df

Browse files
Merge pull request #16 from EricCousineau-TRI/issue/drake_8620
eigen: Fix dtype=object shape conversion for 1D NumPy arrays for Eigen matrices
2 parents 1151a8a + 97647e0 commit 77211df

File tree

3 files changed

+33
-3
lines changed

3 files changed

+33
-3
lines changed

include/pybind11/eigen.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ template <typename props> handle eigen_array_cast(typename props::Type const &sr
223223
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
224224
array a;
225225
using Scalar = typename props::Type::Scalar;
226-
bool is_pyoject = static_cast<pybind11::detail::npy_api::constants>(npy_format_descriptor<Scalar>::value) == npy_api::NPY_OBJECT_;
226+
bool is_pyobject = static_cast<pybind11::detail::npy_api::constants>(npy_format_descriptor<Scalar>::value) == npy_api::NPY_OBJECT_;
227227

228-
if (!is_pyoject) {
228+
if (!is_pyobject) {
229229
if (props::vector)
230230
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
231231
else
@@ -336,7 +336,7 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
336336
if (dims == 1) {
337337
if (Type::RowsAtCompileTime == Eigen::Dynamic)
338338
value.resize(buf.shape(0), 1);
339-
if (Type::ColsAtCompileTime == Eigen::Dynamic)
339+
else if (Type::ColsAtCompileTime == Eigen::Dynamic)
340340
value.resize(1, buf.shape(0));
341341

342342
for (ssize_t i = 0; i < buf.shape(0); ++i) {

tests/test_eigen.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
2424
typedef Eigen::AutoDiffScalar<Eigen::VectorXd> ADScalar;
25+
26+
template <typename Scalar>
27+
using MatrixX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
28+
2529
typedef Eigen::Matrix<ADScalar, Eigen::Dynamic, 1> VectorXADScalar;
2630
typedef Eigen::Matrix<ADScalar, 1, Eigen::Dynamic> VectorXADScalarR;
2731
PYBIND11_NUMPY_OBJECT_DTYPE(ADScalar);
@@ -336,6 +340,20 @@ TEST_SUBMODULE(eigen, m) {
336340
m.def("iss1105_col_obj", [](VectorXADScalar) { return true; });
337341
m.def("iss1105_row_obj", [](VectorXADScalarR) { return true; });
338342

343+
// Test the shape of a matrix via `type_caster`s.
344+
m.def("cpp_matrix_shape", [](const MatrixX<double>& A) {
345+
return py::make_tuple(A.rows(), A.cols());
346+
});
347+
m.def("cpp_matrix_shape", [](const MatrixX<ADScalar>& A) {
348+
return py::make_tuple(A.rows(), A.cols());
349+
});
350+
// TODO(eric.cousineau): Unless `dtype=ADScalar` (user-defined) and not
351+
// `dtype=object`, we should kill any usages of `Eigen::Ref<>` or any
352+
// const-references.
353+
m.def("cpp_matrix_shape_ref", [](const Eigen::Ref<MatrixX<ADScalar>>& A) {
354+
return py::make_tuple(A.rows(), A.cols());
355+
});
356+
339357
// test_named_arguments
340358
// Make sure named arguments are working properly:
341359
m.def("matrix_multiply", [](const py::EigenDRef<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B)

tests/test_eigen.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,18 @@ def test_eigen_passing_adscalar():
204204
assert "incompatible function arguments" in str(excinfo)
205205

206206

207+
def test_eigen_obj_shape():
208+
# Ensure that matrices are of the same shape for dtype=object when given a 1D NumPy array.
209+
# RobotLocomotion/drake#8620
210+
x_f = np.array([1, -1], dtype=float)
211+
shape_f = m.cpp_matrix_shape(x_f)
212+
x_ad = np.array([m.AutoDiffXd(0, []), m.AutoDiffXd(0, [])], dtype=object)
213+
shape_ad = m.cpp_matrix_shape(x_ad)
214+
shape_ad_ref = m.cpp_matrix_shape_ref(x_ad)
215+
assert shape_f == shape_ad
216+
assert shape_f == shape_ad_ref
217+
218+
207219
def test_negative_stride_from_python(msg):
208220
"""Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
209221
copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an

0 commit comments

Comments
 (0)