예제 #1
0
        public void OdeLotkaVolterra()
        {
            // Lotka/Volterra equations are a non-linear predator-prey model.
            //   \dot{x} = A x + B x y
            //   \dot{y} = -C y + D x y
            // See http://mathworld.wolfram.com/Lotka-VolterraEquations.html

            // It can be shown solutions are always periodic (but not sinusoidal, and
            // often with phase shift between x and y).

            // Equilibria are x, y = C/D, A /B (and 0, 0).
            // If started positive, x and y never go negative.
            // A conserved quantity is: - D x + C log x - B y + A log y
            // Period of equations linearized around equilibrium is 2 \pi / \sqrt{AC}.

            // Can also be used to model chemical reaction rates.

            double A = 1.5; // Prey growth rate
            double B = 1.0;
            double C = 3.0; // Predator death rate
            double D = 1.0;

            // Try A = 20, B = 1, C = 30, D = 1, X = 8, Y = 12, T = 1
            // Try A = 1.5, B = 1 C = 3, D = 1, X = 10, Y = 5, T = 10

            Func <double, IList <double>, IList <double> > rhs = (double t, IList <double> p) => new double[] {
                A *p[0] - B * p[0] * p[1],
                -C *p[1] + D * p[0] * p[1]
            };

            Func <IList <double>, double> conservedQuantity = (IList <double> p) =>
                                                              - D * p[0] + C * Math.Log(p[0]) - B * p[1] + A * Math.Log(p[1]);

            ColumnVector p0 = new ColumnVector(10.0, 5.0);

            double L0 = conservedQuantity(p0);

            // Set up a handler that verifies conservation and positivity
            MultiOdeEvaluationSettings settings = new MultiOdeEvaluationSettings()
            {
                Listener = (MultiOdeResult rr) => {
                    double L = conservedQuantity(rr.Y);
                    Assert.IsTrue(rr.Y[0] > 0.0);
                    Assert.IsTrue(rr.Y[1] > 0.0);
                    Assert.IsTrue(TestUtilities.IsNearlyEqual(L, L0, rr.Settings));
                }
            };

            // Estimate period
            double T = 2.0 * Math.PI / Math.Sqrt(A * C);

            // Integrate over a few estimated periods
            MultiOdeResult result = MultiFunctionMath.IntegrateOde(rhs, 0.0, p0, 3.0 * T, settings);

            Console.WriteLine(result.EvaluationCount);
        }
        public void BoxIntegrals()
        {
            // The box integrals
            //   B_n(r) = \int{0}^{1} dx_1 \cdots dx_n ( x_1^2 + \cdots x_n^2 )^{r/2}
            //   D_n(r) = \int{0}^{1} dx_1 \cdots dx_n dy_1 \cdots dy_n \left[ (x_1 - y_1)^2 + \cdots (x_n - y_n)^2 \right]^{r/2}
            // Give the mean distance of a point in a box from its center or from other points. Various of these are known analytically.
            // see Bailey, Borwein, Crandall, "Box Integrals", Journal of Computational and Applied Mathematics 206 (2007) 196
            // http://www.davidhbailey.com/dhbpapers/boxintegrals.pdf and http://www.davidhbailey.com/dhbpapers/bbbz-conmath.pdf

            // More results are in http://crd-legacy.lbl.gov/~dhbailey/dhbpapers/BoxII.pdf

            IntegrationSettings settings = new IntegrationSettings()
            {
                EvaluationBudget = 1000000, RelativePrecision = 1.0E-3
            };

            // 2D integrals

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralB(2, -1, settings), 2.0 * Math.Log(1.0 + Math.Sqrt(2.0)), settings.RelativePrecision * 2
                              ));
            // Note 2 \ln(1 + \sqrt{2}) = \ln(3 + 2 \sqrt{2}) because (1 + \sqrt{2})^2 = 3 + 2 \sqrt{2}

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralB(2, 1, settings), (Math.Sqrt(2.0) + Math.Log(Math.Sqrt(2.0) + 1.0)) / 3.0, settings.RelativePrecision * 2
                              ));

            /*
             * Assert.IsTrue(TestUtilities.IsNearlyEqual(
             *  BoxIntegralD(1, -1, new EvaluationSettings() { EvaluationBudget = 100000, RelativePrecision = 1.0E-2 }),
             *  (2.0 - 4.0 * Math.Sqrt(2.0)) / 3.0 + 4.0 * Math.Log(1.0 + Math.Sqrt(2.0)), settings.RelativePrecision * 2
             * ));
             */

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralD(1, 1, settings), 1.0 / 3.0, settings.RelativePrecision * 2
                              ));

            // 3D integrals

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralB(3, -1, settings), Math.Log(5.0 + 3.0 * Math.Sqrt(3.0)) - Math.Log(2.0) / 2.0 - Math.PI / 4.0, settings.RelativePrecision * 4
                              ));

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralB(3, 1, settings), Math.Log(2.0 + Math.Sqrt(3.0)) / 2.0 + Math.Sqrt(3.0) / 4.0 - Math.PI / 24.0, settings.RelativePrecision * 2
                              ));

            // 4D integrals

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralB(4, -2, settings), Math.PI * Math.Log(2.0 + Math.Sqrt(3.0)) - 2.0 * AdvancedMath.Catalan - Math.PI * Math.PI / 8.0, settings.RelativePrecision * 4
                              ));

            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralD(2, 1, settings), (2.0 + Math.Sqrt(2.0) + 5.0 * Math.Log(1.0 + Math.Sqrt(2.0))) / 15.0, settings.RelativePrecision * 4
                              ));

            // 6D integrals
            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                              BoxIntegralD(3, 1, settings),
                              4.0 / 105.0 + 17.0 * Math.Sqrt(2.0) / 105.0 - 2.0 * Math.Sqrt(3.0) / 35.0 + Math.Log(1.0 + Math.Sqrt(2.0)) / 5.0 + 2.0 * Math.Log(2.0 + Math.Sqrt(3.0)) / 5.0 - Math.PI / 15.0,
                              settings.RelativePrecision * 2
                              ));
        }