#moran_simulation function
#input: population table of individuals and fitness
moran_simulation <- function(population){
  #settings and parameters
  #population size
  N <- nrow(population)
  #initial time
  time <- 0  
  
  sim_pop<-population$id
  events <- data.frame(time = numeric(), 
                       reproducer = numeric(), 
                       replaced = numeric())
  cat("Population:", sim_pop, "Time:", time, "\n")
  
  while (length(unique(sim_pop)) > 1) {
    
    #sum of the fitness
    total_rate <- sum(population$fitness[sim_pop])
    #probability to be choose
    rates <- population$fitness[sim_pop] / total_rate
    
    #waiting time
    wait_time <- rexp(1, rate = total_rate)
    time <- time + wait_time
    
    #choose one individual to reproduce
    reproducer_index <- sample(1:N, 1, prob = rates)
    
    #randomly choose an individual that be replaced
    to_replace_index <- sample(1:N, 1)
    
    sim_pop[to_replace_index]<-sim_pop[reproducer_index]
    
    cat("Population:", sim_pop, "Time:", time, "\n")
    
    # record replacement relationship and time point
    events <- rbind( events, data.frame(time = wait_time, reproducer = reproducer_index, replaced = to_replace_index) )
  }
  return(events)
}

generate tree format from the history

build_coalescent_tree <- function(events, population) {
  
  N <- nrow(population)
  nodes <- as.character(population$id)
  branch_lengths <- rep(0, N)
  ancestors <- nodes
  
  # go through the events backwards
  for (i in nrow(events):1) {
    event <- events[i, ]
    time <- event$time
    
    #branch increasing
    branch_lengths <- branch_lengths + time
    
    #renew ancestors of individuals by the events
    reproducer<-event$reproducer
    ancestors[which(ancestors == event$replaced)] <- reproducer
    
    #emerge nodes that have same ancestor
    if (sum(duplicated(ancestors)) > 0) {
      #if two individuals have same ancestor
      
      #find the individuals that have same ancestor
      rm_index <- which(duplicated(ancestors) | duplicated(ancestors, fromLast = TRUE))
      a <- rm_index[1]
      b <- rm_index[2]
      
      #generate a new node that is the combination of these two
      new_node <- paste0("(", nodes[a], ":", branch_lengths[a], ",", nodes[b], ":", branch_lengths[b], ")")
      
      #remove coalescent nodes
      nodes <- nodes[-rm_index]
      branch_lengths <- branch_lengths[-rm_index]
      ancestors <- ancestors[-rm_index]
      
      #add new node
      nodes <- c(nodes, new_node)
      branch_lengths <- c(branch_lengths, 0)
      ancestors <- c(ancestors, reproducer)
      }
    }
  return(paste0(nodes, ";"))
}
n<-6
id<-c(1:n)
fitness<- c(1.1, 1.2, 1.3, 1, 1, 1)
population <- data.frame(id = id, fitness = fitness)

#simulate the population history
  events <- moran_simulation(population)
## Population: 1 2 3 4 5 6 Time: 0 
## Population: 1 4 3 4 5 6 Time: 0.0744159 
## Population: 1 4 3 6 5 6 Time: 0.2090928 
## Population: 1 1 3 6 5 6 Time: 0.3266537 
## Population: 1 1 6 6 5 6 Time: 0.4289079 
## Population: 1 1 6 6 1 6 Time: 0.4721206 
## Population: 1 1 6 6 1 6 Time: 0.6445721 
## Population: 1 1 6 6 1 6 Time: 0.8298878 
## Population: 1 1 6 6 1 6 Time: 0.9320347 
## Population: 1 1 1 6 1 6 Time: 1.108167 
## Population: 1 1 1 6 1 6 Time: 1.151871 
## Population: 6 1 1 6 1 6 Time: 1.294143 
## Population: 6 1 1 6 1 1 Time: 1.411419 
## Population: 6 1 1 6 1 1 Time: 1.568244 
## Population: 6 1 1 6 1 1 Time: 1.915598 
## Population: 6 6 1 6 1 1 Time: 2.304489 
## Population: 1 6 1 6 1 1 Time: 2.615534 
## Population: 1 6 1 1 1 1 Time: 2.754292 
## Population: 1 6 6 1 1 1 Time: 2.84451 
## Population: 1 6 6 1 1 1 Time: 2.967296 
## Population: 1 6 6 1 1 1 Time: 3.075922 
## Population: 1 6 6 1 1 1 Time: 3.173771 
## Population: 1 6 6 1 1 6 Time: 3.450212 
## Population: 6 6 6 1 1 6 Time: 3.646756 
## Population: 6 6 6 1 1 6 Time: 3.664243 
## Population: 6 6 6 1 1 1 Time: 3.838538 
## Population: 6 6 6 1 1 6 Time: 4.172361 
## Population: 6 6 6 6 1 6 Time: 4.531478 
## Population: 6 6 6 6 1 6 Time: 4.837657 
## Population: 6 6 6 6 6 6 Time: 4.879973
  #events <- events[events$reproducer != events$replaced, ]
  events
##          time reproducer replaced
## 1  0.07441590          4        2
## 2  0.13467694          6        4
## 3  0.11756082          1        2
## 4  0.10225428          4        3
## 5  0.04321265          1        5
## 6  0.17245154          5        5
## 7  0.18531564          2        1
## 8  0.10214696          4        6
## 9  0.17613235          1        3
## 10 0.04370376          1        2
## 11 0.14227244          4        1
## 12 0.11727548          2        6
## 13 0.15682500          5        2
## 14 0.34735415          6        6
## 15 0.38889124          1        2
## 16 0.31104505          6        1
## 17 0.13875821          5        4
## 18 0.09021800          2        3
## 19 0.12278555          5        5
## 20 0.10862643          3        3
## 21 0.09784854          6        5
## 22 0.27644136          2        6
## 23 0.19654392          3        1
## 24 0.01748657          2        3
## 25 0.17429538          4        6
## 26 0.33382307          2        6
## 27 0.35911657          3        4
## 28 0.30617880          2        1
## 29 0.04231614          2        5
#draw tree from the history events
library(ape)
## Warning: 程辑包'ape'是用R版本4.2.3 来建造的
  newick_tree <- build_coalescent_tree(events, population)
  
  #cat( newick_tree)
  plot(read.tree(text = newick_tree), type = "phylogram", show.tip.label = TRUE, edge.width = 2)
  axisPhylo()

main function of simulation

library(ape)
main_moran_simu<-function(population){
  ##main:
  
  #simulate the population history
  events <- moran_simulation(population)
  events <- events[events$reproducer != events$replaced, ]
  #events
  
  #draw tree from the history events
  newick_tree <- build_coalescent_tree(events, population)
  
  #cat( newick_tree)
  
  plot(read.tree(text = newick_tree), type = "phylogram", show.tip.label = TRUE, edge.width = 2)
  axisPhylo()
}

an example

n<-6
id<-c(1:n)
fitness<- c(1.1, 1.2, 1.3, 1, 1, 1)
population <- data.frame(id = id, fitness = fitness)
main_moran_simu(population)
## Population: 1 2 3 4 5 6 Time: 0 
## Population: 1 3 3 4 5 6 Time: 0.4667031 
## Population: 1 3 3 4 5 3 Time: 0.6115389 
## Population: 1 3 3 3 5 3 Time: 0.748682 
## Population: 1 3 3 3 1 3 Time: 0.8133516 
## Population: 1 1 3 3 1 3 Time: 0.8167021 
## Population: 1 3 3 3 1 3 Time: 0.9607275 
## Population: 1 3 3 3 1 3 Time: 1.208978 
## Population: 1 3 3 3 1 3 Time: 1.536519 
## Population: 1 3 3 3 1 3 Time: 1.567063 
## Population: 1 3 3 1 1 3 Time: 1.613481 
## Population: 1 3 3 1 3 3 Time: 1.655239 
## Population: 1 1 3 1 3 3 Time: 1.72249 
## Population: 1 1 3 1 3 3 Time: 2.016673 
## Population: 1 1 3 1 3 3 Time: 2.425347 
## Population: 1 1 3 1 1 3 Time: 2.546316 
## Population: 1 1 3 1 1 3 Time: 2.70798 
## Population: 1 1 1 1 1 3 Time: 3.364686 
## Population: 1 1 1 1 1 3 Time: 3.508249 
## Population: 1 1 1 1 1 1 Time: 3.856845

W-F model:

random_coalescent <- function(N) {
  # poopulation initialization
  # individuals and the corresponding time till coalescent
  population <- as.character(paste("ind", c(1:N)))
  pop_t <- rep(0, N)
  pop_frame <- data.frame(population, pop_t, stringsAsFactors = FALSE)
  
  # coalescent times from N to 2 individuals
  t <- sapply(c(2:N), function(x) rexp(1, 1/choose(x,2)))
  
  # coalescent process
  for (i in 1:(N-1)) {
    #renew waiting time for tips
    pop_frame$pop_t <- pop_frame$pop_t + t[i]
    
    #randomly choose 2 tips
    co_pair <- sample(1:length(pop_frame[,1]), 2, replace = FALSE)
    co_ind <- pop_frame[co_pair, ]
    pop_frame <- pop_frame[-co_pair, ]
    
    # construct new tip by the choosen 2 tips
    new_branch <- paste(
      "(", co_ind[1, 1], ":", as.numeric(co_ind[1, 2]), ",",
      co_ind[2, 1], ":", as.numeric(co_ind[2, 2]), ")"
    )
    
    # renew the tips dataframe
    pop_frame <- rbind(pop_frame, data.frame(population = new_branch, pop_t = 0, stringsAsFactors = FALSE))
  }
  
  # return final tree in newick format
  return(paste0(pop_frame$population[1], ";"))
}
library(ape)

# an example for 10 individuals
plot.phylo(read.tree(text = random_coalescent(6)))
axisPhylo()