For example, I have a function f(x,y,z)
and three vectors x, y, z
. I’d like to compute all combinations and return a 3D array of values. What I can do is this: f.(x,y',reshape(z,1,1,:))
. Is there a less cumbersome way, e.g., a macro, to do the same? Also the '
will conjugate if y
were complex, which is not very clean.
It’s not exactly what you asked for, but I think it’s more readable
using Base.Iterators
f(x, y, z) = x + y + z
f(x) = f(x...)
x, y, z = rand(4), rand(3), rand(2)
f.(product(x, y, z))
I found the following solution through Tullio
:
using Tullio
@tullio v[i,j,k]:=f(x[i],y[j],z[k])
Looks quite intuitive
Is the broadcasting dot needed here? I would not expect so.
When you’re down to one multidimensional iterable, comprehension is neater than broadcasting and doesn’t require you to define the one-argument method to splat an input tuple: [f(i...) for i in product(x, y, z)]
.
Broadcasting really is just awkward for this case because the inputs’ shapes determine the output’s shape, so the straightforward usage is indeed reshaping the input vectors to extend along different axes. It’s fine to use other ways when they are neater; they’re all looping a method call over the same elements anyway.
One clean way to do this is with generator expressions
[f(x,y,z) for x in 1:3, y in 1:5, z in 1:7]
it has the added benefit of being lazy, so operations like sum don’t need to allocate the whole 3D array
sum(f(x,y,z) for x in 1:3, y in 1:5, z in 1:7)
What you wrote is a comprehension. The generator expressions have round brackets, right?
Indeed, a stand alone generator expression has round brackets. I did a comprehension because OP wanted an array. It may not be the case in the internals, but I think of a comprehension as a collected generator.