Programming examples

Set vs SetDelayed

The purpose of this notebook is to illustrate what can happen when you repeatedly run a program in which all of the functions are defined using SetDelayed compared to using Set.

Modules or not

The only reason for using Module is to localize variables. If you do not have any entries in the first argument of Module then the Module is not doing anything and can actually slow things down. I have used Module here instead of Block because of the complexity of the assignments I am making. If all you are doing is assigning constant values to symbols then Block going to be faster and use less memory.

Clear[x, y, z, t, r, s, a, b, c, bigfn, aa, bb, ab, kk, newfunc, 
      sol2]

Set

Here is a function in which most of the assignments are immediate. The only place we use SetDelayed here is for the FindMinimum function, and the only reason we use it there is to be able to vary one of the parameters in the function we are trying to minimize.

bigfn1[a_, b_, c_][r_, s_] := 
      Module[{sol, aa, newfunc, bb, ab, kk, sol2}, 
        sol  =  
          NDSolve[{x'[t] == 
                a (y[t] - x[t]), y'[t]  ==  
                x[t] (b  -  z[t]), z'[t] ==  
                x[t] y[t]  -  c z[t], x[0] == 1, y[0] == 1, 
              z[0] == 1}, {x, y, z}, {t, 0, 
              10}]; 
aa = 
          y /. sol[[1]]; 
newfunc[bb_, kk_] =  
          r aa[bb]  -  s/kk; 
sol2[ab_]  :=  
          FindMinimum[
            newfunc[bb, ab], {bb, 1, 0, 4}]; 
Table[{r1, 
            newfunc[r1, k1], sol2[k1][[1]]}, {r1, 9, 
            10,  .5}, {k1,  .9, 
            1.1,  .1}]
]

SetDelayed

Here we use SetDelayed for all of the assignments. The consequences of this are that every time we evaluate the sol2, we also evaluate newfunc which requires that we evaluate aa which requires solving the system of differential equations.

bigfn2[a_, b_, c_][r_, s_] := 
      Module[{sol, aa, newfunc, bb, ab, kk, sol2}, 
        sol  :=  NDSolve[{x'[t] == 
                a (y[t] - x[t]), y'[t]  ==  
                x[t] (b  -  z[t]), z'[t] ==  
                x[t] y[t]  -  c z[t], x[0] == 1, y[0] == 1, 
              z[0] == 1}, {x, y, z}, {t, 0, 
              10}]; 
aa := 
          y /. sol[[1]]; 
newfunc[bb_, kk_] :=  
          r aa[bb]  -  s/kk; 
sol2[ab_]  :=  
          FindMinimum[
            newfunc[bb, ab], {bb, 1, 0, 4}]; 
Table[{r1, 
            newfunc[r1, k1], sol2[k1][[1]]}, {r1, 9, 
            10,  .5}, {k1,  .9, 
            1.1,  .1}]
]

What this leads to:

First we look at an example of our  first function used in a table. Note this runs in less than two or three seconds.

t1  =  MemoryInUse[]

TableForm[Table[bigfn1[rr, 10, 8/3][1, 2], {rr, 9, 11,  .5}]] // 
      Timing

Now we try the second version of our function. Note what happens to the timing. There is also an increase in memory  use for this function.

t2  =  MemoryInUse[]

TableForm[Table[bigfn2[rr, 10, 8/3][1, 2], {rr, 9, 11,  .5}]] // 
      Timing

t3  =  MemoryInUse[]

Increase in memory use

Notice that the second function uses about fifty percent more memory than the first version of the function.

{t2 - t1, t3 - t2, (t3 - t2) - (t2 - t1) }