# different situations with Compilation of ConstantArray

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?
• Evaluate must wrap the whole argument, it does not work buried inside a CompoundExpression. Dec 31, 2015 at 16:56
• @SimonWoods hi, Simon. What do you mean? Dec 31, 2015 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. Jan 1, 2016 at 2: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 Jan 1, 2016 at 3:09
• 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. Jan 1, 2016 at 19:11

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.

• 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? Jan 4, 2016 at 1: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]. Jan 4, 2016 at 8:59
• Thank you for clarifying this. Actually I tried FullForm[A;B;C] and can't see CompundExpression`. Now I understand. Jan 4, 2016 at 10:55