Indexing an array with rounded array of floating point indexes

I have:

a = rand(Int32, 10, 10)
i = Float32[8.47, 8.47]

and I want access an element e of a using rounded values in i as 2D index. Is there a more concise way of doing it than:

j = Int.(round.(i))
e = a[j[1], j[2]]

There is

a[round.(Int, i)...]

Performance-wise, though,

a[round.(Int, (i[1], i[2]))...]

would be better, as splatting can be done at compile time.

3 Likes

I think the compiler can figure this out just fine if you use eg map:

julia> using BenchmarkTools

julia> round_getindex(a, ι) = a[map(i -> round(Int, i), ι)...]
round_getindex (generic function with 1 method)

julia> round_getindex_dot(a, ι) = a[round.(Ref(Int), ι)...]
round_getindex_dot (generic function with 1 method)

julia> round_getindex2(a, ι) = a[round(Int, ι[1]), round(Int, ι[2])]
round_getindex2 (generic function with 1 method)

julia> a = rand(Int, 100, 100);

julia> ι = (1.1, 3.9)
(1.1, 3.9)

julia> @btime round_getindex($a, $ι)
  5.027 ns (0 allocations: 0 bytes)
9096069683632360821

julia> @btime round_getindex_dot($a, $ι)
  102.631 ns (3 allocations: 48 bytes)
9096069683632360821

julia> @btime round_getindex2($a, $ι)
  5.028 ns (0 allocations: 0 bytes)
9096069683632360821

It runs faster because you are using tuples. My case requires an array, though. Here is what I get:

a = rand(Int, 100, 100)
i = [1.1, 3.9]

round_getindex(a, ι) = a[map(i -> round(Int, i), ι)...]
round_getindex_dot_(a, ι) = a[round.(Int, ι)...]
round_getindex_dot(a, ι) = a[round.(Ref(Int), ι)...]
round_getindex2(a, ι) = a[round(Int, ι[1]), round(Int, ι[2])]

julia> @btime round_getindex($a, $i)
  86.435 ns (4 allocations: 144 bytes)
-1777074699498022323

julia> @btime round_getindex_dot_($a, $i)
  78.898 ns (3 allocations: 128 bytes)
-1777074699498022323

julia> @btime round_getindex_dot($a, $i)
  282.062 ns (10 allocations: 288 bytes)
-1777074699498022323

julia> @btime round_getindex2($a, $i)
  3.363 ns (0 allocations: 0 bytes)
-1777074699498022323

If feasible, consider StaticArrays.SVector if speed is relevant.

1 Like

Fortunately, speed is not a problem. I’m constrained by Makie API:

pos = to_world(scene1, Point2f0(scene1.events.mouseposition[]))

My main objective was to learn a new syntax trick. :slightly_smiling_face: