11
$\begingroup$

I want to compile a function in a way to keep its memory footprint down. In the example below, I am trying to compile a function f that makes three calls to bigNastyFunction. I do not want to define bigNastyFunction outside and use option "InlineExternalDefinitions" -> True because then three copies of that function will be inserted into the body of the compiled function verbatim, leading to excessive memory usage. Instead, my strategy is to define bigNastyFunction inside a Module which is inside Compile. My hope is that bigNastyFunction will be appropriately stored as a subroutine, and called by the body as needed.

SetSystemOptions["CompileOptions" -> "CompileReportExternal" -> True];

f = Compile[{{x, _Complex}},
  Module[{bigNastyFunction = Function[{y}, Sin[y]]},

   bigNastyFunction[x] + bigNastyFunction[x^2]^2 + 3 bigNastyFunction[x^3]

 ]
]

The example above doesn't work because Function is not one of the functions that can be compiled by Compile. What workaround is there to define a large (complicated) function inside the body of a Compile'd function?

$\endgroup$

3 Answers 3

6
$\begingroup$

I think you need "InlineCompiledFunctions" -> False:

f = With[{bigNastyFunction = 
    Compile[{{y, _Complex}}, Sin[y](*,CompilationTarget\[Rule]C*)]}, 
  Compile[{{x, _Complex}}, 
   bigNastyFunction[x] + bigNastyFunction[x^2]^2 + 3 bigNastyFunction[x^3], 
   CompilationOptions -> {"InlineCompiledFunctions" -> False}]]
……
1 C1 = CompiledFunctionCall[ Hold[CompiledFunction[{y}, Sin[y], -CompiledCode-]][ C0]]
2 C2 = Square[ C0]
……

Related post:

Is the CompiledFunctionCall WVM opcode efficient?

CompiledFunctionCall vs. LibraryFunction

$\endgroup$
8
  • $\begingroup$ I think this takes more memory and time than just injecting the code (according to ByteCount and RepeatedTiming). $\endgroup$
    – Michael E2
    Commented Feb 7, 2016 at 3:45
  • $\begingroup$ @MichaelE2 I guess it… depends on how the big nasty function is defined :D $\endgroup$
    – xzczd
    Commented Feb 7, 2016 at 3:51
  • $\begingroup$ +1 to your answer and your links, I learned some things today. $\endgroup$
    – faysou
    Commented Feb 7, 2016 at 9:30
  • $\begingroup$ If you define bigNastyFunction = Function[{y}, Sin[y]] instead of using Compile, then ByteCount[f] goes down from 11704 to 4560, the same as @MichaelE2 's first answer. $\endgroup$
    – QuantumDot
    Commented Feb 7, 2016 at 11:51
  • $\begingroup$ Your method is always produces functions with about twice as big a ByteCount as mine (more than that when bigNastyFunction is small) because three copies of the compiled function are stored in f. For expressions with a LeafCount up to about 500, your method is up to 20% slower than mine; from 500 or so up to 100,000, they're about the same speed; and at a LeafCount of 180,000, yours was about 10% faster. (The expressions were random plus/times combinations of elementary functions.) $\endgroup$
    – Michael E2
    Commented Feb 7, 2016 at 13:39
4
$\begingroup$

Here is one way:

With[{opts = SystemOptions[]},
 With[{bigNastyFunction = Function[{y}, Sin[y]]}, 
  Internal`WithLocalSettings[
   SetSystemOptions["CompileOptions" -> "CompileReportExternal" -> True],
   f = Compile[{{x, _Complex}}, 
     bigNastyFunction[x] + bigNastyFunction[x^2]^2 + 3 bigNastyFunction[x^3]],
   SetSystemOptions[opts]
   ]]]

Here's another way:

Module[{bigNastyFunction = Function[{y}, Sin[y]]},
 Block[{x},
  f = Compile @@ {{{x, _Complex}}, 
     bigNastyFunction[x] + bigNastyFunction[x^2]^2 + 3 bigNastyFunction[x^3]}
  ]]

To check:

Needs["CompiledFunctionTools`"]; 
CompilePrint@f
$\endgroup$
2
  • $\begingroup$ I think this has little difference with define bigNastyFunction outside and use option "InlineExternalDefinitions" -> True, because then three copies of that function will be inserted into the body of the compiled function verbatim" $\endgroup$
    – xzczd
    Commented Feb 7, 2016 at 3:04
  • $\begingroup$ @xzczd Depends on how the big nasty function is defined.... $\endgroup$
    – Michael E2
    Commented Feb 7, 2016 at 3:08
1
$\begingroup$

It seems there is no solution like c language. A workaround is based on list.

    bigNastyFunction =Compile[{{y, _Complex}}, Sin[y](*,CompilationTarget\[Rule]C*)]
    f = Compile[{{x, _Complex}}, 
    Block[{xl = {x, x^2, x^3}, coefList = {1, 1, 3},fx}, fx = 
    Table[bigNastyFunction[ii], {ii, xl}];fx[[2]] = fx[[2]]^2;
    fx.coefList], CompilationOptions -> {"InlineExternalDefinitions" -> True, 
    "InlineCompiledFunctions" -> False}];

The compiled code by CompilePrint[f] is

    1 argument
    8 Integer registers
    5 Complex registers
    4 Tensor registers
    Underflow checking off
    Overflow checking off
    Integer overflow checking on
    RuntimeAttributes -> {}

    C0 = A1
    I3 = 0
    I7 = 4
    I6 = 2
    T(I1)1 = {1, 1, 3}
    I2 = 1
    I0 = 3
    Result = C1

    1   C3 = Square[ C0]
    2   C1 = Power[ C0, I0]
    3   T(C1)2 = {C0, C3, C1}
    4   I5 = Length[ T(C1)2]
    5   I4 = I3
    6   T(C1)0 = Table[ I5]
    7   I1 = I3
    8   goto 12
    9   C3 = GetElement[ T(C1)2, I1]
    10  C4 = CompiledFunctionCall[ Hold[CompiledFunction[{y}, Sin[y],-CompiledCode-]] 
    [[C3]]
    11  Element[ T(C1)0, I4] = C4
    12  if[ ++ I1 <= I5] goto 9
    13  C1 = Part[ T(C1)0, I6]
    14  C4 = Square[ C1]
    15  Part[ T(C1)0, I6] = C4
    16  T(C1)3 = CoerceTensor[ I7, T(I1)1]]
    17  C1 = DotVV[ T(C1)0, T(C1)3, I7]]
    18  Return
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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