1 package nl.tudelft.simulation.jstats.distributions; 2 3 import org.djutils.exceptions.Throw; 4 5 import nl.tudelft.simulation.jstats.math.ProbMath; 6 import nl.tudelft.simulation.jstats.streams.StreamInterface; 7 8 /** 9 * The Negative Binomial distribution. It is also known as the Pascal distribution or Pólya distribution. It gives the 10 * probability of x failures where there are s-1 successes in a total of x+s-1 Bernoulli trials, and trial (x+s) is a success. 11 * The chance for success is p for each trial. For more information on this distribution see 12 * <a href="https://mathworld.wolfram.com/NegativeBinomialDistribution.html"> 13 * https://mathworld.wolfram.com/NegativeBinomialDistribution.html </a> 14 * <p> 15 * Copyright (c) 2002-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See 16 * for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL 17 * project is distributed under a three-clause BSD-style license, which can be found at 18 * <a href="https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>. 19 * </p> 20 * @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a> 21 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a> 22 */ 23 public class DistNegBinomial extends DistDiscrete 24 { 25 /** */ 26 private static final long serialVersionUID = 1L; 27 28 /** s is the number of successes in the sequence of (x+n) trials, where trial (x+n) is a success. */ 29 private int s; 30 31 /** p is the probability of success for each individual trial in the negative binomial distribution. */ 32 private double p; 33 34 /** lnp is a helper variable equal to ln(1-p) to avoid repetitive calculation. */ 35 private double lnp; 36 37 /** 38 * constructs a new negative binomial distribution. 39 * @param stream StreamInterface; the random number stream 40 * @param s int; the number of successes in the sequence of (x+n) trials, where trial (x+n) is a success 41 * @param p double; the probability of success for each individual trial in the negative binomial distribution 42 * @throws IllegalArgumentException when s <= 0 or p <= 0 or p >= 1 43 */ 44 public DistNegBinomial(final StreamInterface stream, final int s, final double p) 45 { 46 super(stream); 47 Throw.when(s <= 0 || p <= 0.0 || p >= 1.0, IllegalArgumentException.class, 48 "Error NegBinomial - s<=0 or p<=0.0 or p>=1.0"); 49 this.s = s; 50 this.p = p; 51 this.lnp = Math.log(1.0 - this.p); 52 } 53 54 @Override 55 public long draw() 56 { 57 long x = 0; 58 for (int i = 0; i < this.s; i++) 59 { 60 double u = this.stream.nextDouble(); 61 x = x + (long) (Math.floor(Math.log(u) / this.lnp)); 62 } 63 return x; 64 } 65 66 @Override 67 public double probability(final long observation) 68 { 69 if (observation >= 0) 70 { 71 return ProbMath.combinations(this.s + observation - 1, observation) * Math.pow(this.p, this.s) 72 * Math.pow(1 - this.p, observation); 73 } 74 return 0.0; 75 } 76 77 /** 78 * Return the number of successes in the sequence of (x+n) trials, where trial (x+n) is a success. 79 * @return int; the number of successes in the sequence of (x+n) trials, where trial (x+n) is a success 80 */ 81 public int getS() 82 { 83 return this.s; 84 } 85 86 /** 87 * Return the probability of success for each individual trial in the negative binomial distribution. 88 * @return double; the probability of success for each individual trial in the negative binomial distribution 89 */ 90 public double getP() 91 { 92 return this.p; 93 } 94 95 @Override 96 public String toString() 97 { 98 return "NegBinomial(" + this.s + "," + this.p + ")"; 99 } 100 }