示例#1
0
 static void     gsl_integration_qk61(IFunction1D f, double a, double b,
                                      out double result, out double abserr,
                                      out double resabs, out double resasc, Workspace workspace)
 {
     lock (fv1_61) {
         gsl_integration_qk(31, xgk_61, wg_61, wgk_61, fv1_61, fv2_61, f, a, b, out result, out abserr, out resabs, out resasc, workspace);
     }
 }
示例#2
0
 static void gsl_integration_qk15(IFunction1D f, double a, double b,
                                  out double result, out double abserr,
                                  out double resabs, out double resasc, Workspace workspace)
 {
     lock (fv1_15) {
         gsl_integration_qk(8, xgk_15, wg_15, wgk_15, fv1_15, fv2_15, f, a, b, out result, out abserr, out resabs, out resasc, workspace);
     }
 }
示例#3
0
        /// <summary>
        /// Differentiation of a one dimensional function.
        /// </summary>
        public static double dfdx(IFunction1D f, double x, out double abserr)
        {
            // adapted from gsl_diff_central

            /* Construct a divided difference table with a fairly large step
             *      size to get a very rough estimate of f'''.  Use this to estimate
             *      the step size which will minimize the error in calculating f'. */

            int    i, k;
            double h = GSL_SQRT_DBL_EPSILON, a3, temp;

            double[] a = new double[4], d = new double[4];

            /* Algorithm based on description on pg. 204 of Conte and de Boor
            *       (CdB) - coefficients of Newton form of polynomial of degree 3. */

            for (i = 0; i < 4; i++)
            {
                a[i] = x + (i - 2) * h;
                d[i] = f.f(a[i]);
            }

            for (k = 1; k < 5; k++)
            {
                for (i = 0; i < 4 - k; i++)
                {
                    d[i] = (d[i + 1] - d[i]) / (a[i + k] - a[i]);
                }
            }

            /* Adapt procedure described on pg. 282 of CdB to find best
             *      value of step size. */
            a3 = Math.Abs(d[0] + d[1] + d[2] + d[3]);

            if (a3 < 100 * GSL_SQRT_DBL_EPSILON)
            {
                a3 = 100 * GSL_SQRT_DBL_EPSILON;
            }

            h = Math.Pow(GSL_SQRT_DBL_EPSILON / (2 * a3), 1.0 / 3.0);

            if (h > 100 * GSL_SQRT_DBL_EPSILON)
            {
                h = 100 * GSL_SQRT_DBL_EPSILON;
            }

            abserr = Math.Abs(100.0 * a3 * h * h);
            temp   = x + h;
            GetH(x, ref h, temp);
            return((f.f(x + h) - f.f(x - h)) / (2 * h));
        }
示例#4
0
		/// <summary>
		/// Integration of the function f with adaptive stepsize. The integration region is divided into subintervals,
		///	and on each iteration the subinterval with the largest estimated error is bisected. This reduces the overall error
		///	rapidly, as the subintervals become concentrated around local difficulties in the integrand. The function allocates static
		/// memory for the used workspace accoring to the parameter memlimit.  
		/// This function applies an integration rule adaptively until an estimate of the integral of f over (a,b) is achieved within
		/// the desired absolute and relative error limits, epsabs and epsrel. The integration rule is determined by the value of smoothness,
		/// which should be chosen between 1 for smooth functions and 0 for functions that contain local difficulties, such as discontinuities.
		/// </summary>
		/// <param name="f">The function to integrate</param>
		/// <param name="a">The lower bound of the integration</param>
		/// <param name="b">The upper bound of the integration</param>
		/// <param name="epsabs">The desired absolute error</param>
		/// <param name="epsrel">The desired relative error</param>
		/// <param name="memlimit">The maximum memory consumption of the routine, in bytes</param>
		/// <param name="smoothness">The smoothness of the funtion. 1 indicates a smooth function and 0 indicates a function with local
		/// difficulties.</param>
		/// <param name="abserr">The absolute error of the integral</param>
		/// <returns></returns>
		public static double qa(IFunction1D f,
												 double a, double b,
												 double epsabs, double epsrel, int memlimit,
												 float smoothness,
												 out double abserr) {
			IntegrationRule integration_rule = r15;
			int limit = memlimit / (4*sizeof(double) + 2*sizeof(int));
			double result = double.NaN;
			Workspace workspace = new Workspace(limit);

			if (smoothness < 0) smoothness = 0;
			else if (smoothness >= 1) smoothness = 1;

			switch ((int)(smoothness*6)) {
			case 0:
				integration_rule = r15;
				break;
			case 1:
				integration_rule = r21;
				break;
			case 2:
				integration_rule = r31;
				break;
			case 3:
				integration_rule = r41;
				break;
			case 4:
				integration_rule = r51;
				break;
			case 5:
			case 6:
				integration_rule = r61;
				break;
			default: break;
			}

			qag_work(f, a, b, epsabs, epsrel, limit, out result, out abserr, integration_rule, workspace);
	
			return result;
		}
示例#5
0
		static void qag_work(IFunction1D f,
				double a, double b,
				double epsabs, double epsrel,
				int limit, out double result, out double abserr,
				 IntegrationRule q, Workspace workspace) {
			double area, errsum;
			double result0, abserr0, resabs0, resasc0;
			double tolerance;
			int iteration = 0;
			int roundoff_type1 = 0, roundoff_type2 = 0, error_type = 0;

			double round_off;

			/* Initialize results */

			workspace.initialise(a, b);

			result = 0;
			abserr = 0;

			if (limit > workspace.limit) { throw new ArgumentOutOfRangeException("iteration limit exceeds available workspace"); }

			if (epsabs <= 0 && (epsrel < 50 * GSL_DBL_EPSILON || epsrel < 0.5e-28)) {
				throw new ArgumentOutOfRangeException("tolerance cannot be acheived with given epsabs and epsrel");
			}

			/* perform the first integration */

			q(f, a, b, out result0, out abserr0, out resabs0, out resasc0, workspace);

			workspace.set_initial_result(result0, abserr0);

			/* Test on accuracy */

			tolerance = Math.Max(epsabs, epsrel * Math.Abs(result0));

			/* need IEEE rounding here to match original quadpack behavior */

			round_off = (50 * GSL_DBL_EPSILON * resabs0);

			if (abserr0 <= round_off && abserr0 > tolerance) {
				result = result0;
				abserr = abserr0;
				if (ThrowOnErrors) throw new ArithmeticException("cannot reach tolerance because of roundoff error on first attempt");
				return;
			} else if ((abserr0 <= tolerance && abserr0 != resasc0) || abserr0 == 0.0) {
				result = result0;
				abserr = abserr0;
				return;
			} else if (limit == 1) {
				result = result0;
				abserr = abserr0;
				if (ThrowOnErrors) throw new ArithmeticException("a maximum of one iteration was insufficient");
				return;
			}

			area = result0;
			errsum = abserr0;

			iteration = 1;

			do {
				double a1, b1, a2, b2;
				double a_i, b_i, r_i, e_i;
				double area1 = 0, area2 = 0, area12 = 0;
				double error1 = 0, error2 = 0, error12 = 0;
				double resasc1, resasc2;
				double resabs1, resabs2;

				/* Bisect the subinterval with the largest error estimate */

				workspace.retrieve(out a_i, out b_i, out r_i, out e_i);

				a1 = a_i;
				b1 = 0.5 * (a_i + b_i);
				a2 = b1;
				b2 = b_i;

				q(f, a1, b1, out area1, out error1, out resabs1, out resasc1, workspace);
				q(f, a2, b2, out area2, out error2, out resabs2, out resasc2, workspace);

				area12 = area1 + area2;
				error12 = error1 + error2;

				errsum += (error12 - e_i);
				area += area12 - r_i;

				if (resasc1 != error1 && resasc2 != error2) {
					double delta = r_i - area12;

					if (Math.Abs(delta) <= 1.0e-5 * Math.Abs(area12) && error12 >= 0.99 * e_i) {
						roundoff_type1++;
					}
					if (iteration >= 10 && error12 > e_i) {
						roundoff_type2++;
					}
				}

				tolerance = Math.Max(epsabs, epsrel * Math.Abs(area));

				if (errsum > tolerance) {
					if (roundoff_type1 >= 6 || roundoff_type2 >= 20) {
						error_type = 2;   /* round off error */
					}

					/* set error flag in the case of bad integrand behaviour at
					 a point of the integration range */

					if (subinterval_too_small(a1, a2, b2)) {
						error_type = 3;
					}
				}

				workspace.update(a1, b1, area1, error1, a2, b2, area2, error2);

				workspace.retrieve(out a_i, out b_i, out r_i, out e_i);

				iteration++;

			} while (iteration < limit && error_type == 0 && errsum > tolerance);

			result = workspace.sum_results();
			abserr = errsum;

			if (errsum <= tolerance) {
				return;
			} else if (error_type == 2) {
				if (ThrowOnErrors) throw new ArithmeticException("roundoff error prevents tolerance from being achieved");
			} else if (error_type == 3) {
				if (ThrowOnErrors) throw new ArithmeticException("bad integrand behavior found in the integration interval");
			} else if (iteration == limit) {
				if (ThrowOnErrors) throw new ArithmeticException("maximum number of subdivisions reached, increase memlimit.");
			} else {
				if (ThrowOnErrors) throw new ArithmeticException("could not integrate function");
			}
		}
示例#6
0
        private static void gsl_integration_qk(int n,
                                               double[] xgk, double[] wg, double[] wgk,
                                               double[] fv1, double[] fv2,
                                               IFunction1D f, double a, double b,
                                               out double result, out double abserr, out double resabs, out double resasc, Workspace workspace)
        {
            double center          = 0.5 * (a + b);
            double half_length     = 0.5 * (b - a);
            double abs_half_length = (half_length);
            double f_center        = f.f(center);

            double result_gauss   = 0;
            double result_kronrod = f_center * wgk[n - 1];

            double result_abs = Math.Abs(result_kronrod);
            double result_asc = 0;
            double mean = 0, err = 0;

            int j;

            if (n % 2 == 0)
            {
                result_gauss = f_center * wg[n / 2 - 1];
            }

            for (j = 0; j < (n - 1) / 2; j++)
            {
                int    jtw      = j * 2 + 1;                /* j=1,2,3 jtw=2,4,6 */
                double abscissa = half_length * xgk[jtw];
                double fval1    = f.f(center - abscissa);
                double fval2    = f.f(center + abscissa);
                double fsum     = fval1 + fval2;
                fv1[jtw]        = fval1;
                fv2[jtw]        = fval2;
                result_gauss   += wg[j] * fsum;
                result_kronrod += wgk[jtw] * fsum;
                result_abs     += wgk[jtw] * (Math.Abs(fval1) + Math.Abs(fval2));
            }

            for (j = 0; j < n / 2; j++)
            {
                int    jtwm1    = j * 2;
                double abscissa = half_length * xgk[jtwm1];
                double fval1    = f.f(center - abscissa);
                double fval2    = f.f(center + abscissa);
                fv1[jtwm1]      = fval1;
                fv2[jtwm1]      = fval2;
                result_kronrod += wgk[jtwm1] * (fval1 + fval2);
                result_abs     += wgk[jtwm1] * (Math.Abs(fval1) + Math.Abs(fval2));
            }

            mean = result_kronrod * 0.5;

            result_asc = wgk[n - 1] * Math.Abs(f_center - mean);

            for (j = 0; j < n - 1; j++)
            {
                result_asc += wgk[j] * (Math.Abs(fv1[j] - mean) + Math.Abs(fv2[j] - mean));
            }

            /* scale by the width of the integration region */

            err = (result_kronrod - result_gauss) * half_length;

            result_kronrod *= half_length;
            result_abs     *= abs_half_length;
            result_asc     *= abs_half_length;

            result = result_kronrod;;
            resabs = result_abs;
            resasc = result_asc;
            abserr = rescale_error(err, result_abs, result_asc);
        }
示例#7
0
        /// <summary>
        /// Integration of a smooth one dimensional function. The integral is computed until the error is below either <c>epsabs</c>
        /// or <c>epsrel</c>. The algorithm is provided for fast integration of smooth functions.
        /// </summary>
        /// <param name="f">The function to integrate</param>
        /// <param name="a">The lower integration bound</param>
        /// <param name="b">The upper integration bound</param>
        /// <param name="epsabs">The desired absolute error</param>
        /// <param name="epsrel">The desired relative error</param>
        /// <param name="abserr">The estimated error of the result</param>
        /// <returns>The integral of the function</returns>
        public static double q(IFunction1D f, double a, double b, double epsabs, double epsrel,
                               out double abserr)
        {
            double[] fv1 = new double[5], fv2 = new double[5], fv3 = new double[5], fv4 = new double[5];
            double[] savfun = new double[21];    /* array of function values which have been computed */
            double   res10, res21, res43, res87; /* 10, 21, 43 and 87 point results */
            double   result_kronrod, result, err;
            double   resabs;                     /* approximation to the integral of abs(f) */
            double   resasc;                     /* approximation to the integral of abs(f-i/(b-a)) */

            double half_length     = 0.5 * (b - a);
            double abs_half_length = Math.Abs(half_length);
            double center          = 0.5 * (b + a);
            double f_center        = f.f(center);

            int k;

            if (epsabs <= 0 && (epsrel < 50 * GSL_DBL_EPSILON || epsrel < 0.5e-28))
            {
                abserr = 0;
                if (ThrowOnErrors)
                {
                    throw new ArgumentException("errors too small");
                }
                return(double.NaN);
            }

            /* Compute the integral using the 10- and 21-point formula. */

            res10  = 0;
            res21  = w21b[5] * f_center;
            resabs = w21b[5] * Math.Abs(f_center);

            for (k = 0; k < 5; k++)
            {
                double abscissa = half_length * x1[k];
                double fval1    = f.f(center + abscissa);
                double fval2    = f.f(center - abscissa);
                double fval     = fval1 + fval2;
                res10    += w10[k] * fval;
                res21    += w21a[k] * fval;
                resabs   += w21a[k] * (Math.Abs(fval1) + Math.Abs(fval2));
                savfun[k] = fval;
                fv1[k]    = fval1;
                fv2[k]    = fval2;
            }

            for (k = 0; k < 5; k++)
            {
                double abscissa = half_length * x2[k];
                double fval1    = f.f(center + abscissa);
                double fval2    = f.f(center - abscissa);
                double fval     = fval1 + fval2;
                res21        += w21b[k] * fval;
                resabs       += w21b[k] * (Math.Abs(fval1) + Math.Abs(fval2));
                savfun[k + 5] = fval;
                fv3[k]        = fval1;
                fv4[k]        = fval2;
            }

            resabs *= abs_half_length;

            {
                double mean = 0.5 * res21;

                resasc = w21b[5] * Math.Abs(f_center - mean);

                for (k = 0; k < 5; k++)
                {
                    resasc +=
                        (w21a[k] * (Math.Abs(fv1[k] - mean) + Math.Abs(fv2[k] - mean))
                         + w21b[k] * (Math.Abs(fv3[k] - mean) + Math.Abs(fv4[k] - mean)));
                }
                resasc *= abs_half_length;
            }

            result_kronrod = res21 * half_length;

            err = rescale_error((res21 - res10) * half_length, resabs, resasc);

            /*   test for convergence. */

            if (err < epsabs || err < epsrel * Math.Abs(result_kronrod))
            {
                result = result_kronrod;
                abserr = err;
                return(result);
            }

            /* compute the integral using the 43-point formula. */

            res43 = w43b[11] * f_center;

            for (k = 0; k < 10; k++)
            {
                res43 += savfun[k] * w43a[k];
            }

            for (k = 0; k < 11; k++)
            {
                double abscissa = half_length * x3[k];
                double fval     = (f.f(center + abscissa) + f.f(center - abscissa));
                res43         += fval * w43b[k];
                savfun[k + 10] = fval;
            }

            /*  test for convergence */

            result_kronrod = res43 * half_length;
            err            = rescale_error((res43 - res21) * half_length, resabs, resasc);

            if (err < epsabs || err < epsrel * Math.Abs(result_kronrod))
            {
                result = result_kronrod;
                abserr = err;
                return(result);
            }

            /* compute the integral using the 87-point formula. */

            res87 = w87b[22] * f_center;

            for (k = 0; k < 21; k++)
            {
                res87 += savfun[k] * w87a[k];
            }

            for (k = 0; k < 22; k++)
            {
                double abscissa = half_length * x4[k];
                res87 += w87b[k] * (f.f(center + abscissa) + f.f(center - abscissa));
            }

            /* test for convergence */

            result_kronrod = res87 * half_length;

            err = rescale_error((res87 - res43) * half_length, resabs, resasc);

            if (err < epsabs || err < epsrel * Math.Abs(result_kronrod))
            {
                result = result_kronrod;
                abserr = err;
                return(result);
            }

            /* failed to converge */

            result = result_kronrod;
            abserr = err;
            return(result);
        }
示例#8
0
 /// <summary>
 /// An alias for the routine <see cref="dfdx(IFunction1D, double, out double)"/>.
 /// </summary>
 public static double diff(IFunction1D f, double x, out double abserr)
 {
     return(dfdx(f, x, out abserr));
 }