0
$\begingroup$

Question: What is the fastest way to obtain a table of values from a parametrized function?

For a function of x, which is a sum of Sin functions parametrized by integers k and m, one can make a table from the discrete set of values for each parameter:

tabT = Table[Sum[m*Sin[k*(x-n)], {n, 1, 5}], {m, 1, 100}, {k, 1, 50}];

This takes about 0.061s on my machine.

Then one can make a list in x of this by writing:

tabTT = Table[tabT[[100]][[50]], {x, 1, 100}];

This takes about 3.5s.

Now this process would need to be repeated for each value of k and m, so the total time to generate a discrete set for every parameter would be 100*50*3.5s = 17500s.

Alternatively, it is much faster to combine the two steps:

Table[tab[k][m] = Table[Sum[m*Sin[k*(x - n)], {n, 1, 5}], {x, 1, 100}], {m, 1, 100}, {k, 1, 50}];

This takes 4.9s, which is about 3600 times faster.

This can be further improved by using a floating point limit in the sum over n:

Table[tab[k][m] = Table[Sum[m*Sin[k*(x - n)], {n, 1., 5}], {x, 1, 100}], {m, 1, 100}, {k, 1, 50}];

This now takes 3.5s.

On the other hand, the speed closely depends on the complexity of the function. For example, if a Cos term is added in parallel to the Sin term, the evaluation takes twice as long.

What is the best way to build such tables from parametrized functions, especially when the functions become more elaborate? Are there further improvements to this example which can speed up evaluation?

$\endgroup$
3
$\begingroup$

There is abolutely no reason for the tab[k][m] = ... in your fastes solution so far. Moreover, the tables can be restructure a bit and Evaluate around the sum seems to slightly improve the resulting compiled function produced by the JIT-compiler.

a = Table[
     tab[k][m] = Table[Sum[m*Sin[k*(x - n)], {n, 1., 5}], {x, 1, 100}],
     {m, 1, 100}, {k, 1, 50}]; // RepeatedTiming // First
b = Table[
     Evaluate[m Sum[Sin[k (x - n)], {n, 1, 5}]], {k, 1, 50}, {m, 1, 
      100}, {x, 1., 100.}]; // RepeatedTiming // First
tab[1][3] == b[[1, 3]]

3.29

0.12

True

Parallelization leads to a further speed-up:

c = ParallelTable[
     Evaluate[m Sum[Sin[k (x - n)], {n, 1, 5}]], 
     {k, 1, 50}, {m, 1, 100}, {x, 1., 100.},
     Method -> "CoarsestGrained"]; // RepeatedTiming // First

0.041

You can also compile the code by hand and exploit parallelization (maybe at the cost of some accuracy); this kind of parallelization often scales better than ParallelTable (at least on my machine):

cf = With[{code = m Sum[Sin[k (x - n)], {n, 1, 5}]},
   Compile[{{x, _Real, 1}},
    Table[code, {k, 1, 50}, {m, 1, 100}],
    CompilationTarget -> "C",
    Parallelization -> True,
    RuntimeAttributes -> {Listable},
    RuntimeOptions -> "Speed"
    ]
   ];
c = cf[Subdivide[1., 100., 99]]; // RepeatedTiming // First
Max[Abs[b - c]]

0.032

4.22929*10^-10

$\endgroup$
  • $\begingroup$ It seems that the evaluation is even slightly faster when all table indices are floating point. Very helpful answer, thank you! $\endgroup$ – Questino Sep 19 '18 at 13:52
  • $\begingroup$ Yes, this potentially reduce the number of type casts. I did not observe any difference though. Anyways, you're welcome! $\endgroup$ – Henrik Schumacher Sep 19 '18 at 17:00

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.