`rand() + I` vs `rand() .+ I`

What is the difference between rand() + I and rand() .+ I? (I is from using LinearAlgebra).

The first one works, but second on throws error.

julia> rand() + I
1.04893935660533

julia> rand() .+ I
ERROR: MethodError: no method matching length(::UniformScaling{Bool})
Closest candidates are:
  length(::Core.SimpleVector) at essentials.jl:596
  length(::Base.MethodList) at reflection.jl:852
  length(::Core.MethodTable) at reflection.jl:938
  ...
Stacktrace:
 [1] _similar_for(::UnitRange{Int64}, ::Type{Bool}, ::UniformScaling{Bool}, ::Base.HasLength) at ./array.jl:576
 [2] _collect(::UnitRange{Int64}, ::UniformScaling{Bool}, ::Base.HasEltype, ::Base.HasLength) at ./array.jl:609
 [3] collect(::UniformScaling{Bool}) at ./array.jl:603
 [4] broadcastable(::UniformScaling{Bool}) at ./broadcast.jl:665
 [5] broadcasted(::Function, ::Float64, ::UniformScaling{Bool}) at ./broadcast.jl:1236
 [6] top-level scope at REPL[20]:1

Regarding the dot notation, you can take a look at the manual here:
https://docs.julialang.org/en/v1/manual/mathematical-operations/index.html

I also like this blog post, which explains why the dot notation is so nice:

2 Likes

Hi @tk3369, thanks for the blog post. I is really useful.

But still I am unable to find why that specific error is occurring for he second version. It happens because I think there is some ambiguity about the size of I. But I would also assume that it could be easily found as in the case of non-dot version.

For normal usage, the I operator adapts its size to the context where it is used in. Take this as an example:

julia> A = rand(1:10, 2, 2) #get a simple matrix
2×2 Array{Int64,2}:
 6  5
 8  6

julia> [A; I]  #extend the marix with the identity Matrix
4×2 Array{Int64,2}:
 6  5
 8  6
 1  0
 0  1

Here you can see, how the size of the identity operator I automatically matches the dimension of the matrix A.
In your case, you try to add a random number to each element of I. That fails because I has no idea about it’s size. To fix this, you just need to add the dimension like this:

julia> rand().+I(2) #size 2
2×2 Array{Float64,2}:
 1.04718    0.0471772
 0.0471772  1.04718
1 Like

Note that rand() .+ I(n) adds the same random number to all elements. If you want to add a different random number to each element of I(n) broadcast also the call to rand():

julia> using LinearAlgebra

julia> rand.() .+ I(2)
2×2 Array{Float64,2}:
 1.9842    0.167312
 0.722555  1.82408
5 Likes

Hi @roble,
Is there any specific reason why the dot version cannot find the size, but the normal version can?

The normal version isn’t finding a size. I+rand() increments all diagonal elements by the same amount, so you don’t need a size. you are just calling rand once.

2 Likes

That’s just because I is being adapted to the size of the other input in the addition, which is just a number. When broadcasting, both inputs must have a definite size.

1 Like