Synthia
Generic and flexible data structure generator
PoissonInteger.java
Go to the documentation of this file.
1 /*
2  Synthia, a data structure generator
3  Copyright (C) 2019-2020 Laboratoire d'informatique formelle
4  Université du Québec à Chicoutimi, Canada
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 package ca.uqac.lif.synthia.random;
20 
21 import ca.uqac.lif.synthia.Reactive;
22 
23 /**
24  * Generates integer numbers following a Poisson distribution.
25  * The <a href="https://en.wikipedia.org/wiki/Poisson_distribution">Poisson
26  * distribution</a> is a discrete probability distribution that expresses
27  * the probability of a given number of events occurring in a fixed interval
28  * of time or space if these events occur with a known constant rate and
29  * independently of the time since the last event.
30  * The distribution is parameterized by a value, &lambda;, which
31  * expresses the probability of occurrence of an event in a given time
32  * interval. The probability of generating a nonnegative integer <i>k</i> is
33  * &lambda;<sup><i>k</i></sup><i>e</i><sup>-&lambda;</sup>/<i>k</i>!.
34  * <p>
35  * The class uses two algorithms for generating Poisson integers, depending
36  * on the value of &lambda;. For small values (&le; 30), a simple algorithm
37  * attributed to Knuth is used. For larger values (&gt; 30), it uses an
38  * algorithm described by
39  * <a href="https://www.johndcook.com/blog/2010/06/14/generating-poisson-random-values/">John
40  * D. Cook</a>.
41  *
42  * @ingroup API
43  */
44 public class PoissonInteger extends RandomPicker<Integer> implements Reactive<Number,Integer>
45 {
46  /**
47  * The &lambda; parameter of the underlying Poisson distribution
48  */
49  protected float m_lambda;
50 
51  /**
52  * Value of constant <i>c</i> in Cook's algorithm
53  */
54  protected double m_c;
55 
56  /**
57  * Value of constant &alpha; in Cook's algorithm
58  */
59  protected double m_alpha;
60 
61  /**
62  * Value of constant &beta; in Cook's algorithm
63  */
64  protected double m_beta;
65 
66  /**
67  * Value of constant <i>c</i> in Cook's algorithm
68  */
69  protected double m_k;
70 
71  /**
72  * Maximum number of iterations in Cook's algorithm. The original
73  * implementation is <em>theoretically</em> unbounded; this parameter
74  * makes sure that it ends after a maximum number of iterations.
75  */
76  protected static final transient int s_maxIterations = 10000;
77 
78  /**
79  * Creates a new instance of the picker
80  * @param lambda The &lambda; parameter of the underlying Poisson
81  * distribution
82  */
83  public PoissonInteger(/*@ non_null @*/ Number lambda)
84  {
85  super();
86  tell(lambda);
87  }
88 
89  /**
90  * Creates a new instance of the picker, with pre-computed values for the
91  * constants in Cook's algorithm.
92  * @param lambda The &lambda; parameter of the underlying Poisson
93  * distribution
94  * @param c Value of constant <i>c</i> in Cook's algorithm
95  * @param alpha Value of constant &alpha; in Cook's algorithm
96  * @param beta Value of constant &beta; in Cook's algorithm
97  * @param k Value of constant <i>k</i> in Cook's algorithm
98  */
99  protected PoissonInteger(float lambda, double c, double alpha, double beta, double k)
100  {
101  super();
102  m_lambda = lambda;
103  m_c = c;
104  m_alpha = alpha;
105  m_beta = beta;
106  m_k = k;
107  }
108 
109  /**
110  * Modifies the parameter &lambda; associated to this picker.
111  * @param lambda The new parameter &lambda;
112  */
113  @Override
114  public void tell(Number lambda)
115  {
116  m_lambda = lambda.floatValue();
117  m_c = 0.767 - 3.36/ m_lambda;
118  m_beta = Math.PI / Math.sqrt(3 * m_lambda);
119  m_alpha = m_beta * m_lambda;
120  m_k = Math.log(m_c) - m_lambda - Math.log(m_beta);
121  }
122 
123  @Override
124  public Integer pick()
125  {
126  if (m_lambda < 30)
127  {
128  return smallPoisson();
129  }
130  return bigPoisson();
131  }
132 
133  /**
134  * Generates a Poisson integer using Knuth's algorithm, which is efficient
135  * for small values of &lambda;
136  * @return A Poisson integer
137  */
138  protected int smallPoisson()
139  {
140  double L = Math.exp(-m_lambda);
141  int k = 0;
142  double p = 1;
143  do
144  {
145  k++;
146  double u = m_random.nextDouble();
147  p *= u;
148  } while (p > L);
149  return k - 1;
150  }
151 
152  /**
153  * Generates a Poisson integer using Cook's algorithm, which is efficient
154  * for larger values of &lambda;
155  * @return A Poisson integer
156  */
157  protected int bigPoisson()
158  {
159  for (int i = 0; i < s_maxIterations; i++)
160  {
161  double u = m_random.nextDouble();
162  double x = (m_alpha - (Math.log(1 - u) / u)) / m_beta;
163  long n = (long) Math.floor(x + 0.5);
164  if (n < 0)
165  {
166  continue;
167  }
168  double v = m_random.nextDouble();
169  double y = m_alpha - m_beta * x;
170  double lhs = y + Math.log(v / Math.pow(1 + Math.exp(y), 2));
171  double rhs = m_k + n * Math.log(m_lambda) - Math.log(factorial(n));
172  if (lhs <= rhs)
173  {
174  return (int) n;
175  }
176  }
177  return 0;
178  }
179 
180  @Override
181  public PoissonInteger duplicate(boolean with_state)
182  {
184 
185  gf.m_seed = m_seed;
186  gf.m_random = this.m_random.Duplicate();
187 
188  if (!with_state)
189  {
190  gf.reset();
191  }
192 
193  return gf;
194  }
195 
196  /**
197  * Computes the factorial of a number. This is a very straightforward
198  * implementation that is not expected to be efficient.
199  * @param n The number to calculate the factorial of
200  * @return The factorial of that number
201  */
202  protected static long factorial(long n)
203  {
204  long x = 1;
205  for (long i = n; i > 0; i--)
206  {
207  x *= i;
208  }
209  return x;
210  }
211 }
ca.uqac.lif.synthia.random.Random.nextDouble
double nextDouble()
Returns the next pseudorandom, uniformly distributed.
Definition: Random.java:551
ca.uqac.lif.synthia.random.PoissonInteger.m_lambda
float m_lambda
The λ parameter of the underlying Poisson distribution.
Definition: PoissonInteger.java:49
ca.uqac.lif.synthia.random.PoissonInteger.factorial
static long factorial(long n)
Computes the factorial of a number.
Definition: PoissonInteger.java:202
ca.uqac.lif.synthia.Reactive
Interface implemented by pickers whose picking of objects can be altered by external information.
Definition: Reactive.java:43
ca.uqac.lif.synthia.random.PoissonInteger.tell
void tell(Number lambda)
Modifies the parameter λ associated to this picker.
Definition: PoissonInteger.java:114
ca.uqac.lif.synthia.random.PoissonInteger.PoissonInteger
PoissonInteger(float lambda, double c, double alpha, double beta, double k)
Creates a new instance of the picker, with pre-computed values for the constants in Cook's algorithm.
Definition: PoissonInteger.java:99
ca.uqac
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.random.PoissonInteger.PoissonInteger
PoissonInteger(Number lambda)
Creates a new instance of the picker.
Definition: PoissonInteger.java:83
ca.uqac.lif.synthia.random.PoissonInteger.m_alpha
double m_alpha
Value of constant α in Cook's algorithm.
Definition: PoissonInteger.java:59
ca.uqac.lif.synthia.random.PoissonInteger.pick
Integer pick()
Picks an object.
Definition: PoissonInteger.java:124
ca.uqac.lif
ca.uqac.lif.synthia.random.PoissonInteger.m_beta
double m_beta
Value of constant β in Cook's algorithm.
Definition: PoissonInteger.java:64
ca.uqac.lif.synthia.random.RandomPicker.reset
void reset()
Puts the picker back into its initial state.
Definition: RandomPicker.java:68
ca.uqac.lif.synthia.random.Random.Duplicate
Random Duplicate()
Creates a new instance of the class with the exact same internal states that the original one.
Definition: Random.java:123
ca
ca.uqac.lif.synthia.random.PoissonInteger.m_k
double m_k
Value of constant c in Cook's algorithm.
Definition: PoissonInteger.java:69
ca.uqac.lif.synthia.random.PoissonInteger.s_maxIterations
static final transient int s_maxIterations
Maximum number of iterations in Cook's algorithm.
Definition: PoissonInteger.java:76
ca.uqac.lif.synthia.random.RandomPicker
Picks an object based on the value of a random number generator.
Definition: RandomPicker.java:39
ca.uqac.lif.synthia.random.PoissonInteger.bigPoisson
int bigPoisson()
Generates a Poisson integer using Cook's algorithm, which is efficient for larger values of λ.
Definition: PoissonInteger.java:157
ca.uqac.lif.synthia.random.RandomPicker.m_seed
int m_seed
Definition: RandomPicker.java:49
ca.uqac.lif.synthia.random.PoissonInteger.smallPoisson
int smallPoisson()
Generates a Poisson integer using Knuth's algorithm, which is efficient for small values of λ.
Definition: PoissonInteger.java:138
ca.uqac.lif.synthia.random.RandomPicker< Integer >::m_random
transient Random m_random
Definition: RandomPicker.java:47
ca.uqac.lif.synthia.random.PoissonInteger.m_c
double m_c
Value of constant c in Cook's algorithm.
Definition: PoissonInteger.java:54
ca.uqac.lif.synthia.random.PoissonInteger.duplicate
PoissonInteger duplicate(boolean with_state)
Creates a copy of the picker.
Definition: PoissonInteger.java:181
ca.uqac.lif.synthia.random.PoissonInteger
Generates integer numbers following a Poisson distribution.
Definition: PoissonInteger.java:44