Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
    
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. –  acl Jun 29 '12 at 10:58
add comment

2 Answers 2

up vote 11 down vote accepted

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).

share|improve this answer
    
Works as intended! Thanks! –  Andrea Colonna Jun 29 '12 at 10:35
1  
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. –  acl Jun 29 '12 at 11:28
    
I know, thanks. I usually use longer names for variables, but just this time I gave in to laziness. –  Andrea Colonna Jun 29 '12 at 12:42
add comment

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.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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