快速索引数组

amr*_*ods 4 arrays indexing julia

访问(也许替换)大型多维数组中的条目的最有效方法是什么?我在循环中使用这样的东西:

tup = (16,45,6,40,3)
A[tup...] = 100
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有更有效的方法.特别是,有什么方法可以避免使用...

Dav*_*ers 5

要迭代多维数组,建议这样做for index in eachindex(A); 见例如

https://groups.google.com/forum/#!msg/julia-users/CF_Iphgt2Wo/V-b31-6oxSkJ

如果A是标准数组,那么这对应于使用单个整数进行索引,这是访问数组的最快方式(原始问题):

A = rand(3, 3)

for i in eachindex(A)
   println(i)
end
Run Code Online (Sandbox Code Playgroud)

但是,如果A是一个更复杂的对象,例如子阵列,那么eachindex(A)将为您提供一个不同的,高效的访问对象:

julia> for i in eachindex(slice(A, 1:3, 2:3))
           println(i)
       end
Run Code Online (Sandbox Code Playgroud)

CartesianIndex{2}((1,1))
CartesianIndex{2}((2,1))
Run Code Online (Sandbox Code Playgroud)

等等


Mat*_* B. 5

splatting并不总是会受到惩罚,但确定它的效率并不总是显而易见(或容易).你的琐碎例子实际上和写作一样有效A[16,45,6,40,3] = 100.你可以通过比较看到这一点

   function f(A)
       tup = (16,45,6,40,3)
       A[tup...] = 100
       A
   end
   function g(A)
       A[16,45,6,40,3] = 100
       A
   end
julia> code_llvm(f, Tuple{Array{Int, 5}})
# Lots of output (bounds checks).
julia> code_llvm(g, Tuple{Array{Int, 5}})
# Identical to above
Run Code Online (Sandbox Code Playgroud)

如果有一个泼溅惩罚,你会以分配的形式看到它.您可以使用@allocated宏来测试这个,或者只是检查code_llvm一个引用@jl_pgcstack- 这就是垃圾收集器,这在任何时候都需要分配.请注意,在更复杂的函数中很可能还会导致分配,因此它的存在并不一定意味着存在splatting悲观化.但如果这是一个热循环,你想最小化所有分配,所以它是一个伟大的目标......即使你的问题不是由于splatting.您也应该使用@code_warntype,因为类型不好的代码肯定会使splats和许多其他操作失望.如果您的元组输入不好,将会发生以下情况:

   function h(A)
       tup = ntuple(x->x+1, 5) # type inference doesn't know the type or size of this tuple
       A[tup...] = 100
       A
   end
julia> code_warntype(h, Tuple{Array{Int,5}})
# Lots of red flags
Run Code Online (Sandbox Code Playgroud)

所以优化这个splat将高度依赖于你如何构建或获得tup.