# Matrices inside a or outside a Function

**URL:** <https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775>\
**Category:** New to Julia\
**Tags:** question, speed-optimization, typed-globals\
**Created:** [August 2, 2024, 9:11pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775 "2024-08-02T21:11:20Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benjamin7](https://avatars.discourse-cdn.com/v4/letter/b/9fc29f/32.png) [@Benjamin7](https://discourse.julialang.org/u/Benjamin7)\
**Post date:** [August 2, 2024, 9:11pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/1 "2024-08-02T21:11:20Z")

</div>

Hello community!  
As I understand from what I have read in Julia’s optimization section, “Performance critical code should be inside a function”.  
My code has several for loops that fill the created arrays, my question is: To make the execution faster, is it better to create the array outside the function or inside the function?  
I think that if I create it outside, the function is only in charge of filling it with elements, on the other hand, if I create it inside, the function is in charge of creating the matrix and filling it with elements, which would demand more memory.

I don’t know if it’s a good idea to put my code here since it’s like 600 lines long, so here is an easy example. I hope it helps your understanding.

```julia
x::Matrix{Float64} = zeros(1,1000)
y = -1.0
function example(x,y)
  for i = 1:1000
    x[1,i] = i^2 + 10y
  end
  return x
end

```

or it would be faster to:

```julia
y = -1.0
function example2(y)
  x::Matrix{Float64} = zeros(1,1000)
  for i = 1:1000
    x[1,i] = i^2 + 10y
  end
  return x
end

```

I know i can measure it with @time or @btime, but i would like to know the “computationally” correct answer, not the one i got by repeting the exercise.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [August 2, 2024, 9:20pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/2 "2024-08-02T21:20:19Z")

</div>

When performance matters, it’s good to provide a mutating interface (function). It’s possible to additionally provide an allocating interface (function), which could just call the mutating interface after allocating the data structure.

NB: in Julia, it’s common and preferred to have the name of a function that mutates its arguments end with a bang (`!`). See [Style Guide · The Julia Language](https://docs.julialang.org/en/v1/manual/style-guide/)

---

<div class="post-metadata">

**Author:** ![Benjamin7](https://avatars.discourse-cdn.com/v4/letter/b/9fc29f/32.png) [@Benjamin7](https://discourse.julialang.org/u/Benjamin7)\
**Post date:** [August 2, 2024, 9:35pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/3 "2024-08-02T21:35:25Z")

</div>

Hi! thanks for your answer. What is the difference between a mutating and an allocating interface?

---

<div class="post-metadata">

**Author:** ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)\
**Post date:** [August 2, 2024, 10:33pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/4 "2024-08-02T22:33:11Z")

</div>

Allocating memory is itself costly both in terms of time and memory.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [August 2, 2024, 10:42pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/5 "2024-08-02T22:42:59Z")

</div>

“Allocating” is what you called “the function is in charge of creating the matrix”. The function `example2` has to allocate memory to put the matrix into. If instead the function `example` takes the matrix as an argument, the matrix is pre-allocated so it’s faster.

You can do

```julia
# nonallocating function mutates its x argument
function example!(x, y)
  for i in eachindex(y)
    x[i] = 10 * y[i]
  end
  x
end

# allocating version creates an x and then calls the nonallocating version
function example(y)
  x = similar(y)
  example!(x, y)
end

```

---

<div class="post-metadata">

**Author:** ![jacobusmmsmit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jacobusmmsmit/32/217669_2.png) [@jacobusmmsmit](https://discourse.julialang.org/u/jacobusmmsmit)\
**Post date:** [August 2, 2024, 10:45pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/6 "2024-08-02T22:45:54Z")

</div>

If we take the code at face value i.e. we don’t try to change its structure, then the right answer here is to construct the matrix _inside_ the function. This makes the function self-contained and therefore makes the code cleaner.

As is, you’ve already added a type hint to `x`, so there shouldn’t be any speed-up by putting the `zeros` inside the function.

---

<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:** [August 2, 2024, 11:14pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/7 "2024-08-02T23:14:42Z")

</div>

We don’t have enough information to answer definitively. If you only run the function _once_, it doesn’t matter, performance-wise, whether you allocate it outside or inside. It will anyway be allocated once, and filled once.

The difference occurs when you run the function multiple times. If you _can_ reuse the matrix, then naturally it’s faster to only allocate _once_ outside the function, and repeatedly fill it inside.

---

<div class="post-metadata">

**Author:** ![PeterSimon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petersimon/32/25193_2.png) [@PeterSimon](https://discourse.julialang.org/u/PeterSimon)\
**Post date:** [August 2, 2024, 11:16pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/8 "2024-08-02T23:16:29Z")

</div>

Hello, @Benjamin7 and welcome to the community!

When I see the following line

> [@Benjamin7](#):
>
> `x::Matrix{Float64} = zeros(1,1000)`

I am a little bit suspicious that you are a recent Matlab convert, and that you should be creating a one-dimensional `Vector` rather than a two-dimensional `Matrix`. Note that unlike Matlab, Julia supports true, one-dimensional arrays, known as `Vector`s for short. You would create such an object as follows:

```julia
x = zeros(1000)

```

Note that it is not necessary to provide a type annotation for `x`—Julia will know the type automatically, because a single, integer argument to the `zeros` function will generate an array of type `Vector{Float64}` (an alias for the slightly more verbose `Array{Float64,1}`).

If these comments are misdirected, please forgive me. I have seen this mistake made frequently in the past.

---

<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:** [August 2, 2024, 11:20pm UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/9 "2024-08-02T23:20:33Z")

</div>

> [@Benjamin7](#):
>
> ```julia
> for i = 1:1000
> x[1,i] = i^2 + 10y
> end
> 
> ```

In addition to the remarks by @PeterSimon, there’s also the risky code snippet above. This will work well for arrays of one particular size, but fail or error for other sizes. Make sure to check the array size inside the function when iterating over its elements.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [August 3, 2024, 6:18am UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/10 "2024-08-03T06:18:04Z")

</div>

Depending on globals as a buffer is probably not a good idea. You can use an optional keyword argument for this purpose.

```julia
function example(
  y;
  x::Matrix{Float64} = zeros(1,1000)
)
  for i = 1:1000
    x[1,i] = i^2 + 10y
  end
  return x
end

```

Then you can call the function without providing a keyword argument, which will have a new buffer allocated everytime. You can also provide the keyword argument to use or reuse a buffer.

```julia-repl
julia> example(-1)
1×1000 Matrix{Float64}:
 -9.0 -6.0 -1.0 6.0 15.0 26.0 … 995994.0 997991.0 999990.0

julia> example(-1; x=xx)
1×1000 Matrix{Float64}:
 -9.0 -6.0 -1.0 6.0 15.0 26.0 … 995994.0 997991.0 999990.0

julia> example(5; x=xx)
1×1000 Matrix{Float64}:
 51.0 54.0 59.0 66.0 75.0 … 996054.0 998051.0 1.00005e6

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [August 3, 2024, 11:57am UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/11 "2024-08-03T11:57:29Z")

</div>

> [@Benjamin7](#):
>
> What is the difference between a mutating and an allocating interface?

Mutation is changing a value. E.g, changing the first element of a vector from `13` to `14`. A mutating function may mutate one of its arguments.

Allocation is less well defined. Basically a function is allocating if it may cause a heap allocation that may need to be tracked by the garbage collector (GC). Or by another allocator, such as the libc malloc, if you’re using FFI, for example.

Mutation is less _safe_ in principle than working with immutable structures (making a modified copy of an existing data structure), but may be preferred for performance reasons when it allows preventing allocation.

A single function/method may be both mutating _and_ allocating, but the goal is often to have a higher-level, more convenient, allocating function, that doesn’t mutate any of its arguments; and a lower-level, mutating function, whose name ends with a `!`, and which doesn’t allocate.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [August 4, 2024, 2:40am UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/12 "2024-08-04T02:40:05Z")

</div>

In general, editing (mutating) Arrays (Vectors, Matrices etc) is “cheaper” than creating (“allocating”) them. So the general rule is create (allocate) once, edit (mutate) as needed. Here’s one possible way to think about it: If your function is meant to create an Array that wouldn’t otherwise exist, then maybe it’s okay to create and edit the array within the function. If your function needs to do a series of complicated calculations/transformations, it might still be worth creating the array once and editing it multiple times, even if your function is creating an array that wouldn’t otherwise exist.

Here’s a case where it might be more efficient to pass an array to the function as an argument and mutate it: You get a column of data from a csv file and the values represent percentages (are between 0 and 100) and you need to scale the values to 0 to 1 before you do further calculations. Say you read in the csv data and store it in a vector `v`. if you DON’T need this vector `v` to stay unchanged in value for later use, you could transform it by doing `scale01!(v)` where `scale01!` is a mutating function defined as:

```julia
function scale01!(x::Vector{<:Real})
	for i in eachindex(x)
		x[i] = x[i] / 100
	end

	return nothing
end

```

Notice that the function returns `nothing`, though it would do that even without the explicit `return` statement.

But, in your example, you’re creating an array of zeros just to store the data, so it might not matter whether you create (allocate) it inside or outside the function.

I’m not an expert on squeezing performance out of Julia, but your example is missing other performance optimizing recommendations:

- avoid using global variables, and if you must, declare them constant
- use `eachindex` so that you can safely use `@inbounds` and avoid bounds checking (making sure you’re not using wrong indices to get elements from your array), though I am not sure if this is helpful for simpler loops. So your example would look like:

```julia
const x = zeros(Float64, 1000)
const y = -1.0
example!(x, y) = @inbounds for i in eachindex(x)
	x[i] = x[i] ^ 2 + 10 * y
end

```

You can do more: like doing the 10 \* y outside the loop, or if this is actually the computation you want, doing `muladd(x[i], x[i], 10y)`. I’m not sure how much these would help in this case.

---

<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:** [August 4, 2024, 8:11am UTC](https://discourse.julialang.org/t/matrices-inside-a-or-outside-a-function/117775/13 "2024-08-04T08:11:16Z")

</div>

> [@sadish-d](#):
>
> ```julia
> example!(x, y) = @inbounds for i in eachindex(x)
> x[i] = x[i] ^ 2 + 10 * y
> end
> 
> ```

I believe `@inbounds` is redundant when you use `eachindex(x)` like that.
