Assignment into array of arrays by broadcasting

I want to simulate a process with 3 discrete outcomes. Let’s say they have probabilities .2, .3 and .5 and I want to run nSim = 10 simulations, each of which is a series of nDraw = 5 draws from the discrete distribution:

using Distributions
d = Multinomial(1,[.2;.3;.5])
M = rand(d, 5, 10)

I get an nDraw x nSim matrix, each element of which is a 3-vector with 2 zeros and 1 one in the slot to show which of the 3 outcomes occurred for the particular draw. Here’s an example:

5×10 Matrix{Vector{Int64}}:
 [1, 0, 0]  [0, 0, 1]  [0, 0, 1]  [0, 0, 1]  [0, 1, 0]  [1, 0, 0]  [0, 0, 1]  [0, 1, 0]  [0, 0, 1]  [0, 0, 1]
 [0, 0, 1]  [0, 1, 0]  [0, 0, 1]  [0, 0, 1]  [0, 0, 1]  [0, 0, 1]  [0, 1, 0]  [0, 1, 0]  [0, 0, 1]  [0, 0, 1]
 [0, 1, 0]  [0, 1, 0]  [0, 1, 0]  [0, 0, 1]  [0, 1, 0]  [0, 1, 0]  [0, 0, 1]  [1, 0, 0]  [0, 0, 1]  [0, 1, 0]
 [1, 0, 0]  [0, 0, 1]  [0, 1, 0]  [0, 0, 1]  [0, 1, 0]  [0, 0, 1]  [0, 0, 1]  [0, 0, 1]  [1, 0, 0]  [1, 0, 0]
 [0, 1, 0]  [1, 0, 0]  [0, 0, 1]  [0, 1, 0]  [0, 1, 0]  [0, 1, 0]  [0, 1, 0]  [0, 0, 1]  [0, 0, 1]  [0, 1, 0]

Anyway, all of this is just to say that, because I’m using Distributions.Multinomial and want to create all the sims at once, I’m stuck with a matrix of vectors…

THE QUESTION (finally): Why can’t I say something like a[1,:] .= [0, 1, 0] to assign that 3 vector to all the elements in the first row of M? When I do so I get:

ERROR: DimensionMismatch: array could not be broadcast to match destination
Stacktrace:
 [1] check_broadcast_shape
   @ ./broadcast.jl:540 [inlined]
 [2] check_broadcast_axes
   @ ./broadcast.jl:543 [inlined]
 [3] instantiate
   @ ./broadcast.jl:284 [inlined]
 [4] materialize!
   @ ./broadcast.jl:871 [inlined]
 [5] materialize!(dest::SubArray{Vector{Int64}, 1, Matrix{Vector{Int64}}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true}, bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(identity), Tuple{Vector{Int64}}})
   @ Base.Broadcast ./broadcast.jl:868
 [6] top-level scope
   @ REPL[159]:1

This is weird to me. I know I can do the assignment by looping but I like broadcasting and also want to understand what I’m doing wrong here…

EDIT: The moral of the story is “Think before you type” :<
I should have written the assignment as a[1,:] .= Ref([0, 1, 0]).

In honor of the world cup: Screwed by the Refs once again…

You could also try to use an SVector from StaticArrays for the three elements in the multinomial distribution, because I think then the draws might be SVectors as well, which would be beneficial in terms of memory layout and allocations.

1 Like

Good idea, thanks.