People on this site keep telling me that good MMa practice avoids the use of loops.

The code below calculates the same Table of derivatives two different ways, and the one with the Do loops is much faster. I think the first, slower version is calculating the nth derivative from scratch without using the (n-1)th derivative as a starting point.

Derivative[q_, 1][y][x, v] = D[(D[y[x, v], {x, 2}] + D[y[x, v], x]^2), {x, q}]/2;
ord = 9;
Print[Timing[dgdv1 = Table[D[y[x, v], {v, i}], {i, 0, ord - 1}];]];
dgdv2 = Flatten[{y[x, v], Table[0, {i, 2, ord}]}];
Print[Timing[Do[dgdv2[[i]] = D[dgdv2[[i - 1]], v], {i, 2, ord}];]];


{2.449216,Null} *)

So how can one efficiently calculate the first several derivatives of g[x,v] wrt v without using a loop?
Bonus Question: Is there some even faster way to do this calculation?

OP's EDIT: Some commentors below were confused by the first line of my code, in which I define a derivative relationship for g[x,v]. It's not really relevant to the computation speed issue this Question is about, but here is a link for people who want to learn about defining derivatives.

  • 3
    $\begingroup$ Derivative is already defined, you code has syntax problems. $\endgroup$
    – rhermans
    Oct 14, 2015 at 14:18
  • $\begingroup$ With NestList NestList[D[#, x] &, y[x], 10] $\endgroup$
    – rhermans
    Oct 14, 2015 at 14:20
  • 1
    $\begingroup$ @rhermans No, that's how you define derivatives for functions. $\endgroup$ Oct 14, 2015 at 15:58
  • $\begingroup$ @Jerry Guern - I am pretty much lost on the first statement and how it affects subsequent statements. Could you kindly explain the first statement and how it affects D[y[x,v], {v, i}]? Thank you $\endgroup$ Oct 15, 2015 at 23:44
  • $\begingroup$ @JackLaVigne The first line of my code implements a diff eq for $g[x,v]$ discussed here. I didn't discuss the meaning of it here because it's outside the scope of the question about performance tuning. $\endgroup$ Oct 16, 2015 at 1:09

2 Answers 2

ord = 9;

Timing[d1 = Table[D[y[x, v], {v, i}], {i, 0, ord - 1}];][[1]]

(*  2.06537  *)

Rather than using Table, mapping onto a Range is often more efficient

  d12 = D[y[x, v], {v, #}] & /@
     Range[0, ord - 1];][[1]]

(*  2.03747  *)

For a fair timing comparison, the initialization of the array should be included in the timing

  d2 = Flatten[{y[x, v], Table[0, {i, 2, ord}]}];
  Do[d2[[i]] = D[d2[[i - 1]], v],
   {i, 2, ord}];][[1]]

(*  1.70694  *)

With symbolic operations it can sometimes be faster to Simplify intermediate steps

d22 = Flatten[{y[x, v], Table[0, {i, 2, ord}]}];
  Do[d22[[i]] = Simplify[D[d22[[i - 1]], v]],
    {i, 2, ord}];][[1]]

(*  0.307888  *)

However, for this type of problem NestList is faster (and "more Mathematica-like")

Timing[d3 = NestList[D[#, v] &, y[x, v], ord - 1];][[1]]

(*  1.58817  *)

Again using Simplify

Timing[d32 = NestList[Simplify[D[#, v]] &, y[x, v], ord - 1];][[1]]

(*  0.060246  *)

Verifying that all approaches return the same results

d1 == d12 == d2 == d22 == d3 == d32 // Simplify

(*  True  *)
  • $\begingroup$ This was great, thanks. I posted a comparison of the two methods in an Answer below. With Expand performed on each derivative, the two methods had similar Timing. $\endgroup$ Oct 14, 2015 at 17:35

From the OP: This is not an Answer, just an extended comment on @BobHanlon's Answer above, which I Accepted. I tried both methods on a longer run and included the Table initialization in the Timing, and I found that the methods were very similar in kernel time, but which was faster varied in different runs:

Derivative[q_, 1][y][x, v] = 
  D[(D[y[x, v], {x, 2}] + D[y[x, v], x]^2), {x, q}]/2;
ord = 16;
   dgdv2 = Flatten[{y[x, v], Table[0, {i, 2, ord}]}];
   Do[dgdv2[[i]] = Expand[D[dgdv2[[i - 1]], v]], {i, 2, ord}];]];
Print[Timing[dgdv3 = NestList[Expand[D[#, v]] &, y[x, v], ord - 1];]];
dgdv2 == dgdv3

Output from 3 runs:

(* {25.584164,Null} {25.006960,Null} True

{24.226955,Null} {24.336156,Null} True

{24.211355,Null} {24.601358,Null} True *)

  • $\begingroup$ Your use of Print is unnecessary if you don't suppress the output with the final semi-colon. expr will give the same output as Print[expr]; $\endgroup$
    – Bob Hanlon
    Oct 14, 2015 at 22:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.