Skip to main content

about Compile and return type


In the mathematica document "tutorial/CompilingWolframLanguageExpressions"


1


It says about how to set return type of a called function you used in Compile.


Clear[com]
com[i_] := Binomial[2 i, i]

test=Compile[{x, {i, _Integer}}, x^com[i], {{com[_], _Integer}}]

From the above example, we can see that because the com function evaluates to integer, so we set {{com[_], _Integer}} to let Compile know the return type of com.



But if you inspect it further


Needs["CompiledFunctionTools`"]
CompilePrint[test]

You can see there is MainEvaluate when calling function com.


So, I don't understand the meaning of this example in the document. If a compiled function has a MainEvaluate process, then I think compiling it is just nonsense, for it won't speed up things, right?


2


Then I came up with another question, it is also mentioned in the same document page. If we compile Sqrt as below


sqrtcom1 = Compile[{{x, _Real}}, Sqrt[x]]


we will run into problems if we evaluate sqrtom1[-1.], it will give errors like



CompiledFunction::cfn: Numerical error encountered at instruction 1; proceeding with uncompiled evaluation. >>



This is because the return type of Sqrt is assumed to be real by default. This can be see from


In[20]:= ToCompiledProcedure[sqrtcom1][[4]]

Out[20]= CompiledResult[Register[Real, 1]]

So, theoretically we could solve this by



sqrtcom2 = Compile[{{x, _Real}}, Sqrt[x], {{Sqrt[_], _Complex}}]

But this is not working!! ToCompiledProcedure[sqrtcom2][[4]] still gives CompiledResult[Register[Real, 1]] and sqrtcom2 still gives errors.


Why is it not working?



Answer



Let me counter Daniel Lichtblau's answer



This has zero to do with type inferencing.



by saying, the example in the tutorial you linked is all about type inference. It is not about compiling com to make it faster. It is about helping the compiler to deduce the correct type for the expression.



You have to understand one thing: Highlevel Mathematica language is untyped, which means that it is not known upfront whether Sqrt[x] is an integer, a real, a complex or whether it stays as a general expression. It all depends on the value that x has.


Compiled code is completely different, because all variables will have a type. Either explicitly given by you, or derived/assumed by the compiler.


Therefore, your first question is not about whether or not com inside the compile will be too slow. The question is, can the compiler derive the type of com and therefore assume a correct return type.


Since this example does work correctly even without the explicit type hint, let me give a different example. Here, realf is a function that returns a real number, when the input is an integer. In Mathematica 10.3, this leads to an error message:


realf[i_] := 1.5*i;
f1 = Compile[{{i, _Integer}}, realf[i]]

Calling f1[3] will give you a warning, saying that realf will be the reason that the uncompiled version of f1 is used. If you check the f1 with CompilePrint you will find the line


I1 = MainEvaluate[ Hold[realf][ I0]]


The important part is that I1 means integer register. So because Compile has no information about realf, it assumes this call will be of type integer which is wrong. If we change the definition to


f2 = Compile[{{i, _Integer}}, realf[i], {{realf[_], _Real}}]

and check the compiled code again, we see that now a real register is used for the result of realf.


R0 = MainEvaluate[ Hold[realf][ I0]]

Therfore, f2[3] will run without message since the types are consistent. Nevertheless, realf will be an external call that is evaluated by the kernel.


What Daniel's answer is showing you is, that in the specific example of com being defined as Binomial, you can expand the call and indeed compile all instructions to gain a lot of speed.


As for your second example,


Compile[{{x, _Real}}, Sqrt[x]]


there is one additional thing to note: You call Sqrt[x] where x is the input of type Real. Therefore, the compiler deduces that you want the square-root that works on reals. It seems, not even the type hint at the end of Compile prevents this, but there is a simpler solution:


sqrtHal = Compile[{{x, _Real}}, 
Module[{xx = 0. I},
xx = x;
Sqrt[xx]
]
]

Look what we did: we created another variable xx and by giving an initial complex value, we force the type-system to assume xx to be complex. The rest works like in most programming languages. When we assign xx=x a type-conversion takes place and xx is still complex where the imaginary part is zero and the real part is x. Furthermore, the correct complex Sqrt function is selected and therefore



sqrtHal[-1]
(* 0. + 1. I *)

works without problems.


As soon as you have understood the reasons behind this, you easily find another solution:


sqrtHal2 = Compile[{{x, _Real}},
Sqrt[x + 0. I]
]

Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...