-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
BUG: Allow any integer type in bincount (fixes #823) #4366
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
Conversation
This is a simpler, slower alternative to the type specific functions I had implemented in #4330. Since solving this issue is orthogonal to whether an |
wouldn't it be simpler to just try to cast the not-intp array to NPY_UINTP then get the maximum and if it fits cast back to intp? Probably also faster than the function pointer compare loop. actually you could probably save the cast if the rest of the code works on npy_uintp as documented and you just create a npy_uintp view of the npy_intp array after the minimum check |
On a 32 bit system A potentially faster alternative without multiple functions for different types is to try to create a |
maybe its better to add type specific functions, even on 64 bit you might not want to cast your large int16 array to 64 bit integers |
I may have gotten a little carried away there, but type specific functions were frowned upon by @charris in #4330, which is what prompted this more flexible, less efficient approach here, as a test of a simplified approach for #4330. I think he was concerned that the additional complexity did not justify making faster a function whose speed nobody is complaining about. Hence this approach that leaves the original path unchanged, and provides a slower alternative path for what used not to work. I am happy to rewrite it either way, or in some middle ground approach, but need your guidance as to what approach best fits NumPy. |
I'd say just chunk the conversions. |
Chunking would probably be a good idea for any integer type bigger than uint16 anyway. Not sure of the best chunk size though, maybe 64K. |
By "chunking" you mean something similar to what |
I was thinking that you could not specify the npy_intp type to begin with, then convert the resulting array to npy_intp in chunks. But there is a problem with the minmax function as it only works with npy_intp. You could call the max/min methods of the array, however. That would probably be slower, especially for small arrays. What you have now doesn't bother me that much, but as Julian says, it does waste space. But no more than it did. |
If you find a cool solution for this, put it into the indexing machinery ;). It currently just casts to |
That's a nasty shortcut you are taking there! ;-)
As you say, probably the proper solution would be to have a set of int-to-int conversion functions that checked for inboundness, and that had a return value that could be used to signal overflows in the conversion. I think I have followed the path of how casting works all the way to here, so duplicating some of those for ints. That's definitely more bite than I can swallow with my current knowledge of the code base, so I won't even dream of attempting it. Quite frankly, if something so ubiquitous as indexing can live with this behavior, the hack in this PR is unwarranted: until an elegant solution is devised for that, perhaps the best solution for this particular bug (which is everywhere, see #4384) is to follow the leader and do as indexing does, i.e. something equivalent to On a 64 bit system, the worse that could happen is that you get an error for a negative number if the values are too large, and we can always change the error to "incorrect values in array" to not mislead the user:
On 32 bit systems you can have messier bugs creeping in:
Which is not good, you should have gotten a "Maximum allowed dimension exceeded", but it's wrong in a way consistent with indexing... |
It is kinda impressive that nobody ever noticed and bothered to open an issue about it ;). But I didn't feel like specializing a load of inner loops for this, and the old code did a forced cast too... One advantage indexing has over bincount is that you can't even fathom the idea of indexing with such a large integer ;). |
True, true. My 64 bit machine only uses 48 bits for memory addressing. That's what, 32 terabytes or so? I've been robbed. |
Actually We (that would be me) make |
|
We just ran into this (kind of) problem : dipy/dipy#789 - not bincount, but repeat. |
|
||
min = (const void *)PyArray_DATA(arr_cmp2); | ||
max = min + stride; | ||
while (size--) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it me, or is there no iteration happening here?
return 0; | ||
} | ||
else if (cmp(a, max, arr) > 0) { | ||
PyErr_SetString(PyExc_ValueError, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these errors would make more sense emitted by the caller
@jaimefrio this PR has been stale for a while, do you still want to continue working on this PR ? |
I'm going to close this, it is stalled and needs rebase. @jaimefrio Please make a new PR if you want to pursue this. |
Gives array-likes that cannot be cast to np.intp a second chance, by
comparing its entries one by one to NPY_INTP_MAX and forcing the cast if
none exceeds it. Fixes #823.