Why is `+(::Number, UniformScaling)` deprecated?


#1

This deprecation makes writing generic code that works with both matrices and scalars harder. What’s the logic behind it?

WARNING: x::Number + J::UniformScaling is deprecated, use x + J.λ instead.
Stacktrace:
 [1] depwarn(::String, ::Symbol) at ./deprecated.jl:70
 [2] +(::Int64, ::UniformScaling{Int64}) at ./deprecated.jl:57
 [3] eval(::Module, ::Any) at ./boot.jl:235
 [4] eval_user_input(::Any, ::Base.REPL.REPLBackend) at ./REPL.jl:66
 [5] macro expansion at ./REPL.jl:97 [inlined]
 [6] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
while loading no file, in expression starting on line 0
2

#2

https://github.com/JuliaLang/julia/issues/17083

Could you post some examples where you would like to use it so someone can show us the preferred formulation?


#3

Ah, but they are about to deprecate +(::Matrix, ::Number) in favour of .+ notation, so that issue won’t be valid in 0.7.

The usage is pretty simple:

function foo(G)
## do something
R = G - I
end

#4

Yup, that’s exactly why we’re deprecating that :slight_smile:


#5

It seems both + UniformScaling and .+ UniformScaling are deprecated in 0.7(Version 0.7.0-DEV.1816 (2017-09-17 15:48 UTC)).

julia> 1 + I
WARNING: x::Number + J::UniformScaling is deprecated, use x + J.λ instead.
Stacktrace:
 [1] depwarn(::String, ::Symbol) at .\deprecated.jl:68
 [2] +(::Int64, ::UniformScaling{Int64}) at .\deprecated.jl:56
 [3] eval(::Module, ::Expr) at .\repl\REPL.jl:3
 [4] eval_user_input(::Any, ::Base.REPL.REPLBackend) at .\repl\REPL.jl:69
 [5] macro expansion at .\repl\REPL.jl:100 [inlined]
 [6] (::getfield(Base.REPL, Symbol("##1#2")){Base.REPL.REPLBackend})() at .\event.jl:96
while loading no file, in expression starting on line 0
2

julia> 1 .+ I
WARNING: x::Number + J::UniformScaling is deprecated, use x + J.λ instead.
Stacktrace:
 [1] depwarn(::String, ::Symbol) at .\deprecated.jl:68
 [2] +(::Int64, ::UniformScaling{Int64}) at .\deprecated.jl:56
 [3] (::getfield(Main, Symbol("##1#2")))(::UniformScaling{Int64}) at .\<missing>:0
 [4] broadcast(::Function, ::UniformScaling{Int64}) at .\broadcast.jl:434
 [5] eval(::Module, ::Expr) at .\repl\REPL.jl:3
 [6] eval_user_input(::Any, ::Base.REPL.REPLBackend) at .\repl\REPL.jl:69
 [7] macro expansion at .\repl\REPL.jl:100 [inlined]
 [8] (::getfield(Base.REPL, Symbol("##1#2")){Base.REPL.REPLBackend})() at .\event.jl:96
while loading no file, in expression starting on line 0
2

#6

My point is once 1 + rand(2,2) no longer works, 1+I should be reenabled as there is no longer an issue of associativity


#7

One is an old deprecation, the other is a new one. We can/should delete the old one now.


#8

You mean delete the old warning, and leave the old behaviour working? (That is, cancel the old deprecation since it’s no longer inconsistent.)


#9

Yes, exactly.


#10

Maybe an unrelated question following this topic:

julia> ones(1, 1) + ones(1, 1) == ones(1, 1) + I
true

julia> ones(1, 1) == I
false

julia> 1 + I == 1 + 1
true

julia> 1 == I
false

Can I expect ‘true’ for the 2nd and 4th equality comparison? The ‘false’ output makes me to think ‘number + UniformScaling’ and ‘matrix + UniformScaling’ an invalid operation. Because ‘a + b == a + c’ should result ‘b == c’ in my math. The equality property should be the same or even more important as associativity.

Edit: But if both ‘I == 1’ and ‘I == ones(1, 1)’ are true, then it results true for ‘1 == ones(1, 1)’. This is also obviously wrong.


#11

Hint: try size(I). If you accept the premise that x == y requires size(x) == size(y), the above is the logical behaviour.


#12

I tend to the point that 1 does not equal to I in any case. My actual concern is that if we could break following rule:
a + b == a + c ==> b == c
If this rule has a higher priority, then we should not take ‘number + UniformScaling’ an valid operation. I am not 100% sure this opinion is correct though.

julia> size(I)
ERROR: MethodError: no method matching size(::UniformScaling{Int64})
Closest candidates are:
  size(::Any, ::Integer, ::Integer, ::Integer...) where N at abstractarray.jl:33
  size(::Char) at char.jl:13
  size(::Char, ::Any) at char.jl:14
  ...

#13

But there is no such “rule”. Eg

julia> a = b = 1.0
1.0

julia> c = 1+eps()
1.0000000000000002

julia> a + b == a + c
true

julia> b == c
false

#14

Wow, I didn’t know it was already a failed rule. Great example, thanks!


#15

IIUC at least @andyferris and @StefanKarpinski want scalars to act more like UniformScaling in this context, so the result of 1+I would be 2I. This differs from the present result of 2, so it’s not simply a reversion.

Further, it looks as if the result of 1+eye(n) would be 2*eye(n) after a deprecation cycle. I presume this would be added as “new syntax” sometime after the 1.0 release. Will scalar+array simply be an error for 1.0?

This would be a step towards making Julia syntax follow conventions of pure math when they deviate from those of other programming languages. It will be interesting to see how this plays out.

For reference, here is the new deprecation mentioned above, with discussion:


#16

1 + I == 2I == I + I ==> 1 == I
So change the result of 1 + I to 2I could not solve my question above.

Yes, it would be interesting to see how this would evolve in future.


#17

To my knowledge, this notation is only used in the context of functional analysis, where the operators are ostensibly scalar differential operators.

I’ve never seen the notation 1-A used when A is a matrix: it’s always I-A


#18

Perhaps I was over-generalizing; functional analysis is indeed what I had in mind.

I thought I had an example in a more general context, but on page 1 Trefethen and Embree say

throughout this book z-A is shorthand for zI-A

so that doesn’t count.


#19

I itself is just shorthand: I’ve never seen a mathematical definition equivalent to UniformScaling.

Operators in the mathematical sense need spaces attached (as they are defined by their graph). Essentially I always needs context to infer the space. In the case of 1+I, I would infer the space as R, and hence the result should be 2.


#20

The identity operator is often represented as blackboard “1” (or even a regular “1”) in quantum mechanics (but perhaps this can be considered part of functional analysis in some way).