/// <summary> /// Sets the parameters to represent the ratio of two Gammas /// </summary> /// <param name="numerator">The numerator Gamma. Can be the same object as this.</param> /// <param name="denominator">The denominator Gamma. Can be the same object as this.</param> /// <param name="forceProper">If true, the result has shape >= 1 and rate >= 0, under the constraint that result*denominator has the same mean as numerator</param> public void SetToRatio(Gamma numerator, Gamma denominator, bool forceProper = false) { if (numerator.IsPointMass) { if (denominator.IsPointMass) { if (numerator.Point.Equals(denominator.Point)) { SetToUniform(); } else { throw new DivideByZeroException(); } } else { Point = numerator.Point; } } else if (denominator.IsPointMass) { throw new DivideByZeroException(); } else if (forceProper && numerator.Rate == 0) { Rate = 0; Shape = 1 + Math.Max(0, numerator.Shape - denominator.Shape); } else if (forceProper && (numerator.Shape < denominator.Shape || numerator.Rate < denominator.Rate)) { double mean = numerator.GetMean(); double shape = mean * denominator.Rate + (1 - denominator.Shape); if (shape < 1) { Rate = denominator.Shape / mean - denominator.Rate; Shape = 1; } else { Shape = shape; Rate = 0; } } else { if (Math.Abs(denominator.Shape) > 10) { Shape = (numerator.Shape - denominator.Shape) + 1; } else { // avoid roundoff errors when numerator shape is below eps Shape = numerator.Shape + (1 - denominator.Shape); } Rate = numerator.Rate - denominator.Rate; } }
/// <summary> /// Sets the parameters to represent the product of two Gammas. /// </summary> /// <param name="a">The first Gamma</param> /// <param name="b">The second Gamma</param> /// <remarks> /// The result may not be proper. No error is thrown in this case. /// </remarks> public void SetToProduct(Gamma a, Gamma b) { if (a.IsPointMass) { if (b.IsPointMass && !a.Point.Equals(b.Point)) { throw new AllZeroException(); } Point = a.Point; return; } else if (b.IsPointMass) { Point = b.Point; return; } else { // avoid roundoff errors when a shape is below eps if (a.Shape < b.Shape) { Shape = a.Shape + (b.Shape - 1); } else { Shape = b.Shape + (a.Shape - 1); } Rate = a.Rate + b.Rate; if (Shape > double.MaxValue || Rate > double.MaxValue) { // (as + bs - 1)/(ar + br) = (am*ar + bm*br - 1)/(ar + br) = am*w + bm*(1-w) - 1/(ar + br) // w = ar/(ar + br) double w = 1 / (1 + b.Rate / a.Rate); Point = a.GetMean() * w + b.GetMean() * (1 - w) - 1 / Rate; } } }