# Error messages from compiling the Piecewise function

The following works

Compile[{{x, _Real}}, Piecewise[{{{0., 0.}, x > 5.}}, {1., 1.}]]


but if I enter the Piecewise[...] in the bracket style, I get two error messages

Compile::cif: The types of the two results in If[True,{1.,1.},0] are incompatible because their ranks are different. Evaluation will use the uncompiled function. >>

Compile::cif: The types of the two results in If[x>5.,{0.,0.},If[True,{1.,1.},0]] are incompatible because their ranks are different. Evaluation will use the uncompiled function. >>

It seems the bracket style input form of the Piecewise function is transformed into

If[x>5.,{0.,0.},If[True,{1.,1.},0]]


and 0 has a different type than {1.,1.}.

Here is the screenshot:

In[2] works as expected, but when I type the bracket style of Piecewise in In[3], it doesn't work. However, if I copy the output bracket style of Piecewise in Out[2] and put it in In[4], it works again.

Why this happens and how to fix it? Am I making stupid mistakes or what?

This is not a complete answer as I don't know precisely why this happens, unless we account for it as a simple omission in/limitation of the compiler (which it could well be). Nonetheless, I can at least tell you what is happening.

As you know, Compile has HoldAll. The fact that the Piecewise is not evaluated before being seen by Compile when entered directly as a bracket leads to its translation into slightly different code.

The evaluated form of the Piecewise is:

Piecewise[{{{0., 0.}, x > 5.}}, {1., 1.}]


Compile correctly translates this into code completely equivalent to:

If[x > 5., {0., 0.}, {1., 1.}]


However, when faced with the unevaluated form as entered using the bracket, i.e.

Piecewise[{{{0., 0.}, x > 5.}, {{1., 1.}, True}}]


it produces (as you rightly say)

If[x > 5., {0., 0.}, If[True, {1., 1.}, 0]]


which is not compilable due to the obvious mismatch in tensor rank between {1., 1.} and 0. We can fix the problem at this stage by substituting {0., 0.} in place of 0, but not by simply removing the 0 (as this is interpreted as Null, which is of a special Null or "void" type). A better way is simply to remove the redundant nested If and place the default value directly in the body of the enclosing If.

Alternatively, we might manually do the same transformation that evaluation effects:

Hold@Compile[{{x, _Real}}, Piecewise[{{{0., 0.}, x > 5.}, {{1., 1.}, True}}]] /.
HoldPattern@Piecewise[{conds__List, {default_, True}}] :>
Piecewise[{conds}, default] // ReleaseHold


However, my personal preference would be to avoid Piecewise and similar functions when writing compilable code. As we saw above, the compiler cannot work with these directly, instead translating them into nested Ifs before compilation. In my opinion, it is much less likely to lead to errors and oddities of the sort encountered here if one uses only constructs that have direct equivalents in bytecode, and hence for which one can predict to a reasonable degree of accuracy what the compiled code will actually be.

• Nice answer. For future readers, use Which instead of Piecewise. – QuantumDot Mar 19 '16 at 8:28