利用广播Julia实现向量到矩阵的转换
我是一个julia新手,有一个小任务要写一个函数,将向量向量转换成矩阵。通过迭代元素,这是非常容易做到的 然而,我读到广播往往更有效率。但我不确定这里怎么做,因为.=操作无法工作,因为它会将向量读取为一个1×n数组,因此尝试在两个不同长度的数组上广播 有广播的方法吗 我的代码在下面利用广播Julia实现向量到矩阵的转换,julia,Julia,我是一个julia新手,有一个小任务要写一个函数,将向量向量转换成矩阵。通过迭代元素,这是非常容易做到的 然而,我读到广播往往更有效率。但我不确定这里怎么做,因为.=操作无法工作,因为它会将向量读取为一个1×n数组,因此尝试在两个不同长度的数组上广播 有广播的方法吗 我的代码在下面 function vecvec_to_matrix(vecvec) dim1 = length(vecvec) dim2 = length(vecvec[1]) my_array = zero
function vecvec_to_matrix(vecvec)
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = zeros(Int64, dim1, dim2)
for i in 1:dim1
for j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
end
return my_array
end
你的方式已经是直观和快速的了。您可以使用一些
@inbounds
来提高性能,仅此而已<代码>vcat也很快。我认为在你的情况下广播是不必要的。你
以下是我能想到的各种方法的一些基准
function vecvec_to_matrix(vecvec)
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = zeros(Int64, dim1, dim2)
for i in 1:dim1
for j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
end
return my_array
end
function vecvec_to_matrix2(vecvec::AbstractVector{T}) where T <: AbstractVector
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = Array{eltype(vecvec[1]), 2}(undef, dim1, dim2)
@inbounds @fastmath for i in 1:dim1, j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
return my_array
end
function vecvec_to_matrix3(vecvec::AbstractVector{T}) where T <: AbstractVector
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = Array{eltype(vecvec[1]), 2}(undef, dim1, dim2)
Threads.@threads for i in 1:dim1
for j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
end
return my_array
end
using Tullio
function using_tullio(vecvec::AbstractVector{T}) where T <: AbstractVector
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = Array{eltype(vecvec[1]), 2}(undef, dim1, dim2)
@tullio my_array[i, j] = vecvec[i][j]
my_array
end
function using_vcat(vecvec::AbstractVector{T}) where T <: AbstractVector
vcat(vecvec...)
end
using BenchmarkTools
vecvec =[rand(Int, 100) for i in 1:100];
@benchmark vecvec_to_matrix(vecvec)
@benchmark vecvec_to_matrix2(vecvec)
@benchmark vecvec_to_matrix3(vecvec)
@benchmark using_tullio(vecvec)
@benchmark using_vcat(vecvec)
你的方式已经是直观和快速的了。您可以使用一些
@inbounds
来提高性能,仅此而已<代码>vcat也很快。我认为在你的情况下广播是不必要的。你
以下是我能想到的各种方法的一些基准
function vecvec_to_matrix(vecvec)
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = zeros(Int64, dim1, dim2)
for i in 1:dim1
for j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
end
return my_array
end
function vecvec_to_matrix2(vecvec::AbstractVector{T}) where T <: AbstractVector
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = Array{eltype(vecvec[1]), 2}(undef, dim1, dim2)
@inbounds @fastmath for i in 1:dim1, j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
return my_array
end
function vecvec_to_matrix3(vecvec::AbstractVector{T}) where T <: AbstractVector
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = Array{eltype(vecvec[1]), 2}(undef, dim1, dim2)
Threads.@threads for i in 1:dim1
for j in 1:dim2
my_array[i,j] = vecvec[i][j]
end
end
return my_array
end
using Tullio
function using_tullio(vecvec::AbstractVector{T}) where T <: AbstractVector
dim1 = length(vecvec)
dim2 = length(vecvec[1])
my_array = Array{eltype(vecvec[1]), 2}(undef, dim1, dim2)
@tullio my_array[i, j] = vecvec[i][j]
my_array
end
function using_vcat(vecvec::AbstractVector{T}) where T <: AbstractVector
vcat(vecvec...)
end
using BenchmarkTools
vecvec =[rand(Int, 100) for i in 1:100];
@benchmark vecvec_to_matrix(vecvec)
@benchmark vecvec_to_matrix2(vecvec)
@benchmark vecvec_to_matrix3(vecvec)
@benchmark using_tullio(vecvec)
@benchmark using_vcat(vecvec)
如果你的向量是短的和固定大小的(例如,在3个维度中的点列表),那么你应该强烈地考虑使用,然后调用<代码>重新解释< /代码>。演示:
julia> using StaticArrays
julia> A = rand(3, 8)
3×8 Array{Float64,2}:
0.153872 0.361708 0.39703 0.405625 0.0881371 0.390133 0.185328 0.585539
0.467841 0.846298 0.884588 0.798848 0.14218 0.156283 0.232487 0.22629
0.390566 0.897737 0.569882 0.491681 0.499163 0.377012 0.140902 0.513979
julia> reinterpret(SVector{3,Float64}, A)
1×8 reinterpret(SArray{Tuple{3},Float64,1,3}, ::Array{Float64,2}):
[0.153872, 0.467841, 0.390566] [0.361708, 0.846298, 0.897737] [0.39703, 0.884588, 0.569882] … [0.390133, 0.156283, 0.377012] [0.185328, 0.232487, 0.140902] [0.585539, 0.22629, 0.513979]
julia> B = vec(copy(ans))
8-element Array{SArray{Tuple{3},Float64,1,3},1}:
[0.1538721224514592, 0.467840786943454, 0.39056612358281706]
[0.3617079493961777, 0.8462982350893753, 0.8977366743282564]
[0.3970299970547111, 0.884587972864584, 0.5698823030478959]
[0.40562472747685074, 0.7988484677138279, 0.49168126614394647]
[0.08813706434793178, 0.14218012559727544, 0.499163319341982]
[0.3901332827772166, 0.15628284837250006, 0.3770117394226711]
[0.18532803309577517, 0.23248748941275688, 0.14090166962667428]
[0.5855387782654986, 0.22628968661452897, 0.5139790762185006]
julia> reshape(reinterpret(Float64, B), (3, 8))
3×8 reshape(reinterpret(Float64, ::Array{SArray{Tuple{3},Float64,1,3},1}), 3, 8) with eltype Float64:
0.153872 0.361708 0.39703 0.405625 0.0881371 0.390133 0.185328 0.585539
0.467841 0.846298 0.884588 0.798848 0.14218 0.156283 0.232487 0.22629
0.390566 0.897737 0.569882 0.491681 0.499163 0.377012 0.140902 0.513979
如果你的向量是短的和固定大小的(例如,在3个维度中的点列表),那么你应该强烈地考虑使用,然后调用<代码>重新解释< /代码>。演示:
julia> using StaticArrays
julia> A = rand(3, 8)
3×8 Array{Float64,2}:
0.153872 0.361708 0.39703 0.405625 0.0881371 0.390133 0.185328 0.585539
0.467841 0.846298 0.884588 0.798848 0.14218 0.156283 0.232487 0.22629
0.390566 0.897737 0.569882 0.491681 0.499163 0.377012 0.140902 0.513979
julia> reinterpret(SVector{3,Float64}, A)
1×8 reinterpret(SArray{Tuple{3},Float64,1,3}, ::Array{Float64,2}):
[0.153872, 0.467841, 0.390566] [0.361708, 0.846298, 0.897737] [0.39703, 0.884588, 0.569882] … [0.390133, 0.156283, 0.377012] [0.185328, 0.232487, 0.140902] [0.585539, 0.22629, 0.513979]
julia> B = vec(copy(ans))
8-element Array{SArray{Tuple{3},Float64,1,3},1}:
[0.1538721224514592, 0.467840786943454, 0.39056612358281706]
[0.3617079493961777, 0.8462982350893753, 0.8977366743282564]
[0.3970299970547111, 0.884587972864584, 0.5698823030478959]
[0.40562472747685074, 0.7988484677138279, 0.49168126614394647]
[0.08813706434793178, 0.14218012559727544, 0.499163319341982]
[0.3901332827772166, 0.15628284837250006, 0.3770117394226711]
[0.18532803309577517, 0.23248748941275688, 0.14090166962667428]
[0.5855387782654986, 0.22628968661452897, 0.5139790762185006]
julia> reshape(reinterpret(Float64, B), (3, 8))
3×8 reshape(reinterpret(Float64, ::Array{SArray{Tuple{3},Float64,1,3},1}), 3, 8) with eltype Float64:
0.153872 0.361708 0.39703 0.405625 0.0881371 0.390133 0.185328 0.585539
0.467841 0.846298 0.884588 0.798848 0.14218 0.156283 0.232487 0.22629
0.390566 0.897737 0.569882 0.491681 0.499163 0.377012 0.140902 0.513979
vcat
将产生不同形状的结果(它将叠加向量)。另外,编写reduce(vcat,vecvec)
更有效一些,但您可能希望transpose(reduce(hcat,x))
获得正确的形状。reduce是reduce更有效吗?是的,因为没有reduce,您就是在浪费,reduce避免了它。这可能只在有数千个元素需要splat时才重要(否则,您将向vcat
传递数千个位置参数)。vcat
将产生不同形状的结果(它将堆叠向量)。另外,编写reduce(vcat,vecvec)
更有效一些,但您可能希望transpose(reduce(hcat,x))
获得正确的形状。reduce是reduce更有效吗?是的,因为没有reduce,您就是在浪费,reduce避免了它。可能只有当您有数千个元素需要splat时(否则您将向vcat
传递数千个位置参数)。代码中最大的性能瓶颈是内存布局。您将vecvec
vector中的向量存储为my_array
的行,在Julia中,按列处理数据更有效(因此,如果您将它们存储在列中,则使用例如reduce(hcat,vecvec)
会更快,如下所述)。广播的效率并不比迭代更高。不管怎样,广播都会在幕后进行迭代。代码中最大的性能瓶颈是内存布局。您将vecvec
vector中的向量存储为my_array
的行,在Julia中,按列处理数据更有效(因此,如果您将它们存储在列中,则使用例如reduce(hcat,vecvec)
会更快,如下所述)。广播的效率并不比迭代更高。不管怎么说,广播在幕后也不起作用。