How to compile self-referencing functions (to perform recursive a task)
I haven't found a way to compile recursive functions to WVM, but you can do it if you compile to C: the trick is to use
CompilationOptions -> {"InlineExternalDefinitions" -> True,
"InlineCompiledFunctions" -> False}
along with
CompilationTarget -> "C"
If you then evaluate the following code twice, you will see that f
calls a LibraryFunction
, which tells you that it has been compiled:
f = Compile[{{r, _Integer}, {x, _Complex}},
If[
r == 0,
x,
x*f[r - 1, x/2]
],
CompilationOptions -> {"InlineExternalDefinitions" -> True,
"InlineCompiledFunctions" -> False},
CompilationTarget -> "C"
]
The part specifying the return value of f
is not needed as MMA figures it out, and I changed the Which
to an If
since you only test one thing.
Leonid Shifrin's answer here may be useful (not just for your current problem, but for many, many compilation questions) as it gives advice for what can and what cannot be compiled. Recursion is explicitly called out as not a candidate. However procedural functions are identified as candidates.
So, yeah, if you completely change the intention (from recursion to iteration), no problem...
f[0, x_] := x;
f[r_Integer /; r > 0, x_] := fc[r, x];
fc = Compile[{{r, _Integer}, {x, _Complex}},
Module[{answer, rCurr, xCurr},
answer = 1 + 0 I;
rCurr = r;
xCurr = x;
While[rCurr > 0,
answer *= xCurr;
rCurr--;
xCurr /= 2;
];
answer
],
{{answer, _Complex}}
];
Then
<< CompiledFunctionTools`
CompilePrint[fc]
(*
2 arguments
1 Boolean register
7 Integer registers
2 Real registers
6 Complex registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}
I0 = A1
C0 = A2
I2 = 0
C1 = 0. + 1. I
I6 = 2
I1 = 1
R1 = 0.
Result = C4
1 R0 = I2
2 C2 = R0 + R1 I
3 C2 = C2 * C1
4 R0 = I1
5 C4 = R0 + R1 I
6 C4 = C4 + C2
7 I3 = I0
8 C2 = C0
9 B0 = I2 < I3
10 if[ !B0] goto 19
11 C5 = C4 * C2
12 C4 = C5
13 I4 = I3
14 I5 = Subtract[ I4, I1]
15 I3 = I5
16 C5 = Divide[ C2, I6]
17 C2 = C5
18 goto 9
19 Return@
*)