6
$\begingroup$

The smallest sample I can find to reproduce this problem is:

test = Compile[{}, If[True, 1]];
<< CompiledFunctionTools`
CompilePrint@test
…………
 1    R0 = MainEvaluate[ Function[{}, If[True, 1]][ ]]
 2    Return

The problem disappears when the If[] is followed by a semicolon:

test = Compile[{}, If[True, 1];];
CompilePrint@test
…………
1     if[ !B0] goto 3
2     goto 3
3     Return

or enclosed by a redundant Do[]:

test = Compile[{}, Do[If[True, 1], {1}]];
CompilePrint@test
…………
1   I1 = I0
2   I3 = I2
3   goto 6
4   if[ !B0] goto 6
5   goto 6
6   if[ ++ I3 < I1] goto 4
7   Return

while a redundant Table[] won't help:

test = Compile[{}, Table[If[True, 1], {1}]];
CompilePrint@test
…………

1   I1 = I0
2   I4 = I3
3   T(R1)0 = Table[ I1]
4   I2 = I3
5   goto 8
6   R1 = MainEvaluate[ Function[{}, If[True, 1]][ ]]
7   Element[ T(R1)0, I4] = R1
8   if[ ++ I2 < I1] goto 6
9   Return

This phenomenon may lead to a total failure of compilation when codes become more complicated:

ie = 200;
ez = ConstantArray[0., {ie + 1}];
hy = ConstantArray[0., {ie}];

f1 = Compile[{{steps}}, 
   Module[{ie = ie, ez = ez, hy = hy}, 
    Do[ez[[2 ;; ie]] = ez[[2 ;; ie]] + (hy[[2 ;; ie]] - hy[[1 ;; ie - 1]]);
     ez[[1]] = Sin[n/10];
     hy[[1 ;; ie]] = hy[[1 ;; ie]] + (ez[[2 ;; ie + 1]] - ez[[1 ;; ie]]), {n, steps}];
    ez]];

f2 = Compile[{{steps, _Integer}, {test, True | False}}, 
   Module[{ie = ie, ez = ez, hy = hy}, 
    Do[ez[[2 ;; ie]] = ez[[2 ;; ie]] + (hy[[2 ;; ie]] - hy[[1 ;; ie - 1]]);
     ez[[1]] = Sin[n/10];
     hy[[1 ;; ie]] = hy[[1 ;; ie]] + (ez[[2 ;; ie + 1]] - ez[[1 ;; ie]]), {n, steps}];
    If[test, ez]]];

f1[1500]; // AbsoluteTiming
{0.0250000, Null}
f2[1500, True]; // AbsoluteTiming

Warnings……

{0.5730000, Null}

So, as the title said, If won't compile when its output is the output of Compile?

Of course it can be easily circumvented, but I wonder if there's a universal rule behind this, or it's just another unreasonable behavior of Compile?

$\endgroup$
2
  • 3
    $\begingroup$ Identical issue, and solution, to those discussed in this question earlier today. In fact I'd be tempted to close this as a duplicate, except that I think it shows the issue a bit more clearly than the other question. $\endgroup$ Commented Apr 18, 2014 at 13:26
  • $\begingroup$ @OleksandrR. In fact it's that question that motivate me to ask this one (I've noticed this behavior for some time), I read it but still failed to notice it's an identical issue 囧. $\endgroup$
    – xzczd
    Commented Apr 18, 2014 at 13:33

1 Answer 1

8
$\begingroup$

This is a type incompatibility problem. The compiler must make an assignment to the output of If in order to return a value. If[True, 1] is equivalent to If[True, 1, Null], and there is no type that can be assigned to both 1 and Null. You will get the same problem if you make an assignment to the If result when it isn't the final output of Compile:

CompilePrint @ Compile[{}, Block[{x}, x = If[True, 1]]; 2]
      I0 = 1
      I1 = 2
      B0 = True
      Result = I1

1 R0 = MainEvaluate[ Function[{}, If[True, 1]][ ]]
2 Return

I'm not sure why you don't get a message, in other cases you do:

CompilePrint @ Compile[{}, If[True, 1, {2, 3}]]

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

      I0 = 1
      T(I1)0 = {2, 3}
      B0 = True
      Result = R0

1 R0 = MainEvaluate[ Function[{}, If[True, 1, {2, 3}]][ ]]
2 Return

Note that if both returns from If are Null there is no problem:

CompilePrint @ Compile[{}, If[True, Null]]
      B0 = True
      Result = V17

1 if[ !B0] goto 3
2 goto 3
3 Return
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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