public virtual IList <IAdaptiveIntegrator> Divide() { GaussKronrodIntegrator i1 = new GaussKronrodIntegrator(Integrand, Interval.FromEndpoints(Range.LeftEndpoint, Range.Midpoint)); i1.Generation = this.Generation + 1; GaussKronrodIntegrator i2 = new GaussKronrodIntegrator(Integrand, Interval.FromEndpoints(Range.Midpoint, Range.RightEndpoint)); i2.Generation = this.Generation + 1; return(new GaussKronrodIntegrator[] { i1, i2 }); }
/// <summary> /// Evaluates a definite integral with the given evaluation settings. /// </summary> /// <param name="integrand">The function to be integrated.</param> /// <param name="range">The range of integration.</param> /// <param name="settings">The settings which control the evaulation of the integal.</param> /// <returns>The result of the integral, which includes an estimated value and estimated uncertainty of that value.</returns> public static IntegrationResult Integrate(Func <double, double> integrand, Interval range, EvaluationSettings settings) { if (integrand == null) { throw new ArgumentNullException("integrand"); } // remap infinite integrals to finite integrals if (Double.IsNegativeInfinity(range.LeftEndpoint) && Double.IsPositiveInfinity(range.RightEndpoint)) { // -infinity to +infinity // remap to (-pi/2,pi/2) Func <double, double> f0 = integrand; Func <double, double> f1 = delegate(double t) { double x = Math.Tan(t); return(f0(x) * (1.0 + x * x)); }; Interval r1 = Interval.FromEndpoints(-Global.HalfPI, Global.HalfPI); return(Integrate(f1, r1, settings)); } else if (Double.IsPositiveInfinity(range.RightEndpoint)) { // finite to +infinity // remap to interval (-1,1) double a0 = range.LeftEndpoint; Func <double, double> f0 = integrand; Func <double, double> f1 = delegate(double t) { double q = 1.0 - t; double x = a0 + (1 + t) / q; return(f0(x) * (2.0 / q / q)); }; Interval r1 = Interval.FromEndpoints(-1.0, 1.0); return(Integrate(f1, r1, settings)); } else if (Double.IsNegativeInfinity(range.LeftEndpoint)) { // -infinity to finite // remap to interval (-1,1) double b0 = range.RightEndpoint; Func <double, double> f0 = integrand; Func <double, double> f1 = delegate(double t) { double q = t + 1.0; double x = b0 + (t - 1.0) / q; return(f0(x) * (2.0 / q / q)); }; Interval r1 = Interval.FromEndpoints(-1.0, 1.0); return(Integrate(f1, r1, settings)); } // normal integral over a finitite range IAdaptiveIntegrator integrator = new GaussKronrodIntegrator(integrand, range); IntegrationResult result = Integrate_Adaptive(integrator, settings); return(result); }
/// <summary> /// Evaluates a definite integral with the given evaluation settings. /// </summary> /// <param name="integrand">The function to be integrated.</param> /// <param name="range">The range of integration.</param> /// <param name="settings">The settings which control the evaulation of the integal.</param> /// <returns>The result of the integral, which includes an estimated value and estimated uncertainty of that value.</returns> public static IntegrationResult Integrate(Func<double,double> integrand, Interval range, EvaluationSettings settings) { if (integrand == null) throw new ArgumentNullException("integrand"); // remap infinite integrals to finite integrals if (Double.IsNegativeInfinity(range.LeftEndpoint) && Double.IsPositiveInfinity(range.RightEndpoint)) { // -infinity to +infinity // remap to (-pi/2,pi/2) Func<double, double> f0 = integrand; Func<double, double> f1 = delegate (double t) { double x = Math.Tan(t); return (f0(x) * (1.0 + x * x)); }; Interval r1 = Interval.FromEndpoints(-Global.HalfPI, Global.HalfPI); return (Integrate(f1, r1, settings)); } else if (Double.IsPositiveInfinity(range.RightEndpoint)) { // finite to +infinity // remap to interval (-1,1) double a0 = range.LeftEndpoint; Func<double, double> f0 = integrand; Func<double, double> f1 = delegate (double t) { double q = 1.0 - t; double x = a0 + (1 + t) / q; return (f0(x) * (2.0 / q / q)); }; Interval r1 = Interval.FromEndpoints(-1.0, 1.0); return (Integrate(f1, r1, settings)); } else if (Double.IsNegativeInfinity(range.LeftEndpoint)) { // -infinity to finite // remap to interval (-1,1) double b0 = range.RightEndpoint; Func<double, double> f0 = integrand; Func<double, double> f1 = delegate (double t) { double q = t + 1.0; double x = b0 + (t - 1.0) / q; return(f0(x) * (2.0 / q / q)); }; Interval r1 = Interval.FromEndpoints(-1.0, 1.0); return(Integrate(f1, r1, settings)); } // normal integral over a finitite range IAdaptiveIntegrator integrator = new GaussKronrodIntegrator(integrand, range); IntegrationResult result = Integrate_Adaptive(integrator, settings); return (result); }
public virtual IList<IAdaptiveIntegrator> Divide() { GaussKronrodIntegrator i1 = new GaussKronrodIntegrator(Integrand, Interval.FromEndpoints(Range.LeftEndpoint, Range.Midpoint)); i1.Generation = this.Generation + 1; GaussKronrodIntegrator i2 = new GaussKronrodIntegrator(Integrand, Interval.FromEndpoints(Range.Midpoint, Range.RightEndpoint)); i2.Generation = this.Generation + 1; return (new GaussKronrodIntegrator[] { i1, i2 }); }
/// <summary> /// Evaluates a definite integral with the given evaluation settings. /// </summary> /// <param name="integrand">The function to be integrated.</param> /// <param name="start">The left integration endpoint.</param> /// <param name="end">The right integration endpoint.</param> /// <param name="settings">The settings which control the evaluation of the integral.</param> /// <returns>The result of the integral.</returns> /// <remarks> /// <para>To do integrals over infinite regions, simply set <paramref name="start"/> or <paramref name="end"/> /// to <see cref="System.Double.NegativeInfinity"/> or <see cref="System.Double.PositiveInfinity"/>.</para> /// <para>Our integrator handles smooth functions extremely efficiently. It handles integrands with /// discontinuities or kinks at the price of slightly more evaluations of the integrand. /// It can handle oscillatory functions, as long as cancelation between positive and negative regions /// is not too severe. It can integrate logarithmic and mild power-law singularities.</para> /// <para>Strong power-law singularities will cause the algorithm to fail with a <see cref="NonconvergenceException"/>. /// This is unavoidable for essentially any double-precision numerical integrator. Consider, for example, /// the integrable singularity x<sup>-1/2</sup>. Since /// ε = ∫<sub>0</sub><sup>δ</sup> x<sup>-1/2</sup> dx = 2 δ<sup>1/2</sup>, /// points within δ ∼ 10<sup>-16</sup> of the end-points, which as a close as you can get to /// a point in double precision without being on top of it, contribute at the ε ∼ 10<sup>-8</sup> /// level to our integral, well beyond limit that nearly-full double precision requires. Said differently, /// to know the value of the integral to ε ∼ 10<sup>-16</sup> precision, we would need to /// evaluate the contributions of points within δ ∼ 10<sup>-32</sup> of the endpoints, /// which is far closer than we can get.</para> /// <para>If you need to evaluate an integral with such a strong singularity, try to make an analytic /// change of variable to absorb the singularity before attempting numerical integration. For example, /// to evaluate I = ∫<sub>0</sub><sup>b</sup> f(x) x<sup>-1/2</sup> dx, substitute y = x<sup>1/2</sup> /// to obtain I = 2 ∫<sub>0</sub><sup>√b</sup> f(y<sup>2</sup>) dy.</para> /// <para>To do multi-dimensional integrals, use /// <see cref="MultiFunctionMath.Integrate(Func{IReadOnlyList{double}, double}, IReadOnlyList{Interval}, IntegrationSettings)"/>. /// </para> /// </remarks> /// <exception cref="ArgumentNullException">The <paramref name="integrand"/> is <see langword="null"/>.</exception> /// <exception cref="NonconvergenceException">The maximum number of function evaluations was exceeded before the integral /// could be determined to the required precision.</exception> public static IntegrationResult Integrate(Func <double, double> integrand, double start, double end, IntegrationSettings settings) { if (integrand == null) { throw new ArgumentNullException(nameof(integrand)); } if (settings == null) { throw new ArgumentNullException(nameof(settings)); } // Deal with right-to-left integrals if (end < start) { IntegrationResult r = Integrate(integrand, end, start, settings); return(new IntegrationResult(-r.Estimate, r.EvaluationCount, r.Settings)); } // Re-map infinite integrals to finite integrals if (Double.IsNegativeInfinity(start) && Double.IsPositiveInfinity(end)) { // -\infty to +\infty // remap to (-\pi/2,\pi/2) Func <double, double> f1 = delegate(double t) { double x = Math.Tan(t); return(integrand(x) * (1.0 + x * x)); }; return(Integrate(f1, -Global.HalfPI, +Global.HalfPI, settings)); } else if (Double.IsPositiveInfinity(end)) { // finite to +\infty // remap to interval (-1,1) Func <double, double> f1 = delegate(double t) { double q = 1.0 / (1.0 - t); double x = start + (1.0 + t) * q; return(integrand(x) * 2.0 * q * q); }; return(Integrate(f1, -1.0, +1.0, settings)); } else if (Double.IsNegativeInfinity(start)) { // -\infty to finite // remap to interval (-1,1) Func <double, double> f1 = delegate(double t) { double q = t + 1.0; double x = end + (t - 1.0) / q; return(integrand(x) * (2.0 / q / q)); }; return(Integrate(f1, -1.0, +1.0, settings)); } // Fix settings. settings = SetIntegrationDefaults(settings); // normal integral over a finite range Debug.Assert(end >= start); IAdaptiveIntegrator integrator = new GaussKronrodIntegrator(integrand, Interval.FromEndpoints(start, end)); IntegrationResult result = Integrate_Adaptive(integrator, settings); return(result); }