Yes, but these are done at the matrix-matrix level. Here I am arguing for consistent associativity at the expression level. I’m arguing for only([x;;] * [y;;] * [z;;]) == x*y*z == (x*y)*z
, which is still compatible with internal reassociations of matrix-matrix multiplication.
I think that writing A * (B * x)
to force right-associativity is less onerous than hoping (or counting on the fact that) that A * B * x
quietly right-associates. It’s also less surprising when it does.
The overwhelming majority of the time, people are simply applying floating point operations to implement math-on-reals and haven’t given thought to this and they won’t notice or care if we re-order stuff for speed. But in very few cases people really do care and this reassociation isn’t documented well enough (in my opinion) that people can be aware of it.
Also, I’m reminded of #52333 and the hazard identified there. In that spirit, see this example:
julia> using Octonions
julia> x = Octonion(1,2,3,4,5,6,7,8); y = Octonion(1,-2,3,4,5,6,7,8); z = Octonion(1,2,-3,4,5,6,7,8);
julia> [x;;] * [y;;] * [z;;]
1Ă—1 Matrix{Octonion{Int64}}:
Octonion{Int64}(-652, -1064, 612, -736, -860, -1128, -1036, -1712)
julia> [x;;] * [y;;] * [z;] # re-assocation changes the value
1-element Vector{Octonion{Int64}}:
Octonion{Int64}(-652, -1064, 612, -736, -1148, -888, -1420, -1376)
Reassociation outside of very controlled contexts is a significant hazard.
I think N-ary *
is a failed experiment, or very close to one. By association, I’m worried about N-ary +
and ++
as well, although those operations are more-commonly associative.