/// <summary> /// Gets the expected logarithm of that distribution under this distribution. /// </summary> /// <param name="that">The distribution to take the logarithm of.</param> /// <returns><c>sum_x this.Evaluate(x)*Math.Log(that.Evaluate(x))</c></returns> /// <remarks>This is also known as the cross entropy.</remarks> public double GetAverageLog(Gaussian that) { if (that.IsPointMass) { if (this.IsPointMass && this.Point == that.Point) { return(0.0); } else { return(Double.NegativeInfinity); } } else if (!IsProper()) { throw new ImproperDistributionException(this); } else { // that.Precision != inf double mean, variance; GetMeanAndVariance(out mean, out variance); return(that.GetLogProb(mean) - 0.5 * that.Precision * variance); } }
/// <summary> /// Get the log probability density at value. /// </summary> /// <param name="value"></param> /// <returns></returns> public double GetLogProb(double value) { // p(x) = sum_k N(x + L*k; m, v) // = a/(2*pi) + a/pi sum_{k=1}^inf cos(a*k*(x-m)) exp(-(a*k)^2 v/2) where a = 2*pi/L double m, v; Gaussian.GetMeanAndVariance(out m, out v); if (v < 0.15) { // use Gaussian summation formula double result = double.NegativeInfinity; for (int k = -1; k <= 1; k++) { double logp = Gaussian.GetLogProb(value + k * Period); result = MMath.LogSumExp(result, logp); } return(result); } else { // v >= 0.15 // use the cosine formula double result = 0.5; double aOverPi = 2 / Period; double a = aOverPi * Math.PI; double diff = value - m; double vHalf = v * 0.5; for (int k = 1; k <= 8; k++) { double ak = a * k; result += Math.Cos(ak * diff) * Math.Exp(-ak * ak * vHalf); } return(Math.Log(result * aOverPi)); } }
/// <summary> /// Get the integral of this distribution times another distribution raised to a power. /// </summary> /// <param name="that"></param> /// <param name="power"></param> /// <returns></returns> public double GetLogAverageOfPower(Gaussian that, double power) { if (IsPointMass) { return(power * that.GetLogProb(Point)); } else if (that.IsPointMass) { if (power < 0) { throw new DivideByZeroException("The exponent is negative and the distribution is a point mass"); } return(this.GetLogProb(that.Point)); } else { var product = this * (that ^ power); return(product.GetLogNormalizer() - this.GetLogNormalizer() - power * that.GetLogNormalizer()); } }
/// <summary> /// Gets the integral of the product of two Gaussians. /// </summary> /// <param name="that"></param> /// <remarks> /// <c>this = N(x;m1,v1)</c>. /// <c>that = N(x;m2,v2)</c>. /// <c>int_(-infinity)^(infinity) N(x;m1,v1) N(x;m2,v2) dx = N(m1; m2, v1+v2)</c>. /// When improper, the density is redefined to be <c>exp(-0.5*x^2*(1/v) + x*(m/v))</c>, /// i.e. we drop the terms <c>exp(-m^2/(2v))/sqrt(2*pi*v)</c>. /// </remarks> /// <returns>log(N(m1;m2,v1+v2)).</returns> public double GetLogAverageOf(Gaussian that) { if (IsPointMass) { return(that.GetLogProb(Point)); } else if (that.IsPointMass) { return(GetLogProb(that.Point)); } else { // neither this nor that is a point mass. // int_x N(x;m1,v1) N(x;m2,v2) dx = N(m1;m2,v1+v2) // (m1-m2)^2/(v1+v2) = (m1-m2)^2/(v1*v2*product.Prec) // (m1-m2)^2/(v1*v2) = (m1/(v1*v2) - m2/(v1*v2))^2 *v1*v2 Gaussian product = this * that; //if (!product.IsProper()) throw new ArgumentException("The product is improper."); return(product.GetLogNormalizer() - this.GetLogNormalizer() - that.GetLogNormalizer()); } }