Julia中的多维差异/梯度

时间:2015-02-22 18:24:40

标签: multidimensional-array julia numerical-methods

我正在寻找一种有效的方法来计算Julia中多维数组的导数。确切地说,我想在朱莉娅中有numpy.gradient的等价物。但是,Julia函数diff

  • 仅适用于二维数组
  • 沿着差异维度将数组的大小减小一个

直接扩展Julia diff的定义,以便它可以在三维数组上工作,例如与

function diff3D(A::Array, dim::Integer)
    if dim == 1
        [A[i+1,j,k] - A[i,j,k] for i=1:size(A,1)-1, j=1:size(A,2), k=1:size(A,3)]
    elseif dim == 2
       [A[i,j+1,k] - A[i,j,k] for i=1:size(A,1), j=1:size(A,2)-1, k=1:size(A,3)]
    elseif dim == 3
       [A[i,j,k+1] - A[i,j,k] for i=1:size(A,1), j=1:size(A,2), k=1:size(A,3)-1]
    else
        throw(ArgumentError("dimension dim must be 1, 2, or 3 got $dim"))
    end
end

可以使用例如

a = [i*j*k for i in 1:10, j in 1:10, k in 1:20]

但是,无法扩展到任意尺寸,并且不考虑边界,因此渐变可以与原始数组具有相同的尺寸。

我有一些想法可以在Julia中实现numpy渐变的类比,但是我担心它们会非常缓慢和丑陋,因此我的问题是:在Julia中我是否有一种规范的方法可以做到这一点我错过了?如果没有,那么最佳的是什么?

感谢。

2 个答案:

答案 0 :(得分:4)

我对diff并不太熟悉,但据我所知,我做了一个n维实现,使用Julia功能,如参数类型和splatting:

function mydiff{T,N}(A::Array{T,N}, dim::Int)
    @assert dim <= N
    idxs_1 = [1:size(A,i) for i in 1:N]
    idxs_2 = copy(idxs_1)
    idxs_1[dim] = 1:(size(A,dim)-1)
    idxs_2[dim] = 2:size(A,dim)
    return A[idxs_2...] - A[idxs_1...]
end

进行一些健全性检查:

A = rand(3,3)
@assert diff(A,1) == mydiff(A,1)  # Base diff vs my impl.
@assert diff(A,2) == mydiff(A,2)  # Base diff vs my impl.

A = rand(3,3,3)
@assert diff3D(A,3) == mydiff(A,3)  # Your impl. vs my impl.

请注意,有更多神奇的方法可以做到这一点,例如使用代码生成来制作有限维度的专用方法,但我认为可能不需要获得足够好的性能。

答案 1 :(得分:1)

更简单的方法:

mydiff(A::AbstractArray,dim) = mapslices(diff, A, dim)

不确定这在速度方面会如何比较。

编辑:可能稍慢,但这是将功能扩展到更高阶数组的更通用的解决方案:

julia> using BenchmarkTools

julia> function mydiff{T,N}(A::Array{T,N}, dim::Int)
           @assert dim <= N
           idxs_1 = [1:size(A,i) for i in 1:N]
           idxs_2 = copy(idxs_1)
           idxs_1[dim] = 1:(size(A,dim)-1)
           idxs_2[dim] = 2:size(A,dim)
           return A[idxs_2...] - A[idxs_1...]
       end
mydiff (generic function with 1 method)

julia> X = randn(500,500,500);

julia> @benchmark mydiff($X,3)
BenchmarkTools.Trial: 
  samples:          3
  evals/sample:     1
  time tolerance:   5.00%
  memory tolerance: 1.00%
  memory estimate:  2.79 gb
  allocs estimate:  22
  minimum time:     2.05 s (15.64% GC)
  median time:      2.15 s (14.62% GC)
  mean time:        2.16 s (11.05% GC)
  maximum time:     2.29 s (3.61% GC)

julia> @benchmark mapslices(diff,$X,3)
BenchmarkTools.Trial: 
  samples:          2
  evals/sample:     1
  time tolerance:   5.00%
  memory tolerance: 1.00%
  memory estimate:  1.99 gb
  allocs estimate:  3750056
  minimum time:     2.52 s (7.90% GC)
  median time:      2.61 s (9.17% GC)
  mean time:        2.61 s (9.17% GC)
  maximum time:     2.70 s (10.37% GC)