Generate Poisson Arrival in Java

感情迁移 提交于 2019-12-03 21:15:16

You can use this algorithm proposed by D. Knuth:

private static int getPoissonRandom(double mean) {
    Random r = new Random();
    double L = Math.exp(-mean);
    int k = 0;
    double p = 1.0;
    do {
        p = p * r.nextDouble();
        k++;
    } while (p > L);
    return k - 1;
}

To understand how this works note that after k iterations the loop condition becomes

p1 * p2 * ... * pk > L

which is equivalent to

-ln(p1)/mean -ln(p2)/mean ... -ln(pk)/mean > 1

Note that if p is uniformly distributed then -ln(p)/mean has exponential distribution with a given mean. A random variable with Poisson distribution is equal to the number of times a given event occurs within a fixed interval when the lengths of the intervals between events are independent random variables with exponential distribution. Since we use the mean of the Poisson distribution as the mean of the exponential distribution for the intervals between events, the fixed internal in which we count occurrences is unit length. Thus, the loop condition sums up the lengths of the intervals between events and checks whether we have gone beyond the unit interval. If we have gone beyond the unit interval while counting kth event, then k-1 events occurred within the interval and so we return k-1.

I found this solution, using inverse transform sampling:

http://preshing.com/20111007/how-to-generate-random-timings-for-a-poisson-process

It doesn't use a rejection sampling approach, is efficient and accurate.

It uses the fact that the distribution of the time between events is an exponential distribution, with parameter lambda which is the arrival rate. The Exponential distribution is lambda exp(-lambda x). In order to sample values from that distribution and avoid rejection sampling, it is easier to use its Cumulative Distribution Function (CDF): 1 - exp(-lambda x). The CDF is a function that starts at 0.0 and grows to 1.0 with larget parameters. Intuitively, the probability that you will get an event increases as time passes.

To sample the CDF, and again avoid rejection sampling, it is easier to pick a uniform random number U between [0,1] and to plug that value in the inverse function of the CDF, which gives: nextEvent = - Ln(U)/lambda. Because Ln(0) is undefined, and most random number generators include 0.0 and exclude 1.0, it is safer to use: nextEvent = -Ln(1.0-U)/lambda. If your code uses a millisecond based time/sleep function you can use:

double rate = 20.0/1000.0; // 20 per second on average

sleep(floor(-1.0 * log(1.0 - rand()*1.0/RAND_MAX) / rate) );

Here's some simplified code to generate a poisson number with a given mean:

private static int poisson(double mean) {
    int r = 0;
    double a = random.nextDouble();
    double p = Math.exp(-mean);

    while (a > p) {
        r++;
        a = a - p;
        p = p * mean / r;
    }
    return r;
}

You should be able to use this or something similar to generate your arrival numbers for each time period: the input should be the mean number of arrivals you expect in the period.

Note that if your mean is very large (say 500+) you will want to approximate the number of arrivals with a normal distribution instead. This is more efficient, plus it avoid numerical overflow issues inherent in the code above (at some point Math.exp(-mean) gets rounded to zero......ooops!)

you can add this to build.gradle

implementation 'org.kie.modules:org-apache-commons-math:6.5.0.Final'

and use class PoissonDistribution more detail

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!