# sudden increase in timing when summing over 250 entries

I see a sudden increase of Timing by a factor of thousands when I sum over 250 elements of a matrix rather than over 249. So for instance, this table contains sums from 1 to 249 and it takes 0.0002s

Clear[vec, time];
vec = Table[i, {i, 100}, {j, 100}, {k, 300}];
time = Timing[
Table[Sum[vec[[i, j, k]], {k, 1, 249}], {i, 1}, {j, 1}]][[1]]; time


while if I go from 1 to 250

Clear[vec, time];
vec = Table[i, {i, 100}, {j, 100}, {k, 300}];
time = Timing[
Table[Sum[vec[[i, j, k]], {k, 1, 250}], {i, 1}, {j, 1}]][[1]]; time


it takes 1.4s. The huge increase occurs regardless of the content of vec, regardless of the upper limits of i,j, and it does not depend on whether I go from 1 to 250 or from 2 to 251, provided it's at least 250 entries. So if I sum from 2 to 250, it's back to 0.0002s. It depends instead on the size of vec (that is why I create a much larger matrix vec than actually needed in the sum). Can anybody reproduce this behavior? Any suggestion?

• This seems closely related. And setting the option @Karsten mentions does work. This looks like something to report to support. – acl Jul 18 '14 at 16:35
• @Karsten thanks, it works! A search of SumCompileLength on the Help->Documentation center returns no results, and CompileOptions returns useless (for me) information. – user16397 Jul 18 '14 at 16:39
• (note that the example I give in my answer to the other question doesn't demonstrate what you are seeing, but the solution is indeed to increase the option mentioned) – acl Jul 18 '14 at 16:39
• try "CompileOptions" /. SystemOptions[] or look at the way they're displayed in my answer to the other question – acl Jul 18 '14 at 16:40
• I can't believe that such a common operation like summing over more than 250 entries require tweaking the SetSystemOptions, which the manual recommend not to modify: – user16397 Jul 18 '14 at 16:41

The default SumCompileLength is 250.
You can increase this number for example to 500 using

SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 500}]


or to infinity using

SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> ∞}]


## What is "SumCompileLength" for?

For sums with a finite number of at least "SumCompileLength" elements autocompilation will be used to compute the sum.

## Visualization and explanation

For a Sum with very simple summands, Sum[k, {k, 1, n}], the timings as a function of the number of elements n using the default settings

SystemOptions["CompileOptions" -> "SumCompileLength"]


$\${"CompileOptions" -> {"SumCompileLength" -> 250}}

can be visualized with

defaultTimings = First@AbsoluteTiming[Sum[k, {k, 1, #}]] &~Array~500;

ListPlot[defaultTimings, PlotRange -> All, Joined -> True,
PlotLegends -> "defaultTimings: \"SumCompileLength\"\[Rule]250"]


As described by the OP there is a huge jump in the timings at 250 elements. This is due to the fact that the time needed to perform the autocompilation is longer than the time saved by using the autocompiled version. Additionally one can observe that the slope is less steep for more than 250 elements, because, after the autocompilation is done, using the autocompiled version is actually faster than using the non-autocompiled version.

## When "SumCompileLength" should not be increased

For the very simple summand given in the question and for 250 and some more elements increasing "SumCompileLength" as shown in the beginning of this answer reduces the time needed to compute the Sum. However, it would be wrong to conclude that "SumCompileLength" should always be increased or set to infinity.

1) Using the Sum multiple times

do1 = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 250}];
First@AbsoluteTiming[RandomReal[]*Sum[k, {k, 1, #}]] &~Array~500);

do100Default = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 250}];
First@AbsoluteTiming[Do[RandomReal[]*Sum[k, {k, 1, #}], {100}]]/100. &~Array~500);

do100SCL∞ = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> ∞}];
First@AbsoluteTiming[Do[RandomReal[]*Sum[k, {k, 1, #}], {100}]]/100. &~Array~500);

do100SCL1 = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 1}];
First@AbsoluteTiming[Do[RandomReal[]*Sum[k, {k, 1, #}], {100}]]/100. &~Array~500);

ListPlot[{do1, do100Default, do100SCL∞, do100SCL1}, PlotRange -> All, Joined -> True,
PlotStyle -> Thick, PlotLegends -> {"do1", "do100Default", "do100SCL∞]", "do100SCL1"}]


In situations where the autocompiled version of the Sum can be reused, it is advantageous to reduce "SumCompileLength".

2) Sum over a huge number of elements

scl250 = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 250}];
First@AbsoluteTiming[Sum[k, {k, 1, #}]] &~Array~1000);

scl1 = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 1}];
First@AbsoluteTiming[Sum[k, {k, 1, #}]] &~Array~1000);

scl∞ = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> ∞}];
First@AbsoluteTiming[Sum[k, {k, 1, #}]] &~Array~1000);

ListPlot[{scl250, scl1, scl∞}, PlotRange -> All, Joined -> True,
PlotStyle -> Thick, PlotLegends -> {"\"SumCompileLength\" \[Rule] 250",
"\"SumCompileLength\" \[Rule] 1", "\"SumCompileLength\" \[Rule] ∞"},
Epilog -> {Red, Line[{{550, 0}, {550, 1}}]}]


For this example using autocompilation is already beneficial for more than approx. 550 elements.

3) Computational expensive, compilable summands
For example LogGamma is a compilable function that is computational more expensive than the previous example.

scl250 = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 250}];
First@AbsoluteTiming[Sum[N@LogGamma[k], {k, 1, #}]] &~Array~350);

scl1 = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> 1}];
First@AbsoluteTiming[Sum[N@LogGamma[k], {k, 1, #}]] &~Array~350);

scl∞ = (SetSystemOptions["CompileOptions" -> {"SumCompileLength" -> ∞}];
First@AbsoluteTiming[Sum[N@LogGamma[k], {k, 1, #}]] &~Array~350);

ListPlot[{scl250, scl1, scl∞}, PlotRange -> All, Joined -> True,
PlotStyle -> Thick, PlotLegends -> {"\"SumCompileLength\" \[Rule] 250",
"\"SumCompileLength\" \[Rule] 1", "\"SumCompileLength\" \[Rule] ∞"},
Epilog -> {Red, Line[{{50, 0}, {50, 1}}]}]


Here the autocompiled version already starts to outperform the non-autocompiled version at about 50 elements.

• What could be the drawbacks of increasing SumCompileLength? – anderstood Sep 30 '15 at 20:52
• @anderstood For the example given in the question, I'm not aware of any drawbacks. Increasing SumCompileLength will be disadvantageous in situations, where compiling the function of the summands causes a speed increase and not a speed decrease as for the very simple summands in the example given in the question. Maybe I'll elaborate on that tomorrow. – Karsten 7. Sep 30 '15 at 21:45
• You might be interested in reading my recently added answer to this question where relate a funny observation. – anderstood Oct 2 '15 at 20:29
• @anderstood I significantly extended my answer. Now it should not only address the problem described in the OP, but also provide a better general understanding of the "*CompileLength" SystemOptions. – Karsten 7. Oct 3 '15 at 9:09
• Very clear, thank you! That explains the behaviour of my example (Case 1: table of table). – anderstood Oct 3 '15 at 15:13

If you don't want to change the system options just to make Sum auto-compile, then you could instead replace Sum by Total:

Clear[vec, time];
vec = Table[i, {i, 100}, {j, 100}, {k, 300}];
time = Timing[
Table[Total[vec[[i, j, 1 ;; 250]]], {i, 1}, {j, 1}]][[1]]; time


The resulting timing doesn't show any significant difference between 249 and 250, and is just as fast as your first example.

• This is almost always a good idea if what you want to do is a numerical sum. – acl Jul 18 '14 at 20:29

As suggested by LLlAMnYP in a comment to this question, this is a humble contribution. The OP has already been answered. This is not answer per se but shows that CompileLength should not always be increased, and should even sometimes be reduced for significant speed gain.

Consider the following (stupid) function:

x1 = Function[{n, T, t}, (Table[Cos[(Mod[t, T] - T/2)]/Sin[T/2.], {j, 1, n}])[[1]]];
times249 = Table[x1[249, 123, 3] // AbsoluteTiming, {i, 1, 100}][[All, 1]];
times250 = Table[x1[250, 123, 3] // AbsoluteTiming, {i, 1, 100}][[All, 1]];
ListPlot[{times249, times250}, PlotRange -> {{0, 100}, {0, 0.005}}]


Output:

It appears that this time, the function x1 takes way more time for values below 250. This can be corrected using

SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> 1}]


Note the value has to be taken lower than 250, contrary to the previous example. The conclusion is, do not increase the values of CompileOptions without thinking, or at least trying.