A .= circshift(b, shfts) and circshift!(a, b, shfts)

Ok. Maybe we are talking a bit different matters. I understand loop fusion with dots, but my question was more about memory allocation. I can formulate it in the following way:

is there a way to preallocate z for a function call like
z=f(x)? Lets say I can modify the code of f. And I assume x and z to be arrays.

Generally not, because f might call a function from a different library which might call another Library etc.

Sometimes functions expose the buffer to the user like circshift! does.

1 Like

so can inplace function f!(z, x). Is there any nuances that I miss by assuming the following code translation to be 100% equivalent (assuming z is correctly preallocated in terms of f! call):
z = f(x) —> f!(z, x) ?

You’ve already shown in your OP that they are not 100% equivalent!

Again, an example to try to clear things up:

f(a,b) = a + b 

a = rand(10)
b = rand(10)
z = zeros(10)

z .= f(a,b) # allocates the result for f(a,b) and then copies it element-wise to z.

# Throwing away the preallocated z and just naming the output of f(a,b) as z is faster here:
# z = f(a,b)

f!(z, a, b) = z .= a .+ b

f!(z,a,b) # this doesn't allocate but writes the result of the computation directly into z.

Here the timings:

julia> @btime $z .= f($a,$b);
  91.037 ns (1 allocation: 160 bytes)

julia> @btime $z = f($a,$b);
  75.565 ns (1 allocation: 160 bytes)

julia> @btime f!($z,$a,$b);
  23.057 ns (0 allocations: 0 bytes)

And as @roflmaostc has pointed out, while it is trivially possible here, it may be hard or impossible (due to library calls) to write a fully in-place function f!(z,a,b). Doing so automatically is of course even harder / impossible.

1 Like

@crstnbr
Sorry that’s not what I asked. Lets forget about vectorization with dots, as I already have got your examples and arguments. As I said, I assumed that .= is a general syntax for avoiding copying.

What I wanted to ask, is if there is any way to instead of writing f!(z, x) to write smth like @coolmacro z=f(x) or even better z _= f(x)?

Well, you can of course define a macro @coolmacro that, syntactically, transforms z = f(x) into f!(z,x). However, as pointed out by @roflmaostc and me above

  1. There isn’t always an in-place variant f!(z,x) for a given f.
  2. Generating such f!(z,x) might not even be possible, neither manually nor automatically. (Of course, it often is, as in the case of circshift!.)

(Also, what about functions with more than one “buffer”, i.e. f!(z1, z2, x)?)

So the answer is, no, there is no @coolmacro in (standard) Julia that does what you ask for because of the points above.

1 Like

For inspiration you might look at InplaceOps.jl. This only changes functions where it knows that the f! version exists. (IIRC there used to be a larger zoo of LinearAlgebra functions which it treated, many of which became mul!, and broadcasting was less clever.)

3 Likes

Thank you, that’s exactly what I needed to know!