2
$\begingroup$

I have a random walk algorithm that I want to implement, but I am getting a recursion depth issue. I am making a list of points that Z particles can be in over the domain $(-L/2,L/2)$. I am using a double For loop that will generate the values for the points of the different particles given this domain. The code is:

    Remove["Global`*"]
    Z = 3;
    NMAX = 3;
    l = 1;
    L = 100;
    x[0, i_] = 0;
    For[i = 0, i <= Z, i++,

    For[n = 1, n <= NMAX, n++,

    If[Abs[x[n - 1, i] + l Cos[2 π RandomReal[]]] >= L/2, 
    x[n, i] := x[n, i] = x[n - 1, i] - l Cos[2 π RandomReal[]], 
    x[n, i] := x[n, i] = x[n - 1, i] + l Cos[2 π RandomReal[]]]]]

    Table[x[n, i], {n, 0, NMAX}, {i, 0, Z}] // TableForm

$l$ is the uniform step that the particle will take and the If statement makes sure that the x position is assigned such that the value is within the domain. I would like to extend this also to y coordinates but that is something I will tackle after I can work this kink out.

I also started the list of particles (at time $n=0$) at position (0,0). The issue I am running into is that while the position for all (3) particles, starts off at 0 and then the first time step is shown but after that the out put is x[2,i] and x[3,i]. It works for the first time step, but not for any subsequent time steps. The error that I get is:

Recursion depth of 1024 exceeded.

I tried setting the recursion limit to 4000, since I found this somewhere else and it works for some problems, but ...

  1. I am not sure what setting the recursion limit does.

  2. It didn't work for me.

Any help would be appreciated!

$\endgroup$
1
  • 1
    $\begingroup$ Try with l1 = 1; l2 = 100; and accordingly the formation of formula. $\endgroup$
    – user9660
    Feb 27, 2016 at 9:13

1 Answer 1

5
$\begingroup$

Random walks are easy to implement with Mathematica. I think you would find many examples on this site if you were to search on "random walk". To implement the walk you describe, it just as easy to implement the 2D version you are aiming for as the 1D one, so the 2D walk is what I will discuss here.

First. Nested For-loops are not the way to go. I will use NestList which is a commonly used functional looping construct. I will also use recursion to handle the bounds constraint, but in a way the will not lead to uncontrolled recursion.

Second. I will use a divide-and-conquer implementation strategy. I break the problem in three parts.

  1. A function nextPt, which given the current point and the radius of the disk of possible next locations returns the next point of the walk. nextPt uses recursion to implement the boundary constraint.

  2. A function walk, which given the starting point, the radius of the disk of possible next locations, and the number of steps to be taken returns a list of points comprising the walk.

  3. A function walkPlot, which given a list made by walk produces a visualization of the walk. The stating point is shown as a red dot and ending point is shown as a blue dot. walkPlot will take additional options which will be passed on to Graphics, so the look of the plot can be modified to suit other needs. (The option handling could certainly be improved, but I thought adding the extra code required would distract from the main point of this answer.)

You may not need walkPlot for your work. You may just need first two functions to generated data for any further processing you have in mind.

With[{w = 10., h = 8.}, 
  With[{bounds = Rectangle[{-w/2., -h/2.}, {w/2., h/2}]}, 
    nextPt[ pt_, r_] := 
      Block[{nxt = pt + r {Cos[#], Sin[#]}&[RandomReal[2. π]]},
        If[RegionMember[bounds, nxt], Return[nxt]];
        nextPt[pt, r]];
    walk[start : {_Real, _Real}, r_Real?Positive, steps_Integer?Positive] :=
      NestList[nextPt[#, r] &, start, steps]; 
    walkPlot[path_, opts : OptionsPattern[]] :=
      Graphics[{
        Line[path],
        Red, Disk[First[path], Scaled[.015]],
        Blue, Disk[Last[path], Scaled[.015]]},
        opts,
        PlotRange -> Transpose[List @@ bounds],
        Frame -> True]]]

Note the following:

  • RegionMember, a fairly recent addition to Mathematica, is used to test whether or not a candidate point lies within the boundary rectangle.
  • The walk function is extremely simple in Mathematica's functional style. It also has much better performance than For.

Now let's run three experiments with the following code.

SeedRandom[2];
Column[Table[walkPlot[walk[{0., 0.}, 2., 150], ImageSize -> Medium], 3]]

walks

Update

I have corrected an error in the function nextPt. The updated version correctly generates steps of magnitude r.

$\endgroup$
9
  • 3
    $\begingroup$ Normalize[RandomVariate[NormalDistribution[], 2]] is a quicker, trig-free way of getting a uniformly distributed random unit vector. $\endgroup$ Feb 27, 2016 at 23:33
  • $\begingroup$ @J.M. Your suggestion relies on mathematics that is beyond me. I merely adopted and adapted the method the OP had already chosen. $\endgroup$
    – m_goldberg
    Feb 28, 2016 at 1:53
  • $\begingroup$ @m_goldberg I will look into NestList as an alternative and thank you for the detailed and outlined response. As J. M. mentioned I was actually using the RandomVariate command in a different approach where I made a list and using the Accumulate ( and If) function to append to an empty list if the number was within the bounds. $\endgroup$
    – phandaman
    Feb 28, 2016 at 2:05
  • $\begingroup$ @m_goldberg I also want to do some analysis of the given data. Say I want to run this 10,000 times for each distinct particle. Then I would want to be able to average over the x values of all particles at a given time step for example I wrote some code using the Do function. Do[s[i_]:=s[i]=walk[{0,0},1.,400.],{i,1,10,000}] which just takes a few seconds to do but accessing the elements in the list takes an atrocious amount of time. Is there anyway you can think of implementing this in a way that makes it faster? $\endgroup$
    – phandaman
    Mar 7, 2016 at 4:00
  • 1
    $\begingroup$ @phandaman. Your walk function can not be the same as the one I posted. It takes a different argument sequence, so I can't reproduce what you doing. I would guess that what you want is something like results = Table[walk[{0., 0.}, 1., 400], 10000]; {xMeans, yMeans} = Transpose[Mean /@ results]; Do not run this with the large numbers 400 and 10000 before trying and verifying that your version of this suggest works with small numbers, say, 4 and 10. $\endgroup$
    – m_goldberg
    Mar 7, 2016 at 18:16

Your Answer

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

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