Skip to content

Commit

Permalink
Fix arrays with zero-size dimensions
Browse files Browse the repository at this point in the history
When converting an array to an Eigen matrix, ignore the strides if any
dimension size is 0. If the array is empty, the strides aren't relevant,
and especially numpy ≥ 1.23 explicitly sets the strides to 0 in this
case. (See numpy commit dd5ab7b11520.)

Update tests to verify that this works, and continues to work. (This
test likely would have caught the behavior change with numpy 1.23.) This
expands on the tests added by #38, but also reverts the logic change
from that PR, as it is no longer needed, and brings the code closer in
line with upstream, since #38 was never pushed upstream.
  • Loading branch information
mwoehlke-kitware committed Jun 29, 2022
1 parent 5df3c00 commit 8051585
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 7 deletions.
20 changes: 13 additions & 7 deletions include/pybind11/eigen.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,19 @@ template <bool EigenRowMajor> struct EigenConformable {

template <typename props> bool stride_compatible() const {
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
// matching strides, or a dimension size of 1 (in which case the stride value is irrelevant)
return
!negativestrides &&
(props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
(EigenRowMajor ? cols : rows) <= 1) &&
(props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
(EigenRowMajor ? rows : cols) <= 1);
// matching strides, or a dimension size of 1 (in which case the stride value is
// irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
// (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
if (negativestrides) {
return false;
}
if (rows == 0 || cols == 0) {
return true;
}
return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|| (EigenRowMajor ? cols : rows) == 1)
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|| (EigenRowMajor ? rows : cols) == 1);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator bool() const { return conformable; }
Expand Down
2 changes: 2 additions & 0 deletions tests/test_eigen.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,8 @@ def test_issue738_issue2038():
)

assert np.all(m.iss738_f1(np.zeros((0, 2))) == np.zeros((0, 2)))
assert np.all(m.iss738_f1(np.zeros((2, 0))) == np.zeros((2, 0)))
assert np.all(m.iss738_f2(np.zeros((0, 2))) == np.zeros((0, 2)))
assert np.all(m.iss738_f2(np.zeros((2, 0))) == np.zeros((2, 0)))


Expand Down

0 comments on commit 8051585

Please sign in to comment.