5

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;

      g[x]
      , 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
Al Guy
  • 1,610
  • 1
  • 10
  • 15
  • Why can't you just define g as a separate function instead of making the definition within Compile[]? – J. M.'s missing motivation Jun 18 '16 at 23:44
  • @J.M. I trying to minimize all overheads of calling various pieces, by putting everything in a big compiled function. – Al Guy Jun 18 '16 at 23:46
  • 1
    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. – Oleksandr R. Jun 19 '16 at 03:10
  • @OleksandrR. will the inlining mean the the body of the compiled function will call MainEvaluate ? – Al Guy Jun 19 '16 at 03:21
  • 1
    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. – Oleksandr R. Jun 19 '16 at 03:25
  • Other tricks/tactics include injecting the definition and evaluating it inside; cfunc = With[{gg = g}, Compile[{{x, _Real}}, Evaluate[gg[x]]]];.This falls into the macro category as noted above. I think it was the main way to do this sort of thing prior to the introduction of InlineExternalDefinitions. – Daniel Lichtblau Jun 19 '16 at 16:17

2 Answers2

10

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}]
vapor
  • 7,911
  • 2
  • 22
  • 55
  • A good workaround; +1. It is essentially the same as the "InlineExternalDefinitions" option accomplishes, but rather more transparent in how it works. – Oleksandr R. Jun 19 '16 at 03:23
  • 1
    @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. – NeverMind Dec 12 '18 at 22:51
8

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.

Oleksandr R.
  • 23,023
  • 4
  • 87
  • 125