ENH: add np.broadcast_to and reimplement np.broadcast_arrays#5371
ENH: add np.broadcast_to and reimplement np.broadcast_arrays#5371charris merged 1 commit intonumpy:masterfrom
Conversation
|
I am a bit worried that someone might use broadcast arrays with more then 32 arguments, then it would be a regression, I am not really worried for the new functions. |
|
@seberg In fact, the test failure I'm getting here is for exactly that reason. So I guess I'll switch |
|
Since it is very simple and if the speed difference is big, we could think of making a fast pat. Though maybe it is a bad idea considering all the funny little things with subclasses (at least if subok=True). and the general maintanence overhead of it (and if just that we need to duplicate all tests)... |
|
Thanks for keeping the subclasses! (after all the time @seberg and I spent on it...). One question (which I had earlier myself but didn't address): is the calculation of the shape much better/faster than using |
|
I wouldn't bother trying to mess around with fast paths until someone finds I think the idea is that we want to steer users away from np.broadcast b/c I don't think there's much point in adapting np.broadcast to use the new On Tue, Dec 16, 2014 at 9:08 PM, Marten van Kerkwijk <
Nathaniel J. Smith |
|
Hmm, just been recommending |
|
Hooray for data! If it does matter then it matters. ...looking at that thread, it sounds like the overall operation you're On Tue, Dec 16, 2014 at 9:31 PM, Marten van Kerkwijk <
Nathaniel J. Smith |
|
The above said, in most cases I think people would indeed just want the final Also a small note: again in the context of astropy, yet another implementation of the same thing could not be replaced by |
|
@njsmith - the 4 ms was for a 10000-element array. But for the simpler functions and fewer elements it does matter. We did quite elaborate timing tests; eg., astropy/astropy#3141 (comment). For small arrays, total time is 20 µs, so, yes, the additional 10 µs does matter a little. |
|
I think that can be interpreted as a request for my suggestion (1) in this (Well, that talks about broadcast_arrays, but the generalization to On Tue, Dec 16, 2014 at 9:37 PM, Marten van Kerkwijk <
Nathaniel J. Smith |
|
yes, looks (very) simiar... |
|
Does that 20 µs matter though? (Genuine question, not trying to denigrate On Tue, Dec 16, 2014 at 9:40 PM, Marten van Kerkwijk <
Nathaniel J. Smith |
|
For the purposes of discussion, I just pushed a fastpath for Interestingly, I needed to use the old iterator, though. This implementation with the new iterator almost works: def broadcast_shape(*args):
return np.nditer(args, flags=['multi_index', 'zerosize_ok']).shapeHowever, it fails with We can also add a fastpath for broadcast_arrays, too, if desired (I have original implementation in my first commit). The other option is to keep a single path for |
|
@shoyer, how about just using |
|
@njsmith - the |
|
@mhvk I would use |
|
or one could fix the 32 argument limit of the iterator, someone want to finish this: |
|
Well, the current code is slow for small arrays, whether this matters in any real world applications, I don't know. I have used |
|
OK, fixing @juliantaylor's tree would obviously be best, but in the meantime how about the following to ensure one is both fast and does not break the API?: (here, |
|
On Wed, Dec 17, 2014 at 12:39 AM, Julian Taylor notifications@github.com
I glanced over your code, and you have a few variable sized arrays here and In any case, if the trouble is with einsum, can this not be partially I still have trouble imagining a real world application where the 32 Jaime (__/) |
numpy/lib/stride_tricks.py
Outdated
There was a problem hiding this comment.
I think this is what np.asanyarray does.
There was a problem hiding this comment.
But note that subok is a variable here, which can be True or False.
core/numeric/asanyarray is defined to
return array(a, dtype, copy=False, order=order, subok=True)
There was a problem hiding this comment.
And that's why you should read all the code before commenting... Sorry for the noise.
|
@mhvk Good idea for simplifying I like the idea of making |
|
@shoyer - had forgotten how forgiving python is with indices outside of a list's range... nice. Seems OK to leave the |
|
@mhvk In that case, we should not expose |
|
@shoyer - agreed that for now it is best not to expose it, as it currently is mostly a work-around the 32-argument limit of |
|
Instead of handling tuples as shapes, let's put them in a separate kwarg.
|
|
Anyone have opinions on my question from the first post: should we allow broadcasting with negative numbers in the shape? Given that |
|
The fact that after 30 seconds thought I can't figure out what negative For reshape you know what the total array size is, so an ndim array has I'm generally against supporting things just because we can. That way lies
|
|
@njsmith In the context of |
numpy/lib/stride_tricks.py
Outdated
There was a problem hiding this comment.
probably to late, just a quick idea; but what if we would make the view readony as default?
There was a problem hiding this comment.
This does seem like a good idea. Would you just add an argument readonly=True?
I suppose we'd need to default to readonly=False on np.broadcast_arrays to ensure backwards compatibility for now.
There was a problem hiding this comment.
Yeah, the readonly=False default for broadcast_arrays is what makes me wonder if that idea is a bit late. But on the other hand, I cannot find a reason why it would not be a good default at least here.
|
We are >< that close to finishing this... |
|
The readonly flag can be set separately if needed? |
|
Yeah, sorry for delaying things in the first place. It can be added later, but if we say it makes sense, I would think that it probably makes sense to make it default to True (for the new function only unfortunatly)? And in that case we need to decide before the release, but we can just make a blocker issue to not forget it. |
|
How about we just default it to readonly now (which does seem safer) and
|
|
Readonly default sounds reasonable to me. |
|
Should we even include a The only justification I can see for |
|
Maybe that makes sense, I am still wondering if there is some nice way to deprecate broadcast_arrays being writeable, but I can't think of one easily, or can we have a "writable but warn" flag without much hassle? |
|
We already implemented writeable-but-warn for diagonal and for some record And leaving out the readonly flag altogether for the new api sounds fine to
|
|
Ok, lets move this finally. Since I guess it is a bit beyond this (though if you are happy to help with it, please do!) to do a deprecation for broadcast_arrays, we don't need to do it in this PR. But there seems to be an agreement that there is no reason to have a writable output for now. Could you make the output readonly (and hack broadcast_arrays to not change for now)? That would be great! I think it might be easiest to make a private function that has a Then we can finally put this in. Again, I am sorry for delaying it all the time.... |
|
@seberg Sounds good, I'll get on that. |
|
OK, I have pushed another commit that makes the result of I have not added the warn-on-write flag for
|
|
OK, great. I will look at it later (hopefully), if I don't, wake me up some time ;). I think we are much safer here then with diagonal to be honest, though it might be a misconception because I simply can't see anyone writing to a non-contiguous multi-dimensional array without risking insane bugs ;). |
numpy/lib/stride_tricks.py
Outdated
There was a problem hiding this comment.
I think it might be safer to do:
if readonly:
result.flags.writable = False
Can you add a test (if not done already) that a readonly array works? I imagine this might throw an error for broadcast_arrays if the array is already readonly, or if not throw an error it might unset an existing readonly flag (I am not sure about the logic, but I think we cannot change the flag if the parent is readonly).
There was a problem hiding this comment.
If fact, I tried this your logic as my first solution. It turns out this didn't work, as I discovered when I pushed this to Travis: https://travis-ci.org/numpy/numpy/jobs/52098107
I'll add a test for preserving the readonly nature of readonly input.
There was a problem hiding this comment.
Done. See the latest commit.
There was a problem hiding this comment.
Are we sure that test did not rely on buggy behaviour in the first place? ;)
There was a problem hiding this comment.
OK, that looks like it should be good. But I will need to understand why the first thing did not work (you don't have to check that though, I will later). There is a fishy smell there for me.
There was a problem hiding this comment.
The issue was that nditer was making even writeable input readonly. That's what I added op_flags=['readonly'] in the latest commit, to try to clarify what nditer is doing (I couldn't get this to work when I tried using another flag like 'readwrite').
There was a problem hiding this comment.
OK, that that makes problems makes sense to me. I guess 'readwrite' would throw an error if it is readonly before, so then this is should be the best way.
|
Sounds like this is ready. I'll merge this evening if no one complains or beats me to it. |
|
@shoyer Could you squash the commits into one? |
Per the mailing list discussion [1], I have implemented a new function `broadcast_to` that broadcasts an array to a given shape according to numpy's broadcasting rules. [1] http://mail.scipy.org/pipermail/numpy-discussion/2014-December/071796.html
ENH: add np.broadcast_to and reimplement np.broadcast_arrays
|
Thanks @shoyer. |
|
Thanks a lot! |
|
Leaving this here in case someone needs to support older versions of numpy. I timed it against the version of def naive_broadcast_to(a, shape):
"Broadcast an array to a specified shape. Returns a view."
return np.broadcast_arrays(a, np.empty(shape, dtype=np.bool))[0]
a = np.random.rand(100, 1, 100)
np.testing.assert_array_equal(naive_broadcast_to(a, (100, 1000, 100)), broadcast_to(a, (100, 1000, 100)))
%timeit naive_broadcast_to(a, (100, 10000, 100))
%timeit broadcast_to(a, (100, 10000, 100)) |
Per the mailing list discussion, I have implemented a new function
broadcast_tothat broadcasts an array to a given shape according to numpy's broadcasting rules.The new array iterator has functionality that could make several of these functions into almost one liners (thank you @jaimefrio, @seberg and @mwiebe for showing how), although we do have to do some extra work to preserve subclasses.
The first commit (eventually to be squashed away) shows how I would implement these without relying heavily on
nditer. It also includes thebroadcast_shapefunction (no longer necessary for the implementation ofbroadcast_arrays), which almost but didn't quite work as a one-liner (it failed for size 0 arrays). We could revive it if others think it would serve a useful purpose.Question: should we allow for broadcasting with negative numbers in the shape? This seems strange but it does work (sort of like reshape) with the current implementation and I suppose someone could find it useful. On the other hand, numbers less than -1 are also supported, which may just be a bug with nditer?
(I did not yet add tests for the behavior with negative sizes.)