예제 #1
0
        /// <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));
            }
        }