I need to iterate through all sequences of integers between 1 and A
, and of length L
. Here A,L
are positive integers. For example, if A = 2, L = 2
, the sequences are:
[1, 1]
[2, 1]
[1, 2]
[2, 2]
The iteration should be as fast as possible. I was thinking of generating the sequences before-hand, and store them in an L times A^L matrix. Then I can loop through the columns of this matrix (as views).
To test this idea, I created a script, myscript.jl
with the following contents:
struct Sequences
sequences::Array{Int, 2}
end
Base.start(S::Sequences) = 1
Base.done(S::Sequences, state) = state > size(S.sequences, 2)
Base.next(S::Sequences, state) = (view(S.sequences, :, state), state + 1)
Base.eltype(::Type{Sequences}) = SubArray{Int64, 1, Array{Int64, 2}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}
Base.length(S::Sequences) = size(S.sequences, 2)
function sequences_generator(L::Integer, A::Integer)
@assert L > 0
@assert A > 1
(digits.(r, A, L) .+ 1 for r = 0 : A^L - 1)
end
function Sequences(L::Integer, A::Integer)
@assert L > 0 && A > 1
sequences = hcat(collect(sequences_generator(L, A))...)
Sequences(sequences)
end
function do_something(sequences)
Z = 0.
for sequence in sequences
Z += rand()
end
return Z
end
const sequences = Sequences(3, 5)
do_something(sequences) # pre-compile
Profile.clear_malloc_data() # only want to measure allocations of next call, so clean slate.
do_something(sequences)
Then I called this script using julia --track-allocation=user myscript.jl
, which generates a report file called myscript.jl.mem
containing memory allocations per line.
Everything looks fine except for the line Base.next(S::Sequences, state) = (view(S.sequences, :, state), state + 1)
, which is allocating a lot of memory. Any ideas of how I can reduce the allocation footprint here? Or perhaps a different approach I can try?