// result is divided by n!! (odd n) public static double NormalCdfMomentDy2(int n, double x, double y, double r) { double omr2 = 1 - r * r; if (omr2 == 0) { double lfact; if (n % 2 == 1) { lfact = DoubleFactorialLn(n); } else { lfact = DoubleFactorialLn(n - 1); } return(System.Math.Pow(x - r * y, n) * System.Math.Exp(Gaussian.GetLogProb(y, 0, 1) - lfact)); } else { double diff = (x - r * y) / System.Math.Sqrt(omr2); double lfact; if (n % 2 == 1) { lfact = DoubleFactorialLn(n - 1); // n!/n!! } else { lfact = DoubleFactorialLn(n) - System.Math.Log(n + 1); // n!/(n+1)!! } return(System.Math.Exp(lfact + Gaussian.GetLogProb(y, 0, 1) + Gaussian.GetLogProb(diff, 0, 1) + 0.5 * n * System.Math.Log(omr2)) * MMath.NormalCdfMomentRatio(n, diff)); } }
// this test shows that a Taylor expansion at zero is not reliable for x less than -0.5 internal void NormalCdfMomentRatioTaylorZeroTest() { double x = -1; for (int n = 0; n < 20; n++) { Console.WriteLine("{0} {1} {2}", n, MMath.NormalCdfMomentRatio(n, x), NormalCdfMomentRatioTaylorZero(n, x)); } }
public static void VarianceGammaTimesGaussianMoments2(double a, double m, double v, out double mu, out double vu) { // compute weights Matrix laplacianMoments = new Matrix(nWeights, nWeights); DenseVector exactMoments = DenseVector.Constant(laplacianMoments.Rows, 1.0); // a=10: 7-1 // a=15: 8-1 // a=20: 10-1 // a=21: 10-1 // a=30: 12-1 // get best results if the lead term has flat moment ratio int jMax = Math.Max(laplacianMoments.Cols, (int)Math.Round(a - 10)) - 1; jMax = laplacianMoments.Cols - 1; for (int i = 0; i < exactMoments.Count; i++) { //int ii = jMax-i; int ii = i; double logMoment = MMath.GammaLn(ii + a) - MMath.GammaLn(a) - MMath.GammaLn(ii + 1); for (int j = 0; j < laplacianMoments.Cols; j++) { int jj = jMax - j; laplacianMoments[i, j] = Math.Exp(MMath.GammaLn(2 * ii + jj + 1) - MMath.GammaLn(2 * ii + 1) - MMath.GammaLn(jj + 1) - logMoment); } } //Console.WriteLine("exactMoments = {0}, laplacianMoments = ", exactMoments); //Console.WriteLine(laplacianMoments); (new LuDecomposition(laplacianMoments)).Solve(exactMoments); DenseVector weights = exactMoments; Console.WriteLine("weights = {0}", weights); double Z0Plus = 0, Z1Plus = 0, Z2Plus = 0; double Z0Minus = 0, Z1Minus = 0, Z2Minus = 0; double sqrtV = Math.Sqrt(v); double InvSqrtV = 1 / sqrtV; double mPlus = (m - v) * InvSqrtV; double mMinus = (-m - v) * InvSqrtV; for (int j = 0; j < weights.Count; j++) { int jj = jMax - j; Z0Plus += weights[j] * MMath.NormalCdfMomentRatio(0 + jj, mPlus) * Math.Pow(sqrtV, 0 + jj); Z1Plus += weights[j] * MMath.NormalCdfMomentRatio(1 + jj, mPlus) * (1 + jj) * Math.Pow(sqrtV, 1 + jj); Z2Plus += weights[j] * MMath.NormalCdfMomentRatio(2 + jj, mPlus) * (1 + jj) * (2 + jj) * Math.Pow(sqrtV, 2 + jj); Z0Minus += weights[j] * MMath.NormalCdfMomentRatio(0 + jj, mMinus) * Math.Pow(sqrtV, 0 + jj); Z1Minus += weights[j] * MMath.NormalCdfMomentRatio(1 + jj, mMinus) * (1 + jj) * Math.Pow(sqrtV, 1 + jj); Z2Minus += weights[j] * MMath.NormalCdfMomentRatio(2 + jj, mMinus) * (1 + jj) * (2 + jj) * Math.Pow(sqrtV, 2 + jj); } double Z0 = Z0Plus + Z0Minus; double Z1 = Z1Plus - Z1Minus; double Z2 = Z2Plus + Z2Minus; mu = Z1 / Z0; vu = Z2 / Z0 - mu * mu; }
/// <summary> /// Computes int_0^Inf x^n N(x;m,v) dx / N(m/sqrt(v);0,1) /// </summary> /// <param name="nMax"></param> /// <param name="m"></param> /// <param name="v"></param> /// <returns></returns> public static double[] NormalCdfMomentRatios(int nMax, double m, double v) { double[] result = new double[nMax + 1]; double sqrtV = Math.Sqrt(v); for (int i = 0; i <= nMax; i++) { // NormalCdfMomentRatio(0,37.66) = infinity result[i] = MMath.NormalCdfMomentRatio(i, m / sqrtV) * Math.Pow(sqrtV, i) * MMath.Gamma(i + 1); } return(result); }
public void NormalCdfMomentRatioSequenceTest() { int n = 0; double x = -1.1; var iter = MMath.NormalCdfMomentRatioSequence(n, x); for (int i = 0; i < 20; i++) { iter.MoveNext(); double r1 = MMath.NormalCdfMomentRatio(n + i, x); double r2 = iter.Current; Console.WriteLine("{0}: {1} {2} {3}", i, r1, r2, Math.Abs(r1 - r2) / Math.Abs(r1)); } }
public void NormalCdfMomentRatioTest() { /* Anaconda Python script to generate a true value (must not be indented): * from mpmath import * * mp.dps = 100; mp.pretty = True * x = mpf('-2'); n=300; * exp(x*x/4)*pcfu(0.5+n,-x) */ double[,] normcdfMomentRatio_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfMomentRatio.csv")); CheckFunctionValues("NormalCdfMomentRatio", delegate(double n, double x) { return(MMath.NormalCdfMomentRatio((int)n, x)); }, normcdfMomentRatio_pairs); }
public static double NormalCdfMomentDy(int n, double x, double y, double r) { double omr2 = 1 - r * r; if (omr2 == 0) { return(System.Math.Pow(x - r * y, n) * System.Math.Exp(Gaussian.GetLogProb(y, 0, 1))); } else { double diff = (x - r * y) / System.Math.Sqrt(omr2); return(System.Math.Exp(MMath.GammaLn(n + 1) + Gaussian.GetLogProb(y, 0, 1) + Gaussian.GetLogProb(diff, 0, 1) + 0.5 * n * System.Math.Log(omr2)) * MMath.NormalCdfMomentRatio(n, diff)); } }
/// <summary> /// Compute moments of 0.5*exp(-abs(x))*N(x;m,v) /// </summary> /// <param name="m"></param> /// <param name="v"></param> /// <param name="logZ"></param> /// <param name="mu"></param> /// <param name="vu"></param> public static void LaplacianTimesGaussianMoments(double m, double v, out double logZ, out double mu, out double vu) { if (Double.IsPositiveInfinity(v)) { // moments of Laplacian only logZ = 0; mu = 0; vu = 2; return; } double invV = 1 / v; double invSqrtV = Math.Sqrt(invV); double mPlus = (m - v) * invSqrtV; double mMinus = (-m - v) * invSqrtV; double Z0, Z1, Z2; if (mPlus > 30) { double[] moments = NormalCdfMoments(2, m - v, v); Z0 = moments[0]; Z1 = moments[1]; Z2 = moments[2]; logZ = Math.Log(0.5 * Z0) - m + 0.5 * v; } else if (mMinus > 30) { double[] moments = NormalCdfMoments(2, -m - v, v); Z0 = moments[0]; Z1 = -moments[1]; Z2 = moments[2]; logZ = Math.Log(0.5 * Z0) + m + 0.5 * v; } else { Z0 = MMath.NormalCdfRatio(mPlus) + MMath.NormalCdfRatio(mMinus); Z1 = Math.Sqrt(v) * (MMath.NormalCdfMomentRatio(1, mPlus) - MMath.NormalCdfMomentRatio(1, mMinus)); Z2 = 2 * v * (MMath.NormalCdfMomentRatio(2, mPlus) + MMath.NormalCdfMomentRatio(2, mMinus)); logZ = Math.Log(0.5 * Z0) - MMath.LnSqrt2PI - 0.5 * m * m * invV; } mu = Z1 / Z0; double mu2 = Z2 / Z0; vu = mu2 - mu * mu; }
public void VarianceGammaTimesGaussianIntegralTest() { double logZ, mu, vu; GaussianFromMeanAndVarianceOp.LaplacianTimesGaussianMoments(-100, 1, out logZ, out mu, out vu); Console.WriteLine(logZ); //GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianMoments5(1, 1000, 1, out mu, out vu); Console.WriteLine(mu); Console.WriteLine(vu); double[][] vgmoments = GaussianFromMeanAndVarianceOp.NormalVGMomentRatios(10, 1, -6, 1); for (int i = 0; i < 10; i++) { double f = MMath.NormalCdfMomentRatio(i, -6) * MMath.Gamma(i + 1); Console.WriteLine("R({0}) = {1}, Zp = {2}", i, f, vgmoments[0][i]); } // true values computed by tex/factors/matlab/test_variance_gamma2.m double scale = 2 * System.Math.Exp(-Gaussian.GetLogProb(2 / System.Math.Sqrt(3), 0, 1)); Assert.True(MMath.AbsDiff(0.117700554409044, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1, 2, 3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(0.112933034747473, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(2, 2, 3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(0.117331854901251, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.1, 2, 3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(0.115563913123152, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.5, 2, 3) / scale, 1e-20) < 2e-5); scale = 2 * System.Math.Exp(-Gaussian.GetLogProb(20 / System.Math.Sqrt(0.3), 0, 1)); Assert.True(MMath.AbsDiff(1.197359429038085e-009, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1, 20, 0.3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(1.239267009054433e-008, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(2, 20, 0.3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(1.586340098271600e-009, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.1, 20, 0.3) / scale, 1e-20) < 1e-4); Assert.True(MMath.AbsDiff(4.319412089896069e-009, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.5, 20, 0.3) / scale, 1e-20) < 1e-4); scale = 2 * System.Math.Exp(-Gaussian.GetLogProb(40 / System.Math.Sqrt(0.3), 0, 1)); scale = 2 * System.Math.Exp(40 - 0.3 / 2); Assert.True(MMath.AbsDiff(2.467941724509690e-018, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1, 40, 0.3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(5.022261409377230e-017, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(2, 40, 0.3) / scale, 1e-20) < 1e-5); Assert.True(MMath.AbsDiff(3.502361147666615e-018, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.1, 40, 0.3) / scale, 1e-20) < 1e-4); Assert.True(MMath.AbsDiff(1.252310352551344e-017, GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.5, 40, 0.3) / scale, 1e-20) < 1e-4); Assert.True(GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.138, 33.4, 0.187) > 0); Assert.True(GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.138, -33.4, 0.187) > 0); Assert.True(GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.138, 58.25, 0.187) > 0); Assert.True(GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.138, 50, 0.187) > 0); Assert.True(GaussianFromMeanAndVarianceOp.VarianceGammaTimesGaussianIntegral(1.138, 100, 0.187) > 0); }
private static IEnumerator <double> NormalCdfMomentRatioSequence(double x) { if (x > -1) { double rPrev = MMath.NormalCdfRatio(x); yield return(rPrev); double r = x * rPrev + 1; yield return(r); for (int i = 1; ; i++) { double rNew = (x * r + rPrev) / (i + 1); rPrev = r; r = rNew; yield return(r); } } else { int tableSize = 10; // rtable[tableStart-i] = R_i double[] rtable = new double[tableSize]; int tableStart = -1; for (int i = 0; ; i++) { if (i > tableStart) { // build the table tableStart = i + tableSize - 1; rtable[0] = MMath.NormalCdfMomentRatio(tableStart, x); rtable[1] = MMath.NormalCdfMomentRatio(tableStart - 1, x); for (int j = 2; j < tableSize; j++) { int n = tableStart - j + 1; rtable[j] = (n + 1) * rtable[j - 2] - x * rtable[j - 1]; } } yield return(rtable[tableStart - i]); } } }
// returns int_0^Inf x^n VG(x;a) N(x;m,v) dx / (0.5*N(m;0,1)) public static double NormalVGMomentRatio(int n, int a, double m, double v) { if (a < 1) { throw new ArgumentException("a < 1", "a"); } if (a == 1) { double sqrtV = Math.Sqrt(v); return(MMath.Gamma(n + 1) * MMath.NormalCdfMomentRatio(n, m / sqrtV) * Math.Pow(sqrtV, n)); } else if (a == 2) { double sqrtV = Math.Sqrt(v); return(0.5 * NormalVGMomentRatio(n, 1, m, v) + 0.5 * MMath.Gamma(n + 2) * MMath.NormalCdfMomentRatio(n + 1, m / sqrtV) * Math.Pow(sqrtV, n + 1)); } else // a > 2 { return(0.25 / ((a - 2) * (a - 1)) * NormalVGMomentRatio(n + 2, a - 2, m, v) + (a - 1.5) / (a - 1) * NormalVGMomentRatio(n, a - 1, m, v)); } }
// Returns NormalCdf divided by N(x;0,1) N((y-rx)/sqrt(1-r^2);0,1), multiplied by scale // This version works best for small r^2 // We need x <= 0 and (y - r*x) <= 0 private static double NormalCdfRatioConFrac3b(double x, double y, double r, double scale) { if (scale == 0) { return(scale); } //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"); } if (x > 0) { throw new ArgumentException("x > 0"); } double omr2 = 1 - r * r; double sqrtomr2 = System.Math.Sqrt(omr2); double rxmy = r * x - y; double ymrx = -rxmy / sqrtomr2; if (ymrx > 0) { throw new ArgumentException("ymrx > 0"); } double offset = MMath.NormalCdfRatio(x) * MMath.NormalCdfRatio(ymrx) * scale; double omsomr2 = MMath.OneMinusSqrtOneMinus(r * r); double delta = (r * y - x * omsomr2) / sqrtomr2; double diff = (x - r * y) / sqrtomr2; double Rdiff = MMath.NormalCdfRatio(diff); //var RdiffIter = MMath.NormalCdfMomentRatioSequence(0, diff); //RdiffIter.MoveNext(); //double Rdiff = RdiffIter.Current; double scale2 = scale * omr2; double numer; if (System.Math.Abs(delta) > 0.5) { // for r =approx 0 this becomes inaccurate due to cancellation numer = scale2 * (MMath.NormalCdfRatio(x) / sqrtomr2 - Rdiff); } else { numer = scale2 * (MMath.NormalCdfRatioDiff(diff, delta) + omsomr2 * Rdiff) / sqrtomr2; } double numerPrev = 0; double denom = rxmy; double denomPrev = 1; double rOld = 0; double result = 0; double cEven = scale2; double cIncr = r * sqrtomr2; double cOdd = cEven * cIncr; cIncr *= cIncr; for (int i = 1; i < 10000; i++) { double numerNew, denomNew; //RdiffIter.MoveNext(); double c = MMath.NormalCdfMomentRatio(i, diff); //double c = RdiffIter.Current; if (i % 2 == 1) { if (i > 1) { cOdd *= (i - 1) * cIncr; } c *= cOdd; numerNew = rxmy * numer + omr2 * numerPrev - c; denomNew = rxmy * denom + omr2 * denomPrev; } else { cEven *= i * cIncr; c *= cEven; numerNew = (rxmy * numer + omr2 * i * numerPrev - c) / (i + 1); denomNew = (rxmy * denom + omr2 * i * denomPrev) / (i + 1); } numerPrev = numer; numer = numerNew; denomPrev = denom; denom = denomNew; if (i % 2 == 1) { result = -numer / denom; Console.WriteLine($"iter {i.ToString().PadLeft(3)}: {result.ToString("r").PadRight(24)} {numer.ToString("r").PadRight(24)} {denom.ToString("r").PadRight(24)} {c}"); if (double.IsInfinity(result) || double.IsNaN(result)) { throw new Exception(string.Format("NormalCdfRatioConFrac3 not converging for x={0} y={1} r={2} scale={3}", x, y, r, scale)); } //if (result == rOld) // return result + offset; rOld = result; } } throw new Exception(string.Format("NormalCdfRatioConFrac3 not converging for x={0} y={1} r={2} scale={3}", x, y, r, scale)); }
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); }
public static Gaussian XAverageConditional_Helper([SkipIfUniform] Bernoulli isPositive, [SkipIfUniform, Proper] Gaussian x, bool forceProper) { if (x.IsPointMass) { if (isPositive.IsPointMass && (isPositive.Point != (x.Point > 0))) { return(Gaussian.PointMass(0)); } else { return(Gaussian.Uniform()); } } double tau = x.MeanTimesPrecision; double prec = x.Precision; if (prec == 0.0) { if (isPositive.IsPointMass) { if ((isPositive.Point && tau < 0) || (!isPositive.Point && tau > 0)) { // posterior is proportional to I(x>0) exp(tau*x) //double mp = -1 / tau; //double vp = mp * mp; return(Gaussian.FromNatural(-tau, tau * tau) / x); } } return(Gaussian.Uniform()); } else if (prec < 0) { throw new ImproperMessageException(x); } double sqrtPrec = Math.Sqrt(prec); // m/sqrt(v) = (m/v)/sqrt(1/v) double z = tau / sqrtPrec; // epsilon = p(b=F) // eq (51) in EP quickref double alpha; if (isPositive.IsPointMass) { if ((isPositive.Point && z < -10) || (!isPositive.Point && z > 10)) { if (z > 10) { z = -z; } //double Y = MMath.NormalCdfRatio(z); // dY = z*Y + 1 // d2Y = z*dY + Y // posterior mean = m + sqrt(v)/Y = sqrt(v)*(z + 1/Y) = sqrt(v)*dY/Y // = sqrt(v)*(d2Y/Y - 1)/z = (d2Y/Y - 1)/tau // =approx sqrt(v)*(-1/z) = -1/tau // posterior variance = v - v*dY/Y^2 =approx v/z^2 // posterior E[x^2] = v - v*dY/Y^2 + v*dY^2/Y^2 = v - v*dY/Y^2*(1 - dY) = v + v*z*dY/Y = v*d2Y/Y // d3Y = z*d2Y + 2*dY // = z*(z*dY + Y) + 2*dY // = z^2*dY + z*Y + 2*dY // = z^2*dY + 3*dY - 1 double d3Y = 6 * MMath.NormalCdfMomentRatio(3, z); //double dY = MMath.NormalCdfMomentRatio(1, z); double dY = (d3Y + 1) / (z * z + 3); if (MMath.AreEqual(dY, 0)) { double tau2 = tau * tau; if (tau2 > double.MaxValue) { return(Gaussian.PointMass(-1 / tau)); } else { return(Gaussian.FromNatural(-2 * tau, tau2)); } } // Y = (dY-1)/z // alpha = sqrtPrec*z/(dY-1) = tau/(dY-1) // alpha+tau = tau*(1 + 1/(dY-1)) = tau*dY/(dY-1) = alpha*dY // beta = alpha * (alpha + tau) // = alpha * tau * dY / (dY - 1) // = prec * z^2 * dY/(dY-1)^2 // prec/beta = (dY-1)^2/(dY*z^2) // prec/beta - 1 = ((dY-1)^2 - dY*z^2)/(dY*z^2) // weight = beta/(prec - beta) // = dY*z^2/((dY-1)^2 - dY*z^2) // = dY*z^2/(dY^2 -2*dY + 1 - dY*z^2) // = dY*z^2/(dY^2 + 1 + z*Y - d3Y) // = dY*z^2/(dY^2 + dY - d3Y) // = z^2/(dY + 1 - d3Y/dY) double d3YidY = d3Y / dY; double denom = dY - d3YidY + 1; double msgPrec = tau * tau / denom; // weight * (tau + alpha) + alpha // = z^2/(dY + 1 - d3Y/dY) * alpha*dY + alpha // = alpha*(z^2*dY/(dY + 1 - d3Y/dY) + 1) // = alpha*(z^2*dY + dY + 1 - d3Y/dY)/(dY + 1 - d3Y/dY) // = alpha*(z^2*dY + dY + 1 - d3Y/dY)/(dY + 1 - d3Y/dY) // = alpha*(d3Y - 2*dY + 2 - d3Y/dY)/(dY + 1 - d3Y/dY) // z^2*dY = d3Y - 3*dY + 1 double numer = (d3Y - 2 * dY - d3YidY + 2) / (dY - 1); double msgMeanTimesPrec = tau * numer / denom; if (msgPrec > double.MaxValue) { // In this case, the message should be the posterior. // posterior mean = (msgMeanTimesPrec + tau)*denom/(tau*tau) // = (numer + denom)/tau return(Gaussian.PointMass((numer + denom) / tau)); } else { return(Gaussian.FromNatural(msgMeanTimesPrec, msgPrec)); } } else if (isPositive.Point) { alpha = sqrtPrec / MMath.NormalCdfRatio(z); } else { alpha = -sqrtPrec / MMath.NormalCdfRatio(-z); } } else { //double v = MMath.LogSumExp(isPositive.LogProbTrue + MMath.NormalCdfLn(z), isPositive.LogProbFalse + MMath.NormalCdfLn(-z)); double v = LogAverageFactor(isPositive, x); alpha = sqrtPrec * Math.Exp(-z * z * 0.5 - MMath.LnSqrt2PI - v) * (2 * isPositive.GetProbTrue() - 1); } // eq (52) in EP quickref (where tau = mnoti/Vnoti) double beta; if (alpha == 0) { beta = 0; // avoid 0 * infinity } else { beta = alpha * (alpha + tau); } double weight = beta / (prec - beta); if (forceProper && weight < 0) { weight = 0; } Gaussian result = new Gaussian(); if (weight == 0) { // avoid 0 * infinity result.MeanTimesPrecision = alpha; } else { // eq (31) in EP quickref; same as inv(inv(beta)-inv(prec)) result.Precision = prec * weight; // eq (30) in EP quickref times above and simplified result.MeanTimesPrecision = weight * (tau + alpha) + alpha; } if (double.IsNaN(result.Precision) || double.IsNaN(result.MeanTimesPrecision)) { throw new InferRuntimeException($"result is NaN. isPositive={isPositive}, x={x}, forceProper={forceProper}"); } return(result); }
public static Gaussian XAverageConditional_Helper([SkipIfUniform] Bernoulli isPositive, [SkipIfUniform, Proper] Gaussian x, bool forceProper) { if (x.IsPointMass) { if (isPositive.IsPointMass && (isPositive.Point != (x.Point > 0))) { return(Gaussian.PointMass(0)); } else { return(Gaussian.Uniform()); } } double tau = x.MeanTimesPrecision; double prec = x.Precision; if (prec == 0.0) { if (isPositive.IsPointMass) { if ((isPositive.Point && tau < 0) || (!isPositive.Point && tau > 0)) { // posterior is proportional to I(x>0) exp(tau*x) double mp = -1 / tau; double vp = mp * mp; return((new Gaussian(mp, vp)) / x); } } if (x.IsUniform()) { return(Gaussian.Uniform()); } throw new ImproperMessageException(x); } else if (prec < 0) { throw new ImproperMessageException(x); } double sqrtPrec = Math.Sqrt(prec); // m/sqrt(v) = (m/v)/sqrt(1/v) double z = tau / sqrtPrec; // epsilon = p(b=F) // eq (51) in EP quickref double alpha; if (isPositive.IsPointMass) { if (isPositive.Point) { if (z < -1e10) { double mp = -1 / (z * sqrtPrec); double vp = 1 / (z * z * prec); return((new Gaussian(mp, vp)) / x); } else if (z < -100) { double Y = MMath.NormalCdfRatio(z); // double dY = MMath.NormalCdfMomentRatio(1, z); // dY = z*Y + 1 // d2Y = z*dY + Y // posterior mean = m + sqrt(v)/Y = sqrt(v)*(z + 1/Y) = sqrt(v)*dY/Y =approx sqrt(v)*(-1/z) // posterior variance = v - v*dY/Y^2 =approx v/z^2 // posterior E[x^2] = v - v*dY/Y^2 + v*dY^2/Y^2 = v - v*dY/Y^2*(1 - dY) = v + v*z*dY/Y = v*d2Y/Y double d2Y = 2 * MMath.NormalCdfMomentRatio(2, z); // m2TimesPrec = z*dY/Y + 1 double m2TimesPrec = d2Y / Y; Assert.IsTrue(tau != 0); double mp = (m2TimesPrec - 1) / tau; double vp = m2TimesPrec / prec - mp * mp; return((new Gaussian(mp, vp)) / x); } alpha = sqrtPrec / MMath.NormalCdfRatio(z); } else { if (z > 1e10) { double mp = 1 / (z * sqrtPrec); double vp = 1 / (z * z * prec); return((new Gaussian(mp, vp)) / x); } else if (z > 100) { double Y = MMath.NormalCdfRatio(-z); // dY = -(d2Y/prec - Y)/(-z)*sqrtPrec // dY/Y/prec = -(d2Y/Y/prec/prec - 1/prec)/(-z)*sqrtPrec // dY/Y/prec = -(d2Y/Y/prec - 1)/(-tau) //double dY = -MMath.NormalCdfMomentRatio(1,-z)*sqrtPrec; double d2Y = 2 * MMath.NormalCdfMomentRatio(2, -z); double m2TimesPrec = d2Y / Y; Assert.IsTrue(tau != 0); double mp = (m2TimesPrec - 1) / tau; double vp = m2TimesPrec / prec - mp * mp; return((new Gaussian(mp, vp)) / x); } alpha = -sqrtPrec / MMath.NormalCdfRatio(-z); } } else { //double v = MMath.LogSumExp(isPositive.LogProbTrue + MMath.NormalCdfLn(z), isPositive.LogProbFalse + MMath.NormalCdfLn(-z)); double v = LogAverageFactor(isPositive, x); alpha = sqrtPrec * Math.Exp(-z * z * 0.5 - MMath.LnSqrt2PI - v) * (2 * isPositive.GetProbTrue() - 1); } // eq (52) in EP quickref (where tau = mnoti/Vnoti) double beta = alpha * (alpha + tau); double weight = beta / (prec - beta); if (forceProper && weight < 0) { weight = 0; } Gaussian result = new Gaussian(); // eq (31) in EP quickref; same as inv(inv(beta)-inv(prec)) result.Precision = prec * weight; // eq (30) in EP quickref times above and simplified result.MeanTimesPrecision = weight * (tau + alpha) + alpha; if (double.IsNaN(result.Precision) || double.IsNaN(result.MeanTimesPrecision)) { throw new ApplicationException("result is nan"); } return(result); }
public static double NormalCdfMomentDyRatio(int n, double x, double y, double r) { double omr2 = 1 - r * r; if (omr2 == 0) { throw new ArgumentException(); } else { double diff = (x - r * y) / System.Math.Sqrt(omr2); //return Math.Exp(MMath.GammaLn(n + 1) + 0.5 * n * Math.Log(omr2)) * MMath.NormalCdfMomentRatio(n, diff); return(System.Math.Exp(MMath.GammaLn(n + 1) + 0.5 * n * System.Math.Log(omr2) + System.Math.Log(MMath.NormalCdfMomentRatio(n, diff)))); } }
// returns phi_n(m,v)/n! public static double NormalCdfMoment(int n, double m, double v) { double InvSqrtV = Math.Sqrt(1 / v); return(MMath.NormalCdfMomentRatio(n, m * InvSqrtV) * MMath.InvSqrt2PI * Math.Exp(-0.5 * m * m / v) * Math.Pow(v, 0.5 * n)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MaxGaussianOp"]/message_doc[@name="AAverageConditional(Gaussian, Gaussian, Gaussian)"]/*'/> public static Gaussian AAverageConditional([SkipIfUniform] Gaussian max, [Proper] Gaussian a, [Proper] Gaussian b) { if (max.IsUniform()) { return(Gaussian.Uniform()); } if (!b.IsProper()) { throw new ImproperMessageException(b); } double logw1, alpha1, vx1, mx1; double logw2, alpha2, vx2, mx2; double logz; ComputeStats(max, a, b, out logz, out logw1, out alpha1, out vx1, out mx1, out logw2, out alpha2, out vx2, out mx2); double w1 = Math.Exp(logw1 - logz); double w2 = Math.Exp(logw2 - logz); bool checkDerivatives = false; if (a.IsPointMass) { // f(a) = int p(x = max(a,b)) p(b) db // f(a) = p(x = a) p(a >= b) + p(x = b) p(a < b | x = b) // f(a) = N(a; mx, vx) phi((a - m2)/sqrt(v2)) + N(m2; mx, vx + v2) phi((mx2 - a)/sqrt(vx2)) // f'(a) = (mx-a)/vx N(a; mx, vx) phi((a - m2)/sqrt(v2)) + N(a; mx, vx) N(a; m2, v2) - N(m2; mx, vx + v2) N(a; mx2, vx2) // = (mx-a)/vx N(a; mx, vx) phi((a - m2)/sqrt(v2)) // f''(a) = -1/vx N(a; mx, vx) phi((a - m2)/sqrt(v2)) + (mx-a)^2/vx^2 N(a; mx, vx) phi((a - m2)/sqrt(v2)) + (mx-a)/vx N(a; mx, vx) N(a; m2, v2) // ddlogf = f''(a)/f(a) - (f'(a)/f(a))^2 = (f''(a) f(a) - f'(a)^2)/f(a)^2 double aPoint = a.Point; if (max.IsPointMass) { return(max); } double z = max.MeanTimesPrecision - aPoint * max.Precision; double alpha = z * w1; double beta = (z * alpha1 - max.Precision + z * z) * w1 - alpha * alpha; if (b.IsPointMass && b.Point != aPoint) { beta -= max.Precision * w2 * alpha2 * (b.Point - aPoint); } if (checkDerivatives) { double m1 = a.GetMean(); double delta = m1 * 1e-6; double logzd, logw1d, alpha1d, vx1d, mx1d, logw2d, alpha2d, vx2d, mx2d; ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 + delta, a.Precision), b, out logzd, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d); double logzd2; ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 - delta, a.Precision), b, out logzd2, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d); double alphaCheck = (logzd - logzd2) / (2 * delta); double alphaError = Math.Abs(alpha - alphaCheck); double betaCheck = (logzd + logzd2 - 2 * logz) / (delta * delta); double betaError = Math.Abs(beta - betaCheck); Console.WriteLine($"alpha={alpha} check={alphaCheck} error={alphaError} beta={beta} check={betaCheck} error={betaError}"); } return(Gaussian.FromDerivatives(aPoint, alpha, beta, ForceProper)); } bool useMessage = (w1 > 0) || (logw2 > -100); if (useMessage) { // vx1 = 1/(1/vx + 1/v1) = vx*v1/(vx + v1) double z, alpha, beta; if (max.IsPointMass) { if (w2 == 0) { return(max); } z = max.Point * a.Precision - a.MeanTimesPrecision; alpha = z * w1 - w2 * alpha2; beta = (z * z - a.Precision) * w1 - z * alpha2 * w2 - alpha * alpha; } else { //z = vx1 * (max.MeanTimesPrecision * a.Precision - a.MeanTimesPrecision * max.Precision); z = (max.MeanTimesPrecision - a.GetMean() * max.Precision) / (max.Precision / a.Precision + 1); alpha = z * w1 - vx1 * max.Precision * w2 * alpha2; if (w2 == 0) { //beta = (z * alpha1 - max.Precision) / (max.Precision / a.Precision + 1); //double resultPrecision = a.Precision * beta / (-a.Precision - beta); //resultPrecision = beta / (-1 - beta/a.Precision); //resultPrecision = 1 / (-1/beta - 1 / a.Precision); //resultPrecision = a.Precision / (-a.Precision / beta - 1); //resultPrecision = a.Precision / (-(a.Precision + max.Precision) / (z * alpha1 - max.Precision) - 1); //resultPrecision = -a.Precision / ((a.Precision + z*alpha1) / (z * alpha1 - max.Precision)); double zalpha1 = z * alpha1; double denom = (1 + zalpha1 / a.Precision); double resultPrecision = (max.Precision - zalpha1) / denom; //double weight = (max.Precision - z * alpha1) / (a.Precision + z * alpha1); //double weightPlus1 = (max.Precision + a.Precision) / (a.Precision + z * alpha1); //double resultMeanTimesPrecision = weight * (a.MeanTimesPrecision + alpha) + alpha; //resultMeanTimesPrecision = weight * a.MeanTimesPrecision + weightPlus1 * alpha; //double resultMeanTimesPrecision = (a.Precision * max.MeanTimesPrecision - z * alpha1 * a.MeanTimesPrecision) / (a.Precision + z * alpha1); double resultMeanTimesPrecision = (max.MeanTimesPrecision - zalpha1 * a.GetMean()) / denom; return(Gaussian.FromNatural(resultMeanTimesPrecision, resultPrecision)); } else { beta = ((z * alpha1 - max.Precision) * vx1 * a.Precision + z * z) * w1 - max.Precision * vx1 * w2 * alpha2 * (mx2 * a.Precision - a.MeanTimesPrecision) / (vx2 * a.Precision + 1) - alpha * alpha; } } //Console.WriteLine($"z={z} w1={w1:r} w2={w2:r} logw2={logw2} alpha1={alpha1} alpha2={alpha2} alpha={alpha:r} beta={beta:r}"); if (checkDerivatives) { double m1 = a.GetMean(); double delta = m1 * 1e-6; double logzd, logw1d, alpha1d, vx1d, mx1d, logw2d, alpha2d, vx2d, mx2d; ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 + delta, a.Precision), b, out logzd, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d); double logzd2; ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 - delta, a.Precision), b, out logzd2, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d); double alphaCheck = (logzd - logzd2) / (2 * delta); double alphaError = Math.Abs(alpha - alphaCheck); double betaCheck = (logzd + logzd2 - 2 * logz) / (delta * delta); double betaError = Math.Abs(beta - betaCheck); Console.WriteLine($"alpha={alpha} check={alphaCheck} error={alphaError} beta={beta} check={betaCheck} error={betaError}"); } return(GaussianOp.GaussianFromAlphaBeta(a, alpha, -beta, ForceProper)); } else { double m1, v1, m2, v2; a.GetMeanAndVariance(out m1, out v1); b.GetMeanAndVariance(out m2, out v2); // the posterior is a mixture model with weights exp(logw1-logz), exp(logw2-logz) and distributions // N(a; mx1, vx1) phi((a - m2)/sqrt(v2)) / phi((mx1 - m2)/sqrt(vx1 + v2)) // N(a; m1, v1) phi((mx2 - a)/sqrt(vx2)) / phi((mx2 - m1)/sqrt(vx2 + v1)) // the moments of the posterior are computed via the moments of these two components. if (vx1 == 0) { alpha1 = 0; } if (vx2 == 0) { alpha2 = 0; } double mc1 = mx1; if (alpha1 != 0) // avoid 0*infinity { mc1 += alpha1 * vx1; } alpha2 = -alpha2; double mc2 = m1; if (alpha2 != 0) // avoid 0*infinity { mc2 += alpha2 * v1; } // z2 = (mx2 - m1) / Math.Sqrt(vx2 + v1) // logw2 = MMath.NormalCdfLn(z2); // alpha2 = -Math.Exp(Gaussian.GetLogProb(mx2, m1, vx2 + v1) - logw2); // = -1/sqrt(vx2+v1)/NormalCdfRatio(z2) // m1 + alpha2*v1 = sqrt(vx2+v1)*(m1/sqrt(vx2+v1) - v1/(vx2+v1)/NormalCdfRatio(z2)) // = sqrt(vx2+v1)*(mx2/sqrt(vx2+v1) - z2 - v1/(vx2+v1)/NormalCdfRatio(z2)) // = sqrt(vx2+v1)*(mx2/sqrt(vx2+v1) - dY/Y) if vx2=0 double z2 = 0, Y = 0, dY = 0; const double z2small = 0; if (vx2 == 0) { z2 = (mx2 - m1) / Math.Sqrt(vx2 + v1); if (z2 < z2small) { Y = MMath.NormalCdfRatio(z2); dY = MMath.NormalCdfMomentRatio(1, z2); mc2 = mx2 - Math.Sqrt(v1) * dY / Y; } } double m = w1 * mc1 + w2 * mc2; double beta1; if (alpha1 == 0) { beta1 = 0; // avoid 0*infinity } else { double r1 = (mx1 - m2) / (vx1 + v2); beta1 = alpha1 * (alpha1 + r1); } double beta2; if (alpha2 == 0) { beta2 = 0; // avoid 0*infinity } else { double r2 = (mx2 - m1) / (vx2 + v1); beta2 = alpha2 * (alpha2 - r2); } double vc1 = vx1 * (1 - vx1 * beta1); double vc2; if (vx2 == 0 && z2 < z2small) { // beta2 = alpha2 * (alpha2 - z2/sqrt(v1)) // vc2 = v1 - v1^2 * alpha2 * (alpha2 - z2/sqrt(v1)) // = v1 - v1*dY/Y^2 // =approx v1/z2^2 // posterior E[x^2] = v - v*dY/Y^2 + v*dY^2/Y^2 = v - v*dY/Y^2*(1 - dY) = v + v*z*dY/Y = v*d2Y/Y //vc2 = v1 * (1 - dY / (Y * Y)); double d2Y = 2 * MMath.NormalCdfMomentRatio(2, z2); double dYiY = dY / Y; vc2 = v1 * (d2Y / Y - dYiY * dYiY); } else if (beta2 == 0) { vc2 = v1; } else { vc2 = v1 * (1 - v1 * beta2); } double diff = mc1 - mc2; double v = w1 * vc1 + w2 * vc2 + w1 * w2 * diff * diff; Gaussian result = new Gaussian(m, v); //Console.WriteLine($"z2={z2} m={m} v={v} vc2={vc2} diff={diff}"); result.SetToRatio(result, a, ForceProper); if (Double.IsNaN(result.Precision) || Double.IsNaN(result.MeanTimesPrecision)) { throw new InferRuntimeException($"result is NaN. max={max}, a={a}, b={b}"); } return(result); } }
public static Gaussian XAverageConditional_Helper([SkipIfUniform] Bernoulli isPositive, [SkipIfUniform, Proper] Gaussian x, bool forceProper) { Gaussian result = new Gaussian(); if (x.IsPointMass) { result.SetToUniform(); return(result); } double prec = x.Precision; if (prec == 0.0) { result.SetToUniform(); return(result); } else if (prec < 0) { throw new ImproperMessageException(x); } double sqrtPrec = Math.Sqrt(prec); double tau = x.MeanTimesPrecision; // m/sqrt(v) = (m/v)/sqrt(1/v) double z = tau / sqrtPrec; // epsilon = p(b=F) // eq (51) in EP quickref double alpha; if (isPositive.IsPointMass) { if (isPositive.Point) { if (z < -100) { double Y = MMath.NormalCdfRatio(z); double d2Y = 2 * MMath.NormalCdfMomentRatio(2, z); double m2TimesPrec = d2Y / Y; Assert.IsTrue(tau != 0); double mp = (m2TimesPrec - 1) / tau; double vp = m2TimesPrec / prec - mp * mp; return((new Gaussian(mp, vp)) / x); } alpha = sqrtPrec / MMath.NormalCdfRatio(z); } else { if (z > 100) { double Y = MMath.NormalCdfRatio(-z); // dY = -(d2Y/prec - Y)/(-z)*sqrtPrec // dY/Y/prec = -(d2Y/Y/prec/prec - 1/prec)/(-z)*sqrtPrec // dY/Y/prec = -(d2Y/Y/prec - 1)/(-tau) //double dY = -MMath.NormalCdfMomentRatio(1,-z)*sqrtPrec; double d2Y = 2 * MMath.NormalCdfMomentRatio(2, -z); double m2TimesPrec = d2Y / Y; Assert.IsTrue(tau != 0); double mp = (m2TimesPrec - 1) / tau; double vp = m2TimesPrec / prec - mp * mp; return((new Gaussian(mp, vp)) / x); } alpha = -sqrtPrec / MMath.NormalCdfRatio(-z); } } else { //double v = MMath.LogSumExp(isPositive.LogProbTrue + MMath.NormalCdfLn(z), isPositive.LogProbFalse + MMath.NormalCdfLn(-z)); double v = LogAverageFactor(isPositive, x); alpha = sqrtPrec * Math.Exp(-z * z * 0.5 - MMath.LnSqrt2PI - v) * (2 * isPositive.GetProbTrue() - 1); } // eq (52) in EP quickref (where tau = mnoti/Vnoti) double beta = alpha * (alpha + tau); double weight = beta / (prec - beta); if (forceProper && weight < 0) { weight = 0; } // eq (31) in EP quickref; same as inv(inv(beta)-inv(prec)) result.Precision = prec * weight; // eq (30) in EP quickref times above and simplified result.MeanTimesPrecision = weight * (tau + alpha) + alpha; if (double.IsNaN(result.Precision) || double.IsNaN(result.MeanTimesPrecision)) { throw new ApplicationException("result is nan"); } return(result); }