# Avoid intermediate arrays in reduction of broadcast

**URL:** <https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 25, 2019, 6:11pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608 "2019-05-25T18:11:13Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [May 25, 2019, 6:11pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/1 "2019-05-25T18:11:13Z")

</div>

I have some code that looks like this:

```julia
A = randn(5,4,2)
B = randn(5,1,1)
C = zeros(5,4,1)
sum!(C, A .* B) # avoid forming `A.*B` ?

```

Is there a simple way to avoid forming the intermediate array `A.*B`? I was looking into the reducing functions in `Base` but I couldn’t find a suitable function for this.

I know I can write a kernel by hand, but if there is something in `Base` for this that I’m missing I would like to exploit it.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 25, 2019, 6:20pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/2 "2019-05-25T18:20:04Z")

</div>

> [@e3c6](#):
>
> sum!(C, A .\* B)

Try

```julia
sum(x->*(x...), zip(A,B))

```

Edit: Sorry, didn’t notice the different array sizes

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 25, 2019, 6:27pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/3 "2019-05-25T18:27:14Z")

</div>

```julia
A = randn(5,4,2)
B = randn(5,1,1)
@time sum(A .* B) # 0.000016 seconds (8 allocations: 624 bytes)
b = Base.broadcasted(*, A, B)
@time sum(b) # 0.000007 seconds (5 allocations: 176 bytes)

```

With larger arrays, the number of allocations are kept constant with the second approach

```julia
A = randn(500,4,2)
B = randn(500,1,1)
@time sum(A .* B) # 0.000028 seconds (9 allocations: 31.547 KiB)
b = Base.broadcasted(*, A, B)
@time sum(b) # 0.000034 seconds (5 allocations: 176 bytes)

```

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [May 25, 2019, 6:28pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/4 "2019-05-25T18:28:08Z")

</div>

Not in base, but you can do this:

```julia
julia> using LazyArrays

julia> sum!(C, @~ A .* B)

```

Or possibly now `sum!(C, LazyArray(@~ A .* B))` after a recent change. The difference is that `sum(::Broadcasted)` is not especially quick, although this will be fixed: [#31020](https://github.com/JuliaLang/julia/pull/31020).

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 25, 2019, 6:32pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/5 "2019-05-25T18:32:23Z")

</div>

> [@mcabbott](#):
>
> Not in base

Well that’s not correct, have a look at `Base.broadcasted(*, A, B)`. It does not form the intermediate result unless you call `materialize` on it.

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [May 25, 2019, 6:39pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/6 "2019-05-25T18:39:09Z")

</div>

Unfortunately …

```julia
julia> sum!(C, Base.broadcasted(*, A, B))
ERROR: MethodError: no method matching sum!(::Array{Float64,3}, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{3},Nothing,typeof(*),Tuple{Array{Float64,3},Array{Float64,3}}})

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 25, 2019, 6:40pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/7 "2019-05-25T18:40:49Z")

</div>

Why do you need C? You didn’t want to form another array, and no array is needed for the reduction using broadcasted  
`sum( Base.broadcasted(*, A, B))`

But as mentioned, this approach seems to be about twice as slow currently.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [May 25, 2019, 6:41pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/8 "2019-05-25T18:41:55Z")

</div>

Looking at that issue, it seems like `dot` ([docs](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.dot)) will do the job for this case also (unless the arrays are complex in which case there will be an extra complex conjugate on the first argument).

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [May 25, 2019, 6:42pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/9 "2019-05-25T18:42:42Z")

</div>

I need `C` to store the result of the sum, which is also an Array.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 25, 2019, 6:44pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/10 "2019-05-25T18:44:35Z")

</div>

As you wrote it, the result of sum is a scalar. Sum only returns arrays if you provide the dims keyword.

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [May 25, 2019, 6:45pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/11 "2019-05-25T18:45:52Z")

</div>

> [@e3c6](#):
>
> ```julia
> A = randn(5,4,2)
> B = randn(5,1,1)
> C = zeros(5,4,1)
> sum!(C, A .* B) # avoid forming `A.*B` ?
> 
> ```

That’s my original example. Note the dimensions of `C`. Also note it’s `sum!`, not `sum`.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [May 25, 2019, 6:48pm UTC](https://discourse.julialang.org/t/avoid-intermediate-arrays-in-reduction-of-broadcast/24608/12 "2019-05-25T18:48:38Z")

</div>

That was badly worded, I just meant that my solution was not in Base. Although how easily it can be done with only Base I don’t know. Writing `sum(Base.broadcasted(*, A, B), dims=3)` is also an error, which is the equivalent of `sum!(C,...` without a pre-allocated destination.

But even when reducing on all dimensions, there is still an issue of which methods of `sum` get used; `LazyArray` makes something `<: AbstractArray` which gets summed more efficiently right now, but there is a PR to fix that eventually.
