/** Computes the probability <SPAN CLASS="MATH"><I>p</I>(<I>x</I>)</SPAN>. */ public static double prob(double n, double p, int x) { final int SLIM = 15; // To avoid overflow final double MAXEXP = (Num.DBL_MAX_EXP - 1) * Num.LN2; // To avoid overflow final double MINEXP = (Num.DBL_MIN_EXP - 1) * Num.LN2; // To avoid underflow double y; if (p < 0.0 || p > 1.0) throw new IllegalArgumentException("p not in [0, 1]"); if (n <= 0.0) throw new IllegalArgumentException("n <= 0.0"); if (x < 0) return 0.0; if (p >= 1.0) { // In fact, p == 1 if (x == 0) return 1.0; else return 0.0; } if (p <= 0.0) // In fact, p == 0 return 0.0; y = Num.lnGamma(n + x) - (Num.lnFactorial(x) + Num.lnGamma(n)) + n * Math.log(p) + x * Math.log1p(-p); if (y >= MAXEXP) throw new IllegalArgumentException("term overflow"); return Math.exp(y); }
public double evaluate(double gam) { if (gam <= 0) return 1.0e100; double sum = 0.0; for (int j = 0; j < m; j++) sum += Num.digamma(gam + x[j]); return sum / m + Math.log(p) - Num.digamma(gam); }
public double evaluate(double s) { if (s <= 0) return 1.0e100; double sum = 0.0; double p = s / (s + mean); for (int j = 0; j < max; j++) sum += Fj[j] / (s + (double) j); return sum + m * Math.log(p); }
/** Computes the distribution function. */ public static double cdf(double n, double p, int x) { final double EPSILON = DiscreteDistributionInt.EPSILON; final int LIM1 = 100000; double sum, term, termmode; int i, mode; final double q = 1.0 - p; if (p < 0.0 || p > 1.0) throw new IllegalArgumentException("p not in [0, 1]"); if (n <= 0.0) throw new IllegalArgumentException("n <= 0.0"); if (x < 0) return 0.0; if (p >= 1.0) // In fact, p == 1 return 1.0; if (p <= 0.0) // In fact, p == 0 return 0.0; // Compute the maximum term mode = 1 + (int) Math.floor((n * q - 1.0) / p); if (mode < 0) mode = 0; else if (mode > x) mode = x; if (mode <= LIM1) { sum = term = termmode = prob(n, p, mode); for (i = mode; i > 0; i--) { term *= i / (q * (n + i - 1.0)); if (term < EPSILON) break; sum += term; } term = termmode; for (i = mode; i < x; i++) { term *= q * (n + i) / (i + 1); if (term < EPSILON) break; sum += term; } if (sum <= 1.0) return sum; else return 1.0; } else // return 1.0 - BinomialDist.cdf (x + n, p, n - 1); return BetaDist.cdf(n, x + 1.0, 15, p); }
/** * Sets the parameter <SPAN CLASS="MATH"><I>n</I></SPAN> and <SPAN CLASS="MATH"><I>p</I></SPAN> of * this object. */ public void setParams(double n, double p) { /* * * Compute all probability terms of the negative binomial distribution; * start at the mode, and calculate probabilities on each side until they * become smaller than EPSILON. Set all others to 0. */ supportA = 0; int i, mode, Nmax; int imin, imax; double sum; double[] P; // Negative Binomial mass probabilities double[] F; // Negative Binomial cumulative if (p < 0.0 || p > 1.0) throw new IllegalArgumentException("p not in [0, 1]"); if (n <= 0.0) throw new IllegalArgumentException("n <= 0"); this.n = n; this.p = p; // Compute the mode (at the maximum term) mode = 1 + (int) Math.floor((n * (1.0 - p) - 1.0) / p); /* * For mode > MAXN, we shall not use pre-computed arrays. mode < 0 should be impossible, unless overflow of long occur, in which case mode will be = LONG_MIN. */ if (mode < 0.0 || mode > MAXN) { pdf = null; cdf = null; return; } /* * In theory, the negative binomial distribution has an infinite range. But for i > Nmax, probabilities should be extremely small. Nmax = Mean + 16 * Standard deviation. */ Nmax = (int) (n * (1.0 - p) / p + 16 * Math.sqrt(n * (1.0 - p) / (p * p))); if (Nmax < 32) Nmax = 32; P = new double[1 + Nmax]; double epsilon = EPSILON / prob(n, p, mode); // We shall normalize by explicitly summing all terms >= epsilon sum = P[mode] = 1.0; // Start from the maximum and compute terms > epsilon on each side. i = mode; while (i > 0 && P[i] >= epsilon) { P[i - 1] = P[i] * i / ((1.0 - p) * (n + i - 1)); i--; sum += P[i]; } imin = i; i = mode; while (P[i] >= epsilon) { P[i + 1] = P[i] * (1.0 - p) * (n + i) / (i + 1); i++; sum += P[i]; if (i == Nmax - 1) { Nmax *= 2; double[] nT = new double[1 + Nmax]; System.arraycopy(P, 0, nT, 0, P.length); P = nT; } } imax = i; // Renormalize the sum of probabilities to 1 for (i = imin; i <= imax; i++) P[i] /= sum; // Compute the cumulative probabilities for F and keep them in the // lower part of CDF. F = new double[1 + Nmax]; F[imin] = P[imin]; i = imin; while (i < imax && F[i] < 0.5) { i++; F[i] = F[i - 1] + P[i]; } // This is the boundary between F (i <= xmed) and 1 - F (i > xmed) in // the array CDF xmed = i; // Compute the cumulative probabilities of the complementary // distribution 1 - F and keep them in the upper part of the array F[imax] = P[imax]; i = imax - 1; do { F[i] = P[i] + F[i + 1]; i--; } while (i > xmed); xmin = imin; xmax = imax; pdf = new double[imax + 1 - imin]; cdf = new double[imax + 1 - imin]; System.arraycopy(P, imin, pdf, 0, imax + 1 - imin); System.arraycopy(F, imin, cdf, 0, imax + 1 - imin); }
/** * Computes and returns the standard deviation of the negative binomial distribution with * parameters <SPAN CLASS="MATH"><I>n</I></SPAN> and <SPAN CLASS="MATH"><I>p</I></SPAN>. * * @return the standard deviation of the negative binomial distribution */ public static double getStandardDeviation(double n, double p) { return Math.sqrt(NegativeBinomialDist.getVariance(n, p)); }
/** Computes the inverse function without precomputing tables. */ public static int inverseF(double n, double p, double u) { if (u < 0.0 || u > 1.0) throw new IllegalArgumentException("u is not in [0,1]"); if (p < 0.0 || p > 1.0) throw new IllegalArgumentException("p not in [0, 1]"); if (n <= 0.0) throw new IllegalArgumentException("n <= 0"); if (p >= 1.0) // In fact, p == 1 return 0; if (p <= 0.0) // In fact, p == 0 return 0; if (u <= prob(n, p, 0)) return 0; if (u >= 1.0) return Integer.MAX_VALUE; double sum, term, termmode; final double q = 1.0 - p; // Compute the maximum term int mode = 1 + (int) Math.floor((n * q - 1.0) / p); if (mode < 0) mode = 0; int i = mode; term = prob(n, p, i); while ((term >= u) && (term > Double.MIN_NORMAL)) { i /= 2; term = prob(n, p, i); } if (term <= Double.MIN_NORMAL) { i *= 2; term = prob(n, p, i); while (term >= u && (term > Double.MIN_NORMAL)) { term *= i / (q * (n + i - 1.0)); i--; } } mode = i; sum = termmode = prob(n, p, i); for (i = mode; i > 0; i--) { term *= i / (q * (n + i - 1.0)); if (term < EPSILON) break; sum += term; } term = termmode; i = mode; double prev = -1; if (sum < u) { // The CDF at the mode is less than u, so we add term to get >= u. while ((sum < u) && (sum > prev)) { term *= q * (n + i) / (i + 1); prev = sum; sum += term; i++; } } else { // The computed CDF is too big so we substract from it. sum -= term; while (sum >= u) { term *= i / (q * (n + i - 1.0)); i--; sum -= term; } } return i; }
/** * Returns the standard deviation of the hypoexponential distribution with rates <SPAN * CLASS="MATH"><I>λ</I><SUB>i</SUB> =</SPAN> <TT>lambda[<SPAN CLASS="MATH"><I>i</I> - * 1</SPAN>]</TT>, <SPAN CLASS="MATH"><I>i</I> = 1,…, <I>k</I></SPAN>. * * @param lambda rates of the hypoexponential distribution * @return standard deviation of the hypoexponential distribution */ public static double getStandardDeviation(double[] lambda) { double s = getVariance(lambda); return Math.sqrt(s); }