using System; namespace IStation.Numerics { public static class DifferIntegrate { /// /// Evaluates the Riemann-Liouville fractional derivative that uses the double exponential integration. /// /// /// order = 1.0 : normal derivative /// order = 0.5 : semi-derivative /// order = -0.5 : semi-integral /// order = -1.0 : normal integral /// /// The analytic smooth function to differintegrate. /// The evaluation point. /// The order of fractional derivative. /// The reference point of integration. /// The expected relative accuracy of the Double-Exponential integration. /// Approximation of the differintegral of order n at x. public static double DoubleExponential(Func f, double x, double order, double x0 = 0, double targetAbsoluteError = 1E-10) { // The Riemann–Liouville fractional derivative of f(x) of order n is defined as // \,_{x_0}{\mathbb{D}}^n_xf(x) = \frac{1}{\Gamma(m-n)} \frac{d^m}{dx^m} \int_{x_0}^{x} (x-t)^{m-n-1} f(t) dt // where m is the smallest interger greater than n. // see https://en.wikipedia.org/wiki/Differintegral if (Math.Abs(order) < double.Epsilon) { return f(x); } else if (order > 0 && Math.Abs(order - (int)order) < double.Epsilon) { return Differentiate.Derivative(f, x, (int)order); } else { int m = (int)Math.Ceiling(order) + 1; if (m < 1) m = 1; double r = m - order - 1; Func g = (v) => Integrate.DoubleExponential((t) => Math.Pow(v - t, r) * f(t), x0, v, targetAbsoluteError: targetAbsoluteError); double numerator = Differentiate.Derivative(g, x, m); double denominator = SpecialFunctions.Gamma(m - order); return numerator / denominator; } } /// /// Evaluates the Riemann-Liouville fractional derivative that uses the Gauss-Legendre integration. /// /// /// order = 1.0 : normal derivative /// order = 0.5 : semi-derivative /// order = -0.5 : semi-integral /// order = -1.0 : normal integral /// /// The analytic smooth function to differintegrate. /// The evaluation point. /// The order of fractional derivative. /// The reference point of integration. /// The number of Gauss-Legendre points. /// Approximation of the differintegral of order n at x. public static double GaussLegendre(Func f, double x, double order, double x0 = 0, int gaussLegendrePoints = 128) { // The Riemann–Liouville fractional derivative of f(x) of order n is defined as // \,_{x_0}{\mathbb{D}}^n_xf(x) = \frac{1}{\Gamma(m-n)} \frac{d^m}{dx^m} \int_{x_0}^{x} (x-t)^{m-n-1} f(t) dt // where m is the smallest interger greater than n. // see https://en.wikipedia.org/wiki/Differintegral if (Math.Abs(order) < double.Epsilon) { return f(x); } else if (order > 0 && Math.Abs(order - (int)order) < double.Epsilon) { return Differentiate.Derivative(f, x, (int)order); } else { int m = (int)Math.Ceiling(order) + 1; if (m < 1) m = 1; double r = m - order - 1; Func g = (v) => Integrate.GaussLegendre((t) => Math.Pow(v - t, r) * f(t), x0, v, order: gaussLegendrePoints); double numerator = Differentiate.Derivative(g, x, m); double denominator = SpecialFunctions.Gamma(m - order); return numerator / denominator; } } /// /// Evaluates the Riemann-Liouville fractional derivative that uses the Gauss-Kronrod integration. /// /// /// order = 1.0 : normal derivative /// order = 0.5 : semi-derivative /// order = -0.5 : semi-integral /// order = -1.0 : normal integral /// /// The analytic smooth function to differintegrate. /// The evaluation point. /// The order of fractional derivative. /// The reference point of integration. /// The expected relative accuracy of the Gauss-Kronrod integration. /// The number of Gauss-Kronrod points. Pre-computed for 15, 21, 31, 41, 51 and 61 points. /// Approximation of the differintegral of order n at x. public static double GaussKronrod(Func f, double x, double order, double x0 = 0, double targetRelativeError = 1E-10, int gaussKronrodPoints = 15) { // The Riemann–Liouville fractional derivative of f(x) of order n is defined as // \,_{x_0}{\mathbb{D}}^n_xf(x) = \frac{1}{\Gamma(m-n)} \frac{d^m}{dx^m} \int_{x_0}^{x} (x-t)^{m-n-1} f(t) dt // where m is the smallest interger greater than n. // see https://en.wikipedia.org/wiki/Differintegral if (Math.Abs(order) < double.Epsilon) { return f(x); } else if (order > 0 && Math.Abs(order - (int)order) < double.Epsilon) { return Differentiate.Derivative(f, x, (int)order); } else { int m = (int)Math.Ceiling(order) + 1; if (m < 1) m = 1; double r = m - order - 1; Func g = (v) => Integrate.GaussKronrod((t) => Math.Pow(v - t, r) * f(t), x0, v, targetRelativeError: targetRelativeError, order: gaussKronrodPoints); double numerator = Differentiate.Derivative(g, x, m); double denominator = SpecialFunctions.Gamma(m - order); return numerator / denominator; } } } }