在Julia中高效地按行对向量矩阵元素逐个相乘

5

我希望将矩阵A的每一行乘以相同的向量v。例如:

A =[1.0 3.0; 1.0 1.0]
v = [1.0, 2.0]

我想要输出。
 [1.0 6.0; 1.0 2.0]

到目前为止,我正在进行以下工作:

(v.*A')'

但是我怀疑这种方法在计算效率上并不高,因为它需要将矩阵转置两次。

需要注意的是,这个问题在Matlab中已经有了答案(https://uk.mathworks.com/matlabcentral/answers/243307-vector-matrix-multiplication-row-wise)。


2
A.*v' 对我来说可行(Julia v0.6.3) - Dan Getz
另外请注意,向量乘法有许多种不同的形式。根据您的示例,您正在将A的每一列乘以不同的标量,以符合v。感谢您提供代码和示例,使问题更加清晰明了。 - Dan Getz
1
@DanGetz,仅作为一条注释,A.*v'在我的机器上(相同的Julia版本)比(v.*A')'略慢,这是出乎意料的。 - carstenbauer
一个人也可以执行 mapslices(row->v.*row, A, 2),但是这个方法比已经提到的方法更慢。 - carstenbauer
1
@DanGetz,我的错,基准测试中犯了一个错误。 - carstenbauer
2个回答

5

您至少有以下几个选项:

  • (v.*A')'(建议采用OP的方法)
  • v'.*A最短的方式
  • mapslices(row->v.*row, A, 2)
  • @AborAmmar的帖子中的手动实现(最快的方式

function tt(v, A)
    r = similar(A)
    @inbounds for j = 1:size(A,2) 
        @simd for i = 1:size(A,1) 
            r[i,j] = v[j] * A[i,j] # fixed a typo here!
        end
    end 
    r
end 

速度比较(按升序排列)

julia> @btime tt($v,$A); # @AborAmmar's answer
  38.826 ns (1 allocation: 112 bytes)

julia> @btime ($v)'.*$A;               
  49.920 ns (1 allocation: 112 bytes)

julia> @btime (($v).*($A)')';           
  123.797 ns (3 allocations: 336 bytes)                           

julia> @btime mapslices(row->($v).*row, $A, 2);
  25.174 μs (106 allocations: 5.16 KiB)

编辑:采用了@AborAmmar的帖子中更仔细和更快速的手工实现(替换旧版),并更新了速度比较。


我已经更正了一个打字错误,应该是 v[j] 而不是 v[i] - AboAmmar

3

Julia真正令人惊叹的是,您可以创建具有与高度优化的内置函数相同性能的自定义函数。以下是另一种实现方式,其性能与(v' .* A)相同(甚至略优):

function tt1(v, A)
    v'.*A
end

function tt(v, A)
    r = similar(A)
    @inbounds for j = 1:size(A,2) 
        @simd for i = 1:size(A,1) 
            r[i,j] = v[j] * A[i,j]
        end
    end 
    r
end   

const n = 10^4
const A = rand(n,n)
const v = rand(n)

@time tt1(v, A);
@time tt(v, A);

  0.283537 seconds (6 allocations: 762.940 MiB, 19.70% gc time)
  0.235699 seconds (6 allocations: 762.940 MiB, 0.44% gc time)

我在我的帖子中引用并添加了你的版本以进行基准测试。 - carstenbauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接