How can I compile a code with target C containing function definition inside?

I saw post using With. But this just inserts the function in the appropriate place like macros in C. Suggestion with With

    f = Compile[{{x, _Real}},
      g[y] = y^2;

      , CompilationTarget -> "C"

Calls Main:

In[12]:= CompilePrint[f]

1 argument
        3 Real registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        R0 = A1
        Result = R2

1   V17 = MainEvaluate[                       2
Function[{x}, g[y] = y ][ R0]]
2   R2 = MainEvaluate[ Hold[g][ R0]]
3   Return
  • $\begingroup$ Why can't you just define g as a separate function instead of making the definition within Compile[]? $\endgroup$
    – J. M.'s torpor
    Jun 18 '16 at 23:44
  • $\begingroup$ @J.M. I trying to minimize all overheads of calling various pieces, by putting everything in a big compiled function. $\endgroup$
    – Al Guy
    Jun 18 '16 at 23:46
  • 1
    $\begingroup$ Can't do it without using tricks to preprocess (rewrite) the input. Just define it externally, either as a compiled definition or otherwise, and set appropriate options to inline it into the parent function. $\endgroup$ Jun 19 '16 at 3:10
  • $\begingroup$ @OleksandrR. will the inlining mean the the body of the compiled function will call MainEvaluate ? $\endgroup$
    – Al Guy
    Jun 19 '16 at 3:21
  • 1
    $\begingroup$ If the function can be inlined, it will be compiled as fully as it would be if it were specified directly as part of the outer function body. $\endgroup$ Jun 19 '16 at 3:25

First define the function normally:

g[y_] := y^2;

Then substitute the definition in:

f = ReleaseHold[Hold[Compile[{{x, _Real}},
 g[x], CompilationTarget -> "C"]] /. DownValues[g]]

And there is no longer MainEvaluatein the compiled function.

As Oleksandr R. suggested, you can also do

g = #^2 &;
f = Compile[{{x, _Real}},
  g[x], CompilationTarget -> "C", 
  CompilationOptions -> {"InlineExternalDefinitions" -> True}]
  • $\begingroup$ A good workaround; +1. It is essentially the same as the "InlineExternalDefinitions" option accomplishes, but rather more transparent in how it works. $\endgroup$ Jun 19 '16 at 3:23
  • 1
    $\begingroup$ @Oleksandr R.: It's not only more transparent as it seems, but also more powerful. Think of a compiled function that contains a Sum, i.e. the body of the function is sth like x = Range[n]; Sum[v[x], {i, 1, n}] where n is an integer argument to that function. Now, v[x] is defined outside of the compiled environment as v[x_] := Part[x, i]. This now compiles through even without even specifying i as a second argument to v. On the other hand, I haven't been able to define sth like v=Part[#1,#2]&; outside of the compiled function and inline it without calls to MainEvaluate. $\endgroup$ Dec 12 '18 at 22:51

Your question probably will not get the answer you are looking for, because although it is technically possible, getting Compile to work properly is hard enough already without the added difficulty of automatically preprocessing its input. Thus I think that this approach will tend to obscure and complicate the job, rather than making anything easier.

The simple answer is: it's not possible because the VM doesn't have any concept of a "function type". The only allowable types are numeric quantities or void. So, you can write

Compile[{{x, _Real}}, Function[{y}, y^2][x]]

and it compiles and operates just as it should. But you can't have

Compile[{{x, _Real}}, Module[{g}, g = Function[{y}, y^2]; g[x]]]

because g is not something that can be represented inside the VM. The code of the function can be, but the treatment of that code as a named quantity is an abstraction too far.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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