`rand()` vs. `rand.()`?

Consider the following example:

x = zeros(10)
x .= rand()

All components of x will have the same (random) value. Now suppose I do instead:

x = zeros(10)
x .= rand.()

Since rand.() is dotted, I’d expect it to apply to each element of x separatedly. In this case, I should obtain ten distinct random values. However the result is the same as above (a single random value fills the whole vector).

Even though rand.() has no arguments, it still should “apply to each element separatedly”. At least that’s what my intuition tells me.

Can someone explain this behavior?

x .= a just fills x with a’s when they are scalars, regardless of how you got a.

rand.() gives you a scalar. The dot has no effect here, as there is nothing to broadcast over, so it is the same as rand().

1 Like

@Tamas_Papp The behavior I suggest could be useful. Don’t you agree?

It’s already fixed on master.

@yuyichao What do you mean? What’s the new behavior?

julia> x = zeros(10);

julia> x .= rand.();

julia> x
10-element Array{Float64,1}:
 0.344676
 0.0245599
 0.276739
 0.500142
 0.256044
 0.176647
 0.406575
 0.547504
 0.913086
 0.170801

https://github.com/JuliaLang/julia/pull/19799

2 Likes

@yuyichao Nice. So it should be on 0.6.

Actually it seems @Tamas_Papp approach makes more sense.

The .= means do the operation in broadcasting way.
Now, broadcasting is operation which its input is array (Or arrays).
It shouldn’t be driven by rand() function.

Seems useful to have it but no coherent as a language.

@RoyiAvital This is fine if you do x .= rand(). However, the point is that if you use a dot in rand.() (as in x .= rand.()), it should be broadcasted too.

x .= rand() is equivalent to broadcast!(identity, x, rand()), so rand is called only once.

x .= rand.() is equivalent to broadcast!(rand, x). So (in 0.6), rand() is called once for each element of x.

The nice thing about the latter is that you can do vectorized operations with random numbers without requiring a temporary array to fill with rand(n) or rand! first. For example, x .+= y .* rand.() occurs entirely in-place in a single loop, adding a random fraction of each element of y to each element of x. (Or equivalently, you can do @. x += y * rand() in 0.6, allowing you to omit all of the dots.)

8 Likes

Just to be clear, I was not making a normative statement, just describing how I think 0.5.0 works. I think the broadcasting semantics of 0.6 are very nice, including the example above by @stevengj and also the broadcasting on Nullables; I am looking forward to both (and the inevitable corner cases which will be surprising :slight_smile:).

1 Like

Is there a syntax equivalent to x .= rand.() on Julia 0.6 that works on Julia 0.5 as well?

rand!(x)?

2 Likes