/// <summary>
 /// Evidence message for EP.
 /// </summary>
 /// <param name="cases">Incoming message from 'cases'.</param>
 /// <param name="b">Incoming message from 'b'.</param>
 public static double LogEvidenceRatio(IList <Bernoulli> cases, Bernoulli b)
 {
     // result = log (p(data|b=true) p(b=true) + p(data|b=false) p(b=false))
     //          log (p(data|b=true) p(b=true) + p(data|b=false) (1-p(b=true))
     //          log ((p(data|b=true) - p(data|b=false)) p(b=true) + p(data|b=false))
     //          log ((p(data|b=true)/p(data|b=false) - 1) p(b=true) + 1) + log p(data|b=false)
     // where cases[0].LogOdds = log p(data|b=true)
     //       cases[1].LogOdds = log p(data|b=false)
     if (b.IsPointMass)
     {
         return(b.Point ? cases[0].LogOdds : cases[1].LogOdds);
     }
     //else return MMath.LogSumExp(cases[0].LogOdds + b.GetLogProbTrue(), cases[1].LogOdds + b.GetLogProbFalse());
     else
     {
         // the common case is when cases[0].LogOdds == cases[1].LogOdds.  we must not introduce rounding error in that case.
         if (cases[0].LogOdds >= cases[1].LogOdds)
         {
             if (Double.IsNegativeInfinity(cases[1].LogOdds))
             {
                 return(cases[0].LogOdds + b.GetLogProbTrue());
             }
             else
             {
                 return(cases[1].LogOdds + MMath.Log1Plus(b.GetProbTrue() * MMath.ExpMinus1(cases[0].LogOdds - cases[1].LogOdds)));
             }
         }
         else
         {
             if (Double.IsNegativeInfinity(cases[0].LogOdds))
             {
                 return(cases[1].LogOdds + b.GetLogProbFalse());
             }
             else
             {
                 return(cases[0].LogOdds + MMath.Log1Plus(b.GetProbFalse() * MMath.ExpMinus1(cases[1].LogOdds - cases[0].LogOdds)));
             }
         }
     }
 }
Example #2
0
        /// <summary>
        /// Sample from a Gaussian(0,1) truncated at the given upper and lower bounds
        /// </summary>
        /// <param name="lowerBound">Can be -Infinity.</param>
        /// <param name="upperBound">Must be &gt;= <paramref name="lowerBound"/>.  Can be Infinity.</param>
        /// <returns>A real number &gt;= <paramref name="lowerBound"/> and &lt; <paramref name="upperBound"/></returns>
        public static double NormalBetween(double lowerBound, double upperBound)
        {
            if (double.IsNaN(lowerBound))
            {
                throw new ArgumentException("lowerBound is NaN");
            }
            if (double.IsNaN(upperBound))
            {
                throw new ArgumentException("upperBound is NaN");
            }
            double delta = upperBound - lowerBound;

            if (delta == 0)
            {
                return(lowerBound);
            }
            if (delta < 0)
            {
                throw new ArgumentException("upperBound (" + upperBound + ") < lowerBound (" + lowerBound + ")");
            }
            // Switch between the following 3 options:
            // 1. Gaussian rejection, with acceptance rate Z = NormalCdf(upperBound) - NormalCdf(lowerBound)
            // 2. Uniform rejection, with acceptance rate sqrt(2*pi)*Z/delta if the interval contains 0
            // 3. Truncated exponential rejection, with acceptance rate
            //    = sqrt(2*pi)*Z*lambda*exp(-lambda^2/2)/(exp(-lambda*lowerBound)-exp(-lambda*upperBound))
            //    = sqrt(2*pi)*Z*lowerBound*exp(lowerBound^2/2)/(1-exp(-lowerBound*(upperBound-lowerBound)))
            // (3) has the highest acceptance rate under the following conditions:
            //     lowerBound > 0.5 or (lowerBound > 0 and delta < 2.5)
            // (2) has the highest acceptance rate if the interval contains 0 and delta < sqrt(2*pi)
            // (1) has the highest acceptance rate otherwise
            if (lowerBound > 0.5 || (lowerBound > 0 && delta < 2.5))
            {
                // Rejection sampler using truncated exponential proposal
                double lambda = lowerBound;
                double s      = MMath.ExpMinus1(-lambda * delta);
                double c      = 2 * lambda * lambda;
                while (true)
                {
                    double x = -MMath.Log1Plus(s * Rand.Double());
                    double u = -System.Math.Log(Rand.Double());
                    if (c * u > x * x)
                    {
                        return(x / lambda + lowerBound);
                    }
                }
                throw new InferRuntimeException("failed to sample");
            }
            else if (upperBound < -0.5 || (upperBound < 0 && delta < 2.5))
            {
                return(-NormalBetween(-upperBound, -lowerBound));
            }
            else if (lowerBound <= 0 && upperBound >= 0 && delta < MMath.Sqrt2PI)
            {
                // Uniform rejection
                while (true)
                {
                    double x = Rand.Double() * delta + lowerBound;
                    double u = -System.Math.Log(Rand.Double());
                    if (2 * u > x * x)
                    {
                        return(x);
                    }
                }
            }
            else
            {
                // Gaussian rejection
                while (true)
                {
                    double x = Rand.Normal();
                    if (x >= lowerBound && x < upperBound)
                    {
                        return(x);
                    }
                }
            }
        }