-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Faster, indices-aware circshift (and non-allocating circshift!) #17861
Conversation
No new exports on the release branch. |
808c2cb
to
942dc59
Compare
Updated to guard against aliasing. While I state that this closes #16032, I should clarify that it's a bit different from what @musm was requesting. The reason I implemented this with with separate |
Thank for this. I'm trying to figure out the code. To clarify, this is using the "chase-the-cycles" approach? And your suggestion is that a truly in place version is possible following stevengj's suggestion of the " two reversal passes" algorithm, but your point here |
"chase the cycles" means something different: it's one implementation (a less efficient one) of a truly inplace version. https://en.wikipedia.org/wiki/In-place_matrix_transposition describes a chase-the-cycles algorithm for inplace transposition, and that should give you the basic idea. chase-the-cycles algorithms seem elegant at first blush, but they're both tricky and slow, because they interact very badly with the CPU's cache. Your second point is exactly correct: in my opinion, it's much better to allocate the memory. For truly huge arrays you'd start
The way it works is like this: if you're doing a
to
it does it using a recursive
the "tuples" here are index ranges. Once all the indices are specified for all the dimensions, The old implementation of |
See also `circshift`. | ||
""" | ||
@noinline function circshift!{T,N}(dest::AbstractArray{T,N}, src, shiftamt::DimsInteger) | ||
dest === src && throw(ArgumentError("dest and src must be separate arrays")) |
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 docs should probably note that dest
should not alias src
.
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.
Fixed.
I'll merge this by the end of the day; it will be useful for my upcoming FFT fixes (#17896). |
@tkelman, do you want me to prepare a backport version that leaves out the new export, or will you just delete that line yourself? |
I'll delete that line. Would tests or anything else need to change? |
Thanks. No changes needed; I anticipated this and adding scoping to the ones that would otherwise have had to change. |
end | ||
a[(I::NTuple{N,Vector{Int}})...] | ||
function circshift(a::AbstractArray, shiftamt) | ||
circshift!(similar(a), a, map(Integer, (shiftamt...,))) |
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 last time I tried this (in 1d), it was faster to do the out-of-place circshift
directly. The in-place variant requires an extra pass over the array.
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.
Oh, nevermind, I see that circshift!
is not actually in-place, because you pass both the source and destination arrays.
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.
map(Int, (shiftamt...,))
? There doesn't seem much point in using Integer
here.
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.
extra pass
2 extra passes, actually, since the truly inplace version needs two passes and then there's the copy for the original array.
There doesn't seem much point in using Integer here.
I was just keeping consistency with the previous version, but I'm happy to change it---perhaps as part of a final resolution to the inconsistencies noted in #17567?
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 function can still accept Integer, but there seems no point in passing Integer when casting to Int should be fine. So this seems independent of #17567
Ah, I'll also want to delete it from the rst manual. edit: or add |
On the benchmark in #17581, this is about 6x faster. On large vectors, this is also about 25% faster than the truly inplace 1d implementation of
circshift!
in #16032.Fixes #16032, fixes #17581.
With regards to backporting to 0.5, perhaps the only question is whether we should export
circshift!
(if we're serious about "feature freeze").