public void LogGammaSpecialValues() { Assert.IsTrue(Double.IsPositiveInfinity(AdvancedMath.LogGamma(0.0))); Assert.IsTrue(AdvancedMath.LogGamma(1.0) == 0.0); Assert.IsTrue(AdvancedMath.LogGamma(2.0) == 0.0); Assert.IsTrue(Double.IsPositiveInfinity(AdvancedMath.LogGamma(Double.PositiveInfinity))); }
public void EllipticFSpecialCases() { foreach (double phi in TestUtilities.GenerateUniformRealValues(-10.0, 10.0, 8)) { Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticF(phi, 0.0), phi)); } }
public void HypergeometricQuadraticTransforms() { foreach (double a in abcs) { foreach (double b in abcs) { foreach (double x in xs) { if (!IsNonpositiveInteger(2.0 * b)) { Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(a, b, 2.0 * b, x), AdvancedMath.Hypergeometric2F1(0.5 * a, b - 0.5 * a, b + 0.5, x * x / (x - 1.0) / 4.0) / Math.Pow(1.0 - x, 0.5 * a), TestUtilities.TargetPrecision * 1000.0 )); } // Wrong sign, but Mathematica agrees with values! /* * if (!IsNonpositiveInteger(a - b + 1.0)) { * Assert.IsTrue(TestUtilities.IsNearlyEqual( * AdvancedMath.Hypergeometric2F1(a, b, a - b + 1.0, x), * AdvancedMath.Hypergeometric2F1(0.5 * a, 0.5 * a - b + 0.5, a - b + 1.0, -4.0 * x / MoreMath.Sqr(1.0 - x)) / Math.Pow(1.0 - x, a) * )); * } */ } } } }
public void HypergeometricCubicTransforms() { foreach (double a in abcs) { foreach (double x in xs) { // DLMF 15.8.31 //if ((a == 7.0) && (x == 0.8)) continue; if ((a == -3.0) && (x == 0.8)) { continue; } if ((a == 3.1) && (x == -5.0)) { continue; } if ((a == 4.5) && (x == -5.0)) { continue; } if ((a == 7.0) && (x == -5.0)) { continue; } if (x < 8.0 / 9.0) { Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(3.0 * a, 3.0 * a + 0.5, 4.0 * a + 2.0 / 3.0, x), AdvancedMath.Hypergeometric2F1(a, a + 0.5, 2.0 * a + 5.0 / 6.0, 27.0 * x * x * (x - 1.0) / MoreMath.Sqr(9.0 * x - 8.0)) * Math.Pow(1.0 - 9.0 / 8.0 * x, -2.0 * a) )); } } } }
public void ModifiedBesselGeneratingFunction() { // DLMF 10.35.1 // e^{(z/2)(t + 1/t)} = \sum_{k=-\infty}^{+\infty} t^k I_k(z) foreach (double t in TestUtilities.GenerateRealValues(1.0E-1, 1.0E-1, 4)) { foreach (double z in TestUtilities.GenerateRealValues(1.0E-2, 1.0E1, 4)) { double tn = 1.0; double S = AdvancedMath.ModifiedBesselI(0, z); for (int n = 1; n < 100; n++) { double S_old = S; tn *= t; S += tn * AdvancedMath.ModifiedBesselI(n, z) + AdvancedMath.ModifiedBesselI(-n, z) / tn; if (S == S_old) { goto Test; } } throw new NonconvergenceException(); Test: Assert.IsTrue(TestUtilities.IsNearlyEqual( S, Math.Exp(z / 2.0 * (t + 1.0 / t)) )); } } }
public void HypergeometricAtSpecialPoints() { // Documented at http://mathworld.wolfram.com/HypergeometricFunction.html Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(1.0 / 3.0, 2.0 / 3.0, 5.0 / 6.0, 27.0 / 32.0), 8.0 / 5.0 )); Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(0.25, 0.5, 0.75, 80.0 / 81.0), 9.0 / 5.0 )); Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(1.0 / 8.0, 3.0 / 8.0, 1.0 / 2.0, 2400.0 / 2401.0), 2.0 / 3.0 * Math.Sqrt(7.0) )); Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(1.0 / 6.0, 1.0 / 3.0, 1.0 / 2.0, 25.0 / 27.0), 3.0 / 4.0 * Math.Sqrt(3.0) )); Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(1.0 / 6.0, 1.0 / 2.0, 2.0 / 3.0, 125.0 / 128.0), 4.0 / 3.0 * Math.Pow(2.0, 1.0 / 6.0) )); Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.Hypergeometric2F1(1.0 / 12.0, 5.0 / 12.0, 1.0 / 2.0, 1323.0 / 1331.0), 3.0 / 4.0 * Math.Pow(11.0, 1.0 / 4.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 EllipticKIntegrals() { Interval i = Interval.FromEndpoints(0.0, 1.0); // http://mathworld.wolfram.com/CatalansConstant.html equation 37 Assert.IsTrue(TestUtilities.IsNearlyEqual( FunctionMath.Integrate( k => AdvancedMath.EllipticK(k), Interval.FromEndpoints(0.0, 1.0)), 2.0 * AdvancedMath.Catalan )); Assert.IsTrue(TestUtilities.IsNearlyEqual( FunctionMath.Integrate( k => AdvancedMath.EllipticK(k) * k, Interval.FromEndpoints(0.0, 1.0)), 1.0 )); Assert.IsTrue(TestUtilities.IsNearlyEqual( FunctionMath.Integrate( k => AdvancedMath.EllipticK(k) / (1.0 + k), Interval.FromEndpoints(0.0, 1.0)), Math.PI * Math.PI / 8.0 )); }
public void HypergeometricIncompleteBeta() { foreach (double a in abcs) { if (a <= 0.0) { continue; } foreach (double b in abcs) { if (b <= 0.0) { continue; } foreach (double x in xs) { if ((x < 0.0) || (x > 1.0)) { continue; } Assert.IsTrue(TestUtilities.IsNearlyEqual( Math.Pow(x, a) * Math.Pow(1.0 - x, b) * AdvancedMath.Hypergeometric2F1(a + b, 1.0, a + 1.0, x) / a, AdvancedMath.Beta(a, b, x) )); } } } }
public void HypergeometricIntegral() { // A&S 15.3.1 // F(a, b, c, x) = \frac{\Gamma(c)}{\Gamma(b) \Gamma(c - b)} // \int_{0}^{1} \! dt \, t^{b-1} (1 - t)^{c - b - 1} (1 - x t)^{-a} // Choose limits on a, b, c so that singularities of integrand are numerically integrable. foreach (double a in TestUtilities.GenerateRealValues(1.0, 10.0, 2)) { foreach (double b in TestUtilities.GenerateRealValues(0.6, 10.0, 2)) { foreach (double c in TestUtilities.GenerateRealValues(b + 0.6, 10.0, 2)) { foreach (double x in xs) { double I = FunctionMath.Integrate( t => Math.Pow(t, b - 1.0) * Math.Pow(1.0 - t, c - b - 1.0) * Math.Pow(1.0 - x * t, -a), Interval.FromEndpoints(0.0, 1.0) ); double B = AdvancedMath.Beta(b, c - b); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Hypergeometric2F1(a, b, c, x), I / B)); } } } } }
/// <summary> /// Initializes a new β distribution. /// </summary> /// <param name="alpha">The left shape parameter, which controls the form of the distribution near x=0.</param> /// <param name="beta">The right shape parameter, which controls the form of the distribution near x=1.</param> /// <remarks> /// <para>The <paramref name="alpha"/> shape parameter controls the form of the distribution near x=0. The /// <paramref name="beta"/> shape parameter controls the form of the distribution near z=1. If a shape parameter /// is less than one, the PDF diverges on the side of the distribution it controls. If a shape parameter /// is greater than one, the PDF goes to zero on the side of the distribution it controls. If the left and right /// shape parameters are equal, the distribution is symmetric about x=1/2.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="alpha"/> or <paramref name="beta"/> is non-positive.</exception> public BetaDistribution(double alpha, double beta) { if (alpha <= 0.0) { throw new ArgumentOutOfRangeException(nameof(alpha)); } if (beta <= 0.0) { throw new ArgumentOutOfRangeException(nameof(beta)); } this.a = alpha; this.b = beta; // cache value of B(alpha, beta) to avoid having to re-calculate it whenever needed this.bigB = AdvancedMath.Beta(alpha, beta); // get a beta generator if (alpha < 0.75 && beta < 0.75) { this.betaRng = new JoehnkBetaGenerator(alpha, beta); } else if (alpha > 1.0 && beta > 1.0) { this.betaRng = new ChengBetaGenerator(alpha, beta); } else { this.betaRng = DeviateGeneratorFactory.GetBetaGenerator(alpha, beta); } // get a beta inverter this.betaInverter = new BetaInverter(alpha, beta); }
public void SphericalBesselSpecialCase() { Assert.IsTrue(AdvancedMath.SphericalBesselJ(0, 0.0) == 1.0); Assert.IsTrue(AdvancedMath.SphericalBesselJ(1, 0.0) == 0.0); Assert.IsTrue(AdvancedMath.SphericalBesselY(0, 0.0) == Double.NegativeInfinity); Assert.IsTrue(AdvancedMath.SphericalBesselY(1, 0.0) == Double.NegativeInfinity); }
/// <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(nameof(shape)); } if (scale <= 0.0) { throw new ArgumentOutOfRangeException(nameof(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 void RootOfPsi() { double x = FunctionMath.FindZero(AdvancedMath.Psi, 1.5); Assert.IsTrue(TestUtilities.IsNearlyEqual(x, 1.46163214496836234126)); Assert.IsTrue(AdvancedMath.Psi(x) < TestUtilities.TargetPrecision); }
public void HypergeometrticRecurrenceA() { // A&S 15.2.10 foreach (double a in abcs) { foreach (double b in abcs) { foreach (double c in abcs) { foreach (double x in xs) { double FM = AdvancedMath.Hypergeometric2F1(a - 1.0, b, c, x); double F0 = AdvancedMath.Hypergeometric2F1(a, b, c, x); double FP = AdvancedMath.Hypergeometric2F1(a + 1.0, b, c, x); if ((c == a) && Double.IsNaN(FM)) { continue; } Assert.IsTrue(TestUtilities.IsSumNearlyEqual( new double[] { (c - a) * FM, (2.0 * a - c - a * x + b * x) * F0 }, -a * (x - 1.0) * FP, new EvaluationSettings() { RelativePrecision = 1.0E-12, AbsolutePrecision = 1.0E-15 } )); } } } } }
public void EllipticNomeAgreement() { foreach (double k in TestUtilities.GenerateRealValues(1.0E-2, 1.0, 4)) { double K = AdvancedMath.EllipticK(k); double k1 = Math.Sqrt((1.0 - k) * (1.0 + k)); double K1 = AdvancedMath.EllipticK(k1); double q = AdvancedMath.EllipticNome(k); // For k << 1, this test fails if formulated as q = e^{\pi K' / K}. // Problem is that computation of k' looses some digits to cancellation, // then K' is near singularity so error is amplified, then // exp function amplifies error some more. Investigation indicates // that q agrees with Mathematica to nearly all digits, so problem // isn't in nome function. Run test in log space and don't let k get // extremely small. Assert.IsTrue(TestUtilities.IsNearlyEqual( Math.Log(q), -Math.PI * K1 / K )); } }
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 ModifiedBesselAtZero() { Assert.IsTrue(AdvancedMath.ModifiedBesselI(0, 0.0) == 1.0); Assert.IsTrue(AdvancedMath.ModifiedBesselI(1, 0.0) == 0.0); Assert.IsTrue(AdvancedMath.ModifiedBesselK(0, 0.0) == Double.PositiveInfinity); Assert.IsTrue(AdvancedMath.ModifiedBesselK(1, 0.0) == Double.PositiveInfinity); }
public void EllipticLandenTransform() { foreach (double k in TestUtilities.GenerateUniformRealValues(0.0, 1.0, 8)) { double kp = Math.Sqrt(1.0 - k * k); double k1 = (1.0 - kp) / (1.0 + kp); // For complete 1st kind Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.EllipticK(k), (1.0 + k1) * AdvancedMath.EllipticK(k1) )); // For complete 2nd kind Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.EllipticE(k) + kp * AdvancedMath.EllipticK(k), (1.0 + kp) * AdvancedMath.EllipticE(k1) )); /* * foreach (double t in TestUtilities.GenerateUniformRealValues(0.0, Math.PI / 2.0, 4)) { * * double s = Math.Sin(t); * double t1 = Math.Asin((1.0 + kp) * s * Math.Sqrt(1.0 - s * s) / Math.Sqrt(1.0 - k * k * s * s)); * * // Since t1 can be > pi/2, we need to handle a larger range of angles before we can test the incomplete cases * * * } * */ } }
public void RootOfEi() { double x = FunctionMath.FindZero(AdvancedMath.IntegralEi, Interval.FromEndpoints(0.1, 1.0)); Assert.IsTrue(TestUtilities.IsNearlyEqual(x, 0.37250741078136663446)); Assert.IsTrue(Math.Abs(AdvancedMath.IntegralEi(x)) < TestUtilities.TargetPrecision); }
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 static double WoodsSaxonPotentialNormalizingConstant3D( double nuclearRadius, double diffuseness ) { return(-8.0 * Math.PI * diffuseness * diffuseness * diffuseness * AdvancedMath.PolyLog(3, -Math.Exp(nuclearRadius / diffuseness))); }
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 CarlsonNormalization() { // All Carlson integrals are normalized so that they are 1 when all arguments are 1. Assert.IsTrue(AdvancedMath.CarlsonF(1.0, 1.0, 1.0) == 1.0); Assert.IsTrue(AdvancedMath.CarlsonG(1.0, 1.0, 1.0) == 1.0); Assert.IsTrue(AdvancedMath.CarlsonD(1.0, 1.0, 1.0) == 1.0); }
public void ComplexDiLogAgreement () { // use negative arguments b/c positive real DiLog function complex for x > 1 foreach (double x in TestUtilities.GenerateRealValues(1.0E-2, 1.0E2, 10)) { Assert.IsTrue(TestUtilities.IsNearlyEqual( AdvancedMath.DiLog(-x), AdvancedComplexMath.DiLog(-x) )); } }
public void InverseErfTest() { foreach (double P in TestUtilities.GenerateRealValues(1.0E-8, 1.0, 16)) { Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Erf(AdvancedMath.InverseErf(P)), P)); Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.Erfc(AdvancedMath.InverseErfc(P)), P)); } }
public void InverseErfSpecialValues() { Assert.IsTrue(AdvancedMath.InverseErf(-1.0) == Double.NegativeInfinity); Assert.IsTrue(AdvancedMath.InverseErf(0.0) == 0.0); Assert.IsTrue(AdvancedMath.InverseErf(1.0) == Double.PositiveInfinity); //Assert.IsTrue(Double.IsNaN(AdvancedMath.InverseErf(Double.NaN))); }
public void IntegralE0() { // A & S 5.1.24 foreach (double x in TestUtilities.GenerateRealValues(1.0E-4, 1.0E3, 8)) { Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.IntegralE(0, x), Math.Exp(-x) / x)); } }
public void IntegralEAtZero() { // A & S 5.1.23 foreach (int n in TestUtilities.GenerateIntegerValues(2, 100, 8)) { Assert.IsTrue(AdvancedMath.IntegralE(n, 0.0) == 1.0 / (n - 1.0)); } }
public void IntegralE1Integral() { // A & S 5.1.33 Assert.IsTrue(TestUtilities.IsNearlyEqual( FunctionMath.Integrate(t => MoreMath.Sqr(AdvancedMath.IntegralE(1, t)), 0.0, Double.PositiveInfinity), 2.0 * Math.Log(2.0) )); }