Skip to content

Commit 0acdad6

Browse files
tylerjereddyseberg
andauthored
BUG: fancy indexing copy (numpy#26558)
* BUG: fancy indexing copy * Fixes numpygh-26542 * For these very simple advanced indexing cases, if the `result` and `self` arrays share the same data pointers, use a copy of `result` to assign values to `self`, otherwise the outcome of the fancy indexing suffers from mutation of `result` before the assignments are complete. * MAINT, BUG: PR 26558 revisions * Avoid leaking the old `tmp_arr`, based on reviewer feedback. * Add a test for a similar 2D case that fails, then hoist `solve_may_share_memory()` check farther up in the control flow such that the test passes. * Add a reviewer-requested test for index overlap. * BUG: PR 26558 revisions * The usage of `solve_may_share_memory` in the above PR wasn't quite right since it ignored the case of failing to solve the overlap problem. This has been revised according to reviewer feedback. Co-authored-by: Sebastian Berg <[email protected]> --------- Co-authored-by: Sebastian Berg <[email protected]>
1 parent 4e88577 commit 0acdad6

File tree

2 files changed

+26
-0
lines changed

2 files changed

+26
-0
lines changed

numpy/_core/src/multiarray/mapping.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,10 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
19601960
tmp_arr = (PyArrayObject *)op;
19611961
}
19621962

1963+
if (tmp_arr && solve_may_share_memory(self, tmp_arr, 1) != 0) {
1964+
Py_SETREF(tmp_arr, (PyArrayObject *)PyArray_NewCopy(tmp_arr, NPY_ANYORDER));
1965+
}
1966+
19631967
/*
19641968
* Special case for very simple 1-d fancy indexing, which however
19651969
* is quite common. This saves not only a lot of setup time in the

numpy/_core/tests/test_indexing.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,28 @@ def test_empty_fancy_index(self):
133133
b = np.array([])
134134
assert_raises(IndexError, a.__getitem__, b)
135135

136+
def test_gh_26542(self):
137+
a = np.array([0, 1, 2])
138+
idx = np.array([2, 1, 0])
139+
a[idx] = a
140+
expected = np.array([2, 1, 0])
141+
assert_equal(a, expected)
142+
143+
def test_gh_26542_2d(self):
144+
a = np.array([[0, 1, 2]])
145+
idx_row = np.zeros(3, dtype=int)
146+
idx_col = np.array([2, 1, 0])
147+
a[idx_row, idx_col] = a
148+
expected = np.array([[2, 1, 0]])
149+
assert_equal(a, expected)
150+
151+
def test_gh_26542_index_overlap(self):
152+
arr = np.arange(100)
153+
expected_vals = np.copy(arr[:-10])
154+
arr[10:] = arr[:-10]
155+
actual_vals = arr[10:]
156+
assert_equal(actual_vals, expected_vals)
157+
136158
def test_ellipsis_index(self):
137159
a = np.array([[1, 2, 3],
138160
[4, 5, 6],

0 commit comments

Comments
 (0)