DelaySSA

February 7, 2025 · View on GitHub

DelaySSA is an R package designed to simulate non-Markovian models of gene expression by extending the Gillespie algorithm to reactions with delay. This package is particularly useful for researchers and practitioners in computational biology and systems biology who are interested in modeling the dynamics of gene expression with intrinsic delays.

Features

  • Implementation of the delayed Gillespie algorithm [1-4].
  • Support for modeling gene expression with various delay distributions.
  • Easy-to-use interface for defining reactions with delays.
  • Capability to handle complex gene regulatory networks.
  • Visualization tools for analyzing simulation results.

Installation

Download the installation package from GitHub

devtools::install_github("Zoey-JIN/DelaySSA")

Or download and install locally

devtools::install("~/DelaySSA")

Then load the package

library("DelaySSA")

Tutorial Example : Delayed Production and Annihilation System

This tutorial is designed to demonstrate how to use DelaySSA for defining chemical reaction models, solving related problems, and visualizing the results. The source code for all examples and figures can be found in the GitHub examples folder. We study the system with two non-delay channels and one delay channel. This model describes that molecule S1S_1 binds S2S_2 and then degrade with the reaction rate k1k_1. Once the reaction occurs, the molecule S3S_3 will be generated after a fixed time delay τ\tau, and will degrade with the rate k2k_2. This procedure can be described by

S1+S2k1,  τS3,  S3k2.S_1+S_2 \xrightarrow{k_1}\emptyset,~~\emptyset\stackrel{\tau}\Rightarrow S_3,~~S_3 \xrightarrow{k_2}\emptyset.

The species are S1,S2,S3S_1,S_2,S_3. Let k1=0.001,k2=0.001τ=0.1.k_1=0.001, k_2 = 0.001,\tau = 0.1.

Initialization Part

Assume reactions occur in this system from t_initial=0 to tmax=150, repeating this process for sample=1000 times. The initial quantities of S1,S2S_1,S_2 and S3S_3 are 1000, 1000, and 1, respectively.

sample <- 1000
tmax <- 150
n_initial <- matrix(c(1000,1000,0),nrow = 3)
t_initial <- 0

According to the reactions, the counting of reactant and product molecules rows is arranged with rows indexed as S1,S2,S3S_1,S_2,S_3, and columns indexed in order of the reactions. sirs_{ir} and sirs_{ir}' denote numbers of reactant and product molecules, respectively. Then, we define ss as reactant_matrix and ss'. Therefore, we can define SS as S_matrix. For delay part, we can define SdelayS_\text{delay} as S_matrix_delay, which can be expressed as

s=(101001), s=(000000), S=ss=(101001), Sdelay=(000010)s=\begin{pmatrix} 1 & 0 \\ 1 & 0 \\ 0 & 1 \end{pmatrix},~ s'=\begin{pmatrix}0 & 0 \\0 & 0 \\0 & 0\end{pmatrix}, ~ S=s'-s=\begin{pmatrix} -1 & 0 \\ -1 & 0 \\0 & -1 \end{pmatrix},~ S_\text{delay}=\begin{pmatrix} 0 & 0 \\0 & 0 \\1 & 0\end{pmatrix}
S_matrix <- c(-1,-1,0,0,0,-1)
S_matrix <- matrix(S_matrix,nrow = 3) 
> S_matrix
     [,1] [,2]
[1,]   -1    0
[2,]   -1    0
[3,]    0   -1

S_matrix_delay <- c(0,0,1,0,0,0)
S_matrix_delay <- matrix(S_matrix_delay,nrow = 3)
> S_matrix_delay
     [,1] [,2]
[1,]    0    0
[2,]    0    0
[3,]    1    0

k <- c(0.001,0.001)
reactant_matrix <- matrix(c(1,1,0,0,0,1),nrow = 3)
> reactant_matrix
     [,1] [,2]
[1,]    1    0
[2,]    1    0
[3,]    0    1

The reactions are categorized as ICD and ND, with delay_type corresponding to 2 and 1 respectively. delaytime_list records the delay times of the reactions. The first reaction will trigger a delay reaction that will happen after τ=0.1\tau = 0.1 seconds. The second reaction will not trigger a delay reaction, thus a 0 is added to delaytime_list.

tau = 0.1
delay_type <- matrix(c(2,0),nrow = 1)
delaytime_list <- list()
delaytime_list <- append(delaytime_list,c(tau,0))

Simulation and Visualization Part

Next, use the function simulation_DelaySSA from the package to calculate the quantities of species after reactions occur and the corresponding times for each reaction

result <- simulation_DelaySSA(algorithm = "DelayMNR", sample_size=sample, tmax=tmax, n_initial=n_initial, t_initial=t_initial, S_matrix=S_matrix, S_matrix_delay=S_matrix_delay, k=k, reactant_matrix=reactant_matrix, delay_type=delay_type , delaytime_list=delaytime_list)

result is a list whose length is determined by the number of simulations sample_size. Each element of this list is also a list, consisting of:

  1. A vector representing the times at which reactions occurred.
  2. A matrix showing the changes in species over time.

Sampling times are taken as seq(0, tmax, by = 1). Use plot_SSA_mean to calculate and plot the mean values in the quantities of each species at these time points. At time tmax, use plot_SSA_density to calculate and plot the probability distribution of the quantities of each species. Here the number of S1S_1 is the same as the number of S2S_2.

plot_SSA_mean(result = result,t=seq(0, tmax, by = 1) ,n_initial = n_initial,t_initial = 0)
plot_SSA_density(result = result,t_pick = tmax)

To be more specific, result is the output list from simulation. Then use picksample(result,i,t) to sample the species i at time t. convert_pdf(n) can convert the vector to a list containing the probability density. The list has two elements, where the first element is a vecter representing number of the species, and the second element is a table representing the probability for each quantity. plot_mean(result, i, t) returns the mean value of species i at time t after the simulation, using the result data. plot_mean relies on the picksample and mean functions to perform the calculation. All in all, we can use picksample and convert_pdf functions to obtain the probability distribution of each species at each time point and use plot_mean function to obtain the mean value of each species over repeated simulations.

> a <- c(1,2,3,4,5)
> convert_pdf(a)
[[1]]
[1] 1 2 3 4 5

[[2]]
a_vector
  1   2   3   4   5 
0.2 0.2 0.2 0.2 0.2 
library(ggplot2)
Species <- c("S1 S2","S1 S2","S3")
svg <- svglite("TwoChannels_mean.svg", width = 5, height = 5)
t=seq(0, tmax, by = 1)
t_initial = 0
num_columns <- nrow(result[[1]]$n_values)
data_list <- lapply(c(2,3), function(i) {
  n <- lapply(t, function(x) plot_mean(result, i, x))
  n <- unlist(n)
  if (t[1] == t_initial) 
    n[1] <- n_initial[i, ]
  data.frame(t = t, quantity = n, Species = Species[i])
})
plot_data <- do.call(rbind, data_list)
ggplot(plot_data, aes(x = t, y = quantity, color = Species)) + 
  geom_line(linewidth = 0.7) +  
  labs(x = "T", y = "Mean Value") + 
  scale_color_brewer(palette = "Set1") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"), 
    axis.title = element_text(size = 12, face = "bold"),  
    axis.text = element_text(size = 10), 
    legend.title = element_blank(),  
    legend.text = element_text(size = 10),  
    panel.grid = element_blank(),  
    panel.background = element_blank(), 
    axis.line = element_line(color = "black")  
  )
dev.off()
svg <- svglite("TwoChannels_S1andS2_density_150s.svg", width = 5, height = 5)
num_columns <- nrow(result[[1]]$n_values)
data_list <- lapply(c(2), function(i) {
  n <- lapply(result, function(x) picksample(x, i, t=tmax))
  n <- unlist(n)
  plot_xy <- convert_pdf(n)
  if (!all(data.frame(percentage = plot_xy)[, 1] == data.frame(percentage = plot_xy)[,2])) {
    warning("Error in Calculating Density Table")
  }
  data.frame(quantity = data.frame(percentage = plot_xy)[,1], percentage = data.frame(percentage = plot_xy)[,3], Species = Species[i])
})
plot_data <- do.call(rbind, data_list)
ggplot(plot_data, aes(x = quantity, y = percentage, color = Species)) + 
  geom_line(linewidth = 0.7) +  
  labs(x = "# of Products", y = "Probability") + 
  scale_color_brewer(palette = "Set1") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),  
    axis.title = element_text(size = 12, face = "bold"), 
    axis.text = element_text(size = 10),  
    legend.title = element_blank(), 
    legend.text = element_text(size = 10),  
    panel.grid = element_blank(), 
    panel.background = element_blank(),  
    axis.line = element_line(color = "black") 
  )
dev.off()
svg <- svglite("TwoChannels_S3_density_150s.svg", width = 5, height = 5)
num_columns <- nrow(result[[1]]$n_values)
data_list <- lapply(c(3), function(i) {
  n <- lapply(result, function(x) picksample(x, i, t=tmax))
  n <- unlist(n)
  plot_xy <- convert_pdf(n)
  if (!all(data.frame(percentage = plot_xy)[, 1] == data.frame(percentage = plot_xy)[,2])) {
    warning("Error in Calculating Density Table")
  }
  data.frame(quantity = data.frame(percentage = plot_xy)[,1], percentage = data.frame(percentage = plot_xy)[,3], Species= Species[i])
})
plot_data <- do.call(rbind, data_list)
ggplot(plot_data, aes(x = quantity, y = percentage, color = Species)) + 
  geom_line(linewidth = 0.7) + 
  labs(x = "# of Products", y = "Probability") + 
  scale_color_brewer(palette = "Set1") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),  
    axis.title = element_text(size = 12, face = "bold"),  
    axis.text = element_text(size = 10), 
    legend.title = element_blank(),  
    legend.text = element_text(size = 10),  
    panel.grid = element_blank(),  
    panel.background = element_blank(), 
    axis.line = element_line(color = "black")  
  )
dev.off()

TwoChannels_mean TwoChannels_S1andS2_density_150s TwoChannels_S3_density_150s

Main API

algorithm
The alternative algorithm must be one of DelayMNR (default), DelayReject, or DelayDirect. Traditional stochastic simulation including Direct, MNR and NR are recommended and the parameters of S_matrix_dalay delay_type and delaytime_list can be omitted.

sample_size
A numeric value representing trajectories for the system.

tmax
A numeric value representing the cut-off time for the system.

n_initial
An N-by-1 matrix representing the initial quantity of species, where N corresponds to the number of molecular species.

t_initial
A numeric value representing the initial time for the system.

S_matrix
An N-by-R matrix, where N corresponds to the number of species types and R corresponds to the number of reactions. It represents the stoichiometric matrix at the initiation time tt, denoting the change in the number of molecules per reaction.

S_matrix_dalay
An N-by-R matrix, representing the stoichiometric matrix at the completion time t+tdelayt+t_\text{delay}, which is only relevant for the delayed type of CD and ICD reactions. If it is not a delay reaction namely ND reactions, the corresponding column is filled with zeros.

k
An R-dimensional vector representing the reaction constant rate or a function representing the variable rate.

reactant_matrix
An N-by-R matrix, representing the quantity of reactants.

reactant_matrix_delay
An N-by-R matrix, representing the quantity of reactants in delay part.

f_r
A function determined by kk and nn. f_r represents the propensity function.

delay_type
An R-dimensional vector or a 1-by-R matrix representing the type of the reactions. It is a numerical vector, where each element can take on the values 0, 1, or 2. Here 0 represents ND, 1 represents CD and 2represents ICD.

delaytime_list
An R-dimensional list representing the delay time of the reactions. Every element can be a fixed number or a stochastic value governed by a function.

delay_effect_matrix
A 2-row matrix. The first row represents the reaction index of S_matrix, the second row represents the reaction index of S_matrix_dalay. If not empty, each column of the matrix links S_matrix and S_matrix_delay: the first row shows the column index rr from S_matrix, while the second row shows the corresponding column index rr' from S_matrix_delay, where both columns are the same. This will cause the rr'-th reaction in delay part to be randomly eliminated when the rr-th reaction in S_matrix occurs called interruption.

Function

Function Description
check_delay_relative* Delay Effect Matrix
convert_pdf Probability Density Functions Conversion
fun_fr Propensity Function
picksample Results Sampling
plot_mean The Mean Value of Species i at Time t
plot_SSA_density* Density at Time t_pick
plot_SSA_mean* Mean of Species over Time
propensity_n For Propensity Calculation
simulate_reaction* Gillespie Algorithm
simulate_reaction_delay_direct* Delay Direct Method Algorithm
simulate_reaction_delay_modifiednextreaction* Delay Modified Next Reaction Method Algorithm
simulate_reaction_delay_rejection* Delay Rejection Method Algorithm
simulate_reaction_modifiednextreaction* Modified Next Reaction Method Algorithm
simulate_reaction_nextreaction* Next Reaction Method Algorithm
simulation_DelaySSA* Simulation Algorithm (SSA) with Delays
tau_element Delay Time

* This function can be used independently.

Basic Concepts

Biological processes encompass a multitude of intricate mechanisms involving various molecules and physical interactions. By conceptualizing these processes as a series of discrete chemical reactions, we can mathematically formalize them. This mathematical representation enables precise modeling of the reaction dynamics and facilitates accurate predictions of reactant quantities.

Stochastic Simulation Algorithm (SSA) [1] is a method used to simulate stochastic processes in chemical reaction systems. This algorithm is particularly suitable for systems with a small number of molecules.

However, some chemical reactions, such as gene transcription and translation within living cells, necessitate a defined temporal duration to reach completion following their initiation. As a result, the products of these reactions will manifest only after a time delay which makes the traditional SSA algorithm unsuitable for these reactions. DelaySSA implements a stochastic simulation algorithm (SSA) with delays in R language. It can simulate chemical reaction systems both with and without delays. now DelaySSA supports three exact delay stochastic simulation algorithms, namely, delay direct method DelayDirect [2], delay rejection method DelayRejction DelayReject [3] and delay modified next reaction method DelayMNR [4]. Here we give the basic concepts of these algorithms.

Given a finite set of chemical species Xi,i=1,,N,X_i, i = 1, \ldots,N, and RR chemical reactions, we define the reactions by the notation

i=1NsirXikri=1NsirXi,  r=1,,R,\sum_{i=1}^{N} s_{ir}X_i \xrightarrow{k_r} \sum_{i=1}^{N} s^{'}_{ir}X_i,~~r=1, \ldots,R,

where sirs_{ir} and sirs'_{ir} denote numbers of reactant and product molecules, respectively. krk_r is the reaction rate constant of the rr-th reacion. And the stoichiometric matrix SS is given by

Sir=sirsir,  r=1,,R,  i=1,,N.S_{ir}=s^{'}_{ir}-s_{ir},~~r=1, \ldots,R,~~i=1, \ldots,N.

According to [5], propensity function f(n)f(\textbf{n}) are in the form of mass-action kinetics type

fr(n)=krΩi=1Nni!(nisir)!Ωsir,f_r(\textbf{n})_=k_r \Omega \prod_{i=1}^{N} \frac{n_i!}{(n_i-s_{ir})! \Omega^{s_{ir}}},

where n=(n1,,nN)\textbf{n} = \left( n_1, \ldots, n_N \right), nin_i is the number of species XiX_i, Ω\Omega is the volume of a closed compartment.

The time delay could be a fixed number or a stochastic value. According to [3], reactions with delays are categorized into consuming and nonconsuming reactions. If a delayed reaction is a nonconsuming reaction, it initiates at tt and will finish until t+tdelayt+t_\text{delay}, then the n\textbf{n} of the number of species will change only at t+tdelayt+t_\text{delay}. If a delayed reaction is a consuming reactions, it initiates at tt and will finish until t+tdelayt+t_\text{delay}, then the n\textbf{n} of the number of species will change both at tt and t+tdelayt+t_\text{delay}.

We can categorize reactions into the following three cases.

Case 1: If reaction rr loses the reactant species and gains the product species at the initiation time tt, we define the reaction rr with no delays as ND.

Case 2: If reaction rr loses the reactant species and gains the product species at the completion time t+tdelayt+t_\text{delay}, we define the reaction rr with delays as CD.

Case 3: If reaction rr loses the reactant species and gains the product species at the initiation time tt and the completion time t+tdelayt+t_\text{delay}, respectively, we define the reaction rr with delays as ICD.

Delay Direct Method Algorithm

Consider that NdN_d delay reactions are ongoing at the time tt. The delay reactions will complete at t+T1,,t+TNdt+T_1,\ldots,t+T_{N_d}, where T1T2TNdT_1 \leq T_2 \leq \ldots \leq T_{N_d}. As in the derivation of Gillespie’s exact Stochastic Simulation Algorithm (SSA), p(τ,ν)dτp(\tau, \nu) d\tau can be found from the fundamental assumption as p(τ,ν)dτ=p0(τ)fμ(t+τ)dτp(\tau, \nu) d\tau = p_0(\tau) f_\mu(t + \tau) d\tau, where p0(τ)p_0(\tau) is the probability that no reaction will happen in the time interval [t,t+τ)[t,t+\tau). The delay effects the propensity function. So p0(τ)p_0(\tau) comes to exp(Σj=0i1λ(t+Tj)(Tj+1Tj)λ(t+Ti)(τTi)),  τ[Ti,Ti+1),  i=0,,Nd\exp(-\Sigma_{j=0}^{i-1}\lambda(t+T_j)(T_{j+1}-T_j)-\lambda(t+T_i)(\tau-T_{i})),~~\tau \in [T_i, T_{i+1}), ~~i=0,\ldots,N_d, where the exponent assumes equal to zero when i=0i=0.

p(τn,t)=λ(t+Ti)exp(j=0i1λ(t+Tj)(Tj+1Tj)λ(t+Ti)(τTi)),  λ(t+Ti)=r=1Rfr(t+Ti),p(\tau|\textbf{n},t)=\lambda(t + T_i) \exp ( - \sum_{j=0}^{i-1} \lambda(t + T_j)(T_{j+1} - T_j) - \lambda(t + T_i)(\tau - T_i) ),~~\lambda(t + T_i)=\sum_{r=1}^{R} f_r(t + T_i), p(μn,t)=fr(t+Ti)/λ(t+Ti),  μ=1,,R,  τ[Ti,Ti+1),  i=0,,Nd.p(\mu|\textbf{n},t)=f_r(t + T_i)/\lambda(t + T_i),~~\mu= 1, \ldots,R, ~~\tau \in [T_i, T_{i+1}), ~~i=0,\ldots,N_d.

According this two equations, τ\tau and μ\mu can be generated as,

τ=Ti+ln(1u1)Σj=0i1λ(t+Tj)(Tj+1Tj)λ(t+Ti),\tau=T_i+\frac{-\ln(1-u_1)-\Sigma_{j=0}^{i-1} \lambda(t + T_j)(T_{j+1} - T_j)}{\lambda(t + T_i)} , μ=the integer satisfies r=1μ1fr(t+Ti)<u2λ(t+Ti)r=1μfr(t+Ti),\mu=\text{the integer satisfies $\sum_{r=1}^{\mu-1} f_r(t + T_i)< u_2 \lambda (t + T_i) \leq \sum_{r=1}^{\mu} f_r(t + T_i)$} ,

where u1,u2Uniform(0,1)u_1,u_2\sim \text{Uniform}(0,1) respectively.

Algorithm

Suppose that at time tt there are ongoing delayed reactions set to complete at times t+T1,t+T2,,t+Tdt+T_1, t+T_2, \ldots, t+T_d. Define T0=0T_0=0 and Td+1=T_{d+1}=\infty.

Define Tstruct, whose ii-th (i=1,,d)(i=1,\dots,d) row stores TiT_i and the index, μi\mu_i, of the reaction that TiT_i is associated with.

  1. Initialize. Set t=0t=0 and set species number n=ninitialn = n_\text{initial}. Create a empty Tstruct.

  2. Calculate propensity functions fr(t),r=1,,Rf_r(t), r=1, \ldots,R.

  3. Generate τ\tau.

    • Generate an independent Uniform(0,1)\text{Uniform}(0,1) random number u1u_1.

    • If Tstruct is empty, it means there is no ongoing delayed reaction.

      • Set τ=ln(u1)/Σr=1Rfr\tau = -\ln(u_1)/ \Sigma_{r=1}^{R}f_r.
    • Else

      • Set amask=0a_\text{mask}=0.

      • Set i=0i=0, F=0F=0 and at=Σr=1RfrT1a_t = \Sigma_{r=1}^{R} f_rT_1.

      • While F<u1F < u_1

        • Calculate F=1eat,i=i+1F=1-e^{-a_t},i=i+1.

        • Calculate propensity fr(t+Ti)f_r(t+T_i) due to the finish of the delayed reaction at t+Tit+T_{i} and calculate Σr=1Rfr(t+Ti)\Sigma_{r=1}^{R}f_r(t+T_i).

        • Set amask=ata_{mask}=a_t. Update at=at+Σr=1Rfr(t+Ti)(Ti+1Ti)a_t=a_t+\Sigma_{r=1}^{R}f_r(t+T_i)(T_{i+1}-T_i).

        • If i>1i>1, update species number nn due to the delay reaction at t+Ti1t+T_{i-1}

      • EndWhile

      • Set i=i1i=i-1.

      • Calculate τ=Ti(ln(1u1)+amaskΣr=1Rfr(t+Ti)(Ti+1Ti))/Σr=1Rfr(t+Ti)\tau=T_i-(\ln(1-u_1)+a_\text{mask}-\Sigma_{r=1}^{R}f_r(t+T_i)(T_{i+1}-T_i))/\Sigma_{r=1}^{R}f_r(t+T_i).

    • EndIf

  4. If τ[Ti,Ti+1)\tau\in[T_i,T_{i+1}), delete the columns $1,\ldots,iofofT_iandsetand setT_j=T_j-\tau$.

  5. Generate u2u_2 from a Uniform(0,1) random variable, and find the integer μ\mu which satisfies Σr=1μ1fr<u2Σr=1RfrΣr=1μfr\Sigma_{r=1}^{\mu-1} f_r< u_2 \Sigma_{r=1}^{R} f_r \leq \Sigma_{r=1}^{\mu} f_r.

  6. Update according to the type of reaction μ\mu belongs to: if the reaction μ\mu belongs to type ND, update species number n\textbf{n}; if the reaction belongs to type CD, store the time t+τμt+\tau_\mu; if the reaction belongs to type ICD, update species number n\textbf{n} and store the time t+τμt+\tau_\mu. If it is a delay reaction, insert τμ\tau_\mu and the reaction μ\mu into Tstruct, ensuring that the times in Tstruct remain in ascending order.

  7. Set t=t+τt=t+\tau.

  8. Return to step 2 or quit.

Remark. Notice that in the above pseudocode, we modified the Step 4 in the original algorithm for computational efficiency, but both are equivalent. More details are illustrated in [2].

Delay Modified Next Reaction Method Algorithm

Delay Modified Next Reaction Method Algorithm is modified Next Reaction Method to systems with delays. According to [4], if TrT_r is the current internal time of YrY_r, PrP_r the first internal time after TrT_r at which YrY_r fires, and the propensity function for the rr-th reaction channel is given by frf_r, then the time until the next initiation of reaction rr (assuming no other reactions initiate or complete) is still given by Δtr=(1/fr)(PrTr)\Delta t_r = (1/f_r)(P_r − T_r). To each delayed reaction channel we therefore assign a vector, srs_r, that stores the completion times of that reaction in ascending order. Thus, the time until there is a change in the state of the system, be it an initiation or a completion, will be given by

Δ=min{Δtr,sr[1]t}\Delta=\min\{\Delta t_r, s_r[1]-t\}

where tt is the current time of the system.

Algorithm

  1. Initialize. Set t=0t=0 and set species number n=ninitialn= n_\text{initial}. For each rRr \leq R, set Pr=0P_r = 0, Tr=0T_r = 0, and sr=[]s_r = [\infty].

  2. Calculate the propensity function, frf_r, for each reaction.

  3. Generate RR independent, Uniform(0,1)\text{Uniform}(0,1) random numbers, uru_r, and set Pr=ln(ur)P_r = -\ln(u_r).

  4. Set τr=(PrTr)/fr\tau_r = (P_r − T_r)/f_r.

  5. Set τ=minr{τr,sr[1]t}\tau = \min_r \{ \tau_r , s_r[1]-t \}.

  6. Set t=t+τt = t + \tau.

  7. If choose the completion of the delayed reaction μ\mu:

    • Update species number nn based upon the completion of the reaction μ\mu.

    • Delete the first element of SμS_\mu.

  8. Elseif reaction μ\mu initiated and μND\mu\in \text{ND}

    • Update species number nn according to reaction μ\mu.
  9. Elseif reaction μ\mu initiated and μCD\mu\in \text{CD}

    • Update sμs_\mu by inserting t+τμt + \tau_\mu into sμs_\mu ensuring that the times in sμs_\mu remain in ascending order.
  10. Elseif reaction μ\mu initiated and μICD\mu\in \text{ICD}

    • Update species number nn based upon the initiation of reaction μ\mu.

    • Update sμs_\mu by inserting t+τμt + \tau_\mu into sμs_\mu ensuring that the times in sμs_\mu remain in ascending order.

  11. For each r, set Tr=Tr+frτT_r = T_r + f_r \tau.

  12. If reaction μ\mu initiated, let uu' be Uniform(0,1)\text{Uniform}(0,1) and set Pμ=Pμln(u)P_\mu = P_\mu - \ln(u').

  13. Recalculate the propensity functions, frf_r.

  14. Return to step 4 or quit.

Delay Rejection Method Algorithm

Based upon the non-delay algorithm, we see that simulation methods for systems with delays need to calculate when reactions initiate and store when they complete. However, because of the delayed reactions, the propensity functions can change between initiation times. [3] used an algorithm for computing the initiation times that is exactly like the original Gillespie Algorithm except that if there is a stored delayed reaction set to finish within a computed timestep, then the computed timestep is discarded, and the system is updated to incorporate the stored delayed reaction. The algorithm then attempts another step starting at its new state. This algorithm will be referred to as the Rejection Method.

Algorithm

  1. Initialize. Set t=0t = 0 and set species number n=ninitialn= n_\text{initial}.

  2. Calculate propensity functions fr(t),r=1,,Rf_r(t), r=1, \ldots,R.

  3. Generate u1u_1 from a Uniform(0,1) random variable, and set τ=ln(u1)/Σr=1Rfr\tau = -\ln(u_1)/\Sigma_{r=1}^{R} f_r.

  4. If there is a delayed reaction to finish in [t,t+τ)[t,t+\tau)

    • Discard τ\tau.
    • Update tt to be the time of the first next delayed reaction and update the species number.
    • Return to step 2 or quit
  5. Else if there is no delayed reaction in [t,t+τ)[t,t+\tau).

    • Generate u2u_2 from a Uniform(0,1) random variable, and find the integer μ\mu which satisfies Σr=1μ1fr<u2Σr=1RfrΣr=1μfr\Sigma_{r=1}^{\mu-1} f_r< u_2 \Sigma_{r=1}^{R} f_r \leq \Sigma_{r=1}^{\mu} f_r.
  6. Update according to the type of reaction μ\mu belongs to: if the reaction μ\mu belongs to type ND, update species number n\textbf{n}; if the reaction belongs to type CD, store the time t+τμt+\tau_\mu; if the reaction belongs to type ICD, update species number n\textbf{n} and store the time t+τμt+\tau_\mu.

  7. Set the time t=t+τt= t+\tau.

  8. Return to step 2 or quit.

Gillespie Algorithm

Consider a system of NN chemical species with RR ongoing chemical reactions, each of which has a corresponding tendency function fr(n)f_r(n). The Gillespie algorithm assumes that the time from start to finish for each reaction is negligible. Through random simulations, calculate 1) how much time will pass before the next reaction occurs (i.e. starts and finishes), and 2) which reaction will occur at that future point in time. The following assumptions, sometimes referred to as the basic premises of chemical dynamics, are based on physical principles and serve as the underlying assumptions for methods of simulating chemical reaction systems [1]:

fr(n(t))dt=the probability that reaction r takes place in a small time interval [t,t+dt)f_r(n(t)) dt = \text{the probability that reaction r takes place in a small time interval} ~[t, t + dt)

Based on this fundamental assumptions, τ\tau and μ\mu are two independent random variables and following the probability density functions as:

p(τn,t)=λ(n,t)exp(τλ(n,t)),  λ=r=1Rfr(n,t)p(\tau|n,t)=\lambda(n,t) \exp(-\tau \lambda(n,t)), ~~\lambda=\sum_{r=1}^{R} f_r(n,t) p(μn,t)=fr(n,t)/λ(n,t).p(\mu|n,t)=f_r(n,t)/\lambda(n,t) .

According this two equations, τ\tau and μ\mu can be generated as,

τ=ln(u1)/λ(n,t),\tau=-\ln(u_1)/\lambda(n,t) , μ=the integer satisfies r=1μ1fr(n,t)<u2λ(n,t)r=1μfr(n,t),\mu=\text{the integer satisfies $\sum_{r=1}^{\mu-1} f_r(n,t)< u_2 \lambda(n,t) \leq \sum_{r=1}^{\mu} f_r(n,t)$} ,

where u1,u2Uniform(0,1)u_1,u_2\sim \text{Uniform}(0,1) respectively.

Algorithm

  1. Initialize. Set t=0t = 0 and set species number n=ninitialn= n_\text{initial}.

  2. Calculate the propensity function, frf_r, for each reaction.

  3. Generate two independent, Uniform (0,1)(0,1) random numbers, u1u_1 and u2u_2.

  4. Set τ=ln(u1)/Σr=1Rfr\tau = -\ln(u_1)/\Sigma_{r=1}^{R} f_r.

  5. Find the integer μ\mu which satisfies Σr=1μ1fr<u2Σr=1RfrΣr=1μfr\Sigma_{r=1}^{\mu-1} f_r< u_2 \Sigma_{r=1}^{R} f_r \leq \Sigma_{r=1}^{\mu} f_r.

  6. Set t=t+τt = t + \tau.

  7. Update species number nn based upon the completion of the reaction μ\mu.

  8. Return to step 2 or quit.

The Next Reaction Method Algorithm

Let vrv_r, vrN0Nv'_r\in N{\geq 0}^N be the vectors representing the number of each species consumed and created in the rth reaction, respectively. Then, if Nr(t)N_r(t) is the number of initiations of reaction rr by time tt, the state of the system at time tt is

n(t)=n(0)+r=1RNr(t)(vrvr).n(t)=n(0)+\sum_{r=1}^R{N_r(t)(v'_r-v_r)}.

However, based upon the fundamental assumption of stochastic chemical kinetics, Nr(t)N_r(t) is a counting process with intensity fr(n(t))f_r(n(t)) such that p(Nk(t+Δt)Nk(t)=1)=fr(n(t))Δtp(N_k(t+\Delta t)-N_k(t)=1)=f_r(n(t))\Delta t, for small Δt\Delta t. Therefore, we have

Nr(t)=Yr(0tfr(n(s))ds),N_r(t)=Y_r\Big(\int^t_0f_r(n(s))ds\Big),

where the YrY_r are independent, unit rate Poisson processes.

Each Poisson process YrY_r brings its own time frame. If we define Tr(t)=0tfr(n(s))dsT_r(t)=\int^t_0f_r(n(s))ds for each rr, then it is relevant for us to consider Yr(Tr(t))Y_r(T_r(t)). We will call Tr(t)T_r(t) the "internal time" for reaction rr.

Δtr\Delta t_r notes the gap time which the rth reaction needs. Δ=minrΔtr\Delta=\min_r { \Delta t_r }. For the moment we denote t=t+Δ\overline{t} = t +\Delta and the updated propensity functions by fr\overline{f_r}.

The internal time of the next firing of YrY_r has not changed and is still given by Tr(t)+frΔtrT_r(t) + f_r \Delta t_r. We also know that the updated internal time of YrY_r is given by Tr(t)=Tr(t)+frΔT_r(\overline{t}) =T_r(t)+ f_r \Delta . Therefore, the amount of internal time that must pass before the rth reaction fires is given as the difference:

(Tr(t)+frΔtr)(Tr(t)+frΔ)=fr(ΔtrΔ).(T_r(t) + f_r \Delta t_r) − (T_r(t)+ f_r \Delta ) = f_r(\Delta t_r − \Delta).

Thus, the amount of absolute time that must pass before the rth reaction channel fires, Δtr\Delta\overline{t}_r, is given as the solution to frΔtr=fr(ΔtrΔ)\overline{f_r}\Delta \overline{t}_r = f_r(\Delta t_r − \Delta), and we can get:

τr=fr/fr(ΔtrΔ)+t=fr/fr((t+Δtr)(t+Δ))+t=fr/fr(τrt)+t\overline{\tau_r} = f_r / \overline{f_r} (\Delta t_r − \Delta) + \overline{t} = f_r / \overline{f_r} ((t+\Delta t_r )− (t+\Delta)) + \overline{t} = f_r / \overline{f_r} (\tau_r − \overline{t}) + \overline{t}

We have therefore found the absolute times of the next firings of reactions r=µr = µ without having to generate any new random numbers.

Note that after the first timestep is taken in the Next Reaction Method, all subsequent timesteps only demand one random number to be generated. The Next Reaction Method developed with the notion of a dependency graph and a priority queue in order to increase computational efficiency [6]. This is similar with random numbers needed for each step of the original Gillespie Algorithm.

Algorithm

  1. Initialize. Set t=0t=0 and set species number n=ninitialn= n_\text{initial}.

  2. Calculate the propensity function, frf_r, for each reaction.

  3. Generate RR independent, Uniform(0,1)\text{Uniform}(0,1) random numbers, uru_r.

  4. set τr=ln(ur)/fr\tau_r = -\ln(u_r)/ f_r.

  5. Set t=minr{τr}t = \min_r \{ \tau_r \}. Here we assume that τμ\tau_\mu is the minimum.

  6. Update species number nn based upon the completion of the reaction μ\mu.

  7. Recalculate the propensity function, fr\overline{f_r}, for each reaction.

  8. For each rμr \neq \mu, set τr=(fr/fr)(τrt)+t\tau_r=(f_r/\overline{f_r})(\tau_r-t)+t.

  9. For reaction μ\mu, let uu' be Uniform (0,1)(0,1) and set τμ=ln(u)/fμ+t\tau_\mu=-\ln(u')/\overline{f_ \mu}+t. If τr\tau_r is either NANA or InfInf, it also needs to be recalculated in this manner.

  10. For each rr, set fr=frf_r = \overline{f_r}.

  11. Return to step 5 or quit.

Modified Next Reaction Method Algorithm

According to [4], Modified Next Reaction Method Algorithm that is completely equivalent to Next Reaction Method Algorithm. But makes more explicit use of the internal times TrT_r. The main idea of this algorithm is Δtr=(1/fr)(PrTr)\Delta t_r = (1/f_r)(P_r − T_r).

Algorithm

  1. Initialize. Set t=0t = 0 and set species number n=ninitialn= n_\text{initial}. For each rRr\leq R, set Pr=0P_r = 0 and Tr=0T_r = 0.

  2. Calculate the propensity function, frf_r, for each reaction.

  3. Generate RR independent, Uniform (0,1)(0,1) random numbers, uru_r, and set Pr=ln(ur)P_r = -\ln(u_r).

  4. Set τr=(PrTr)/fr\tau_r = (P_r − T_r)/f_r.

  5. Set τ=minr{τr}\tau = \min_r \{ \tau_r \}. Here we assume that τμ\tau_\mu is the minimum.

  6. Set t=t+τt = t + \tau. And update species number nn based upon the completion of the reaction μ\mu.

  7. For each rr, set Tr=Tr+frτT_r = T_r+f_r\tau.

  8. For reaction μ\mu, let uu' be Uniform (0,1)(0,1) and set Pμ=Pμln(u)P_\mu = P_\mu - \ln(u').

  9. Recalculate the propensity function, frf_r, for each reaction.

  10. Return to step 4 or quit.

References

[1]Gillespie, D. T. (1977). Exact stochastic simulation of coupled chemical reactions. The journal of physical chemistry, 81(25), 2340-2361.

[2] Cai, X. (2007). Exact stochastic simulation of coupled chemical reactions with delays. The Journal of chemical physics, 126(12).

[3] Barrio, M., Burrage, K., Leier, A., & Tian, T. (2006). Oscillatory regulation of Hes1: discrete stochastic delay modelling and simulation. PLoS computational biology, 2(9), e117.

[4] Anderson, D. F. (2007). A modified next reaction method for simulating chemical systems with time dependent propensities and delays. The Journal of chemical physics, 127(21).

[5] Van Kampen, N. G. (1992). Stochastic processes in physics and chemistry (Vol. 1). Elsevier.

[6] Gibson, M. A., & Bruck, J. (2000). Efficient exact stochastic simulation of chemical systems with many species and many channels. The journal of physical chemistry A, 104(9), 1876-1889.