# Efficient way for looping over off-diagonal terms

Hello,

What is the most efficient way of doing the following double loop?

``````function test(N,T)
νtemp = rand(N,T)
v = zeros(N,T)
println(νtemp)
@inbounds for n=1:N, t=1:T
ν[n,t] = νtemp[n,t]
for l=1:N
if (l!=n)
v[n,t] = v[n,t] + 5.0*νtemp[l,t]
end
end
end
return  v
end

``````

I wonder if there is a faster way without using the logical operator.

First of all, get rid of the `println`, that makes the function ~10000x slower!!

Secondly, do you really have to use `ν` here instead of `v`? They look identical in my editor, so there seems to be no point to it, and it cost me a couple of extra minutes to figure out what was going on. Use unicode symbols only when it makes your code significantly more readable, not less, like now.

Thirdly, it’s hard to compare implementations when you generate the random data inside the function. Make `vtemp` outside the function and pass it in.

Finally, here’s an alternative, and comparison:

``````function test(vtemp)
(N, T) = size(vtemp)
v = zeros(N,T)
# println(vtemp)
@inbounds for n=1:N, t=1:T
v[n,t] = vtemp[n,t]
for l=1:N
if (l!=n)
v[n,t] = v[n,t] + 5.0*vtemp[l,t]
end
end
end
return  v
end

function test2(vtest)
s5 = sum(vtest; dims=1)
s5 .*= 5
return s5 .- 4 .* vtest
end

julia> vtemp = rand(100,100);

julia> test(vtemp) ≈ test2(vtemp)
true

julia> @btime test(\$vtemp);
813.427 μs (2 allocations: 78.20 KiB)

julia> @btime test2(\$vtemp);
9.859 μs (3 allocations: 79.08 KiB)
``````

Edit: Actually, you could make it a one-liner with the same performance:

``````test3(vtest) = 5 .* sum(vtest; dims=1) .- 4 .* vtest
``````
3 Likes

Hi,

This is exactly what I was after. Quick question why do you pass \$vtemp as argument instead of vtemp?

What is the logic of this?

It’s a benchmarking thing, related to the BenchmarkTools package, not something you do when you run the code. It’s to avoid type instability issues with global variables.

1 Like

I see. Thanks!