示例#1
0
 public void NormalCdf2Test4()
 {
     for (int j = 8; j <= 17; j++)
     {
         double r        = -1 + System.Math.Pow(10, -j);
         double expected = System.Math.Log(NormalCdfZero(r));
         for (int i = 5; i < 100; i++)
         {
             double x      = -System.Math.Pow(10, -i);
             double y      = -x;
             double actual = MMath.NormalCdfLn(x, y, r);
             //double actual = Math.Log(NormalCdfConFrac3(x, y, r));
             double error;
             if (actual == expected)
             {
                 error = 0;
             }
             else
             {
                 error = System.Math.Abs(actual - expected);
             }
             //Console.WriteLine($"NormalCdfLn({x},{y},{r}) = {actual}, error = {error}");
             Assert.True(error < 1e-9);
         }
     }
 }
        /// <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
        }
示例#3
0
        private double NormalCdfIntegralTaylor(double x, double y, double r)
        {
            double omr2     = 1 - r * r;
            double sqrtomr2 = System.Math.Sqrt(omr2);
            double ymrx     = y / sqrtomr2;
            double dx0      = MMath.NormalCdf(0, y, r);
            double ddx0     = System.Math.Exp(Gaussian.GetLogProb(0, 0, 1) + MMath.NormalCdfLn(ymrx));
            // \phi_{xx} &= -x \phi_x - r \phi_r
            double dddx0 = -r *System.Math.Exp(Gaussian.GetLogProb(0, 0, 1) + Gaussian.GetLogProb(ymrx, 0, 1));

            Trace.WriteLine($"dx0 = {dx0} {ddx0} {dddx0}");
            return(MMath.NormalCdfIntegral(0, y, r) + x * dx0 + 0.5 * x * x * ddx0 + 1.0 / 6 * x * x * x * dddx0);
        }
示例#4
0
        public static double NormalCdfDx(double x, double y, double r)
        {
            double omr2 = 1 - r * r;

            if (omr2 == 0)
            {
                return(NormalCdfMomentDy(0, y, x, r));
            }
            else
            {
                return(System.Math.Exp(Gaussian.GetLogProb(x, 0, 1)
                                       + MMath.NormalCdfLn((y - r * x) / System.Math.Sqrt(omr2))));
            }
        }
示例#5
0
        private double NormalCdfIntegralBasic(double x, double y, double r)
        {
            double omr2     = 1 - r * r;
            double sqrtomr2 = System.Math.Sqrt(omr2);
            double ymrx     = (y - r * x) / sqrtomr2;
            double xmry     = (x - r * y) / sqrtomr2;
            // should use this whenever x > 0 and Rymrx >= Rxmry (y-r*x >= x-r*y implies y*(1+r) >= x*(1+r) therefore y >= x)
            // we need a special routine to compute 2nd half without cancellation and without dividing by phir
            // what about x > y > 0?
            //double t = MMath.NormalCdfIntegral(-x, y, -r) + x * MMath.NormalCdf(y) + r * System.Math.Exp(Gaussian.GetLogProb(y, 0, 1));
            //Console.WriteLine(t);
            double phix = System.Math.Exp(Gaussian.GetLogProb(x, 0, 1) + MMath.NormalCdfLn(ymrx));
            double phiy = System.Math.Exp(Gaussian.GetLogProb(y, 0, 1) + MMath.NormalCdfLn(xmry));

            //Trace.WriteLine($"phix = {phix} phiy = {phiy}");
            return(x * MMath.NormalCdf(x, y, r) + phix + r * phiy);
            //return y * MMath.NormalCdf(x, y, r) + r * System.Math.Exp(Gaussian.GetLogProb(x, 0, 1) + MMath.NormalCdfLn(ymrx)) + System.Math.Exp(Gaussian.GetLogProb(y, 0, 1) + MMath.NormalCdfLn(xmry));
        }
示例#6
0
        // r psi_0
        public static double NormalCdfConFrac4(double x, double y, double r)
        {
            if (r * (y - r * x) < 0)
            {
                throw new ArgumentException("r*(y - r*x) < 0");
            }
            if (x - r * y > 0)
            {
                throw new ArgumentException("x - r*y > 0");
            }
            double omr2      = 1 - r * r;
            double rxmy      = r * x - y;
            double numer     = omr2 * (System.Math.Exp(MMath.NormalCdfLn(x) + Gaussian.GetLogProb(y, r * x, omr2)) - NormalCdfMomentDy(0, x, y, r));
            double numerPrev = 0;
            double denom     = rxmy;
            double denomPrev = 1;
            double rOld      = 0;
            double result    = 0;

            for (int i = 1; i < 1000; i++)
            {
                double numerNew = rxmy * numer + omr2 * (i * numerPrev - System.Math.Pow(r, i) * NormalCdfMomentDy(i, x, y, r));
                double denomNew = rxmy * denom + omr2 * i * denomPrev;
                numerPrev = numer;
                numer     = numerNew;
                denomPrev = denom;
                denom     = denomNew;
                result    = -numer / denom;
                Console.WriteLine("iter {0}: {1}", i, result.ToString("r"));
                if (double.IsInfinity(result) || double.IsNaN(result))
                {
                    throw new Exception(string.Format("NormalCdfConFrac4 not converging for x={0} y={1} r={2}", x, y, r));
                }
                if (result == rOld)
                {
                    return(result);
                }
                rOld = result;
            }
            return(result);

            throw new Exception("not converging");
        }
示例#7
0
        public static double NormalCdfAlt2(double x, double y, double r)
        {
            double omr2      = 1 - r * r;
            double diff      = (y - r * x) / System.Math.Sqrt(omr2);
            double logOffset = MMath.NormalCdfLn(x) + MMath.NormalCdfLn(diff);
            double psi       = NormalCdfBrute2(0, x, y, r);

            Console.WriteLine("psi = {0}", psi);
            bool verbose = false;

            if (verbose)
            {
                double special = System.Math.Exp(MMath.NormalCdfLn(x) + Gaussian.GetLogProb(y, r * x, omr2));
                double psi2    = omr2 / r * (NormalCdfMomentDy(0, x, y, r) - special) / (r * x - y);
                Console.WriteLine("{0} approx {1}", psi, psi2);
                double psi1 = NormalCdfBrute2(1, x, y, r);
                Console.WriteLine("{0} {1}", r * psi1, (r * x - y) * psi + omr2 / r * (special - NormalCdfMomentDy(0, x, y, r)));
                Console.WriteLine("{0} {1}", NormalCdfMomentDy(0, x, y, r) + r / omr2 * ((y - r * x) * psi + r * psi1), special);
            }
            return(System.Math.Exp(logOffset) + r * psi);
        }
示例#8
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);
        }
示例#9
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);
        }
示例#10
0
        // computes psi_n
        public static double NormalCdfBrute2(int n, double x, double y, double r)
        {
            int    nSamples = 1000000;
            double tMax     = 20;
            double inc      = tMax / nSamples;
            double sum      = 0;
            double f0       = 0;
            double omr2     = 1 - r * r;
            double s        = System.Math.Sqrt(omr2);

            for (int i = 0; i < nSamples; i++)
            {
                double t    = (i + 1) * inc;
                double diff = (y - r * (x - t)) / s;
                double f    = System.Math.Pow(t, n) * System.Math.Exp(-0.5 * diff * diff + MMath.NormalCdfLn(x - t));
                if (i == 0)
                {
                    f0 = f;
                }
                if (i == nSamples - 1)
                {
                    if (f > f0 * 1e-20)
                    {
                        throw new Exception();
                    }
                }
                sum += f;
            }
            return(sum * inc / MMath.Sqrt2PI / s);
        }
示例#11
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)));
                    }
                }
            }
        }
示例#12
0
        /// <summary>
        /// Computes the cumulative bivariate normal distribution.
        /// </summary>
        /// <param name="x">First upper limit.  Must be finite.</param>
        /// <param name="y">Second upper limit.  Must be finite.</param>
        /// <param name="r">Correlation coefficient.</param>
        /// <returns><c>phi(x,y,r)</c></returns>
        /// <remarks>
        /// The double integral is transformed into a single integral which is approximated by quadrature.
        /// Reference:
        /// "Numerical Computation of Rectangular Bivariate and Trivariate Normal and t Probabilities"
        /// Alan Genz, Statistics and Computing, 14 (2004), pp. 151-160
        /// http://www.math.wsu.edu/faculty/genz/genzhome/research.html
        /// </remarks>
        private static double NormalCdf_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);
            double result = 0.0;

            if (absr < 0.925)
            {
                // 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;
                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;
                result += MMath.NormalCdf(x, y, 0);
            }
            else
            {
                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)
                    {
                        // avoid 0*Inf problems
                        result += sqrt1mrr * System.Math.Exp(exponentr) * (1 - c * (diff2 - cos2asinr) * (1 - d * diff2 / 5) / 3 + c * d * cos2asinr * cos2asinr / 5);
                        // for large absdiff, NormalCdfLn(-absdiff / sqrt1mrr) =approx -0.5*diff2/cos2asinr
                        // so (-0.5*sxy + NormalCdfLn) =approx exponentr
                        result -= System.Math.Exp(-0.5 * sxy + MMath.NormalCdfLn(-absdiff / sqrt1mrr)) * absdiff * (1 - c * diff2 * (1 - d * diff2 / 5) / 3) * MMath.Sqrt2PI;
                    }
                    result /= -2 * System.Math.PI;
                }
                if (r > 0)
                {
                    // exact value for r=1
                    result += MMath.NormalCdf(x, y, 1);
                }
                else
                {
                    // exact value for r=-1
                    result  = -result;
                    result += MMath.NormalCdf(x, y, -1);
                }
            }
            if (result < 0)
            {
                result = 0.0;
            }
            else if (result > 1)
            {
                result = 1.0;
            }
            return(result);
        }
示例#13
0
        // Used to debug MMath.NormalCdf
        internal void NormalCdf2Test3()
        {
            double x, y, r;
            bool   first = true;

            if (first)
            {
                // x=-2, y=-10, r=0.9 is dominated by additive part of numerator - poor convergence
                // -2,-2,-0.5
                x = -1.0058535005109381;
                y = -0.11890687017604007;
                r = -0.79846947062734286;
                x = -63;
                y = 63;
                r = -0.4637494637494638;

                x = -1.0329769464004883E-08;
                y = 1.0329769464004876E-08;
                r = -0.99999999999999512;

                x = 0;
                y = 0;
                r = -0.6;

                x = -1.15950886531361;
                y = 0.989626418003324;
                r = -0.626095038754337;

                x = -1.5;
                y = 1.5;
                r = -0.49;

                x = -1.6450031341281908;
                y = 1.2645625117080999;
                r = -0.054054238344620031;

                x = -0.5;
                y = -0.5;
                r = 0.001;

                Console.WriteLine(1 - r * r);

                Console.WriteLine("NormalCdfBrute: {0}", NormalCdfBrute(0, x, y, r));
                Console.WriteLine("NormalCdf_Quadrature: {0}", NormalCdf_Quadrature(x, y, r));
                //Console.WriteLine("{0}", NormalCdfAlt2(x, y, r));
                //Console.WriteLine("NormalCdfAlt: {0}", NormalCdfAlt(x, y, r));
                //Console.WriteLine("NormalCdfTaylor: {0}", MMath.NormalCdfRatioTaylor(x, y, r));
                //Console.WriteLine("NormalCdfConFrac3: {0}", NormalCdfConFrac3(x, y, r));
                //Console.WriteLine("NormalCdfConFrac4: {0}", NormalCdfConFrac4(x, y, r));
                //Console.WriteLine("NormalCdfConFrac5: {0}", NormalCdfConFrac5(x, y, r));
                Console.WriteLine("MMath.NormalCdf: {0}", MMath.NormalCdf(x, y, r));
                Console.WriteLine("MMath.NormalCdfLn: {0}", MMath.NormalCdfLn(x, y, r));
                for (int i = 1; i < 50; i++)
                {
                    //Console.WriteLine("{0}: {1}", i, NormalCdfBrute(i, x, y, r));
                }
                //x = 0;
                //y = 0;
                //r2 = -0.7;
                //r2 = -0.999;
            }
            else
            {
                // x=-2, y=-10, r=0.9 is dominated by additive part of numerator - poor convergence
                // -2,-2,-0.5
                x = -0.1;
                y = -0.1;
                r = -0.999999;
                Console.WriteLine("{0}", MMath.NormalCdfLn(x, y, r));
                //x = 0;
                //y = 0;
                //r2 = -0.7;
                //r2 = -0.999;
            }
        }
示例#14
0
        private double NormalCdfIntegralBasic2(double x, double y, double r)
        {
            double omr2     = 1 - r * r;
            double sqrtomr2 = System.Math.Sqrt(omr2);
            double ymrx     = (y - r * x) / sqrtomr2;
            double xmry     = (x - r * y) / sqrtomr2;

            double func(double t)
            {
                return((y - r * x + r * t) * System.Math.Exp(Gaussian.GetLogProb(t, x, 1) + MMath.NormalCdfLn(ymrx + r * t / sqrtomr2)));
            }

            func(0);
            double func2(double t)
            {
                double ymrxt = ymrx + r * t / sqrtomr2;

                return(sqrtomr2 * System.Math.Exp(Gaussian.GetLogProb(t, x, 1) + Gaussian.GetLogProb(ymrxt, 0, 1)) * (MMath.NormalCdfMomentRatio(1, ymrxt) - 1));
            }

            func2(0);
            //return -MMath.NormalCdf(x, y, r) * (y / r - x) + Integrate(func2) / r;
            double func3(double t)
            {
                double xmryt = xmry + r * t / sqrtomr2;

                return(sqrtomr2 * System.Math.Exp(Gaussian.GetLogProb(t, y, 1) + Gaussian.GetLogProb(xmryt, 0, 1)) * MMath.NormalCdfMomentRatio(1, xmryt));
            }

            //double Z = MMath.NormalCdf(x, y, r, out double exponent);
            double Z3 = Integrate(func3);

            //return System.Math.Exp(exponent)*(-Z * (y / r - x) - omr2 / r * MMath.NormalCdfRatio(xmry)) + Z3/r;
            return(Z3);
        }
示例#15
0
        // logw1 = N(mx;m1,vx+v1) phi((mx1 - m2)/sqrt(vx1+v2))
        // a1 = N(mx1;m2,vx1+v2)/phi
        internal static void ComputeStats(Gaussian max, Gaussian a, Gaussian b, out double logz,
                                          out double logw1, out double a1, out double vx1, out double mx1,
                                          out double logw2, out double a2, out double vx2, out double mx2)
        {
            double m1, v1, m2, v2;

            a.GetMeanAndVariance(out m1, out v1);
            b.GetMeanAndVariance(out m2, out v2);
            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)
                        logw1 = Double.NegativeInfinity;
                        logw2 = MMath.NormalCdfLn((max.Point - m1) / Math.Sqrt(v1));
                        logz  = logw2;
                        a1    = 0;
                        a2    = Math.Exp(Gaussian.GetLogProb(max.Point, m1, v1) - logw2);
                        return;
                    }
                    else
                    {
                        // b.Point < max.Point
                        // the factor reduces to the constraint (a == max.Point)
                        throw new NotImplementedException();
                    }
                }
                else if (a.IsPointMass)
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                if (a.IsPointMass)
                {
                    vx1 = 0.0;
                    mx1 = a.Point;
                }
                else
                {
                    vx1 = 1.0 / (max.Precision + a.Precision);
                    mx1 = vx1 * (max.MeanTimesPrecision + a.MeanTimesPrecision);
                }
                if (b.IsPointMass)
                {
                    vx2 = 0.0;
                    mx2 = b.Point;
                }
                else
                {
                    vx2 = 1.0 / (max.Precision + b.Precision);
                    mx2 = vx2 * (max.MeanTimesPrecision + b.MeanTimesPrecision);
                }
            }
            logw1 = max.GetLogAverageOf(a);
            double logPhi1 = MMath.NormalCdfLn((mx1 - m2) / Math.Sqrt(vx1 + v2));

            logw1 += logPhi1;

            logw2 = max.GetLogAverageOf(b);
            double logPhi2 = MMath.NormalCdfLn((mx2 - m1) / Math.Sqrt(vx2 + v1));

            logw2 += logPhi2;

            logz = MMath.LogSumExp(logw1, logw2);

            double logN1 = Gaussian.GetLogProb(mx1, m2, vx1 + v2);

            a1 = Math.Exp(logN1 - logPhi1);
            double logN2 = Gaussian.GetLogProb(mx2, m1, vx2 + v1);

            a2 = Math.Exp(logN2 - logPhi2);
        }