10
$\begingroup$

I'm trying to write a simulation using Mathematica 8.0. Since I will most likely be doing the same operation over and over again, I'm trying to Compile whatever I can. However, I've been having problems avoiding MainEvaluate calls when I define CompiledFunction objects which refer to global variables. A simplified sample of what I'm trying to use is:

g = 4.49*^3;
m = 1.;
s = 1.;
ϵ = 2.;
sAcceleration = Compile[{{sPosition, _Real, 1}},
   (-g (m + s))/(sPosition.sPosition + ϵ*ϵ)^(3/2) sPosition];

I have also tried wrapping the whole thing inside a Module, to no avail:

sAcceleration2 =  Compile[{{sPosition, _Real, 1}},
  Module[{gg = g, mm = m,  ss = s, ϵϵ = ϵ^2},
    (-gg (mm + ss))/(sPosition.sPosition + ϵϵ)^(3/2) sPosition]];

They seem to run just fine. However, when I take a look at what the CompiledFunction is trying to do internally using CompilePrint

<< CompiledFunctionTools`
CompilePrint[sAcceleration]
CompilePrint[sAcceleration2]

I get, respectively

1 R1 = MainEvaluate[ Function[{sPosition}, g][ T(R1)0]]

...

3 R1 = MainEvaluate[ Function[{sPosition}, m][ T(R1)0]]

4 R4 = MainEvaluate[ Function[{sPosition}, s][ T(R1)0]]

...

7 R6 = MainEvaluate[ Function[{sPosition}, ϵ][ T(R1)0]]

8 R7 = MainEvaluate[ Function[{sPosition}, ϵ][ T(R1)0]]

...

and

1 R1 = MainEvaluate[ Function[{sPosition}, g][ T(R1)0]]

2 R3 = MainEvaluate[ Function[{sPosition}, m][ T(R1)0]]

3 R4 = MainEvaluate[ Function[{sPosition}, s][ T(R1)0]]

4 R6 = MainEvaluate[ Function[{sPosition}, ϵ][ T(R1)0]]

...

Since I will most likely be toying with different values for these variables in different simulation runs, but they will be held constant within a given run, can I avoid both MainEvaluate and feeding these variables to my function as additional arguments? Thanks in advance.

$\endgroup$
1
  • $\begingroup$ you might want to wait a bit longer before accepting the answer, in case someone else comes up with something better than I did. You can remove the checkmark for a while to encourage others to look at the question. $\endgroup$
    – acl
    Jun 29, 2012 at 10:58

2 Answers 2

12
$\begingroup$

Try this:

g = 4.49*^3;
m = 1.;
s = 1.;
ϵ = 2.;
With[{g = g, m = m, s = s, ϵ = ϵ},
 sAcceleration = Compile[{{sPosition, _Real, 1}},
     (-g (m + s))/(sPosition.sPosition + ϵ*ϵ)^(3/2) sPosition];
 sAcceleration2 = Compile[{{sPosition, _Real, 1}}, 
   Module[{gg = g, mm = m, ss = s, ϵϵ = ϵ^2},
     (-gg (mm + ss))/(sPosition.sPosition + ϵ)^(3/2) sPosition]];
 ]

that is, inject the values before evaluation with With.

By the way, if you do SetSystemOptions["CompileOptions" -> {"CompileReportExternal" -> True}] then you'll be warned of calls to the main evaluator at compile time (i.e. without using CompilePrint).

$\endgroup$
3
  • $\begingroup$ Works as intended! Thanks! $\endgroup$ Jun 29, 2012 at 10:35
  • 1
    $\begingroup$ By the way, using capitalized variable names can lead to conflicts. For instance, N and K are reserved. I use things like thisIsAVar to avoid this. Of course nothing will happen to you if you keep using G and so on, but you can sometimes end up with hard to diagnose bugs. $\endgroup$
    – acl
    Jun 29, 2012 at 11:28
  • $\begingroup$ I know, thanks. I usually use longer names for variables, but just this time I gave in to laziness. $\endgroup$ Jun 29, 2012 at 12:42
7
$\begingroup$

You could go even further than @acl's answer with something like this:

mkCF[g_, m_, s_, e_] := Module[{body, SPosition},
  body = (-g (m + s))/(SPosition.SPosition + e*e)^(3/2) SPosition;
  With[{body = body}, Compile[{{SPosition, _Real, 1}}, body]]
  ]

This has the advantage that body has seen an evaluation which in this cases means a simplification and consequently less to compute.

$\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.