public void WatsonIntegrals() { // Watson defined and analytically integrated three complicated triple integrals related to random walks in three dimension // See http://mathworld.wolfram.com/WatsonsTripleIntegrals.html Interval watsonWidth = Interval.FromEndpoints(0.0, Math.PI); Interval[] watsonBox = new Interval[] { watsonWidth, watsonWidth, watsonWidth }; Assert.IsTrue( MultiFunctionMath.Integrate( (IReadOnlyList <double> x) => 1.0 / (1.0 - Math.Cos(x[0]) * Math.Cos(x[1]) * Math.Cos(x[2])), watsonBox ).Estimate.ConfidenceInterval(0.99).ClosedContains( MoreMath.Pow(AdvancedMath.Gamma(1.0 / 4.0), 4) / 4.0 ) ); Assert.IsTrue( MultiFunctionMath.Integrate( (IReadOnlyList <double> x) => 1.0 / (3.0 - Math.Cos(x[0]) * Math.Cos(x[1]) - Math.Cos(x[1]) * Math.Cos(x[2]) - Math.Cos(x[0]) * Math.Cos(x[2])), watsonBox ).Estimate.ConfidenceInterval(0.99).ClosedContains( 3.0 * MoreMath.Pow(AdvancedMath.Gamma(1.0 / 3.0), 6) / Math.Pow(2.0, 14.0 / 3.0) / Math.PI ) ); Assert.IsTrue( MultiFunctionMath.Integrate( (IReadOnlyList <double> x) => 1.0 / (3.0 - Math.Cos(x[0]) - Math.Cos(x[1]) - Math.Cos(x[2])), watsonBox ).Estimate.ConfidenceInterval(0.99).ClosedContains( Math.Sqrt(6.0) / 96.0 * AdvancedMath.Gamma(1.0 / 24.0) * AdvancedMath.Gamma(5.0 / 24.0) * AdvancedMath.Gamma(7.0 / 24.0) * AdvancedMath.Gamma(11.0 / 24.0) ) ); }
public void HypergeometricAtOne() { // A&S 15.1.20 foreach (double a in abcs) { foreach (double b in abcs) { foreach (double c in abcs) { // Formula only hold for positive real c-a-b if ((c - a - b) <= 0.0) { continue; } // Formula is still right for non-positive c, but to handle it we would need to deal with canceling infinite Gammas if (IsNonpositiveInteger(c)) { continue; } Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(a, b, c, 1.0), AdvancedMath.Gamma(c) * AdvancedMath.Gamma(c - a - b) / AdvancedMath.Gamma(c - a) / AdvancedMath.Gamma(c - b) )); } } } }
public void HypergeometricAtMinusOne() { foreach (double a in abcs) { if ((a <= 0.0) && (Math.Round(a) == a)) { continue; } Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(1.0, a, a + 1.0, -1.0), a / 2.0 * (AdvancedMath.Psi((a + 1.0) / 2.0) - AdvancedMath.Psi(a / 2.0)) )); foreach (double b in abcs) { double c = a - b + 1.0; if ((c <= 0.0) && (Math.Round(c) == c)) { continue; } // If result vanishes, returned value may just be very small. double R = AdvancedMath.Gamma(a - b + 1.0) * AdvancedMath.Gamma(a / 2.0 + 1.0) / AdvancedMath.Gamma(a + 1.0) / AdvancedMath.Gamma(a / 2.0 - b + 1.0); if (R == 0.0) { Assert.IsTrue(Math.Abs(AdvancedMath.Hypergeometric2F1(a, b, a - b + 1.0, -1.0)) <= 1.0E-14); } else { Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Hypergeometric2F1(a, b, a - b + 1.0, -1.0), R)); } } } }
public void BesselInflectionValue() { // Abromowitz derived a series for J_{\nu}(\nu) and Y_{\nu}(\nu), // the value at the inflection point. // These appear in A&S 9.3.31 - 9.3.34 with numerical values for the coefficients. // Symbolic values for the coefficients appear in Jentschura & Loetstedt 2011 // (https://arxiv.org/abs/1112.0072) // This is a fairly onerous test to code, but it is a good one, because // the Bessel functions are difficult to calculate in this region. double A = Math.Pow(2.0, 1.0 / 3.0) / Math.Pow(3.0, 2.0 / 3.0) / AdvancedMath.Gamma(2.0 / 3.0); double B = Math.Pow(2.0, 2.0 / 3.0) / Math.Pow(3.0, 1.0 / 3.0) / AdvancedMath.Gamma(1.0 / 3.0); double[] a = new double[] { 1.0, -1.0 / 225.0, 151439.0 / 218295000.0, -887278009.0 / 2504935125000.0, 1374085664813273149.0 / 3633280647121125000000.0 }; double[] b = new double[] { 1.0 / 70.0, -1213.0 / 1023750.0, 16542537833.0 / 37743205500000.0, -9597171184603.0 / 25476663712500000.0, 53299328587804322691259.0 / 91182706744837207500000000.0 }; foreach (double nu in TestUtilities.GenerateRealValues(10.0, 100.0, 8)) { double Af = A / Math.Pow(nu, 1.0 / 3.0); double Bf = B / Math.Pow(nu, 5.0 / 3.0); double J = 0.0; double dJ = 0.0; for (int k = 0; k < Math.Min(a.Length, b.Length); k++) { double nuk = MoreMath.Pow(nu, 2 * k); dJ = Af * a[k] / nuk; J += dJ; dJ = Bf * b[k] / nuk; J -= dJ; } EvaluationSettings e = new EvaluationSettings() { RelativePrecision = TestUtilities.TargetPrecision, AbsolutePrecision = Math.Abs(dJ) }; TestUtilities.IsNearlyEqual(AdvancedMath.BesselJ(nu, nu), J, e); } }
/// <summary> /// Initializes a new instance of a Gamma distribution with the given parameters. /// </summary> /// <param name="shape">The shape parameter, which must be positive.</param> /// <param name="scale">The scale parameter, which must be positive.</param> public GammaDistribution(double shape, double scale) { if (shape <= 0.0) { throw new ArgumentOutOfRangeException("shape"); } if (scale <= 0.0) { throw new ArgumentOutOfRangeException("scale"); } a = shape; s = scale; // depending on size of a, store Gamma(a) or -Ln(Gamma(a)) for future use if (a < 64.0) { ga = AdvancedMath.Gamma(a); } else { ga = -AdvancedMath.LogGamma(a); } gammaRng = DeviateGeneratorFactory.GetGammaGenerator(a); }
public override double RawMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(1.0); } else if (r == 1) { return(Global.SqrtHalfPI * (1.0 - 1.0 / 6.0 / sqrt_n)); } else if (r == 3) { return(Global.SqrtHalfPI * (3.0 / 2.0 * AdvancedMath.Apery - 3.0 / 4.0 / sqrt_n)); } else { // we needed to handle 1st and 3rd moments specially because \zeta divergences but multiplication by zero gives finite result return(AdvancedMath.Gamma(r / 2.0 + 1.0) / Math.Pow(2.0, r / 2.0 - 1.0) * ((r - 1) * AdvancedMath.RiemannZeta(r) - (r - 3) * AdvancedMath.RiemannZeta(r - 2) / sqrt_n) ); } }
public void GammaRecurrsion() { // Limit x to avoid overflow. foreach (double x in TestUtilities.GenerateRealValues(1.0E-4, 1.0E2, 16)) { Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Gamma(x + 1.0), x * AdvancedMath.Gamma(x))); } }
public void GammaAtNegativeIntegers() { Assert.IsTrue(Double.IsInfinity(AdvancedMath.Gamma(0.0))); foreach (int n in TestUtilities.GenerateIntegerValues(1, 100, 4)) { Assert.IsTrue(Double.IsInfinity(AdvancedMath.Gamma(-n))); } }
public void GammaReflection() { foreach (double x in TestUtilities.GenerateRealValues(1.0E-4, 1.0E2, 16)) { double GP = AdvancedMath.Gamma(x); double GN = AdvancedMath.Gamma(-x); Assert.IsTrue(TestUtilities.IsNearlyEqual(-x * GN * GP, Math.PI / MoreMath.SinPi(x))); } }
public void HypergeometricLinearTransforms() { foreach (double a in abcs) { foreach (double b in abcs) { foreach (double c in abcs) { if (IsNonpositiveInteger(c)) { continue; } foreach (double x in xs) { double F = AdvancedMath.Hypergeometric2F1(a, b, c, x); // A&S 15.3.3 Assert.IsTrue(TestUtilities.IsNearlyEqual(F, AdvancedMath.Hypergeometric2F1(c - a, c - b, c, x) * Math.Pow(1.0 - x, c - a - b))); // A&S 15.3.4 Assert.IsTrue(TestUtilities.IsNearlyEqual(F, AdvancedMath.Hypergeometric2F1(a, c - b, c, x / (x - 1.0)) * Math.Pow(1.0 - x, -a))); // A&S 15.3.5 Assert.IsTrue(TestUtilities.IsNearlyEqual(F, AdvancedMath.Hypergeometric2F1(b, c - a, c, x / (x - 1.0)) * Math.Pow(1.0 - x, -b))); // A&S 15.3.6 if (!IsNonpositiveInteger(c - a - b) && !IsNonpositiveInteger(a + b - c) && (x > 0.0)) { Assert.IsTrue(TestUtilities.IsSumNearlyEqual( new double[] { AdvancedMath.Gamma(c) * AdvancedMath.Gamma(c - a - b) / AdvancedMath.Gamma(c - a) / AdvancedMath.Gamma(c - b) * AdvancedMath.Hypergeometric2F1(a, b, a + b - c + 1.0, 1.0 - x), AdvancedMath.Gamma(c) * AdvancedMath.Gamma(a + b - c) / AdvancedMath.Gamma(a) / AdvancedMath.Gamma(b) * AdvancedMath.Hypergeometric2F1(c - a, c - b, c - a - b + 1.0, 1.0 - x) * Math.Pow(1.0 - x, c - a - b) }, F )); } // A&S 15.3.7 if (!IsNonpositiveInteger(a - b) && !IsNonpositiveInteger(b - a) && (x < 0.0)) { Assert.IsTrue(TestUtilities.IsSumNearlyEqual( new double[] { AdvancedMath.Gamma(c) * AdvancedMath.Gamma(b - a) / AdvancedMath.Gamma(b) / AdvancedMath.Gamma(c - a) * AdvancedMath.Hypergeometric2F1(a, 1.0 - c + a, 1.0 - b + a, 1.0 / x) * Math.Pow(-x, -a), AdvancedMath.Gamma(c) * AdvancedMath.Gamma(a - b) / AdvancedMath.Gamma(a) / AdvancedMath.Gamma(c - b) * AdvancedMath.Hypergeometric2F1(b, 1.0 - c + b, 1.0 - a + b, 1.0 / x) * Math.Pow(-x, -b) }, F )); } } } } } }
public void GammaTrottIdentity() { // http://mathworld.wolfram.com/GammaFunction.html double G1 = AdvancedMath.Gamma(1.0 / 24.0); double G5 = AdvancedMath.Gamma(5.0 / 24.0); double G7 = AdvancedMath.Gamma(7.0 / 24.0); double G11 = AdvancedMath.Gamma(11.0 / 24.0); Assert.IsTrue(TestUtilities.IsNearlyEqual((G1 * G11) / (G5 * G7), Math.Sqrt(3.0) * Math.Sqrt(2.0 + Math.Sqrt(3.0)))); }
private double GammaProduct(int r) { double p = 1.0; for (int i = 1; i < r; i++) { p *= AdvancedMath.Gamma(((double)i) / r); } return(p); }
public void HypergeometricAtOneNinth() { foreach (double a in abcs) { Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(a, a + 0.5, 5.0 / 6.0 + 2.0 / 3.0 * a, 1.0 / 9.0), Math.Sqrt(Math.PI) * Math.Pow(3.0 / 4.0, a) * AdvancedMath.Gamma(5.0 / 6.0 + 2.0 / 3.0 * a) / AdvancedMath.Gamma(1.0 / 2.0 + 1.0 / 3.0 * a) / AdvancedMath.Gamma(5.0 / 6.0 + 1.0 / 3.0 * a) )); } }
public void HypergeometricAtMinusOneThird() { foreach (double a in abcs) { Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(a, a + 0.5, 1.5 - 2.0 * a, -1.0 / 3.0), Math.Pow(8.0 / 9.0, -2.0 * a) * AdvancedMath.Gamma(4.0 / 3.0) / AdvancedMath.Gamma(3.0 / 2.0) * AdvancedMath.Gamma(3.0 / 2.0 - 2.0 * a) / AdvancedMath.Gamma(4.0 / 3.0 - 2.0 * a) )); } }
public void GammaDuplication() { foreach (double x in TestUtilities.GenerateRealValues(1.0E-4, 1.0E2, 16)) { Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Gamma(2.0 * x), AdvancedMath.Gamma(x) * AdvancedMath.Gamma(x + 0.5) * Math.Pow(2.0, 2.0 * x - 1.0) / Math.Sqrt(Math.PI) )); } }
public void GammaIntegral() { foreach (double x in TestUtilities.GenerateRealValues(1.0, 1.0E2, 4)) { Func <double, double> f = delegate(double t) { return(Math.Pow(t, x - 1.0) * Math.Exp(-t)); }; Interval r = Interval.FromEndpoints(0.0, Double.PositiveInfinity); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Gamma(x), FunctionMath.Integrate(f, r))); } }
/// <inheritdoc /> public override double RawMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else { return(Math.Pow(2.0, r / 2.0) * AdvancedMath.Gamma(1.0 + r / 2.0) * MoreMath.Pow(s, r)); } }
public void GammaInequality() { foreach (double x in TestUtilities.GenerateRealValues(2.0, 1.0E2, 16)) { // for x >= 2 double lower = Math.Pow(x / Math.E, x - 1.0); double upper = Math.Pow(x / 2.0, x - 1.0); double value = AdvancedMath.Gamma(x); Assert.IsTrue((lower <= value) && (value <= upper)); } }
public void GammaSpecialCases() { // It would be nice to be able to make more of these comparisons exact. Assert.IsTrue(Double.IsPositiveInfinity(AdvancedMath.Gamma(0.0))); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Gamma(0.5), Math.Sqrt(Math.PI))); Assert.IsTrue(AdvancedMath.Gamma(1.0) == 1.0); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Gamma(1.5), Math.Sqrt(Math.PI) / 2.0)); Assert.IsTrue(AdvancedMath.Gamma(2.0) == 1.0); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Gamma(3.0), 2.0)); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Gamma(4.0), 6.0)); Assert.IsTrue(Double.IsPositiveInfinity(AdvancedMath.Gamma(Double.PositiveInfinity))); }
public void EllipticESPecialCases() { Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticE(0.0), Math.PI / 2.0)); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticE(1.0), 1.0)); double g2 = Math.Pow(AdvancedMath.Gamma(1.0 / 4.0), 2.0); Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.EllipticE(1.0 / Math.Sqrt(2.0)), Math.Pow(Math.PI, 3.0 / 2.0) / g2 + g2 / 8.0 / Math.Sqrt(Math.PI) )); }
// standard deviation inherits from base; nothing special to say about it /// <inheritdoc /> public override double RawMoment(int r) { if (r < 0.0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(1.0); } else { return(Math.Pow(scale, r) * AdvancedMath.Gamma(1.0 + r / shape)); } }
public void AssociatedLaguerreOrthonormality() { // don't let orders get too big, or (1) the Gamma function will overflow and (2) our integral will become highly oscilatory foreach (int n in TestUtilities.GenerateIntegerValues(1, 10, 3)) { foreach (int m in TestUtilities.GenerateIntegerValues(1, 10, 3)) { foreach (double a in TestUtilities.GenerateRealValues(0.1, 10.0, 5)) { //int n = 2; //int m = 4; //double a = 3.5; Console.WriteLine("n={0} m={1} a={2}", n, m, a); // evaluate the orthonormal integral Func <double, double> f = delegate(double x) { return(Math.Pow(x, a) * Math.Exp(-x) * OrthogonalPolynomials.LaguerreL(m, a, x) * OrthogonalPolynomials.LaguerreL(n, a, x) ); }; Interval r = Interval.FromEndpoints(0.0, Double.PositiveInfinity); // need to loosen default evaluation settings in order to get convergence in some of these cases // seems to have most convergence problems for large a IntegrationSettings e = new IntegrationSettings(); e.AbsolutePrecision = TestUtilities.TargetPrecision; e.RelativePrecision = TestUtilities.TargetPrecision; double I = FunctionMath.Integrate(f, r, e).Value; Console.WriteLine(I); // test for orthonormality if (n == m) { Assert.IsTrue(TestUtilities.IsNearlyEqual( I, AdvancedMath.Gamma(n + a + 1) / AdvancedIntegerMath.Factorial(n) )); } else { Assert.IsTrue(Math.Abs(I) < TestUtilities.TargetPrecision); } } } } }
/// <inheritdoc/> public override double RawMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r < a) { // This only works for m = 0 return(MoreMath.Pow(s, r) * AdvancedMath.Gamma(1.0 - r / a)); } else { return(Double.PositiveInfinity); } }
public void GammaMultiplication() { foreach (int k in new int[] { 2, 3, 4 }) { foreach (double z in TestUtilities.GenerateRealValues(1.0E-2, 10.0, 4)) { double p = AdvancedMath.Gamma(z); for (int i = 1; i < k; i++) { p *= AdvancedMath.Gamma(z + ((double)i) / k); } Assert.IsTrue(TestUtilities.IsNearlyEqual( p, Math.Pow(2.0 * Math.PI, (k - 1) / 2.0) * Math.Pow(k, 0.5 - k * z) * AdvancedMath.Gamma(k * z) )); } } }
public static void ComputeSpecialFunctions() { // Compute the value x at which erf(x) is just 10^{-15} from 1. double x = AdvancedMath.InverseErfc(1.0E-15); // The Gamma function at 1/2 is sqrt(pi) double y = AdvancedMath.Gamma(0.5); // Compute a Coulomb Wave Function in the quantum tunneling region SolutionPair s = AdvancedMath.Coulomb(2, 4.5, 3.0); // Compute the Reimann Zeta function at a complex value Complex z = AdvancedComplexMath.RiemannZeta(new Complex(0.75, 6.0)); // Compute the 100th central binomial coefficient double c = AdvancedIntegerMath.BinomialCoefficient(100, 50); }
/* * public override double Variance { * get { * return (Global.HalfPI * (Math.PI / 6.0 - Global.LogTwo * Global.LogTwo) - Global.SqrtHalfPI * Global.LogTwo / 12.0 / Math.Sqrt(n)); * } * } */ public override double Moment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException("r"); } else if (r == 0) { return(1.0); } else { // we can get these expressions just by integrating Q_0' and Q_1' term by term double M0 = AdvancedMath.DirichletEta(r) * AdvancedMath.Gamma(r / 2.0 + 1.0) / Math.Pow(2.0, r / 2.0 - 1.0); double M1 = -2.0 / 3.0 * AdvancedMath.DirichletEta(r - 1) * AdvancedMath.Gamma((r + 1) / 2.0) / Math.Pow(2.0, (r + 1) / 2.0) * r; return(M0 + M1 / Math.Sqrt(n)); } }
/// <inheritdoc /> public override double RawMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(1.0); } else if (r == 1) { return(Mean); } else { return(AdvancedMath.Gamma(r / 2.0 + 1.0) * AdvancedMath.DirichletEta(r) / Math.Pow(2.0, r / 2.0 - 1.0)); } }
public void BallVolumeIntegrals() { // The volume of a d-sphere is \frac{\pi^{d/2}}{\Gamma(d/2 + 1)} // and the fraction in the first quadrant is 1/2^d of that // This is a simple test of the integration of a discontinuous function Func <IList <double>, double> f = delegate(IList <double> x) { double r2 = 0.0; for (int j = 0; j < x.Count; j++) { r2 += x[j] * x[j]; } if (r2 <= 1.0) { return(1.0); } else { return(0.0); } }; for (int d = 1; d <= 8; d++) { if (d == 6) { continue; //. For d=6, integral returns after just ~300 evaluation with an underestimated error; look into this } Console.WriteLine(d); IntegrationResult result = MultiFunctionMath.Integrate(f, UnitCube(d), new EvaluationSettings() { AbsolutePrecision = 0.0, RelativePrecision = 5.0E-3, EvaluationBudget = 1000000 }); double V = Math.Pow(Math.PI, d / 2.0) / AdvancedMath.Gamma(d / 2.0 + 1.0) * MoreMath.Pow(2.0, -d); Console.WriteLine("{0} ({1}) {2}: {3}", result.Value, result.Precision, result.Value - V, result.EvaluationCount); Assert.IsTrue(TestUtilities.IsNearlyEqual(result.Value, V, new EvaluationSettings() { AbsolutePrecision = 4.0 * result.Precision })); } }
private double ProbabilityDensity_Series(double x) { double z = lambda * x / 4.0; double halfNu = nu / 2.0; double t = 1.0 / AdvancedMath.Gamma(halfNu); double s = t; for (int k = 1; k < Global.SeriesMax; k++) { double s_old = s; t *= z / k / (k - 1 + halfNu); s += t; if (s == s_old) { return(s); } } throw new NonconvergenceException(); }
public void BallVolumeIntegrals() { // The volume of a d-sphere is \frac{\pi^{d/2}}{\Gamma(d/2 + 1)} // and the fraction in the first quadrant is 1/2^d of that. // This is a simple test of the integration of a discontinuous function. Func <IReadOnlyList <double>, double> f = delegate(IReadOnlyList <double> x) { double r2 = 0.0; for (int j = 0; j < x.Count; j++) { r2 += x[j] * x[j]; } if (r2 <= 1.0) { return(1.0); } else { return(0.0); } }; for (int d = 1; d <= 8; d++) { if (d == 6) { continue; //. For d=6, integral returns after just ~300 evaluation with an underestimated error; look into this } Console.WriteLine(d); IntegrationSettings settings = new IntegrationSettings() { AbsolutePrecision = 0.0, RelativePrecision = 1.0E-2 }; IntegrationResult result = MultiFunctionMath.Integrate(f, UnitCube(d), settings); double V = Math.Pow(Math.PI, d / 2.0) / AdvancedMath.Gamma(d / 2.0 + 1.0) * MoreMath.Pow(2.0, -d); Assert.IsTrue(result.Estimate.ConfidenceInterval(0.95).ClosedContains(V)); } }