# How to set the return type of a compiled function? (Compile::noinfo warning)

I have simple function I would like to compile, but I get a warning and a call to MainEvaluate. I would like to avoid both.

ClearAll[MakeInPeriodicCell]
On["CompilerWarnings"]
MakeInPeriodicCell =
Compile[{x, cellwidth},
First@Sort[{x, x - cellwidth, x + cellwidth}, Abs[#1] < Abs[#2] &]];
CompiledFunctionToolsCompilePrint[MakeInPeriodicCell]

(*Compile::noinfo: No information is available for compilation of
Sort[{x,x cellwidth,x+cellwidth},Abs[#1]<Abs[#2]&].
The compiler will use an external evaluation and make assumptions about the return type.*)

(*
...
5   T(R1)2 = MainEvaluate[ Function[{x, cellwidth}, Sort[{x, x - \
cellwidth, x + cellwidth}, Abs[#1] < Abs[#2] & ]][ R0, R1]]
...
*)


EDIT

(I got the correct syntax for the subexpression from an answer that got deleted?) I tried setting the type of a subexpression like this:

MakeInPeriodicCell =
Compile[{x, cellwidth},
First@Sort[{x, x - cellwidth, x + cellwidth},
Abs[#1] < Abs[#2] &], {{Sort[_,_], _Real,1}}]


This gets rid of the warning, but the call to MainEvaluate remains.

Can this snippet be compiled without a call to MainEvaluate?

EDIT 1

Since compile is always about speed, here is some benchmark info. (the code is here, as it clutters the question a bit)

data = RandomReal[{-100, 100}, 100000];
(*Original implementation*)
m0 = MakeInPeriodicCellOrig[data, 30]; // AbsoluteTiming (*0.8370473*)
(*my revritten*)
m1 = MakeInPeriodicCellImp[data, 30]; // AbsoluteTiming  (*0.0360021*)
m2 = MakeInPeriodicCellFx[data, 30]; // AbsoluteTiming   (*0.0140008*)

m0 == m1 == m2 (*True*)


So getting read of MainEvaluate gives you about 20x speed-up and changing to a better algorithm another 3x. I usually have a million to ten million points, so the speed-up is very welcome.

-
If you set SetSystemOptions["CompileOptions" -> "CompileReportExternal" -> True] the warning does not go away. Out of curiosity, have you read these two questions? – rcollyer Apr 5 '12 at 15:36
@rcollyer But of course I have read the two questions:) – Ajasja Apr 5 '12 at 15:39
I had to ask. :) – rcollyer Apr 5 '12 at 15:41
I did figure out what the problem is: Function[] is not in the compilable list. But I didn't notice it before, since it was hidden in the short form &. Should I post the answer or just delete the whole question? – Ajasja Apr 5 '12 at 15:43
@Ajasja one could post a workaround as an answer; I don't see why to delete the question – acl Apr 5 '12 at 15:44

I think Leonid’s comment is spot on. You could work around the issue with a completely different approach:

MakeInPeriodicCell = Compile[{{x, _Real}, {cellwidth, _Real}},
If[x < -(cellwidth/2.), x + cellwidth,
If[x > cellwidth/2., x - cellwidth, x]]
];

-
Could also use Ordering and order Abs of your list, and then extract elements - this way one can use default comparison function and compile. – Leonid Shifrin Apr 5 '12 at 15:48

It appears that in this case Function[] can not be compiled without a call to MainEvaluate.

This is my workaround, but I like F'x much better:)

MakeInPeriodicCell = Compile[{x, cellwidth},
With[{  l = {x, x - cellwidth, x + cellwidth}},
Sort[Transpose[{Abs[l], l}]][[1, 2]]
]]

-
This is not a problem of Function not being compiled, this is a problem of type-inferencing inside Sort. I suspect that this is a flaw or limitation of how compilation of Sort was implemented, and has nothing to do directly with abilities of Compile` to compile pure functions. – Leonid Shifrin Apr 5 '12 at 15:55