3

First, we load some tools related to Compile for analysis.

Needs["CompiledFunctionTools`"]
On["CompilerWarnings"];
SetSystemOptions["CompileOptions" -> "CompileReportExternal" -> True];

0

test0 = Compile[{x}, ConstantArray[x, {2, 2}]]

will not show message, but

test0 // CompilePrint

shows there is MainEvaluate like this

T(R2)1 = MainEvaluate[ Hold[ConstantArray][ R0, T(I1)0]]

1

test1 = Compile[{x}, Evaluate@ConstantArray[x, {2, 2}]]

test1 actually successfully compiled ConstantArray!! Because test1//CompilePrint shows

T(R2)0 = {{R0, R0}, {R0, R0}}

This is understandable, according to the doc

You can use Compile[...,Evaluate[expr]] to specify that expr should be evaluated symbolically before compilation.

2

Now comes the strangest part

test2 = Compile[{x, y}, Evaluate@ConstantArray[x, {2, 2}]; y]

running this directly popup error message

Compile::noinfo: No information is available for compilation of Evaluate[ConstantArray[x,{2,2}]]. The compiler will use an external evaluation and make assumptions about the return type. >>

Compile::extscalar: Evaluate[ConstantArray[x,{2,2}]] cannot be compiled and will be evaluated externally. The result is assumed to be of type Void. >>

and test2//CompilePrint shows

V17 = MainEvaluate[ Function[{x, y}, {{x, x}, {x, x}}][ R0, R1]]

This is different from test0, but it is still a MainEvaluate.

3

Let us see this

test3 = Compile[{x}, Block[{y}, y = Evaluate@ConstantArray[x, {2, 2}]]]
test3 // CompilePrint

also show error message and

1   T(R2)1 = MainEvaluate[ Hold[ConstantArray][ R0, T(I1)0]]
2   T(R2)2 = MainEvaluate[ Hold[Evaluate][ T(R2)1]]

4

Since test1 is full compiled, so we can inline it freely as follows

Compile[{x, y}, test1[x]; y, 
  CompilationOptions -> {"InlineExternalDefinitions" -> 
     True}] // CompilePrint

Compile[{x}, Block[{y}, y = test1[x]], 
  CompilationOptions -> {"InlineExternalDefinitions" -> 
     True}] // CompilePrint

The above two both are fully compiled. Free from MainEvaluate.

This trick also works for IdentityMatrix, DiagonalMatrix

Question:

  1. Why Compile[...,Evaluate[expr]] is not working for ConstantArray for situation 2 and 3 ?
  2. Why in 1, there is no error message, while in 2 and 3 there are error message?
jkuczm
  • 15,078
  • 2
  • 53
  • 84
matheorem
  • 17,132
  • 8
  • 45
  • 115
  • 2
    Evaluate must wrap the whole argument, it does not work buried inside a CompoundExpression. – Simon Woods Dec 31 '15 at 16:56
  • @SimonWoods hi, Simon. What do you mean? – matheorem Dec 31 '15 at 16:58
  • He means that Compile[{x,y}, Evaluate[Block[{a}, a=ConstantArray[x, {2,2}]; y; a}]]], with Evaluate surrounding the whole expression, works. If you need to control evaluation, using InlineExternalDefinitions as you show is the way to go. No idea on the error messages. – ZachB Jan 01 '16 at 02:48
  • @ZachB Thank you, you are right. But this kind of Evaluation of whole block is not useful, since most of the time, we have a lot more code in a block to be compiled, evaluate the whole will spoil the whole thing – matheorem Jan 01 '16 at 03:09
  • 1
    This behavior of Evaluate is documented, in Possible Issues section we can read: "Evaluate works only on the first level, directly inside a held function". To overcome this, you can use something like following function: deepEvaluate = Function[, Unevaluated[#] /. HoldPattern[Evaluate][x_] :> RuleCondition[x], HoldFirst]; Compile[{x, y}, Evaluate@ConstantArray[x, {2, 2}]; y] // deepEvaluate. – jkuczm Jan 01 '16 at 19:11
  • @jkuczm Wow, your deepEvaluate is extremely useful in Compile. Thanks so much for sharing. Would you like to make it an answer and add some explanation? – matheorem Jan 02 '16 at 06:23

1 Answers1

6
  1. Why Compile[...,Evaluate[expr]] is not working for ConstantArray for situation 2 and 3 ?

It doesn't work as you expect because, as already noted in comments, Evaluate is to deep inside Compile expression.

As we can read in Possible Issues section of Evaluate documentation:

Evaluate works only on the first level, directly inside a held function

In Compile[{x, y}, Evaluate@ConstantArray[x, {2, 2}]; y] expression, Evaluate is on second level, inside CompoundExpression and leads to MainEvaluate call in which it's put inside a function: Function[{x, y}, Evaluate@ConstantArray[x, {2, 2}]]. Since now Evaluate is on first level inside Function, it evaluates to Function[{x, y}, {{x, x}, {x, x}}].

In Compile[{x}, Block[{y}, y = Evaluate@ConstantArray[x, {2, 2}]]] expression, Evaluate is in level 3 inside Block and Set.


In cases in which you want to evaluate sub-expression on arbitrary level before evaluating whole Compile expression, you may use following function.

ClearAll[deepEvaluate]
SetAttributes[deepEvaluate, HoldFirst]
deepEvaluate[expr_] := 
   Unevaluated[expr] /. HoldPattern[Evaluate][subExpr_] :> RuleCondition[subExpr]

It takes unevaluated Compile expression and replaces all sub-expressions wrapped with Evaluate with their evaluated forms using undocumented RuleCondition. If one wants to stick with documented functions only, then RuleCondition can be replaced by Trott-Strzebonski in-place evaluation.

With deepEvaluate, ConstantArray is evaluated in both compiled functions:

Compile[{x, y}, Evaluate@ConstantArray[x, {2, 2}]; y] // 
  deepEvaluate // CompilePrint
Compile[{x}, Block[{y}, y = Evaluate@ConstantArray[x, {2, 2}]]] // 
  deepEvaluate // CompilePrint

they both have T(R2)0 = {{R0, R0}, {R0, R0}} in byte code.

For more complicated problems of partial evaluation of held expressions there are also techniques like: injector pattern (also in nested version), code freezing, or step by step evaluation.


  1. Why in 1, there is no error message, while in 2 and 3 there are error message?

As to this question, unfortunately I have no idea.

jkuczm
  • 15,078
  • 2
  • 53
  • 84
  • accpet your answer,+1. For CompoundExpression, do you mean for A;B;C, it is actually CompoundExpression[A,B,C], so A is in 2nd level? – matheorem Jan 04 '16 at 01:31
  • Yes, look at Hold[A; B; C] // FullForm. A is in first level of CompoundExpression, so in second level of Hold[A; B; C]. – jkuczm Jan 04 '16 at 08:59
  • Thank you for clarifying this. Actually I tried FullForm[A;B;C] and can't see CompundExpression. Now I understand. – matheorem Jan 04 '16 at 10:55