# Assign vector to slices and allocation

**URL:** <https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887>\
**Category:** Performance\
**Tags:** memory-allocation\
**Created:** [November 10, 2020, 6:19am UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887 "2020-11-10T06:19:45Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![cricci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cricci/32/25160_2.png) [@cricci](https://discourse.julialang.org/u/cricci)\
**Post date:** [November 10, 2020, 6:19am UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/1 "2020-11-10T06:19:45Z")

</div>

I am trying to optimize my code by reducing all unnecessary memory allocation. In particular I have a some assignment I need to repeat many many times. Hence I pre-allocate all necessary vectors and matrices in order to reduce GC time and allocation time in general. Here I have a working example

```nohighlight

function test_assign()
    N = 100
    A = rand(N,N,N)
    B = zeros(N)
    C = zeros(N,N)
    assign_1!(A,B)
    assign_2!(A,C)
end

function assign_1!(A,B)
    N,N,N = size(A)
    for i=1:N
        @views B[i] = test_scalar_field(A[i,:,1])
    end
end

function assign_2!(A,C)
    N,N,N = size(A)
    for i=1:N
        y = @view A[i,:,1]
        x = @view C[i,:]
        x .= test_vector_field(y)
    end
end

function test_scalar_field(x)
    return 10*norm(x)^2
end

function test_vector_field(x)
    return 10*2*x
end

```

If I do

```julia
julia> @benchmark assign_1!(A,B)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 5.355 μs (0.00% GC)
  median time: 5.391 μs (0.00% GC)
  mean time: 5.586 μs (0.00% GC)
  maximum time: 78.947 μs (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 6

```

so everything is good here where I assign scalar results. While when I assign vectors

```julia
@benchmark assign_2!(A,C)
BenchmarkTools.Trial: 
  memory estimate: 87.50 KiB
  allocs estimate: 100
  --------------
  minimum time: 21.977 μs (0.00% GC)
  median time: 45.901 μs (0.00% GC)
  mean time: 50.889 μs (13.14% GC)
  maximum time: 22.403 ms (99.77% GC)
  --------------
  samples: 10000
  evals/sample: 1

```

I haven’t yet found a way to remove those N allocation that apparently are unnecessary since everything is already there in memory. It should be possible somehow. As a rule of thumb I usually think about allocations in the following way:  
Are they really mandatory? Can I write a Fortran90 code with less allocation (where you explicitly `allocate`) ?  
If the answer is YES, then there should be a way

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [November 10, 2020, 7:15am UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/2 "2020-11-10T07:15:18Z")

</div>

`x .= test_vector_field.(y)`

Or, maybe `test_vector_field` must be itself a function that mutates data in-place, i.e. `test_vector_field!(x, y)` overwrites `x` with some values based on `y`.

---

<div class="post-metadata">

**Author:** ![cricci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cricci/32/25160_2.png) [@cricci](https://discourse.julialang.org/u/cricci)\
**Post date:** [November 10, 2020, 7:24am UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/3 "2020-11-10T07:24:22Z")

</div>

> [@Vasily\_Pisarev](#):
>
> x .= test\_vector\_field.(y)

this doesn’t really makes much sense. It works in this specific examples where test\_vector\_field acts only component wise without mixing the components. But think at something like test\_vector\_field(x) = A\*x where the function is really vector → vector and not the vector version of something that acts on scalar → scalar written in vector form.

> [@Vasily\_Pisarev](#):
>
> Or, maybe `test_vector_field` must be itself a function that mutates data in-place, i.e. `test_vector_field!(x, y)` overwrites `x` with some values based on `y` .

This is perhaps the way to go, and actually achieves what I need. It is utterly boring to write everything in that way but at least it has 0 allocations if x and y are already pre-allocated.  
Thanks for the idea!

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [November 10, 2020, 7:51am UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/4 "2020-11-10T07:51:59Z")

</div>

> [@cricci](#):
>
> It is utterly boring to write everything in that way

Somewhat better looking, maybe:

```julia
function assign_2!(A,C)
    N,N,N = size(A)
    buf = zeros(eltype(A), N)
    vector_field(y) = test_vector_field!(buf, y)
    for i=1:N
        y = @view A[i,:,1]
        x = @view C[i,:]
        x .= vector_field(y)
    end
end

```

Otherwise, there is just no way semantically to avoid allocation if you need a non-destructive vector → vector function in Julia.  
A macro transforming `x = f(args...)` into `f(x, args...)` for such purposes must be possible, though.

---

<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:** [November 10, 2020, 8:38am UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/5 "2020-11-10T08:38:51Z")

</div>

> [@cricci](#):
>
> ```julia
> function test_vector_field(x)
> return 10*2*x
> end
> 
> ```

If `x` is a vector, this necessarily allocates a new vector, there’s no way around this. If `test_vector_field` works on scalars, you dot both function call and assignment, otherwise, you just have to go with `test_vector_field!`.

> [@cricci](#):
>
> But think at something like test\_vector\_field(x) = A\*x where the function is really vector → vector

For in-place matrix-vector product you _anyway_ have to use `mul!(y, A, x)`.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 10, 2020, 2:07pm UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/6 "2020-11-10T14:07:05Z")

</div>

> [@DNF](#):
>
> If `x` is a vector, this necessarily allocates a new vector, there’s no way around this.

Perhaps with the exception when `x` is a static array? Depending on the context that would not allocate anything.

```julia
julia> function f(x)
         10*x
       end

julia> let 
         x = SVector{3,Float64}(rand(3))
         @allocated f(x)
       end
0

```

I am mentioning this because effectively you have taught me this a few days ago, and that allowed me to write some parts of a code of mine much clearer (without carrying the `!` and preallocating some vectors obsessively everywhere, which was my programming habit).

---

<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:** [November 10, 2020, 2:11pm UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/7 "2020-11-10T14:11:14Z")

</div>

> [@lmiq](#):
>
> Perhaps with the exception when `x` is a static array?

Well, yes and no. It would create a _new_ vector, but there is no performance cost to it, so it doesn’t matter. So I guess it doesn’t _allocate_ a vector, but it does create it.

> [@lmiq](#):
>
> I am mentioning this because effectively you have taught me this a few days ago, and that allowed me to write some parts of a code of mine much clearer

👍

---

<div class="post-metadata">

**Author:** ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)\
**Post date:** [November 23, 2020, 6:06pm UTC](https://discourse.julialang.org/t/assign-vector-to-slices-and-allocation/49887/8 "2020-11-23T18:06:50Z")

</div>

> [@Vasily\_Pisarev](#):
>
> A macro transforming `x = f(args...)` into `f(x, args...)` for such purposes must be possible, though.

Here’s a macro for inplace operations:

```julia
macro in(code)
  code.head == :(=) || error("assignment expected")
  lhs, expr = code.args
  expr.head == :call || error("function call expected")
  # append `!` to the function name
  expr.args[1] = Symbol(String(expr.args[1]) * "!")
  # insert `lhs` as the first argument to the function
  insert!(expr.args, 2, lhs)
  esc(expr)
end

```

For instance, as can be verified with `@macroexpand`,

```julia
@in lhs = f(g(x), y, h(z) + k(w))

```

gets translated to

```julia
f!(lhs, g(x), y, h(z) + k(w))

```

I _do not_ advocate the use of this macro.
