# Can not understand this timing result

I set

a=1.
tmptmp = Tuples[Range /@ {1000, 100}].{{3 a, 0}, {0, Sqrt[3] a}}


And then run

Transpose[# +
Transpose[{{0, 0}, {a, 0}, {-a/2, Sqrt[3] a/2}, {3 a/2,
Sqrt[3] a/2}}]] & /@ tmptmp; // AbsoluteTiming


It takes 3.67229 sec on my computer

But if we run differently as

base = {{0, 0}, {a, 0}, {-a/2, Sqrt[3] a/2}, {3 a/2, Sqrt[3] a/2}};
Transpose[# + Transpose[base]] & /@ tmptmp; // AbsoluteTiming


It just takes 0.105543 sec

First question: Why such a difference?

The only thing I can guess is that maybe Transpose[# + Transpose[{{0, 0}, {a, 0}, {-a/2, Sqrt[3] a/2}, {3 a/2, Sqrt[3] a/2}}]]is not getting autocompiled. If so, why it is not autocompiled? And also comes the second question.

Second question: is there an option that can be turn on to indicate whenever there is an autocompile occured?

• Repeating these evaluations takes time. Do[Sqrt[3] a/2, {100000}] // AbsoluteTiming -> .7 . Why the interpreter can't readily see that that thing doesn't need to be reevaluated is a good question. Nov 6, 2015 at 14:37
• I believe it's just a matter of the number of symbolic nodes that Mathematica needs to "move" from one step to the next. Both calcs are mostly equal, (you can Trace[ ] them) except the second one is "shorter" because the base symbol is. Nov 6, 2015 at 14:58
• @belisariushassettled Hi, I am not sure if understand this sentence number of symbolic nodes that Mathematica needs to "move" from one step to the next. You mean the total step that Trace shows, right? Nov 7, 2015 at 2:17

For your first question

a=1.
tmptmp = Tuples[Range /@ {1000, 100}].{{3 a, 0}, {0, Sqrt[3] a}}


The basic answer is that in your first case

Transpose[# +
Transpose[{{0, 0}, {a, 0}, {-a/2, Sqrt[3] a/2}, {3 a/2,
Sqrt[3] a/2}}]] & /@ tmptmp


the variable a gets evaluated many many times.

I simplified the problem by defining a small number of tuples.

tmptmp = Tuples[Range /@ {2, 1}].{{3 a, 0}, {0, Sqrt[3] a}}


Then ran a Trace on

Trace[
Transpose[# +
Transpose[{{0, 0}, {a, 0}, {-a/2, Sqrt[3] a/2}, {3 a/2,
Sqrt[3] a/2}}]
] & /@ tmptmp
]


Below is an image of a formatted output from Trace

If you look closely you will see a being evaluated over and over ... again.

Your second approach is much faster because it skips all those a evaluations.

base = {{0, 0}, {a, 0}, {-a/2, Sqrt[3] a/2}, {3 a/2, Sqrt[3] a/2}};
Transpose[# + Transpose[base]] & /@ tmptmp //AbsoluteTiming


When you encounter problems like this With can be used so that you don't have to define a global variable (i.e., one that sticks around).

The following form is just as fast as the one with base defined globally.

With[
{
base = {{0, 0}, {a, 0},
{-a/2, Sqrt[3] a/2},
{3 a/2, Sqrt[3] a/2}}
},
Transpose[# + Transpose[base]] & /@ tmptmp
]


I am unaware of the answer to your second question about autocompile.

• Thank you for your analysis. I understand now that Map evaluate at the first step. This is really pitfall to me Nov 7, 2015 at 2:14

I address the second question.

Every now and then, questions turn up in connection with the autocompilation property of the function Map, this one being the latest. In the comments, it was mentioned by @Karsten7 that the CompileOptions can be set such that messages are generated if something goes wrong. That in fact answers more ore less the above question on how we can test if a function autocompiles one of its arguments.

Let us first inspect the CompileOptions.

SystemOptions["CompileOptions"]
(*
{CompileOptions->{ApplyCompileLength->\[Infinity],ArrayCompileLength->250,AutoCompileAllowCoercion->False,AutoCompileProtectValues->False,AutomaticCompile->False,BinaryTensorArithmetic->False,CompileAllowCoercion->True,CompileConfirmInitializedVariables->True,CompiledFunctionArgumentCoercionTolerance->2.10721,CompiledFunctionMaxFailures->3,CompileDynamicScoping->False,CompileEvaluateConstants->True,CompileOptimizeRegisters->False,CompileParallelizationThreshold->10,CompileReportCoercion->False,CompileReportExternal->False,CompileReportFailure->False,CompileValuesLast->True,FoldCompileLength->100,InternalCompileMessages->False,ListableFunctionCompileLength->250,MapCompileLength->100,NestCompileLength->100,NumericalAllowExternal->False,ProductCompileLength->250,ReuseTensorRegisters->True,SumCompileLength->250,SystemCompileOptimizations->All,TableCompileLength->250}}
*)


We see three options that could produce messages: CompileReportExternal, CompileReportFailure, InternalCompileMessages. The last one generates a message when the compilation fails, and the second one takes care that it is reported. When we set them to True, we will see a message when the compilation fails. Therefore, our test to see if a function autocompiles will simply be to use an argument for which the compilation fails. When we see the message, it autocompiles and otherwise not.

We also see some options that end on CompileLength and have the name of a Mathematica function in front: Array, Fold, Map, Nest, Product, Sum, Table. These are functions that do autocompile when the relevant argument is at least as long as the value given in the option.

Here is a demonstration. It is simple to construct a function that cannot be compiled. Just use a symbol without a value in the function body.

SetSystemOptions["CompileOptions" -> {"CompileReportFailure"->True, "InternalCompileMessages"->True}];

Clear[zz];

Array[#+zz&, {250}];
Fold[#+zz&, 0, Range[100]];
Map[#+zz&, Range[100]];
Nest[#+zz&, 0, 100];
Product[x+zz, {x, 1, 250}];
Sum[x+zz, {x, 1, 250}, Method->"Procedural"];
Table[x+zz, {x, 1, 250}];

(* During evaluation of In[4]:= Compile::compfail: Compilation of Array[#1+zz&,{250}] failed because zz was not a form suitable for the compiler.*)
(* other results skipped *)


All commands show a compilation error, similar to the one above. The function Sum can be used with a lot of options. For many of them, there is nothing numerical to do, so then there is no autocompilation.

Of course, many more functions autocompile. For example:

NIntegrate[x+zz,{x,0,1}]
(* During evaluation of In[26]:= Compile::compfail: Compilation of x+zz failed because zz was not a form suitable for the compiler, etc *)

NSum[x+zz, {x, 1, 1}]
(* During evaluation of In[28]:= Compile::compfail: Compilation of x+zz failed because zz was not a form suitable for the compiler, etc *)

Plot[x+zz,{x,0,1}]
(* During evaluation of In[20]:= Compile::compfail: Compilation of x+zz failed because zz was not a form suitable for the compiler, etc *)


A little bit surprising: Table does autocompile, but Do does not:

Do[x+zz, {x, 1, 5000}]
(* no message *)

• Great! When Karsten7 answered my question, I didn't realize it is related to this one. Thank you for the explanation Dec 10, 2016 at 12:42