18
$\begingroup$

Here is the example, copied from here

square = Function[x, x^2];
square1 = #^2 &;

the timing and unpacking status shows

data = RandomReal[{0, 10}, {10000}];

AbsoluteTiming[Developer`PackedArrayQ[Map[square, data]]]
AbsoluteTiming[Developer`PackedArrayQ[tmp1 = Map[square1, data]]]

{0.000771589, True}
{0.000748647, True}

Now we add external variable into these two definition.

a = 1
square = Function[x, x^2 + a];
square1 = #^2 + a &;

and time it again, you got

{0.0336384, False}
{0.0062035, True}

we can see & is still autocompiled, while Function is not. Why? I think the documentation treats them as identical way of writing. This distinction is oddly subtle, I just found it today. What is bad is that without Function, we can not give parameters names, thus less readability.

$\endgroup$
  • $\begingroup$ To be precise, it seems that square = Function[x, x^2 + a]; isn't compared in Map. I think this can be considered as another evidence that the auto-compilation of pure function is still not that stable currently. $\endgroup$ – xzczd Dec 3 '16 at 6:27
  • 1
    $\begingroup$ It's not just about autocompilation. square is slower than square1 without compilation. You can use Trace to see that there is a significant difference in the evaluation. Autocompilation can be switched of with SetSystemOptions["CompileOptions" -> {"MapCompileLength" -> \[Infinity]}] and increases the difference in your second case, while it removes the difference in your first case. $\endgroup$ – Karsten 7. Dec 3 '16 at 7:22
  • $\begingroup$ Hi, @Karsten7. I think it is might not be the point. The goal to use Function is to make use of autocompilation. When & and Function both been autocompiled, they are of same speed. If speed is not of concern, then I can just use square2[x_] := x^2;, and in case of "MapCompileLength" -> \[Infinity], square2[x_] := x^2 is actually faster than Function. $\endgroup$ – matheorem Dec 3 '16 at 7:47
  • 3
    $\begingroup$ square2 = With[{a = a}, Function[x, x^2 + a]] would autocompile properly. Maybe "InlineExternalDefinitions" is handled differently? $\endgroup$ – Karsten 7. Dec 3 '16 at 7:50
  • 2
    $\begingroup$ SetSystemOptions[ "CompileOptions" -> {"CompileReportFailure" -> True, "InternalCompileMessages" -> True}] can be used to switch on the generation of an error message. $\endgroup$ – Karsten 7. Dec 3 '16 at 7:51
7
$\begingroup$

The solution, as suggested by Karsten7, in a comment is to use With.

data = RandomReal[{0, 10}, {10000}];

a = 1;
With[{a = a}, square = Function[x, x^2 + a]];
square1 = #^2 + a &

Timing[Developer`PackedArrayQ[Map[square, data]]]
Timing[Developer`PackedArrayQ[tmp1 = Map[square1, data]]]

{0.000578, True}

{0.000528, True}

$\endgroup$
  • $\begingroup$ The question asks why, perhaps we could elucidate the underlying reason. $\endgroup$ – M.R. Jan 10 '17 at 3:07

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.