# Fast evaluation of multiple functions on multiple arguments

**URL:** <https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040>\
**Category:** Performance\
**Created:** [June 7, 2019, 11:06am UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040 "2019-06-07T11:06:55Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [June 7, 2019, 11:06am UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/1 "2019-06-07T11:06:55Z")

</div>

In my application I often have a bunch of functions that I need to evaluate on many arguments (i.e. each combination of function and argument).  
I thought of extending the `Base.map` function as follows:

```julia
function Base.map(F::AbstractArray{Function}, A::AbstractArray)
    [[f(a) for f in F] for a in A]
end

```

Although this produces the correct output, it is about 10 times slower than expected. On the other hand, the following

```julia
function Base.map(F::AbstractArray{Function}, A::AbstractArray)
    [Base.map(f, A) for f in F]
end

```

is as fast as it should be, but it does not have the desired output format (for my use).

1. is the above extension of `Base.map` duplicating some existing function in julia?
2. how do I perform the computation in roughly the same time, while obtaining the desired output format?

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [June 7, 2019, 11:16am UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/2 "2019-06-07T11:16:05Z")

</div>

You can just do what you want with the broadcasting syntax like this:

```julia
map.(F, Ref(A))

```

The `Ref` here is to make `A` a scalar with respect to broadcasting, so that it iterates `map(f, A)` over all `f ∈ F`.

If performance is important, you might want to consider using a tuple for the functions instead of an array, since `Function` is an abstract type and therefore, your function will not be type stable.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [June 7, 2019, 11:16am UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/3 "2019-06-07T11:16:11Z")

</div>

Could perhaps do something like:

```julia
julia> fs = [sin, cos, tan];

julia> args = [0.0, pi/2, pi];

julia> apply(f, x) = f(x);

julia> apply.(fs, permutedims(args))
3×3 Array{Float64,2}:
 0.0 1.0 1.22465e-16
 1.0 6.12323e-17 -1.0
 0.0 1.63312e16 -1.22465e-16

```

But I guess that gives you a matrix which you don’t want.

---

<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 7, 2019, 11:32am UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/4 "2019-06-07T11:32:10Z")

</div>

If one loop is fast and the other is slow, it makes a difference which one is the inner and which is the outer. Iterating over an array of `Function`s is possibly slow.

Maybe you should do the calculations with the fast inner loop, and then rearrange the output afterwards.

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [June 7, 2019, 12:05pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/5 "2019-06-07T12:05:22Z")

</div>

Thanks, this looks as if it might to the job!

Regarding type stability, you mean that I should define `map` to take as follows:

```julia
function Base.map(F::NTuple{N, Function}, A::AbstractArray) where N
    map.(F, Ref(A))
end

```

? Does it mean that the compiler will specialize for a specific set of functions?

In fact, if I do this, the result seems to be slightly faster even than `[Base.map(f, A) for f in F]` and there are no type warnings.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [June 7, 2019, 12:50pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/6 "2019-06-07T12:50:49Z")

</div>

> [@simsurace](#):
>
> Regarding type stability, you mean that I should define `map` to take as follows:

It’s generally bad practise to overload methods from Base for Base types, as this could have unexpected side effects.

> [@simsurace](#):
>
> Does it mean that the compiler will specialize for a specific set of functions?

Yes, this should happen. This also explains, why your second function was faster than the first, since map could specialize on each `f` individually, at least.

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [June 7, 2019, 1:29pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/7 "2019-06-07T13:29:54Z")

</div>

> [@simeonschaub](#):
>
> It’s generally bad practise to overload methods from Base for Base types, as this could have unexpected side effects.

I see. Unfortunately there are no existing methods for `Base.map` for tuples of functions (there is probably a good reason for this). The tradeoff I have is that I have to separately code function evaluation on a sample depending on whether the function is scalar- or vector-valued. If I only need the function for a custom type, the overloading should be fine. In the case where I need the function on arbitrary arrays, I could define `Map = deepcopy(Base.map)` and then overload the `Map` and only work with `Map` in all of my code. Or would there be an even simpler way?

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [June 7, 2019, 1:31pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/8 "2019-06-07T13:31:08Z")

</div>

Thanks! I’m sure this will also become useful at some point.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [June 7, 2019, 1:42pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/9 "2019-06-07T13:42:45Z")

</div>

> [@simsurace](#):
>
> The tradeoff I have is that I have to separately code function evaluation on a sample depending on whether the function is scalar- or vector-valued.

The way I proposed, with the dot syntax will work just fine, if F is a scalar, too.

> [@simsurace](#):
>
> I could define `Map = deepcopy(Base.map)` and then overload the `Map` and only work with `Map` in all of my code.

You have to be careful with these types of function definitions, since non-const functions can negatively impact performance. If you really want to put it in its own function, I would just declare it just like any other function and give it a name, that makes the difference clear.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 7, 2019, 2:19pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/10 "2019-06-07T14:19:23Z")

</div>

> [@simeonschaub](#):
>
> You have to be careful with these types of function definitions, since non-const functions can negatively impact performance

That is the last thing you need to worry about and the non-constness is also not related to copying. It could even be local for example.

However, that just won’t work. `deepcopy` only copy the value, it does not copy the type, what you’ll get is an object of the same type (`typeof(x) === typeof(deepcopy(x))` should always be true) and since the method table is a property of the **type** , deepcopy will not change which method table you extend.

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [June 7, 2019, 2:36pm UTC](https://discourse.julialang.org/t/fast-evaluation-of-multiple-functions-on-multiple-arguments/25040/11 "2019-06-07T14:36:46Z")

</div>

Thanks! I just noticed that the `deepcopy` construction is not going to work.  
In the end, it seems the safest bet is to define a new function `Map` and call `Base.map` for those methods I will need and then define new methods for the function tuples on top of that.
