I've tried the following.
a = randn(100,100);
b = randn(100,100);
c = randn(100,1);
@time a*b*c
@time a*(b*c)
Results
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)
Results are quite consistent with the above. While it does make intuitive sense why the the second one is better (A matrix-vector multiplication twice instead of a large matrix-matrix multiplication).
I was wondering, shouldn't Julia have optimized this knowing that the dimensions of the matrices and it could've reordered the operation to have optimized it? Or am I just being too lazy to wish for that or are there other technical issues that I don't see.
So, this is what I get when I use dump() on (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
So, is there an issue trying to optimize on this assuming operators are associative? Does it become very complex or intractable otherwise?