Skip to content

ENH: Deprecate writeable broadcast_array #12609

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 7 commits into from
Jun 29, 2019
Merged

Conversation

mattip
Copy link
Member

@mattip mattip commented Dec 25, 2018

Relates to #2705, will fix it when deprecation warning is removed and readonly flag set. Replaces #11667.

As suggested in #11667 and in the code, the view returned from broadcast_arrays should be made readonly. set the NPY_ARRAY_WARN_ON_WRITE flag if the data is repeated across the array to fit the new shape. Currently we leave the readonly flag False which can lead to errors.

An alternative would be to immediately set the readonly flag False, with no deprecation cycle. Advantages to the alternative path:

- we are disrupting workflows anyway, we could do it only once instead of twice (once to filter the DeprecationWarning, once to remove the filter and handle the readonly change)
- The current behavior is clearly wrong and will cause bugs if the returned arrays are written to.

I will solicit responses from the mailing list

Edit: modified to set NPY_ARRAY_WARN_ON_WRITE

Edit: modified to set a DeprecationWarning

@seberg
Copy link
Member

seberg commented Dec 25, 2018

Was going to answer on the list, but another (or two) emails of me are not being accepted by the mailing list right now:

We have/used to have NPY_ARRAY_WARN_ON_WRITE flag for some deprecations, changing the warning text to include broadcast arrays, may be a way to have at least some deprecation cycle, that does not require any changed. I am not quite sure it fits here, but if it does and we are not in a rush, it seems like a reasonable thing to do that first.

@mattip
Copy link
Member Author

mattip commented Jan 21, 2019

Looking at NPY_ARRAY_WARN_ON_WRITE and array_might_be_written, it seems the work around PyArray_Diagonal was never finished. At one point perhaps it set NPY_ARRAY_WARN_ON_WRITE, but does no longer. It now returns a readonly view into the original ndarray, with a note where the view is made readonly: "For numpy 1.9 the diagonal view is not writeable. This line needs to be removed in 1.10".

The NPY_ARRAY_WARN_ON_WRITE flag is never set in the code (as far as I can tell). It is passed along to views and is checked before writing to an ndarray via array_might_be_written, so indeed we could set the flag when we create a view with overlapping memory.

@seberg
Copy link
Member

seberg commented Jan 21, 2019

The diagonal stuff is a bit cursed IIRC. @njsmith can probably give a quick hint on were it got stuck, I can't say I fully remember right now. I seem to recall that there was a lot of pushback or simply problems around the whole thing, I think it was one of the examples for "deprecations that did not turn out to go well" in the deprecations NEP or roadmap thingy.

@mattip mattip mentioned this pull request Mar 23, 2019
5 tasks
@ahaldane
Copy link
Member

ahaldane commented Mar 24, 2019

I can comment on diag and NPY_ARRAY_WARN_ON_WRITE, as it is related to the multifield view stuff that finally got merged in 1.16 after many years in #12447. In that PR I guess I got rid of the last code that set the flag, apparently np.diagonal did not do so and instead used a readonly flag.

The original plan was to make both diag and multifield-indexes return views instead of (packed) copies. Part of the problem is that this breaks views of the result, because the views in both cases have padding bytes, but the copy does not.

See #7661 #5407 #5409

Now that the multifield stuff is in I guess we could either remove or repurpose NPY_ARRAY_WARN_ON_WRITE.

@mattip
Copy link
Member Author

mattip commented Mar 24, 2019

The mailing list generated a few comments, with a request to not change the API as it understood that this may create overlapping memory.

The broadcast_to api return readonly views.

Perhaps repurposing array_might_be_written with a more specific warning would be the best path, such a warning would be easy to filter for experts who don't want to see it.

@mattip mattip changed the title DEP: issue warning when creating 0-stride broadcasted arrays ENH: issue warning when creating 0-stride broadcasted arrays Mar 24, 2019
@mhvk
Copy link
Contributor

mhvk commented Mar 25, 2019

Belatedly: I'd be quite happy to just go directly to changing the default to readonly=True, but if a warning on writing to a broadcast array with zero strides is not too much hassle, that's obviously OK too. Just as long as we don't warn everybody who uses the function in effectively readonly fashion.

@mattip mattip force-pushed the broadcast-readonly branch 2 times, most recently from 6b14c91 to 7d28a6b Compare March 28, 2019 13:15
@mattip mattip changed the title ENH: issue warning when creating 0-stride broadcasted arrays ENH: expose NPY_ARRAY_WARN_ON_WRITE and repurpose it for broadcast_array Mar 28, 2019
@mattip
Copy link
Member Author

mattip commented Mar 29, 2019

I have repurposed NPY_ARRAY_WARN_ON_WRITE for general use. In order to actually use it in broadcast_array, I needed to expose it to python like any other flag. Does this need to hit the mailing list as an API change?

@ahaldane
Copy link
Member

I guess the only question in my mind is whether it is right to make this flag a part of the python API, because that means we may need to keep supporting it forever. Eg, if someone writes a library which turns off the flag, that code needs to work even after we no longer use the flag anywhere.

But, I think that is acceptable, and the flag seems useful to have around in case similar cases turn up in the future. I, for one, am fine merging without discussion on the list - this isn't going to break anyone's code.

@seberg
Copy link
Member

seberg commented Mar 29, 2019

Oh, have to think about fully exposing it/this a bit more I guess. I somewhat thought we would re-purpose it for deprecation only (switching over to giving an error on such writes, unless someone opts in with writeable=True. Which would be OK with a private function).
On the other hand, if we start giving lots of errors due to not writeable arrays, it might be good have a clearer error message as to why some array is suddenly not writeable.

@seberg
Copy link
Member

seberg commented May 11, 2019

OK, after discussing with Stephan Hoyer, I think we should morph this into:

  • Simply deprecate np.broadcast_arrays returning a writeable view
  • Give a warning saying that you will have to do arr.flags.writeable = True if you want to keep the old behaviour. We could point out that broadcast_arrays to add a singleton dimension is not too helpful.
  • If too many people complain, we expose a readonly=True kwarg to np.broadcast_arrays.

I do remember that there was some push-back on the mailing list, but IIRC it was mostly one person and it was a bit unclear whether there was a real use-case around it.

I do think we should not expose new public API for this, instead have a private function to set the flag (since we need it).

EDIT: I can work on this if you prefer.

@mattip mattip force-pushed the broadcast-readonly branch from 7d28a6b to 2e23b42 Compare May 11, 2019 23:02
@mattip mattip changed the title ENH: expose NPY_ARRAY_WARN_ON_WRITE and repurpose it for broadcast_array WIP, ENH: Deprecate writeable broadcast_array May 11, 2019
@mattip mattip force-pushed the broadcast-readonly branch from 2e23b42 to e7af42e Compare May 13, 2019 18:42
@mattip
Copy link
Member Author

mattip commented May 13, 2019

Needs #13463 to fix a bug with _IsWritable before this can go in

@seberg seberg force-pushed the broadcast-readonly branch from e7af42e to c78f8d3 Compare May 21, 2019 22:04
@seberg
Copy link
Member

seberg commented May 21, 2019

Rebased. I forgot to add that fix to gh-13463, inserted it as a new commit here now, but maybe it would be better as its own PR. I hope you do not mind the forced pushing.

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

This looks good but I think the change log entry could be a bit clearer; hopefully my suggestions make sense. The rest is mostly nitpicks, though also one query.

@charris
Copy link
Member

charris commented May 22, 2019

The diagonal stuff is a bit cursed IIRC

If I recall, we converted it to a view and made it readonly with intent to change that later. At that point I'm forgetful, although ISTR that there was a reason I didn't precede to finish that program.

@mattip mattip changed the title WIP, ENH: Deprecate writeable broadcast_array ENH: Deprecate writeable broadcast_array May 22, 2019
Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

This now looks great. A few more wording comments for the changelog entry - hopefully me working out my confusing will end up helping others not be confused...

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

OK, all great now!

@eric-wieser
Copy link
Member

Approach looks sounds, but some of the prose seems wrong, and there's an unhandled error path.

@eric-wieser
Copy link
Member

I assume the flag gets propagated?

a, b = np.broadcast_arrays(np.arange(3), np.arange(3)[:,None])
a.writeable  # warns
a2 = a.view()
a2.writeable  # but does this warn?

@mattip
Copy link
Member Author

mattip commented Jun 2, 2019

Yes, the flag propagates. However, if after creating a2, the flag on a is reset, a2 still warns. I don't know if changing that is worth the effort for a deprecation on a rarely-used function.

>>> a, b = np.broadcast_arrays(np.arange(3), np.arange(3)[:,None])
>>> a.flags.writeable  # warns
__console__:1: FutureWarning: future versions will not create a writeable array from broadcast_array. Set the writable flag explicitly to avoid this warning.
True
>>> a2 = a.view()
>>> a2.flags.writeable
__console__:1: FutureWarning: future versions will not create a writeable array from broadcast_array. Set the writable flag explicitly to avoid this warning.
True
>>> a.flags.writeable = True
>>> a2.flags.writeable
__console__:1: FutureWarning: future versions will not create a writeable array from broadcast_array. Set the writable flag explicitly to avoid this warning.
True

@eric-wieser
Copy link
Member

eric-wieser commented Jun 2, 2019

Agreed that we don't need to fix that. Maybe worth documenting that behavior somehow, either just in the release notes or the warning message. Something about fixing up the flag before taking views such as by slicing. Putting the word "immediately" in the existing text might be enough.

@mattip mattip requested a review from eric-wieser June 9, 2019 19:25
seberg and others added 2 commits June 26, 2019 00:02
When the base is not an array (or generally when the flag of the base
array was toggled), it is OK to allow setting the writeable flag to
True, as long as any ancestor (especially the last one) is writeable.
@mattip mattip force-pushed the broadcast-readonly branch from 831cf15 to b31f896 Compare June 25, 2019 21:02
@mattip
Copy link
Member Author

mattip commented Jun 25, 2019

@eric-wieser, @seberg: I rebased and squashed this. Any more review?

@seberg seberg self-requested a review June 25, 2019 21:52
Copy link
Member

@seberg seberg left a comment

Choose a reason for hiding this comment

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

Didn't go through it super carefully, but I remember it being all fine. And tests seem thorough enough, some blank lines are missing in the release notes, but I can also do that later. Just in case someone still wants to comment, not merging it right now.

mattip and others added 5 commits June 26, 2019 01:07
Co-Authored-By: Sebastian Berg <sebastian@sipsolutions.net>
Co-Authored-By: Sebastian Berg <sebastian@sipsolutions.net>
Co-Authored-By: Sebastian Berg <sebastian@sipsolutions.net>
Co-Authored-By: Sebastian Berg <sebastian@sipsolutions.net>
@mattip mattip requested a review from seberg June 29, 2019 00:33
@seberg
Copy link
Member

seberg commented Jun 29, 2019

Sorry, and thanks for the additional ping. I will put this in.

@mhvk
Copy link
Contributor

mhvk commented Jul 7, 2019

With cython code, this beatifully constructed PR sadly is giving false positives; see #13929

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

Successfully merging this pull request may close these issues.

6 participants