Trouble with Dot Syntax: .* Works, .+ and sin. Do Not Work

Hello. This is my first post on here. I am doing some work with arrays for a small simulator. I have noticed that multiplication dot functions work fine but addition and trig functions do not.

Example where all is well:

Input:

TryArray = Array[1:30,1:30]
TryArray .* 2

Output:

2-element Array{Array{Int64,1},1}:
 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20  …  42, 44, 46, 48, 50, 52, 54, 56, 58, 60]
 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20  …  42, 44, 46, 48, 50, 52, 54, 56, 58, 60]

Example where all is not well:
Input:

TryArray = Array[1:30,1:30]
TryArray .+ 2

Output:

MethodError: no method matching +(::Array{Int64,1}, ::Int64)
Closest candidates are:
  +(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:529
  +(!Matched::Complex{Bool}, ::Real) at complex.jl:301
  +(!Matched::Missing, ::Number) at missing.jl:115
  ...

Stacktrace:
 [1] _broadcast_getindex_evalf at .\broadcast.jl:631 [inlined]
 [2] _broadcast_getindex at .\broadcast.jl:604 [inlined]
 [3] getindex at .\broadcast.jl:564 [inlined]
 [4] copy at .\broadcast.jl:854 [inlined]
 [5] materialize(::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(+),Tuple{Array{Array,1},Int64}}) at .\broadcast.jl:820
 [6] top-level scope at In[18]:2

sin.(TryArray) and broadcast(+,1,(TryArray,)) produce similar results. I am not sure why the method does not match. Could someone help me understand what is missing? Thanks!

2 Likes

I think the problem is that Array[1:30,1:30] returns an array of arrays, not a matrix. TryArray .+ 2 means "add 2 to each element of TryArray", but those are arrays themselves. Addition of a scalar and an array is not defined.

The reason .* works is that multiplication of a scalar and an array is defined:

julia> 2*[1,2,3]
3-element Array{Int64,1}:
 2
 4
 6
6 Likes

Thank you mbaz!

I did not realize that the “,” created two arrays. My original function had a single multidimensional array, but my testing was with the two arrays. A single array works great. Thank you.

Input:

TryArray = [1:30 1:30]'
sin.(TryArray)

Output:

×30 Array{Float64,2}:
 0.841471  0.909297  0.14112  -0.756802  …  0.270906  -0.663634  -0.988032
 0.841471  0.909297  0.14112  -0.756802     0.270906  -0.663634  -0.988032
1 Like

Actually, the comma isn’t what creates two arrays. It’s a product of the fact that you can make arrays of non-numbers (of anything really). See below where I make an array consisting of two iterators, each one equal to the range 1:30

julia> [1:30, 1:30]
2-element Array{UnitRange{Int64},1}:
 1:30
 1:30

By declaring the array type to be Array, which is what you were doing, you are asking julia to convert anything that goes into it into an Array. And you can convert a unit range into an array! First see:

julia> Array(1:30)
30-element Array{Int64,1}:
  1
  2
  ...
  29
  30

And we apply the conversion to both iterators:

julia> Array[1:30, 1:30]
2-element Array{Array,1}:
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10  …  21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10  …  21, 22, 23, 24, 25, 26, 27, 28, 29, 30]

If you wanted the above to come out a matrix, there are plenty of ways you could do that. One is the one you showed with a space instead of comma (because a space in square brackets means hcat) but you will see that TryArray itself is actually of type Adjoint (what the transpose operator returns) rather than Array. That might not matter to you, particularly if you’re immediately going to broadcast something like sin over it.

You could instead use a semicolon for vcat, with each range being individually transposed:

julia> [(1:30)'; (1:30)']
2×30 Array{Int64,2}:
 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30
 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30

You can also use an array comprehension:

julia> [j for i in 1:2, j in 1:30]
2×30 Array{Int64,2}:
 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30
 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30

You can create an empty array and fill it in a for-loop, either with zeros(Int, n, m), or with Matrix{Int}(undef, n, m), and plenty of other things as well. Etc, etc!

1 Like