// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2016 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Numerics; using IStation.Numerics.Integration; namespace IStation.Numerics { /// /// Numerical Integration (Quadrature). /// public static class Integrate { /// /// Approximation of the definite integral of an analytic smooth function on a closed interval. /// /// The analytic smooth function to integrate. /// Where the interval starts, inclusive and finite. /// Where the interval stops, inclusive and finite. /// The expected relative accuracy of the approximation. /// Approximation of the finite integral in the given interval. public static double OnClosedInterval(Func f, double intervalBegin, double intervalEnd, double targetAbsoluteError) { return DoubleExponentialTransformation.Integrate(f, intervalBegin, intervalEnd, targetAbsoluteError); } /// /// Approximation of the definite integral of an analytic smooth function on a closed interval. /// /// The analytic smooth function to integrate. /// Where the interval starts, inclusive and finite. /// Where the interval stops, inclusive and finite. /// Approximation of the finite integral in the given interval. public static double OnClosedInterval(Func f, double intervalBegin, double intervalEnd) { return DoubleExponentialTransformation.Integrate(f, intervalBegin, intervalEnd, 1e-8); } /// /// Approximates a 2-dimensional definite integral using an Nth order Gauss-Legendre rule over the rectangle [a,b] x [c,d]. /// /// The 2-dimensional analytic smooth function to integrate. /// Where the interval starts for the first (inside) integral, exclusive and finite. /// Where the interval ends for the first (inside) integral, exclusive and finite. /// Where the interval starts for the second (outside) integral, exclusive and finite. /// /// Where the interval ends for the second (outside) integral, exclusive and finite. /// Defines an Nth order Gauss-Legendre rule. The order also defines the number of abscissas and weights for the rule. Precomputed Gauss-Legendre abscissas/weights for orders 2-20, 32, 64, 96, 100, 128, 256, 512, 1024 are used, otherwise they're calculated on the fly. /// Approximation of the finite integral in the given interval. public static double OnRectangle(Func f, double invervalBeginA, double invervalEndA, double invervalBeginB, double invervalEndB, int order) { return GaussLegendreRule.Integrate(f, invervalBeginA, invervalEndA, invervalBeginB, invervalEndB, order); } /// /// Approximates a 2-dimensional definite integral using an Nth order Gauss-Legendre rule over the rectangle [a,b] x [c,d]. /// /// The 2-dimensional analytic smooth function to integrate. /// Where the interval starts for the first (inside) integral, exclusive and finite. /// Where the interval ends for the first (inside) integral, exclusive and finite. /// Where the interval starts for the second (outside) integral, exclusive and finite. /// /// Where the interval ends for the second (outside) integral, exclusive and finite. /// Approximation of the finite integral in the given interval. public static double OnRectangle(Func f, double invervalBeginA, double invervalEndA, double invervalBeginB, double invervalEndB) { return GaussLegendreRule.Integrate(f, invervalBeginA, invervalEndA, invervalBeginB, invervalEndB, 32); } /// /// Approximation of the definite integral of an analytic smooth function by double-exponential quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth function to integrate. /// Where the interval starts. /// Where the interval stops. /// The expected relative accuracy of the approximation. /// Approximation of the finite integral in the given interval. public static double DoubleExponential(Func f, double intervalBegin, double intervalEnd, double targetAbsoluteError = 1E-8) { // Reference: // Formula used for variable subsitution from // 1. Shampine, L. F. (2008). Vectorized adaptive quadrature in MATLAB. Journal of Computational and Applied Mathematics, 211(2), 131-140. // 2. quadgk.m, GNU Octave if (intervalBegin > intervalEnd) { return -DoubleExponential(f, intervalEnd, intervalBegin, targetAbsoluteError); } // (-oo, oo) => [-1, 1] // // integral_(-oo)^(oo) f(x) dx = integral_(-1)^(1) f(g(t)) g'(t) dt // g(t) = t / (1 - t^2) // g'(t) = (1 + t^2) / (1 - t^2)^2 if (double.IsInfinity(intervalBegin) && double.IsInfinity(intervalEnd)) { Func u = (t) => { return f(t / (1 - t * t)) * (1 + t * t) / ((1 - t * t) * (1 - t * t)); }; return DoubleExponentialTransformation.Integrate(u, -1, 1, targetAbsoluteError); } // [a, oo) => [0, 1] // // integral_(a)^(oo) f(x) dx = integral_(0)^(oo) f(a + t^2) 2 t dt // = integral_(0)^(1) f(a + g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 - s) // g'(s) = 1 / (1 - s)^2 else if (double.IsInfinity(intervalEnd)) { Func u = (s) => { return 2 * s * f(intervalBegin + (s / (1 - s)) * (s / (1 - s))) / ((1 - s) * (1 - s) * (1 - s)); }; return DoubleExponentialTransformation.Integrate(u, 0, 1, targetAbsoluteError); } // (-oo, b] => [-1, 0] // // integral_(-oo)^(b) f(x) dx = -integral_(-oo)^(0) f(b - t^2) 2 t dt // = -integral_(-1)^(0) f(b - g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 + s) // g'(s) = 1 / (1 + s)^2 else if (double.IsInfinity(intervalBegin)) { Func u = (s) => { return -2 * s * f(intervalEnd - s / (1 + s) * (s / (1 + s))) / ((1 + s) * (1 + s) * (1 + s)); }; return DoubleExponentialTransformation.Integrate(u, -1, 0, targetAbsoluteError); } else { return DoubleExponentialTransformation.Integrate(f, intervalBegin, intervalEnd, targetAbsoluteError); } } /// /// Approximation of the definite integral of an analytic smooth function by Gauss-Legendre quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth function to integrate. /// Where the interval starts. /// Where the interval stops. /// Defines an Nth order Gauss-Legendre rule. The order also defines the number of abscissas and weights for the rule. Precomputed Gauss-Legendre abscissas/weights for orders 2-20, 32, 64, 96, 100, 128, 256, 512, 1024 are used, otherwise they're calculated on the fly. /// Approximation of the finite integral in the given interval. public static double GaussLegendre(Func f, double intervalBegin, double intervalEnd, int order = 128) { // Reference: // Formula used for variable subsitution from // 1. Shampine, L. F. (2008). Vectorized adaptive quadrature in MATLAB. Journal of Computational and Applied Mathematics, 211(2), 131-140. // 2. quadgk.m, GNU Octave if (intervalBegin > intervalEnd) { return -GaussLegendre(f, intervalEnd, intervalBegin, order); } // (-oo, oo) => [-1, 1] // // integral_(-oo)^(oo) f(x) dx = integral_(-1)^(1) f(g(t)) g'(t) dt // g(t) = t / (1 - t^2) // g'(t) = (1 + t^2) / (1 - t^2)^2 if (double.IsInfinity(intervalBegin) && double.IsInfinity(intervalEnd)) { Func u = (t) => { return f(t / (1 - t * t)) * (1 + t * t) / ((1 - t * t) * (1 - t * t)); }; return GaussLegendreRule.Integrate(u, -1, 1, order); } // [a, oo) => [0, 1] // // integral_(a)^(oo) f(x) dx = integral_(0)^(oo) f(a + t^2) 2 t dt // = integral_(0)^(1) f(a + g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 - s) // g'(s) = 1 / (1 - s)^2 else if (double.IsInfinity(intervalEnd)) { Func u = (s) => { return 2 * s * f(intervalBegin + (s / (1 - s)) * (s / (1 - s))) / ((1 - s) * (1 - s) * (1 - s)); }; return GaussLegendreRule.Integrate(u, 0, 1, order); } // (-oo, b] => [-1, 0] // // integral_(-oo)^(b) f(x) dx = -integral_(-oo)^(0) f(b - t^2) 2 t dt // = -integral_(-1)^(0) f(b - g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 + s) // g'(s) = 1 / (1 + s)^2 else if (double.IsInfinity(intervalBegin)) { Func u = (s) => { return -2 * s * f(intervalEnd - s / (1 + s) * (s / (1 + s))) / ((1 + s) * (1 + s) * (1 + s)); }; return GaussLegendreRule.Integrate(u, -1, 0, order); } // [a, b] => [-1, 1] // // integral_(a)^(b) f(x) dx = integral_(-1)^(1) f(g(t)) g'(t) dt // g(t) = (b - a) * t * (3 - t^2) / 4 + (b + a) / 2 // g'(t) = 3 / 4 * (b - a) * (1 - t^2) else { Func u = (t) => { return f((intervalEnd - intervalBegin) / 4 * t * (3 - t * t) + (intervalEnd + intervalBegin) / 2) * 3 * (intervalEnd - intervalBegin) / 4 * (1 - t * t); }; return GaussLegendreRule.Integrate(u, -1, 1, order); } } /// /// Approximation of the definite integral of an analytic smooth function by Gauss-Kronrod quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth function to integrate. /// Where the interval starts. /// Where the interval stops. /// The expected relative accuracy of the approximation. /// The maximum number of interval splittings permitted before stopping. /// The number of Gauss-Kronrod points. Pre-computed for 15, 21, 31, 41, 51 and 61 points. /// Approximation of the finite integral in the given interval. public static double GaussKronrod(Func f, double intervalBegin, double intervalEnd, double targetRelativeError = 1E-8, int maximumDepth = 15, int order = 15) { return GaussKronrodRule.Integrate(f, intervalBegin, intervalEnd, out _, out _, targetRelativeError: targetRelativeError, maximumDepth: maximumDepth, order: order); } /// /// Approximation of the definite integral of an analytic smooth function by Gauss-Kronrod quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth function to integrate. /// Where the interval starts. /// Where the interval stops. /// The difference between the (N-1)/2 point Gauss approximation and the N-point Gauss-Kronrod approximation /// The L1 norm of the result, if there is a significant difference between this and the returned value, then the result is likely to be ill-conditioned. /// The expected relative accuracy of the approximation. /// The maximum number of interval splittings permitted before stopping /// The number of Gauss-Kronrod points. Pre-computed for 15, 21, 31, 41, 51 and 61 points /// Approximation of the finite integral in the given interval. public static double GaussKronrod(Func f, double intervalBegin, double intervalEnd, out double error, out double L1Norm, double targetRelativeError = 1E-8, int maximumDepth = 15, int order = 15) { return GaussKronrodRule.Integrate(f, intervalBegin, intervalEnd, out error, out L1Norm, targetRelativeError: targetRelativeError, maximumDepth: maximumDepth, order: order); } } /// /// Numerical Contour Integration of a complex-valued function over a real variable,. /// public static class ContourIntegrate { /// /// Approximation of the definite integral of an analytic smooth complex function by double-exponential quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth complex function to integrate, defined on the real domain. /// Where the interval starts. /// Where the interval stops. /// The expected relative accuracy of the approximation. /// Approximation of the finite integral in the given interval. public static Complex DoubleExponential(Func f, double intervalBegin, double intervalEnd, double targetAbsoluteError = 1E-8) { // Reference: // Formula used for variable subsitution from // 1. Shampine, L. F. (2008). Vectorized adaptive quadrature in MATLAB. Journal of Computational and Applied Mathematics, 211(2), 131-140. // 2. quadgk.m, GNU Octave if (intervalBegin > intervalEnd) { return -DoubleExponential(f, intervalEnd, intervalBegin, targetAbsoluteError); } // (-oo, oo) => [-1, 1] // // integral_(-oo)^(oo) f(x) dx = integral_(-1)^(1) f(g(t)) g'(t) dt // g(t) = t / (1 - t^2) // g'(t) = (1 + t^2) / (1 - t^2)^2 if (double.IsInfinity(intervalBegin) && double.IsInfinity(intervalEnd)) { Func u = (t) => { return f(t / (1 - t * t)) * (1 + t * t) / ((1 - t * t) * (1 - t * t)); }; return DoubleExponentialTransformation.ContourIntegrate(u, -1, 1, targetAbsoluteError); } // [a, oo) => [0, 1] // // integral_(a)^(oo) f(x) dx = integral_(0)^(oo) f(a + t^2) 2 t dt // = integral_(0)^(1) f(a + g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 - s) // g'(s) = 1 / (1 - s)^2 else if (double.IsInfinity(intervalEnd)) { Func u = (s) => { return 2 * s * f(intervalBegin + (s / (1 - s)) * (s / (1 - s))) / ((1 - s) * (1 - s) * (1 - s)); }; return DoubleExponentialTransformation.ContourIntegrate(u, 0, 1, targetAbsoluteError); } // (-oo, b] => [-1, 0] // // integral_(-oo)^(b) f(x) dx = -integral_(-oo)^(0) f(b - t^2) 2 t dt // = -integral_(-1)^(0) f(b - g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 + s) // g'(s) = 1 / (1 + s)^2 else if (double.IsInfinity(intervalBegin)) { Func u = (s) => { return -2 * s * f(intervalEnd - s / (1 + s) * (s / (1 + s))) / ((1 + s) * (1 + s) * (1 + s)); }; return DoubleExponentialTransformation.ContourIntegrate(u, -1, 0, targetAbsoluteError); } else { return DoubleExponentialTransformation.ContourIntegrate(f, intervalBegin, intervalEnd, targetAbsoluteError); } } /// /// Approximation of the definite integral of an analytic smooth complex function by double-exponential quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth complex function to integrate, defined on the real domain. /// Where the interval starts. /// Where the interval stops. /// Defines an Nth order Gauss-Legendre rule. The order also defines the number of abscissas and weights for the rule. Precomputed Gauss-Legendre abscissas/weights for orders 2-20, 32, 64, 96, 100, 128, 256, 512, 1024 are used, otherwise they're calculated on the fly. /// Approximation of the finite integral in the given interval. public static Complex GaussLegendre(Func f, double intervalBegin, double intervalEnd, int order = 128) { // Reference: // Formula used for variable subsitution from // 1. Shampine, L. F. (2008). Vectorized adaptive quadrature in MATLAB. Journal of Computational and Applied Mathematics, 211(2), 131-140. // 2. quadgk.m, GNU Octave if (intervalBegin > intervalEnd) { return -GaussLegendre(f, intervalEnd, intervalBegin, order); } // (-oo, oo) => [-1, 1] // // integral_(-oo)^(oo) f(x) dx = integral_(-1)^(1) f(g(t)) g'(t) dt // g(t) = t / (1 - t^2) // g'(t) = (1 + t^2) / (1 - t^2)^2 if (double.IsInfinity(intervalBegin) && double.IsInfinity(intervalEnd)) { Func u = (t) => { return f(t / (1 - t * t)) * (1 + t * t) / ((1 - t * t) * (1 - t * t)); }; return GaussLegendreRule.ContourIntegrate(u, -1, 1, order); } // [a, oo) => [0, 1] // // integral_(a)^(oo) f(x) dx = integral_(0)^(oo) f(a + t^2) 2 t dt // = integral_(0)^(1) f(a + g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 - s) // g'(s) = 1 / (1 - s)^2 else if (double.IsInfinity(intervalEnd)) { Func u = (s) => { return 2 * s * f(intervalBegin + (s / (1 - s)) * (s / (1 - s))) / ((1 - s) * (1 - s) * (1 - s)); }; return GaussLegendreRule.ContourIntegrate(u, 0, 1, order); } // (-oo, b] => [-1, 0] // // integral_(-oo)^(b) f(x) dx = -integral_(-oo)^(0) f(b - t^2) 2 t dt // = -integral_(-1)^(0) f(b - g(s)^2) 2 g(s) g'(s) ds // g(s) = s / (1 + s) // g'(s) = 1 / (1 + s)^2 else if (double.IsInfinity(intervalBegin)) { Func u = (s) => { return -2 * s * f(intervalEnd - s / (1 + s) * (s / (1 + s))) / ((1 + s) * (1 + s) * (1 + s)); }; return GaussLegendreRule.ContourIntegrate(u, -1, 0, order); } // [a, b] => [-1, 1] // // integral_(a)^(b) f(x) dx = integral_(-1)^(1) f(g(t)) g'(t) dt // g(t) = (b - a) * t * (3 - t^2) / 4 + (b + a) / 2 // g'(t) = 3 / 4 * (b - a) * (1 - t^2) else { Func u = (t) => { return f((intervalEnd - intervalBegin) / 4 * t * (3 - t * t) + (intervalEnd + intervalBegin) / 2) * 3 * (intervalEnd - intervalBegin) / 4 * (1 - t * t); }; return GaussLegendreRule.ContourIntegrate(u, -1, 1, order); } } /// /// Approximation of the definite integral of an analytic smooth function by Gauss-Kronrod quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth complex function to integrate, defined on the real domain. /// Where the interval starts. /// Where the interval stops. /// The expected relative accuracy of the approximation. /// The maximum number of interval splittings permitted before stopping /// The number of Gauss-Kronrod points. Pre-computed for 15, 21, 31, 41, 51 and 61 points /// Approximation of the finite integral in the given interval. public static Complex GaussKronrod(Func f, double intervalBegin, double intervalEnd, double targetRelativeError = 1E-8, int maximumDepth = 15, int order = 15) { return GaussKronrodRule.ContourIntegrate(f, intervalBegin, intervalEnd, out _, out _, targetRelativeError: targetRelativeError, maximumDepth: maximumDepth, order: order); } /// /// Approximation of the definite integral of an analytic smooth function by Gauss-Kronrod quadrature. When either or both limits are infinite, the integrand is assumed rapidly decayed to zero as x -> infinity. /// /// The analytic smooth complex function to integrate, defined on the real domain. /// Where the interval starts. /// Where the interval stops. /// The difference between the (N-1)/2 point Gauss approximation and the N-point Gauss-Kronrod approximation /// The L1 norm of the result, if there is a significant difference between this and the returned value, then the result is likely to be ill-conditioned. /// The expected relative accuracy of the approximation. /// The maximum number of interval splittings permitted before stopping /// The number of Gauss-Kronrod points. Pre-computed for 15, 21, 31, 41, 51 and 61 points /// Approximation of the finite integral in the given interval. public static Complex GaussKronrod(Func f, double intervalBegin, double intervalEnd, out double error, out double L1Norm, double targetRelativeError = 1E-8, int maximumDepth = 15, int order = 15) { return GaussKronrodRule.ContourIntegrate(f, intervalBegin, intervalEnd, out error, out L1Norm, targetRelativeError: targetRelativeError, maximumDepth: maximumDepth, order: order); } } }