# Efficient Evaluation of a Matrix of Function Products

**URL:** <https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466>\
**Category:** Performance\
**Created:** [June 28, 2022, 3:25pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466 "2022-06-28T15:25:42Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![martintb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/martintb/32/37505_2.png) [@martintb](https://discourse.julialang.org/u/martintb)\
**Post date:** [June 28, 2022, 3:25pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/1 "2022-06-28T15:25:42Z")

</div>

Hi all,  
I’m trying to compute every product of two functions of a set of different functions `fv` (e.g., a set of wavefunctions) at different `x` to obtain a matrix `y` for each `x` of shape `NxN` where `N` is the number of functions. Here, `fv` is just a vector of arbitrary functions.

The best I could come up with is the following:

```julia
using BenchmarkTools
import Base.*

*(f::Function, g::Function) = @. (x...) -> f(x...) * g(x...)

function get_function_matrix(fv::Vector{Function})
    N = length(fv)
    Mf = Array{Function, 2}(undef, N, N)
    for j in 1:N, i in 1:N
        Mf[i, j] = fv[i] * fv[j]
    end
    return Mf
end

function evaluate_function_matrix(Mf::Array{Function, 2}, x)
    N = size(Mf, 1)
    y = zeros(length(x), N, N)
    for j in 1:N, i in 1:N
        y_ = @view y[:, i, j]
        map!(Mf[i, j], y_, x) # <- Why does cause an allocation?
    end
    return y
end

x = rand(100)
fv = [sin, cos, sinh, cosh, tan, tanh]
Mf = get_function_matrix(fv)
@btime y = evaluate_function_matrix(Mf, x)

```

My questions are:

1.) Why does the `map!` function cause an allocation and is there a way to optimize this? Am I wrong to expect that this step should not cause any allocations at all?  
2.) If one replaces the `map!` function with `y[i, j] = M[i, j](x), where `x` is just a float, the allocations increase even more which I don’t understand.  
3.) Is there a more Julian way to solve this problem?

Thank you very much in advance for your help!

---

<div class="post-metadata">

**Author:** ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)\
**Post date:** [June 28, 2022, 8:52pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/2 "2022-06-28T20:52:27Z")

</div>

It is because `Function`is an abstract type and every function has their separate types. Allocation occurs because it causes boxing and unboxing if some container has element type as an abstract type.

---

<div class="post-metadata">

**Author:** ![martintb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/martintb/32/37505_2.png) [@martintb](https://discourse.julialang.org/u/martintb)\
**Post date:** [June 29, 2022, 9:58am UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/3 "2022-06-29T09:58:45Z")

</div>

So if my container has elements of concrete types no allocation occurs?

---

<div class="post-metadata">

**Author:** ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)\
**Post date:** [June 29, 2022, 12:32pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/4 "2022-06-29T12:32:56Z")

</div>

Yes, if they have the same concrete type. However, two distinct functions in julia have different concrete types.

---

<div class="post-metadata">

**Author:** ![pitsianis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pitsianis/32/26588_2.png) [@pitsianis](https://discourse.julialang.org/u/pitsianis)\
**Post date:** [June 29, 2022, 1:09pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/5 "2022-06-29T13:09:17Z")

</div>

If I am not mistaken, you are complicating your life unnecessarily.

Do not build the array of functions. Build a matrix of function values  
`V = [fv[j](x[i]) for i in 1:length(x), j in 1:N]`

Wouldn’t your `y[i,j,k]` be `V[i,j] * V[i,k]`?

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [June 29, 2022, 3:14pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/6 "2022-06-29T15:14:20Z")

</div>

As others have suggested, you really should be doing this specific example a different way. However, in cases where one really does require the ability to do what you’re attempting in the original post, one can look into [the FunctionWrappers.jl package](https://github.com/yuyichao/FunctionWrappers.jl).

---

<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:** [June 29, 2022, 3:20pm UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/7 "2022-06-29T15:20:23Z")

</div>

> [@martintb](#):
>
> `*(f::Function, g::Function) = @. (x...) -> f(x...) * g(x...)`

In case you’re not aware, this is called [type piracy](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy), and is strongly discouraged.

---

<div class="post-metadata">

**Author:** ![martintb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/martintb/32/37505_2.png) [@martintb](https://discourse.julialang.org/u/martintb)\
**Post date:** [June 30, 2022, 7:24am UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/8 "2022-06-30T07:24:49Z")

</div>

Thanks! Is there any documentation or explanation how to use this package?

---

<div class="post-metadata">

**Author:** ![martintb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/martintb/32/37505_2.png) [@martintb](https://discourse.julialang.org/u/martintb)\
**Post date:** [June 30, 2022, 7:30am UTC](https://discourse.julialang.org/t/efficient-evaluation-of-a-matrix-of-function-products/83466/9 "2022-06-30T07:30:08Z")

</div>

@DNF I was aware that it is far from good practice what I’m doing but I couldn’t yet find a different way to get the desired functionality.

@pitsianis For this simple example that is true. However, in practice I don’t know any of the entries of my array of functions explicitly. They are constructed on the go depending on my system as sums/products of some base functions. Of course, one could still evaluate all components at the desired points and sum/multiply them in the required way but I feel like this would be even more complicated whereas constructing arrays of functions is just really convenient.
