我有一个带有两个向量字段u
和v
的xy网格。我将矢量字段表示为Array{Float64, 3}
,其尺寸为nx
×ny
×2
。
我想将点积u.v
作为标量字段(Array{Float64,2}
,尺寸为nx
×ny
)。实现这一目标的最佳方法是什么?
像dot(u,v,3)
这样的东西是完美的,其中3是点积的维度。
nx, ny = 3, 4
u = Array{Float64,3}(rand(0:1, nx, ny, 2))
#[0.0 1.0 0.0 1.0; 1.0 0.0 1.0 0.0; 1.0 0.0 1.0 0.0]
#[1.0 0.0 1.0 0.0; 1.0 0.0 0.0 1.0; 1.0 0.0 1.0 1.0]
v = Array{Float64,3}(rand(0:1, nx, ny, 2))
#[1.0 1.0 1.0 1.0; 0.0 1.0 0.0 0.0; 0.0 1.0 1.0 0.0]
#[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 1.0 1.0 1.0 0.0]
[dot(u[i,j,:], v[i,j,:]) for i in 1:nx, j in 1:ny]
3×4 Array{Float64,2}:
1.0 1.0 0.0 1.0
0.0 0.0 0.0 0.0
1.0 0.0 2.0 0.0
答案 0 :(得分:5)
sum(u.*v,3)
(合理)快速和短暂。
要明确获得矩阵,您可以像第squeeze(sum(u.*v,3), 3)
更新:当然,这有分配,如果速度就是一切,则不是最佳答案。在这种情况下,请参阅@ DNF的直接循环实现,它基本上与您可以获得的速度一样快。
答案 1 :(得分:4)
squeeze(sum(u .* v, 3), 3)
干净简单,但如果你需要更快的速度,这在我的电脑上快了大约20倍:
a = fill(zero(eltype(u)), nx, ny)
@inbounds for k in indices(u, 3)
for j in indices(u, 2)
for i in indices(u, 1)
a[i, j] += u[i, j, k] * v[i, j, k]
end
end
end
修改:为了更轻松地进行基准比较,请尝试以下代码:
function dotsum3(u, v)
a = fill(zero(eltype(u)), size(u, 1), size(u, 2))
@inbounds for k in indices(u, 3)
for j in indices(u, 2)
for i in indices(u, 1)
a[i, j] += u[i, j, k] * v[i, j, k]
end
end
end
return a
end
另请注意,如果使用@inbounds
,则应明确检查u
和v
的尺寸是否兼容。
答案 2 :(得分:1)
另一个版本是
a = copy(view(u,:,:,1))
a .*= view(v,:,:,1)
a .+= @views u[:,:,2].*v[:,:,2]
可以轻松扩展到任意第三维长度。我机器的基准测试:
julia> using BenchmarkTools
julia> function f1(u,v)
a = fill(zero(eltype(u)), nx, ny)
@inbounds for k in indices(u, 3)
for j in indices(u, 2)
for i in indices(u, 1)
a[i, j] += u[i, j, k] * v[i, j, k]
end
end
end
return a
end
f1 (generic function with 1 method)
julia> f2(u,v) = squeeze(sum(u .* v, 3), 3)
f2 (generic function with 1 method)
julia> function f3(u,v)
a = copy(view(u,:,:,1))
a .*= view(v,:,:,1)
a .+= @views u[:,:,2].*v[:,:,2]
return a
end
f3 (generic function with 1 method)
julia> nx, ny = 3, 4
(3, 4)
julia> u = Array{Float64,3}(rand(0:1, nx, ny, 2));
julia> v = Array{Float64,3}(rand(0:1, nx, ny, 2));
计时结果:
julia> @btime f1($u,$v); # DNF suggestion
1.016 μs (1 allocation: 176 bytes)
julia> @btime f2($u,$v); # original answer
1.263 μs (14 allocations: 816 bytes)
julia> @btime f3($u,$v); # this answer
168.591 ns (5 allocations: 432 bytes)
建议的版本更快(考虑到Julia Arrays的内存排序,这是合乎逻辑的)。