Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

BUG: safer bincount casting #28355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion 9 numpy/_core/src/multiarray/compiled_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ arr_bincount(PyObject *NPY_UNUSED(self), PyObject *const *args,
npy_intp *numbers, *ians, len, mx, mn, ans_size;
npy_intp minlength = 0;
npy_intp i;
int flags;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would move this down into the if, but OK.

I think we can put this in, if we change things to a PyArray_Check below, unless I am missing something. It seems fine, even if it might not be 100% for array-likes.

I would lean towards not backporting. It has been around forever, and the reason it came up was just cupy testing against NumPy as far as I am aware.

double *weights , *dans;

NPY_PREPARE_ARGPARSER;
Expand Down Expand Up @@ -177,7 +178,13 @@ arr_bincount(PyObject *NPY_UNUSED(self), PyObject *const *args,
}

if (lst == NULL) {
lst = (PyArrayObject *)PyArray_ContiguousFromAny(list, NPY_INTP, 1, 1);
flags = NPY_ARRAY_WRITEABLE | NPY_ARRAY_ALIGNED | NPY_ARRAY_C_CONTIGUOUS;
if (PyArray_Size((PyObject *)list) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deprecation makes this pretty messy, almost wondering if we should just finalize it...

In either case, I think the PyArray_Size() here ends up as an imprecise PyArray_Check() here (as it misses an empty uint8 array for example)?

I am not quite sure that not setting force-cast in the non-array case won't finalize the deprecation (in small parts).
Since both paths use PyArray_ContiguousFromAny, I think that is fine. Although, it may be that we are not relaxing allowing uint64 for an array-like here i.e. something like:

class a:
    def __array__(self):
        return np.ones(10, dtype=np.uint64)

PyArray_ISINTEGER((PyArrayObject *)list)) {
flags = flags | NPY_ARRAY_FORCECAST;
}
seberg marked this conversation as resolved.
Show resolved Hide resolved
PyArray_Descr* local_dtype = PyArray_DescrFromType(NPY_INTP);
lst = (PyArrayObject *)PyArray_FromAny(list, local_dtype, 1, 1, flags, NULL);
if (lst == NULL) {
goto fail;
}
Expand Down
11 changes: 11 additions & 0 deletions 11 numpy/lib/tests/test_function_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2959,6 +2959,17 @@ def test_error_not_1d(self, vals):
with assert_raises(ValueError):
np.bincount(vals)

@pytest.mark.parametrize("dt", np.typecodes["AllInteger"])
def test_gh_28354(self, dt):
a = np.array([0, 1, 1, 3, 2, 1, 7], dtype=dt)
actual = np.bincount(a)
expected = [1, 3, 1, 1, 0, 0, 0, 1]
assert_array_equal(actual, expected)

def test_contiguous_handling(self):
# check for absence of hard crash
np.bincount(np.arange(10000)[::2])


class TestInterp:

Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.