2017-05-05 64 views
6

每个矩阵I具有3维阵列朱莉娅乘以沿着昏暗

x = rand(6,6,2^10) 

我想由矢量乘以沿着第三维中的每个矩阵。是否有一个更清洁的方式来做到这一点比:

y = rand(6,1) 
z = zeros(6,1,2^10) 
for i in 1:2^10 
    z[:,:,i] = x[:,:,i] * y 
end 

回答

6

如果使用矩阵工作,也可适当将x视为矩阵的向量而不是3D阵列。那么你可以做

x = [rand(6,6) for _ in 1:2^10] 
y = [rand(6)] 
z = x .* y 

z现在是一个载体的载体。

如果z预先分配,这将是

z .= x .* y 

而且,如果你想它的真快,使用这显示在我的电脑上10倍的加速比StaticArrays

using StaticArrays 

x = [@SMatrix rand(6, 6) for _ in 1:2^10] 
y = [@SVector rand(6)] 
z = x .* y 

载体,运行在12us。

+0

'_'如何在理解中工作? –

+1

这只是一个虚拟变量。例如,我可以使用'i',但通常让'_'表示一个一次性使用的变量,它不被进一步使用,并且哪个名称不重要。 – DNF

7

mapslices(i->i*y, x, (1,2))也许是“清洁”,但它会慢一些。

读为:将函数“times by y”应用于前两个维度的每个切片。

function tst(x,y) 
    z = zeros(6,1,2^10) 
    for i in 1:2^10 
     z[:,:,i] = x[:,:,i] * y 
    end 
    return z 
end 

tst2(x,y) = mapslices(i->i*y, x, (1,2)) 

time tst(x,y); 0.002152秒(4.10ķ分配:624.266 KB)

@time tst2(x,y); 0.005720秒(13.36ķ分配:466.969 KB)

+0

我会同意这个解决方案更“干净”,但另一方面我也不清楚发生了什么。 –

+0

也许...虽然我会同意@DNF,如果你只是想迭代这个维度,那么矩阵的矢量将更具可读性。 –

3

sum(x.*y',2)是一个简洁的解决方案。

它也具有良好的速度和记忆性能。诀窍是将矩阵向量乘法看作由向量元素缩放的矩阵列的线性组合。我们对x [:,i:]使用相同的尺度y [i],而不是对矩阵x [:,:i]做每个线性组合。在代码:

const x = rand(6,6,2^10); 
const y = rand(6,1); 
function tst(x,y) 
    z = zeros(6,1,2^10) 
    for i in 1:2^10 
     z[:,:,i] = x[:,:,i]*y 
    end 
    return z 
end 
tst2(x,y) = mapslices(i->i*y,x,(1,2)) 
tst3(x,y) = sum(x.*y',2) 

标杆得出:使用

julia> using BenchmarkTools 
julia> z = tst(x,y); z2 = tst2(x,y); z3 = tst3(x,y); 
julia> @benchmark tst(x,y) 
    BenchmarkTools.Trial: 
    memory estimate: 688.11 KiB 
    allocs estimate: 8196 
    -------------- 
    median time:  759.545 μs (0.00% GC) 
    samples:   6068 
julia> @benchmark tst2(x,y) 
    BenchmarkTools.Trial: 
    memory estimate: 426.81 KiB 
    allocs estimate: 10798 
    -------------- 
    median time:  1.634 ms (0.00% GC) 
    samples:   2869 
julia> @benchmark tst3(x,y) 
    BenchmarkTools.Trial: 
    memory estimate: 336.41 KiB 
    allocs estimate: 12 
    -------------- 
    median time:  114.060 μs (0.00% GC) 
    samples:   10000 

所以tst3sum具有更好的性能(〜7倍以上tst和15X〜在tst2)。

按@DNF的建议使用StaticArrays也是一种选择,并且将它与此处的解决方案进行比较将会很好。

+1

'reducedim(+,x。* y',2)'和'sum(x。* y',2)'是否有区别? – DNF

+0

不是。嗯,是的,'sum'比较好。我将编辑以反映这一点。谢谢。 –

+0

顺便说一句,要真正优化,将索引的顺序改为(6,2^10,6),并使用循环和'@ inbounds'手动编码操作可以获得另一个** 10x **。这是为了使内存布局和索引计算更容易。 –