If you were to write from scratch a program that simulates a homogeneous Poisson point process, the trickiest part would be the random number of points, which requires simulating a Poisson random variable. In previous posts, such as this one and this one, I’ve simply used the inbuilt functions for simulating (or generating) Poisson random variables (or variates).1In the literature, researchers describe methods for generating random deviates or variates. But, in my informal way, I will often say simulate random variables or generate random variates, somewhat interchangeably.
But how would one create such a Poisson function using just a standard uniform random variate generator? In this post I will write my own Poisson simulation code in MATLAB, Python, C and C#, which can be found here.
The method being used depends on the value of the Poisson parameter, denoted here by \(\lambda\), which is the mean (as well as the variance) of a random variable with a Poisson distribution. If this parameter value is small, then a direct simulation method can be used to generate Poisson random variates. In practice a small Poisson parameter is a number less than some number between 10 to 30.
For large \(\lambda\) values, other methods are generally used, such as rejection or (highly accurate) approximation methods. In the book Non-uniform random variate generation, the author Luc Devroye groups the methods into five categories (Section X.3.2), which I briefly describe in the next post. The first of those categories covers the method that I mentioned above. I will cover that method in this post, presenting some Poisson sampling code in C and C#. (I will also present some code in MATLAB, but you would never use it instead of the the inbuilt function poissrnd.)
In the next post, I’ll describe other types of Poisson simulation methods, and I’ll detail which simulation methods various programming libraries use.
Warning: My online webpage editor tends to mangle symbols like < and >, so it’s best not to copy my code straight from the website, unless you check and edit it.
Direct method
An elegant and natural method for simulating Poisson variates is to a result based on the homogeneous Poisson stochastic process. The points in time when a given homogeneous Poisson stochastic process increases forms a Poisson point process on the real line. 2Confusingly, the term Poisson process is often used to refer to both the stochastic process and the point process, but there is a slight difference.
Using exponential random variables
Here’s the algorithm for sampling Poisson variables with exponential random variables, which I’ll explain.
Sample Poisson random variable \(N\) with parameter (mean) \(\lambda\) using exponential random variables
- Set count variable \(N=0\) and initial sum variable \(S=0\);
- While \(S<1\):
- Sample uniform random variable \(U\sim U(0,1)\);
- Calculate \(E= -\log(U)/\lambda \) ;
- Update count and sum variables by setting \(N\rightarrow N+1\) and \(S\rightarrow S+E\);
- Return N;
The point in time when the Poisson stochastic process increases are called arrival times or occurrence times. In classic random models they represent the arrivals or occurrences of something, such as phone calls over time. The differences between consecutive times are called inter-arrival times or inter-occurrence times. The inter-arrival times of a homogeneous Poisson process form independent exponential random variables, a result known as the Interval Theorem.
Using this connection to the Poisson stochastic process, we can generate exponential variables \(E_1\), \(E_2, \dots \), and add them up. The smallest number of exponential variables for the resulting sum to exceeds one will give a Poisson random variable. That is, if we define \(N\) to be the smallest \(n\) such that
$$ \sum_{k=1}^{n+1} E_k > 1, $$
then \(N\) is a random variable distributed according to a Poisson distribution.
Generating exponential variates is easily done by using the inverse method. For a uniform random variable \(U\) on the unit interval \((0,1)\), the transformation \(E= -\log(U)/\lambda \) gives an exponential random variable with mean \(1/\lambda\).
But we can skip generating exponential random variates.
Using uniform random variables
Here’s the algorithm for sampling Poisson variables with uniform random variables.
Sample Poisson random variable \(N\) with parameter (mean) \(\lambda\) using uniform random variables
- Set count variable \(N=0\) and initial product variable \(P=1\);
- While \(P>e^{-\lambda}\):
- Sample uniform random variable \(U\sim U(0,1)\);
- Update count and product variables by setting \(N\rightarrow N+1\) and \(P\rightarrow P\times U\);
- Return N;
To reduce computations, the direct method using exponential random variables is often reformulated as products of uniform random variables. We can do this, due to logarithmic identities, and work with products of uniform variables instead of sums of exponential random variables.
Then, by using standard uniform random variables \(U_1, U_2,\dots\), we define \(N\) to be the smallest \(n\) such that
$$ \prod_{k=1}^{n+1} U_k < e^{-\lambda}. $$
These two different formulations of the same method are captured by Lemma 3.2 and Lemma 3.3 in Chapter 10 of Devroye’s book.
Example in MATLAB
In MATLAB, we can implement this method with the first formulation in a function with a simple while-loop:
function N=funPoissonLoop(lambda) T=0; %initialize sum of exponential variables as zero n=-1;%initialize counting variable as negative one while (T <1) E=-(1/lambda)*log(rand(1));%generate exponential random variable T=T+E; %update sum of exponential variables n=n+1; %update number of exponential variables end N=n; end
But, as I said before, don’t use this code instead of the inbuilt function poissrnd.
If you want to be a bit more tricky, you could achieve the same result by using recursion:
function N=funPoissonRecursive(lambda) T=0; %initialize sum of exponential variables as zero n=-1; %initialize counting variable as negative one %run (recursive) exponential function step function [~,N]=funStepExp(lambda,T,n); function [T,N]=funStepExp(nu,S,m) if (S < 1) %run if sum of exponential variables is not high enough %generate exponential random variable E=(-log(rand(1)))/nu; S=S+E; %update sum of exponential variables m=m+1; %update nunber of exponential variables %recursively call function again [T,N]=funStepExp(nu,S,m); else T=S; N=m; end end end
Note how the code recursively calls the function funStepExp, which generates an exponential variable each time.
In the Code section below I describe my code in C and C#, using the second formulation.
Origins
Some people attribute the direct method, based on inter-arrival times, to (or, at least, cite) Donald Knuth, who details it in the second volume of his classic series of books, but I doubt that the great Knuth was the first to have this idea. For example, a quick search on Google Scholar found a paper by K. D. Tocher on computers and random sampling, where Tocher proposes the direct method in 1954, some years before Knuth started publishing his classic series.
The direct method for Poisson sampling relies upon the Interval theorem. The Poisson point process expert Günter Last studied the origins of this fundamental result. He presented its history in a recent book authored by him and Matthew Penrose; see Chapter 7 and its corresponding historical footnotes in Section C of the appendix. (A free version of the book can be found here. ) People connected to the result include Robert Ellis and William Feller.
Other methods
The direct method perfectly generates Poisson random variables (or I should say Poisson random variates). But it can be too slow for large values of the Poisson parameter (that, is the mean) \(\lambda\). This has motivated researchers to develop other methods, which I will mention in the next post.
Code
I wrote some code that simulates Poisson random variables by employing the direct method based on exponential inter-arrival times. As always, all my the code is online, with the code from this post being located here.
I have implemented the second formulation (using just uniform variables) in the C and C# languages. In the code, I have used a while-loop to implement the method. But I could have also used a recursion method, as I did in the MATLAB example above, which I have also done in Python (with NumPy).
For an empirical test, the code also calculates the mean and variance of a collection of Poisson variables. For a large enough number of variables, the sample mean and the variance will closely agree with each other, converging to the same value.
C
Warning: My C code uses rand(), the standard pseudo-random number function in C, which is known for failing certain tests of randomness. The function is adequate for regular simulation work. But it gives poor results for large number of simulations. Replace this function with another pseudo-random number generator.
The code for generating a single Poisson variate is fairly straightforward in C. Here’s a sample of the code with just the Poisson function:
//Poisson function -- returns a single Poisson random variable int funPoissonSingle(double lambda) { double exp_lambda = exp(-lambda); //constant for terminating loop double randUni; //uniform variable double prodUni; //product of uniform variables int randPoisson; //Poisson variable //initialize variables randPoisson = -1; prodUni = 1; do { randUni = funUniformSingle(); //generate uniform variable prodUni = prodUni * randUni; //update product randPoisson++; //increase Poisson variable } while (prodUni > exp_lambda); return randPoisson; }
For generating multiple variates, the code becomes more complicated, as one needs to use pointers, due to the memory capabilities of C. Again, the function uses the pseudo-random number generator in C.
C#
The code for generating a single Poisson variate is also straightforward in C#. Here’s the function in C#:
//Poisson function -- returns a single Poisson random variable public int funPoissonSingle (double lambda) { double exp_lambda = Math.Exp (-lambda); //constant for terminating loop double randUni; //uniform variable double prodUni; //product of uniform variables int randPoisson; //Poisson variable //initialize variables randPoisson = -1; prodUni = 1; do { randUni = funUniformSingle (); //generate uniform variable prodUni = prodUni * randUni; //update product randPoisson++; // increase Poisson variable } while (prodUni > exp_lambda); return randPoisson; }
Generalizing the code so it generates multiple variates just requires a little change, compared to C, as the C# language is a much more modern language.
Fortran
After this original post, I later wrote a post about implementing the same Poisson algorithm in Fortran. My Fortran code is very similar to the code that I wrote in C and C#. You should be able to run it on this website or similar ones that can compile Fortran (95) code.
Further reading
For various Poisson simulation methods, see the stochastic simulation books by Devroye (Section X.3) or Fishman (Section 8.16). There’s a free online version of Devroye’s book here. The book by Gentle (Section 5.2.8) also briefly covers Poisson variables.
In this post on generating Poisson variates, John D. Cook briefly discusses the direct method for small \(\lambda\) values and a rejection method from a 1979 paper by Atkinson, which I will mention in the next post. He presents his C# sharp code in this post.