SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
NegativeBinomialDist.java
1/*
2 * Class: NegativeBinomialDist
3 * Description: negative binomial distribution
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.probdist;
26
27import umontreal.ssj.util.*;
28import umontreal.ssj.functions.MathFunction;
29import optimization.*;
30
52public class NegativeBinomialDist extends DiscreteDistributionInt {
53 protected double n;
54 protected double p;
55 private static final double EPS2 = 1000.0 * EPSILON;
56
57 private static class Func1 implements MathFunction {
58 protected int m;
59 protected int[] x;
60 protected double p;
61
62 public Func1(double p, int[] x, int m) {
63 this.p = p;
64 this.m = m;
65 this.x = x;
66 }
67
68 public double evaluate(double gam) {
69 if (gam <= 0)
70 return 1.0e100;
71
72 double sum = 0.0;
73 for (int j = 0; j < m; j++)
74 sum += Num.digamma(gam + x[j]);
75 return sum / m + Math.log(p) - Num.digamma(gam);
76 }
77 }
78
79 private static class Function implements MathFunction {
80 protected int m;
81 protected int max;
82 protected double mean;
83 protected int[] Fj;
84
85 public Function(int m, int max, double mean, int[] Fj) {
86 this.m = m;
87 this.max = max;
88 this.mean = mean;
89 this.Fj = new int[Fj.length];
90 System.arraycopy(Fj, 0, this.Fj, 0, Fj.length);
91 }
92
93 public double evaluate(double s) {
94 // if (s <= 0 ) return 1.0e100;
95 double sum = 0.0;
96 double p = s / (s + mean);
97
98 for (int j = 0; j < max; j++)
99 sum += Fj[j] / (s + (double) j);
100
101 return sum + m * Math.log(p);
102 }
103 }
104
105 private static class FuncInv extends Function implements MathFunction {
106
107 public FuncInv(int m, int max, double mean, int[] Fj) {
108 super(m, max, mean, Fj);
109 }
110
111 public double evaluate(double nu) {
112 double r = nu * mean;
113 double sum = 0.;
114 for (int j = 0; j < max; j++)
115 sum += Fj[j] / (1.0 + nu * j);
116
117 return (nu * sum - m * Math.log1p(r));
118 }
119 }
120
121 /************************
122 * // Class Optim seems to be useless private static class Optim implements
123 * Lmder_fcn { private double mean; private int N; private int max; private int
124 * [] Fj;
125 *
126 * public Optim (int N, int max, double mean, int[] Fj) { this.N = N; this.max =
127 * max; this.mean = mean; this.Fj = new int[max]; System.arraycopy (Fj, 0,
128 * this.Fj, 0, max); }
129 *
130 * public void fcn (int m, int n, double[] x, double[] fvec, double[][] fjac,
131 * int iflag[]) { if (x[1] <= 0.0 || x[2] <= 0.0 || x[2] >= 1.0) { final double
132 * BIG = 1.0e100; fvec[1] = BIG; fvec[2] = BIG; fjac[1][1] = BIG; fjac[1][2] =
133 * 0.0; fjac[2][1] = 0.0; fjac[2][2] = BIG; return; }
134 *
135 * double trig; if (iflag[1] == 1) { double sum = 0.0; for (int j = 0; j < max;
136 * j++) sum += Fj[j] / (x[1] + j); fvec[1] = x[2] * mean - x[1] * (1.0 - x[2]);
137 * fvec[2] = N * Math.log (x[2]) + sum;
138 *
139 * } else if (iflag[1] == 2) {
140 *
141 * fjac[1][1] = x[2] - 1.0; fjac[1][2] = mean + x[1]; double sum = 0.0; for (int
142 * j = 0; j < max; j++) sum += Fj[j] / ((x[1] + j)*(x[1] + j)); fjac[2][1] =
143 * -sum; fjac[2][2] = N / x[2]; } } }
144 ****************************/
145
149
154 public static double MAXN = 100000;
155
159
160 protected NegativeBinomialDist() {
161 }
162
169 public NegativeBinomialDist(double n, double p) {
170 setParams(n, p);
171 }
172
173 public double prob(int x) {
174 if (x < 0)
175 return 0.0;
176
177 if (p == 0.0)
178 return 0.0;
179
180 if (p == 1.0) {
181 if (x > 0)
182 return 0.0;
183 else
184 return 1.0;
185 }
186
187 if (pdf == null)
188 return prob(n, p, x);
189
190 if (x > xmax || x < xmin)
191 return prob(n, p, x);
192
193 return pdf[x - xmin];
194 }
195
196 public double cdf(int x) {
197 if (x < 0)
198 return 0.0;
199 if (p >= 1.0) // In fact, p == 1
200 return 1.0;
201 if (p <= 0.0) // In fact, p == 0
202 return 0.0;
203
204 if (cdf != null) {
205 if (x >= xmax)
206 return 1.0;
207 if (x < xmin)
208 return cdf(n, p, x);
209 if (x <= xmed)
210 return cdf[x - xmin];
211 else
212 // We keep the complementary distribution in the upper part of cdf
213 return 1.0 - cdf[x + 1 - xmin];
214
215 } else
216 return cdf(n, p, x);
217 }
218
219 public double barF(int x) {
220 if (x < 1)
221 return 1.0;
222 if (p >= 1.0) // In fact, p == 1
223 return 0.0;
224 if (p <= 0.0) // In fact, p == 0
225 return 1.0;
226
227 if (cdf == null)
228 // return BinomialDist.cdf (x - 1 + n, p, n - 1);
229 return BetaDist.barF(n, x, p);
230
231 if (x > xmax)
232 // return BinomialDist.cdf (x - 1 + n, p, n - 1);
233 return BetaDist.barF(n, x, p);
234
235 if (x <= xmin)
236 return 1.0;
237 if (x > xmed)
238 // We keep the complementary distribution in the upper part of cdf
239 return cdf[x - xmin];
240 else
241 return 1.0 - cdf[x - 1 - xmin];
242 }
243
244 public int inverseFInt(double u) {
245 if ((cdf == null) || (u <= EPS2))
246 return inverseF(n, p, u);
247 else
248 return super.inverseFInt(u);
249 }
250
251 public double getMean() {
252 return NegativeBinomialDist.getMean(n, p);
253 }
254
255 public double getVariance() {
256 return NegativeBinomialDist.getVariance(n, p);
257 }
258
259 public double getStandardDeviation() {
260 return NegativeBinomialDist.getStandardDeviation(n, p);
261 }
262
267 public static double prob(double n, double p, int x) {
268 final int SLIM = 15; // To avoid overflow
269 final double MAXEXP = (Num.DBL_MAX_EXP - 1) * Num.LN2;// To avoid overflow
270 final double MINEXP = (Num.DBL_MIN_EXP - 1) * Num.LN2;// To avoid underflow
271 double y;
272
273 if (p < 0.0 || p > 1.0)
274 throw new IllegalArgumentException("p not in [0, 1]");
275 if (n <= 0.0)
276 throw new IllegalArgumentException("n <= 0.0");
277 if (x < 0)
278 return 0.0;
279 if (p >= 1.0) { // In fact, p == 1
280 if (x == 0)
281 return 1.0;
282 else
283 return 0.0;
284 }
285 if (p <= 0.0) // In fact, p == 0
286 return 0.0;
287
288 y = Num.lnGamma(n + x) - (Num.lnFactorial(x) + Num.lnGamma(n)) + n * Math.log(p) + x * Math.log1p(-p);
289
290 if (y >= MAXEXP)
291 throw new IllegalArgumentException("term overflow");
292 return Math.exp(y);
293 }
294
298 public static double cdf(double n, double p, int x) {
300 final int LIM1 = 100000;
301 double sum, term, termmode;
302 int i, mode;
303 final double q = 1.0 - p;
304
305 if (p < 0.0 || p > 1.0)
306 throw new IllegalArgumentException("p not in [0, 1]");
307 if (n <= 0.0)
308 throw new IllegalArgumentException("n <= 0.0");
309
310 if (x < 0)
311 return 0.0;
312 if (p >= 1.0) // In fact, p == 1
313 return 1.0;
314 if (p <= 0.0) // In fact, p == 0
315 return 0.0;
316
317 // Compute the maximum term
318 mode = 1 + (int) Math.floor((n * q - 1.0) / p);
319 if (mode < 0)
320 mode = 0;
321 else if (mode > x)
322 mode = x;
323
324 if (mode <= LIM1) {
325 sum = term = termmode = prob(n, p, mode);
326 for (i = mode; i > 0; i--) {
327 term *= i / (q * (n + i - 1.0));
328 if (term < EPSILON)
329 break;
330 sum += term;
331 }
332
333 term = termmode;
334 for (i = mode; i < x; i++) {
335 term *= q * (n + i) / (i + 1);
336 if (term < EPSILON)
337 break;
338 sum += term;
339 }
340 if (sum <= 1.0)
341 return sum;
342 else
343 return 1.0;
344 } else
345 // return 1.0 - BinomialDist.cdf (x + n, p, n - 1);
346 return BetaDist.cdf(n, x + 1.0, p);
347 }
348
353 public static double barF(double n, double p, int x) {
354 return 1.0 - cdf(n, p, x - 1);
355 }
356
360 public static int inverseF(double n, double p, double u) {
361 if (u < 0.0 || u > 1.0)
362 throw new IllegalArgumentException("u is not in [0,1]");
363 if (p < 0.0 || p > 1.0)
364 throw new IllegalArgumentException("p not in [0, 1]");
365 if (n <= 0.0)
366 throw new IllegalArgumentException("n <= 0");
367 if (p >= 1.0) // In fact, p == 1
368 return 0;
369 if (p <= 0.0) // In fact, p == 0
370 return 0;
371 if (u <= prob(n, p, 0))
372 return 0;
373 if (u >= 1.0)
374 return Integer.MAX_VALUE;
375
376 double sum, term, termmode;
377 final double q = 1.0 - p;
378
379 // Compute the maximum term
380 int mode = 1 + (int) Math.floor((n * q - 1.0) / p);
381 if (mode < 0)
382 mode = 0;
383 int i = mode;
384 term = prob(n, p, i);
385 while ((term >= u) && (term > Double.MIN_NORMAL)) {
386 i /= 2;
387 term = prob(n, p, i);
388 }
389
390 if (term <= Double.MIN_NORMAL) {
391 i *= 2;
392 term = prob(n, p, i);
393 while (term >= u && (term > Double.MIN_NORMAL)) {
394 term *= i / (q * (n + i - 1.0));
395 i--;
396 }
397 }
398
399 mode = i;
400 sum = termmode = prob(n, p, i);
401
402 for (i = mode; i > 0; i--) {
403 term *= i / (q * (n + i - 1.0));
404 if (term < EPSILON)
405 break;
406 sum += term;
407 }
408
409 term = termmode;
410 i = mode;
411 double prev = -1;
412 if (sum < u) {
413 // The CDF at the mode is less than u, so we add term to get >= u.
414 while ((sum < u) && (sum > prev)) {
415 term *= q * (n + i) / (i + 1);
416 prev = sum;
417 sum += term;
418 i++;
419 }
420 } else {
421 // The computed CDF is too big so we substract from it.
422 sum -= term;
423 while (sum >= u) {
424 term *= i / (q * (n + i - 1.0));
425 i--;
426 sum -= term;
427 }
428 }
429 return i;
430 }
431
447 public static double[] getMLE(int[] x, int m, double n) {
448 if (m <= 0)
449 throw new IllegalArgumentException("m <= 0");
450 double mean = 0.0;
451 for (int i = 0; i < m; i++) {
452 mean += x[i];
453 }
454 mean /= (double) m;
455 double[] param = new double[1];
456 param[0] = n / (n + mean);
457 return param;
458 }
459
470 public static NegativeBinomialDist getInstanceFromMLE(int[] x, int m, double n) {
471 double parameters[] = getMLE(x, m, n);
472 return new NegativeBinomialDist(n, parameters[0]);
473 }
474
491 public static double[] getMLE1(int[] x, int m, double p) {
492 if (m <= 0)
493 throw new IllegalArgumentException("m <= 0");
494 double mean = 0.0;
495 for (int i = 0; i < m; i++)
496 mean += x[i];
497 mean /= m;
498
499 double gam0 = mean * p / (1.0 - p);
500 double[] param = new double[1];
501 Func1 f = new Func1(p, x, m);
502 param[0] = RootFinder.brentDekker(gam0 / 100.0, 100.0 * gam0, f, 1e-5);
503 return param;
504 }
505
516 public static NegativeBinomialDist getInstanceFromMLE1(int[] x, int m, double p) {
517 double param[] = getMLE1(x, m, p);
518 return new NegativeBinomialDist(param[0], p);
519 }
520
539 public static double[] getMLE(int[] x, int m) {
540 if (m <= 0)
541 throw new IllegalArgumentException("m<= 0");
542
543 int i, j;
544 int max = Integer.MIN_VALUE;
545 double sum = 0.0;
546 for (i = 0; i < m; i++) {
547 sum += x[i];
548 if (x[i] > max)
549 max = x[i];
550 }
551 double mean = sum / (double) m;
552
553 double var = 0.0;
554 for (i = 0; i < m; i++)
555 var += (x[i] - mean) * (x[i] - mean);
556 var /= (double) m;
557
558 if (mean >= var) {
559 throw new UnsupportedOperationException("mean >= variance");
560 }
561 double estimGamma = (mean * mean) / (var - mean);
562
563 int[] Fj = new int[max];
564 for (j = 0; j < max; j++) {
565 int prop = 0;
566 for (i = 0; i < m; i++)
567 if (x[i] > j)
568 prop++;
569
570 Fj[j] = prop;
571 }
572
573 double[] param = new double[3];
574 Function f = new Function(m, max, mean, Fj);
575 param[1] = RootFinder.brentDekker(estimGamma / 100, estimGamma * 100, f, 1.0e-5);
576 param[2] = param[1] / (param[1] + mean);
577
578 /*
579 * // Seems to be useless Optim system = new Optim (m, max, mean, Fj); double[]
580 * fvec = new double [3]; double[][] fjac = new double[3][3]; int[] iflag = new
581 * int[2]; int[] info = new int[2]; int[] ipvt = new int[3];
582 *
583 * Minpack_f77.lmder1_f77 (system, 2, 2, param, fvec, fjac, 1e-5, info, ipvt);
584 */
585 double parameters[] = new double[2];
586 parameters[0] = param[1];
587 parameters[1] = param[2];
588
589 return parameters;
590 }
591
600 public static NegativeBinomialDist getInstanceFromMLE(int[] x, int m) {
601 double parameters[] = getMLE(x, m);
602 return new NegativeBinomialDist(parameters[0], parameters[1]);
603 }
604
620 public static double getMLEninv(int[] x, int m) {
621 if (m <= 0)
622 throw new IllegalArgumentException("m <= 0");
623
624 int i, j;
625 int max = Integer.MIN_VALUE;
626 double mean = 0.0;
627 for (i = 0; i < m; i++) {
628 mean += x[i];
629 if (x[i] > max)
630 max = x[i];
631 }
632 mean /= (double) m;
633
634 double var = 0.0;
635 for (i = 0; i < m; i++)
636 var += (x[i] - mean) * (x[i] - mean);
637 var /= (double) m;
638
639 if (mean >= var) {
640 throw new UnsupportedOperationException("mean >= variance");
641 }
642
643 int[] Fj = new int[max];
644 for (j = 0; j < max; j++) {
645 int prop = 0;
646 for (i = 0; i < m; i++)
647 if (x[i] > j)
648 prop++;
649
650 Fj[j] = prop;
651 }
652
653 FuncInv f = new FuncInv(m, max, mean, Fj);
654 double nu = RootFinder.brentDekker(1.0e-8, 1.0e8, f, 1.0e-5);
655 return nu;
656 }
657
665 public static double getMean(double n, double p) {
666 if (p < 0.0 || p > 1.0)
667 throw new IllegalArgumentException("p not in [0, 1]");
668 if (n <= 0.0)
669 throw new IllegalArgumentException("n <= 0");
670
671 return (n * (1 - p) / p);
672 }
673
681 public static double getVariance(double n, double p) {
682 if (p < 0.0 || p > 1.0)
683 throw new IllegalArgumentException("p not in [0, 1]");
684 if (n <= 0.0)
685 throw new IllegalArgumentException("n <= 0");
686
687 return (n * (1 - p) / (p * p));
688 }
689
696 public static double getStandardDeviation(double n, double p) {
697 return Math.sqrt(NegativeBinomialDist.getVariance(n, p));
698 }
699
703 @Deprecated
704 public double getGamma() {
705 return n;
706 }
707
711 public double getN() {
712 return n;
713 }
714
718 public double getP() {
719 return p;
720 }
721
725 public void setParams(double n, double p) {
731 supportA = 0;
732 int i, mode, Nmax;
733 int imin, imax;
734 double sum;
735 double[] P; // Negative Binomial mass probabilities
736 double[] F; // Negative Binomial cumulative
737
738 if (p < 0.0 || p > 1.0)
739 throw new IllegalArgumentException("p not in [0, 1]");
740 if (n <= 0.0)
741 throw new IllegalArgumentException("n <= 0");
742
743 this.n = n;
744 this.p = p;
745
746 // Compute the mode (at the maximum term)
747 mode = 1 + (int) Math.floor((n * (1.0 - p) - 1.0) / p);
748
754
755 if (mode < 0.0 || mode > MAXN) {
756 pdf = null;
757 cdf = null;
758 return;
759 }
760
766
767 Nmax = (int) (n * (1.0 - p) / p + 16 * Math.sqrt(n * (1.0 - p) / (p * p)));
768 if (Nmax < 32)
769 Nmax = 32;
770 P = new double[1 + Nmax];
771
772 double epsilon = EPSILON / prob(n, p, mode);
773
774 // We shall normalize by explicitly summing all terms >= epsilon
775 sum = P[mode] = 1.0;
776
777 // Start from the maximum and compute terms > epsilon on each side.
778 i = mode;
779 while (i > 0 && P[i] >= epsilon) {
780 P[i - 1] = P[i] * i / ((1.0 - p) * (n + i - 1));
781 i--;
782 sum += P[i];
783 }
784 imin = i;
785
786 i = mode;
787 while (P[i] >= epsilon) {
788 P[i + 1] = P[i] * (1.0 - p) * (n + i) / (i + 1);
789 i++;
790 sum += P[i];
791 if (i == Nmax - 1) {
792 Nmax *= 2;
793 double[] nT = new double[1 + Nmax];
794 System.arraycopy(P, 0, nT, 0, P.length);
795 P = nT;
796 }
797 }
798 imax = i;
799
800 // Renormalize the sum of probabilities to 1
801 for (i = imin; i <= imax; i++)
802 P[i] /= sum;
803
804 // Compute the cumulative probabilities for F and keep them in the
805 // lower part of CDF.
806 F = new double[1 + Nmax];
807 F[imin] = P[imin];
808 i = imin;
809 while (i < imax && F[i] < 0.5) {
810 i++;
811 F[i] = F[i - 1] + P[i];
812 }
813
814 // This is the boundary between F (i <= xmed) and 1 - F (i > xmed) in
815 // the array CDF
816 xmed = i;
817
818 // Compute the cumulative probabilities of the complementary
819 // distribution 1 - F and keep them in the upper part of the array
820 F[imax] = P[imax];
821 i = imax - 1;
822 do {
823 F[i] = P[i] + F[i + 1];
824 i--;
825 } while (i > xmed);
826
827 xmin = imin;
828 xmax = imax;
829 pdf = new double[imax + 1 - imin];
830 cdf = new double[imax + 1 - imin];
831 System.arraycopy(P, imin, pdf, 0, imax + 1 - imin);
832 System.arraycopy(F, imin, cdf, 0, imax + 1 - imin);
833
834 }
835
840 public double[] getParams() {
841 double[] retour = { n, p };
842 return retour;
843 }
844
848 public String toString() {
849 return getClass().getSimpleName() + " : n = " + n + ", p = " + p;
850 }
851
852}
Extends the class ContinuousDistribution for the beta distribution.
Definition BetaDist.java:54
double barF(double x)
Returns the complementary distribution function.
double cdf(double x)
Returns the distribution function .
Classes implementing discrete distributions over the integers should inherit from this class.
static double EPSILON
Environment variable that determines what probability terms can be considered as negligible when buil...
static double MAXN
If the maximum term is greater than this constant, then the tables will not be precomputed.
static double prob(double n, double p, int x)
Computes the probability defined in ( fmass-negbin ).
static double barF(double n, double p, int x)
Returns , the complementary distribution function.
double getGamma()
Returns the parameter of this object.
static int inverseF(double n, double p, double u)
Computes the inverse function without precomputing tables.
void setParams(double n, double p)
Sets the parameter and of this object.
static double[] getMLE(int[] x, int m)
Estimates the parameter of the negative binomial distribution using the maximum likelihood method,...
static NegativeBinomialDist getInstanceFromMLE(int[] x, int m)
Creates a new instance of a negative binomial distribution with parameters and estimated using the ...
double barF(int x)
Returns , the complementary distribution function.
static double getMLEninv(int[] x, int m)
Estimates and returns the parameter of the negative binomial distribution using the maximum likeliho...
static double getStandardDeviation(double n, double p)
Computes and returns the standard deviation of the negative binomial distribution with parameters an...
static double getVariance(double n, double p)
Computes and returns the variance of the negative binomial distribution with parameters and.
double cdf(int x)
Returns the distribution function evaluated at (see ( FDistDisc )).
double[] getParams()
Return a table containing the parameters of the current distribution.
double prob(int x)
Returns , the probability of .
double getVariance()
Returns the variance of the distribution function.
static double getMean(double n, double p)
Computes and returns the mean of the negative binomial distribution with parameters and .
double getN()
Returns the parameter of this object.
static double cdf(double n, double p, int x)
Computes the distribution function.
static double[] getMLE(int[] x, int m, double n)
Estimates the parameter of the negative binomial distribution using the maximum likelihood method,...
int inverseFInt(double u)
Returns the inverse distribution function , where.
static NegativeBinomialDist getInstanceFromMLE(int[] x, int m, double n)
Creates a new instance of a negative binomial distribution with parameters given and estimated usin...
NegativeBinomialDist(double n, double p)
Creates an object that contains the probability terms ( fmass-negbin ) and the distribution function ...
double getMean()
Returns the mean of the distribution function.
static double[] getMLE1(int[] x, int m, double p)
Estimates the parameter of the negative binomial distribution using the maximum likelihood method,...
double getP()
Returns the parameter of this object.
String toString()
Returns a String containing information about the current distribution.
static NegativeBinomialDist getInstanceFromMLE1(int[] x, int m, double p)
Creates a new instance of a negative binomial distribution with parameters given and estimated usin...
double getStandardDeviation()
Returns the standard deviation of the distribution function.
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static double lnGamma(double x)
Returns the natural logarithm of the gamma function evaluated at x.
Definition Num.java:417
static final int DBL_MIN_EXP
Smallest int such that is representable (approximately) as a normalised double.
Definition Num.java:102
static double lnFactorial(int n)
Returns the value of , the natural logarithm of factorial .
Definition Num.java:313
static final int DBL_MAX_EXP
Largest int such that is representable (approximately) as a double.
Definition Num.java:96
static double digamma(double x)
Returns the value of the logarithmic derivative of the Gamma function .
Definition Num.java:487
static final double LN2
The values of .
Definition Num.java:148
This class provides numerical methods to solve non-linear equations.
static double brentDekker(double a, double b, MathFunction f, double tol)
Computes a root of the function in f using the Brent-Dekker method.
This interface should be implemented by classes which represent univariate mathematical functions.