I am having difficulties to understand how to best avoid local memory allocation. Here is some code based on CartesianIndices, which works really fast and nicely as it is NOT allocating extra memory:
using LinearAlgebra, StaticArrays
import AbstractFFTs.fftshift
@inline function myrad(MyIndices::CartesianIndex{N}) where {N}
norm(Tuple(MyIndices),2);
end
@inline function fftshift(ind::CartesianIndex{N},asize::CartesianIndex{N})::CartesianIndex{N} where {N}
ind+CartesianIndex((ind.I .> div.(asize.I,2)).*(asize.I .- 2 .* ind.I) .- 1);
end
A=zeros(200,100,100);
sz=last(CartesianIndices(A))
myfkt(I)=myrad(fftshift(I,sz))
@time myr=[myfkt(I) for I in CartesianIndices(A)]; # pretty cool and fast code
As one may guess, the aim would be to replace the time-consuming Fourier-shift with a nice view concept. The deamt of usage would be
generate(myrad(fftshift(CalcIndices(mysize))));
So I started wrinting a type to do this, which however then became really inefficient:
# now, lets make a class for even more simple usage:
struct CalcIndices{T<:Number,N}
A::AbstractArray{T,N}
mysize::NTuple{N,Int}
FunctionList # concatinated function list
end
@inline function CalcIndicesIdentity(CI::CartesianIndex{N})::CartesianIndex{N} where {N}
CI
end
@inline function CalcIndices(A::AbstractArray{T,N})::CalcIndices where {T,N}
CalcIndices(A,NTuple(size(A)),nothing)
end
@inline function fftshift(CI::CalcIndices{T,N})::CalcIndices{T,N} where {T,N}
if CI.FunctionList==nothing
myFkt=F->fftshift(F::CartesianIndex{N},CartesianIndex(CI.mysize...));
else
myFkt=F->fftshift(CI.FunctionList(F::CartesianIndex{N}),CartesianIndex(CI.mysize...));
end
CalcIndices(CI.A,NTuple(size(CI.A)),myFkt)
end
@inline function myrad(CI::CalcIndices{T,N})::CalcIndices{T,N} where {T,N}
if CI.FunctionList==nothing
myFkt=F->myrad(F);
else
myFkt=F->myrad(CI.FunctionList(F));
end
# myFkt=myrad;
CalcIndices(CI.A,CI.mysize,myFkt)
end
@inline function generate(CI::CalcIndices)
myFktList=CI.FunctionList;
myr=[myFktList(I) for I in CartesianIndices(CI.A)];
end
# Try it out:
A=zeros(200,100,100);
myCI=myrad(fftshift(CalcIndices(A))) # too much memory consumed
@time A=generate(myCI) # BAD: Uses 167 Mb instead of 15 Mb
However, if I do not stack the functions, (either fftshift or myrad), the result is again fine:
myCI=myrad(CalcIndices(A)) # low mem and fast again.
@time A=generate(myCI)
Does anyone have an idea how to modify the class so that it does not use any extra memory even if several function calls are stacked? Or is there any other elegand mechanism to achieve a similar effect in Julia?