List of compilable functions
Yes, but this only exists in version 8 onwards and is undocumented:
Compile`CompilerFunctions[] // Sort
giving, for reference:
{Abs, AddTo, And, Append, AppendTo, Apply, ArcCos, ArcCosh, ArcCot, ArcCoth, ArcCsc,
ArcCsch, ArcSec, ArcSech, ArcSin, ArcSinh, ArcTan, ArcTanh, Arg, Array, ArrayDepth,
Internal`Bag, Internal`BagPart, BitAnd, BitNot, BitOr, BitXor, Block, BlockRandom, Boole,
Break, Cases, Catch, Ceiling, Chop, Internal`CompileError, System`Private`CompileSymbol,
Complement, ComposeList, CompoundExpression, Conjugate, ConjugateTranspose, Continue,
Cos, Cosh, Cot, Coth, Count, Csc, Csch, Decrement, Delete, DeleteCases, Dimensions,
Divide, DivideBy, Do, Dot, Drop, Equal, Erf, Erfc, EvenQ, Exp, Fibonacci, First,
FixedPoint, FixedPointList, Flatten, NDSolve`FEM`FlattenAll, Floor, Fold, FoldList, For,
FractionalPart, FreeQ, Compile`GetElement, Goto, Greater, GreaterEqual, Gudermannian,
Haversine, If, Im, Implies, Increment, Inequality, Compile`InnerDo, Insert,
IntegerDigits, IntegerPart, Intersection, InverseGudermannian, InverseHaversine,
Compile`IteratorCount, Join, Label, Last, Length, Less, LessEqual, List, Log, Log10,
Log2, LucasL, Map, MapAll, MapAt, MapIndexed, MapThread, NDSolve`FEM`MapThreadDot,
MatrixQ, Max, MemberQ, Min, Minus, Mod, Compile`Mod1, Module, Most, N, Negative, Nest,
NestList, NonNegative, Not, OddQ, Or, OrderedQ, Out, Outer, Part, Partition, Piecewise,
Plus, Position, Positive, Power, PreDecrement, PreIncrement, Prepend, PrependTo, Product,
Quotient, Random, RandomChoice, RandomComplex, RandomInteger, RandomReal, RandomSample,
RandomVariate, Range, Re, ReplacePart, Rest, Return, Reverse, RotateLeft, RotateRight,
Round, RuleCondition, SameQ, Scan, Sec, Sech, SeedRandom, Select, Set, SetDelayed,
Compile`SetIterate, Sign, Sin, Sinc, Sinh, Sort, Sqrt, Internal`Square, Internal`StuffBag,
Subtract, SubtractFrom, Sum, Switch, Table, Take, Tan, Tanh, TensorRank, Throw, Times,
TimesBy, Tr, Transpose, Unequal, Union, Unitize, UnitStep, UnsameQ, VectorQ, Which,
While, With, Xor}
As of Mathematica 10.0.2, there are also the following functions:
{Gamma, Indexed, LogGamma, LogisticSigmoid, Internal`ReciprocalSqrt}
As of Mathematica 11, there are also the following functions:
{Internal`Expm1, Internal`Log1p, Ramp}
As of Mathematica 11.2, there are also the following functions:
{RealAbs, RealSign}
About Tr
:
Please note that Tr
appears in this list, but cannot actually be compiled without a call to MainEvaluate[]
. It is unclear if this is deliberate or a bug.
Edit: additional functions
I have just discovered the symbol Internal`CompileValues
, which provides various definitions and function calls needed to compile further functions not in the list above. Using the following code,
Internal`CompileValues[]; (* to trigger auto-load *)
ClearAttributes[Internal`CompileValues, ReadProtected];
syms = DownValues[Internal`CompileValues] /.
HoldPattern[Verbatim[HoldPattern][Internal`CompileValues[sym_]] :> _] :>
sym;
Complement[syms, Compile`CompilerFunctions[]]
we get some more compilable functions as follows:
{Accumulate, ConstantArray, Cross, Depth, Det, DiagonalMatrix,
Differences, NDSolve`FEM`FEMDot, NDSolve`FEM`FEMHold,
NDSolve`FEM`FEMInverse, NDSolve`FEM`FEMPart, NDSolve`FEM`FEMTDot,
NDSolve`FEM`FEMTotalTimes, NDSolve`FEM`FEMZeroMatrix, FromDigits,
Identity, IdentityMatrix, Inverse, LinearSolve, Mean, Median, Nand,
NestWhile, NestWhileList, Nor, Norm, Ordering, PadLeft, PadRight,
Permutations, Ratios, Signature, SquareWave, StandardDeviation,
Tally, Total, TrueQ, Variance}
Looking at the definition of Internal`CompileValues[sym]
for sym in the list above will provide some additional information about how these functions are compiled. This can range from type information (for e.g. Inverse
), through to an implementation in terms of lower-level functions (e.g. NestWhileList
). One can presumably also make one's own implementations of non-compilable functions using this mechanism, giving Compile
the ability to compile a wider range of functions than it usually would be able to.
As of Mathematica 10.3, there are also the following functions:
{DeleteDuplicates, Region`Mesh`SmallMatrixRank,
Region`Mesh`SmallQRSolve, Region`Mesh`SmallSingularValues,
Region`Mesh`SmallSingularValueSystem, Region`Mesh`SmallSVDSolve,
NDSolve`SwitchingVariable}
As of Mathematica 11, there are also the following functions:
{NearestFunction, RegionDistanceFunction, RegionMemberFunction, RegionNearestFunction}
Edit 2: the meaning of the second list
In response to a recent question, I want to be clear that the presence of a function in the second list given above does not necessarily mean it can be compiled into a form free of MainEvaluate
calls. If a top-level function is already highly optimized (as e.g. LinearSolve
is), the purpose of Internal`CompileValues[func]
may be solely to provide type information on the return value, assuming that this can be inferred from the types of the arguments or some other salient information. This mechanism allows more complex functions that call these highly-optimized top-level functions to be compiled more completely since there is no longer any question of what the return type may be and so further unnecessary MainEvaluate
calls may be avoided. It does not imply that the use of MainEvaluate
is unnecessary to call the function itself.
In addition to Oleks list, there is of course a way to study what happens under the hood.
f = Compile[{{x, _Integer, 1}},
Accumulate[x]
];
<< CompiledFunctionTools`
CompilePrint[f]
(*
1 argument
1 Integer register
2 Tensor registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}
T(I1)0 = A1
I0 = 4
Result = T(I1)1
1 T(I1)1 = Accumulate[ T(I1)0, I0]]
2 Return
*)
Here you see, that Accumulate
can be compiled down, the question is where does this come from? Since version 8 you can compile to C-code, so let's do this and check what happens
<< CCodeGenerator`
CCodeGenerate[f, "fun", "tmp.c"];
FilePrint["tmp.c"]
I won't copy the whole output, but inspecting the code shows you
FP0 = funStructCompile->getFunctionCallPointer("Accumulate");
So the library extracts a function pointer from another (the WolframRTL) library. This library is distributed with Mathematica and you should have it in your SystemFiles/Libraries/$SystemID
directory. You can now study this library by using tools like nm
(on *nix systems) showing you the exported symbols.
This is a very long list of course and maybe a bit cryptic to those not used to C-programming, but it should be readable. Here a short snip
00000000003327d0 T _MTensor_outerList
0000000000336e10 T _MTensor_outerPlus
00000000003352a0 T _MTensor_outerTimes
000000000032d1f0 t _MTensor_pTranspose
00000000003291b0 T _MTensor_pad
000000000032a580 T _MTensor_position
0000000000326140 T _MTensor_reallocateAndCopyData
0000000000325750 t _MTensor_releaseData
00000000003263f0 T _MTensor_resetDimensions
0000000000328f90 T _MTensor_reverse
000000000032cc80 T _MTensor_rotate
The question is, can you get more insight (if wanted) when inspecting this together with the list provided by Olek? I think it depends, sometimes yes, sometimes no. In my opinion, it is always nice to have a clue what's going on in the deep.
One example from the Compile`CompilerFunctions[]
list is the function Outer
. As you can see in the output above, this function does not directly exist, but is split into three forms, outerList
, outerPlus
and outerTimes
. Regarding this, it seems Outer
cannot be compiled in every form. Let's test this
f = Compile[{{x, _Integer, 1}},
Outer[List, x, x]
];
CompilePrint[f]
(*
1 T(I3)1 = OuterList[ T(I1)0, T(I1)0, I0, I0]]
)*
This works as expected and we see the function OuterList
is used. You can if you want to inspect the c-code too. Let me skip this here and try the same function with a Divide
as head
f = Compile[{{x, _Integer, 1}},
Outer[Divide, x, x]
];
(*
Compile::cpapot: Compilation of Outer[Divide,x,x] is not supported
for the function argument Complex. The only function arguments supported
are Times, Plus, or List. Evaluation will use the uncompiled function. >>
*)
If the error message would not point out directly, that Outer
is only possible with the 3 heads, one could argue, that Divide
is a bad function anyway since integers are not closed under this operation. You can easily try it with Complex
and get the same message.
To summarize: Usually, you don't need any list of supported functions, because the rule of thumb is, that compile will not work with already optimized, complicated Mathematica-methods. This includes NIntegrate
, FindRoot
or NMinimize
. Nevertheless, Compile
can easily be used to make those function-calls really fast. What you have to do is to compile your target function, because the most time with stuff like NIntegrate
is spent, evaluating the integrand. The same is true for FindRoot
, NMinimize
and many more methods.
Another good indicator to guess whether or not a function is supported is to look at the kinds of functions of Oleks list. There are exceptions to this rule but basically the list of supported functions can be divided into two classes. Simple numerical functions like Sin
or Xor
and functions which help you to work with tensors. I don't remember how often I wished I simply had Tally
, Map
or Fold
in C. Even the addition or multiplication of tensors must be done manually.
Therefore, if a Mathematica-function implements a complicated method, when it's not a mathematical function or when it does not help you working with tensors/lists, it is most probably not supported by Compile
.
Warning: The SetSystemOptions
method to detect failed compilation, described below, is not 100% reliable. Please see the comments (e.g. trC = Compile[{{a, _Integer, 2}}, Tr[a]]
won't warn).
I assume you need the list of compilable functions to make sure that all of your code will be properly compiled, and it won't take any speed penalties (that why I was looking for this information before). People have shown you how to print the compiled code and check that there are no calls to MainEvaluate
in it. There is an alternative and simpler way of working:
SetSystemOptions["CompileOptions" -> "CompileReportExternal" -> True]
After setting this, Compile
will warn about uncompilable things:
In[4]:= cf1 = Compile[{x}, Total[x]]
During evaluation of In[4]:= Compile::extscalar:
Total[x] cannot be compiled and will be evaluated externally.
The result is assumed to be of type Real. >>
Out[4]= CompiledFunction[{x},Total[x],-CompiledCode-]
In[5]:= cf2 = Compile[{{x,_Integer,1}}, Total[x]]
Out[5]= CompiledFunction[{x},Total[x],-CompiledCode-]
This is better than just thinking about which function is compilable and which isn't because as you can see, whether something can be compiled also depends on context (Total
in this example.)
For completeness, let me show that CompilePrint[cf1]
gives
R0 = A1
Result = R1
1 R1 = MainEvaluate[ Hold[Total][ R0]]
2 Return
while CompilePrint[cf2]
gives
T(I1)0 = A1
I0 = 4
Result = I1
1 I1 = TotalAll[ T(I1)0, I0]]
2 Return