Random walk on a sphere

Here is an approach.

rws[n_, p0_?(Norm@# == 1 &), ang_] := 
 NestList[RotationMatrix[ang/(2 Pi),
          (Function[{u, v}, {Cos[u] Cos[v], Cos[u] Sin[v], Sin[u]}] @@
           RandomReal[{0, 2 Pi}, 2])].# &, p0, n]

Visualizing:

Graphics3D[{Sphere[], Line[rws[10000, {1, 0, 0}, 1]]}, Boxed -> False]

spherical random walk from different views

trace of spherical random walk


If something is evaluating forever, it is because of poor implementation, an error or because it is just too much work to do :).

What I'm doing while debugging, is: if it looks ok -> run the minimal example, if it fails -> run it step by step:

screenshot

As you can see Abs[0. - 0.0987745-] is an expression that has no way to appear if - was a real Minus.

Fortunately, there aren't many explicitly written subtractions; you can copy each and try:

(1 – Cos[theta]) // FullForm
Times[\[Dash], Cos[theta]]

As noted by previous answerers, the desired distributional properties of the spherical random walk were not properly clarified. Nevertheless, let me offer two variations of interest.

The first variation is the spherical analog of the bounded random walk (this recent thread shows a few ways on how to implement this). This would seem to have been the variation that was being attempted. Before I can show my solution, let me pull out a few auxiliary routines:

(* https://mathematica.stackexchange.com/a/10994 *)
arc[center_?VectorQ, {start_?VectorQ, end_?VectorQ}] := Module[{ang, co, r},
    ang = VectorAngle[start - center, end - center];
    co = Cos[ang/2]; r = EuclideanDistance[center, start];
    BSplineCurve[{start, center + r/co Normalize[(start + end)/2 - center], end}, 
                 SplineDegree -> 2, SplineKnots -> {0, 0, 0, 1, 1, 1},
                 SplineWeights -> {1, co, 1}]]

(* slightly faster than the equivalent RotationMatrix[{vv1, vv2}];
   from https://doi.org/10.1080/10867651.1999.10487509 *)
vectorRotate[vv1_?VectorQ, vv2_?VectorQ] := 
 Module[{v1 = Normalize[vv1], v2 = Normalize[vv2], c, d, d1, d2, t1, t2},
        d = v1.v2;
        If[TrueQ[Chop[1 + d] == 0],
           c = UnitVector[3, First[Ordering[Abs[v1], 1]]];
           t1 = c - v1; t2 = c - v2; d1 = t1.t1; d2 = t2.t2;
           IdentityMatrix[3] - 2 (Outer[Times, t2, t2]/d2 - 
           2 t2.t1 Outer[Times, t2, t1]/(d2 d1) + Outer[Times, t1, t1]/d1),

           c = Cross[v1, v2];
           d IdentityMatrix[3] + Outer[Times, c, c]/(1 + d) - LeviCivitaTensor[3].c]]

Here is a function that takes a bounded random step in the sphere.

boundedRandomStep[v_?VectorQ, φ_?NumericQ] :=
       vectorRotate[{0, 0, 1}, v].({0, 0, Cos[φ]} + 
       Sin[φ] Append[Normalize[RandomVariate[NormalDistribution[], 2]], 0])

φ here is the length of the arc connecting the unit vector v and the generated random variate.

From this, here is how one might generate a bounded random walk:

With[{start = {0, 0, 1}, steps = 200, φ = π/15}, 
     BlockRandom[SeedRandom[42, Method -> "Legacy"]; 
                 Graphics3D[{Sphere[], {Red, Sphere[start, Scaled[1/150]]},
                             {Directive[Blue, Arrowheads[Small]], 
                              Arrow[Tube[arc[{0, 0, 0}, #], Scaled[1/1000]]] & /@ 
                              Partition[NestList[boundedRandomStep[#, φ] &, start, steps],
                                        2, 1]}}, Boxed -> False, PlotRange -> 1.2]]]

bounded random walk on a sphere


Another variation rests on using a distribution biased towards a particular "mean direction"; one such distribution is the the von Mises-Fisher distribution. First, here is a routine for generating von Mises-Fisher variates (previously shown in this answer):

vonMisesFisherRandom[μ_?VectorQ, κ_?NumericQ] := Module[{ξ = RandomReal[], w},
        w = 1 + (Log[ξ] + Log[1 + (1 - ξ) Exp[-2 κ]/ξ])/κ;
        RotationTransform[{{0, 0, 1}, Normalize[μ]}][
        Append[Sqrt[1 - w^2] Normalize[RandomVariate[NormalDistribution[], 2]], w]]]

Here is the random walk based on von Mises-Fisher:

With[{start = {0, 0, 1}, steps = 200, κ = 8}, 
     BlockRandom[SeedRandom[42, Method -> "MersenneTwister"]; 
     Graphics3D[{Sphere[], {Red, Sphere[start, Scaled[1/150]]},
                 {Directive[Blue, Arrowheads[Small]], 
                  Arrow[Tube[arc[{0, 0, 0}, #], Scaled[1/1000]]] & /@ 
                  Partition[NestList[vonMisesFisherRandom[#, κ] &, start, steps],
                            2, 1]}}, Boxed -> False, PlotRange -> 1.2]]]

von Mises-Fisher random walk