-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
in-place fftshift and in-place shifted ffts #20696
Comments
cc @stevengj |
Seems like a dup of #19923. |
The function Maybe I should clarify what I mean with in-place here: for a given array |
@JKrehl, as discussed in that issue, there is some desire to have a completely in-place |
Why does Is there no place for a bespoke half-space swap (or shift because that's the same here) in the light that this problem can be solved more efficiently? What's the current status of the truly in-place |
Yes, the I'd rather see the implementation effort go into a more general-purpose function ( |
(By the way, if you really care about performance, a bunch of individual swap loops along each dimension, which is what it looks like your |
So is it just by lack of manhours that this hasn't been implemented yet? There is one swap expression around which loops in Fortran order (except for the odd-axis-length case) are nested (in all the |
@stevengj using Base.Cartesian
function _splitreverse_loop_nester(ex, half, i, x, rx, hex)
quote
$rx = split[$i]
for $x in 1:$(half ? :(div(split[$i], 2)) : :(split[$i]))
$ex
$rx -= 1
end
$(half ? :(if isodd(split[$i]); $x=$rx=div(split[$i]+1, 2); $hex; end) : nothing)
$rx = size(src, $i)
for $x in split[$i]+1:$(half ? :(div(size(src, $i)+split[$i], 2)) : :(size(src, $i)))
$ex
$rx -= 1
end
$(half ? :(if isodd(size(src, $i)-split[$i]); $x=$rx=div(size(src, $i)+split[$i]+1, 2); $hex; end) : nothing)
end
end
@generated function splitreverse!{T,N,I<:Integer}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}, split::NTuple{N, I})
xs = ((Symbol("x_", i) for i in 1:N)...)
rxs = ((Symbol("rx_", i) for i in 1:N)...)
ex = :((dest[$(xs...)], dest[$(rxs...)]) = (src[$(rxs...)], src[$(xs...)]))
hex = copy(ex)
for i in 1:N
hex = _splitreverse_loop_nester(ex, true, i, xs[i], rxs[i], hex)
ex = _splitreverse_loop_nester(ex, false, i, xs[i], rxs[i], nothing)
end
quote
@nexprs $N i->(size_i = size(src, i))
@inbounds $hex
dest
end
end
function circshift!{T,N,I<:Integer}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}, shifts::NTuple{N, I})
@assert size(dest) == size(src)
splits = map(mod, map(-, shifts), size(src))
splitreverse!(dest, src, splits)
splitreverse!(dest, dest, size(src))
end
circshift!{I<:Integer}(dest::AbstractVector, src::AbstractVector, shifts::I) = circshift!(dest, src, (shifts,)) Now with correct handling of odd-length outermost axis. The mechanism complicates the code code generation a bit. Some tests, this thing passes: @testset begin
@test begin A = collect(1:6); circshift!(A, A, 0) == Int[1, 2, 3, 4, 5, 6] end
@test begin A = collect(1:5); circshift!(A, A, 2) == Int[4, 5, 1, 2, 3] end
@test begin A = collect(1:5); circshift!(A, A, 7) == Int[4, 5, 1, 2, 3] end
@test begin A = collect(1:7); circshift!(A, A, -4) == Int[5, 6, 7, 1, 2, 3, 4] end
begin
A = reshape(collect(1:30), (5,6))
circshift!(A, A, (2,4))
@test A== [14 19 24 29 4 9;
15 20 25 30 5 10;
11 16 21 26 1 6;
12 17 22 27 2 7;
13 18 23 28 3 8]
A = reshape(collect(1:90), (5,6,3))
@test circshift!(copy(A), A, (1,2,2)) == circshift!(A, A, (1,2,2))
A = reshape(collect(1:90), (5,6,3))
B = copy(A)
@test circshift!(B, A, (3,3,1)) == circshift!(A, A, (3,3,1))
B = copy(A)
circshift!(A, A, (0,0,1))
circshift!(A, A, (4,0,0))
circshift!(A, A, (0,1,-1))
@test A == circshift!(B, B, (4,1,0))
end
end; |
Seems like there is nothing concrete here to do. Also https://github.com/JuliaMath/FFTW.jl is moved so fft specific things could be reopened at that repo. |
For various reasons I have large multidimensional complex datasets (sth like 512^3) which I need both in real space and Fourier transformed, both times centered around 0, i.e. separated by ifftshift(fft(fftshift(A))). Allocating a new array for every transform is a waste of good RAM.
I have not found any in-place fftshift so I wrote my own. The basic idea is to exchange four memory places over cross ( a,b = b,a ) which gives an atomically contained operation and the fftshift can be achieved using (almost) exclusively this operation.
Of the n-dimensional array a subset of the axes are to be shifted (named
TS
in the code) and one of these axes has to be iterated only half over (denotedHA
). Actually half of the n-dimensional space has to be iterated over and if split along a not-to-be-shifted axis I cannot use the over-cross exchange operation.The case of an axis of odd length has to be considered on its own. If it is not the half iterated-over axis it is sufficient to formulate the shift parameters correctly. It it is iterated over (indicated by
HAEV
and that is sometimes unavoidable) one element has to be separately saved before the iteration, a lop-sided cross-exchange be used ( a,b-1 = b,a ) and the saved element copied back in. In order that only one element has to be saved in this case the half-length-iteration is pulled into the innemost loop while otherwise the loops are nested as the elements lie in memory (assuming Fortran order).It's called
swaphs2!
not to interfere with the builtinfftshift
andswaphs!
is a doctoredfftshift
based oncircshift!
which cannot operate in-place.Of course, based on this shifted ffts that operate in-place can be formulated quite easily.
Is there any interest in this functionality at all?
And in such a (quite unreadable) approach?
If so I could tinker together a testing suite (I have tested it so far against
fftshift
in quite a number of situations and in benchmarking it reliably beatfftshift
, even withfftshift
s array allocation overhead removed). Also comment the code and maybe structure it more (this current state is optimized for brevity).As a bye the bye question: Should I make such a question/contribution a PR from the start?
The text was updated successfully, but these errors were encountered: