8
$\begingroup$

In general, to define a function, we often use f[x_]. Another way is to use pure function (full form and shorthand). I want to test the performance of these function declaration.

Original test:

Here is a simple test:

ClearAll[f1, f2, f3, f4];

f1[x_] = 3 x;
f2[x_] := 3 x;
f3 = Function[x, 3 x];
f4 = (3 #) &;

l1 = Range[10^7];

f1 /@ l1; // Timing
f2 /@ l1; // Timing
f3 /@ l1; // Timing
f4 /@ l1; // Timing

f1[l1]; // Timing
f2[l1]; // Timing
f3[l1]; // Timing
f4[l1]; // Timing

And here is a result:

{5.04688, Null}

{5.29688, Null}

{0.21875, Null}

{0.171875, Null}

{0., Null}

{0.015625, Null}

{0., Null}

{0., Null}

So here is what I've learned: (It's not new here, many people have shown it).

1. Use built-in Listability: f1[l1] is much faster than f1 /@ l1;

2. Pure function is the fastest solution f4 = (3 #) &; is faster than f3 = Function[x, 3 x];, and faster than f2[x_] := 3 x;

3. Searching the global rule definition is costly f2[x_] := 3 x; searching global rule is inside the loop.

f2 /@ l1; // Timing
{5.29688, Null}


f3 /@ l1; // Timing
{0.21875, Null}

Update 1: To avoid the built-in Listable over a list, I change the definition.

ClearAll[f1, f2, f3, f4];

f1[x_] = something[x];
f2[x_] := something[x];
f3 = Function[x, something[x]];
f4 = (something[#]) &;

Repeat these functions on a list:

l1 = Range[10^6];

f1 /@ l1; // Timing
f2 /@ l1; // Timing
f3 /@ l1; // Timing
f4 /@ l1; // Timing

Here is what I get:

{0.390625, Null}

{0.390625, Null}

{0.5, Null}

{0.296875, Null}

The pure function shorthand is the fastest. And the classic function declaration is very slow (50 times slower). I wonder why? Is it due to the x Pattern, or due to the difference between Set and SetDelay?

When do I need to do an intensive calculation, which type of function declaration I should use?

Conclusion: I found that using pure function is very fast. Adding the global rewrite rule in the inner loop is slow. Each time we define a new function, a rewrite rule is added. Term rewriting is expensive inside the loop. (For the built-in function, don't forget the Listability). For the complex function, use /@ combined with pure function.

$\endgroup$
5
  • 2
    $\begingroup$ seen Functions vs. patterns? $\endgroup$
    – kglr
    Oct 28, 2020 at 10:27
  • 2
    $\begingroup$ The function f1 doesn't work and is defined incorrectly. Try evaluating f1[1] to see what I mean. $\endgroup$ Oct 28, 2020 at 10:34
  • $\begingroup$ oh, thank you. This is a duplicated question I think. Sorry for that. $\endgroup$
    – Nam Nguyen
    Oct 28, 2020 at 10:37
  • 2
    $\begingroup$ Once f1 is reparied, you should also try f1[l1], f2[l1], f3[l1], and f4[l1] to become fully confused... ;) Explanation: Plus and Times have the attribute Listable which circumvents almost all of the calling overhead. $\endgroup$ Oct 28, 2020 at 11:12
  • $\begingroup$ Thank you. :D. Most built-in Mathematica function is "internal listable", that's why they are so fast. By reading another post, I see that Function declaration is much faster than the global rewrite rule f[x_] $\endgroup$
    – Nam Nguyen
    Oct 28, 2020 at 11:27

0

Your Answer

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