-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Make AdvancedNew iter more 0-d aware #3104
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
@mwiebe Might be useful for Mark to comment. |
Maybe for the first half gh-2840 is better, much less intrusive and 0-d does not fit too well in anyway (though I would move the NDIM reporting fix from npyiter_pywrap to npyiter_api.c probably). That is independent from the |
def test_0d_iter(): | ||
# Basic test for iteration of 0-d arrays: | ||
i = nditer([2, 3], ['multi_index'], [['readonly']]*2) | ||
assert_(i.ndim == 0) |
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.
Small style comment - wouldn't using assert_equal be better, so if something does fail in the future, it will print out the values that are different?
The changes look good to me, I see there were quite a bit of small changes required where the code was using the invariant that ndim >= 1. I've built and run the tests, and I get two failures, one of which looks to be related to this change. Are you getting the same thing? I'll run the tests without the patch to check that.
|
The failures aren't from this pull request, looks like they got into master earlier. This is on windows, by the way, I suspect the tests aren't getting regularly exercised on this platform. |
Thanks for checking! Probably true about windows being tested, but I believe the first test is because the lapack tests are apparently still a bit strict after making dot aware of fortran order array (there must be an open issue for macs about this), and the second test looks like a test file that does not exist any more (and thus hopefully is not a real failure). |
Right, after deleting numpy and reinstalling, those errors aren't there. Sorry for the false alarm on that! |
* third party software must use `oa_ndim == 0` for <1.8 compatibility. | ||
*/ | ||
if ((oa_ndim == 0) && (op_axes == NULL)) { | ||
oa_ndim = -1; |
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.
Why not just DEPRECATE
this here and now?
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.
@njsmith, because DEPRECATE spits out warnings. And you cannot change to -1 if you want to support <1.8 (it is not well defined for those versions). So effectively I think that third party code cannot really use -1 yet and thus deprecating it before we can say that 1.8. is old seemes not right...
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.
Deprecation warnings are just to give people a heads up, and only visible
if explicitly requested. The functionality is deprecated; we might as
well start giving people that heads up in the standard way now, and they
can figure out for themselves when they want to make the change.
On 2 Mar 2013 14:44, "seberg" notifications@github.com wrote:
In numpy/core/src/multiarray/nditer_constr.c:
@@ -158,6 +156,16 @@
return NULL;
}
- /*
\* Before 1.8, if `oa_ndim == 0`, this meant `op_axes != NULL` was an error.
\* With 1.8, `oa_ndim == -1` takes this role, while op_axes in that case
\* enforces a 0-d iterator. At some point this should be deprecated, but
\* third party software must use `oa_ndim == 0` for <1.8 compatibility.
*/
- if ((oa_ndim == 0) && (op_axes == NULL)) {
oa_ndim = -1;
@njsmith https://github.com/njsmith, because DEPRECATE spits out
warnings. And you cannot change to -1 if you want to support <1.8 (it is
not well defined for those versions). So effectively I think that third
party code cannot really use -1 yet and thus deprecating it before we can
say that 1.8. is old seemes not right...—
Reply to this email directly or view it on GitHubhttps://github.com//pull/3104/files#r3215077
.
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 this is new functionality that is not backward compatible, so the old needs to be left in. Might be worth leaving a comment tag in the code though so we can find it again.
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.
@charris: Not sure what you're suggesting. In case it was unclear, what i was suggesting is: we keep in backwards compatibility code for the oa_ndim == 0 && op_axes == NULL
special case; if anyone takes advantage of this special case we issue a DeprecationWarning; someday off in the future, once people have had time to fix their code, we take out the special case.
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.
@rgommers Let's get a fourth opinion ;)
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.
Each option has a downside. If I understand correctly, this is the trade-off:
Deprecate now: people who don't want to see warnings have to write code like:
if np.__version__ < '1.8.0': # OT: we need proper version tuples asap, this will break for numpy 1.10
oa_ndim = 0
else:
oa_ndim = -1
Deprecate later: more people write oa_ndim = 0
now. For those that don't care about earlier versions, they're still OK but may have to fix their code several versions down the road. Then they can simply fix it without doing version comparisons.
I have a preference for deprecating later. Deprecation warnings aren't common for numpy (check the release notes of recent releases - 1.7.0 is the only one that has a significant amount), so I don't really agree that warnings that can't be fixed are "very common".
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.
Completely missed that it actually it is possible to work around by using the the MultiNew iterator function in that case. And that does not even sound bad. So I would have no problem with deprecating right away.
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.
Ah, unless you want control over the buffer size... but probably that is getting so rare that its no use to worry.
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.
Great, never mind my comment then.
@seberg, I think Mark's style comment on the test makes sense. Apart from that I think this can be merged. |
Jup, fixed and rebased. |
Oops ;) |
Would be a shame if it would work the first try, wouldn't it? :) |
"contained invalid " | ||
"values %d", (int)iop, (int)i); | ||
return 0; | ||
} else if(axes_dupcheck[i] == 1) { |
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.
Great, I get to style nit pick ;) else if
should be on next line.
Those code comments are nice! |
There are relatively few changes necessare here. However there is a conceptionally there are no axes for the 0-d case, and no axesdata needs to be used. This still uses the first axisdata. Which means that in a few places ndim == 0 is special cased or special cased to act like ndim == 1. It would probably be a little cleaner to to use the base pointers directly in the 0-d case and no axes iteration at all. That would require similar special cases though. This also makes oa_ndim == -1 the "correct" way to signal that no op_axes are given with oa_ndim == 0 being, for the time being, dual use. Either meaning that nothing may be given, or if something something was given enforcing a 0-d iteration. The necessary changes to the ufunc machinery are also done. Documented that the dtype transfer functions do not handle the scalar case unless even shape is set.
Also uses oa_ndim == -1 to signal no op_axes were given. This is slightly cleaner inside pywrap itself and is a cleaner signal for the iterator.
OK, I put in the actual deprecation. There are no tests (Where would I add them? I would need to write some C-code to test.), but I involuntarily tested the deprecation because I actually had forgotten to put in the fix for the ufuncs AdvancedNew usage, so good point for deprecating sooner rather then later ;) |
If someone thinks that 3rd party code may want to use buffersize, since creating special cases in C-code for which numpy version you find is likely annoying (not sure how hard it is), I am be very much open to undoing that. |
@seberg What has changed about |
@charris nothing. That comment was about third party code using a non-default buffersize. If third party code does that but does not use op_axes (if they do, my guess is they got the same 0-d problem as einsum and like the change), they will have to check for the numpy version in C code to avoid the deprecation warning. |
Well then, in it goes! |
Make AdvancedNew iter more 0-d aware
This is the old PR basically reincarnated, with some (actually relatively few) changes.
This changes the AdvancedIter to use
ndim == 0
when the iteration is 0-D. This means that unfortunately a few special need to be added, since before ndim was set to 1 for the scalar case. The approach here is to store one "axisdata" as if iteration was 1-d, and add special cases to fill and use this where necessary. I do not claim that it is the best approach, it may not be...Since it does make some sense (and einsum "tries" to basicaly) to force 0-d iterations, the
oa_ndim
logic is changed to allow forcing a 0-D iteration ifop_axes
is not NULL. This means thatop_axes
not being NULL is important for signalling what should happen (is this ok?), and what was previously an error now makes a forced 0-d iteration. Since that seems not too great, -1 is used to signal the old 0 cleanly, but backwards compatibility doesn't allow deprecating that.These changes enable to remove the 0-d nditer hack, and make einsum work for the 0-d special case without modification.