2
$\begingroup$

If a global variable is changed before each call of the function then answer is not changed accordingly. Please see a toy example:

Clear[zIc];
With[{Aopt = Aopt},
  zIc = Compile[{{q, _Integer}},
                Aopt + q
                , CompilationTarget -> "C", 
    CompilationOptions -> {"InlineExternalDefinitions" -> True}
    ]];

Aopt = 1;
zIc[3]
Aopt = 3;
zIc[3]

(Debug) Out[203]=
6
(Debug) Out[205]=
6

Expected answers are 4 and 6. I familiar with 31627 and 78768 posts but theirs solutions don't help.

[EDITED]:

  1. Removing With doesn't help also.
  2. As it is very simple toy example it seems to be very obvious answer to pass global variable as an argument to the function but not in real code where zIc already has 7 arguments and Aopt is calculated 4 logical layers above.
$\endgroup$
  • 1
    $\begingroup$ The central goal of compilation is that you know in advance what goes in and what comes out. Having a global variable inside of compiled code like that would defeat the purpose of compilation. What you are asking for is simply not what compile was designed for or can be designed around. It will work if you don't compile to C, but it won't really give you tangible benefits. $\endgroup$ – Sjoerd Smit Apr 25 at 11:45
  • 1
    $\begingroup$ Correction: for this to work, you need to remove the "InlineExternalDefinitions" option (which essentially bakes the current value of Aopt into the function). $\endgroup$ – Sjoerd Smit Apr 25 at 11:54
  • $\begingroup$ @SjoerdSmit Thanks for explanation of compiling mechanism. In my point of view compiling has significant leak of functionality. There is no possibility to use some kind of struct as an argument. So passing a lot of arguments to functions makes code poor readable. In other hand function decomposition breaks mathematic representation and makes code “C-like”. May be you could address me an idea or link to a workaround. $\endgroup$ – fmvin Apr 26 at 6:40
4
$\begingroup$

By using With, you freeze the value of Aopt at compile time if it has already a value assigned to it. You may want to execute Clear[Aopt] before the compilation takes place.

Anyways, it is probably better to supply the value of Aopt as an argument to the compiled function. This makes things a lot more predictable and efficient as this removes MainEvaluate calls from the compiled function.

$\endgroup$
0
$\begingroup$

There are basically 3 ways you can go with this:

  1. Include Aopt as an argument (Henrik's answer).
  2. Include Aopt as a global variable without "InlineExternalDefinitions". If you do this, the code compiled code will use MainEvaluate, which essentially stops the compiled code and makes it reach into normal WL evaluation to retrieve the value of Aopt. More often than not, this will kill off most of the benefits of compilation and if Aopt doesn't have a value that the compiled code can use it will be even worse than sub-optimal because the compile function will have to be completely abandoned and WL needs to resort to normal evaluation.

You can see this for yourself with CompilePrint:

Needs["CompiledFunctionTools`"];
zIc = Compile[{{q, _Integer}}, Aopt + q]
CompilePrint[zIc]
  1. Define a function that returns a compiled function with the value of Aopt "baked in". In this case, you treat Aopt as a parameter that doesn't change to often, so you can afford to make a new compiled function whenever it's value changes. Kind of like a just-in-time compilation.

This would look a bit like this:

ClearAll[zIc2];
zIc2[Aopt_?NumericQ] := zIc2[Aopt] = Compile[{{q, _Integer}}, Aopt + q]

Aopt = 1.;
cf = zIc2[Aopt];
cf[3]

Out[24]= 4.
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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