-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Array+Scalar elementwise operations #6417
Comments
There was a very long debate at JuliaLang/LinearAlgebra.jl#75, where we got to this consensus. The decision was based on deep consideration about the consistency in both element-wise operations and algebraic computation. |
I am shocked by that consensus, especially that in the discussion I have seen the natural argument: *I guess "+, -, , / are elementwise when one argument is a scalar" is a reasonable and easy-to-remember rule. |
Some users downloading only binaries will see the result of this decision only today. |
I would agree that this is being unnecessarily pedantic about element-wise operators. |
More precisely, the arguments for the change were summarized here: JuliaLang/LinearAlgebra.jl#75 Maybe this is too strict after all. I don't think any concrete cases where the old behavior was a problem were found. |
Let me put in a vote for loving this rule. |
This goes back to the eternal question about whether Array{T,2} is a two-dimensional container of Ts or whether it is a Matrix imbued with linear algebraic operations. As the latter, only multiplication by a scalar makes sense (and division by a scalar as multiplying by its reciprocal): addition and subtraction do not. As the former, all four elementary operations make sense if one uses broadcasting semantics to perform the appropriate scalar operation on each array element. My understanding of the current consensus is that we decided to make clear the distinction between broadcasting operators (.+, etc.) which are short forms for scalar operations on each element, and the ordinary operators which work on the scale of the Array itself as a single algebraic entity, and thus should support the semantics of linear algebra only. |
@jiahao, Thank you for summarizing the arguments. But can you give an example when the former, widespread, and no-surprise |
|
From @toivoh's comment in JuliaLang/LinearAlgebra.jl#75:
This seems to be the key argument for this behavior. To be perfectly clear, (A+B)*x == A*x + B*x when (A+1)*x != A*x + 1*x if we the 1 is broadcast and added to each element of A. (And similarly, (A.+1).*B == A.*B .+ 1.*B if we explicitly specify the broadcast operator.) Of course, for the last, you don't need to use A.*B .+ 1.*B == A.*B + 1.*B |
The most troublesome example is |
Similarly it is not clear if |
@jihao I completely agree that division quickly leads to trouble. I disagree entirely that |
Also, parenthesis in programming languages (as opposed to mathematic expression) are often not movable without consequences. Our broadcasting behavior similarly breaks with some like: |
@jiahao The only problematic case is |
I agree that it shouldn't. But if it did, then (A+2)*x == Ax + 2I*x == Ax + 2x which is quite nice, mathematically. Hence, the need to be clear about what Since Julia is targeting a mathematical audience, I don't really have a problem with it being more mathematically consistent than other languages, even if that means the operators are slightly more pedantic. I have vociferously argued the opposite view on other issues--that consistency with other languages or convenience was more important than mathematical consistency--when I first started using the language, but I've come to appreciate the subtle distinctions over time. But there is a need for a balance. |
I don't think there is an expectation that this should be equivalent, since there's no mathematical relation between (a+b)*c == ac + bc for arbitrary |
I think this is a question about habit. I you are used to write
Here I think it should be noted the burden is just a matter of typing a |
I suppose I am fine with that so long as after matrix+scalar falls off the deprecation list, it becomes an error suggesting the |
@blakejohnson I totally agree: see d2d7c32 In my opinion the fundamental problem is that linear algebra called dibs on the operators without |
Overall I support the change. But it was a bit painful, in no small measure because our backtraces are often not as useful as one could hope. I suspect I am not alone in having spent a couple of hours over the last week chasing down missing But going forward it's no big deal. |
I am still chasing the missing |
Although I find Gabor's quoting of my own argument highly incisive and compelling, I'm fine with the current behavior. Functions should mean something; they shouldn't just become elementwise because it is convenient or (in many systems) more efficient. |
Jeff, I really did not mean to hurt anybody. |
I don't think @JeffBezanson was offended at all, @GaborOszlanyi. I think we're all happy to have this kind of measured discussion about issues like this – keeping in mind that one may not always win. |
Thanks Stefan. |
I actually think the fact that this is a somewhat painful change is indicative that this is important. The two senses of plus are different and code that doesn't distinguish them is, in some sense, fundamentally ambiguous. |
While I support the |
Couldn't you do |
No, because comprehensions would bite you. This issue is the same (and indeed slightly worse), because your editor can't reliably tell when a quantity is a scalar. |
@timholy With that change you could write a simple parser that automatically fixed your codebase. With |
Changing |
To get away from artificial examples like |
I actually just did this by accident and the new behavior annoyed / saved me – at first I was annoyed, then I realized that what I'd written was a mistake and the warning had saved prevented me from messing up. What I did was write a polynomial expression and then apply it to matrices: julia> A = randn(3,3)
3x3 Array{Float64,2}:
1.04366 0.724268 0.187964
0.347349 1.24317 0.84459
-1.14403 -0.295596 -1.46345
julia> A^2 - 2A + 1
WARNING: A::Array + x::Number is deprecated, use A .+ x instead.
in + at deprecated.jl:26
3x3 Array{Float64,2}:
0.0384445 1.15218 1.15688
0.133397 0.0610497 -0.809932
3.66563 0.827721 5.60388 Oops. Did I want to add a 3x3 matrix of ones at the end or did I want to add a 3x3 identity matrix? Good question. And that's why it's a good thing that this behavior will be undefined and force you to choose between these very different meanings: julia> A^2 - 2A .+ 1
3x3 Array{Float64,2}:
0.0384445 1.15218 1.15688
0.133397 0.0610497 -0.809932
3.66563 0.827721 5.60388
julia> A^2 - 2A + I
3x3 Array{Float64,2}:
0.0384445 0.152184 0.156877
-0.866603 0.0610497 -1.80993
2.66563 -0.172279 5.60388 One thing I think we should do is allow |
See #6472, allowing polynomials using |
Recently (when? prerelease+2486?),
Array+Scalar
andArray-Scalar
operations were deprecated,and one has to use the
.+
and.-
operators instead.I hate this change and see it only as visual clutter.
It is also inconsistent, as one can still happily use
the
Array*Scalar
andArray/Scalar
operations.Why is one forbidden while the other one is allowed?
The text was updated successfully, but these errors were encountered: