package org.seqcode.math.stats; import umontreal.ssj.probdist.NegativeBinomialDist; import cern.jet.random.Gamma; import cern.jet.random.Poisson; import cern.jet.random.engine.DRand; /** * NegativeBinomial: distribution of the number of failures (X) before the rth success in independent trials, with success * probability p in each trial. * * This class implements a random number generator that samples from the NB. PDF & CDF will be added/ * * This class is necessary because of a bug in the Colt implementation of NegativeBinomial (in the nextInt method), and also because * the Colt implementation does not allow a real-valued r. * @author Shaun Mahony * @version %I%, %G% */ public class NegativeBinomialDistrib { protected double r; //Number of successes protected double p; //Probability of success protected double mean; protected double var; protected Gamma gamma; //Gamma distribution protected Poisson poisson; //Poisson protected NegativeBinomialDist nb; //SSJ NegativeBinomial /** * NegativeBinomial (r p parameterization) * Parameterized as the distribution of the number of failures (X) before the rth success in independent trials * @param r : Number of successes * @param p : Probability of success in each trial */ public NegativeBinomialDistrib(double r, double p){ this.r = r; this.p = p; gamma = new Gamma(1, 1.0, new DRand()); poisson = new Poisson(10, new DRand()); nb = new NegativeBinomialDist(r, p); } /** * Update the r & p parameters directly * @param r * @param p */ public void setRandP(double r, double p){ this.r = r; this.p = p; mean = r*(1-p)/p; var = r*(1-p)/(p*p); } /** * Update the r & p parameters via the mean and variance * @param mean * @param var */ public void setMeanVar(double mean, double var){ r = (mean*mean)/(var-mean); p = mean/var; this.mean = mean; this.var = var; } /** * Returns a random number from the distribution, bypassing internal state * This method samples a random number from the NegativeBinomial * distribution with parameters r (no. of successes in n independent trials) * and p (probability of success) * Valid for r > 0, 0 < p < 1. * If G from Gamma(r) then K from Poiss((1-p)G/p) is NB(r,p)--distributed. * REFERENCE: - J.H. Ahrens, U. Dieter (1974): Computer methods for * sampling from gamma, beta, Poisson and * binomial distributions, * Computing 12, 223--246. * * @return integer */ public int nextInt(double nb_r, double nb_p){ setRandP(nb_r, nb_p); return nextInt(); } public int nextInt(){ if(mean==var) return poisson.nextInt(mean); else{ double x = (1.0 - p)/p; double y = x * gamma.nextDouble(r, 1.0); return poisson.nextInt(y); } } /** * Call SSJ NegativeBinomial pdf * @param x Number of failures before the r-th success * @return */ public double pdf(int x){ return nb.prob(x); } /** * Call SSJ NegativeBinomial static pdf * @param x Number of failures before the r-th success * @param nb_r Number of successes * @param nb_p Probability of success * @return */ public static double pdf(int x, double nb_r, double nb_p){ return NegativeBinomialDist.prob(nb_r, nb_p, x); } /** * Call SSJ NegativeBinomial cdf * @param x Number of failures before the r-th success * @return */ public double cdf(int x){ return nb.cdf(x); } /** * Call SSJ NegativeBinomial static cdf * @param x Number of failures before the r-th success * @param nb_r Number of successes * @param nb_p Probability of success * @return */ public static double cdf(int x, double nb_r, double nb_p){ return NegativeBinomialDist.cdf(nb_r, nb_p, x); } }