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

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

equation solving - Invert and fit implicitly defined curve

I need to fit an implicitly defined curve. I thought I could get some data out of Solve , and then using FindFit . Therefore, I would like to find the relation the parametric curve defined by $F(x,y)=0$: Solve[-(1/2) + 1/2 (0.41202 BesselK[0, 0.1 Sqrt[x^2 + y^2]] + (0.101483 x BesselK[1, 0.1 Sqrt[x^2 + y^2]])/Sqrt[x^2 + y^2]) == 0, y] But I can't get an output: Solve was unable to solve the system with inexact coefficients or the system obtained by direct rationalization of inexact numbers present in the system. Since many of the methods used by Solve require exact input, providing Solve with an exact version of the system may help. >> Edit: In particular, I would like to fit the data coming from the curve with the expression of another curve, and not with a function $f(x)$. In particular, since this clearly looks like a cardioid , I would like it to fit to something like it. What other strategies could I try?

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...