Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am trying to compile a little summation function. As far as I understand, because the built-in Sum function can also return NaN objects I have to make sure only numbers get out before returning.

X = Compile[{}, (
   result = Sum[i, {i, 10}];
   If[NumberQ[result], Return[result], Abort[]];
   )];

The problem is that I keep getting the following two warnings...

CompiledFunction::cfse: Compiled expression True should be a machine-size real number. CompiledFunction::cfex: Could not complete external evaluation at instruction 2; proceeding with uncompiled evaluation.

I guess the glitch is in the NumberQ function and its return type.

Any ideas on how to handle this issue correctly and effectively?

EDIT:

When I omit the check for numeric values while inserting a Return[] statement Mathematica falls back to the uncompiled version (warning: Compile::cret).

share|improve this question
add comment

4 Answers

For the error handling use the compilers error handling mechanism:

cffail = Compile[{{x, _Real, 1}}, Exp[x], 
   "RuntimeOptions" -> {"RuntimeErrorHandler" -> Function[$Failed]}];
cffail[{1000.}]

The Function can be anything (Throw[..],...).

For the summation you could use Total in stead:

Compile[{{x, _Real, 1}}, Total[x]]
share|improve this answer
    
Even though there doesn't seem to be any call to MainEvaluate, I didn't notice any difference in execution speed on my system between: tot = Compile[{{x, _Real, 1}}, Total[x]] ; Timing[tot[RandomInteger[4, 100000000]]] and Timing[Total[RandomReal[4, 100000000]]]. I'm not sure why, but Total applied to integers seemed to be about 15% quicker than applied to reals. –  image_doctor Apr 16 '12 at 9:47
    
@image_doctor, I am not sure what you are trying to say here. I wanted to point out that Total will be faster than Sum. Also, as a side note, AbsoluteTiming is better suited for than Timing. –  user21 Apr 16 '12 at 10:09
    
Thanks for the tip about AbsoluteTiming. I'm not always sure about what I'm saying either :) Perhaps it was that in this context, with Total and other 'simple' functions there is little if any advantage to using a compiled function, it may be that Total is already quite well optimised. I can see there is a difference between using Sum and Total. Total sums an existing list of numbers whereas Sum needs to construct an iteration across a range of not yet existing values, perhaps this means that they can't be compared directly. –  image_doctor Apr 16 '12 at 13:55
    
@image_doctor Compiled Total is just a direct call to the kernel function TotalAll, which is probably the same one used to implement the ordinary Total for machine number inputs. In regard to why Total of integers is faster than reals: memory bandwidth. Reals are twice the size of integers. –  Oleksandr R. Apr 16 '12 at 22:05
    
@OleksandrR Interesting, I was assuming that RandomInteger, which I used to generate the list to be summed, returned Mathematica arbitrary length exact integers as this is what is described in the "Types of Numbers" tutorial. So I thought they would consume more space than a machine sized reals. So does this mean exact integers are dynamic in size, or that RandomInteger and presumably other functions, return a machine sized integer type? –  image_doctor Apr 17 '12 at 7:26
show 3 more comments

I'm having to read between the lines because you did not fully specify your problem, however I suspect that you need to use the third argument of Compile.

func =
  Compile[{{length}},
   (result = Sum[i^2, {i, length}]; If[NumberQ[result], result, Abort[]]),
   {{NumberQ[_], True | False}}
  ]

func[5]
55.
share|improve this answer
    
Although if you look at the result of CompilePrint, you will see that this is not very efficient, since sum is not compiled, but just called using MainEvaluate. –  Ajasja Apr 16 '12 at 8:16
add comment

I’m afraid your base assumption here is false, and the sum compiles much better without this call to NumberQ. See:

<< CompiledFunctionTools`;
func = Compile[{{length, _Integer}}, (
    Sum[i^2, {i, 1, length}]
    )];
CompiledFunctionTools`CompilePrint[func]

The output of CompilePrint shows that the sum is performed without any call to MainEvaluate, which you absolutely want to avoid if you to compile efficiently.

share|improve this answer
    
As a side note, this uses the compiled version up to parameters values of around 1870 when, I guess, numerical overflow causes it to switch back to the uncompiled version. –  image_doctor Apr 16 '12 at 12:56
add comment

Are you definitely sure you need the error checking for NaN inside Compile? The error checking seems to generate very inefficient compiled code. It basically only calls MainEvaluate, so you gain nothing by compiling.

data = Range[1000];
func /@ data; // AbsoluteTiming
func1 /@ data; // AbsoluteTiming

(* ==> {0.1280073, Null} *)

(* ==> {0.0140008, Null} *)

func = 
  Compile[{{length}}, (result = Sum[i^2, {i, length}]; 
    If[NumberQ[result], result, Abort[]]), {{NumberQ[_], 
     True | False}}];
func1 = Compile[{{length, _Integer}}, Sum[i^2, {i, length}]];

data = Range[1000];
d1 = func /@ data; // AbsoluteTiming
d2 = func1 /@ data; // AbsoluteTiming
d1 == d2

(* ==> {0.1160067, Null} *)

(* ==> {0.0140008, Null} *)

(* ==> True *)

Needs["CompiledFunctionTools`"]
CompilePrint[func]
CompilePrint[func1]

(*
==> "
        1 argument
        1 Boolean register
        4 Integer registers
        7 Real registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        R0 = A1
        I1 = 0
        R3 = 0.
        Result = R2

1   V17 = MainEvaluate[                                  2
Function[{length}, result = Sum[i , {i, length}]][ R0]]
2   B0 = MainEvaluate[ Function[{length}, NumberQ[result]][ R0]]
3   if[ !B0] goto 7
4   R5 = MainEvaluate[ Function[{length}, result][ R0]]
5   R2 = R5
6   goto 9
7   R1 = MainEvaluate[ Function[{length}, Abort[]][ R0]]
8   R2 = R1
9   Return
"
*)

(*
==> "
        1 argument
        9 Integer registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        I0 = A1
        I3 = 0
        Result = I4

1   I4 = I3
2   I5 = I0
3   I7 = I3
4   goto 8
5   I6 = Square[ I7]
6   I8 = I4 + I6
7   I4 = I8
8   if[ ++ I7 < I5] goto 5
9   Return
"
*)

So my recommendation is to skip the check (what could generate the NaN in such a simple sum anyway?) or check for NaN values outside the compiled function.

share|improve this answer
    
But when I run your "func1" the result I get is Null. At the moment I use the Return[] statement it falls back to the uncompiled version because "the return types in the Sum statement are different (Compile::cret)"... –  Petr Apr 16 '12 at 9:39
    
Works fine for me. func1[55] returns 56980. Which mma version are you using? –  Ajasja Apr 16 '12 at 10:48
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.