# How to force Compile to return multiple results?

I would like to return two separate values from a compiled function, but Mathematica refuses to use the compiled version. Here is a narrowed-down example:

    cFunc = Compile[{{a, _Integer, 1}}, {a, a.a}];

(*
==> CompiledFunction::cfex: Could not complete external evaluation at instruction 3; proceeding with uncompiled evaluation. >>

==> {{1, 1, 1}, 3}
*)


Here a and a.a are hypothetic intermediate results of some long computation, that must be externalized in order for computation to go on outside the compiled function. I assume it is not possible to return lists that are not uniform (data type and dimensions). Is there any way to return more than one results from a compiled computation?

-

What about making the result uniform inside Compile and constructing things back afterwards? Like

   cFunc = Compile[
{{a, _Integer, 1}},
Join @@ {a, {a . a}}];
cFunc[{1, 3}]
Function[z, {Most[z],
Last[z]}][%]


which has the nice feature of not calling MainEvaluate:

    Needs["CompiledFunctionTools"]; cFunc // CompilePrint

(*
==>
1 argument
2 Integer registers
3 Tensor registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}

T(I1)0 = A1
I0 = 4
Result = T(I1)2

1   I1 = DotVV[ T(I1)0, T(I1)0, I0]]
2   T(I1)1 ={ I1 }
3   T(I1)2 = Join[ T(I1)0, T(I1)1]]
4   Return

*)

-
I think your code is going to break in this case: cFunc = Compile[{{a, _Integer, 1}}, Join @@ {1.*a, {a.a}}];It makes some assuptions about a, that may not be true. Also, a single call to MainEvaluate is not so much of an issue, as long as it is not in a loop. –  user21 Feb 15 '12 at 15:04
@ruebenko what is your analysis of my methods? –  Mr.Wizard Feb 15 '12 at 15:11
@ruebenko: Definitely it is in a loop... But then the problem with Rolf's code is that joining and retrieving partial results from z might not be that easy. –  István Zachar Feb 15 '12 at 23:55
why not? can you be more specific? –  Rolf Mertig Feb 16 '12 at 0:16

You can use a technique like this:

cf = Compile[{{n, _Integer}, {m, _Integer}},
Module[{cpos = RandomSample[Range[n], m]},
Set[pos, cpos];
RandomReal[1, Length[cpos]]]];

{valres, posres} = Block[{pos}, {cf[10, 5], pos}]


The set works on a variable which is scoped with Block. Since this is done only once, the call to MainEvaluate is not a problem.

-
Am I correct in thinking that any solution must force a (one-time) call to MainEvaluate because compiled functions can only work with non-ragged arrays? –  Szabolcs Feb 15 '12 at 14:20
I think there are special cases where this is not the case (e.g. Listable compiled functions that returns arrays of different length), but to the best of my knowledge, yes, you need a call to MainEvaluate. –  user21 Feb 15 '12 at 14:24
@Szabolcs I guess it might be possible without the MainEvaluate call if in future support for passing InternalBags between the Mathematica VM and the interpreter is implemented. But for now, this is indeed the only way to do it as far as I know. –  Oleksandr R. Feb 15 '12 at 14:27
@Szabolcs the problem there is that the error encountered by the VM, even though it occurs at the very end of the compiled code, forces a complete re-evaluation in the interpreter. Error control for compiled code isn't very sophisticated, unfortunately, so evaluation won't pick up in the interpreter where it left off in the VM. –  Oleksandr R. Feb 15 '12 at 14:39
@Oleksandr I see. I wasn't sure if that was the case. cf = Compile[{a}, Print[a]]; cf[2] prints twice and shows that this is indeed what happens. But now it is not clear to me when MainEvaluate will force a complete re-evaluation and when it won't. –  Szabolcs Feb 15 '12 at 14:42

A couple of ideas:

cfun = Compile[{{a, _Integer, 1}}, x[1] = a; x[2] = a.a;]
fun[a_?VectorQ] :=
Block[{x},
cfun[a];
{x[1], x[2]}
]

fun[{1,2,3,4,5}]

{{1, 2, 3, 4, 5}, 55}

cf2 = Compile[{{a, _Integer, 1}}, Sow[a]; Sow[a.a];];

Reap[cf2@{1, 2, 3, 4, 5}][[2, 1]]

{{1, 2, 3, 4, 5}, 55}

-
which also calls MainEvaluate –  Rolf Mertig Feb 15 '12 at 14:37
@Rolf but it does not result in CompiledFunction::cfex isn't that the point? By the way I voted for yours; slick. –  Mr.Wizard Feb 15 '12 at 14:40
@Mr.Wizard: nice ideas from you, too! Voted for it. Just try to understand how things work and what are the differences. –  Rolf Mertig Feb 15 '12 at 14:42
@Rolf good point. I don't have CompilePrint in v7. I think your method will be the best if the function is low complexity. On a computationally complex function I think the overhead that my methods have will not matter, but I haven't tested that assertion. –  Mr.Wizard Feb 15 '12 at 14:45
@Mr.Wizard, I think your methods are fine, you need to call MainEvaluate one more time than with my approach. (That's the only thing I could think of...) –  user21 Feb 15 '12 at 15:36