R Studio

Brownian Motion Simulation

#Simulation

install.packages.("sde")

# Brownian motion is very easy to simulate. To start off, let's simulate a single instance of 
# Brownian motion for 100 generations of discrete time in which the variance of the diffusion 
# process is ??2 = 0.01 per generation.

t <- 0:100  # time
sig2 <- 0.01
## first, simulate a set of random deviates
x <- rnorm(n = length(t) - 1, sd = sqrt(sig2))
## now compute their cumulative sum
x <- c(0, cumsum(x))
plot(t, x, type = "l", ylim = c(-2, 2))


# One path  simulation

t <- 0:100    # time
sig2 <- 0.01
## first, simulate a set of random deviates
X <- matrix(0, nsim, length(t))
for (i in 1:nsim) 
## first, simulate a set of random deviates  
X[i, ] <- c(0, cumsum(rnorm(n = length(t) - 1, sd = sqrt(sig2))))
plot(t, X[1, ], xlab = "time", ylab = "phenotype", ylim = c(-2, 2), type = "l")


# The trick here is that we draw random normal deviates for the change over each t time intervals; 
# and then to get the state of our chain at each time interval we just compute the cumulative sum of 
# all the individual changes using cumsum. We can do this because the distribution of the changes under 
# Brownian motion is invariant and does not depend on the state of the chain.

We can also easily do a whole bunch of simulations like this at once, using the same conditions:

nsim <- 100
X <- matrix(rnorm(n = nsim * (length(t) - 1), sd = sqrt(sig2)), nsim, length(t) - 1)
X <- cbind(rep(0, nsim), t(apply(X, 1, cumsum)))
plot(t, X[1, ], xlab = "time", ylab = "phenotype", ylim = c(-2, 2), type = "l")
apply(X[2:nsim, ], 1, function(x, t) lines(t, x), t = t)


#To see how the outcome depends on ??2, let's compate the result when we divide sig2 by 10:

X <- matrix(rnorm(n = nsim * (length(t) - 1), sd = sqrt(sig2/10)), nsim, length(t) - 
              1)
X <- cbind(rep(0, nsim), t(apply(X, 1, cumsum)))
plot(t, X[1, ], xlab = "time", ylab = "phenotype", ylim = c(-2, 2), type = "l")
apply(X[2:nsim, ], 1, function(x, t) lines(t, x), t = t)


# There are a number of different ways we could've done this. For example, instead of using apply, 
# which economizes on code, we could have used a for loop as follows:

X <- matrix(0, nsim, length(t))
for (i in 1:nsim) X[i, ] <- c(0, cumsum(rnorm(n = length(t) - 1, sd = sqrt(sig2))))
plot(t, X[1, ], xlab = "time", ylab = "phenotype", ylim = c(-2, 2), type = "l")
for (i in 1:nsim) lines(t, X[i, ])


#As mentioned above, the expected variance under Brownian motion is just ??2 � t. To see this easiest, 
#we can just do the following. Here I will use 10,000 simulations for 100 generations under the same 
#conditions to "smooth out" our result:

nsim <- 10000
X <- matrix(rnorm(n = nsim * (length(t) - 1), sd = sqrt(sig2)), nsim, length(t) - 
              1)
X <- cbind(rep(0, nsim), t(apply(X, 1, cumsum)))
v <- apply(X, 2, var)
plot(t, v, type = "l", xlab = "time", ylab = "variance among simulations")


#Brownian motion is generally assumed to be trendless; however it is possible to simulate and (under 
#some conditions) fit a model of Brownian evolution with a trend. Here is an example of a simulation 
#(using the same general approach as above) with a trend

nsim = 100
X <- matrix(rnorm(mean = 0.02, n = nsim * (length(t) - 1), sd = sqrt(sig2/4)), 
            nsim, length(t) - 1)
X <- cbind(rep(0, nsim), t(apply(X, 1, cumsum)))
plot(t, X[1, ], xlab = "time", ylab = "phenotype", ylim = c(-1, 3), type = "l")
apply(X[2:nsim, ], 1, function(x, t) lines(t, x), t = t)


                                                                     
library(phytools)
t <- 100  # total time
n <- 30  # total taxa
b <- (log(n) - log(2))/t
tree <- pbtree(b = b, n = n, t = t, type = "discrete")
## simulating with both taxa-stop (n) and time-stop (t) is
## performed via rejection sampling & may be slow
## 
##   31 trees rejected before finding a tree
plotTree(tree)



# The threshold model
tree <- pbtree(n = 100, scale = 1)
xx <- bmPlot(tree, sig2 = 2/1000, type = "threshold", thresholds = c(-2, 0, 2))

# Here is an example of a continuous time simulation & visualization using canned functions.

## simulate Brownian evolution on a tree with fastBM
x <- fastBM(tree, sig2 = sig2, internal = TRUE)
## visualize Brownian evolution on a tree
phenogram(tree, x, spread.labels = TRUE, spread.cost = c(1, 0))