为什么强制执行Julia矩阵向量乘法的顺序加快了?

时间:2017-11-13 05:56:03

标签: julia

我尝试了以下内容。

a = randn(100,100);
b = randn(100,100);
c = randn(100,1);

@time a*b*c
@time a*(b*c)

结果

julia> @time a*b*c;
  0.000591 seconds (7 allocations: 79.234 KiB)

julia> @time a*(b*c);
  0.000101 seconds (6 allocations: 1.906 KiB)

结果与上述结果非常一致。虽然它确实直观地理解为什么第二个更好(矩阵向量乘法两次而不是大矩阵 - 矩阵乘法)。

我很想知道,朱莉娅不应该优化这一点,知道矩阵的尺寸,它可以重新排序操作以优化它吗?或者我只是懒得想要那个或者是否有其他我没有看到的技术问题。

所以,这是我在dump()

上使用(a*b*c)时得到的结果
  head: Symbol call
  args: Array{Any}((4,))
    1: Symbol *
    2: Array{Float64}((100, 100)) [0.290788 -0.0601455 … -0.408164 1.16261; -0.539274 -1.56979 … 2.56233 0.806247; … ; 1.30981 -1.31929 … 1.38655 -1.89169; -1.58483 0.318804 … -0.0500151 2.13105]
    3: Array{Float64}((100, 100)) [-0.464882 1.60371 … -0.390234 0.605401; -1.06837 0.296049 … 0.759708 0.0124688; … ; -0.149613 -1.38653 … 0.284494 1.47524; 0.34351 0.420449 … 0.544973 1.85736]
    4: Array{Float64}((100, 1)) [1.64066; 0.593296; … ; 0.908361; 0.486164]
  typ: Any

dump(a*(b*c))

Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol *
    2: Array{Float64}((100, 100)) [0.290788 -0.0601455 … -0.408164 1.16261; -0.539274 -1.56979 … 2.56233 0.806247; … ; 1.30981 -1.31929 … 1.38655 -1.89169; -1.58483 0.318804 … -0.0500151 2.13105]
    3: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol *
        2: Array{Float64}((100, 100)) [-0.464882 1.60371 … -0.390234 0.605401; -1.06837 0.296049 … 0.759708 0.0124688; … ; -0.149613 -1.38653 … 0.284494 1.47524; 0.34351 0.420449 … 0.544973 1.85736]
        3: Array{Float64}((100, 1)) [1.64066; 0.593296; … ; 0.908361; 0.486164]
      typ: Any
  typ: Any

那么,假设运算符是关联的,是否存在尝试优化此问题的问题?它会变得非常复杂或难以处理吗?

1 个答案:

答案 0 :(得分:3)

编辑:整个答案假定*是Julia中的二元运算符。 这是不正确的,因此OP问题完全有效。有关一些讨论,请参阅https://discourse.julialang.org/t/is-there-any-way-to-make-custom-binary-infix-operators-right-associative/3202/5(特别提到*被解析为n-arry,which can be seen here)。我将在下面留下原来的答案。

矩阵 - 矩阵乘法需要n^3步(对于小矩阵)。矩阵向量乘法需要n^2步。

a*b*c(a*b)*c相同,后者共执行n^3+n^2次操作,a*(b*c)执行2*n^2次操作,因为它只包含矩阵向量乘法

如果您想要自动优化矩阵代数表达式,可以尝试像https://github.com/Jutho/TensorOperations.jl这样的库(谷歌首次针对这类问题点击)。评论中提到的另一个选项是https://github.com/AustinPrivett/MatrixChainMultiply.jl

至于Julia为什么不自动执行此操作:这必须是解析器的一部分(运算符的优先级),但是您不希望解析器能够在运行时内部查看以了解对象是什么是。另一方面,这可以通过在编译之前应用宏来实现,如上述包所做的那样。也许如果你使用一些编译时类型信息也是可行的,但是对于朱莉娅优雅的多分派机制中的几种类型而言,这将是一个相当丑陋的特例。