2
$\begingroup$

I declare my compiled function:

Gapped = Compile[{{angle, _Complex}},
  Module[{c1, c2, c3, cond, Phi, theta, phi},
    theta = Re[angle];
    phi = Im[angle];
    {c1, c2, c3} = 1 - 3 Sin[theta]^2 Cos[phi - 2 Pi (# - 1)/3]^2 & /@ {1, 2, 3};
    cond = ((c2 + c3)^2 - c1^2)/(4 c2 c3);
    If[0 <= cond <= 1, {theta, phi}, Null]]];

And then I perform a calculation

res = 2;
AngleArray = 
  Transpose[Table[theta + I phi, {theta, 0, Pi, Pi/res}, {phi, 0, 2 Pi, Pi/res}]];
start = AbsoluteTime[];
array = Map[Gapped, AngleArray, {2}];
end = AbsoluteTime[] - start
ArrayPlot[array, ColorRules -> {Null -> Green}]

First time I hit evaluate on the second block of code I get error warnings [1] but the second time I hit evaluate the error warning dissapear (and it seems to work properly as it evaluates much faster). What is going on here? Thanks very much.

[1] error warnings:

CompiledFunction::cfse: Compiled expression {0., 0.} should be a machine-size real number. >>

CompiledFunction::cfex: Could not complete external evaluation at instruction 51; proceeding with uncompiled evaluation. >>

$\endgroup$

1 Answer 1

2
$\begingroup$

The issue is with your If returning different types ( a real list or Null ). Try this:

 Gapped = Compile[{{angle, _Complex}},
   Module[{c1, c2, c3, cond, Phi, theta, phi},
    theta = Re[angle];
    phi = Im[angle];
    {c1, c2, c3} = 1 - 3 Sin[theta]^2 Cos[phi - 2 Pi (# - 1)/3]^2 & /@ {1, 2, 3};
    cond = ((c2 + c3)^2 - c1^2)/(4 c2 c3);
    If[0 <= cond <= 1, {theta, phi}, {$MaxMachineNumber, $MaxMachineNumber}]]];
 res = 500;
 AngleArray = 
   Transpose[
    Table[theta + I phi, {theta, 0, Pi, Pi/res}, {phi, 0, 2 Pi, 
      Pi/res}]];
 start = AbsoluteTime[];
 array = Map[Gapped, AngleArray, {2}];
 end = AbsoluteTime[] - start
 ArrayPlot[array, ColorRules -> {{$MaxMachineNumber, $MaxMachineNumber} -> Green}]

3.7127762 (end)

enter image description here

I suspect with your version, after the first pass, it gives up trying to compile and you just don't get the warning. Mine is 100x faster than yours (on the warning free second pass )

If you really want the Null return I think you need to create a wrapper, have the compiled function return {cond, theta, phi} and move the If outside like this:

 gwrap[v_] := If[0 <= #[[1]] <= 1, #[[2 ;; 3]] , Null ] &@ (Gapped@v)

edit

this issue can be seen very simply, if I do this:

 Compile[ { x} , If[ x < 0, {0, 0}, 0]];

you get an immediate error:

"The types of the two results in If[x<0,{0,0},0] are incompatible because their ranks are different"

however if we do this:

 f = Compile[ { x} , If[ x < 0, 0, Null]];

an error occurs only if we hit the Null:

 f[-1]->0
 f[1]-> "proceeding with uncompiled evaluation" 

but the List/Null case:

  f = Compile[ { x} , If[ x < 0, {0, 0}, Null]];

throws a "runtime" error regardless of which result - indicating the compiled code is expecting to return a scalar number. I guess its not a b-g since the docs are silent on the expected behavior.

$\endgroup$
2
  • $\begingroup$ Amazing! I like the use of $MaxMachineNumber. Question: I'm not particularly computer literate, is using such a large number going to cause me any problems? $\endgroup$
    – Tom
    Commented Mar 4, 2015 at 22:57
  • $\begingroup$ The idea is just to use some number that will not ordinarily occur in the calculation. (so you can detect it outside ) I think in this example anything outside 0-2Pi would do.. $\endgroup$
    – george2079
    Commented Mar 4, 2015 at 23:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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