/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="XAverageConditional(Pareto, Gamma, double)"]/*'/> public static Gamma XAverageConditional(Pareto pow, Gamma x, double y) { // factor is delta(pow - x^y) // marginal for x is Pareto(x^y; s,L) Ga(x; a,b) // =propto x^(a-1-y(s+1)) exp(-bx) for x >= L^(1/y) // we can compute moments via the incomplete Gamma function. // change variables to: z=bx, dz=b dx // int_LL^inf x^(c-1) exp(-bx) dx = int_(bLL)^inf z^(c-1)/b^c exp(-z) dz = gammainc(c,bLL,inf)/b^c double lowerBound = System.Math.Pow(pow.LowerBound, 1 / y); double b = x.Rate; double c = x.Shape - y * (pow.Shape + 1); double bL = b * lowerBound; double m, m2; if (y > 0) { // note these ratios can be simplified double z = MMath.GammaUpper(c, bL); m = MMath.GammaUpper(c + 1, bL) * c / z / b; m2 = MMath.GammaUpper(c + 2, bL) * c * (c + 1) / z / (b * b); } else { double z = MMath.GammaLower(c, bL); m = MMath.GammaLower(c + 1, bL) * c / z / b; m2 = MMath.GammaLower(c + 2, bL) * c * (c + 1) / z / (b * b); } double v = m2 - m * m; Gamma xPost = Gamma.FromMeanAndVariance(m, v); Gamma result = new Gamma(); result.SetToRatio(xPost, x, true); return(result); }
/// <summary> /// Get the mean and variance after truncation. /// </summary> /// <param name="mean"></param> /// <param name="variance"></param> public void GetMeanAndVariance(out double mean, out double variance) { if (this.Gamma.IsPointMass) { mean = this.Gamma.Point; variance = 0.0; } else if (!IsProper()) { throw new ImproperDistributionException(this); } else { double Z = GetNormalizer(); if (Z == 0) { mean = Math.Min(UpperBound, Math.Max(LowerBound, this.Gamma.GetMean())); variance = 0.0; return; } double m = this.Gamma.Shape / this.Gamma.Rate; double sum = m * (MMath.GammaLower(this.Gamma.Shape + 1, this.Gamma.Rate * UpperBound) - MMath.GammaLower(this.Gamma.Shape + 1, this.Gamma.Rate * LowerBound)); mean = sum / Z; double sum2 = m * (this.Gamma.Shape + 1) / this.Gamma.Rate * (MMath.GammaLower(this.Gamma.Shape + 2, this.Gamma.Rate * UpperBound) - MMath.GammaLower(this.Gamma.Shape + 2, this.Gamma.Rate * LowerBound)); variance = sum2 / Z - mean * mean; } }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="IsGreaterThanOp"]/message_doc[@name="IsGreaterThanAverageConditional(Poisson, int)"]/*'/> public static Bernoulli IsGreaterThanAverageConditional([Proper] Poisson a, int b) { if (a.IsPointMass) { return(Bernoulli.PointMass(a.Point > b)); } if (a.Precision == 1) { if (b < 0) { return(Bernoulli.PointMass(true)); } else { return(new Bernoulli(MMath.GammaLower(b + 1, a.Rate))); } } else { double sum = 0; for (int i = 0; i <= b; i++) { sum += Math.Exp(a.GetLogProb(i)); } if (sum > 1) { sum = 1; // this can happen due to round-off errors } return(new Bernoulli(1 - sum)); } }
/// <summary> /// Computes GammaLower(a, r*u) - GammaLower(a, r*l) to high accuracy. /// </summary> /// <param name="shape"></param> /// <param name="rate"></param> /// <param name="lowerBound"></param> /// <param name="upperBound"></param> /// <param name="regularized"></param> /// <returns></returns> public static double GammaProbBetween(double shape, double rate, double lowerBound, double upperBound, bool regularized = true) { double rl = rate * lowerBound; // Use the criterion from Gautschi (1979) to determine whether GammaLower(a,x) or GammaUpper(a,x) is smaller. bool lowerIsSmaller; if (rl > 0.25) { lowerIsSmaller = (shape > rl + 0.25); } else { lowerIsSmaller = (shape > -MMath.Ln2 / Math.Log(rl)); } if (!lowerIsSmaller) { double logl = Math.Log(lowerBound); if (rate * upperBound < 1e-16 && shape < -1e-16 / (Math.Log(rate) + logl)) { double logu = Math.Log(upperBound); return(shape * (logu - logl)); } else { // This is inaccurate when lowerBound is close to upperBound. In that case, use a Taylor expansion of lowerBound around upperBound. return(MMath.GammaUpper(shape, rl, regularized) - MMath.GammaUpper(shape, rate * upperBound, regularized)); } } else { double diff = MMath.GammaLower(shape, rate * upperBound) - MMath.GammaLower(shape, rl); return(regularized ? diff : (MMath.Gamma(shape) * diff)); } }
/// <summary> /// Computes E[x^power] /// </summary> /// <returns></returns> public double GetMeanPower(double power) { if (power == 0.0) { return(1.0); } else if (IsPointMass) { return(Math.Pow(Point, power)); } //else if (Rate == 0.0) return (power > 0) ? Double.PositiveInfinity : 0.0; else if (!IsProper()) { throw new ImproperDistributionException(this); } else if (this.Gamma.Shape <= -power && LowerBound == 0) { throw new ArgumentException("Cannot compute E[x^" + power + "] for " + this + " (shape <= " + (-power) + ")"); } else { double Z = GetNormalizer(); double shapePlusPower = this.Gamma.Shape + power; double Z1; bool regularized = shapePlusPower >= 1; if (regularized) { Z1 = Math.Exp(MMath.GammaLn(shapePlusPower) - MMath.GammaLn(this.Gamma.Shape)) * (MMath.GammaLower(shapePlusPower, this.Gamma.Rate * UpperBound) - MMath.GammaLower(shapePlusPower, this.Gamma.Rate * LowerBound)); } else { Z1 = Math.Exp(-MMath.GammaLn(this.Gamma.Shape)) * (MMath.GammaUpper(shapePlusPower, this.Gamma.Rate * LowerBound, regularized) - MMath.GammaUpper(shapePlusPower, this.Gamma.Rate * UpperBound, regularized)); } return(Math.Pow(this.Gamma.Rate, -power) * Z1 / Z); } }
/// <summary> /// Compute the probability that a sample from this distribution is less than x. /// </summary> /// <param name="x">Any real number.</param> /// <returns>The cumulative gamma distribution at <paramref name="x"/></returns> public double GetProbLessThan(double x) { if (x < 0.0) { return(0.0); } else if (double.IsPositiveInfinity(x)) { return(1.0); } else if (this.IsPointMass) { return((this.Point < x) ? 1.0 : 0.0); } else if (this.IsUniform()) { throw new ImproperDistributionException(this); } else { return(MMath.GammaLower(Shape, x * Rate)); } }
/// <summary> /// Returns the mean (first moment) of the distribution /// </summary> /// <returns></returns> public double GetMean() { if (this.Gamma.IsPointMass) { return(this.Gamma.Point); } else if (!IsProper()) { throw new ImproperDistributionException(this); } else { double Z = GetNormalizer(); if (Z == 0) { double mean = this.Gamma.GetMean(); return(Math.Min(UpperBound, Math.Max(LowerBound, mean))); } // if Z is not zero, then Z1 cannot be zero. double Z1 = MMath.GammaLower(this.Gamma.Shape + 1, this.Gamma.Rate * UpperBound) - MMath.GammaLower(this.Gamma.Shape + 1, this.Gamma.Rate * LowerBound); double sum = this.Gamma.Shape / this.Gamma.Rate * Z1; return(sum / Z); } }