I am trying to battle, overcome regressions when moving to Julia 0.7. Let’s say I have the function
function next_collision(
p::AbstractParticle{T}, bt::Tuple)::Tuple{T,Int} where {T}
tmin::T = T(Inf)
ind::Int = 0
for i in eachindex(bt)
tcol::T = collisiontime(p, bt[i])
# Set minimum time:
if tcol < tmin
tmin = tcol
ind = i
end
end#obstacle loop
return tmin, ind
end
I want to make it faster because doing bt[i]
isn’t very good. That is because the elements of the tuple bt
are not the same type. They are all subtypes of the same abstract type, but they are not the same concrete type.
I thought I could use metaprogramming to “unroll” the loop, something similar with the package Unrolled.jl.
But I think I don’t know how to get the length of a tuple by its type?.. This is what I have:
@generated function next_collision3(p::AbstractParticle{T}, bt::TUP) where {T, TUP}
L = length(TUP)
quote
i::Int = 0; ind::Int = 0
tmin::T = T(Inf)
for i in 1:L
let x = bt[i]
tcol::T = collisiontime(p, x)
# Set minimum time:
if tcol < tmin
tmin = tcol
ind = i
end
end
end
end
end
bt
is a Tuple. But length(TUP)
doesn’t work. But the actual length of a tuple is know by its type, right?
EDIT: The answer of how to do this, by slightly modifying an answer by @mauro3, is:
@generated function next_collision(p::AbstractParticle{T}, bt::TUP) where {T, TUP}
L = fieldcount(TUP)
out = quote
i = 0; ind = 0
tmin = T(Inf)
end
for j=1:L
push!(out.args,
quote
let x = bt[$j]
tcol = collisiontime(p, x)
# Set minimum time:
if tcol < tmin
tmin = tcol
ind = $j
end
end
end
)
end
push!(out.args, :(return tmin, ind))
return out
end
The result is non allocating and almost perfectly benchmarks equal to the sum of doing the collisiontime
individually for each entry in the tuple.