This is a proof of concept of the idea of parsing the Compile
expression, extracting Symbols, finding dependent definitions, and inserting them back into Compile
.
First a HoldFirst
variation of heldCases
:
makeHeld[(L_ -> R_) | (L_ :> R_)] := L :> HoldComplete[R];
makeHeld[pat_] := x : pat :> HoldComplete[x];
Attributes[heldCases] = {HoldFirst};
heldCases[expr_, rule_, args___] :=
Join @@ Cases[Unevaluated @ expr, makeHeld @ rule, args]
Then the main definition:
Attributes[inject] = {HoldFirst};
inject[all : Compile[var_, body_, opts___]] :=
Complement[
heldCases[body, s_Symbol /; Context[s] =!= "System`", {-1}, Heads -> True],
heldCases[var, s_Symbol | {s_Symbol, __} :> s, {2}]
] //
Apply[FullDefinition] //
InputForm // ToString // ToHeldExpression //
Cases[(Set | SetDelayed)[s_Symbol, RHS_] :> (HoldPattern[s] :> RHS)] //
( Unevaluated[all] //. # & )
Usage :
Compile[{{x, _Real, 1}}, f /@ x,
CompilationOptions -> {"InlineExternalDefinitions" -> True}] // inject
Replacing Unevaluated
with Hold
in the last line of inject
shows the intermediate output:
Hold[Compile[{{x, _Real, 1}}, ((#1 - 1 &)[#1]^2 &) /@ x,
CompilationOptions -> {"InlineExternalDefinitions" -> True}]]
Notes
This is rather verbose for what is conceptually a fairly simple operation.
I am not happy with the ToString
conversion and back. Possibly I should have extracted Symbols
only and used OwnValues
as you did, but since I resorted to pulling the definitions with FullDefinition
using that information directly seemed a natural approach.
The replacements should really only be done on the body
rather than the entire Compile
, but the latter was expedient for a proof of concept.
"InlineExternalDefinitions" -> True
seems opaque, that is I cannot find any information about how it is implemented usingTrace
. Would it be useful to you simply to programmatically extractf
andg
from yourCompile
expression for use in your own method? $\endgroup$f
insideCompile
and the derived symbols likeg
, the problem is solved. But I don't know how to do that. $\endgroup$System`
Symbols or do you prefer to restrict it toGlobal`
Symbols? $\endgroup$Compile
and local variable inModule
inside compile which hasGlobal
context) $\endgroup$