2
$\begingroup$

I would like to define a function func using a combination of built in functions and obtain a similar speed in evaluation as if I evaluated those built in functions by themselves. Currently I am seeing a slow down. An example:

K[x_] = ConstantArray[func[x], {100, 100}];
K2[x_] = ConstantArray[Sin[x], {100, 100}];
func[x_] = Sin[x];
AbsoluteTiming[K[1.]]
AbsoluteTiming[K2[1.]]

{0.00953596, {...}}

{0.00413393, {...}}

The matrix K2 evaluates significantly faster if I replace func by Sin, even though func is defined to be an alias of Sin.

My questions:

  • What internal process leads to this time difference?
  • How can I define func such that the times are comparable?
$\endgroup$
  • 1
    $\begingroup$ With K2[x_] = ConstantArray[Sin[x], {100, 100}]; you will evaluate Sin 10000 times for each call to K2. Use SetDelayed i.e. K2[x_] := ConstantArray[Sin[x], {100, 100}]; $\endgroup$ – Coolwater Nov 25 '17 at 18:15
  • $\begingroup$ Yes okay. K and K2 are somehow representative for a large matrix with many built in functions that need to be evaluated. I want to keep the Set here and understand where the speed up comes from $\endgroup$ – Mr Puh Nov 25 '17 at 18:24
  • 1
    $\begingroup$ In K it takes 2 top-level calls to compute each entry. In K2 there is only 1 top-level call, so you should expect the time difference. If you change the 3rd line to func = Sin; the pattern matcher is skipped in the second call which makes the difference smaller. $\endgroup$ – Coolwater Nov 25 '17 at 18:33
  • $\begingroup$ How many entries are there in the actual matrix, and how many of the entries are the same? $\endgroup$ – Coolwater Nov 25 '17 at 18:35
  • $\begingroup$ It makes the time difference indeed smaller but its still there. What is a top level call and why does it take 1 less when defining without the x? The actual matrix has dimension 1000x1000 and has no equal entries and evaluates func at different points. $\endgroup$ – Mr Puh Nov 25 '17 at 18:48
2
$\begingroup$

Let's take a smaller example:

Clear[func];
k[x_] = ConstantArray[func[x], 3];
k2[x_] = ConstantArray[Sin[x], 3];
func[x_] = Sin[x];

First compare the DownValues:

Information[k]
Information[k2]

Global`k

k[x_]={func[x],func[x],func[x]}

Global`k2

k2[x_]={Sin[x],Sin[x],Sin[x]}

Now, let's trace what happens:

Trace[k[1.]]

{k[1.],{func[1.],func[1.],func[1.]},{func[1.],Sin[1.],0.841471},{func[1.],Sin[1.],0.841471},{func[1.],Sin[1.],0.841471},{0.841471,0.841471,0.841471}}

Trace[k2[1.]]

{k2[1.],{Sin[1.],Sin[1.],Sin[1.]},{Sin[1.],0.841471},{Sin[1.],0.841471},{Sin[1.],0.841471},{0.841471,0.841471,0.841471}}

For k there is an extra top-level evaluation going from func[1.] to Sin[1.]. This extra evaluation accounts for the timing difference you see.

$\endgroup$
  • $\begingroup$ Trace is a nice command thanks for pointing that out! Is there a solution to skip this additional step apart from replacing func directly by Sin? $\endgroup$ – Mr Puh Nov 27 '17 at 22:01
1
$\begingroup$

Put in some colons, then the difference in execution times is almost not measurable (and the execution times get significantly smaller).

f[x_] := ConstantArray[func[x], {10000, 1000}];
f2[x_] := ConstantArray[Sin[x], {10000, 1000}];
func[x_] := Sin[x];
RepeatedTiming[a = f[1.];]
RepeatedTiming[a2 = f2[1.];]
a == a2

{0.024, Null}

{0.025, Null}

True

By the way: Have a look what ??K and ??K2 return you after you ran your code. Compare that with ??f and ??f2! Moreover, it's crucial in your code where you put the definition of func. If you put that in front, then there is almost no difference left.

$\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.