Example #1
0
        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 });
        }
Example #2
0
        /// <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 });
 }
Example #5
0
        /// <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
        /// &#x3B5; = &#x222B;<sub>0</sub><sup>&#x3B4;</sup> x<sup>-1/2</sup> dx = 2 &#x3B4;<sup>1/2</sup>,
        /// points within &#x3B4; &#x223C; 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 &#x3B5; &#x223C; 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 &#x3B5; &#x223C; 10<sup>-16</sup> precision, we would need to
        /// evaluate the contributions of points within &#x3B4; &#x223C; 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 = &#x222B;<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 &#x222B;<sub>0</sub><sup>&#x221A;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);
        }