Skip to content

SimpleArray should handle negative NumPy strides and Python slice semantics consistently #856

@ThreeMonth03

Description

@ThreeMonth03

SimpleArray does not consistently follow Python/NumPy slicing semantics when negative bounds, negative steps, slice offsets, or negative NumPy strides are involved. Therefore, SimpleArray only works reliably when bounds, steps, and strides are positive and the array view starts from the beginning of the underlying buffer.

Affected APIs include:

Tasks

This issues could be devided to a lot of tasks:

  • Support negetive index for SimpleArray.__getitem__.
  • Remove the usage of SimpleArray::value_type const & at(size_t it).
  • Change stride storage from small_vector<size_t> to
    small_vector<ssize_t>.
  • Change shape and indices storage from small_vector<size_t> to
    small_vector<ssize_t>.
  • Support negative strides for as_mdspan.
  • Add a local workaround for SimpleArray.setitem.
  • Verify that the related issues continue to behave correctly.

Related Issues

How to reproduce the error

$ python3 - <<'PY'
import numpy as np
import modmesh

ndarr_shape = (8, 9, 10, 11, 12)
ndarr = np.arange(np.prod(ndarr_shape), dtype='float64')
ndarr = ndarr.reshape(ndarr_shape)
expected = ndarr.copy()
sarr = modmesh.SimpleArrayFloat64(array=ndarr)

key = np.index_exp[-8:-1:2, 8:1:-2, 1:-1:3, ..., -2:-8:-2]
value_shape = expected[key].shape

value = np.empty(value_shape, dtype='float64')
next_value = 1000.0
for i0 in range(value_shape[0]):
    for i1 in range(value_shape[1]):
        for i2 in range(value_shape[2]):
            for i3 in range(value_shape[3]):
                for i4 in range(value_shape[4]):
                    value[i0, i1, i2, i3, i4] = next_value
                    next_value += 1

sarr[key] = value
expected[key] = value
np.testing.assert_array_equal(sarr.ndarray, expected)
PY
Traceback (most recent call last):
  File "<stdin>", line 23, in <module>
RuntimeError: Broadcast input array from shape(4, 4, 3, 11, 3) into shape(4, 4, 1, 11, 3)
$ python3 - <<'PY'
import numpy as np
import modmesh

ndarr_shape = (16, 18, 20, 22, 24)
ndarr = np.arange(np.prod(ndarr_shape), dtype='float64')
ndarr = ndarr.reshape(ndarr_shape)

view = ndarr[15::-2, 1::2, 19::-2, 1::2, 23::-2]
expected = np.array(view, copy=True)
sarr = modmesh.SimpleArrayFloat64(array=view)

key = np.index_exp[::-2, 1:-1:2, -8:-1:2, 10:2:-3, ...]
value_shape = expected[key].shape

value = np.empty(value_shape, dtype='float64')
next_value = 1000.0
for i0 in range(value_shape[0]):
    for i1 in range(value_shape[1]):
        for i2 in range(value_shape[2]):
            for i3 in range(value_shape[3]):
                for i4 in range(value_shape[4]):
                    value[i0, i1, i2, i3, i4] = next_value
                    next_value += 1

sarr[key] = value
expected[key] = value
np.testing.assert_array_equal(view, expected)
PY
Traceback (most recent call last):
  File "<stdin>", line 24, in <module>
RuntimeError: Broadcast input array from shape(4, 4, 4, 3, 12) into shape(18446744073709551612, 18446744073709551615, 4, 3, 12)

Metadata

Metadata

Assignees

Labels

arrayMulti-dimensional array implementation
No fields configured for Feature.

Projects

Status
In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions