4

In Python I can have an numpy array a with dimensions (2, 3, 2) and b with (3) and do

c = a[:, :, :] + b[None, :, None]

I did not manage to figure out how to do this with Julia broadcast, because I do not know how to select the middle dimension.

c = broadcast(+, a, b)

What is the proper way to do this?

Chiel
  • 6,006
  • 2
  • 32
  • 57
  • can you give an example of the expected result ? – MarcMush Jul 20 '21 at 11:54
  • I would like add to each index in `a` the element of `b` with the same index as the actual index of the middle dimension in `a`. – Chiel Jul 20 '21 at 11:59
  • `reshape(b, 1, :, 1)` ? – MarcMush Jul 20 '21 at 12:03
  • Indeed, `c = broadcast(+, a, reshape(b, 1, :, 1))` works. Numpy wins it here in elegance! – Chiel Jul 20 '21 at 12:10
  • 1
    `a + reshape(b, 1, :, 1)` should work too (or `a .+ reshape(b, 1, :, 1)` if you need broadcasting) – MarcMush Jul 20 '21 at 12:12
  • It would be pretty easy to create a package that implements `None` expansion: just create a tuple for passing to `reshape` from `getindex`. If you miss NumPy's ease, consider writing it! – tholy Jul 21 '21 at 07:28
  • @tholy not a bad idea! – Chiel Jul 21 '21 at 08:26
  • 1
    The `None` serves as a new axis of length 1 in NumPy basic slicing. iirc, `na = [CartesianIndex()]` does the job in Julia. So `c = a[:, :, :] .+ b[na, :, na]` would be the syntactic equivalent. Still different because Julia copies arrays upon slicing. – BatWannaBe Jul 21 '21 at 10:40

1 Answers1

2
a .+ b'

For example

julia> a = rand(2,3,2)
2×3×2 Array{Float64, 3}:
[:, :, 1] =
 0.690245  0.358837   0.240053
 0.206133  0.0406269  0.985161

[:, :, 2] =
 0.207407  0.602692  0.483698
 0.625693  0.236401  0.306893

julia> b = rand(3)
3-element Vector{Float64}:
 0.1824121021951648
 0.33153839873473867
 0.024984235771881913

julia> a .+ b'
2×3×2 Array{Float64, 3}:
[:, :, 1] =
 0.872657  0.690375  0.265037
 0.388545  0.372165  1.01015

[:, :, 2] =
 0.38982   0.93423  0.508682
 0.808105  0.56794  0.331878

To elaborate, vectors in Julia are row vectors by default; transpose to a column vector to broadcast over the second dimension.

cbk
  • 4,225
  • 6
  • 27
  • Thanks, and what if it was the outermost dimension rather than the middle? – Chiel Jul 20 '21 at 14:32
  • 1
    For your example, second dimension is the only one of the right length, but if `b` were of length 2 and a vector along dimension 1 (e.g. `b = rand(2)`), then innermost would be `a .+ b` and outermost would be `a .+ reshape(b,(1,1,2))` – cbk Jul 20 '21 at 14:49
  • 1
    though in the latter case it may be more elegant to make `b` the size you need from the start with e.g. `b = rand(1,1,2)` and then it is just `a .+ b` again. – cbk Jul 20 '21 at 14:49