# Subtract Vector from Vector of Vectors

I’m having a bit of a moment. What is wrong with

``````julia> x = [[1, 2, 3], [4, 5, 6]]
2-element Vector{Vector{Int64}}:
[1, 2, 3]
[4, 5, 6]
julia> x .- [1, 2, 3]
ERROR: DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 2 and 3
Stacktrace:
 _bcs1
 _bcs
 combine_axes
 instantiate
 top-level scope
@ REPL:1
``````

? I would like to see

``````[[0, 0, 0], [3, 3, 3]]
``````

but I’m obviously doing something silly.

The issue is that you have a 2-vector of 3-vectors and you try to elementwise subtract a 3-vector. Broadcasting semantics mean you’re trying to compute the 2-vector (of 3-vectors) minus a 3-vector. Since 2 != 3, this doesn’t make sense and you get the error.

What you’re looking for is to subtract the 3-vector from each of the 3-vectors in the 2-vector. This means you want to broadcast the 2-vector but not the 3-vector. You can use `Ref` (or a 1-element array, a 1-element tuple, or a few other constructs) to prevent broadcasting of a collection. When used, it broadcast over the 1-element `Ref` (or array or tuple…) instead of the inner contents. Like this:

``````[[1, 2, 3], [4, 5, 6]] .- Ref([1, 2, 3])
``````
4 Likes

This works for subtraction, but it doesn’t for division. Understandably, because “division by a vector” is not exactly clear, but what I want to do now is elementwise division of vectors, e.g.,

``````julia> [1., 2.] ./ [3., 4.]
2-element Vector{Float64}:
0.3333333333333333
0.5
``````

If I change the solution above to division instead, I get

``````julia> [[1, 2, 3], [4, 5, 6]] ./ Ref([1, 2, 3])
2-element Vector{Matrix{Float64}}:
[0.07142857142857142 0.14285714285714285 0.21428571428571427; 0.14285714285714285 0.2857142857142857 0.42857142857142855; 0.21428571428571427 0.42857142857142855 0.6428571428571428]
[0.2857142857142857 0.5714285714285714 0.8571428571428571; 0.3571428571428571 0.7142857142857142 1.0714285714285714; 0.42857142857142855 0.8571428571428571 1.2857142857142856]

``````

which is not what I intend or expect. I can do instead

``````julia> x = [[1, 2, 3], [4, 5, 6]]
2-element Vector{Vector{Int64}}:
[1, 2, 3]
[4, 5, 6]

julia> [xx ./ [1, 2, 3] for xx in x]
2-element Vector{Vector{Float64}}:
[1.0, 1.0, 1.0]
[4.0, 2.5, 2.0]
``````

to circumvent the issue, but this feels a little clunky. Is there a cleaner way, nearer the spirit of the above solution for division?

maybe

``````vdiv(a, b) = a ./ b
vdiv.(x, Ref([1,2,3]))
``````

or

`map(r -> r ./ [1, 2, 3], x)`

I think the problem is that `/(::Vector, ::Vector)` is already defined but it doesn’t do element-wise division like you’re looking for

1 Like

There isn’t a fancy syntax for nested broadcasting (EDIT: See the following post for fancy syntax), but you can construct it using the `broadcast` function over broadcasted division `./` like this:

``````julia> broadcast(./, [[1, 2, 3], [4, 5, 6]], Ref([1, 2, 3]))
2-element Vector{Vector{Float64}}:
[1.0, 1.0, 1.0]
[4.0, 2.5, 2.0]
``````

The subtraction solution above `[[1, 2, 3], [4, 5, 6]] .- Ref([1, 2, 3])` is equivalent to `broadcast(-, [[1, 2, 3], [4, 5, 6]], Ref([1, 2, 3]))`. It is also in-practice equivalent to `broadcast(.-, [[1, 2, 3], [4, 5, 6]], Ref([1, 2, 3]))`, but only because `-` and `.-` are equivalent on pairs of vectors (unlike `/` and `./`).

2 Likes

A somewhat simpler-looking way is

``````julia> (./).([[1, 2, 3], [4, 5, 6]], Ref([1, 2, 3]))
2-element Vector{Vector{Float64}}:
[1.0, 1.0, 1.0]
[4.0, 2.5, 2.0]
``````

But yeah, convenient interface for deeper broadcasting would be nice…

3 Likes

For unlimited-depth broadcasting, it’s often easiest to create a function that broadcasts over itself. Something like

``````dotplus(a, b) = dotplus.(a, b)
dotplus(a::Number, b::Number) = +(a, b) # base case

x = fill(fill([1 3; 2 4],2),3)
y = [50 70; 60 80]

dotplus(x,Ref(y))
# 3-element Vector{Matrix{Matrix{Int64}}}:
#  [[51 53; 52 54] [71 73; 72 74]; [61 63; 62 64] [81 83; 82 84]]
#  [[51 53; 52 54] [71 73; 72 74]; [61 63; 62 64] [81 83; 82 84]]
#  [[51 53; 52 54] [71 73; 72 74]; [61 63; 62 64] [81 83; 82 84]]

dotplus(x,Ref(Ref(y)))
# 3-element Vector{Vector{Matrix{Int64}}}:
#  [[51 73; 62 84], [51 73; 62 84]]
#  [[51 73; 62 84], [51 73; 62 84]]
#  [[51 73; 62 84], [51 73; 62 84]]
``````

although you may need to change things depending on how exactly you want each term passed down through the broadcasting.

Broadcasting to significant depth is not terribly common.

1 Like