/// <summary>EP message to <c>logOdds</c>.</summary> /// <param name="sample">Constant value for <c>sample</c>.</param> /// <param name="logOdds">Incoming message from <c>logOdds</c>. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <returns>The outgoing EP message to the <c>logOdds</c> argument.</returns> /// <remarks> /// <para>The outgoing message is the factor viewed as a function of <c>logOdds</c> conditioned on the given values.</para> /// </remarks> /// <exception cref="ImproperMessageException"> /// <paramref name="logOdds" /> is not a proper distribution.</exception> public static Gaussian LogOddsAverageConditional(bool sample, [SkipIfUniform] Gaussian logOdds) { double m, v; logOdds.GetMeanAndVariance(out m, out v); double s = sample ? 1 : -1; m *= s; // catch cases when sigma0 would evaluate to 0 if (m + 1.5 * v < -38) // this check catches sigma0=0 when v <= 200 { double beta2 = Math.Exp(m + 1.5 * v); return(Gaussian.FromMeanAndVariance(s * (m + v), v * (1 - v * beta2)) / logOdds); } else if (m + v < 0) { // Factor out exp(m+v/2) in the following formulas: // sigma(m,v) = exp(m+v/2)(1-sigma(m+v,v)) // sigma'(m,v) = d/dm sigma(m,v) = exp(m+v/2)(1-sigma(m+v,v) - sigma'(m+v,v)) // sigma''(m,v) = d/dm sigma'(m,v) = exp(m+v/2)(1-sigma(m+v,v) - 2 sigma'(m+v,v) - sigma''(m+v,v)) // This approach is always safe if sigma(-m-v,v)>0, which is guaranteed by m+v<0 double sigma0 = MMath.LogisticGaussian(-m - v, v); double sd = MMath.LogisticGaussianDerivative(m + v, v); double sigma1 = sigma0 - sd; double sigma2 = sigma1 - sd - MMath.LogisticGaussianDerivative2(m + v, v); double alpha = sigma1 / sigma0; // 1 - sd/sigma0 if (Double.IsNaN(alpha)) { throw new Exception("alpha is NaN"); } double beta = alpha * alpha - sigma2 / sigma0; if (Double.IsNaN(beta)) { throw new Exception("beta is NaN"); } return(GaussianProductOp_Laplace.GaussianFromAlphaBeta(logOdds, s * alpha, beta, ForceProper)); } else if (v > 1488 && m < 0) { double sigma0 = MMath.LogisticGaussianRatio(m, v, 0); double sigma1 = MMath.LogisticGaussianRatio(m, v, 1); double sigma2 = MMath.LogisticGaussianRatio(m, v, 2); double alpha, beta; alpha = sigma1 / sigma0; if (Double.IsNaN(alpha)) { throw new Exception("alpha is NaN"); } beta = alpha * alpha - sigma2 / sigma0; if (Double.IsNaN(beta)) { throw new Exception("beta is NaN"); } return(GaussianProductOp_Laplace.GaussianFromAlphaBeta(logOdds, s * alpha, beta, ForceProper)); } else { // the following code only works when sigma0 > 0 // sigm0=0 can only happen here if v > 1488 double sigma0 = MMath.LogisticGaussian(m, v); double sigma1 = MMath.LogisticGaussianDerivative(m, v); double sigma2 = MMath.LogisticGaussianDerivative2(m, v); double alpha, beta; alpha = sigma1 / sigma0; if (Double.IsNaN(alpha)) { throw new Exception("alpha is NaN"); } if (m + 2 * v < -19) { beta = Math.Exp(3 * m + 2.5 * v) / (sigma0 * sigma0); } else { //beta = (sigma1*sigma1 - sigma2*sigma0)/(sigma0*sigma0); beta = alpha * alpha - sigma2 / sigma0; } if (Double.IsNaN(beta)) { throw new Exception("beta is NaN"); } return(GaussianProductOp_Laplace.GaussianFromAlphaBeta(logOdds, s * alpha, beta, ForceProper)); } }