-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Generalized flip #7346
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
Generalized flip #7346
Conversation
I think this is a nice idea, but we have a policy that new API needs to be discussed on the mailing list. Could you please post your proposal to the numpy-discussion list: https://mail.scipy.org/mailman/listinfo/numpy-discussion Thanks! |
[7, 6]]]) | ||
|
||
assert_equal(flip(a, 2), b) | ||
|
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 you should add a test for a flip at higher dimensions. If you don't want to construct the input array and expected result manually, perhaps show something like
a = np.arange(2 * 3 * 4 * 5).reshape(2, 3, 4, 5)
for i in range(a.ndim):
assert_equal(flip(a, i), np.flipud(a.swapaxes(0, i)).swapaxes(i, 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.
This will also implicitly demonstrate the claim that the shape of the array is preserved, although you can add an explicit check. All your other test arrays are 2**3, so it would be hard to tell if the dimensions moved around.
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.
Added your test example here: 468c4f2
>>> np.all(flip(A,2)==A[:,:,::-1,...]) | ||
True | ||
""" | ||
if axis==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.
Are these special cases really necessary? The function seems to be able to handle them already.
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.
They are not necessary but flipud
and fliplr
should be slightly faster. Should we remove the cases?
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.
In general, clarity is more important than unmeasured micro-optimizations.
On Fri, Feb 26, 2016 at 3:10 PM, C. Eren Sezener
notifications@github.com wrote:
In numpy/lib/twodim_base.py:
[[0, 1],
[2, 3]]])
flip(A, 1)
- array([[[2, 3],
[0, 1]],
[[6, 7],
[4, 5]]])
A = np.random.randn(3,4,5)
np.all(flip(A,2)==A[:,:,::-1,...])
- True
- """
- if axis==0:
They are not necessary but flipud and fliplr should be slightly faster.
Should we remove the cases?—
Reply to this email directly or view it on GitHub.
Nathaniel J. Smith -- https://vorpus.org
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.
Removed the special cases 4443294
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.
The special cases increase the speed for axis = 0
and axis = 1
by a factor of approximately 1.5.
Measuring the execution time of flip(a, 0)
using timeit
and for an array a = np.arange(100**4).reshape(100,100,100,100)
I got (from 1000000 loops, best of 3):
0.865 us
when using the special cases (returning flipud(a)
)
1.34 us
when using the current implementation from abe1735 using @njsmith suggestion.
Does that still fall into micro-optimization?
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.
Yes. 0.5 us is very, very fast.
On Fri, Feb 26, 2016 at 11:32 PM Denis Alevi notifications@github.com
wrote:
In numpy/lib/twodim_base.py
#7346 (comment):
[[0, 1],
[2, 3]]])
flip(A, 1)
- array([[[2, 3],
[0, 1]],
[[6, 7],
[4, 5]]])
A = np.random.randn(3,4,5)
np.all(flip(A,2)==A[:,:,::-1,...])
- True
- """
- if axis==0:
The special cases increase the speed for axis = 0 and axis = 1 by a
factor of approximately 1.5.Measuring the execution time of flip(a, 0) using timeit and for an array a
= np.arange(100**4).reshape(100,100,100,100) I got (from 1000000 loops,
best of 3):0.865 us when using the special cases (returning flipud(a))
1.34 us when using the current implementation from abe1735
erensezener@abe1735
using @njsmith https://github.com/njsmith suggestion.Does that still fall into micro-optimization?
—
Reply to this email directly or view it on GitHub
https://github.com/numpy/numpy/pull/7346/files#r54328158.
Add a note in the release notes. Aside from the possible bug and other comments, nice job, this looks like a really handy addition. |
@@ -32,6 +32,76 @@ def _min_int(low, high): | |||
return int64 | |||
|
|||
|
|||
def flip(m, axis): |
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.
Since this is a function that works on arbitrary dimensions, not just 2-d, is this the right file to put it? Perhaps function_base.py
and tests/test_function_base.py
would be a better choice?
Should |
In principle, this could be made even more general by allowing an iterable for |
I think I addressed all the issues pointed out besides @madphysicist's last comment:
Should I also change the file of the function? What are other opinions? |
""" | ||
if not hasattr(m, 'ndim'): | ||
m = asarray(m) | ||
if m.ndim <= axis: |
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.
This doesn't cover negative values of axis
. I would remove this altogether and replace it by making the assignment part of a try/except, as follows:
try:
indexer[axis] = slice(None, None, -1)
except IndexError:
raise ValueError(...)
Question: Should this be an IndexError
rather than a ValueError
?
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.
No, ValueError is definitely the right error to raise for an invalid axis.
On Fri, Feb 26, 2016 at 9:30 PM Marten van Kerkwijk <
notifications@github.com> wrote:
In numpy/lib/twodim_base.py
#7346 (comment):
[2, 3]]])
flip(A, 1)
- array([[[2, 3],
[0, 1]],
[[6, 7],
[4, 5]]])
A = np.random.randn(3,4,5)
np.all(flip(A,2)==A[:,:,::-1,...])
- True
- """
- if not hasattr(m, 'ndim'):
m = asarray(m)
- if m.ndim <= axis:
This doesn't cover negative values of axis. I would remove this
altogether and replace it by making the assignment part of a try/except, as
follows:try: indexer[axis] = slice(None, None, -1) except IndexError: raise ValueError(...)
Question: Should this be an IndexError rather than a ValueError?
—
Reply to this email directly or view it on GitHub
https://github.com/numpy/numpy/pull/7346/files#r54326237.
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.
Also, I would recommend adding one more exception test that passes in axis < -m.ndim
.
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.
As far as I can see, @denisalevi handled all the remaining issues. Ready for merge? |
------- | ||
out : array_like | ||
A view of `m` with the entries of axis reversed. Since a view is | ||
returned, this operation is :math:`\\mathcal O(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.
I would simply say "constant time".
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.
Done e10be0e
Updated. |
Needs mention in |
Also squash the 12 commits into one or two. You can use |
indexer[axis] = slice(None, None, -1) | ||
except IndexError: | ||
raise ValueError("axis=%i is invalid for the %i-dimensional input array" | ||
%(axis, m.ndim)) |
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.
per pep8, please add a space after the %
operator
@charris under what title should the release note be? New features? |
c619a79
to
4333f98
Compare
4333f98
to
5e0de07
Compare
87f5ea1
to
7614188
Compare
7614188
to
5530793
Compare
@@ -99,6 +99,10 @@ keyword argument. It can be set to False when no write operation | |||
to the returned array is expected to avoid accidental | |||
unpredictable writes. | |||
|
|||
Generalized ``flip`` | |||
~~~~~~~~~~~~~~~~~~~~ | |||
``flipud`` and ``fliplr`` reverse the elements of an array along axis=0 and axis=1 respectively. The newly added ``flip`` function reverses the elements of an array along any given axis. |
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.
Lines less than 80 characters in length, need line breaks here.
Getting close. Add an entry in |
5530793
to
e7de401
Compare
@charris done and squashed. |
def test_3d_swap_axis0(self): | ||
a = np.array([[[0, 1], | ||
[2, 3]], | ||
|
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.
Can leave out the blank lines.
I've made a few comments in the tests for formatting. I'll put this in and you can do the fixes in the rot90 PR. |
Thanks @erensezener and co. |
Thanks @charris. Did the changes here: 7a57783d84188d24ed18dc16a825b13a556087d3 |
This PR generalizes
fliplr
andflipud
for arbitrary axes.flipud
andfliplr
reverse the elements of an array alongaxis=0
andaxis=1
respectively. Theflip
function reverses the elements of an array along any given axis. In caseflip
is called withaxis=0
oraxis=1
, the function is equivalent toflipud
andfliplr
respectively.A similar function is also available in MATLAB™.
This pull request is part of a BCCN Berlin student project by @denisalevi @ge00rg @erensezener