Here is a fully vectorized function that will return a matrix of positions in a random walk with k
steps. The matrix will have k + 1
rows (it includes the original position at the origin) unless the walk returns to the origin.
walk2d <- function(k) {
k1 <- k + 1L
m <- matrix(0L, k1, 2)
m[2:k1 + sample(c(0L, k1), k, 1)] <- sample(c(-1L, 1L), k, 1)
m[,1] <- cumsum(m[,1])
m[,2] <- cumsum(m[,2])
i <- which.min(rowSums(abs(m[-1,])))
if (i == 1L) m else m[1:(i + 1L),]
}
A walk that returns to the origin on the 14th step:
set.seed(123)
walk2d(20L)
#> [,1] [,2]
#> [1,] 0 0
#> [2,] -1 0
#> [3,] -1 -1
#> [4,] -2 -1
#> [5,] -1 -1
#> [6,] -2 -1
#> [7,] -1 -1
#> [8,] -1 0
#> [9,] -1 1
#> [10,] -2 1
#> [11,] -2 0
#> [12,] -1 0
#> [13,] -1 1
#> [14,] 0 1
#> [15,] 0 0
A walk that does not return to the origin within k
steps
set.seed(94)
walk2d(20L)
#> [,1] [,2]
#> [1,] 0 0
#> [2,] 1 0
#> [3,] 2 0
#> [4,] 2 1
#> [5,] 3 1
#> [6,] 3 2
#> [7,] 4 2
#> [8,] 4 1
#> [9,] 3 1
#> [10,] 2 1
#> [11,] 3 1
#> [12,] 4 1
#> [13,] 4 0
#> [14,] 4 1
#> [15,] 3 1
#> [16,] 4 1
#> [17,] 5 1
#> [18,] 6 1
#> [19,] 5 1
#> [20,] 4 1
#> [21,] 3 1
To estimate the probability of returning to the origin in less than 1000 steps, here is a vectorized function that will perform n
simulations and return the proportion that returned to the origin within k
steps. Note that walks can return to the origin only on even steps, so the probability of returning to the origin in less than 1000 steps is the same as the probability of returning within 998 steps.
library(Rfast)
library(parallel)
pReturn <- function(n, k) {
kn <- k*n
a <- array(0, c(k, n, 2))
a[1:kn + sample(c(0, kn), kn, 1)] <- sample(c(-1, 1), kn, 1)
a[,,1] <- colCumSums(a[,,1])
a[,,2] <- colCumSums(a[,,2])
sum(colSums(rowSums(abs(a), dims = 2) == 0) != 0)/n
}
pReturn(1e3, 998)
#> [1] 0.664
Setting n
too large will result in memory problems, so call pReturn
multiple times to get a better estimate.
cl <- makeCluster(detectCores() - 1L, type = "PSOCK")
clusterExport(cl, "pReturn")
invisible(clusterEvalQ(cl, library(Rfast)))
mean(unlist(parLapply(cl, 1:1e3, function(i) pReturn(1e3, 998)))) # 1M replications
#> [1] 0.678182
This compares well against the exact probability (building off http://oeis.org/A054474 in Mathematica, with m = k/2
):
In[1]:= m = 499; gf[x_] = 2 - Pi/(2*EllipticK[4*Sqrt[x]]);
N[Total[(List @@ Normal[Series[gf[x], {x, 0, m - 1}]] /. x -> 1)[[2 ;;
m + 1]]*Table[4^k, {k, -1, -m, -1}]]]
Out[2]= 0.678159