1
$\begingroup$

Tha Mathematica documentation gives a good example of the simultaneous use of Set and SetDelayed in dynamic programming for the Fibonacci sequence under "neat examples" for SetDelayed

fib[1] = fib[2] = 1; fib[n_] := fib[n] = fib[n - 1] + fib[n - 2]

However, in the notebooks that accompany Hartle's Gravity, An Introduction to Einsteins General Relativity there are uses of Set and SetDelayed that seem significantly different, for example:

geodesic := geodesic = 
   Simplify[Table[
     -Sum[affine[[i, j, k]] u[ coord[[j]] ] u[ coord[[k]] ], {j, 1, n}, {k, 1, n}], 
     {i, 1, n}]]

Since no parameters are specified in association with geodesic (and without worrying about the detailed content of the Simplify) what was the author (Leonard Parker) achieving by this construction?

| improve this question | | | | |
$\endgroup$
  • 4
    $\begingroup$ The effect is to delay computing geodesic until it is actually used for the first time (SetDelayed) but also avoid computing it more than once (Set). I am not sure why he does this. Does he define affine and coord after geodesic? $\endgroup$ – Szabolcs Jan 21 '15 at 16:05
  • 1
    $\begingroup$ For example, x := x = a^2; a=2; x has pretty much the same effect as a = 2; x = a^2, but the former allows for exchanging the order of definitions of a and x. This is just an uncertain guess at the author's motivation though. $\endgroup$ – Szabolcs Jan 21 '15 at 16:10
  • 3
    $\begingroup$ It's likely that geodesic might never be called, so it isn't calculated unless required. $\endgroup$ – Chris Degnen Jan 21 '15 at 18:37
  • $\begingroup$ Thanks for the comments. affine and coord are defined before geodesic geodesic is called subsequently in listgeodesic := Table[{"d/d\[Tau]" ToString[u[coord[[i]]]], "=", geodesic[[i]]}, {i, 1, n}] Uses of "not sure" and "uncertain" noted! $\endgroup$ – Julian Moore Jan 22 '15 at 14:21
2
$\begingroup$

This syntax is called memoization.

f[x_] := f[x] = RandomInteger[x]

See the documentation: Functions That Remember Values They Have Found

The first result is remembered to save time on subsequent calls. Rather than re-run a possibly time-consuming calculation, if the input parameter has been used before the previous result is returned.

For example, RandomInteger is only called once here:

f[99]

29

f[99]

29

A new parameter causes RandomInteger to be run again.

f[100]

80

f[100]

80

The stored results can be seen in downvalues:

DownValues[f]

{HoldPattern[f[99]] :> 29, HoldPattern[f[100]] :> 80, HoldPattern[f[x_]] :> (f[x] = RandomInteger[x])}

Memoization should be used with some caution when variables are likely to change, e.g.

y = 10;

f[z_] := f[z] = RandomInteger[z + y]

f[2]

4

y = 10000;

f[2]

4

The stored value is returned despite y having changed.

f[3]

1075

A new parameter causes the function to run, picking up the new value of y.

| improve this answer | | | | |
$\endgroup$
  • 1
    $\begingroup$ It might be helpful to the OP if you give an example of memoization on a function with no parameters, like the second example in the question. $\endgroup$ – 2012rcampion Jan 21 '15 at 17:30
  • 1
    $\begingroup$ Followed-up in comments to the question. $\endgroup$ – Chris Degnen Jan 21 '15 at 18:39
  • $\begingroup$ @chris-degnen Thanks. It would seem however that without parameters there is only on value that will be remembered. Perhaps the advantage is that the evaluation time can be incurred at the time of the user's choosing rather than later when the function is finally called? The example showing where and how care is required is appreciated. $\endgroup$ – Julian Moore Jan 22 '15 at 14:25

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