8000 ENH: ufuncs can take a tuple of arrays as 'out' kwarg by jaimefrio · Pull Request #5621 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

ENH: ufuncs can take a tuple of arrays as 'out' kwarg #5621

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 1 commit into from
Mar 8, 2015

Conversation

jaimefrio
Copy link
Member

Closes #4752

@jaimefrio
Copy link
Member Author

As discussed in #4752 this is currently failing the tests, because these expect ufuncs with multiple returns to accept a single array in the out kwarg to be used for the first of the returns.

Old behavior

  • Inputs are the nin first positional arguments
  • Outputs are the next nout positional arguments.
  • If less than nout are provided, they default to None (i.e. allocated by iterator)
  • If no output array has been provided positionally, then the first output array can be provided with the out keyword argument.

New behavior

  • Positional inputs are unchanged
  • If no output array has been provided positionally, then:
    • the out keyword argument can be a tuple of exactly nout items, which must all either be arrays or None.
    • if nout == 1, then a single array or None can also be passed as the out keyword argument.

Changes to maintain backwards compatibility

  • Allow a single array or None to be passed as the out keyword argument (if no positional output arrays have been provided), even if nout > 1, and use it for the first array.

@jaimefrio jaimefrio force-pushed the ufunc_out_tuple branch 5 times, most recently from b876c2d to 019360e Compare March 3, 2015 07:32
@jaimefrio
Copy link
Member Author

OK, this seems to be working now. I still need to document the new behavior, and since I also had to make changes to the array wrapping might be a good idea to add some tests for that. But I'd appreciate a first review.

}
else if (nout == 1) {
/* Can be an array if it only has one output */
if (_check_out_array(value, out_op+nin) < 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Overall, to the extent I can judge, this looks good and clearer than the code that was present. A perhaps nitpick is that I think assignments inside if functions make the code less clear than it could be otherwise. I would suggest replacing this stanza (and similar ones) with something like the following:

array_ok = _set_out_array(value, out_op+nin)
if (array_ok < 0) {
    ...

Here, I also changed the name to ensure it is clear what the function does; it could also be _check_and_set_out_array or _set_out_array_if_not_None or so).

Copy link
Member Author

Choose a reason for hiding this comment

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

Good suggestion on the name of the function, will change. But single function calls inside an if statement, when the return isn't needed elsewhere, are everywhere in the numpy code base, and in general in all Python C extensions, starting with the if (!PyArg_ParseTupleAndKeywords...) {return NULL;} in the python.org tutorial on C extensions.

I really think that adding a variable is unnecessary bulk in this case, so am going to stand my ground on that one, unless there is an overwhelming opinion against.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not being used very much to C I'm happy to follow convention -- though this particular piece of code did not seem to follow it originally. Anyway, I think that with the name change it will be much more obvious that the main action is something being set, not just checked.

@jaimefrio
Copy link
Member Author

I have incorporated some of Marten's suggestions, and added some more tests to validate the wrapping behavior. Documenting the new behavior is the only thing left, but the code itself should be almost ready to go.

@jaimefrio
Copy link
Member Author

I have made some changes, to properly report the error when the tuple does not have as many items as output arguments. I have also added some testing for the proper errors being raised. I think now only the documentation part is left.

@jaimefrio
Copy link
Member Author

Ok, have added the documentation changes too. I think it is ready to go.


..versionadded:: 1.10

The 'out' keyword argument is now expected to be a tuple with one entry
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd delete "now" here. Documentation should aim at those without previous knowledge; the versionadded will be enough for those who did know.

@mhvk
Copy link
Contributor
mhvk commented Mar 6, 2015

Looks good! Only two very minor comments.

@jaimefrio
Copy link
Member Author

Minor but sensible, should be corrected in the latest push.

PyErr_SetString(PyExc_TypeError,
"return arrays must be "
"of ArrayType");
if (_set_out_array(obj, out_op+i) < 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Space around +.

@charris
Copy link
Member
charris commented Mar 8, 2015

Few style nitpicks, otherwise LGTM. Does this affect #5566?

@jaimefrio
Copy link
Member Author

Fixed.

About #5566, I don't think it affects it, since the code seems to already be considering the possibility of out being a tuple of arrays. Can you confirm, @cowlicks?

charris added a commit that referenced this pull request Mar 8, 2015
ENH: ufuncs can take a tuple of arrays as 'out' kwarg
@charris charris merged commit bc034dc into numpy:master Mar 8, 2015
@charris
Copy link
Member
charris commented Mar 8, 2015

Thanks Jaime. Noticed a few more places needing spaces, but I think we should make a script to find those and do a general cleanup at some point.

@jaimefrio jaimefrio deleted the ufunc_out_tuple branch March 8, 2015 20:00
@juliantaylor
< 8000 span data-view-component="true"> Copy link
Contributor

thanks this is great, I think using tuple makes much more sense, makes me wonder why was this not originally done like this.

though now: ufunc(x, out=x, out2=y) only raises an warning while previously it raised a value error:

x = np.arange(9)
o1 = np.empty(9)
o2 = np.empty(9, dtype=np.int32)
np.frexp(x, out=o1, out2=o2)

ValueError: cannot specify 'out' as both a positional and keyword argument

@jaimefrio
Copy link
Member Author

Should we be more strict in the checking of 'out' being just 'out'?

@njsmith
Copy link
Member
njsmith commented Mar 9, 2015 via email

@jaimefrio
Copy link
Member Author

I'm not sure why the code uses strncmp and not directly strcmp, which is all it would take to do proper checking. Am I missing something?

@njsmith
Copy link
Member
njsmith commented Mar 10, 2015

I guess it's either an ancient thinko, or else maybe someone was planning
to actually support out1=, out2=, like the docstrings say, but then got
distracted halfway through. Either way it doesn't much matter at this
point...
On Mar 9, 2015 4:58 PM, "Jaime" notifications@github.com wrote:

I'm not sure why the code uses strncmp and not directly strcmp, which is
all it would take to do proper checking. Am I missing something?


Reply to this email directly or view it on GitHub
#5621 (comment).

@mhvk
Copy link
Contributor
mhvk commented Mar 10, 2015

👍 to checking out properly; it definitely confused me the first time I encountered it.

@jaimefrio
Copy link
Member Author

Take a look at #5659 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BUG cannot specify second output to ufunc as keyword argument
5 participants
0