Usage of `@.`

Hi,

I am trying to generate random vector with {-1, +1} on length n.

The following code works

y = 2 .* (rand(n) .> 0.50) .- 1

When I try to use @., it throws error

y = @. 2 * (rand(n) > 0.50) - 1
ERROR: MethodError: no method matching isless(::Float64, ::Vector{Float64})
Closest candidates are:
  isless(::T, ::T) where T<:Union{Float16, Float32, Float64} at float.jl:424
  isless(::AbstractVector, ::AbstractVector) at abstractarray.jl:2612
  isless(::AbstractFloat, ::AbstractFloat) at operators.jl:184
  ...
Stacktrace:
  [1] <(x::Float64, y::Vector{Float64})
    @ Base ./operators.jl:356
  [2] >(x::Vector{Float64}, y::Float64)
    @ Base ./operators.jl:382
  [3] _broadcast_getindex_evalf
    @ ./broadcast.jl:670 [inlined]
  [4] _broadcast_getindex
    @ ./broadcast.jl:643 [inlined]
  [5] _getindex
    @ ./broadcast.jl:667 [inlined]
  [6] _getindex
    @ ./broadcast.jl:666 [inlined]
  [7] _broadcast_getindex
    @ ./broadcast.jl:642 [inlined]
  [8] _getindex
    @ ./broadcast.jl:666 [inlined]
  [9] _broadcast_getindex
    @ ./broadcast.jl:642 [inlined]
 [10] getindex
    @ ./broadcast.jl:597 [inlined]
 [11] copy
    @ ./broadcast.jl:875 [inlined]
 [12] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, typeof(-), Tuple{Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, typeof(*), Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, typeof(>), Tuple{Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, typeof(rand), Tuple{Int64}}, Float64}}}}, Int64}})
    @ Base.Broadcast ./broadcast.jl:860
 [13] top-level scope
    @ REPL[51]:1

But, if I create the random vector first and then use @., it works again

u = rand(n)
y = @. 2 * (u > 0.50) - 1

I could like to know why I cannot use rand() with @.?

@. rand(n) > 0.5 is equivalent to rand.(2) .> 0.5 and not rand(2) .> 0.5. The former is equivalent to

julia> for i in 2
           rand(i) > 0.5
       end

Perhaps you want something like

julia> @. (i -> 2 * (rand() > 0.50) - 1)(1:4)
4-element Vector{Int64}:
 -1
 -1
 -1
 -1

or, more clearly,

julia> [2 * (rand() > 0.50) - 1 for i in 1:4]
4-element Vector{Int64}:
  1
 -1
  1
  1

You could also solve this particular problem as:

julia> rand([-1, 1], 6)
6-element Vector{Int64}:
 -1
  1
  1
  1
 -1
  1

The version, rand(v, n), will pick random elements from v to fill up a vector of length n, so you can use it to generate more complicated sequences as well.

Since you only need two values, generating random Bools (instead of Float64s like in your original code) is faster:

julia> @btime 2 .* (rand(100_000) .> .5) .- 1;
  256.643 μs (4 allocations: 1.53 MiB)

julia> @btime rand($([-1,1]), 100_000);
  668.837 μs (2 allocations: 781.30 KiB)

julia> @btime rand($(-1:2:1), 100_000);
  647.847 μs (2 allocations: 781.30 KiB)

julia> @btime 2 .* rand(Bool, 100_000) .- 1;
  79.452 μs (4 allocations: 879.03 KiB)