/// <summary> /// Computes GammaLower(a, r*u) - GammaLower(a, r*l) to high accuracy. /// </summary> /// <param name="shape"></param> /// <param name="rate"></param> /// <param name="lowerBound"></param> /// <param name="upperBound"></param> /// <param name="regularized"></param> /// <returns></returns> public static double GammaProbBetween(double shape, double rate, double lowerBound, double upperBound, bool regularized = true) { double rl = rate * lowerBound; // Use the criterion from Gautschi (1979) to determine whether GammaLower(a,x) or GammaUpper(a,x) is smaller. bool lowerIsSmaller; if (rl > 0.25) { lowerIsSmaller = (shape > rl + 0.25); } else { lowerIsSmaller = (shape > -MMath.Ln2 / Math.Log(rl)); } if (!lowerIsSmaller) { double logl = Math.Log(lowerBound); if (rate * upperBound < 1e-16 && shape < -1e-16 / (Math.Log(rate) + logl)) { double logu = Math.Log(upperBound); return(shape * (logu - logl)); } else { // This is inaccurate when lowerBound is close to upperBound. In that case, use a Taylor expansion of lowerBound around upperBound. return(MMath.GammaUpper(shape, rl, regularized) - MMath.GammaUpper(shape, rate * upperBound, regularized)); } } else { double diff = MMath.GammaLower(shape, rate * upperBound) - MMath.GammaLower(shape, rl); return(regularized ? diff : (MMath.Gamma(shape) * diff)); } }
/// <summary> /// Computes <c>GammaUpper(s,x)/(x^(s-1)*exp(-x)) - 1</c> to high accuracy /// </summary> /// <param name="s"></param> /// <param name="x">A real number gt;= 45 and gt; <paramref name="s"/>/0.99</param> /// <param name="regularized"></param> /// <returns></returns> public static double GammaUpperRatio(double s, double x, bool regularized = true) { if (s >= x * 0.99) { throw new ArgumentOutOfRangeException(nameof(s), s, "s >= x*0.99"); } if (x < 45) { throw new ArgumentOutOfRangeException(nameof(x), x, "x < 45"); } double term = (s - 1) / x; double sum = term; for (int i = 2; i < 1000; i++) { term *= (s - i) / x; double oldSum = sum; sum += term; if (MMath.AreEqual(sum, oldSum)) { return(regularized ? sum / MMath.Gamma(s) : sum); } } throw new Exception($"GammaUpperRatio not converging for s={s:g17}, x={x:g17}, regularized={regularized}"); }
private static void VarianceGammaTimesGaussianMoments(double a, double m, double v, out double sum, out double moment1, out double moment2) { int n = 1000000; double lowerBound = -20; double upperBound = 20; double range = upperBound - lowerBound; sum = 0; double sumx = 0, sumx2 = 0; for (int i = 0; i < n; i++) { double x = range * i / (n - 1) + lowerBound; double absx = System.Math.Abs(x); double diff = x - m; double logp = -0.5 * diff * diff / v - absx; double p = System.Math.Exp(logp); if (a == 1) { // do nothing } else if (a == 2) { p *= 1 + absx; } else if (a == 3) { p *= 3 + 3 * absx + absx * absx; } else if (a == 4) { p *= 15 + 15 * absx + 6 * absx * absx + absx * absx * absx; } else { throw new ArgumentException("a is not in {1,2,3,4}"); } sum += p; sumx += x * p; sumx2 += x * x * p; } moment1 = sumx / sum; moment2 = sumx2 / sum; sum /= MMath.Gamma(a) * System.Math.Pow(2, a); sum /= MMath.Sqrt2PI * System.Math.Sqrt(v); double inc = range / (n - 1); sum *= inc; }
public static double[] xBesselKDerivativesAt0(int n, double a) { double[] derivs = new double[n + 1]; derivs[0] = MMath.Gamma(System.Math.Abs(a)) * System.Math.Pow(2, a - 0.5) / System.Math.Sqrt(System.Math.PI); if (n > 0) { derivs[1] = derivs[0]; if (n > 1) { double[] derivs2 = xBesselKDerivativesAt0(n - 2, a - 1); for (int i = 0; i < n - 2; i++) { derivs[i + 2] = derivs[i + 1] - (i + 1) * derivs2[i]; } } } return(derivs); }
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); }
// 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)); } }
/// <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); }