# Multiple Outputs (Tuple) from IfElse with VectorizationBase

**URL:** <https://discourse.julialang.org/t/multiple-outputs-tuple-from-ifelse-with-vectorizationbase/68255>\
**Category:** Performance\
**Tags:** loopvectorization\
**Created:** [September 16, 2021, 11:34am UTC](https://discourse.julialang.org/t/multiple-outputs-tuple-from-ifelse-with-vectorizationbase/68255 "2021-09-16T11:34:14Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [September 16, 2021, 11:34am UTC](https://discourse.julialang.org/t/multiple-outputs-tuple-from-ifelse-with-vectorizationbase/68255/1 "2021-09-16T11:34:14Z")

</div>

Hi there,

I am trying to experiment a bit with VectorizationBase to create functions that can be used inside the `@turbo` macro from LoopVectorization.

I have a use case where my computation can be significantly sped up in case one of my inputs is 0 (not only sped up but the full routine would lead to NaN values for points where the input is 0) so I was thinking of generating two subfunctions that support `Vec` inputs from VectorizationBase and call them using `IfElse.ifelse`.

Since I am dealing with Complex outputs and LoopVectorization does not currently support complex inputs, I would need to output 2 values out of the subfunctions (or two sets of `Vec`, one for the real and one for the complex part of the result).

Unfortunately it seems that `IfElse.ifelse` fails as soon as I want to produce more than one output from my subfunctions.

Here is a MWE of the problem I am facing.

```julia
using IfElse, VectorizationBase

 vx = Vec(ntuple(_ -> rand(0:3), VectorizationBase.pick_vector_width(Int64))...)

_simple(x) = (x,x)

_full(x) = (10x,5x)

IfElse.ifelse(vx == 0,_simple(vx)[1],_full(vx)[1])

```

The above example work, but if one removes the indexing inside the `ifelse` as follows:  
`IfElse.ifelse(vx == 0,_simple(vx),_full(vx))`

I get the following error:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/9/c9bfa40453cafd2ae7b4bc221b37ada3316fb452.png)

I could use two `ifelse` statements to gather both inputs separately but I guess that would re-perfom all the computations inside the subfunctions twice.

Is getting two (or more) outputs out of the `ifelse` possible or is it not supported yet?

Tagging @Elrod as he might be able to shed light into this 🙂

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [September 16, 2021, 12:53pm UTC](https://discourse.julialang.org/t/multiple-outputs-tuple-from-ifelse-with-vectorizationbase/68255/2 "2021-09-16T12:53:10Z")

</div>

> [@disberd](#):
>
> Is getting two (or more) outputs out of the `ifelse` possible or is it not supported yet?

I could add a method.  
And you wouldn’t have to recompute:

```julia
s = _simple(vx)
f = _full(vx)
x = IfElse.ifelse(vx == 0, s[1], f[1])
y = IfElse.ifelse(vx == 0, s[2], f[2])

```

Alternatively, this should already work:

```julia
VectorizationBase.data(IfElse.ifelse(vx == 0, VecUnroll(_simple(vx)), VecUnroll(_full(vx))))

```

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [September 16, 2021, 2:22pm UTC](https://discourse.julialang.org/t/multiple-outputs-tuple-from-ifelse-with-vectorizationbase/68255/3 "2021-09-16T14:22:46Z")

</div>

Thanks a lot,

Looking at your first proposed solution, this implies that whenever you have a `ifelse` branch both function are evaluated for each input before doing selection with the mask?

So there would be no actual time saving here by doing a branch inside the `@turbo` macro since both the simple and full version are evaluated for each input?

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [September 16, 2021, 2:36pm UTC](https://discourse.julialang.org/t/multiple-outputs-tuple-from-ifelse-with-vectorizationbase/68255/4 "2021-09-16T14:36:08Z")

</div>

> [@disberd](#):
>
> Looking at your first proposed solution, this implies that whenever you have a `ifelse` branch both function are evaluated for each input before doing selection with the mask?
> 
> So there would be no actual time saving here by doing a branch inside the `@turbo` macro since both the simple and full version are evaluated for each input?

Yes.  
Much of LoopVectorization’s performance benefit comes from SIMD, which stands for “Single Instruction Multiple Data”.

Basically, it applies each instruction to multiple data points. Trying to do this while handling branches is tricky.  
Referring to each iteration of a loop / element being processed as a “lane”, the simplest approach is to have each lane take both sides of the branch and then combine the results afterwards based on which side of the branch each particular lane would’ve taken.

If you have a rarely taken path that is also very slow, e.g. you have a function that needs lots of special handling over a certain rarely encountered range of the input, you could insert an actual branch and check `if VectorizationBase.vany(condition)` to only evaluate that branch if it is actually needed.
