static void gsl_integration_qk61(Function1DDelegate 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); } }
static void gsl_integration_qk15(Function1DDelegate 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); } }
/// <summary> /// Differentiation of a one dimensional function. /// </summary> public static double dfdx(Function1DDelegate 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(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(x + h) - f(x - h)) / (2 * h)); }
/// <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(Function1DDelegate f, double a, double b, double epsabs, double epsrel, int memlimit, float smoothness, out double abserr) { IntegrationRuleDelegate integration_rule = r15d; 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 = r15d; break; case 1: integration_rule = r21d; break; case 2: integration_rule = r31d; break; case 3: integration_rule = r41d; break; case 4: integration_rule = r51d; break; case 5: case 6: integration_rule = r61d; break; default: break; } qag_work(f, a, b, epsabs, epsrel, limit, out result, out abserr, integration_rule, workspace); return result; }
static void qag_work(Function1DDelegate f, double a, double b, double epsabs, double epsrel, int limit, out double result, out double abserr, IntegrationRuleDelegate 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"); } }
private static void gsl_integration_qk(int n, double[] xgk, double[] wg, double[] wgk, double[] fv1, double[] fv2, Function1DDelegate 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(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(center - abscissa); double fval2 = 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(center - abscissa); double fval2 = 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); }
/// <summary> /// An alias for the routine <see cref="dfdx(IFunction1D, double, out double)"/>. /// </summary> public static double diff(Function1DDelegate f, double x, out double abserr) { return(dfdx(f, x, out abserr)); }
/// <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(Function1DDelegate 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(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(center + abscissa); double fval2 = 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(center + abscissa); double fval2 = 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(center + abscissa) + 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(center + abscissa) + 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); }