Пример #1
0
        Integrate(Func <double, double> f,
                  double a,
                  OscillatoryTerm oscTerm,
                  double omega,
                  double epsabs, int limit,
                  bool debug,
                  out double result, out double abserr)
        {
            if (null == _workSpace || limit > _workSpace.limit)
            {
                _workSpace = new gsl_integration_workspace(limit);
            }

            if (null == _cycleWorkspace || limit > _cycleWorkspace.limit)
            {
                _cycleWorkspace = new gsl_integration_workspace(limit);
            }

            if (null == _qawoTable)
            {
                _qawoTable = new gsl_integration_qawo_table(omega, 1, oscTerm == OscillatoryTerm.Cosine ? gsl_integration_qawo_enum.GSL_INTEG_COSINE : gsl_integration_qawo_enum.GSL_INTEG_SINE, _defaultOscTableLength);
            }
            else
            {
                _qawoTable.set(omega, 1, oscTerm == OscillatoryTerm.Cosine ? gsl_integration_qawo_enum.GSL_INTEG_COSINE : gsl_integration_qawo_enum.GSL_INTEG_SINE);
            }
            return(gsl_integration_qawf(f, a, epsabs, limit, _workSpace, _cycleWorkspace, _qawoTable, out result, out abserr, debug));
        }
Пример #2
0
			Integrate(Func<double, double> f,
			double a, double b,
			OscillatoryTerm oscTerm,
			double omega,
			double epsabs, double epsrel, int limit,
			bool debug,
			out double result, out double abserr)
		{
			if (null == _workSpace || limit > _workSpace.limit)
				_workSpace = new gsl_integration_workspace(limit);
			if (null == _qawoTable)
			{
				_qawoTable = new gsl_integration_qawo_table(omega, b - a, oscTerm == OscillatoryTerm.Cosine ? gsl_integration_qawo_enum.GSL_INTEG_COSINE : gsl_integration_qawo_enum.GSL_INTEG_SINE, _defaultOscTableLength);
			}
			else
			{
				_qawoTable.set(omega, b - a, oscTerm == OscillatoryTerm.Cosine ? gsl_integration_qawo_enum.GSL_INTEG_COSINE : gsl_integration_qawo_enum.GSL_INTEG_SINE);
			}

			return gsl_integration_qawo(f, a, epsabs, epsrel, limit, _workSpace, _qawoTable, out result, out abserr, debug);
		}
Пример #3
0
		qc25f(Func<double, double> f, double a, double b,
					 gsl_integration_qawo_table wf, int level,
					 out double result, out double abserr, out double resabs, out double resasc)
		{
			double center = 0.5 * (a + b);
			double half_length = 0.5 * (b - a);
			double omega = wf.omega;

			double par = omega * half_length;

			if (Math.Abs(par) < 2)
			{
				Func<double, double> weighted_function;
				fn_fourier_params fn_params;

				fn_params.function = f;
				fn_params.omega = omega;

				if (wf.sine == gsl_integration_qawo_enum.GSL_INTEG_SINE)
				{
					weighted_function = delegate(double t) { return fn_sin(t, fn_params); };
				}
				else
				{
					weighted_function = delegate(double t) { return fn_cos(t, fn_params); };
				}

				QK15.Integration(weighted_function, a, b, out result, out abserr,
															out resabs, out resasc);

				return;
			}
			else
			{
				int momentix;
				double[] cheb12 = new double[13];
				double[] cheb24 = new double[25];
				double result_abs, res12_cos, res12_sin, res24_cos, res24_sin;
				double est_cos, est_sin;
				double c, s;
				int i;

				Qcheb.Approximation(f, a, b, cheb12, cheb24);

				if (level >= wf.n)
				{
					/* table overflow should not happen, check before calling */
					new GSL_ERROR("table overflow in internal function", GSL_ERR.GSL_ESANITY, true);
					throw new ArithmeticException("table overflow in internal function"); //
				}

				/* obtain moments from the table */

				momentix = 25 * level;

				res12_cos = cheb12[12] * wf.chebmo[momentix + 12];
				res12_sin = 0;

				for (i = 0; i < 6; i++)
				{
					int k = 10 - 2 * i;
					res12_cos += cheb12[k] * wf.chebmo[momentix + k];
					res12_sin += cheb12[k + 1] * wf.chebmo[momentix + k + 1];
				}

				res24_cos = cheb24[24] * wf.chebmo[momentix + 24];
				res24_sin = 0;

				result_abs = Math.Abs(cheb24[24]);

				for (i = 0; i < 12; i++)
				{
					int k = 22 - 2 * i;
					res24_cos += cheb24[k] * wf.chebmo[momentix + k];
					res24_sin += cheb24[k + 1] * wf.chebmo[momentix + k + 1];
					result_abs += Math.Abs(cheb24[k]) + Math.Abs(cheb24[k + 1]);
				}

				est_cos = Math.Abs(res24_cos - res12_cos);
				est_sin = Math.Abs(res24_sin - res12_sin);

				c = half_length * Math.Cos(center * omega);
				s = half_length * Math.Sin(center * omega);

				if (wf.sine == gsl_integration_qawo_enum.GSL_INTEG_SINE)
				{
					result = c * res24_sin + s * res24_cos;
					abserr = Math.Abs(c * est_sin) + Math.Abs(s * est_cos);
				}
				else
				{
					result = c * res24_cos - s * res24_sin;
					abserr = Math.Abs(c * est_cos) + Math.Abs(s * est_sin);
				}

				resabs = result_abs * half_length;
				resasc = GSL_CONST.GSL_DBL_MAX;

				return;
			}
		}
Пример #4
0
		gsl_integration_qawo(Func<double, double> f,
													double a,
													double epsabs, double epsrel,
													int limit,
													gsl_integration_workspace workspace,
													gsl_integration_qawo_table wf,
													out double result, out double abserr,
														bool bDebug)
		{
			double area, errsum;
			double res_ext, err_ext;
			double result0, abserr0, resabs0, resasc0;
			double tolerance;

			double ertest = 0;
			double error_over_large_intervals = 0;
			double reseps = 0, abseps = 0, correc = 0;
			int ktmin = 0;
			int roundoff_type1 = 0, roundoff_type2 = 0, roundoff_type3 = 0;
			int error_type = 0;
			bool error_type2 = false;

			int iteration = 0;

			bool positive_integrand = false;
			bool extrapolate = false;
			bool extall = false;
			bool disallow_extrapolation = false;

			extrapolation_table table = new extrapolation_table();

			double b = a + wf.L;
			double abs_omega = Math.Abs(wf.omega);

			/* Initialize results */

			workspace.initialise(a, b);

			result = 0;
			abserr = 0;

			if (limit > workspace.limit)
			{
				return new GSL_ERROR("iteration limit exceeds available workspace", GSL_ERR.GSL_EINVAL, bDebug);
			}

			/* Test on accuracy */

			if (epsabs <= 0 && (epsrel < 50 * GSL_CONST.GSL_DBL_EPSILON || epsrel < 0.5e-28))
			{
				return new GSL_ERROR("tolerance cannot be acheived with given epsabs and epsrel",
									 GSL_ERR.GSL_EBADTOL, bDebug);
			}

			/* Perform the first integration */

			qc25f(f, a, b, wf, 0, out result0, out abserr0, out resabs0, out resasc0);

			workspace.set_initial_result(result0, abserr0);

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

			if (abserr0 <= 100 * GSL_CONST.GSL_DBL_EPSILON * resabs0 && abserr0 > tolerance)
			{
				result = result0;
				abserr = abserr0;

				return new GSL_ERROR("cannot reach tolerance because of roundoff error on first attempt", GSL_ERR.GSL_EROUND, bDebug);
			}
			else if ((abserr0 <= tolerance && abserr0 != resasc0) || abserr0 == 0.0)
			{
				result = result0;
				abserr = abserr0;

				return null; // GSL_SUCCESS;
			}
			else if (limit == 1)
			{
				result = result0;
				abserr = abserr0;

				return new GSL_ERROR("a maximum of one iteration was insufficient", GSL_ERR.GSL_EMAXITER, bDebug);
			}

			/* Initialization */

			table.initialise_table();

			if (0.5 * abs_omega * Math.Abs(b - a) <= 2)
			{
				table.append_table(result0);
				extall = true;
			}

			area = result0;
			errsum = abserr0;

			res_ext = result0;
			err_ext = GSL_CONST.GSL_DBL_MAX;

			positive_integrand = test_positivity(result0, resabs0);

			iteration = 1;

			do
			{
				int current_level;
				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;
				double last_e_i;

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

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

				current_level = workspace.level[workspace.i] + 1;

				if (current_level >= wf.n)
				{
					error_type = -1; /* exceeded limit of table */
					break;
				}

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

				iteration++;

				qc25f(f, a1, b1, wf, current_level, out area1, out error1, out resabs1, out resasc1);
				qc25f(f, a2, b2, wf, current_level, out area2, out error2, out resabs2, out resasc2);

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

				/* Improve previous approximations to the integral and test for
					 accuracy.

					 We write these expressions in the same way as the original
					 QUADPACK code so that the rounding errors are the same, which
					 makes testing easier. */

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

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

				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)
					{
						if (!extrapolate)
						{
							roundoff_type1++;
						}
						else
						{
							roundoff_type2++;
						}
					}
					if (iteration > 10 && error12 > e_i)
					{
						roundoff_type3++;
					}
				}

				/* Test for roundoff and eventually set error flag */

				if (roundoff_type1 + roundoff_type2 >= 10 || roundoff_type3 >= 20)
				{
					error_type = 2;       /* round off error */
				}

				if (roundoff_type2 >= 5)
				{
					error_type2 = true;
				}

				/* 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 = 4;
				}

				/* append the newly-created intervals to the list */

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

				if (errsum <= tolerance)
				{
					goto compute_result;
				}

				if (0 != error_type)
				{
					break;
				}

				if (iteration >= limit - 1)
				{
					error_type = 1;
					break;
				}

				/* set up variables on first iteration */

				if (iteration == 2 && extall)
				{
					error_over_large_intervals = errsum;
					ertest = tolerance;
					table.append_table(area);
					continue;
				}

				if (disallow_extrapolation)
				{
					continue;
				}

				if (extall)
				{
					error_over_large_intervals += -last_e_i;

					if (current_level < workspace.maximum_level)
					{
						error_over_large_intervals += error12;
					}

					if (extrapolate)
						goto label70;
				}

				if (workspace.large_interval())
				{
					continue;
				}

				if (extall)
				{
					extrapolate = true;
					workspace.nrmax = 1;
				}
				else
				{
					/* test whether the interval to be bisected next is the
						 smallest interval. */
					int i = workspace.i;
					double width = workspace.blist[i] - workspace.alist[i];

					if (0.25 * Math.Abs(width) * abs_omega > 2)
						continue;

					extall = true;
					error_over_large_intervals = errsum;
					ertest = tolerance;
					continue;
				}

			label70:
				if (!error_type2 && error_over_large_intervals > ertest)
				{
					if (workspace.increase_nrmax())
						continue;
				}

				/* Perform extrapolation */

				table.append_table(area);

				if (table.n < 3)
				{
					workspace.reset_nrmax();
					extrapolate = false;
					error_over_large_intervals = errsum;
					continue;
				}

				table.qelg(out reseps, out abseps);

				ktmin++;

				if (ktmin > 5 && err_ext < 0.001 * errsum)
				{
					error_type = 5;
				}

				if (abseps < err_ext)
				{
					ktmin = 0;
					err_ext = abseps;
					res_ext = reseps;
					correc = error_over_large_intervals;
					ertest = Math.Max(epsabs, epsrel * Math.Abs(reseps));
					if (err_ext <= ertest)
						break;
				}

				/* Prepare bisection of the smallest interval. */

				if (table.n == 1)
				{
					disallow_extrapolation = true;
				}

				if (error_type == 5)
				{
					break;
				}

				/* work on interval with largest error */

				workspace.reset_nrmax();
				extrapolate = false;
				error_over_large_intervals = errsum;
			}
			while (iteration < limit);

			result = res_ext;
			abserr = err_ext;

			if (err_ext == GSL_CONST.GSL_DBL_MAX)
				goto compute_result;

			if (0 != error_type || error_type2)
			{
				if (error_type2)
				{
					err_ext += correc;
				}

				if (error_type == 0)
					error_type = 3;

				if (result != 0 && area != 0)
				{
					if (err_ext / Math.Abs(res_ext) > errsum / Math.Abs(area))
						goto compute_result;
				}
				else if (err_ext > errsum)
				{
					goto compute_result;
				}
				else if (area == 0.0)
				{
					goto return_error;
				}
			}

			/*  Test on divergence. */

			{
				double max_area = Math.Max(Math.Abs(res_ext), Math.Abs(area));

				if (!positive_integrand && max_area < 0.01 * resabs0)
					goto return_error;
			}

			{
				double ratio = res_ext / area;

				if (ratio < 0.01 || ratio > 100 || errsum > Math.Abs(area))
					error_type = 6;
			}

			goto return_error;

		compute_result:

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

		return_error:

			if (error_type > 2)
				error_type--;

			if (error_type == 0)
			{
				return null; // GSL_SUCCESS;
			}
			else if (error_type == 1)
			{
				return new GSL_ERROR("number of iterations was insufficient", GSL_ERR.GSL_EMAXITER, bDebug);
			}
			else if (error_type == 2)
			{
				return new GSL_ERROR("cannot reach tolerance because of roundoff error",
									 GSL_ERR.GSL_EROUND, bDebug);
			}
			else if (error_type == 3)
			{
				return new GSL_ERROR("bad integrand behavior found in the integration interval",
									 GSL_ERR.GSL_ESING, bDebug);
			}
			else if (error_type == 4)
			{
				return new GSL_ERROR("roundoff error detected in extrapolation table", GSL_ERR.GSL_EROUND, bDebug);
			}
			else if (error_type == 5)
			{
				return new GSL_ERROR("integral is divergent, or slowly convergent", GSL_ERR.GSL_EDIVERGE, bDebug);
			}
			else if (error_type == -1)
			{
				return new GSL_ERROR("exceeded limit of trigonometric table", GSL_ERR.GSL_ETABLE, bDebug);
			}
			else
			{
				return new GSL_ERROR("could not integrate function", GSL_ERR.GSL_EFAILED, bDebug);
			}
		}
Пример #5
0
		gsl_integration_qawf(Func<double, double> f,
													double a,
													double epsabs,
													int limit,
													gsl_integration_workspace workspace,
													gsl_integration_workspace cycle_workspace,
													gsl_integration_qawo_table wf,
													out double result, out double abserr,
													bool bDebug)
		{
			double area, errsum;
			double res_ext, err_ext;
			double correc, total_error = 0.0, truncation_error = 0;

			int ktmin = 0;
			int iteration = 0;

			extrapolation_table table = new extrapolation_table();

			double cycle;
			double omega = wf.omega;

			double p = 0.9;
			double factor = 1;
			double initial_eps, eps;
			int error_type = 0;

			/* Initialize results */

			workspace.initialise(a, a);

			result = 0;
			abserr = 0;

			if (limit > workspace.limit)
			{
				return new GSL_ERROR("iteration limit exceeds available workspace", GSL_ERR.GSL_EINVAL, bDebug);
			}

			/* Test on accuracy */

			if (epsabs <= 0)
			{
				return new GSL_ERROR("absolute tolerance epsabs must be positive", GSL_ERR.GSL_EBADTOL, bDebug);
			}

			if (omega == 0.0)
			{
				if (wf.sine == gsl_integration_qawo_enum.GSL_INTEG_SINE)
				{
					/* The function sin(w x) f(x) is always zero for w = 0 */

					result = 0;
					abserr = 0;

					return null; // GSL_SUCCESS;
				}
				else
				{
					/* The function cos(w x) f(x) is always f(x) for w = 0 */

					GSL_ERROR status = QagiuIntegration.gsl_integration_qagiu(f, a, epsabs, 0.0,
																							cycle_workspace.limit,
																							cycle_workspace,
																							out result, out abserr,
																							QagiuIntegration.DefaultIntegrationRule, QagiuIntegration.DefaultDebugFlag);
					return status;
				}
			}

			if (epsabs > GSL_CONST.GSL_DBL_MIN / (1 - p))
			{
				eps = epsabs * (1 - p);
			}
			else
			{
				eps = epsabs;
			}

			initial_eps = eps;

			area = 0;
			errsum = 0;

			res_ext = 0;
			err_ext = GSL_CONST.GSL_DBL_MAX;
			correc = 0;

			cycle = (2 * Math.Floor(Math.Abs(omega)) + 1) * Math.PI / Math.Abs(omega);

			wf.set_length(cycle);

			table.initialise_table();

			for (iteration = 0; iteration < limit; iteration++)
			{
				double area1, error1, reseps, erreps;

				double a1 = a + iteration * cycle;
				double b1 = a1 + cycle;

				double epsabs1 = eps * factor;

				GSL_ERROR status = gsl_integration_qawo(f, a1, epsabs1, 0.0, limit,
																					 cycle_workspace, wf,
																					 out area1, out error1, false);

				workspace.append_interval(a1, b1, area1, error1);

				factor *= p;

				area = area + area1;
				errsum = errsum + error1;

				/* estimate the truncation error as 50 times the final term */

				truncation_error = 50 * Math.Abs(area1);

				total_error = errsum + truncation_error;

				if (total_error < epsabs && iteration > 4)
				{
					goto compute_result;
				}

				if (error1 > correc)
				{
					correc = error1;
				}

				if (null != status)
				{
					eps = Math.Max(initial_eps, correc * (1.0 - p));
				}

				if (null != status && total_error < 10 * correc && iteration > 3)
				{
					goto compute_result;
				}

				table.append_table(area);

				if (table.n < 2)
				{
					continue;
				}

				table.qelg(out reseps, out erreps);

				ktmin++;

				if (ktmin >= 15 && err_ext < 0.001 * total_error)
				{
					error_type = 4;
				}

				if (erreps < err_ext)
				{
					ktmin = 0;
					err_ext = erreps;
					res_ext = reseps;

					if (err_ext + 10 * correc <= epsabs)
						break;
					if (err_ext <= epsabs && 10 * correc >= epsabs)
						break;
				}
			}

			if (iteration == limit)
				error_type = 1;

			if (err_ext == GSL_CONST.GSL_DBL_MAX)
				goto compute_result;

			err_ext = err_ext + 10 * correc;

			result = res_ext;
			abserr = err_ext;

			if (error_type == 0)
			{
				return null; // GSL_SUCCESS;
			}

			if (res_ext != 0.0 && area != 0.0)
			{
				if (err_ext / Math.Abs(res_ext) > errsum / Math.Abs(area))
					goto compute_result;
			}
			else if (err_ext > errsum)
			{
				goto compute_result;
			}
			else if (area == 0.0)
			{
				goto return_error;
			}

			if (error_type == 4)
			{
				err_ext = err_ext + truncation_error;
			}

			goto return_error;

		compute_result:

			result = area;
			abserr = total_error;

		return_error:

			if (error_type > 2)
				error_type--;

			if (error_type == 0)
			{
				return null; // GSL_SUCCESS;
			}
			else if (error_type == 1)
			{
				return new GSL_ERROR("number of iterations was insufficient", GSL_ERR.GSL_EMAXITER, bDebug);
			}
			else if (error_type == 2)
			{
				return new GSL_ERROR("cannot reach tolerance because of roundoff error",
									 GSL_ERR.GSL_EROUND, bDebug);
			}
			else if (error_type == 3)
			{
				return new GSL_ERROR("bad integrand behavior found in the integration interval",
									 GSL_ERR.GSL_ESING, bDebug);
			}
			else if (error_type == 4)
			{
				return new GSL_ERROR("roundoff error detected in the extrapolation table",
									 GSL_ERR.GSL_EROUND, bDebug);
			}
			else if (error_type == 5)
			{
				return new GSL_ERROR("integral is divergent, or slowly convergent",
									 GSL_ERR.GSL_EDIVERGE, bDebug);
			}
			else
			{
				return new GSL_ERROR("could not integrate function", GSL_ERR.GSL_EFAILED, bDebug);
			}
		}
Пример #6
0
        gsl_integration_qawf(Func <double, double> f,
                             double a,
                             double epsabs,
                             int limit,
                             gsl_integration_workspace workspace,
                             gsl_integration_workspace cycle_workspace,
                             gsl_integration_qawo_table wf,
                             out double result, out double abserr,
                             bool bDebug)
        {
            double area, errsum;
            double res_ext, err_ext;
            double correc, total_error = 0.0, truncation_error = 0;

            int ktmin     = 0;
            int iteration = 0;

            var table = new extrapolation_table();

            double cycle;
            double omega = wf.omega;

            double p = 0.9;
            double factor = 1;
            double initial_eps, eps;
            int    error_type = 0;

            /* Initialize results */

            workspace.initialise(a, a);

            result = 0;
            abserr = 0;

            if (limit > workspace.limit)
            {
                return(new GSL_ERROR("iteration limit exceeds available workspace", GSL_ERR.GSL_EINVAL, bDebug));
            }

            /* Test on accuracy */

            if (epsabs <= 0)
            {
                return(new GSL_ERROR("absolute tolerance epsabs must be positive", GSL_ERR.GSL_EBADTOL, bDebug));
            }

            if (omega == 0.0)
            {
                if (wf.sine == gsl_integration_qawo_enum.GSL_INTEG_SINE)
                {
                    /* The function sin(w x) f(x) is always zero for w = 0 */

                    result = 0;
                    abserr = 0;

                    return(null); // GSL_SUCCESS;
                }
                else
                {
                    /* The function cos(w x) f(x) is always f(x) for w = 0 */

                    GSL_ERROR status = QagiuIntegration.gsl_integration_qagiu(f, a, epsabs, 0.0,
                                                                              cycle_workspace.limit,
                                                                              cycle_workspace,
                                                                              out result, out abserr,
                                                                              QagiuIntegration.DefaultIntegrationRule, QagiuIntegration.DefaultDebugFlag);
                    return(status);
                }
            }

            if (epsabs > GSL_CONST.GSL_DBL_MIN / (1 - p))
            {
                eps = epsabs * (1 - p);
            }
            else
            {
                eps = epsabs;
            }

            initial_eps = eps;

            area   = 0;
            errsum = 0;

            res_ext = 0;
            err_ext = GSL_CONST.GSL_DBL_MAX;
            correc  = 0;

            cycle = (2 * Math.Floor(Math.Abs(omega)) + 1) * Math.PI / Math.Abs(omega);

            wf.set_length(cycle);

            table.initialise_table();

            for (iteration = 0; iteration < limit; iteration++)
            {
                double a1 = a + iteration * cycle;
                double b1 = a1 + cycle;

                double epsabs1 = eps * factor;

                GSL_ERROR status = gsl_integration_qawo(f, a1, epsabs1, 0.0, limit,
                                                        cycle_workspace, wf,
                                                        out var area1, out var error1, false);

                workspace.append_interval(a1, b1, area1, error1);

                factor *= p;

                area   = area + area1;
                errsum = errsum + error1;

                /* estimate the truncation error as 50 times the final term */

                truncation_error = 50 * Math.Abs(area1);

                total_error = errsum + truncation_error;

                if (total_error < epsabs && iteration > 4)
                {
                    goto compute_result;
                }

                if (error1 > correc)
                {
                    correc = error1;
                }

                if (null != status)
                {
                    eps = Math.Max(initial_eps, correc * (1.0 - p));
                }

                if (null != status && total_error < 10 * correc && iteration > 3)
                {
                    goto compute_result;
                }

                table.append_table(area);

                if (table.n < 2)
                {
                    continue;
                }

                table.qelg(out var reseps, out var erreps);

                ktmin++;

                if (ktmin >= 15 && err_ext < 0.001 * total_error)
                {
                    error_type = 4;
                }

                if (erreps < err_ext)
                {
                    ktmin   = 0;
                    err_ext = erreps;
                    res_ext = reseps;

                    if (err_ext + 10 * correc <= epsabs)
                    {
                        break;
                    }
                    if (err_ext <= epsabs && 10 * correc >= epsabs)
                    {
                        break;
                    }
                }
            }

            if (iteration == limit)
            {
                error_type = 1;
            }

            if (err_ext == GSL_CONST.GSL_DBL_MAX)
            {
                goto compute_result;
            }

            err_ext = err_ext + 10 * correc;

            result = res_ext;
            abserr = err_ext;

            if (error_type == 0)
            {
                return(null); // GSL_SUCCESS;
            }

            if (res_ext != 0.0 && area != 0.0)
            {
                if (err_ext / Math.Abs(res_ext) > errsum / Math.Abs(area))
                {
                    goto compute_result;
                }
            }
            else if (err_ext > errsum)
            {
                goto compute_result;
            }
            else if (area == 0.0)
            {
                goto return_error;
            }

            if (error_type == 4)
            {
                err_ext = err_ext + truncation_error;
            }

            goto return_error;

compute_result:

            result = area;
            abserr = total_error;

return_error:

            if (error_type > 2)
            {
                error_type--;
            }

            if (error_type == 0)
            {
                return(null); // GSL_SUCCESS;
            }
            else if (error_type == 1)
            {
                return(new GSL_ERROR("number of iterations was insufficient", GSL_ERR.GSL_EMAXITER, bDebug));
            }
            else if (error_type == 2)
            {
                return(new GSL_ERROR("cannot reach tolerance because of roundoff error",
                                     GSL_ERR.GSL_EROUND, bDebug));
            }
            else if (error_type == 3)
            {
                return(new GSL_ERROR("bad integrand behavior found in the integration interval",
                                     GSL_ERR.GSL_ESING, bDebug));
            }
            else if (error_type == 4)
            {
                return(new GSL_ERROR("roundoff error detected in the extrapolation table",
                                     GSL_ERR.GSL_EROUND, bDebug));
            }
            else if (error_type == 5)
            {
                return(new GSL_ERROR("integral is divergent, or slowly convergent",
                                     GSL_ERR.GSL_EDIVERGE, bDebug));
            }
            else
            {
                return(new GSL_ERROR("could not integrate function", GSL_ERR.GSL_EFAILED, bDebug));
            }
        }
Пример #7
0
        qc25f(Func <double, double> f, double a, double b,
              gsl_integration_qawo_table wf, int level,
              out double result, out double abserr, out double resabs, out double resasc)
        {
            double center      = 0.5 * (a + b);
            double half_length = 0.5 * (b - a);
            double omega       = wf.omega;

            double par = omega * half_length;

            if (Math.Abs(par) < 2)
            {
                Func <double, double> weighted_function;
                fn_fourier_params     fn_params;

                fn_params.function = f;
                fn_params.omega    = omega;

                if (wf.sine == gsl_integration_qawo_enum.GSL_INTEG_SINE)
                {
                    weighted_function = delegate(double t)
                    { return(fn_sin(t, fn_params)); };
                }
                else
                {
                    weighted_function = delegate(double t)
                    { return(fn_cos(t, fn_params)); };
                }

                QK15.Integration(weighted_function, a, b, out result, out abserr,
                                 out resabs, out resasc);

                return;
            }
            else
            {
                int      momentix;
                double[] cheb12 = new double[13];
                double[] cheb24 = new double[25];
                double   result_abs, res12_cos, res12_sin, res24_cos, res24_sin;
                double   est_cos, est_sin;
                double   c, s;
                int      i;

                Qcheb.Approximation(f, a, b, cheb12, cheb24);

                if (level >= wf.n)
                {
                    /* table overflow should not happen, check before calling */
                    new GSL_ERROR("table overflow in internal function", GSL_ERR.GSL_ESANITY, true);
                    throw new ArithmeticException("table overflow in internal function"); //
                }

                /* obtain moments from the table */

                momentix = 25 * level;

                res12_cos = cheb12[12] * wf.chebmo[momentix + 12];
                res12_sin = 0;

                for (i = 0; i < 6; i++)
                {
                    int k = 10 - 2 * i;
                    res12_cos += cheb12[k] * wf.chebmo[momentix + k];
                    res12_sin += cheb12[k + 1] * wf.chebmo[momentix + k + 1];
                }

                res24_cos = cheb24[24] * wf.chebmo[momentix + 24];
                res24_sin = 0;

                result_abs = Math.Abs(cheb24[24]);

                for (i = 0; i < 12; i++)
                {
                    int k = 22 - 2 * i;
                    res24_cos  += cheb24[k] * wf.chebmo[momentix + k];
                    res24_sin  += cheb24[k + 1] * wf.chebmo[momentix + k + 1];
                    result_abs += Math.Abs(cheb24[k]) + Math.Abs(cheb24[k + 1]);
                }

                est_cos = Math.Abs(res24_cos - res12_cos);
                est_sin = Math.Abs(res24_sin - res12_sin);

                c = half_length * Math.Cos(center * omega);
                s = half_length * Math.Sin(center * omega);

                if (wf.sine == gsl_integration_qawo_enum.GSL_INTEG_SINE)
                {
                    result = c * res24_sin + s * res24_cos;
                    abserr = Math.Abs(c * est_sin) + Math.Abs(s * est_cos);
                }
                else
                {
                    result = c * res24_cos - s * res24_sin;
                    abserr = Math.Abs(c * est_cos) + Math.Abs(s * est_sin);
                }

                resabs = result_abs * half_length;
                resasc = GSL_CONST.GSL_DBL_MAX;

                return;
            }
        }
Пример #8
0
        gsl_integration_qawo(Func <double, double> f,
                             double a,
                             double epsabs, double epsrel,
                             int limit,
                             gsl_integration_workspace workspace,
                             gsl_integration_qawo_table wf,
                             out double result, out double abserr,
                             bool bDebug)
        {
            double area, errsum;
            double res_ext, err_ext;
            double tolerance;

            double ertest = 0;
            double error_over_large_intervals = 0;
            double reseps = 0, abseps = 0, correc = 0;
            int    ktmin = 0;
            int    roundoff_type1 = 0, roundoff_type2 = 0, roundoff_type3 = 0;
            int    error_type           = 0;
            bool   error_type2          = false;

            int iteration               = 0;

            bool positive_integrand = false;
            bool extrapolate            = false;
            bool extall                 = false;
            bool disallow_extrapolation = false;

            var table = new extrapolation_table();

            double b         = a + wf.L;
            double abs_omega = Math.Abs(wf.omega);

            /* Initialize results */

            workspace.initialise(a, b);

            result = 0;
            abserr = 0;

            if (limit > workspace.limit)
            {
                return(new GSL_ERROR("iteration limit exceeds available workspace", GSL_ERR.GSL_EINVAL, bDebug));
            }

            /* Test on accuracy */

            if (epsabs <= 0 && (epsrel < 50 * GSL_CONST.GSL_DBL_EPSILON || epsrel < 0.5e-28))
            {
                return(new GSL_ERROR("tolerance cannot be acheived with given epsabs and epsrel",
                                     GSL_ERR.GSL_EBADTOL, bDebug));
            }

            /* Perform the first integration */

            qc25f(f, a, b, wf, 0, out var result0, out var abserr0, out var resabs0, out var resasc0);

            workspace.set_initial_result(result0, abserr0);

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

            if (abserr0 <= 100 * GSL_CONST.GSL_DBL_EPSILON * resabs0 && abserr0 > tolerance)
            {
                result = result0;
                abserr = abserr0;

                return(new GSL_ERROR("cannot reach tolerance because of roundoff error on first attempt", GSL_ERR.GSL_EROUND, bDebug));
            }
            else if ((abserr0 <= tolerance && abserr0 != resasc0) || abserr0 == 0.0)
            {
                result = result0;
                abserr = abserr0;

                return(null); // GSL_SUCCESS;
            }
            else if (limit == 1)
            {
                result = result0;
                abserr = abserr0;

                return(new GSL_ERROR("a maximum of one iteration was insufficient", GSL_ERR.GSL_EMAXITER, bDebug));
            }

            /* Initialization */

            table.initialise_table();

            if (0.5 * abs_omega * Math.Abs(b - a) <= 2)
            {
                table.append_table(result0);
                extall = true;
            }

            area   = result0;
            errsum = abserr0;

            res_ext = result0;
            err_ext = GSL_CONST.GSL_DBL_MAX;

            positive_integrand = test_positivity(result0, resabs0);

            iteration = 1;

            do
            {
                int    current_level;
                double a1, b1, a2, b2;
                double area12  = 0;
                double error12 = 0;
                double last_e_i;

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

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

                current_level = workspace.level[workspace.i] + 1;

                if (current_level >= wf.n)
                {
                    error_type = -1; /* exceeded limit of table */
                    break;
                }

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

                iteration++;

                qc25f(f, a1, b1, wf, current_level, out var area1, out var error1, out var resabs1, out var resasc1);
                qc25f(f, a2, b2, wf, current_level, out var area2, out var error2, out var resabs2, out var resasc2);

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

                /* Improve previous approximations to the integral and test for
                 *                               accuracy.
                 *
                 *                               We write these expressions in the same way as the original
                 *                               QUADPACK code so that the rounding errors are the same, which
                 *                               makes testing easier. */

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

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

                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)
                    {
                        if (!extrapolate)
                        {
                            roundoff_type1++;
                        }
                        else
                        {
                            roundoff_type2++;
                        }
                    }
                    if (iteration > 10 && error12 > e_i)
                    {
                        roundoff_type3++;
                    }
                }

                /* Test for roundoff and eventually set error flag */

                if (roundoff_type1 + roundoff_type2 >= 10 || roundoff_type3 >= 20)
                {
                    error_type = 2; /* round off error */
                }

                if (roundoff_type2 >= 5)
                {
                    error_type2 = true;
                }

                /* 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 = 4;
                }

                /* append the newly-created intervals to the list */

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

                if (errsum <= tolerance)
                {
                    goto compute_result;
                }

                if (0 != error_type)
                {
                    break;
                }

                if (iteration >= limit - 1)
                {
                    error_type = 1;
                    break;
                }

                /* set up variables on first iteration */

                if (iteration == 2 && extall)
                {
                    error_over_large_intervals = errsum;
                    ertest = tolerance;
                    table.append_table(area);
                    continue;
                }

                if (disallow_extrapolation)
                {
                    continue;
                }

                if (extall)
                {
                    error_over_large_intervals += -last_e_i;

                    if (current_level < workspace.maximum_level)
                    {
                        error_over_large_intervals += error12;
                    }

                    if (extrapolate)
                    {
                        goto label70;
                    }
                }

                if (workspace.large_interval())
                {
                    continue;
                }

                if (extall)
                {
                    extrapolate     = true;
                    workspace.nrmax = 1;
                }
                else
                {
                    /* test whether the interval to be bisected next is the
                     *                                     smallest interval. */
                    int    i     = workspace.i;
                    double width = workspace.blist[i] - workspace.alist[i];

                    if (0.25 * Math.Abs(width) * abs_omega > 2)
                    {
                        continue;
                    }

                    extall = true;
                    error_over_large_intervals = errsum;
                    ertest = tolerance;
                    continue;
                }

label70:
                if (!error_type2 && error_over_large_intervals > ertest)
                {
                    if (workspace.increase_nrmax())
                    {
                        continue;
                    }
                }

                /* Perform extrapolation */

                table.append_table(area);

                if (table.n < 3)
                {
                    workspace.reset_nrmax();
                    extrapolate = false;
                    error_over_large_intervals = errsum;
                    continue;
                }

                table.qelg(out reseps, out abseps);

                ktmin++;

                if (ktmin > 5 && err_ext < 0.001 * errsum)
                {
                    error_type = 5;
                }

                if (abseps < err_ext)
                {
                    ktmin   = 0;
                    err_ext = abseps;
                    res_ext = reseps;
                    correc  = error_over_large_intervals;
                    ertest  = Math.Max(epsabs, epsrel * Math.Abs(reseps));
                    if (err_ext <= ertest)
                    {
                        break;
                    }
                }

                /* Prepare bisection of the smallest interval. */

                if (table.n == 1)
                {
                    disallow_extrapolation = true;
                }

                if (error_type == 5)
                {
                    break;
                }

                /* work on interval with largest error */

                workspace.reset_nrmax();
                extrapolate = false;
                error_over_large_intervals = errsum;
            }while (iteration < limit);

            result = res_ext;
            abserr = err_ext;

            if (err_ext == GSL_CONST.GSL_DBL_MAX)
            {
                goto compute_result;
            }

            if (0 != error_type || error_type2)
            {
                if (error_type2)
                {
                    err_ext += correc;
                }

                if (error_type == 0)
                {
                    error_type = 3;
                }

                if (result != 0 && area != 0)
                {
                    if (err_ext / Math.Abs(res_ext) > errsum / Math.Abs(area))
                    {
                        goto compute_result;
                    }
                }
                else if (err_ext > errsum)
                {
                    goto compute_result;
                }
                else if (area == 0.0)
                {
                    goto return_error;
                }
            }

            /*  Test on divergence. */

            {
                double max_area = Math.Max(Math.Abs(res_ext), Math.Abs(area));

                if (!positive_integrand && max_area < 0.01 * resabs0)
                {
                    goto return_error;
                }
            }

            {
                double ratio = res_ext / area;

                if (ratio < 0.01 || ratio > 100 || errsum > Math.Abs(area))
                {
                    error_type = 6;
                }
            }

            goto return_error;

compute_result:

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

return_error:

            if (error_type > 2)
            {
                error_type--;
            }

            if (error_type == 0)
            {
                return(null); // GSL_SUCCESS;
            }
            else if (error_type == 1)
            {
                return(new GSL_ERROR("number of iterations was insufficient", GSL_ERR.GSL_EMAXITER, bDebug));
            }
            else if (error_type == 2)
            {
                return(new GSL_ERROR("cannot reach tolerance because of roundoff error",
                                     GSL_ERR.GSL_EROUND, bDebug));
            }
            else if (error_type == 3)
            {
                return(new GSL_ERROR("bad integrand behavior found in the integration interval",
                                     GSL_ERR.GSL_ESING, bDebug));
            }
            else if (error_type == 4)
            {
                return(new GSL_ERROR("roundoff error detected in extrapolation table", GSL_ERR.GSL_EROUND, bDebug));
            }
            else if (error_type == 5)
            {
                return(new GSL_ERROR("integral is divergent, or slowly convergent", GSL_ERR.GSL_EDIVERGE, bDebug));
            }
            else if (error_type == -1)
            {
                return(new GSL_ERROR("exceeded limit of trigonometric table", GSL_ERR.GSL_ETABLE, bDebug));
            }
            else
            {
                return(new GSL_ERROR("could not integrate function", GSL_ERR.GSL_EFAILED, bDebug));
            }
        }