2
$\begingroup$

Consider, in the examples below, the difference between defining $n$ as a global variable or as an argument to function comp[], which includes a compiled function that depends on a constant defined in an encompassing With[] which depends on $n$.

  1. If I evaluate
ClearAll[comp, n]

n = 3;

comp = With[{x = n^2},
   Compile[{}, x]];

then running comp[] outputs 9. This is fine.

  1. If I evaluate
ClearAll[comp, n]

comp = With[{x = n^2},
   Compile[{{n, _Integer}}, x]];

then running comp[3] outputs 9. This is fine.

  1. If I evaluate
ClearAll[comp, n]

n = 3;

comp = With[{x = Array[#^2 &, n]},
   Compile[{}, x]];

then running comp[] gives me {1,4,9}. This is fine.

  1. However, if I evaluate
ClearAll[comp, n]

comp = With[{x = Array[#^2 &, n]},
   Compile[{{n, _Integer}}, x]];

I get the error "Array: Single or list of non-negative machine-sized integers expected at position 2 of Array[#1^2&,n]". The output to comp[3] is still {1,4,9} (however, in more complicated forms of example 4, the output is not what it should be).

Example 1 is to example 3 as example 2 is to example 4.

Why do examples 1-3 not give an error but example 4 does?

$\endgroup$
4
$\begingroup$

The error is thrown by Array, not by compile. With has to evaluate the code for x first and this is why Array throws the error.

$\endgroup$
6
  • $\begingroup$ Compile[] is an important part though, is it not? For example, no error is thrown in either f[n_] := With[{x = Array[#^2 &, n]}, 2] or f = With[{x = Array[#^2 &, n]}, Function[n, 2]] (f[3], for example, throws no error). If you mean the error is "Array:..." then I agree; I mentioned this in my question. $\endgroup$ – Just Some Old Man Aug 7 '20 at 16:13
  • $\begingroup$ f = With[{x = Array[#^2 &, n]}, Function[n, 2]] does throw the same error if n is undefined. $\endgroup$ – Henrik Schumacher Aug 7 '20 at 16:53
  • $\begingroup$ My bad, thank you. I forgot to clear n. $\endgroup$ – Just Some Old Man Aug 7 '20 at 17:48
  • $\begingroup$ What would be the best way to pass n as an argument to comp without throwing the error? (Essentially, I'd like to get the behavior of example 3 but define n as an argument, to comp, not as a global variable). I know I can do something like comp[n_] := With[{x = Array[#^2 &, n]}, f = Compile[{}, x]; f[]], and comp[3] gives me the right answer with no error, but introducing f is a bit sloppy. Do you believe this is best? $\endgroup$ – Just Some Old Man Aug 8 '20 at 6:47
  • $\begingroup$ Well, this error can easily be ignored. You can do comp = Quiet[With[{x = Array[#^2 &, n]}, Compile[{{n, _Integer}}, x]]];. But an easier way would be comp = Compile[{{n, _Integer}}, Array[#^2 &, n]]. Or comp = Compile[{{n, _Integer}}, Table[i^2 &, {i, 1, n}]]. $\endgroup$ – Henrik Schumacher Aug 8 '20 at 7:11
4
$\begingroup$

As explained by Henrik, the problem is that Array is being evaluated before it gets inserted into Compile. The solution here is to use SetDelayed to prevent its evaluation.

comp = With[{x := Array[#^2 &, n]}, Compile[{{n, _Integer}}, x]]
$\endgroup$
1
  • $\begingroup$ This seems to work, but the function I am using suffered a massive drop in speed, probably because x is now being evaluated millions of times. $\endgroup$ – Just Some Old Man Aug 10 '20 at 9:04
4
$\begingroup$

Another way:

comp = With[{x = Unevaluated@Array[#^2 &, n]}, 
  Compile[{{n, _Integer}}, x]]

By the way, Trace or TracePrint will show the order of evaluation, when there is a question about what is happening. When the code is short, like in this case, it can clarify what is going on.

TracePrint@With[{x = Array[#^2 &, n]}, Compile[{{n, _Integer}}, x]]

It also shows the desired code is injected for x, despite the error.

$\endgroup$
1
  • $\begingroup$ I use a variation of this technique: I let body = Hold[Unevaluated[Array[#^2 &, n]]]; so that I can readily generate compiled and uncompiled versions of the same code: fCompiled = Compile[{{n, _Integer}}, #] & @@ body and fUncompiled = Function[{n}, #] & @@ body. $\endgroup$ – J. M.'s torpor Aug 9 '20 at 14:11

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.