Repository navigation
ENH: Add the Array Iterator API to Cython - #24691
Conversation
5456312 to
47b2dd5
Compare
|
@seberg Any idea how I can resolve the error: EDIT: Had to make the |
47b2dd5 to
5e80aac
Compare
5d0328d to
052aab7
Compare
You must not do that, we need that struct to remain private. You cannot wrap |
|
I guess there may be a way to write it in this way, but maybe a good start wouold also be to not try to implement an |
Ah I see, I will make the change and just specify the signatures instead of implementing the |
|
@seberg your suggestion was implemented in |
| int NpyIter_Deallocate(NpyIter* it) | ||
| int NpyIter_Reset(NpyIter* it, char** errmsg) nogil | ||
| int NpyIter_ResetToIterIndexRange(NpyIter* it, npy_intp istart, | ||
| npy_intp iend, char** errmsg) nogil |
There was a problem hiding this comment.
Thanks, just a quick comment, since you are iterating.
I would be tempted to not add nogil as itis only correct when errmsg is passed, and I frankly find it a bit awkward.
(I am not sure it is actually important API for an unused threading usecase, or more of a try to allow use without GIL but without a concrete use-case)
My main question is how much you checked the correct except ... statements. Pretty use NpyIter_Dealloc needs an except 0, so I think there may be a few more. Also clearly creating a new one needs except NULL. (in other words, we need to carefully review those)
There was a problem hiding this comment.
Just addressed the above comment in e5c2883 (#24691) by removing the nogil and replacing it with except? NPY_FAIL. I also checked the implementation of of the functions listed and added appropriate except ... where needed. Please give another look when you can.
|
@seberg , I've been meaning to ask how would one be able to retrieve the numerical values of operands during iteration through the |
I don't understand. You need to cast them to the correct type to perform the operation of course (but the stride |
Ah, I see the issue I had was that I did not use the parenthesis around the cast pointer, which led to unexpected behaviour. Thanks. BTW, I was able to prototype the use of this API here |
seberg
left a comment
There was a problem hiding this comment.
Thanks, a few comments. I think all of those ? are unnecessary. The test could use a tiny bit of docs maybe.
The only real comment is that you are not cleaning up thing in the test. And note that this is very much tedious, because it will often mean that you need a:
try:
....
finally:
NpyIter_Dealloc(it)
in cython!
Maybe we should note that somewhere?
| if it.has_delayed_bufalloc: | ||
| flags |= cnp.NPY_ITER_BUFFERED | cnp.NPY_ITER_DELAY_BUFALLOC | ||
| if it.has_multi_index: | ||
| flags |= cnp.NPY_ITER_MULTI_INDEX |
There was a problem hiding this comment.
Is extracting this from the Python version worth it?
In either case, it's fine but maybe add short doc string that says that this is a limited implementation that recreates the NpyIter wrapped by a Python created np.nditer for testing?
(I started reading it as if it was some generic function, but it really is just a quick testing mock-up, which is fair!)
There was a problem hiding this comment.
it makes it easy to test the methods from cython if I extract what's already in the nditer object. It doesn't cover everything but allows some testing to be done easily. I added a docstring in 365b6ff
|
|
||
| def get_npyiter_size(it: "nditer"): | ||
| cdef cnp.NpyIter* cit = npyiter_from_npyiter_obj(it) | ||
| return cnp.NpyIter_GetIterSize(cit) |
There was a problem hiding this comment.
All of these are missing the NpyIter_Dealloc(cit) call! (Yes, it is unfortunate that we cannot avoid that.)
| # functions for iterating an NpyIter object | ||
| ctypedef int (*NpyIter_IterNextFunc)(NpyIter* it) | ||
| ctypedef void (*NpyIter_GetMultiIndexFunc)(NpyIter* it, npy_intp* outcoords) | ||
| NpyIter_IterNextFunc* NpyIter_GetIterNext(NpyIter* it, char** errmsg) except? NULL |
There was a problem hiding this comment.
I don't think you need the ?. Pretty sure NULL is always an error? (same below)
There was a problem hiding this comment.
This function has an annoying little feature that if you pass errmsg, it is actually nogil. Maybe that is the confusion? I think we just have to ignore that fact.
(There is a thought to that, that you can copy an iterator and run things in a multi-threaded environment. I am not aware that anyone has ever really done this and even if, I don't think this is the right way to design such an API.)
There was a problem hiding this comment.
Added suggestion in 365b6ff#diff-1e081d27e4d07ed1eaa8fe4af755d81de8c1dc062c919559b9678788dfc691f3
| npy_intp NpyIter_GetIterIndex(NpyIter* it) nogil | ||
| void NpyIter_GetIterIndexRange(NpyIter* it, npy_intp* istart, | ||
| npy_intp* iend) nogil | ||
| int NpyIter_GotoIterIndex(NpyIter* it, npy_intp iterindex) except? NPY_FAIL |
There was a problem hiding this comment.
No need for the ? here also. (Actually, same above, I don't think there is any function that needs the ?)
There was a problem hiding this comment.
Is it really? I looked through the function implementations and it appears there are code paths that seemingly return the "error" values but with no exception set. For example, this code path for NpyIter_AdvancedNew seems to return the error value NULL but does not set an exception:
numpy/numpy/_core/src/multiarray/nditer_constr.c
Lines 355 to 361 in 79ccbd1
NpyIter_Deallocate and several others I marked with except?
There was a problem hiding this comment.
dtype == NULL means something set an error already. the point is if an error is set we indicate that, ``NPY_FAIL` is never returned unless an error is set. That is not typical.
There was a problem hiding this comment.
Ah I see, I removed the ? in the except in 365b6ff#diff-1e081d27e4d07ed1eaa8fe4af755d81de8c1dc062c919559b9678788dfc691f3
|
@seberg I added the suggested changes. Not all of the cython functions can be easily tested in python since |
|
Thanks, I think those were the last changes. The |
Since numpy v2.0.0, the Iterator API is part of cython declarions. See the PR adding this feature: numpy/numpy#24691 . This means we do not need to manually import these declarations.
Since numpy v2.0.0, the Iterator API is part of cython declarions. See the PR adding this feature: numpy/numpy#24691 . This means we do not need to manually import these declarations.
Since numpy v2.0.0, the Iterator API is part of cython declarions. See the PR adding this feature: numpy/numpy#24691 . This means we do not need to manually import these declarations.
Since numpy v2.0.0, the Iterator API is part of cython declarions. See the PR adding this feature: numpy/numpy#24691 . This means we do not need to manually import these declarations.
Since numpy v2.0.0, the Iterator API is part of cython declarions. See the PR adding this feature: numpy/numpy#24691 . This means we do not need to manually import these declarations.
Since numpy v2.0.0, the Iterator API is part of cython declarions. See the PR adding this feature: numpy/numpy#24691 . This means we do not need to manually import these declarations.
This is a followup to #24658, and adds the Array Iterator API to the Cython 3.X init file as suggested by @seberg in #24658 (comment).