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