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 )); }