// // 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.GaussRule; namespace IStation.Numerics.Integration { /// /// Approximates a definite integral using an Nth order Gauss-Legendre 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. /// public class GaussLegendreRule { private readonly GaussPoint _gaussLegendrePoint; /// /// Initializes a new instance of the class. /// /// Where the interval starts, inclusive and finite. /// Where the interval stops, inclusive 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. public GaussLegendreRule(double intervalBegin, double intervalEnd, int order) { _gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(intervalBegin, intervalEnd, order); } /// /// Gettter for the ith abscissa. /// /// Index of the ith abscissa. /// The ith abscissa. public double GetAbscissa(int index) { return _gaussLegendrePoint.Abscissas[index]; } /// /// Getter that returns a clone of the array containing the abscissas. /// public double[] Abscissas => _gaussLegendrePoint.Abscissas.Clone() as double[]; /// /// Getter for the ith weight. /// /// Index of the ith weight. /// The ith weight. public double GetWeight(int index) { return _gaussLegendrePoint.Weights[index]; } /// /// Getter that returns a clone of the array containing the weights. /// public double[] Weights => _gaussLegendrePoint.Weights.Clone() as double[]; /// /// Getter for the order. /// public int Order => _gaussLegendrePoint.Order; /// /// Getter for the InvervalBegin. /// public double IntervalBegin => _gaussLegendrePoint.IntervalBegin; /// /// Getter for the InvervalEnd. /// public double IntervalEnd => _gaussLegendrePoint.IntervalEnd; /// /// Approximates a definite integral using an Nth order Gauss-Legendre rule. /// /// The analytic smooth function to integrate. /// Where the interval starts, exclusive and finite. /// Where the interval ends, 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 Integrate(Func f, double invervalBegin, double invervalEnd, int order) { GaussPoint gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(order); double sum, ax; int i; int m = (order + 1) >> 1; double a = 0.5*(invervalEnd - invervalBegin); double b = 0.5*(invervalEnd + invervalBegin); if (order.IsOdd()) { sum = gaussLegendrePoint.Weights[0]*f(b); for (i = 1; i < m; i++) { ax = a*gaussLegendrePoint.Abscissas[i]; sum += gaussLegendrePoint.Weights[i]*(f(b + ax) + f(b - ax)); } } else { sum = 0.0; for (i = 0; i < m; i++) { ax = a*gaussLegendrePoint.Abscissas[i]; sum += gaussLegendrePoint.Weights[i]*(f(b + ax) + f(b - ax)); } } return a*sum; } /// /// Approximates a definite integral using an Nth order Gauss-Legendre rule. /// /// The analytic smooth complex function to integrate, defined on the real domain. /// Where the interval starts, exclusive and finite. /// Where the interval ends, 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 Complex ContourIntegrate(Func f, double invervalBegin, double invervalEnd, int order) { GaussPoint gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(order); Complex sum; double ax; int i; int m = (order + 1) >> 1; double a = 0.5 * (invervalEnd - invervalBegin); double b = 0.5 * (invervalEnd + invervalBegin); if (order.IsOdd()) { sum = gaussLegendrePoint.Weights[0] * f(b); for (i = 1; i < m; i++) { ax = a * gaussLegendrePoint.Abscissas[i]; sum += gaussLegendrePoint.Weights[i] * (f(b + ax) + f(b - ax)); } } else { sum = 0.0; for (i = 0; i < m; i++) { ax = a * gaussLegendrePoint.Abscissas[i]; sum += gaussLegendrePoint.Weights[i] * (f(b + ax) + f(b - ax)); } } return a * sum; } /// /// 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 Integrate(Func f, double invervalBeginA, double invervalEndA, double invervalBeginB, double invervalEndB, int order) { GaussPoint gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(order); double ax, cy, sum; int i, j; int m = (order + 1) >> 1; double a = 0.5*(invervalEndA - invervalBeginA); double b = 0.5*(invervalEndA + invervalBeginA); double c = 0.5*(invervalEndB - invervalBeginB); double d = 0.5*(invervalEndB + invervalBeginB); if (order.IsOdd()) { sum = gaussLegendrePoint.Weights[0]*gaussLegendrePoint.Weights[0]*f(b, d); double t; for (j = 1, t = 0.0; j < m; j++) { cy = c*gaussLegendrePoint.Abscissas[j]; t += gaussLegendrePoint.Weights[j]*(f(b, d + cy) + f(b, d - cy)); } sum += gaussLegendrePoint.Weights[0]*t; for (i = 1, t = 0.0; i < m; i++) { ax = a*gaussLegendrePoint.Abscissas[i]; t += gaussLegendrePoint.Weights[i]*(f(b + ax, d) + f(b - ax, d)); } sum += gaussLegendrePoint.Weights[0]*t; for (i = 1; i < m; i++) { ax = a*gaussLegendrePoint.Abscissas[i]; for (j = 1; j < m; j++) { cy = c*gaussLegendrePoint.Abscissas[j]; sum += gaussLegendrePoint.Weights[i]*gaussLegendrePoint.Weights[j]*(f(b + ax, d + cy) + f(ax + b, d - cy) + f(b - ax, d + cy) + f(b - ax, d - cy)); } } } else { sum = 0.0; for (i = 0; i < m; i++) { ax = a*gaussLegendrePoint.Abscissas[i]; for (j = 0; j < m; j++) { cy = c*gaussLegendrePoint.Abscissas[j]; sum += gaussLegendrePoint.Weights[i]*gaussLegendrePoint.Weights[j]*(f(b + ax, d + cy) + f(ax + b, d - cy) + f(b - ax, d + cy) + f(b - ax, d - cy)); } } } return c*a*sum; } } }