/// <summary> /// Constructs a Gamma distribution with the given log mean and mean logarithm. /// </summary> /// <param name="logMean">Log of desired expected value.</param> /// <param name="meanLog">Desired expected logarithm.</param> /// <returns>A new Gamma distribution.</returns> /// <remarks> /// This function is significantly slower than the other constructors since it /// involves nonlinear optimization. The algorithm is a generalized Newton iteration, /// described in "Estimating a Gamma distribution" by T. Minka, 2002. /// </remarks> public static Gamma FromLogMeanAndMeanLog(double logMean, double meanLog) { // logMean = log(shape)-log(rate) // meanLog = Psi(shape)-log(rate) // delta = log(shape)-Psi(shape) double delta = logMean - meanLog; if (delta <= 2e-16) { return(Gamma.PointMass(Math.Exp(logMean))); } double shape = 0.5 / delta; for (int iter = 0; iter < 100; iter++) { double oldShape = shape; double g = Math.Log(shape) - delta - MMath.Digamma(shape); shape /= 1 + g / (1 - shape * MMath.Trigamma(shape)); if (Math.Abs(shape - oldShape) < 1e-8) { break; } } if (Double.IsNaN(shape)) { throw new Exception("shape is nan"); } Gamma result = Gamma.FromShapeAndRate(shape, shape / Math.Exp(logMean)); return(result); }
/// <summary> /// Constructs a Gamma distribution with the given mean and mean logarithm. /// </summary> /// <param name="mean">Desired expected value.</param> /// <param name="meanLog">Desired expected logarithm.</param> /// <returns>A new Gamma distribution.</returns> /// <remarks>This function is equivalent to maximum-likelihood estimation of a Gamma distribution /// from data given by sufficient statistics. /// This function is significantly slower than the other constructors since it /// involves nonlinear optimization. The algorithm is a generalized Newton iteration, /// described in "Estimating a Gamma distribution" by T. Minka, 2002. /// </remarks> public static Gamma FromMeanAndMeanLog(double mean, double meanLog) { double delta = Math.Log(mean) - meanLog; if (delta <= 2e-16) { return(Gamma.PointMass(mean)); } double shape = 0.5 / delta; for (int iter = 0; iter < 100; iter++) { double oldShape = shape; double g = Math.Log(shape) - delta - MMath.Digamma(shape); shape /= 1 + g / (1 - shape * MMath.Trigamma(shape)); if (Math.Abs(shape - oldShape) < 1e-8) { break; } } if (Double.IsNaN(shape)) { throw new Exception("shape is nan"); } return(Gamma.FromShapeAndRate(shape, shape / mean)); }
/// <summary> /// Constructs a Gamma distribution with the given mean and mean logarithm. /// </summary> /// <param name="mean">Desired expected value.</param> /// <param name="logMeanMinusMeanLog">Logarithm of desired expected value minus desired expected logarithm.</param> /// <returns>A new Gamma distribution.</returns> /// <remarks>This function is equivalent to maximum-likelihood estimation of a Gamma distribution /// from data given by sufficient statistics. /// This function is significantly slower than the other constructors since it /// involves nonlinear optimization. The algorithm is a generalized Newton iteration, /// described in "Estimating a Gamma distribution" by T. Minka, 2002. /// </remarks> public static Gamma FromLogMeanMinusMeanLog(double mean, double logMeanMinusMeanLog) { if (logMeanMinusMeanLog <= 0) { return(Gamma.PointMass(mean)); } double shape = 0.5 / logMeanMinusMeanLog; for (int iter = 0; iter < 100; iter++) { double g = LogMinusDigamma(shape) - logMeanMinusMeanLog; //Trace.WriteLine($"shape = {shape} g = {g}"); if (MMath.AreEqual(g, 0)) { break; } shape /= 1 + g / (1 - shape * MMath.Trigamma(shape)); } if (double.IsNaN(shape)) { throw new InferRuntimeException("shape is nan"); } if (shape > double.MaxValue) { return(Gamma.PointMass(mean)); } return(Gamma.FromShapeAndRate(shape, shape / mean)); }
public TruncatedGamma(Gamma Gamma, double lowerBound, double upperBound) { LowerBound = lowerBound; UpperBound = upperBound; if (lowerBound == upperBound) { this.Gamma = Gamma.PointMass(lowerBound); } else { this.Gamma = Gamma; } }
/// <summary> /// Create a truncated Gamma from untruncated (shape, scale) and bounds /// </summary> /// <param name="shape"></param> /// <param name="scale"></param> /// <param name="lowerBound"></param> /// <param name="upperBound"></param> public TruncatedGamma(double shape, double scale, double lowerBound, double upperBound) { LowerBound = lowerBound; UpperBound = upperBound; if (lowerBound == upperBound) { this.Gamma = Gamma.PointMass(lowerBound); } else { this.Gamma = Gamma.FromShapeAndScale(shape, scale); } }
/// <summary> /// Construct a Gamma distribution whose pdf has the given derivatives at a point. /// </summary> /// <param name="x">Cannot be negative</param> /// <param name="dLogP">Desired derivative of log-density at x</param> /// <param name="ddLogP">Desired second derivative of log-density at x</param> /// <param name="forceProper">If true and both derivatives cannot be matched by a proper distribution, match only the first.</param> /// <returns></returns> public static Gamma FromDerivatives(double x, double dLogP, double ddLogP, bool forceProper) { if (x < 0) { throw new ArgumentOutOfRangeException(nameof(x), x, "x < 0"); } double a; if (double.IsPositiveInfinity(x)) { if (ddLogP < 0) { return(Gamma.PointMass(x)); } else if (ddLogP == 0) { a = 0.0; } else if (forceProper) { if (dLogP <= 0) { return(Gamma.FromShapeAndRate(1, -dLogP)); } else { return(Gamma.PointMass(x)); } } else { return(Gamma.FromShapeAndRate(-x, -x - dLogP)); } } else { a = -x * x * ddLogP; if (a + 1 > double.MaxValue) { return(Gamma.PointMass(x)); } } if (forceProper) { if (dLogP <= 0) { if (a < 0) { a = 0; } } else { double amin = x * dLogP; if (a < amin) { return(Gamma.FromShapeAndRate(amin + 1, 0)); } } } double b = ((a == 0) ? 0 : (a / x)) - dLogP; if (forceProper) { // correct roundoff errors that might make b negative b = Math.Max(b, 0); } return(Gamma.FromShapeAndRate(a + 1, b)); }