4
$\begingroup$

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?

$\endgroup$
  • 2
    $\begingroup$ Notice your first line of code isn't compiled actually because Apply will be compiled only if its first argument is Times or Plus. $\endgroup$ – xzczd Sep 28 '16 at 12:02
  • 3
    $\begingroup$ 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. $\endgroup$ – xzczd Sep 28 '16 at 12:10
  • 4
    $\begingroup$ -1 for poor formatting; format your code, and I will remove -1. $\endgroup$ – QuantumDot Sep 28 '16 at 13:20
  • 1
    $\begingroup$ Sorry, I earned the -1 indeed. I will invest more time in posting an answer next time. Apologies again $\endgroup$ – Breugem Sep 28 '16 at 15:28
12
$\begingroup$

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 ...

$\endgroup$
  • 2
    $\begingroup$ 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. $\endgroup$ – Michael E2 Sep 28 '16 at 12:33
  • 2
    $\begingroup$ Compare with Compile[{{x, _Integer}}, Switch[x, 1, 10, 2, 20, _, 0]]. $\endgroup$ – Michael E2 Sep 28 '16 at 12:36
  • $\begingroup$ @MichaelE2 You are right, not a bug. $\endgroup$ – Szabolcs Sep 28 '16 at 12:37
  • 2
    $\begingroup$ FWIW, it's consistent with the regular Mathematica value of Switch[1., 1, 10, 2, 20, _, 0]. $\endgroup$ – Michael E2 Sep 28 '16 at 12:41
  • 1
    $\begingroup$ @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. $\endgroup$ – Michael E2 Sep 28 '16 at 22:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.