Mathematica8 can compile this function but Mathematica 9 can't if I set CompilationTarget -> "C"

11

Bug introduced in 9.0 and persisting through 11.0


Following code worked on Mathematica 8, but in Mathematica 9 it can't be compiled, it return this message

CompiledFunction::cflist: Nontensor object generated; proceeding with uncompiled evaluation. >>

How can I fix this?

Clear[cf1];
cf1 = Compile[{},
   Module[{s = 0.0},
    Do[
      If[s > 15, Print@i; Break[]];
      s = s + 1.0/i;
      , {i, 10^7}];
    ], CompilationTarget -> "C"];

cf1[]

expression

Posted 2013-06-02T18:05:50.433

Reputation: 3 966

@OleksandrR. do you know if this bug is fixed in v10? – QuantumDot – 2016-03-19T08:12:10.407

This issue still persists. Is it reported and confirmed by WRI to be a bug than intended design? – Silvia – 2020-05-25T11:58:45.767

3You function does not return anything and it uses a Print which is never a good idea inside a compiled function. Removing the Print fixed your problem here. – halirutan – 2013-06-02T18:23:50.987

1Although I haven't tried it, I'm certain that @halirutan is correct so, probably, V9 is doing a better job of flagging uncompilable functions In addition, I'd point out that I don't see any output coming from your function. Perhaps, you should replace Do with Table and remove the semi-colon from the final statement inside the loop. – Mark McClure – 2013-06-02T18:31:55.577

2Regardless of the fact that the use of Print is not optimal, this does seem to be a bug in the version 9 VM or CCodeGenerator\`` package. The same bytecode is generated by versions 8 and 9, but the interpretation of it by version 9 seems to be incorrect. It's not clear to me why this only shows up withCompilationTarget -> "C"`. – Oleksandr R. – 2013-06-02T18:52:43.033

1@OleksandrR. But Print, so far as I know, is not compilable. It certainly doesn't appear in the list Compile`CompilerFunctions[] and CompilePrint[cf1] reveals a callback to MainEvaluate. – Mark McClure – 2013-06-02T19:48:40.300

1

@MarkMcClure that's correct, but irrelevant to the situation except in as much as it might expose a bug that would remain hidden otherwise (cf. this). The presence of a call back into the interpreter certainly should not trigger an exception that leads to re-evaluation of the entire function, and especially not in a version-specific way and only for a particular compilation target. I think the most likely situation is that version 9 produces an incorrect translation of the bytecode to C.

– Oleksandr R. – 2013-06-02T20:11:09.893

Answers

16

In version 8, the callback into the interpreter (also known as MainEvaluate or WolframCompileLibrary_Functions->evaluateFunctionExpression) looks like

Function[{iCompile$1}, Block[{i = iCompile$1}, {Print[i], i}]][register]

where register is the (integer, scalar) register that contains the value of i. This looks correct to me, although I'll admit that I don't understand the reason for translating Print[i] into {Print[i], i}.

In version 9, however, it takes the incorrect form:

Function[{}, Print[i]][register]

Since this is obviously wrong (which one can also see from the fact that i is printed literally), the question might as well ask why it works at all, even without translating the bytecode to C. The reason is that the bytecode contains the instruction

{46, Function[{}, Print[i]], {i, 2, 0, 3, Block}, 6, 0, 17}

in both versions, and it is the responsibility of the execution host (either the VM, or the CCodeGenerator` package in case of translation to C) to interpret this into a valid call. Clearly, the VM is capable of doing this in both version 8 and version 9, which is not surprising since I don't believe that any changes were made to the VM in version 9. Thus, although this problem resembles the one discussed in this question, I don't think the bugs are actually related.

However, the CCodeGenerator` package was changed in version 9, and appears to have become broken in this respect. In conclusion: it's a bug--please report it.

Since bugs may not be fixed in a publicly available release for some time, you can work around the issue simply by removing the reference to Print and returning the value of i instead:

Clear[cf1];
cf1 = Compile[{},
   Module[{s = 0.0},
    Do[If[s > 15, Return[i]]; s = s + 1.0/i, {i, 10^7}]
   ], CompilationTarget -> "C"
  ];

cf1[]

Oleksandr R.

Posted 2013-06-02T18:05:50.433

Reputation: 22 073