Skip to content

Commit 855a133

Browse files
Fix arrays with zero-size dimensions
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.)
1 parent 374a5b0 commit 855a133

File tree

3 files changed

+17
-3
lines changed

3 files changed

+17
-3
lines changed

include/pybind11/eigen.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ struct EigenConformable {
111111
bool stride_compatible() const {
112112
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
113113
// matching strides, or a dimension size of 1 (in which case the stride value is
114-
// irrelevant)
114+
// irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
115+
// (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
116+
if (rows == 0 || cols == 0)
117+
return !negativestrides;
115118
return !negativestrides
116119
&& (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
117120
|| (EigenRowMajor ? cols : rows) == 1)

tests/test_eigen.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,13 @@ TEST_SUBMODULE(eigen, m) {
345345
},
346346
py::arg{}.noconvert());
347347

348-
// test_issue738
349-
// Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an
348+
// test_issue738, test_zero_length
349+
// Issue #738: 1×N or N×1 2D matrices were neither accepted nor properly copied with an
350350
// incompatible stride value on the length-1 dimension--but that should be allowed (without
351351
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
352+
// Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since
353+
// they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to
354+
// 0 if any dimension size is 0.
352355
m.def("iss738_f1",
353356
&adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
354357
py::arg{}.noconvert());

tests/test_eigen.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,14 @@ def test_issue738():
744744
)
745745

746746

747+
def test_zero_length():
748+
"""Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)"""
749+
assert np.all(m.iss738_f1(np.zeros((0, 2))) == np.zeros((0, 2)))
750+
assert np.all(m.iss738_f1(np.zeros((2, 0))) == np.zeros((2, 0)))
751+
assert np.all(m.iss738_f2(np.zeros((0, 2))) == np.zeros((0, 2)))
752+
assert np.all(m.iss738_f2(np.zeros((2, 0))) == np.zeros((2, 0)))
753+
754+
747755
def test_issue1105():
748756
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
749757
compile-time row vectors or column vector"""

0 commit comments

Comments
 (0)