# Speed up matrix evaluation

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?
• 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}]; Nov 25, 2017 at 18:15
• 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 Nov 25, 2017 at 18:24
• 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. Nov 25, 2017 at 18:33
• How many entries are there in the actual matrix, and how many of the entries are the same? Nov 25, 2017 at 18:35
• 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. Nov 25, 2017 at 18:48

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]


Globalk

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

Globalk2

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.

• 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? Nov 27, 2017 at 22:01

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.