I am relatively new to Mathematica, and to learn it I am working my way through W. Garrett Mitchener's very informative "Learning to program simulations in Mathematica" . I've gotten as far as his Exercise 8 on p. 14, at which point I get stuck. (Actually, writing out this request for help, I solved the problem. So I'm still posting it in case you experts out there can give me some tips for improvement.)
The tutorial develops random walk Monte Carlo simulations of increasing complexity. Exercise 8 uses a data record (an "ant") with two attributes: position (k) along a line with n discrete locations and the direction (dir) in which the ant is facing (Left or Right). So the record is defined as "Ant[k,dir]" (e.g., Ant[5,Left]). The random walk has no absorbing states. Instead, the ant will step forward in the direction it is facing with probability pStep and turn around with probability 1-pStep. If the ant is at either endpoint of the line, it stays there until it turns around. The exercise sets pStep = 2/3 and n=15. It asks the reader to program Mathematica to return a list of 20 random steps, such as {Ant[5,Right], Ant[6,Right], Ant[7,Right], Ant[7,Left], ...}.
To tackle this problem, I wrote functions Step and Turn respectively to move and turn the ant. They are:
Step[Ant[k_, dir_], n_] :=
If[FreeQ[dir, Right], Ant[Max[1, k - 1], Left], Ant[Min[n, k + 1], Right]]
and
Turn[Ant[k_, dir_]] :=
If[FreeQ[dir, Right], Ant[k, Right], Ant[k, Left]]
Then function MoveAnt moves or turns the ant:
MoveAnt[Ant[k_, dir_], pStep_, n_, u_] :=
If[u < pStep, Step[Ant[k, dir], n], Turn[Ant[k, dir]]]
where u is (will be) a uniformly distributed random variable. The function MoveAntRandom generates this random variable and calls MoveAnt:
MoveAntRandom[Ant[k_, dir_], pStep_, n_] :=
MoveAnt[Ant[k, dir], pStep, n, Random[]]
So far, so good. Everything works as expected. For example,
MoveAntRandom[Ant[5, Left], 2/3, 15]
returns "Ant(4,Left)."
My problem comes when I try to generate the list of 20 random steps. Up to this point Mitchener has gone over a few tools. To generate lists like this, he uses NestList. So given the above, I would expect to be able to do this:
NestList[MoveAntRandom, Ant[5,Left], 20]
But instead of generating a list of ant records, this command generates a list of recursive calls to MoveAntRandom of increasing depth. For example, the third item in the list is "MoveAntRandom(MoveAntRandom(Ant(5,Left)))."
Of course the call to MoveAntRandom in the NestList does not have all its parameters. (Is there a way to set defaults?) Mitchener suggests using an "anonymous function" to address this. As I understand it (which probably means not at all) this implies
NestList[Function[{k}, MoveAntRandom[Ant[k, Left], 2/3, 15]], Ant[5, Left], 20]
should work.
It doesn't! The results are even more wrong than before. E.g., this time the third item in the list is "Ant(max(1, Ant(max(1, Ant(5, Left) - 1), Left) - 1), Left)."
Now what would make sense would be something like:
NestList[Function[{Ant[k, dir]}, MoveAntRandom[Ant[k, dir], 2/3, 15]], Ant[5, Left], 20]
But this is even more wrong than the others!
But if one replaces the Ant record in the anonymous function with x, we get a list like the one we want:
NestList[Function[{x}, MoveAntRandom[x, 2/3, 15]], Ant[5, Left], 20].
OK. Now let's put this into a function that passes the parameters for pStep, n, the number of random steps (nSteps), and an initial ant to use in the NestList:
AntWalk[Ant1_, pStep_, n_, nSteps_] :=
NestList[Function[{x}, MoveAntRandom[x, pStep, n]], Ant1, 20]
But if we try this with
AntWalk[Ant[5, Left], 2/3, 15, 20],
we get a mess. Also, if we use "Ant_ [k,dir]" instead of "Ant1_" as the first argument in the definition of AntWalk we get garbage back.
We can fix this by not passing an ant as the first argument. Instead, just pass the position and direction of the initial ant:
AntWalk[k_, dir_, pStep_, n_, nSteps_] :=
NestList[Function[{x}, MoveAntRandom[x, pStep, n]], Ant[k, dir], 20].
Now
AntWalk[5, Left, 2/3, 15, 20]
works!
We can also define AntWalk as
AntWalk[Ant[k_, dir_], pStep_, n_, nSteps_] :=
NestList[Function[{x}, MoveAntRandom[x, pStep, n]], Ant[k, dir], 20],
and this works.
Professor Mitchener wrote this tutorial in 2005, and Mathematica has changed. Since I'm using the tutorial to learn how to program simulations in Mathematica 10.1 in 2015, are there any changes that would make the above solutions easier or better?