Suppose I have such a module as below:
test[int_] := Module[{m},
m = Table[i, {i, 1, 10}];
Do[m[[i]] = i*i, {i, 1, int}];
Return[m]
]
The bound for Do
loop is not determined until an argument is given to the test. The argument must be between 1 and 10 in this mini example. It works fine:
test[10]
(*{1, 4, 9, 16, 25, 36, 49, 64, 81, 100}*)
Now, I want to compile it:
test2 = Compile[{{iter, _Integer}}, test[iter],
"RuntimeOptions" -> {"EvaluateSymbolically" -> False},
CompilationOptions -> {"InlineCompiledFunctions" -> True},
Parallelization -> True]
executing this returns:
test2[10]
CompiledFunction::cfex: Could not complete external evaluation at instruction 1; proceeding with uncompiled evaluation. >>
{1, 4, 9, 16, 25, 36, 49, 64, 81, 100}
So, it evaluates test2
uncompiled.
Then, I tried to use Evaluate
:
test3 = Compile[{{iter, _Integer}}, Evaluate[test[iter]],
"RuntimeOptions" -> {"EvaluateSymbolically" -> False},
CompilationOptions -> {"InlineCompiledFunctions" -> True},
Parallelization -> True]
The compiling returns:
Do::iterb: Iterator {i,1,iter} does not have appropriate bounds. >>
and if I run compiled version using Evaluate
it returns:
test3[10]
(*{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}*)
It won't execute the Do
loop.
How can I compile a Module
which has a loop with the upper bound as a variable?
Edit
I changed the code to see how the answer below works:
test[int_] := Module[{m, n},
m = Table[i, {i, 1, int}];
n = Table[i*j, {i, 1, int}, {j, 1, int}];
Do[m[[i]] = Tr[n.n], {i, 1, int}];
Return[m]]
test3 = Compile @@ (Hold[{{iter, _Integer}}, test[iter]] /.
DownValues@test)
test[200]; // AbsoluteTiming
(*{0.104010, Null}*)
test3[200]; // AbsoluteTiming
(*{6.565657, Null}*)
Compiled version is much more slow.
Tr
is not compiled, but results in a call toMainEvaluate
. $\endgroup$AbsoluteTiming
. $\endgroup$