# Broadcast product of arrays

**URL:** <https://discourse.julialang.org/t/broadcast-product-of-arrays/21437>\
**Category:** New to Julia\
**Created:** [March 3, 2019, 10:04pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437 "2019-03-03T22:04:08Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 3, 2019, 10:04pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/1 "2019-03-03T22:04:09Z")

</div>

I would like to call a function with all combination of values from several arrays, and get the corresponding array of values. Is a convenient general way to do that? Broadcasting comes first to my mind, but I wouldn’t call it convenient for this case, e.g.:

```julia
array_a = 1:3
array_b = 1:5
array_c = 1:7
f.(array_a, reshape(array_b, 1, length(array_b)), reshape(array_c, 1, 1, length(array_c)))

```

```julia
array_a = 1:3
array_b = [1 2; 3 4]
array_c = 1:7
f.(array_a, reshape(array_b, 1, size(array_b)...), reshape(array_c, 1, 1, 1, length(array_c)))

```

First it is very verbose and repetitive, and second it is error-prone especially if some of those arrays have the same size. I failed to find a better way, is there any?

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [March 3, 2019, 10:21pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/2 "2019-03-03T22:21:18Z")

</div>

Consider using `Iterators.product`:

```julia
[f(t...) for t = Iterators.product(array_a, array_b, array_c)]

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 3, 2019, 10:24pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/3 "2019-03-03T22:24:05Z")

</div>

Oh, really! I didn’t even look at that method thinking that `Iterators` are “single-dimensional” only. I guess that will work fine for me.  
If only it could also transparently be applied to cases like `f.(scalar, scalar, arr, arr, scalar, a=b, c=d)`…

---

<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:** [March 3, 2019, 10:28pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/4 "2019-03-03T22:28:40Z")

</div>

I wrote a package for doing such things, in which your second example looks like this:

```julia
using TensorCast
@cast res[α,β,β′,γ] := f(array_a[α], array_b[β,β′], array_c[γ])

```

It should be no problem to give `f` other scalar arguments.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 3, 2019, 10:30pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/5 "2019-03-03T22:30:46Z")

</div>

Interesting package indeed, it looks very general!

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [March 3, 2019, 10:45pm UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/6 "2019-03-03T22:45:20Z")

</div>

> [@aplavin](#):
>
> I would like to call a function with all combination of values from several arrays, and get the corresponding array of values. Is a convenient general way to do that?

You could just use a comprehension `[f(a,b) for a in A, b in B]`, depending on what shape you want for the result array.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 4, 2019, 6:19am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/7 "2019-03-04T06:19:52Z")

</div>

> [@aplavin](#):
>
> ```julia-auto
> f.(array_a, reshape(array_b, 1, length(array_b)), reshape(array_c, 1, 1, length(array_c)))
> 
> ```

A comprehension is the way to go, or maybe `Iterators.product`. But note also that you’re making `reshape` unnecessarily verbose:

```julia-auto
f.(a, reshape(b, 1, :), reshape(c, 1, 1, :))

```

You could also use `transpose(b)` or even `b'` for real data.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 4, 2019, 8:24am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/8 "2019-03-04T08:24:43Z")

</div>

Also nice suggestion, thank you - didn’t know about reshape with colon.

However, one needs to be very careful with `transpose` in Julia: at first I used `a` and `b'` for two-dimensional broadcast as you say, and surprisingly got wrong results. After digging in it turned out that `transpose` is not the same transpose I got used to in other languages, but also performs conjugation. Yes, my arrays were complex in that case, but after that I’m certainly not going to use transpose for broadcasting. Broadcasting syntax should not depend on the array element type, otherwise you can easily get errors like this when some `eltype` changes.

And anyway, `transpose` solves only a single simple case of multidimensional broadcasting, it is not of much help for \> 2 arrays, or when they are \> 1 dimensional (see 1st post for example of both). And it doesn’t work at all with non-numeric types.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 4, 2019, 8:30am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/9 "2019-03-04T08:30:27Z")

</div>

Yes, I would not use `transpose` or `'` in this case.

Be aware, though, that `transpose` does _not_ do complex conjugation, while `'` _does_ (`'` is the same as `adjoint`). Both of them work _recursively_ on their elements, which is important to be aware of, if the elements of your array can themselves be transposed.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 4, 2019, 8:35am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/10 "2019-03-04T08:35:01Z")

</div>

Ah, ok. Actually approach to transpose in julia feels like an inconvenience for me, and very simple stuff like “swap rows and columns in e.g. a matplotlib plot” cannot be written as `ax'` like in Python (`ax.T` there of course), but only as `permutedims(ax, 2, 1)`. However after reading the discussion I see that the majority is happy with the current state, so it will stay like this.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 4, 2019, 8:40am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/11 "2019-03-04T08:40:21Z")

</div>

Are you sure? You should be able to use `'` or `transpose` in most cases. Are you talking about higher-dimensional arrays? You would have the same problem in Matlab, btw. And in Matlab `'` also complex conjugates.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 4, 2019, 8:42am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/12 "2019-03-04T08:42:00Z")

</div>

Yes, sure - I tried that 🙂 Minimal example:

```julia
arr = [:a :b; :c :d]
a' # MethodError: no method matching adjoint(::Symbol)
arr |> transpose # MethodError: no method matching transpose(::Symbol)

```

Same goes for any non-numerical array.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 4, 2019, 8:47am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/13 "2019-03-04T08:47:55Z")

</div>

Wow, that caught me by surprise. To be honest, I personally think that should work. The reason it’s not is that there is no method for `transpose(::Symbol)`. Might be worth opening a discussion thread on that topic specifically.

But how does this look in python?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 4, 2019, 8:51am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/14 "2019-03-04T08:51:27Z")

</div>

In numpy transpose `arr.T` just swaps rows and cols of an array, without any regards to its internal structure (eltype), and without modifying elements of course, unlike `arr'` in julia.

And yes, there is not `transpose(::Symbol)`, as well as no `transpose(::anything else but for numerics)`. And as I understood the corresponding discussion, it is by design.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 4, 2019, 8:52am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/15 "2019-03-04T08:52:08Z")

</div>

I mean, what does the array look like? I have only ever seen numerical arrays in numpy.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 4, 2019, 8:55am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/16 "2019-03-04T08:55:10Z")

</div>

Numpy supports any kind of objects in elements - e.g. after `fig, ax = plt.subplots(2, 2)` `ax` is a 2x2 numpy array of matplotlib axes.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 4, 2019, 9:01am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/17 "2019-03-04T09:01:28Z")

</div>

OK, didn’t know that. Anyway, I think it’s strange that transpose doesn’t work on non-numeric matrices. I would ask about it specifically if I were you, unless you’ve seen somewhere that it is definitely intensional.

Anyway, note that for matrices, you don’t need to specify dimension to swap, since there are only two:

```julia
julia> arr = [:a :b; :c :d]
2×2 Array{Symbol,2}:
 :a :b
 :c :d

julia> permutedims(arr)
2×2 Array{Symbol,2}:
 :a :c
 :b :d 

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 4, 2019, 9:16am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/18 "2019-03-04T09:16:38Z")

</div>

Cool, didn’t know about that as well (`permutedims` without explicit dims)!  
And as for transpose, it is definitely intensional:

- `permutedims(m::AbstractMatrix)` is now short for `permutedims(m, (2,1))` , and is now a more convenient way of making a “shallow transpose” of a 2D array. This is the recommended approach for manipulating arrays of data, rather than the recursively defined, linear-algebra function `transpose` . Similarly, `permutedims(v::AbstractVector)` will create a row matrix ([#24839](https://github.com/JuliaLang/julia/issues/24839)).

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [March 4, 2019, 9:17am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/19 "2019-03-04T09:17:47Z")

</div>

> [@aplavin](#):
>
> only as `permutedims(ax, 2, 1)`

Note that for a matrix, you don’t need to specify dimensions, just `permutedims(ax)` is fine. See `?permutedims`.

---

<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:** [March 4, 2019, 10:10am UTC](https://discourse.julialang.org/t/broadcast-product-of-arrays/21437/20 "2019-03-04T10:10:06Z")

</div>

Note that `transpose(mat)` is lazy, while `permutedims(mat)` makes a copy. There is also `PermutedDimsArray(mat,(2,1))` which is lazy and not recursive.

(It would probably make sense to have `PermutedDimsArray(mat)` too, for matrices, but currently this does not exist.)
