Sum over arrays - What am I doing wrong?

Im trying to port a python numpy implementation of something into Julia and one step is

import numpy as np
np.random.rand(12,10) + np.random.rand(10)

Output shape - (12, 10)
but in Julia

rand(12,10) + rand(10)

throws DimensionMismatch(“dimensions must match: a has dims (Base.OneTo(12), Base.OneTo(10)), b has dims (Base.OneTo(10),), mismatch at 1”)

I tried broadcasting

rand(12,10) .+ rand(10)

DimensionMismatch(“arrays could not be broadcast to a common size; got a dimension with lengths 12 and 10”)

Im so confused. Is there something different here?

I’m not sure what ‘+’ does in python but if you want to add rand(10) to each rows of rand(12, 10) you should store them as a temporary array then add:

tmp = rand(10)
tmp2  = rand(12, 10)
vcat([permutedims(tmp2[i, :] + tmp) for i in 1:12]...)

Youd need the permutedims to keep row array when indexing in it and the vcat to concatenate all the rows.

1 Like

Broadcasting in Julia can expand dimensions that have only one value, like in Python, but it has to be the “right” dimension.

Here you are adding a 10-value array to a matrix with 10 columns and 12 rows. That will work if the array is a row so it can be expanded to 12 rows:

rand(12,10) .+ rand(10)'
3 Likes

Ohh okay that makes sense

Okay now I get it. I thought it would be a direct translation.
Thanks a lot!

The reason for this difference is that while python creates row vectors when calling np.random.rand, julia creates a column vector. Which explains your dimension mismatch.

1 Like

I think it’s easier to remember that in Python, you have to start aligning dimensions from the right, and in Julia from the left. That’s because Python is row-major and therefore the right-most dimension is the one contiguous in memory, while in Julia it’s the left-most.

In this example, broadcasting only works if two numbers on top of each other are the same, or at least one of them is 1. The [1] are implicit singleton dimensions that will always match, if one of the arguments is shorter than another.

# python: align from the right
arr1:  12  10
arr2:  [1] 10

# julia: align from the left, 12 and 10 are incompatible
arr1:  12  10
arr2:  10  [1]

# julia: with rand(10)', we have added a singleton dimension
# to arr2, so now it works
arr1:  12  10
arr2:   1  10

That works in higher dimensions, too, where it’s not just about rows and columns anymore.

I actually think it would be cool if the error messages for broadcasting gave such a visualization, but maybe it would be too crazy with many components.

6 Likes