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
                                  ));
            }
        }
예제 #2
0
        public void JacobiIntegrals()
        {
            foreach (double k in TestUtilities.GenerateRealValues(1.0E-1, 1.0, 4))
            {
                // DLMF 22.14.18 says
                //   \int_{0}^{K(k)} \ln(\dn(t, k)) \, dt = \frac{1}{2} K(k) \ln k'

                double K = AdvancedMath.EllipticK(k);

                double k1 = Math.Sqrt(1.0 - k * k);

                double I1 = FunctionMath.Integrate(
                    x => Math.Log(AdvancedMath.JacobiDn(x, k)),
                    Interval.FromEndpoints(0.0, K)
                    );

                Assert.IsTrue(TestUtilities.IsNearlyEqual(I1, K / 2.0 * Math.Log(k1)));

                // If k is small, log(k1) is subject to cancellation error, so don't pick k too small.

                // It also gives values for the analogous integrals with \sn and \cn,
                // but their values involve K'(k), for which we don't have a method.

                // Mathworld (http://mathworld.wolfram.com/CompleteEllipticIntegraloftheSecondKind.html) says
                //   \int_{0}^{K(k)} \dn^2(t, k) = E(k)

                double I2 = FunctionMath.Integrate(
                    u => MoreMath.Sqr(AdvancedMath.JacobiDn(u, k)),
                    Interval.FromEndpoints(0.0, K)
                    );

                Assert.IsTrue(TestUtilities.IsNearlyEqual(I2, AdvancedMath.EllipticE(k)));
            }
        }
예제 #3
0
        public void EllipticKCatalanIntegral()
        {
            System.Diagnostics.Stopwatch timer = System.Diagnostics.Stopwatch.StartNew();


            Interval i = Interval.FromEndpoints(0.0, 1.0);

            // http://mathworld.wolfram.com/CatalansConstant.html equation 37

            Func <double, double> f1 = delegate(double k) {
                return(AdvancedMath.EllipticK(k));
            };

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              FunctionMath.Integrate(f1, i), 2.0 * AdvancedMath.Catalan
                              ));

            Func <double, double> f2 = delegate(double k) {
                return(AdvancedMath.EllipticK(k) * k);
            };

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              FunctionMath.Integrate(f2, i), 1.0
                              ));

            timer.Stop();
            Console.WriteLine(timer.ElapsedTicks);
        }
예제 #4
0
        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 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
                              ));
        }
예제 #6
0
        public void JacobiPeriodic()
        {
            double u = 3.1;
            double k = 0.2;

            double K = AdvancedMath.EllipticK(k);

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              AdvancedMath.JacobiSn(u, k),
                              -AdvancedMath.JacobiSn(u + 2.0 * K, k)
                              ));

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              AdvancedMath.JacobiSn(u, k),
                              AdvancedMath.JacobiSn(u + 4.0 * K, k)
                              ));

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              AdvancedMath.JacobiCn(u, k),
                              -AdvancedMath.JacobiCn(u + 2.0 * K, k)
                              ));

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              AdvancedMath.JacobiCn(u, k),
                              AdvancedMath.JacobiCn(u + 4.0 * K, k)
                              ));

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              AdvancedMath.JacobiDn(u, k),
                              AdvancedMath.JacobiDn(u + 2.0 * K, k)
                              ));
        }
예제 #7
0
 public void EllipticKInequality()
 {
     // DLMF 19.9.1
     foreach (double k in TestUtilities.GenerateUniformRealValues(0.0, 1.0, 4))
     {
         double S = AdvancedMath.EllipticK(k) + Math.Log(Math.Sqrt(1.0 - k * k));
         Assert.IsTrue((Math.Log(4.0) <= S) && (S <= Math.PI / 2.0));
     }
 }
예제 #8
0
 public void EllipticFCompleteAgreement()
 {
     foreach (double k in TestUtilities.GenerateRealValues(0.01, 1.0, 8))
     {
         Assert.IsTrue(TestUtilities.IsNearlyEqual(
                           AdvancedMath.EllipticF(Math.PI / 2.0, k),
                           AdvancedMath.EllipticK(k)
                           ));
     }
 }
예제 #9
0
 public void EllipticLegendreRelation()
 {
     foreach (double k in TestUtilities.GenerateRealValues(0.01, 1.0, 8))
     {
         double kp = Math.Sqrt(1.0 - k * k);
         double E  = AdvancedMath.EllipticE(k);
         double EP = AdvancedMath.EllipticE(kp);
         double K  = AdvancedMath.EllipticK(k);
         double KP = AdvancedMath.EllipticK(kp);
         Assert.IsTrue(TestUtilities.IsNearlyEqual(K * EP + KP * E, Math.PI / 2.0 + K * KP));
     }
 }
        public void CompleteEllipticHypergeometricAgreement()
        {
            foreach (double k in TestUtilities.GenerateRealValues(1.0E-4, 1.0, 4))
            {
                Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                  AdvancedMath.EllipticK(k),
                                  Math.PI / 2.0 * AdvancedMath.Hypergeometric2F1(0.5, 0.5, 1.0, k * k)
                                  ));

                Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                  AdvancedMath.EllipticE(k),
                                  Math.PI / 2.0 * AdvancedMath.Hypergeometric2F1(0.5, -0.5, 1.0, k * k)
                                  ));
            }
        }
예제 #11
0
 public void EllipticFDisplacement()
 {
     foreach (int m in TestUtilities.GenerateUniformIntegerValues(-100, 100, 4))
     {
         foreach (double phi in TestUtilities.GenerateUniformRealValues(-Math.PI / 2.0, +Math.PI / 2.0, 4))
         {
             foreach (double k in TestUtilities.GenerateRealValues(1.0E-4, 1.0, 4))
             {
                 Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                   AdvancedMath.EllipticF(m * Math.PI + phi, k),
                                   2 * m * AdvancedMath.EllipticK(k) + AdvancedMath.EllipticF(phi, k)
                                   ));
             }
         }
     }
 }
예제 #12
0
        public void EllipticKIntegration()
        {
            // The defining integral for K

            Interval i = Interval.FromEndpoints(0.0, Math.PI / 2.0);

            foreach (double k in TestUtilities.GenerateRealValues(0.01, 1.0, 8))
            {
                Func <double, double> f = delegate(double t) {
                    double z = k * Math.Sin(t);
                    return(1.0 / Math.Sqrt(1.0 - z * z));
                };

                Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                  FunctionMath.Integrate(f, i), AdvancedMath.EllipticK(k)
                                  ));
            }
        }
예제 #13
0
        public void OdePendulum()
        {
            // Without the small-angle approximation, the period of a pendulum is not
            // independent of angle. Instead, it is given by
            //   P = 4 K(\sin(\phi_0) / 2)
            // where \phi_0 is the release angle and K is the complete elliptic function
            // of the first kind.
            // See https://en.wikipedia.org/wiki/Pendulum_(mathematics)
            // We compute for an initial angle of 45 degrees, far beyond a small angle.

            Func <double, double, double> rhs = (double t, double u) => - MoreMath.Sin(u);

            double u0 = Math.PI / 4.0;
            double p  = 4.0 * AdvancedMath.EllipticK(MoreMath.Sin(u0 / 2.0));

            OdeResult r = FunctionMath.IntegrateConservativeOde(rhs, 0.0, u0, 0.0, p);

            Assert.IsTrue(TestUtilities.IsNearlyEqual(r.Y, u0));

            Console.WriteLine(r.EvaluationCount);
        }
예제 #14
0
        public void JacobiSpecial()
        {
            // Verify values at u = 0, K/2, K given in DMLF 22.5i and A&S

            double k  = 1.0 / 3.1;
            double k1 = Math.Sqrt(1.0 - k * k);
            double K  = AdvancedMath.EllipticK(k);

            // u = 0
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiSn(0.0, k), 0.0));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiCn(0.0, k), 1.0));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiDn(0.0, k), 1.0));

            // u = K / 2
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiSn(K / 2.0, k), 1.0 / Math.Sqrt(1.0 + k1)));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiCn(K / 2.0, k), Math.Sqrt(k1 / (1.0 + k1))));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiDn(K / 2.0, k), Math.Sqrt(k1)));

            // u = K
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiSn(K, k), 1.0));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiCn(K, k), 0.0));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.JacobiDn(K, k), k1));
        }
 public void EllipticKExtremeValues()
 {
     Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticK(Double.Epsilon), Math.PI / 2.0));
     Assert.IsTrue(AdvancedMath.EllipticK(1.0 - 2.0E-16) < Double.PositiveInfinity);
     Assert.IsTrue(Double.IsNaN(AdvancedMath.EllipticK(Double.NaN)));
 }
예제 #16
0
        public void OdeEuler()
        {
            // Euler's equations for rigid body motion (without external forces) are
            //   I_1 \dot{\omega}_1  = (I_2 - I_3) \omega_2 \omega_3
            //   I_2 \dot{\omega}_2  = (I_3 - I_1) \omega_3 \omega_1
            //   I_3 \dot{\omega}_3  = (I_1 - I_2) \omega_1 \omega_2
            // where \omega's are rotations about the principal axes and I's are the moments
            // of inertia about those axes. The rotational kinetic energy
            //   I_1 \omega_1^2 + I_2 \omega_2^2 + I_3 \omega_3^2 = 2 E
            // and angular momentum
            //   I_1^2 \omega_1^2 + I_2^2 \omega_2^2 + I_3^2 \omega_3^2 = L^2
            // are conserved quantities.

            // Landau & Lifshitz, Mechanics (3rd edition) solves these equations.

            // Note
            //   (\cn u)' = - (\sn u)(\dn u)
            //   (\sn u)' = (\dn u)(\cn u)
            //   (\dn u)' = -k^2 (\cn u)(\sn u)
            // So a solution with \omega_1 ~ \cn, \omega_2 ~ \sn, \omega_3 ~ \dn
            // would seem to work, if we can re-scale variables to eliminate factors.
            // In fact, this turns out to be the case.

            // Label axis so that I_3 > I_2 > I_1. If L^2 > 2 E I_2, define
            //   v^2 = \frac{(I_3 - I_2)(L^2 - 2E I_1)}{I_1 I_2 I_3}
            //   k^2 = \frac{(I_2 - I_1)(2E I_3 - L^2)}{(I_3 - I_2)(L^2 - 2E I_1)}
            //   A_1^2 = \frac{2E I_3 - L^2}{I_1 (I_3 - I_1)}
            //   A_2^2 = \frac{2E I_3 - L^2}{I_2 (I_3 - I_2)}
            //   A_3^2 = \frac{L^2 - 2E I_1}{I_3 (I_3 - I_1)}
            // (If L^2 < 2 E I_2, just switch subscripts 1 <-> 3). Then
            //   \omega_1 = A_1 \cn (c t, k)
            //   \omega_2 = A_2 \sn (c t, k)
            //   \omega_3 = A_3 \dn (c t, k)
            // Period is complete when v T = 4 K.

            ColumnVector I = new ColumnVector(3.0, 4.0, 5.0);

            Func <double, IReadOnlyList <double>, IReadOnlyList <double> > rhs = (double t, IReadOnlyList <double> w) => {
                return(new ColumnVector((I[1] - I[2]) * w[1] * w[2] / I[0], (I[2] - I[0]) * w[2] * w[0] / I[1], (I[0] - I[1]) * w[0] * w[1] / I[2]));
            };

            ColumnVector w0 = new ColumnVector(6.0, 0.0, 1.0);

            // Determine L^2 and 2 E
            double L2 = EulerAngularMomentum(I, w0);
            double E2 = EulerKineticEnergy(I, w0);

            // As Landau points out, these inequalities should be ensured by the definitions of E and L.
            Debug.Assert(E2 * I[0] < L2);
            Debug.Assert(L2 < E2 * I[2]);

            double v, k;
            Func <double, ColumnVector> sln;

            if (L2 > E2 * I[1])
            {
                v = Math.Sqrt((I[2] - I[1]) * (L2 - E2 * I[0]) / I[0] / I[1] / I[2]);
                k = Math.Sqrt((I[1] - I[0]) * (E2 * I[2] - L2) / (I[2] - I[1]) / (L2 - E2 * I[0]));
                ColumnVector A = new ColumnVector(
                    Math.Sqrt((E2 * I[2] - L2) / I[0] / (I[2] - I[0])),
                    Math.Sqrt((E2 * I[2] - L2) / I[1] / (I[2] - I[1])),
                    Math.Sqrt((L2 - E2 * I[0]) / I[2] / (I[2] - I[0]))
                    );
                sln = t => new ColumnVector(
                    A[0] * AdvancedMath.JacobiCn(v * t, k),
                    A[1] * AdvancedMath.JacobiSn(v * t, k),
                    A[2] * AdvancedMath.JacobiDn(v * t, k)
                    );
            }
            else
            {
                v = Math.Sqrt((I[0] - I[1]) * (L2 - E2 * I[2]) / I[0] / I[1] / I[2]);
                k = Math.Sqrt((I[1] - I[2]) * (E2 * I[0] - L2) / (I[0] - I[1]) / (L2 - E2 * I[2]));
                ColumnVector A = new ColumnVector(
                    Math.Sqrt((L2 - E2 * I[2]) / I[0] / (I[0] - I[2])),
                    Math.Sqrt((E2 * I[0] - L2) / I[1] / (I[0] - I[1])),
                    Math.Sqrt((E2 * I[0] - L2) / I[2] / (I[0] - I[2]))
                    );
                sln = t => new ColumnVector(
                    A[0] * AdvancedMath.JacobiDn(v * t, k),
                    A[1] * AdvancedMath.JacobiSn(v * t, k),
                    A[2] * AdvancedMath.JacobiCn(v * t, k)
                    );
            }

            Debug.Assert(k < 1.0);

            double T = 4.0 * AdvancedMath.EllipticK(k) / v;

            int listenerCount         = 0;
            MultiOdeSettings settings = new MultiOdeSettings()
            {
                Listener = (MultiOdeResult q) => {
                    listenerCount++;

                    // Verify that energy and angular momentum conservation is respected
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(EulerKineticEnergy(I, q.Y), E2, q.Settings));
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(EulerAngularMomentum(I, q.Y), L2, q.Settings));

                    // Verify that the result agrees with the analytic solution
                    //ColumnVector YP = new ColumnVector(
                    //    A[0] * AdvancedMath.JacobiCn(v * q.X, k),
                    //    A[1] * AdvancedMath.JacobiSn(v * q.X, k),
                    //    A[2] * AdvancedMath.JacobiDn(v * q.X, k)
                    //);
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(q.Y, sln(q.X), q.Settings));
                }
            };
            MultiOdeResult result = MultiFunctionMath.IntegrateOde(rhs, 0.0, w0, T, settings);

            Console.WriteLine(result.EvaluationCount);
            //MultiOdeResult r2 = NewMethods.IntegrateOde(rhs, 0.0, w0, T, settings);

            // Verify that one period of evolution has brought us back to our initial state
            Assert.IsTrue(TestUtilities.IsNearlyEqual(result.X, T));
            Assert.IsTrue(TestUtilities.IsNearlyEqual(result.Y, w0, settings));
            Assert.IsTrue(listenerCount > 0);
        }
예제 #17
0
 public void EllipticKSpecialCases()
 {
     Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticK(0.0), Math.PI / 2.0));
     Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticK(1.0 / Math.Sqrt(2.0)), Math.Pow(AdvancedMath.Gamma(1.0 / 4.0), 2.0) / Math.Sqrt(Math.PI) / 4.0));
     Assert.IsTrue(Double.IsPositiveInfinity(AdvancedMath.EllipticK(1.0)));
 }
예제 #18
0
        public void RambleIntegrals()
        {
            // W_{n}(s) = \int_{0}^{1} dx_1 \cdots dx_n \vert \sum_k e^{2 \pi i x_k} \vert^{s}
            // appears in problems of random walk in n dimensions. This is an oscilatory integral.
            // Analytic values are known for W_3(1) and W_3(-1) (https://www.carma.newcastle.edu.au/jon/walks.pdf).
            // Also W_2(1) = 4 / \pi and even arguments (http://www.carma.newcastle.edu.au/jon/walkstalk.pdf).
            // W_4(-1) can be related to a one-dimensional integral involving elliptic functions
            // (https://www.carma.newcastle.edu.au/jon/walks2.pdf and http://crd-legacy.lbl.gov/~dhbailey/dhbpapers/combat.pdf).

            // This is an oscilatory integral, so drop the required precision.
            IntegrationSettings settings2 = new IntegrationSettings()
            {
                RelativePrecision = 1.0E-4
            };
            IntegrationSettings settings3 = new IntegrationSettings()
            {
                RelativePrecision = 1.0E-3
            };
            IntegrationSettings settings4 = new IntegrationSettings()
            {
                RelativePrecision = 1.0E-2
            };

            Assert.IsTrue(RambleIntegral(2, 1, settings3).Estimate.ConfidenceInterval(0.95).ClosedContains(4.0 / Math.PI));

            Assert.IsTrue(RambleIntegral(3, -1, settings3).Estimate.ConfidenceInterval(0.95).ClosedContains(
                              3.0 / 16.0 * Math.Pow(2.0, 1.0 / 3.0) / MoreMath.Pow(Math.PI, 4) * MoreMath.Pow(AdvancedMath.Gamma(1.0 / 3.0), 6)
                              ));

            Assert.IsTrue(RambleIntegral(3, 1, settings3).Estimate.ConfidenceInterval(0.95).ClosedContains(
                              3.0 / 16.0 * Math.Pow(2.0, 1.0 / 3.0) / MoreMath.Pow(Math.PI, 4) * MoreMath.Pow(AdvancedMath.Gamma(1.0 / 3.0), 6) +
                              27.0 / 4.0 * Math.Pow(2.0, 2.0 / 3.0) / MoreMath.Pow(Math.PI, 4) * MoreMath.Pow(AdvancedMath.Gamma(2.0 / 3.0), 6)
                              ));

            Assert.IsTrue(RambleIntegral(4, -1, settings4).Estimate.ConfidenceInterval(0.95).ClosedContains(
                              8.0 / MoreMath.Pow(Math.PI, 3) * FunctionMath.Integrate(k => MoreMath.Sqr(AdvancedMath.EllipticK(k)), Interval.FromEndpoints(0.0, 1.0))
                              ));
        }
예제 #19
0
        public void HypergeometricBasicFunctions()
        {
            foreach (double x in xs)
            {
                // A&S 15.1.3
                if (x < 1.0 && (x != 0.0))
                {
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                      AdvancedMath.Hypergeometric2F1(1.0, 1.0, 2.0, x), -Math.Log(1.0 - x) / x
                                      ));
                }

                // A&S 15.1.5
                if (x != 0.0)
                {
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                      AdvancedMath.Hypergeometric2F1(0.5, 1.0, 1.5, -x * x), Math.Atan(x) / x
                                      ));
                }

                // A&S 15.1.6
                if ((-1.0 <= x) && (x <= 1.0) && (x != 0.0))
                {
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                      AdvancedMath.Hypergeometric2F1(0.5, 0.5, 1.5, x * x), Math.Asin(x) / x
                                      ));
                }

                // Complete elliptic integrals
                if ((0.0 <= x) && (x < 1.0))
                {
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                      Math.PI / 2.0 * AdvancedMath.Hypergeometric2F1(0.5, 0.5, 1.0, x * x), AdvancedMath.EllipticK(x)
                                      ));

                    Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                      Math.PI / 2.0 * AdvancedMath.Hypergeometric2F1(-0.5, 0.5, 1.0, x * x), AdvancedMath.EllipticE(x)
                                      ));
                }
            }
        }
 public void EllipticPiSpecialCharacteristic()
 {
     foreach (double k in TestUtilities.GenerateRealValues(1.0E-4, 1.0, 4))
     {
         // DLMF 19.6.1
         Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticPi(k * k, k), AdvancedMath.EllipticE(k) / (1.0 - k * k)));
         // DLMF 19.6.2
         Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticPi(-k, k), Math.PI / 4.0 / (1.0 + k) + AdvancedMath.EllipticK(k) / 2.0));
         // DLMF 19.6.3
         Assert.IsTrue(TestUtilities.IsNearlyEqual(AdvancedMath.EllipticPi(0.0, k), AdvancedMath.EllipticK(k)));
         Assert.IsTrue(Double.IsPositiveInfinity(AdvancedMath.EllipticPi(1.0, k)));
     }
 }