# Question about program design with ComponentArrays

**URL:** <https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732>\
**Category:** Performance\
**Tags:** question, arrays, componentarrays\
**Created:** [April 7, 2021, 5:19am UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732 "2021-04-07T05:19:03Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [April 7, 2021, 5:19am UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732/1 "2021-04-07T05:19:03Z")

</div>

I’m retaking a program I did some time ago, trying to speed it up. I am using `ComponentArrays` because it is very easy to organize data and parameters with it. Consider this:

```julia
using ComponentArrays
using Parameters: @unpack

const homecode = 6

function agecat(a)
    (19 <= a <= 24) && return 1
    (25 <= a <= 29) && return 2
    (30 <= a <= 34) && return 3
    (35 <= a <= 39) && return 4
    (40 <= a <= 44) && return 5
    (45 <= a <= 49) && return 6
    (50 <= a <= 54) && return 7
    (55 <= a <= 59) && return 8
    (60 <= a <= 64) && return 9
end

const data = ComponentArray(
    wẘ = rand(2, 9, 2, 2, 5, 44),
    P_1 = rand(5, 44),
    ē = rand(5, 44)
)

const θ = ComponentArray(
    α0 = rand(2, 2, 5),
    α = rand(3),
    α̃h = rand(2, 2),
    α̃ga = rand(2, 9)
)

function Uk(g, a, e, k, t; data=data, θ=θ)
    @unpack α0, α = θ
    @unpack wẘ, P_1, ē = data
    w = wẘ[:, :, :, 1, :, :]

    α0[g,e,k] + α[1] * w[g, agecat(a), e, k, t] + α[2] * (e - ē[k, t])^2 + α[3] * P_1[k, t]
end

function α̃0(g, a, e, t; data=data, θ=θ)
    @unpack α̃h, α̃ga = θ

    α̃h[1,g] + α̃h[2,g] * t + α̃ga[g, agecat(a)]
end

function U0(g, a, e, t; data=data, θ=θ)

    α̃0(g, a, e, t; data=data, θ=θ)
end

function Probk(g,a,e,k,t; data=data, θ=θ)

    uk = ( k == homecode ? U0(g, a, e, t; data=data, θ=θ) : Uk(g, a, e, k, t; data=data, θ=θ) )
    1/(sum(exp(Uk(g, a, e, kk, t; data=data, θ=θ)-uk) for kk=1:5) + exp(U0(g, a, e, t; data=data, θ=θ)-uk))
end

```

Notice how I pass `data` and `θ` from `Probk` to `U0` and `Uk`. Is that good practice? I’m worried about allocations.

Ultimately, I will have to optimize a function over `θ` and I am trying squeeze as much speed as possible from the program.

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [April 7, 2021, 12:27pm UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732/2 "2021-04-07T12:27:39Z")

</div>

Three easy thoughts:

1. This seems to allocate a new array:

> [@amrods](#):
>
> `w = wẘ[:, :, :, 1, :, :]`

Why not pass `wẘ` to `α0` instead of `w`?

1. `Probk` computes `U0` or one of the `Uk` twice, depending on the value of `k`.

2. Precompute the categorized `a` and pass it into `Probk` as an additional argument, so that `agecat` does not have to be called over and over again.

Then run the profiler and see where most of the time is actually spent.

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [April 7, 2021, 11:22pm UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732/3 "2021-04-07T23:22:46Z")

</div>

About your point 2, do you have any suggestions on how to avoid that?

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [April 8, 2021, 12:42am UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732/4 "2021-04-08T00:42:54Z")

</div>

What I meant was simply

```julia
function Probk(g,a,e,k,t; data=data, θ=θ)
    u00 = U0(g, a, e, t; data=data, θ=θ)
    ukk = Uk(g, a, e, k, t; data=data, θ=θ)
    uk = ( k == homecode ? u00 : ukk )
    1/(sum(exp(Uk(g, a, e, kk, t; data=data, θ=θ)-uk) for kk=1:5) + exp(u00-uk))
end

```

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [April 8, 2021, 2:51am UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732/5 "2021-04-08T02:51:07Z")

</div>

Fantastic, thank you. I think there is another improvement, if it is possible to drop an element from `1:5` since for `k != homecode`, `k` is in `1:5`, but that is precomputed and stored in `ukk`.

About point 1, doesn’t inlining take care of that?

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [April 8, 2021, 11:42am UTC](https://discourse.julialang.org/t/question-about-program-design-with-componentarrays/58732/6 "2021-04-08T11:42:25Z")

</div>

You could  
`sum(f(kk) for k = 1 : 5 if k != kk) + ukk`

About point 1: do you mean a `view`? That would avoid the allocation, but is not entirely costless. I just don’t see the benefit of `w[g, agecat(a), e, k, t]` over `wẘ[g, agecat(a), e, 1, k, t]`.

I don’t know if there is a reason to pass the entire `wẘ` array into `U0` and `Uk`. If not, it would avoid a fair bit of indexing to just pass a view into a slice (over `k`).
