# Can one compile the Switch function?

I am aware that one can compile Which, e.g.:

ff = Compile[x, Which @@ {x < 0, 2, x >= 0, 3}
ff[1.]


3

A drawback of Which is that it evaluates x repeatedly until one of the conditions is satisfied. This is time consuming when x is a complicated expression or/and when the set of conditions is large. As a far as I know, the same issue arises with Piecewise.

Switch evaluates x only once, but seems to be not compilable. My try was as follows:

gg = Compile[x, Switch[x, x < 0, 3, x >= 0, 3]]
gg[1.]


CompiledFunction::cfse: Compiled expression Null should be a machine-size real number. >> CompiledFunction::cfex: Could not complete external evaluation at instruction 1; proceeding with uncompiled evaluation. >>

Does anyone know how to compile Switch correctly?

• Notice your first line of code isn't compiled actually because Apply will be compiled only if its first argument is Times or Plus. – xzczd Sep 28 '16 at 12:02
• Also, as a member for 3 years, please learn to format your code properly. And, you've totally misunderstand Switch in Mathematica, please check the document of Switch carefully. – xzczd Sep 28 '16 at 12:10
• -1 for poor formatting; format your code, and I will remove -1. – QuantumDot Sep 28 '16 at 13:20
• Sorry, I earned the -1 indeed. I will invest more time in posting an answer next time. Apologies again – Breugem Sep 28 '16 at 15:28

A drawback of the Which command is that it evaluates x repeatedly until one of the conditions of Which is satisfied. This is time consuming when x is a complicated expression or/and when the set of conditions is large.

This is not true in Compile as x will always be a number or an array. Multiple uses of x won't slow anything down.

It isn't even true outside of Compile in most practical cases unless you defined x using := instead of =.

The command "Switch" only evaluates x once, but seems to be not compilable.

Simple forms of Switch are compilable. In your question, you are misusing Switch. It takes patterns, not true/false conditions. Please read the documentation.

When using it in Compile, only literal patterns seem to be accepted. An exception is the last pattern, which must be _ to handle the default case.

Example:

cf = Compile[{{x, _Integer}},
Switch[x,
1, 10,
2, 20,
_, 0
]
]

"
1 argument
2 Boolean registers
8 Integer registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}

I0 = A1
I1 = 1
I4 = 20
I2 = 10
I3 = 2
I5 = 0
Result = I7

1   B0 = I0 == I1
2   if[ !B0] goto 5
3   I7 = I2
4   goto 11
5   B1 = I0 == I3
6   if[ !B1] goto 9
7   I6 = I4
8   goto 10
9   I6 = I5
10  I7 = I6
11  Return
"


If you try to use a more general pattern, such as _Integer or x_ /; x > 0, it will trigger a call to MainEvaluate (i.e. it won't be compiled) for that particular test.

Warning: When testing with literal patterns, it is important to be aware that 1. and 1 are considered to be different. We needed to explicitly specify that the input is an integer, otherwise it would be converted to a real (floating point) number, which never matches the integer 1. Thanks to @MichaelE2 for pointing this out!

In summary:

Inside Compile,

• use Switch if you need an equivalent of switch from C

• use Which if you need the equivalent of a sequence of if ... else if ... else if ...

• Try Compile[{x}, Switch[x, 1., 10, 2., 20, _, 0]]. Your input x is Real by default. Not sure I completely understand yet...-- I guess the compiler decides that a real x cannot match an integer 1 or 2, so it pre-evaluates the boolean condition to False. – Michael E2 Sep 28 '16 at 12:33
• Compare with Compile[{{x, _Integer}}, Switch[x, 1, 10, 2, 20, _, 0]]. – Michael E2 Sep 28 '16 at 12:36
• @MichaelE2 You are right, not a bug. – Szabolcs Sep 28 '16 at 12:37
• FWIW, it's consistent with the regular Mathematica value of Switch[1., 1, 10, 2, 20, _, 0]. – Michael E2 Sep 28 '16 at 12:41
• @AlexeyPopkov Yes, I get the same, and it seems quite normal, no? I mean in the first case, the type of x is by default _Real, so the input 1 is first converted to the real 1. before being passed to the compiled function. So it matches the case that returns 10. In the uncompiled Switch[..], the 1. does not match 1, since a Real is not an Integer. – Michael E2 Sep 28 '16 at 22:16