Пример #1
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GateExitTwoOp"]/message_doc[@name="ExitTwoAverageConditional{TExit}(TExit, Bernoulli, Bernoulli, IList{TExit}, TExit)"]/*'/>
        /// <typeparam name="TExit">The type of the distribution over the variable exiting the gate.</typeparam>
        public static TExit ExitTwoAverageConditional <TExit>(
            TExit exitTwo, Bernoulli case0, Bernoulli case1, [SkipIfAllUniform] IList <TExit> values, TExit result)
            where TExit : SettableTo <TExit>, ICloneable, SettableToProduct <TExit>, SettableToRatio <TExit>, SettableToWeightedSum <TExit>
        {
            result.SetToProduct(exitTwo, values[0]);
            double scale       = case0.LogOdds;
            double resultScale = scale;
            // TODO: use pre-allocated buffer
            TExit product = (TExit)exitTwo.Clone();

            product.SetToProduct(exitTwo, values[1]);
            scale = case1.LogOdds;
            double shift = Math.Max(resultScale, scale);

            // avoid (-Infinity) - (-Infinity)
            if (Double.IsNegativeInfinity(shift))
            {
                throw new AllZeroException();
            }
            else
            {
                result.SetToSum(Math.Exp(resultScale - shift), result, Math.Exp(scale - shift), product);
                resultScale = MMath.LogSumExp(resultScale, scale);
            }
            result.SetToRatio(result, exitTwo);
            return(result);
        }
Пример #2
0
        /// <summary>
        /// Computes log(sum_{x=0..infinity} lambda^x / x!^nu)
        /// </summary>
        /// <param name="lambda">Rate.</param>
        /// <param name="nu">Precision.</param>
        /// <returns></returns>
        public static double GetLogNormalizer(double lambda, double nu)
        {
            if (lambda < 0)
            {
                throw new ArgumentException("lambda (" + lambda + ") < 0");
            }
            if (lambda == 0 || nu < 0 || Double.IsPositiveInfinity(nu))
            {
                return(0.0);
            }
            if (nu == 1)
            {
                return(lambda);
            }
            else if (nu == 0)
            {
                if (lambda >= 1)
                {
                    return(0.0);
                }
                /* needed when lambda is close to 1 */
                return(-Math.Log(1 - lambda));
            }
            double lambda_ln = Math.Log(lambda);
            double term      = lambda_ln;
            double result    = Math.Log(1 + lambda); // start off with first two terms
            int    i;

            for (i = 2; i < maxiter; i++)
            {
                double delta = lambda_ln - nu * Math.Log(i);
                term  += delta;
                result = MMath.LogSumExp(result, term);
                if (delta < 0)
                {
                    /* truncation error */
                    // the rest of the series is sum_{i=0..infinity} exp(term + delta(i)*i)
                    // because delta is decreasing, we can bound the sum of the rest of the series
                    // by sum_{i=0..infinity} exp(term + delta*i) = exp(term)/(1 - exp(delta))
                    double r = Math.Exp(term - result) / (1 - Math.Exp(delta));
                    /* truncation error in log domain */
                    /* log(z+r)-log(z) = log(1 + r/z) =approx r/z */
                    if (r < tol)
                    {
                        break;
                    }
                }
            }
            if (i == maxiter)
            {
                double r = Math.Pow(lambda, 1 / nu);
                if (r > 10)
                {
                    /* use asymptotic approximation */
                    result = nu * r - (nu - 1) / 2 / nu * lambda_ln - (nu - 1) * MMath.LnSqrt2PI - 0.5 * Math.Log(nu);
                    i      = 0;
                }
            }
            return(result);
        }
Пример #3
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GateExitTwoOp"]/message_doc[@name="ExitTwoAverageConditional{TExit, TExitDomain}(TExit, Bernoulli, Bernoulli, IList{TExitDomain}, TExit)"]/*'/>
        /// <typeparam name="TExit">The type of the distribution over the variable exiting the gate.</typeparam>
        /// <typeparam name="TExitDomain">The domain of the variable exiting the gate.</typeparam>
        public static TExit ExitTwoAverageConditional <TExit, TExitDomain>(
            TExit exitTwo, Bernoulli case0, Bernoulli case1, IList <TExitDomain> values, TExit result)
            where TExit : ICloneable, HasPoint <TExitDomain>, SettableToWeightedSum <TExit>
        {
            result.Point = values[0];
            double scale       = case0.LogOdds;
            double resultScale = scale;
            // TODO: overload SetToSum to accept constants.
            TExit product = (TExit)exitTwo.Clone();

            product.Point = values[1];
            scale         = case1.LogOdds;
            double shift = Math.Max(resultScale, scale);

            // avoid (-Infinity) - (-Infinity)
            if (Double.IsNegativeInfinity(shift))
            {
                throw new AllZeroException();
                // do nothing
            }
            else
            {
                result.SetToSum(Math.Exp(resultScale - shift), result, Math.Exp(scale - shift), product);
                resultScale = MMath.LogSumExp(resultScale, scale);
            }
            return(result);
        }
            /// <summary>
            /// Gets a value indicating how close this weight function is to a given one
            /// in terms of weights they assign to sequences.
            /// </summary>
            /// <param name="that">The other weight function.</param>
            /// <returns>The logarithm of a non-negative value, which is close to zero if the two automata assign similar values to all sequences.</returns>
            protected double GetLogSimilarity(TThis that)
            {
                // Consistently with Automaton.GetLogSimilarity
                var thisIsZero = IsZero();
                var thatIsZero = that.IsZero();

                if (thisIsZero)
                {
                    return(thatIsZero ? double.NegativeInfinity : 1.0);
                }
                if (thatIsZero)
                {
                    return(1.0);
                }

                double logNormProduct = GetLogNormalizerOfProduct(that);

                if (double.IsNegativeInfinity(logNormProduct))
                {
                    return(1.0);
                }

                double logNormThisSquared = GetLogNormalizerOfSquare();
                double logNormThatSquared = that.GetLogNormalizerOfSquare();

                double term1  = MMath.LogSumExp(logNormThisSquared, logNormThatSquared);
                double term2  = logNormProduct + MMath.Ln2;
                double result = MMath.LogDifferenceOfExp(Math.Max(term1, term2), Math.Min(term1, term2)); // To avoid NaN due to numerical instabilities

                System.Diagnostics.Debug.Assert(!double.IsNaN(result), "Log-similarity must be a valid number.");
                return(result);
            }
        /// <summary>
        /// Evidence message for EP
        /// </summary>
        /// <param name="isPositive">Incoming message from 'isPositive'.</param>
        /// <param name="x">Incoming message from 'x'.</param>
        /// <returns>Logarithm of the factor's average value across the given argument distributions</returns>
        /// <remarks><para>
        /// The formula for the result is <c>log(sum_(isPositive,x) p(isPositive,x) factor(isPositive,x))</c>.
        /// </para></remarks>
        public static double LogAverageFactor(Bernoulli isPositive, Gaussian x)
        {
            Bernoulli to_isPositive = IsPositiveAverageConditional(x);

            return(isPositive.GetLogAverageOf(to_isPositive));

#if false
            // Z = p(b=T) p(x > 0) + p(b=F) p(x <= 0)
            //   = p(b=F) + (p(b=T) - p(b=F)) p(x > 0)
            if (x.IsPointMass)
            {
                return(Factor.IsPositive(x.Point) ? isPositive.GetLogProbTrue() : isPositive.GetLogProbFalse());
            }
            else if (x.IsUniform())
            {
                return(Bernoulli.LogProbEqual(isPositive.LogOdds, 0.0));
            }
            else
            {
                // m/sqrt(v) = (m/v)/sqrt(1/v)
                double z = x.MeanTimesPrecision / Math.Sqrt(x.Precision);
                if (isPositive.IsPointMass)
                {
                    return(isPositive.Point ? MMath.NormalCdfLn(z) : MMath.NormalCdfLn(-z));
                }
                else
                {
                    return(MMath.LogSumExp(isPositive.GetLogProbTrue() + MMath.NormalCdfLn(z), isPositive.GetLogProbFalse() + MMath.NormalCdfLn(-z)));
                }
            }
#endif
        }
Пример #6
0
        /// <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));
            }
        }
Пример #7
0
        /// <summary>EP message to <c>value</c>.</summary>
        /// <param name="enter">Incoming message from <c>enter</c>. Must be a proper distribution. If all elements are uniform, the result will be uniform.</param>
        /// <param name="selector">Incoming message from <c>selector</c>.</param>
        /// <param name="value">Incoming message from <c>value</c>.</param>
        /// <param name="result">Modified to contain the outgoing message.</param>
        /// <returns>
        ///   <paramref name="result" />
        /// </returns>
        /// <remarks>
        ///   <para>The outgoing message is a distribution matching the moments of <c>value</c> as the random arguments are varied. The formula is <c>proj[p(value) sum_(enter,selector) p(enter,selector) factor(enter,selector,value)]/p(value)</c>.</para>
        /// </remarks>
        /// <exception cref="ImproperMessageException">
        ///   <paramref name="enter" /> is not a proper distribution.</exception>
        /// <typeparam name="TDist">The type of the distribution over the variable entering the gate.</typeparam>
        public static TDist ValueAverageConditional <TDist>([SkipIfAllUniform] IList <TDist> enter, Discrete selector, TDist value, TDist result)
            where TDist : SettableTo <TDist>, SettableToWeightedSum <TDist>, CanGetLogAverageOf <TDist>
        {
            if (enter == null)
            {
                throw new ArgumentNullException("enter");
            }

            if (selector == null)
            {
                throw new ArgumentNullException("selector");
            }

            if (selector.Dimension != enter.Count)
            {
                throw new ArgumentException("selector.Dimension != enter.Count");
            }

            // TODO: use pre-allocated buffers
            double logWeightSum = selector.GetLogProb(0);

            if (!double.IsNegativeInfinity(logWeightSum))
            {
                logWeightSum -= enter[0].GetLogAverageOf(value);
                result.SetTo(enter[0]);
            }

            if (selector.Dimension > 1)
            {
                for (int i = 1; i < selector.Dimension; i++)
                {
                    double logWeight = selector.GetLogProb(i);
                    double shift     = Math.Max(logWeightSum, logWeight);

                    // Avoid (-Infinity) - (-Infinity)
                    if (double.IsNegativeInfinity(shift))
                    {
                        if (i == selector.Dimension - 1)
                        {
                            throw new AllZeroException();
                        }

                        // Do nothing
                    }
                    else
                    {
                        double logWeightShifted = logWeight - shift;
                        if (!double.IsNegativeInfinity(logWeightShifted))
                        {
                            logWeightShifted -= enter[i].GetLogAverageOf(value);
                            result.SetToSum(Math.Exp(logWeightSum - shift), result, Math.Exp(logWeightShifted), enter[i]);
                            logWeightSum = MMath.LogSumExp(logWeightSum, logWeightShifted + shift);
                        }
                    }
                }
            }

            return(result);
        }
Пример #8
0
 /// <summary>
 /// Evidence message for EP
 /// </summary>
 /// <param name="sample">Constant value for 'sample'.</param>
 /// <param name="logProbs">Incoming message from 'logProbs'.</param>
 /// <returns>Logarithm of the factor's average value across the given argument distributions</returns>
 /// <remarks><para>
 /// The formula for the result is <c>log(sum_(logProbs) p(logProbs) factor(sample,logProbs))</c>.
 /// </para></remarks>
 public static double LogAverageFactor(int sample, IList <double> logProbs)
 {
     if (logProbs.Count <= 1)
     {
         return(0);
     }
     return(logProbs[sample] - MMath.LogSumExp(logProbs));
 }
            /// <inheritdoc/>
            public double GetLogNormalizer()
            {
                if (Dictionary == null || Dictionary.Count == 0)
                {
                    return(double.NegativeInfinity);
                }

                return(MMath.LogSumExp(Dictionary.Values.Select(v => v.LogValue)));
            }
Пример #10
0
        private static void Normalize(double[] logProb)
        {
            double logSum = MMath.LogSumExp(logProb);

            for (int i = 0; i < logProb.Length; i++)
            {
                logProb[i] -= logSum;
            }
        }
Пример #11
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="DiscreteUniform"]/message_doc[@name="AverageLogFactor(Discrete, Discrete)"]/*'/>
        public static double AverageLogFactor(Discrete sample, Discrete size)
        {
            double logZ = Double.NegativeInfinity;

            for (int n = 1; n < size.Dimension; n++)
            {
                logZ = MMath.LogSumExp(logZ, AverageLogFactor(sample, n));
            }
            return(logZ);
        }
        /// <summary>
        /// Evidence message for EP
        /// </summary>
        /// <param name="sample">Constant value for 'sample'.</param>
        /// <param name="p">Incoming message from 'p'.</param>
        /// <param name="trialCount">Incoming message from 'trialCount'.</param>
        /// <returns>Logarithm of the factor's average value across the given argument distributions</returns>
        /// <remarks><para>
        /// The formula for the result is <c>log(sum_(p,trialCount) p(p,trialCount) factor(sample,trialCount,p))</c>.
        /// </para></remarks>
        public static double LogAverageFactor(int sample, Beta p, Discrete trialCount)
        {
            double logZ = Double.NegativeInfinity;

            for (int n = 0; n < trialCount.Dimension; n++)
            {
                logZ = MMath.LogSumExp(logZ, trialCount.GetLogProb(n) + LogAverageFactor(sample, p, n));
            }
            return(logZ);
        }
Пример #13
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="DoubleOp"]/message_doc[@name="LogAverageFactor(Gaussian, Discrete)"]/*'/>
        public static double LogAverageFactor(Gaussian Double, Discrete Integer)
        {
            double logZ = double.NegativeInfinity;

            for (int i = 0; i < Integer.Dimension; i++)
            {
                double logp = Double.GetLogProb(i) + Integer.GetLogProb(i);
                logZ = MMath.LogSumExp(logZ, logp);
            }
            return(logZ);
        }
 /// <summary>
 /// Computes the logarithm of the normalizer (sum of values of the weight function on all sequences)
 /// of the square of the current weight function.
 /// </summary>
 /// <returns>The logarithm of the normalizer.</returns>
 protected double GetLogNormalizerOfSquare()
 {
     if (Dictionary == null || Dictionary.Count == 0)
     {
         return(double.NegativeInfinity);
     }
     else
     {
         return(MMath.LogSumExp(Dictionary.Values.Select(v => 2 * v.LogValue)));
     }
 }
Пример #15
0
 /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GateExitOp{T}"]/message_doc[@name="ExitAverageConditional{TDist}(TDist, IList{Bernoulli}, IList{TDist}, TDist)"]/*'/>
 /// <typeparam name="TDist">The type of the distribution over the variable exiting the gate.</typeparam>
 public static TDist ExitAverageConditional2 <TDist>(
     TDist exit, IList <Bernoulli> cases, [SkipIfAllUniform] IList <TDist> values, TDist result)
     where TDist : SettableTo <TDist>, ICloneable, SettableToProduct <TDist>,
 SettableToRatio <TDist>, SettableToWeightedSum <TDist>
 {
     if (cases.Count != values.Count)
     {
         throw new ArgumentException("cases.Count != values.Count");
     }
     if (cases.Count == 0)
     {
         throw new ArgumentException("cases.Count == 0");
     }
     else if (cases.Count == 1)
     {
         result.SetTo(values[0]);
     }
     else
     {
         result.SetToProduct(exit, values[0]);
         double scale       = cases[0].LogOdds;
         double resultScale = scale;
         // TODO: use pre-allocated buffer
         TDist product = (TDist)exit.Clone();
         for (int i = 1; i < cases.Count; i++)
         {
             scale = cases[i].LogOdds;
             double shift = Math.Max(resultScale, scale);
             // avoid (-Infinity) - (-Infinity)
             if (Double.IsNegativeInfinity(shift))
             {
                 if (i == cases.Count - 1)
                 {
                     throw new AllZeroException();
                 }
                 // do nothing
             }
             else
             {
                 double weight1 = Math.Exp(resultScale - shift);
                 double weight2 = Math.Exp(scale - shift);
                 if (weight2 > 0)
                 {
                     product.SetToProduct(exit, values[i]);
                     result.SetToSum(weight1, result, weight2, product);
                     resultScale = MMath.LogSumExp(resultScale, scale);
                 }
             }
         }
         result.SetToRatio(result, exit, GateEnterOp <T> .ForceProper);
     }
     return(result);
 }
Пример #16
0
        //public double GetAverageLogOfComponent(TDist that)
        //{
        //    double sum = 0;
        //    double weightSum = 0;
        //    for (int i = 0; i < weights.Count; i++)
        //    {
        //        weightSum += weights[i];
        //        sum += weights[i]*components[i].GetAverageLog(that);
        //    }
        //    return sum/weightSum;
        //}

        public double GetLogProb(TDomain value)
        {
            double logProb   = double.NegativeInfinity;
            double weightSum = 0;

            for (int i = 0; i < weights.Count; i++)
            {
                weightSum += weights[i];
                logProb    = MMath.LogSumExp(logProb, System.Math.Log(weights[i]) + components[i].GetLogProb(value));
            }
            return(logProb - System.Math.Log(weightSum));
        }
 /// <summary>
 /// Evidence message for EP
 /// </summary>
 /// <param name="case0">Incoming message from 'case0'.</param>
 /// <param name="case1">Incoming message from 'case1'.</param>
 /// <param name="b">Incoming message from 'b'.</param>
 /// <returns>Logarithm of the factor's contribution the EP model evidence</returns>
 /// <remarks><para>
 /// The formula for the result is <c>log(sum_(case0,case1,b) p(case0,case1,b) factor(b,case0,case1))</c>.
 /// Adding up these values across all factors and variables gives the log-evidence estimate for EP.
 /// </para></remarks>
 public static double LogEvidenceRatio(Bernoulli case0, Bernoulli case1, Bernoulli b)
 {
     // result = log (p(data|b=true) p(b=true) + p(data|b=false) p(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 ? case0.LogOdds : case1.LogOdds);
     }
     else
     {
         return(MMath.LogSumExp(case0.LogOdds + b.GetLogProbTrue(), case1.LogOdds + b.GetLogProbFalse()));
     }
 }
        public static double LogAverageFactor <GaussianList>([SkipIfUniform] GaussianList list, GaussianList to_list, IndexOfMaximumBuffer[] Buffers, Discrete IndexOfMaximumDouble)
            where GaussianList : DistributionStructArray <Gaussian, double>
        {
            var evidences  = new double[list.Count];
            var tempBuffer = new IndexOfMaximumBuffer();

            for (int i = 0; i < list.Count; i++)
            {
                tempBuffer.to_list       = new DistributionStructArray <Gaussian, double>(list.Select(o => Gaussian.Uniform()).ToArray());
                tempBuffer.to_list[i]    = Buffers[i].MessagesToMax.Aggregate((p, q) => p * q);
                tempBuffer.MessagesToMax = new DistributionStructArray <Gaussian, double>(Buffers[i].MessagesToMax.Select(o => (Gaussian)o.Clone()).ToArray());
                evidences[i]             = IndexOfMaximumOp.LogAverageFactor(tempBuffer, list, i) + IndexOfMaximumDouble.GetLogProb(i);;
            }
            return(MMath.LogSumExp(evidences));
        }
 /// <summary>
 /// Evidence message for EP.
 /// </summary>
 /// <param name="cases">Incoming message from 'casesInt'.</param>
 public static double LogEvidenceRatio([SkipIfUniform] IList <Bernoulli> cases, Discrete i)
 {
     if (i.IsPointMass)
     {
         return(cases[i.Point].LogOdds);
     }
     else
     {
         double[] logOdds = new double[cases.Count];
         for (int j = 0; j < cases.Count; j++)
         {
             logOdds[j] = cases[j].LogOdds + i.GetLogProb(j);
         }
         return(MMath.LogSumExp(logOdds));
     }
 }
Пример #20
0
        /// <summary>
        /// Adds a weighted observation.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="logWeight"></param>
        public void Add(double x, double logWeight)
        {
            // new_mean = mean + w/(count + w)*(x - mean)
            // new_var = count/(count + w)*(var + w/(count+w)*(x-mean)*(x-mean)')
            LogCount = MMath.LogSumExp(LogCount, logWeight);
            if (double.IsNegativeInfinity(LogCount))
            {
                return;
            }
            double diff = x - Mean;
            double s    = System.Math.Exp(logWeight - LogCount);

            Mean     += s * diff;
            Variance += s * diff * diff;
            Variance  = (1 - s) * Variance;
        }
Пример #21
0
 /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GateExitOp{T}"]/message_doc[@name="ExitAverageConditional{TDist}(TDist, IList{Bernoulli}, IList{T}, TDist)"]/*'/>
 /// <typeparam name="TDist">The type of the distribution over the variable exiting the gate.</typeparam>
 public static TDist ExitAverageConditional <TDist>(
     TDist exit, IList <Bernoulli> cases, IList <T> values, TDist result)
     where TDist : ICloneable, HasPoint <T>, SettableToWeightedSum <TDist>
 {
     if (cases.Count != values.Count)
     {
         throw new ArgumentException("cases.Count != values.Count");
     }
     if (cases.Count == 0)
     {
         throw new ArgumentException("cases.Count == 0");
     }
     else if (cases.Count == 1)
     {
         result.Point = values[0];
     }
     else
     {
         result.Point = values[0];
         double scale       = cases[0].LogOdds;
         double resultScale = scale;
         // TODO: overload SetToSum to accept constants.
         TDist product = (TDist)exit.Clone();
         for (int i = 1; i < cases.Count; i++)
         {
             product.Point = values[i];
             scale         = cases[i].LogOdds;
             double shift = Math.Max(resultScale, scale);
             // avoid (-Infinity) - (-Infinity)
             if (Double.IsNegativeInfinity(shift))
             {
                 if (i == cases.Count - 1)
                 {
                     throw new AllZeroException();
                 }
                 // do nothing
             }
             else
             {
                 result.SetToSum(Math.Exp(resultScale - shift), result, Math.Exp(scale - shift), product);
                 resultScale = MMath.LogSumExp(resultScale, scale);
             }
         }
     }
     return(result);
 }
Пример #22
0
        public static void ComputeStats(Gaussian max, Gaussian a, Gaussian b, out double logz,
                                        out double logw1, out double logPhi1, out double logu1, out double vx1, out double mx1,
                                        out double logw2, out double logPhi2, out double logu2, out double vx2, out double mx2)
        {
            double mx, vx, ma, va, mb, vb;

            max.GetMeanAndVariance(out mx, out vx);
            a.GetMeanAndVariance(out ma, out va);
            b.GetMeanAndVariance(out mb, out vb);
            if (false)
            {
                vx1 = 1.0 / (1.0 / vx + 1.0 / va);
                mx1 = vx1 * (mx / vx + ma / va);
                vx2 = 1.0 / (1.0 / vx + 1.0 / vb);
                mx2 = vx2 * (mx / vx + mb / vb);
            }
            else
            {
                if (max.IsPointMass || a.IsPointMass || b.IsPointMass)
                {
                    throw new NotImplementedException();
                }
                vx1 = 1.0 / (max.Precision + a.Precision);
                mx1 = vx1 * (max.MeanTimesPrecision + a.MeanTimesPrecision);
                vx2 = 1.0 / (max.Precision + b.Precision);
                mx2 = vx2 * (max.MeanTimesPrecision + b.MeanTimesPrecision);
            }
            logw1   = max.GetLogAverageOf(a);
            logPhi1 = MMath.NormalCdfLn((mx1 - mb) / Math.Sqrt(vx1 + vb));
            logu1   = Gaussian.GetLogProb(mx1, mb, vx1 + vb);

            logw2   = max.GetLogAverageOf(b);
            logPhi2 = MMath.NormalCdfLn((mx2 - ma) / Math.Sqrt(vx2 + va));
            logu2   = Gaussian.GetLogProb(mx2, ma, vx2 + va);

            logz = MMath.LogSumExp(logw1 + logPhi1, logw2 + logPhi2);
        }
Пример #23
0
        // logz is the log-expectation of the factor value.
        // logw1 is the log-probability that max==a
        // exp(logw1) = N(mx;m1,vx+v1) phi((mx1 - m2)/sqrt(vx1+v2))
        // alpha1 is the correction to the mean of a due to b given that max==a
        // alpha1 = N(mx1;m2,vx1+v2)/phi
        // vx1 is the variance of a given that max==a (ignoring b)
        // mx1 is the mean of a given that max==a (ignoring b)
        internal static void ComputeStats(Gaussian max, Gaussian a, Gaussian b, out double logz,
                                          out double logw1, out double alpha1, out double vx1, out double mx1,
                                          out double logw2, out double alpha2, out double vx2, out double mx2)
        {
            double logPhi1, logPhi2;

            if (max.IsPointMass)
            {
                vx1 = 0.0;
                mx1 = max.Point;
                vx2 = 0.0;
                mx2 = max.Point;
                if (b.IsPointMass)
                {
                    if (b.Point > max.Point)
                    {
                        throw new AllZeroException();
                    }
                    else if (b.Point == max.Point)
                    {
                        // the factor reduces to the constraint (max.Point >= a)
                        if (a.IsPointMass)
                        {
                            if (a.Point > max.Point)
                            {
                                throw new AllZeroException();
                            }
                            if (a.Point == max.Point)
                            {
                                logw1  = -MMath.Ln2;
                                logw2  = -MMath.Ln2;
                                logz   = 0;
                                alpha1 = 0;
                                alpha2 = 0;
                                return;
                            }
                            else
                            {
                                logw2 = 0;
                            }
                        }
                        else if (a.Precision == 0)
                        {
                            logw1  = double.NegativeInfinity;
                            logw2  = -MMath.Ln2;
                            logz   = logw2;
                            alpha1 = 0;
                            alpha2 = 0;
                            return;
                        }
                        else
                        {
                            logw2 = MMath.NormalCdfLn((max.Point * a.Precision - a.MeanTimesPrecision) / Math.Sqrt(a.Precision));
                        }
                        logw1  = double.NegativeInfinity;
                        logz   = logw2;
                        alpha1 = 0;
                        alpha2 = Math.Exp(a.GetLogProb(max.Point) - logw2);
                        return;
                    }
                    else // b.Point < max.Point
                    {
                        // the factor reduces to the constraint (a == max.Point)
                        logw1  = a.GetLogProb(max.Point);
                        logw2  = double.NegativeInfinity;
                        logz   = logw1;
                        alpha1 = 0;
                        alpha2 = 0;
                        return;
                    }
                }
                else if (a.IsPointMass) // !b.IsPointMass
                {
                    if (a.Point > max.Point)
                    {
                        throw new AllZeroException();
                    }
                    else if (a.Point == max.Point)
                    {
                        // the factor reduces to the constraint (max.Point > b)
                        if (b.Precision == 0)
                        {
                            logw2  = double.NegativeInfinity;
                            logw1  = -MMath.Ln2;
                            logz   = logw1;
                            alpha1 = 0;
                            alpha2 = 0;
                            return;
                        }
                        else
                        {
                            logw1  = MMath.NormalCdfLn((max.Point * b.Precision - b.MeanTimesPrecision) / Math.Sqrt(b.Precision));
                            logw2  = double.NegativeInfinity;
                            logz   = logw1;
                            alpha2 = 0;
                            alpha1 = Math.Exp(b.GetLogProb(max.Point) - logw1);
                            return;
                        }
                    }
                    else // a.Point < max.Point
                    {
                        // the factor reduces to the constraint (b == max.Point)
                        logw2  = b.GetLogProb(max.Point);
                        logw1  = double.NegativeInfinity;
                        logz   = logw2;
                        alpha1 = 0;
                        alpha2 = 0;
                        return;
                    }
                }
                else // !a.IsPointMass && !b.IsPointMass
                {
                    double z1 = (mx1 * b.Precision - b.MeanTimesPrecision) / Math.Sqrt(b.Precision);
                    logPhi1 = MMath.NormalCdfLn(z1);
                    alpha1  = Math.Sqrt(b.Precision) / MMath.NormalCdfRatio(z1);
                    double z2 = (mx2 * a.Precision - a.MeanTimesPrecision) / Math.Sqrt(a.Precision);
                    logPhi2 = MMath.NormalCdfLn(z2);
                    alpha2  = Math.Sqrt(a.Precision) / MMath.NormalCdfRatio(z2);
                }
                // fall through
            }
            else // !max.IsPointMass
            {
                if (a.IsPointMass)
                {
                    vx1 = 0.0;
                    mx1 = a.Point;
                    if (b.IsPointMass)
                    {
                        vx2 = 0.0;
                        mx2 = b.Point;
                        if (a.Point > b.Point)
                        {
                            logw1 = max.GetLogAverageOf(a);
                            logw2 = double.NegativeInfinity;
                            logz  = logw1;
                        }
                        else if (a.Point < b.Point)
                        {
                            logw2 = max.GetLogAverageOf(b);
                            logw1 = double.NegativeInfinity;
                            logz  = logw2;
                        }
                        else // a.Point == b.Point
                        {
                            logw1  = -MMath.Ln2;
                            logw2  = -MMath.Ln2;
                            logz   = 0;
                            alpha1 = double.PositiveInfinity;
                            alpha2 = double.PositiveInfinity;
                            return;
                        }
                        alpha1 = 0;
                        alpha2 = 0;
                        return;
                    }
                    double z1 = (a.Point * b.Precision - b.MeanTimesPrecision) / Math.Sqrt(b.Precision);
                    logPhi1 = MMath.NormalCdfLn(z1);
                    alpha1  = Math.Sqrt(b.Precision) / MMath.NormalCdfRatio(z1);
                }
                else // !a.IsPointMass
                {
                    vx1 = 1.0 / (max.Precision + a.Precision);
                    mx1 = vx1 * (max.MeanTimesPrecision + a.MeanTimesPrecision);
                    double m2, v2;
                    b.GetMeanAndVariance(out m2, out v2);
                    double s = Math.Sqrt(vx1 + v2);
                    // This approach is more accurate for large max.Precision
                    double z1 = (max.MeanTimesPrecision + a.MeanTimesPrecision - m2 * (max.Precision + a.Precision)) * vx1 / s;
                    logPhi1 = MMath.NormalCdfLn(z1);
                    alpha1  = 1 / (s * MMath.NormalCdfRatio(z1));
                }
                if (b.IsPointMass)
                {
                    vx2 = 0.0;
                    mx2 = b.Point;
                    double z2 = (b.Point * a.Precision - a.MeanTimesPrecision) / Math.Sqrt(a.Precision);
                    logPhi2 = MMath.NormalCdfLn(z2);
                    alpha2  = Math.Sqrt(a.Precision) / MMath.NormalCdfRatio(z2);
                }
                else // !b.IsPointMass
                {
                    vx2 = 1.0 / (max.Precision + b.Precision);
                    mx2 = vx2 * (max.MeanTimesPrecision + b.MeanTimesPrecision);
                    double m1, v1;
                    a.GetMeanAndVariance(out m1, out v1);
                    double s = Math.Sqrt(vx2 + v1);
                    // This approach is more accurate for large max.Precision
                    double z2 = (max.MeanTimesPrecision + b.MeanTimesPrecision - m1 * (max.Precision + b.Precision)) * vx2 / s;
                    logPhi2 = MMath.NormalCdfLn(z2);
                    //double logPhi2b = MMath.NormalCdfLn((mx2 - m1) / Math.Sqrt(vx2 + v1));
                    alpha2 = 1 / (s * MMath.NormalCdfRatio(z2));
                }
            }
            // !(max.IsPointMass && a.IsPointMass)
            // !(max.IsPointMass && b.IsPointMass)
            // !(a.IsPointMass && b.IsPointMass)
            logw1  = max.GetLogAverageOf(a);
            logw1 += logPhi1;

            logw2  = max.GetLogAverageOf(b);
            logw2 += logPhi2;

            logz = MMath.LogSumExp(logw1, logw2);
        }
Пример #24
0
 /// <summary>
 /// Compute the sum of given weights.
 /// </summary>
 /// <param name="weight1">The first weight.</param>
 /// <param name="weight2">The second weight.</param>
 /// <returns>The computed sum.</returns>
 public static Weight Sum(Weight weight1, Weight weight2)
 {
     return(new Weight(MMath.LogSumExp(weight1.LogValue, weight2.LogValue)));
 }
Пример #25
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="BeliefPropagationGateEnterPartialOp"]/message_doc[@name="ValueAverageConditional{TDist}(IList{TDist}, Discrete, TDist, int[], TDist)"]/*'/>
        /// <typeparam name="TDist">The type of the distribution over the variable entering the gate.</typeparam>
        public static TDist ValueAverageConditional <TDist>(
            [SkipIfUniform] IList <TDist> enterPartial, [SkipIfUniform] Discrete selector, TDist value, int[] indices, TDist result)
            where TDist : ICloneable, SettableToUniform, SettableTo <TDist>, SettableToWeightedSum <TDist>, CanGetLogAverageOf <TDist>, CanGetLogNormalizer
        {
            if (enterPartial == null)
            {
                throw new ArgumentNullException(nameof(enterPartial));
            }

            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            if (indices == null)
            {
                throw new ArgumentNullException(nameof(indices));
            }

            if (indices.Length != enterPartial.Count)
            {
                throw new ArgumentException("indices.Length != enterPartial.Count");
            }

            if (selector.Dimension < enterPartial.Count)
            {
                throw new ArgumentException("selector.Dimension < enterPartial.Count");
            }

            if (indices.Length == 0)
            {
                throw new ArgumentException("indices.Length == 0");
            }

            // TODO: use pre-allocated buffers
            double logProbSum   = selector.GetLogProb(indices[0]);
            double logWeightSum = logProbSum;

            if (!double.IsNegativeInfinity(logWeightSum))
            {
                // Subtract to avoid double-counting since selector already contains this quantity
                // See IntCasesOp.IAverageConditional
                double logAverage = enterPartial[0].GetLogAverageOf(value);
                if (!double.IsNegativeInfinity(logAverage))
                {
                    logWeightSum -= logAverage;
                    result.SetTo(enterPartial[0]);
                }
            }

            if (indices.Length > 1)
            {
                for (int i = 1; i < indices.Length; i++)
                {
                    double logProb = selector.GetLogProb(indices[i]);
                    logProbSum = MMath.LogSumExp(logProbSum, logProb);
                    double shift = Math.Max(logWeightSum, logProb);

                    // Avoid (-Infinity) - (-Infinity)
                    if (double.IsNegativeInfinity(shift))
                    {
                        if (i == selector.Dimension - 1)
                        {
                            throw new AllZeroException();
                        }

                        // Do nothing
                    }
                    else
                    {
                        double logWeightShifted = logProb - shift;
                        if (!double.IsNegativeInfinity(logWeightShifted))
                        {
                            double logAverage = enterPartial[i].GetLogAverageOf(value);
                            if (!double.IsNegativeInfinity(logAverage))
                            {
                                logWeightShifted -= logAverage;
                                result.SetToSum(Math.Exp(logWeightSum - shift), result, Math.Exp(logWeightShifted), enterPartial[i]);
                                logWeightSum = MMath.LogSumExp(logWeightSum, logWeightShifted + shift);
                            }
                        }
                    }
                }
            }

            if (indices.Length < selector.Dimension)
            {
                double logProb = MMath.Log1MinusExp(logProbSum);
                double shift   = Math.Max(logWeightSum, logProb);
                if (double.IsNegativeInfinity(shift))
                {
                    throw new AllZeroException();
                }

                var uniform = (TDist)result.Clone();
                uniform.SetToUniform();
                double logWeight = logProb + uniform.GetLogNormalizer();
                result.SetToSum(Math.Exp(logWeightSum - shift), result, Math.Exp(logWeight - shift), uniform);
            }

            return(result);
        }
Пример #26
0
        /// <summary>
        /// Computes log(sum_{x=0..infinity} x^p lambda^x / x!^nu)
        /// </summary>
        /// <param name="lambda">Rate.</param>
        /// <param name="nu">Precision.</param>
        /// <param name="p">Exponent.</param>
        /// <returns></returns>
        public static double GetLogPowerSum(double lambda, double nu, double p)
        {
            if (p == 0)
            {
                return(GetLogNormalizer(lambda, nu));
            }
            if (lambda < 0)
            {
                throw new ArgumentException("lambda (" + lambda + ") < 0");
            }
            if (lambda == 0 || nu < 0)
            {
                return(0.0);
            }
            if (Double.IsPositiveInfinity(nu))
            {
                throw new ArgumentException("nu = Inf");
            }
            double lambda_ln = Math.Log(lambda);
            double result    = lambda_ln; // start off with first two terms (p != 0)
            double term      = lambda_ln;

            if (nu == 1)
            {
                if (p == 1)
                {
                    return(lambda + lambda_ln);        // log(sum x*lambda^x/x!) = log(lambda*exp(lambda))
                }
                else if (p == 2)
                {
                    return(lambda + lambda_ln + Math.Log(1 + lambda));             // log(sum x^2*lambda^x/x!) = log(lambda+lambda^2)+lambda
                }
            }
            else if (nu == 0)
            {
                if (lambda >= 1)
                {
                    return(0.0);
                }
                if (p == 1)
                {
                    return(lambda_ln - 2 * Math.Log(1 - lambda));
                }
                else if (p == 2)
                {
                    return(lambda_ln + Math.Log(1 + lambda) - 3 * Math.Log(1 - lambda));
                }
            }
            int i = 2;

            for (; i < maxiter; i++)
            {
                double delta = lambda_ln - nu * Math.Log(i) + p * Math.Log((double)i / (i - 1));
                term  += delta;
                result = MMath.LogSumExp(result, term);
                if (delta < 0)
                {
                    /* truncation error */
                    double r = Math.Exp(term - result) / (1 - Math.Exp(delta));
                    /* truncation error in log domain */
                    /* log(z+r)-log(z) = log(1 + r/z) =approx r/z */
                    if (r < tol)
                    {
                        break;
                    }
                }
            }
            if (i == maxiter)
            {
                double r = Math.Pow(lambda, 1 / nu);
                if (r > 10 && p == 1)
                {
                    /* use asymptotic approximation */
                    result = nu * r - (nu - 1) / 2 / nu * lambda_ln - (nu - 1) * MMath.LnSqrt2PI - 0.5 * Math.Log(nu);
                    result = result + Math.Log(r - (nu - 1) / 2 / nu);
                    i      = 0;
                }
            }
            return(result);
        }
Пример #27
0
        /// <summary>EP message to <c>exit</c>.</summary>
        /// <param name="cases">Incoming message from <c>cases</c>.</param>
        /// <param name="values">Incoming message from <c>values</c>. Must be a proper distribution. If any element is uniform, the result will be uniform.</param>
        /// <param name="result">Modified to contain the outgoing message.</param>
        /// <returns>
        ///   <paramref name="result" />
        /// </returns>
        /// <remarks>
        ///   <para>The outgoing message is a distribution matching the moments of <c>exit</c> as the random arguments are varied. The formula is <c>proj[p(exit) sum_(cases,values) p(cases,values) factor(exit,cases,values)]/p(exit)</c>.</para>
        /// </remarks>
        /// <exception cref="ImproperMessageException">
        ///   <paramref name="values" /> is not a proper distribution.</exception>
        /// <typeparam name="TDist">The type of the distribution over the variable exiting the gate.</typeparam>
        public static TDist ExitAverageConditional <TDist>(IList <Bernoulli> cases, [SkipIfUniform] IList <TDist> values, TDist result)
            where TDist : SettableTo <TDist>, SettableToWeightedSum <TDist>
        {
            if (cases == null)
            {
                throw new ArgumentNullException("cases");
            }

            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            if (cases.Count != values.Count)
            {
                throw new ArgumentException("cases.Count != values.Count");
            }

            if (cases.Count == 0)
            {
                throw new ArgumentException("cases.Count == 0");
            }

            if (cases.Count == 1)
            {
                result.SetTo(values[0]);
            }
            else
            {
                double logResultProb = cases[0].LogOdds;
                if (double.IsNaN(logResultProb))
                {
                    throw new AllZeroException();
                }

                // TODO: use pre-allocated buffer
                int resultIndex = 0;
                for (int i = 1; i < cases.Count; i++)
                {
                    double logProb = cases[i].LogOdds;
                    double shift   = Math.Max(logResultProb, logProb);

                    // Avoid (-Infinity) - (-Infinity)
                    if (double.IsNegativeInfinity(shift))
                    {
                        if (i == cases.Count - 1)
                        {
                            throw new AllZeroException();
                        }

                        // Do nothing
                    }
                    else
                    {
                        double weight1 = Math.Exp(logResultProb - shift);
                        double weight2 = Math.Exp(logProb - shift);
                        if (weight2 > 0)
                        {
                            if (weight1 == 0)
                            {
                                resultIndex   = i;
                                logResultProb = logProb;
                            }
                            else
                            {
                                if (resultIndex >= 0)
                                {
                                    result.SetTo(values[resultIndex]);
                                    resultIndex = -1;
                                }

                                result.SetToSum(weight1, result, weight2, values[i]);
                                logResultProb = MMath.LogSumExp(logResultProb, logProb);
                            }
                        }
                    }
                }

                if (resultIndex >= 0)
                {
                    // result is simply values[resultIndex]
                    return(values[resultIndex]);
                }
            }

            return(result);
        }
Пример #28
0
        /// <summary>EP message to <c>value</c>.</summary>
        /// <param name="enterPartial">Incoming message from <c>enterPartial</c>. Must be a proper distribution. If any element is uniform, the result will be uniform.</param>
        /// <param name="selector">Incoming message from <c>selector</c>. Must be a proper distribution. If uniform, the result will be uniform.</param>
        /// <param name="value">Incoming message from <c>value</c>.</param>
        /// <param name="indices">Constant value for <c>indices</c>.</param>
        /// <param name="result">Modified to contain the outgoing message.</param>
        /// <returns>
        ///   <paramref name="result" />
        /// </returns>
        /// <remarks>
        ///   <para>The outgoing message is a distribution matching the moments of <c>value</c> as the random arguments are varied. The formula is <c>proj[p(value) sum_(enterPartial,selector) p(enterPartial,selector) factor(enterPartial,selector,value,indices)]/p(value)</c>.</para>
        /// </remarks>
        /// <exception cref="ImproperMessageException">
        ///   <paramref name="enterPartial" /> is not a proper distribution.</exception>
        /// <exception cref="ImproperMessageException">
        ///   <paramref name="selector" /> is not a proper distribution.</exception>
        /// <typeparam name="TDist">The type of the distribution over the variable entering the gate.</typeparam>
        public static TDist ValueAverageConditional <TDist>(
            [SkipIfUniform] IList <TDist> enterPartial, [SkipIfUniform] Bernoulli selector, TDist value, int[] indices, TDist result)
            where TDist : ICloneable, SettableToUniform, SettableTo <TDist>, SettableToWeightedSum <TDist>, CanGetLogAverageOf <TDist>, CanGetLogNormalizer
        {
            if (enterPartial == null)
            {
                throw new ArgumentNullException("enterPartial");
            }

            if (indices == null)
            {
                throw new ArgumentNullException("indices");
            }

            if (indices.Length != enterPartial.Count)
            {
                throw new ArgumentException("indices.Length != enterPartial.Count");
            }

            if (2 < enterPartial.Count)
            {
                throw new ArgumentException("enterPartial.Count should be 2 or 1");
            }

            if (indices.Length == 0)
            {
                throw new ArgumentException("indices.Length == 0");
            }

            // TODO: use pre-allocated buffers
            double logProbSum   = (indices[0] == 0) ? selector.GetLogProbTrue() : selector.GetLogProbFalse();
            double logWeightSum = logProbSum;

            if (!double.IsNegativeInfinity(logProbSum))
            {
                logWeightSum -= enterPartial[0].GetLogAverageOf(value);
                result.SetTo(enterPartial[0]);
            }

            if (indices.Length > 1)
            {
                for (int i = 1; i < indices.Length; i++)
                {
                    double logProb = (indices[i] == 0) ? selector.GetLogProbTrue() : selector.GetLogProbFalse();
                    logProbSum += logProb;
                    double shift = Math.Max(logWeightSum, logProb);

                    // Avoid (-Infinity) - (-Infinity)
                    if (double.IsNegativeInfinity(shift))
                    {
                        if (i == 1)
                        {
                            throw new AllZeroException();
                        }

                        // Do nothing
                    }
                    else
                    {
                        double logWeightShifted = logProb - shift;
                        if (!double.IsNegativeInfinity(logWeightShifted))
                        {
                            logWeightShifted -= enterPartial[i].GetLogAverageOf(value);
                            result.SetToSum(Math.Exp(logWeightSum - shift), result, Math.Exp(logWeightShifted), enterPartial[i]);
                            logWeightSum = MMath.LogSumExp(logWeightSum, logWeightShifted + shift);
                        }
                    }
                }
            }

            if (indices.Length < 2)
            {
                double logProb = MMath.Log1MinusExp(logProbSum);
                double shift   = Math.Max(logWeightSum, logProb);
                if (double.IsNegativeInfinity(shift))
                {
                    throw new AllZeroException();
                }

                var uniform = (TDist)result.Clone();
                uniform.SetToUniform();
                double logWeight = logProb + uniform.GetLogNormalizer();
                result.SetToSum(Math.Exp(logWeightSum - shift), result, Math.Exp(logWeight - shift), uniform);
            }

            return(result);
        }
Пример #29
0
        private static double NormalCdfLn_Quadrature(double x, double y, double r)
        {
            double absr = System.Math.Abs(r);
            Vector nodes, weights;
            int    count = 20;

            if (absr < 0.3)
            {
                count = 6;
            }
            else if (absr < 0.75)
            {
                count = 12;
            }
            nodes   = Vector.Zero(count);
            weights = Vector.Zero(count);
            // hasInfiniteLimit is true if NormalCdf(x,y,-1) is 0
            bool hasInfiniteLimit = false;

            if (r < -0.5)
            {
                if (x > 0)
                {
                    // NormalCdf(y) <= NormalCdf(-x)  iff y <= -x
                    if (y < 0)
                    {
                        hasInfiniteLimit = (y <= -x);
                    }
                }
                else
                {
                    // NormalCdf(x) <= NormalCdf(-y) iff x <= -y
                    if (y > 0)
                    {
                        hasInfiniteLimit = (x <= -y);
                    }
                    else
                    {
                        hasInfiniteLimit = true;
                    }
                }
            }
            if (absr < 0.925 && !hasInfiniteLimit)
            {
                // use equation (3)
                double asinr = System.Math.Asin(r);
                Quadrature.UniformNodesAndWeights(0, asinr, nodes, weights);
                double sq = 0.5 * (x * x + y * y), xy = x * y;
                double logResult     = double.NegativeInfinity;
                bool   useLogWeights = true;
                if (useLogWeights)
                {
                    for (int i = 0; i < nodes.Count; i++)
                    {
                        double sin  = System.Math.Sin(nodes[i]);
                        double cos2 = 1 - sin * sin;
                        logResult = MMath.LogSumExp(logResult, System.Math.Log(System.Math.Abs(weights[i])) + (xy * sin - sq) / cos2);
                    }
                    logResult -= 2 * MMath.LnSqrt2PI;
                }
                else
                {
                    double result = 0.0;
                    for (int i = 0; i < nodes.Count; i++)
                    {
                        double sin  = System.Math.Sin(nodes[i]);
                        double cos2 = 1 - sin * sin;
                        result += weights[i] * System.Math.Exp((xy * sin - sq) / cos2);
                    }
                    result   /= 2 * System.Math.PI;
                    logResult = System.Math.Log(System.Math.Abs(result));
                }
                double r0 = MMath.NormalCdfLn(x, y, 0);
                if (asinr > 0)
                {
                    return(MMath.LogSumExp(r0, logResult));
                }
                else
                {
                    return(MMath.LogDifferenceOfExp(r0, logResult));
                }
            }
            else
            {
                double result = 0.0;
                double sy     = (r < 0) ? -y : y;
                if (absr < 1)
                {
                    // use equation (6) modified by (7)
                    // quadrature part
                    double cos2asinr = (1 - r) * (1 + r), sqrt1mrr = System.Math.Sqrt(cos2asinr);
                    Quadrature.UniformNodesAndWeights(0, sqrt1mrr, nodes, weights);
                    double sxy = x * sy;
                    double diff2 = (x - sy) * (x - sy);
                    double c = (4 - sxy) / 8, d = (12 - sxy) / 16;
                    for (int i = 0; i < nodes.Count; i++)
                    {
                        double cos2     = nodes[i] * nodes[i];
                        double sin      = System.Math.Sqrt(1 - cos2);
                        double series   = 1 + c * cos2 * (1 + d * cos2);
                        double exponent = -0.5 * (diff2 / cos2 + sxy);
                        double f        = System.Math.Exp(-0.5 * sxy * (1 - sin) / (1 + sin)) / sin;
                        result += weights[i] * System.Math.Exp(exponent) * (f - series);
                    }
                    // Taylor expansion part
                    double exponentr = -0.5 * (diff2 / cos2asinr + sxy);
                    double absdiff   = System.Math.Sqrt(diff2);
                    if (exponentr > -800)
                    {
                        double taylor = sqrt1mrr * (1 - c * (diff2 - cos2asinr) * (1 - d * diff2 / 5) / 3 + c * d * cos2asinr * cos2asinr / 5);
                        // avoid 0*Inf problems
                        //result -= Math.Exp(-0.5*sxy + NormalCdfLn(-absdiff/sqrt1mrr))*absdiff*(1 - c*diff2*(1 - d*diff2/5)/3)*Sqrt2PI;
                        taylor -= MMath.NormalCdfRatio(-absdiff / sqrt1mrr) * absdiff * (1 - c * diff2 * (1 - d * diff2 / 5) / 3);
                        result += System.Math.Exp(exponentr) * taylor;
                    }
                    result /= -2 * System.Math.PI;
                }
                if (r > 0)
                {
                    // result += NormalCdf(x, y, 1);
                    double r1 = MMath.NormalCdfLn(x, y, 1);
                    if (result > 0)
                    {
                        result = System.Math.Log(result);
                        return(MMath.LogSumExp(result, r1));
                    }
                    else
                    {
                        return(MMath.LogDifferenceOfExp(r1, System.Math.Log(-result)));
                    }
                }
                else
                {
                    // return NormalCdf(x, y, -1) - result;
                    double r1 = MMath.NormalCdfLn(x, y, -1);
                    if (result > 0)
                    {
                        return(MMath.LogDifferenceOfExp(r1, System.Math.Log(result)));
                    }
                    else
                    {
                        return(MMath.LogSumExp(r1, System.Math.Log(-result)));
                    }
                }
            }
        }
Пример #30
0
        /// <summary>
        /// Set this distribution equal to the approximate product of a and b
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <remarks>
        /// Since WrappedGaussians are not closed under multiplication, the result is approximate.
        /// </remarks>
        public void SetToProduct(WrappedGaussian a, WrappedGaussian b)
        {
            if (a.Period < b.Period)
            {
                SetToProduct(b, a);
                return;
            }
            // a.Period >= b.Period
            if (a.IsUniform())
            {
                SetTo(b);
                return;
            }
            if (b.IsUniform())
            {
                SetTo(a);
                return;
            }
            if (a.IsPointMass)
            {
                if (b.IsPointMass && !a.Point.Equals(b.Point))
                {
                    throw new AllZeroException();
                }
                Point = a.Point;
                return;
            }
            if (b.IsPointMass)
            {
                Point = b.Point;
                return;
            }
            // (a,b) are not uniform or point mass
            double ratio    = a.Period / b.Period;
            int    intRatio = (int)Math.Round(ratio);

            if (Math.Abs(ratio - intRatio) > a.Period * 1e-4)
            {
                throw new ArgumentException("a.Period (" + a.Period + ") is not a multiple of b.Period (" + b.Period + ")");
            }
            this.Period = a.Period;
            // a.Period = k*b.Period, k >= 1
            // because one period is a multiple of the other, we only need to sum over one set of shifts.
            // otherwise, we would need to sum over two sets of shifts.
            double ma, va, mb, vb;

            a.Gaussian.GetMeanAndVariance(out ma, out va);
            b.Gaussian.GetMeanAndVariance(out mb, out vb);
            double diff = (ma - mb) / b.Period;

#if true
            // approximate using only the one best shift
            int      k        = (int)Math.Round(diff);
            Gaussian bShifted = new Gaussian(mb + k * b.Period, vb);
            Gaussian.SetToProduct(a.Gaussian, bShifted);
#else
            // we will sum over shifts from kMin to kMax, numbering intRatio in total
            int kMin, kMax;
            if (intRatio % 2 == 1)
            {
                // odd number of shifts
                int kMid      = (int)Math.Round(diff);
                int halfRatio = intRatio / 2;
                kMin = kMid - halfRatio;
                kMax = kMid + halfRatio;
            }
            else
            {
                // even number of shifts
                int kMid      = (int)Math.Floor(diff);
                int halfRatio = intRatio / 2;
                kMin = kMid - halfRatio + 1;
                kMax = kMid + halfRatio;
            }
            if (kMax - kMin != intRatio - 1)
            {
                throw new InferRuntimeException("kMax - kMin != intRatio-1");
            }
            // exclude shifts that are too far away
            double sa         = Math.Sqrt(va + vb);
            double lowerBound = ma - 5 * sa;
            double upperBound = ma + 5 * sa;
            // find the largest k such that (mb + k*Lb <= lowerBound)
            double kLower = Math.Floor((lowerBound - mb) / b.Period);
            if (kLower > kMin)
            {
                kMin = (int)kLower;
            }
            // find the smallest k such that (mb + k*Lb >= upperBound)
            double kUpper = Math.Ceiling((upperBound - mb) / b.Period);
            if (kUpper < kMax)
            {
                kMax = (int)kUpper;
            }
            if (kMax - kMin > 100)
            {
                throw new InferRuntimeException("kMax - kMin = " + (kMax - kMin));
            }
            double totalWeight = Double.NegativeInfinity;
            for (int k = kMin; k <= kMax; k++)
            {
                Gaussian bShifted = new Gaussian(mb + k * b.Period, vb);
                Gaussian product  = a.Gaussian * bShifted;
                double   weight   = a.Gaussian.GetLogAverageOf(bShifted);
                if (double.IsNegativeInfinity(totalWeight))
                {
                    Gaussian.SetTo(product);
                    totalWeight = weight;
                }
                else
                {
                    Gaussian.SetToSum(1.0, Gaussian, Math.Exp(weight - totalWeight), product);
                    totalWeight = MMath.LogSumExp(totalWeight, weight);
                }
            }
#endif
            if (double.IsNaN(Gaussian.MeanTimesPrecision))
            {
                throw new InferRuntimeException("result is nan");
            }
            Normalize();
        }