We will first simulate a homogeneous Poisson process. This is fairly simple. It proceeds as follows:
Step 1. Take the pdf (probability density function) of the time between events (where
Step 2. Find the associated cdf (cumulative distribution function).
Step 3. Find the inverse of the cdf.
Step 4. Generate a random, uniformly distributed number
Step 5. Use the inverse cdf to get a corresponding time since last event.
Step 6. Repeat 4. and 5. until a sufficient number of interarrival times have been generated.
This process will yield a sequence of time between events, which can be converted into arrival times or total counts.
import numpy as np
import matplotlib.pyplot as plt# Play with these parametres to alter the rate time and number of simulated events.
_lambda = 2
n = 10
# Do the simulation.
U = np.random.uniform(0,1,n)
interarrival_times = -np.log(U)/_lambda
arrival_times = np.cumsum(interarrival_times)
counts = np.arange(n)+1
# Plot the results.
plt.step(arrival_times, counts)
plt.title("Simulation of Homogeneous Poisson Process")
plt.xlabel("Time")
plt.ylabel("Event count")
plt.show()The process is easy enough for a homogeneous Poisson process, but when the intensity
Instead of sampling directly from the inhomogeneous process, we will sample from a homogeneous Poisson process with
The trick is to generate another random, uniformly distributed number
For this example, we will assume
def lambda_t(t, beta=1., alpha=0.5):
return beta*np.sin(alpha*t)+np.abs(beta)# Play with these parametres to alter the rate time and number of simulated events.
beta = 1.
alpha = 0.5
# We need to choose lambda to be greater than lambda_t at all times
_lambda = 2*beta
n = 10
# Sample from homogeneous Poisson process.
U = np.random.uniform(0,1,n)
interarrival_times = -np.log(U)/_lambda
arrival_times = np.cumsum(interarrival_times)
# Do rejection sampling.
thresholds = lambda_t(arrival_times)/_lambda
U_1 = np.random.uniform(0,1,n)
keep = U_1<thresholds
arrival_times = arrival_times[keep]
counts = np.arange(len(arrival_times))+1
# Plot the results.
plt.step(arrival_times, counts)
plt.title("Simulation of Inhomogeneous Poisson Process")
plt.xlabel("Time")
plt.ylabel("Event count")
plt.show()Hawkes processes are a generalisation of Poisson processes that allow past events to increase the intensity. The method of simulation is conceptually the same as for an inhomogeneous Poisson process, but we now need to account for a more complex intensity,
The reason we need to be more careful about sampling is that for any given
The general procedure will be to restrict our samples to certain time frames (rejecting sampled times outside of it) in order to allow us to calculate
For the first example, we will use an exponentially decaying
We can take advantage of the fact that, in the time just after an event and just before the next event,
For this specific example, do not need to restrict each point simulation to a specific interval as our conditional intensity possesses proporties which allow us to choose
def lambda_t(cur_time, hist, base_rate=2., alpha=20, beta=1.):
if len(hist)==0:
return base_rate
else:
hist = np.cumsum(hist)
exp_arg = -beta*(cur_time-hist)
intensity = base_rate + np.sum(alpha*beta*np.exp(exp_arg))
return intensity# Play around with these parameters.
base_rate = 2
N = 100
alpha = 2.
beta = 1.
# Simulate the process.
hist = np.array([])
time = 0
n=0
while n < N:
_lambda = lambda_t(time, hist, base_rate, alpha, beta)
U = np.random.uniform()
interarrival_time = -np.log(U)/_lambda
_lambda_hist = lambda_t(interarrival_time, hist, base_rate, alpha, beta)
if np.random.uniform()<_lambda_hist/_lambda:
hist = np.append(hist, interarrival_time)
time += interarrival_time
n+=1
hist = np.cumsum(hist)
counts = np.arange(len(hist))+1
# Plot the results.
plt.step(hist, counts)
plt.title("Simulation of Hawkes Process (Example 1)")
plt.xlabel("Time")
plt.ylabel("Event count")
plt.show()For the second example, we will use an exponentially increasing
In this example, for a fixed interval
in each interval.
We now need to restrict simulated arrival times to the interval we are operating in, as
Note: if you're following along with Ogata's paper, be aware that algorithm 3, step 8 should include "set j = j+1" and "if $ j = N_{*}^{i} $ , go to step 11".
# Loop version of homogeneous Poisson process simulation
def homog_Poisson(rate, T):
t = 0
arrival_times = []
while t<T:
U = np.random.uniform()
interarrival_time = -np.log(U)/rate
t+=interarrival_time
if t<T:
arrival_times.append(t)
return np.array(arrival_times)base_rate = 2.
delta_time = (1/base_rate)/10
cur_time = 0
hist = np.array([])
n = 20
max_time = 10
while len(hist)<n:
# Set rate for homogeneous Poisson process and get arrival times for
# current time interval
_lambda = lambda_t(cur_time+delta_time, hist, base_rate, alpha, beta)
arrival_times = homog_Poisson(_lambda, delta_time) + cur_time
if len(arrival_times)==0:
cur_time+=delta_time
for j in range(len(arrival_times)):
U_j = np.random.uniform()
lambda_hist = lambda_t(arrival_times[j], hist, base_rate, alpha, beta)
threshold = lambda_hist/_lambda
if U_j<threshold:
hist = np.append(hist, arrival_times[j])
cur_time+=delta_time
if cur_time>max_time:
break
counts = np.arange(len(hist))
# Plot the results.
plt.step(hist, counts)
plt.title("Simulation of Hawkes Process (Example 2)")
plt.xlabel("Time")
plt.ylabel("Event count")
plt.show()