Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-02 08:48:22

0001 #ifndef GAUSS_KRONROD_ADAPTIVE_H
0002 #define GAUSS_KRONROD_ADAPTIVE_H
0003 
0004 /**
0005  * @file GaussKronrodAdaptive.h
0006  * @author Bryan BERTHOU (SPhN / CEA Saclay)
0007  * @date 27 January 2016
0008  * @version 1.0
0009  */
0010 
0011 #include <cmath>
0012 #include <iostream>
0013 #include <limits>
0014 #include <vector>
0015 #include <stddef.h>
0016 #include <stdlib.h>
0017 
0018 #include "../../../functor/one_dimension/FunctionType1D.h"
0019 //#include "../../../utils/Errors.h"
0020 //#include "../../../utils/Tolerances.h"
0021 #include "../Integrator1D.h"
0022 
0023 #define GSL_DBL_EPSILON        2.2204460492503131e-16
0024 #define GSL_DBL_MIN        2.2250738585072014e-308
0025 #define GSL_DBL_MAX        1.7976931348623157e+308
0026 
0027 #define GSL_ERROR(reason, gsl_errno) \
0028        do { \
0029        gsl_error (reason, __FILE__, __LINE__, gsl_errno) ; \
0030        return gsl_errno ; \
0031        } while (0)
0032 
0033 #define GSL_ERROR_VAL(reason, gsl_errno, value) \
0034        do { \
0035        gsl_error (reason, __FILE__, __LINE__, gsl_errno) ; \
0036        return value ; \
0037        } while (0)
0038 
0039 namespace NumA {
0040 
0041 /**
0042  * @class GaussKronrodAdaptive
0043  *
0044  * @brief
0045  */
0046 
0047 class GaussKronrodAdaptive: public Integrator1D {
0048 public:
0049     void gsl_error(const char * reason, const char * file, int line,
0050             int gsl_errno) {
0051         std::cerr << "GSL_ERROR = " << gsl_errno << std::endl;
0052     }
0053 
0054     enum {
0055         GSL_SUCCESS = 0, GSL_FAILURE = -1, GSL_CONTINUE = -2, /* iteration has not converged */
0056         GSL_EDOM = 1, /* input domain error, e.g sqrt(-1) */
0057         GSL_ERANGE = 2, /* output range error, e.g. exp(1e100) */
0058         GSL_EFAULT = 3, /* invalid pointer */
0059         GSL_EINVAL = 4, /* invalid argument supplied by user */
0060         GSL_EFAILED = 5, /* generic failure */
0061         GSL_EFACTOR = 6, /* factorization failed */
0062         GSL_ESANITY = 7, /* sanity check failed - shouldn't happen */
0063         GSL_ENOMEM = 8, /* malloc failed */
0064         GSL_EBADFUNC = 9, /* problem with user-supplied function */
0065         GSL_ERUNAWAY = 10, /* iterative process is out of control */
0066         GSL_EMAXITER = 11, /* exceeded max number of iterations */
0067         GSL_EZERODIV = 12, /* tried to divide by zero */
0068         GSL_EBADTOL = 13, /* user specified an invalid tolerance */
0069         GSL_ETOL = 14, /* failed to reach the specified tolerance */
0070         GSL_EUNDRFLW = 15, /* underflow */
0071         GSL_EOVRFLW = 16, /* overflow  */
0072         GSL_ELOSS = 17, /* loss of accuracy */
0073         GSL_EROUND = 18, /* failed because of roundoff error */
0074         GSL_EBADLEN = 19, /* matrix, vector lengths are not conformant */
0075         GSL_ENOTSQR = 20, /* matrix not square */
0076         GSL_ESING = 21, /* apparent singularity detected */
0077         GSL_EDIVERGE = 22, /* integral or series is divergent */
0078         GSL_EUNSUP = 23, /* requested feature is not supported by the hardware */
0079         GSL_EUNIMPL = 24, /* requested feature not (yet) implemented */
0080         GSL_ECACHE = 25, /* cache limit exceeded */
0081         GSL_ETABLE = 26, /* table limit exceeded */
0082         GSL_ENOPROG = 27, /* iteration is not making progress towards solution */
0083         GSL_ENOPROGJ = 28, /* jacobian evaluations are not improving the solution */
0084         GSL_ETOLF = 29, /* cannot reach the specified tolerance in F */
0085         GSL_ETOLX = 30, /* cannot reach the specified tolerance in X */
0086         GSL_ETOLG = 31, /* cannot reach the specified tolerance in gradient */
0087         GSL_EOF = 32 /* end of file */
0088     };
0089 
0090     GaussKronrodAdaptive() :
0091             Integrator1D() {
0092 
0093     }
0094 
0095     virtual ~GaussKronrodAdaptive() {
0096 
0097     }
0098 
0099     virtual void configure() {
0100 
0101     }
0102 
0103     typedef struct {
0104         size_t limit;
0105         size_t size;
0106         size_t nrmax;
0107         size_t i;
0108         size_t maximum_level;
0109         double *alist;
0110         double *blist;
0111         double *rlist;
0112         double *elist;
0113         size_t *order;
0114         size_t *level;
0115     } gsl_integration_workspace;
0116 
0117     struct extrapolation_table {
0118         size_t n;
0119         double rlist2[52];
0120         size_t nres;
0121         double res3la[3];
0122     };
0123 
0124     inline double integrate(FunctionType1D* pFunction, double a, double b,
0125             std::vector<double> &parameters) {
0126         double result = 0.;
0127         const size_t limit = 1000;
0128 
0129         gsl_integration_workspace * workspace = gsl_integration_workspace_alloc(
0130                 limit);
0131 
0132         compute(pFunction, a, b, parameters, result, workspace, limit);
0133 
0134         gsl_integration_workspace_free(workspace);
0135 
0136         return result;
0137     }
0138 
0139     inline int compute(FunctionType1D* pFunction, const double a,
0140             const double b, std::vector<double> &parameters, double &result,
0141             gsl_integration_workspace * workspace, const double limit) {
0142 
0143         double epsabs = m_tolerances.getAbsoluteTolerance();
0144         double epsrel = m_tolerances.getRelativeTolerance();
0145 
0146         //TODO when use those calls results are differents !!!
0147 //        double epsabs = m_tolerances.getAbsoluteTolerance();
0148 //        double epsrel = m_tolerances.getRelativeTolerance();
0149 
0150 // ##### ROOT MathMore section #####
0151         if (epsabs <= 0.) {
0152             // from static variable in ROOT::GSLIntegrator
0153             epsabs = 1e-06;
0154         }
0155         if (epsrel <= 0.) {
0156             // from static variable in ROOT::GSLIntegrator
0157             epsrel = 1e-09;
0158         }
0159         // ##################################
0160 
0161         double area, errsum;
0162         double res_ext, err_ext;
0163         double result0, abserr0, resabs0, resasc0;
0164         double tolerance;
0165 
0166         double ertest = 0;
0167         double error_over_large_intervals = 0;
0168         double reseps = 0, abseps = 0, correc = 0;
0169         size_t ktmin = 0;
0170         int roundoff_type1 = 0, roundoff_type2 = 0, roundoff_type3 = 0;
0171         int error_type = 0, error_type2 = 0;
0172 
0173         size_t iteration = 0;
0174 
0175         int positive_integrand = 0;
0176         int extrapolate = 0;
0177         int disallow_extrapolation = 0;
0178 
0179         struct extrapolation_table table;
0180 
0181         /* Initialize results */
0182 
0183         initialise(workspace, a, b);
0184 
0185         result = 0;
0186         double abserr = 0;
0187 
0188         if (limit > workspace->limit) {
0189             GSL_ERROR ("iteration limit exceeds available workspace", GSL_EINVAL)
0190             ;
0191         }
0192 
0193         /* Test on accuracy */
0194 
0195         if (epsabs <= 0
0196                 && (epsrel < 50 * GSL_DBL_EPSILON || epsrel < 0.5e-28)) {
0197             GSL_ERROR(
0198                     "tolerance cannot be acheived with given epsabs and epsrel",
0199                     GSL_EBADTOL);
0200         }
0201 
0202         /* Perform the first integration */
0203 
0204         gsl_integration_21qk(pFunction, a, b, result0, abserr0, resabs0,
0205                 resasc0, parameters);
0206 
0207         set_initial_result(workspace, result0, abserr0);
0208 
0209         tolerance = GSL_MAX_DBL(epsabs, epsrel * fabs(result0));
0210 
0211         if (abserr0 <= 100 * GSL_DBL_EPSILON * resabs0 && abserr0 > tolerance) {
0212             result = result0;
0213             abserr = abserr0;
0214             m_errors.setAbsolute(abserr);
0215 
0216             GSL_ERROR("cannot reach tolerance because of roundoff error"
0217                     "on first attempt", GSL_EROUND);
0218         } else if ((abserr0 <= tolerance && abserr0 != resasc0)
0219                 || abserr0 == 0.0) {
0220             result = result0;
0221             abserr = abserr0;
0222             m_errors.setAbsolute(abserr);
0223 
0224             return GSL_SUCCESS;
0225         } else if (limit == 1) {
0226             result = result0;
0227             abserr = abserr0;
0228             m_errors.setAbsolute(abserr);
0229 
0230             GSL_ERROR("a maximum of one iteration was insufficient",
0231                     GSL_EMAXITER);
0232         }
0233 
0234         /* Initialization */
0235 
0236         initialise_table(&table);
0237         append_table(&table, result0);
0238 
0239         area = result0;
0240         errsum = abserr0;
0241 
0242         res_ext = result0;
0243         err_ext = GSL_DBL_MAX;
0244 
0245         positive_integrand = test_positivity(result0, resabs0);
0246 
0247         iteration = 1;
0248 
0249         do {
0250             size_t current_level;
0251             double a1, b1, a2, b2;
0252             double a_i, b_i, r_i, e_i;
0253             double area1 = 0, area2 = 0, area12 = 0;
0254             double error1 = 0, error2 = 0, error12 = 0;
0255             double resasc1, resasc2;
0256             double resabs1, resabs2;
0257             double last_e_i;
0258 
0259             /* Bisect the subinterval with the largest error estimate */
0260 
0261             retrieve(workspace, &a_i, &b_i, &r_i, &e_i);
0262 
0263             current_level = workspace->level[workspace->i] + 1;
0264 
0265             a1 = a_i;
0266             b1 = 0.5 * (a_i + b_i);
0267             a2 = b1;
0268             b2 = b_i;
0269 
0270             iteration++;
0271 
0272             gsl_integration_21qk(pFunction, a1, b1, area1, error1, resabs1,
0273                     resasc1, parameters);
0274             gsl_integration_21qk(pFunction, a2, b2, area2, error2, resabs2,
0275                     resasc2, parameters);
0276 
0277             area12 = area1 + area2;
0278             error12 = error1 + error2;
0279             last_e_i = e_i;
0280 
0281             /* Improve previous approximations to the integral and test for
0282              accuracy.
0283 
0284              We write these expressions in the same way as the original
0285              QUADPACK code so that the rounding errors are the same, which
0286              makes testing easier. */
0287 
0288             errsum = errsum + error12 - e_i;
0289             area = area + area12 - r_i;
0290 
0291             tolerance = GSL_MAX_DBL(epsabs, epsrel * fabs(area));
0292 
0293             if (resasc1 != error1 && resasc2 != error2) {
0294                 double delta = r_i - area12;
0295 
0296                 if (fabs(delta) <= 1.0e-5 * fabs(area12)
0297                         && error12 >= 0.99 * e_i) {
0298                     if (!extrapolate) {
0299                         roundoff_type1++;
0300                     } else {
0301                         roundoff_type2++;
0302                     }
0303                 }
0304                 if (iteration > 10 && error12 > e_i) {
0305                     roundoff_type3++;
0306                 }
0307             }
0308 
0309             /* Test for roundoff and eventually set error flag */
0310 
0311             if (roundoff_type1 + roundoff_type2 >= 10 || roundoff_type3 >= 20) {
0312                 error_type = 2; /* round off error */
0313             }
0314 
0315             if (roundoff_type2 >= 5) {
0316                 error_type2 = 1;
0317             }
0318 
0319             /* set error flag in the case of bad integrand behaviour at
0320              a point of the integration range */
0321 
0322             if (subinterval_too_small(a1, a2, b2)) {
0323                 error_type = 4;
0324             }
0325 
0326             /* append the newly-created intervals to the list */
0327 
0328             update(workspace, a1, b1, area1, error1, a2, b2, area2, error2);
0329 
0330             if (errsum <= tolerance) {
0331                 goto compute_result;
0332             }
0333 
0334             if (error_type) {
0335                 break;
0336             }
0337 
0338             if (iteration >= limit - 1) {
0339                 error_type = 1;
0340                 break;
0341             }
0342 
0343             if (iteration == 2) /* set up variables on first iteration */
0344             {
0345                 error_over_large_intervals = errsum;
0346                 ertest = tolerance;
0347                 append_table(&table, area);
0348                 continue;
0349             }
0350 
0351             if (disallow_extrapolation) {
0352                 continue;
0353             }
0354 
0355             error_over_large_intervals += -last_e_i;
0356 
0357             if (current_level < workspace->maximum_level) {
0358                 error_over_large_intervals += error12;
0359             }
0360 
0361             if (!extrapolate) {
0362                 /* test whether the interval to be bisected next is the
0363                  smallest interval. */
0364 
0365                 if (large_interval(workspace))
0366                     continue;
0367 
0368                 extrapolate = 1;
0369                 workspace->nrmax = 1;
0370             }
0371 
0372             if (!error_type2 && error_over_large_intervals > ertest) {
0373                 if (increase_nrmax(workspace))
0374                     continue;
0375             }
0376 
0377             /* Perform extrapolation */
0378 
0379             append_table(&table, area);
0380 
0381             qelg(&table, reseps, abseps);
0382 
0383             ktmin++;
0384 
0385             if (ktmin > 5 && err_ext < 0.001 * errsum) {
0386                 error_type = 5;
0387             }
0388 
0389             if (abseps < err_ext) {
0390                 ktmin = 0;
0391                 err_ext = abseps;
0392                 res_ext = reseps;
0393                 correc = error_over_large_intervals;
0394                 ertest = GSL_MAX_DBL(epsabs, epsrel * fabs(reseps));
0395                 if (err_ext <= ertest)
0396                     break;
0397             }
0398 
0399             /* Prepare bisection of the smallest interval. */
0400 
0401             if (table.n == 1) {
0402                 disallow_extrapolation = 1;
0403             }
0404 
0405             if (error_type == 5) {
0406                 break;
0407             }
0408 
0409             /* work on interval with largest error */
0410 
0411             reset_nrmax(workspace);
0412             extrapolate = 0;
0413             error_over_large_intervals = errsum;
0414 
0415         } while (iteration < limit);
0416 
0417         result = res_ext;
0418         abserr = err_ext;
0419         m_errors.setAbsolute(abserr);
0420 
0421         if (err_ext == GSL_DBL_MAX)
0422             goto compute_result;
0423 
0424         if (error_type || error_type2) {
0425             if (error_type2) {
0426                 err_ext += correc;
0427             }
0428 
0429             if (error_type == 0)
0430                 error_type = 3;
0431 
0432             if (res_ext != 0.0 && area != 0.0) {
0433                 if (err_ext / fabs(res_ext) > errsum / fabs(area))
0434                     goto compute_result;
0435             } else if (err_ext > errsum) {
0436                 goto compute_result;
0437             } else if (area == 0.0) {
0438                 goto return_error;
0439             }
0440         }
0441 
0442         /*  Test on divergence. */
0443 
0444         {
0445             double max_area = GSL_MAX_DBL(fabs(res_ext), fabs(area));
0446 
0447             if (!positive_integrand && max_area < 0.01 * resabs0)
0448                 goto return_error;
0449         }
0450 
0451         {
0452             double ratio = res_ext / area;
0453 
0454             if (ratio < 0.01 || ratio > 100.0 || errsum > fabs(area))
0455                 error_type = 6;
0456         }
0457 
0458         goto return_error;
0459 
0460         compute_result:
0461 
0462         result = sum_results(workspace);
0463         abserr = errsum;
0464         m_errors.setAbsolute(abserr);
0465 
0466         return_error:
0467 
0468         if (error_type > 2)
0469             error_type--;
0470 
0471         if (error_type == 0) {
0472             return GSL_SUCCESS;
0473         } else if (error_type == 1) {
0474             GSL_ERROR("number of iterations was insufficient", GSL_EMAXITER);
0475         } else if (error_type == 2) {
0476             GSL_ERROR("cannot reach tolerance because of roundoff error",
0477                     GSL_EROUND);
0478         } else if (error_type == 3) {
0479             GSL_ERROR(
0480                     "bad integrand behavior found in the integration interval",
0481                     GSL_ESING);
0482         } else if (error_type == 4) {
0483             GSL_ERROR("roundoff error detected in the extrapolation table",
0484                     GSL_EROUND);
0485         } else if (error_type == 5) {
0486             GSL_ERROR("integral is divergent, or slowly convergent",
0487                     GSL_EDIVERGE);
0488         } else {
0489             GSL_ERROR("could not integrate function", GSL_EFAILED);
0490         }
0491     }
0492 
0493     gsl_integration_workspace *
0494     gsl_integration_workspace_alloc(const size_t n) {
0495         gsl_integration_workspace * w;
0496 
0497         if (n == 0) {
0498             GSL_ERROR_VAL("workspace length n must be positive integer",
0499                     GSL_EDOM, 0);
0500         }
0501 
0502         w = (gsl_integration_workspace *) malloc(
0503                 sizeof(gsl_integration_workspace));
0504 
0505         if (w == 0) {
0506             GSL_ERROR_VAL("failed to allocate space for workspace struct",
0507                     GSL_ENOMEM, 0);
0508         }
0509 
0510         w->alist = (double *) malloc(n * sizeof(double));
0511 
0512         if (w->alist == 0) {
0513             free(w); /* exception in constructor, avoid memory leak */
0514 
0515             GSL_ERROR_VAL("failed to allocate space for alist ranges",
0516                     GSL_ENOMEM, 0);
0517         }
0518 
0519         w->blist = (double *) malloc(n * sizeof(double));
0520 
0521         if (w->blist == 0) {
0522             free(w->alist);
0523             free(w); /* exception in constructor, avoid memory leak */
0524 
0525             GSL_ERROR_VAL("failed to allocate space for blist ranges",
0526                     GSL_ENOMEM, 0);
0527         }
0528 
0529         w->rlist = (double *) malloc(n * sizeof(double));
0530 
0531         if (w->rlist == 0) {
0532             free(w->blist);
0533             free(w->alist);
0534             free(w); /* exception in constructor, avoid memory leak */
0535 
0536             GSL_ERROR_VAL("failed to allocate space for rlist ranges",
0537                     GSL_ENOMEM, 0);
0538         }
0539 
0540         w->elist = (double *) malloc(n * sizeof(double));
0541 
0542         if (w->elist == 0) {
0543             free(w->rlist);
0544             free(w->blist);
0545             free(w->alist);
0546             free(w); /* exception in constructor, avoid memory leak */
0547 
0548             GSL_ERROR_VAL("failed to allocate space for elist ranges",
0549                     GSL_ENOMEM, 0);
0550         }
0551 
0552         w->order = (size_t *) malloc(n * sizeof(size_t));
0553 
0554         if (w->order == 0) {
0555             free(w->elist);
0556             free(w->rlist);
0557             free(w->blist);
0558             free(w->alist);
0559             free(w); /* exception in constructor, avoid memory leak */
0560 
0561             GSL_ERROR_VAL("failed to allocate space for order ranges",
0562                     GSL_ENOMEM, 0);
0563         }
0564 
0565         w->level = (size_t *) malloc(n * sizeof(size_t));
0566 
0567         if (w->level == 0) {
0568             free(w->order);
0569             free(w->elist);
0570             free(w->rlist);
0571             free(w->blist);
0572             free(w->alist);
0573             free(w); /* exception in constructor, avoid memory leak */
0574 
0575             GSL_ERROR_VAL("failed to allocate space for order ranges",
0576                     GSL_ENOMEM, 0);
0577         }
0578 
0579         w->size = 0;
0580         w->limit = n;
0581         w->maximum_level = 0;
0582 
0583         return w;
0584     }
0585 
0586     void gsl_integration_workspace_free(gsl_integration_workspace * w) {
0587         if (w != 0) {
0588             free(w->level);
0589             free(w->order);
0590             free(w->elist);
0591             free(w->rlist);
0592             free(w->blist);
0593             free(w->alist);
0594             free(w);
0595         }
0596     }
0597 
0598     inline void initialise(gsl_integration_workspace * workspace, double a,
0599             double b) {
0600         workspace->size = 0;
0601         workspace->nrmax = 0;
0602         workspace->i = 0;
0603         workspace->alist[0] = a;
0604         workspace->blist[0] = b;
0605         workspace->rlist[0] = 0.0;
0606         workspace->elist[0] = 0.0;
0607         workspace->order[0] = 0;
0608         workspace->level[0] = 0;
0609 
0610         workspace->maximum_level = 0;
0611     }
0612 
0613     inline void retrieve(const gsl_integration_workspace * workspace,
0614             double * a, double * b, double * r, double * e) {
0615         const size_t i = workspace->i;
0616         double * alist = workspace->alist;
0617         double * blist = workspace->blist;
0618         double * rlist = workspace->rlist;
0619         double * elist = workspace->elist;
0620 
0621         *a = alist[i];
0622         *b = blist[i];
0623         *r = rlist[i];
0624         *e = elist[i];
0625     }
0626 
0627     inline
0628     void update(gsl_integration_workspace * workspace, double a1, double b1,
0629             double area1, double error1, double a2, double b2, double area2,
0630             double error2) {
0631         double * alist = workspace->alist;
0632         double * blist = workspace->blist;
0633         double * rlist = workspace->rlist;
0634         double * elist = workspace->elist;
0635         size_t * level = workspace->level;
0636 
0637         const size_t i_max = workspace->i;
0638         const size_t i_new = workspace->size;
0639 
0640         const size_t new_level = workspace->level[i_max] + 1;
0641 
0642         /* append the newly-created intervals to the list */
0643 
0644         if (error2 > error1) {
0645             alist[i_max] = a2; /* blist[maxerr] is already == b2 */
0646             rlist[i_max] = area2;
0647             elist[i_max] = error2;
0648             level[i_max] = new_level;
0649 
0650             alist[i_new] = a1;
0651             blist[i_new] = b1;
0652             rlist[i_new] = area1;
0653             elist[i_new] = error1;
0654             level[i_new] = new_level;
0655         } else {
0656             blist[i_max] = b1; /* alist[maxerr] is already == a1 */
0657             rlist[i_max] = area1;
0658             elist[i_max] = error1;
0659             level[i_max] = new_level;
0660 
0661             alist[i_new] = a2;
0662             blist[i_new] = b2;
0663             rlist[i_new] = area2;
0664             elist[i_new] = error2;
0665             level[i_new] = new_level;
0666         }
0667 
0668         workspace->size++;
0669 
0670         if (new_level > workspace->maximum_level) {
0671             workspace->maximum_level = new_level;
0672         }
0673 
0674         qpsrt(workspace);
0675     }
0676 
0677     inline
0678     void qpsrt(gsl_integration_workspace * workspace) {
0679         const size_t last = workspace->size - 1;
0680         const size_t limit = workspace->limit;
0681 
0682         double * elist = workspace->elist;
0683         size_t * order = workspace->order;
0684 
0685         double errmax;
0686         double errmin;
0687         int i, k, top;
0688 
0689         size_t i_nrmax = workspace->nrmax;
0690         size_t i_maxerr = order[i_nrmax];
0691 
0692         /* Check whether the list contains more than two error estimates */
0693 
0694         if (last < 2) {
0695             order[0] = 0;
0696             order[1] = 1;
0697             workspace->i = i_maxerr;
0698             return;
0699         }
0700 
0701         errmax = elist[i_maxerr];
0702 
0703         /* This part of the routine is only executed if, due to a difficult
0704          integrand, subdivision increased the error estimate. In the normal
0705          case the insert procedure should start after the nrmax-th largest
0706          error estimate. */
0707 
0708         while (i_nrmax > 0 && errmax > elist[order[i_nrmax - 1]]) {
0709             order[i_nrmax] = order[i_nrmax - 1];
0710             i_nrmax--;
0711         }
0712 
0713         /* Compute the number of elements in the list to be maintained in
0714          descending order. This number depends on the number of
0715          subdivisions still allowed. */
0716 
0717         if (last < (limit / 2 + 2)) {
0718             top = last;
0719         } else {
0720             top = limit - last + 1;
0721         }
0722 
0723         /* Insert errmax by traversing the list top-down, starting
0724          comparison from the element elist(order(i_nrmax+1)). */
0725 
0726         i = i_nrmax + 1;
0727 
0728         /* The order of the tests in the following line is important to
0729          prevent a segmentation fault */
0730 
0731         while (i < top && errmax < elist[order[i]]) {
0732             order[i - 1] = order[i];
0733             i++;
0734         }
0735 
0736         order[i - 1] = i_maxerr;
0737 
0738         /* Insert errmin by traversing the list bottom-up */
0739 
0740         errmin = elist[last];
0741 
0742         k = top - 1;
0743 
0744         while (k > i - 2 && errmin >= elist[order[k]]) {
0745             order[k + 1] = order[k];
0746             k--;
0747         }
0748 
0749         order[k + 1] = last;
0750 
0751         /* Set i_max and e_max */
0752 
0753         i_maxerr = order[i_nrmax];
0754 
0755         workspace->i = i_maxerr;
0756         workspace->nrmax = i_nrmax;
0757     }
0758 
0759     int increase_nrmax(gsl_integration_workspace * workspace) {
0760         int k;
0761         int id = workspace->nrmax;
0762         int jupbnd;
0763 
0764         const size_t * level = workspace->level;
0765         const size_t * order = workspace->order;
0766 
0767         size_t limit = workspace->limit;
0768         size_t last = workspace->size - 1;
0769 
0770         if (last > (1 + limit / 2)) {
0771             jupbnd = limit + 1 - last;
0772         } else {
0773             jupbnd = last;
0774         }
0775 
0776         for (k = id; k <= jupbnd; k++) {
0777             size_t i_max = order[workspace->nrmax];
0778 
0779             workspace->i = i_max;
0780 
0781             if (level[i_max] < workspace->maximum_level) {
0782                 return 1;
0783             }
0784 
0785             workspace->nrmax++;
0786 
0787         }
0788 
0789         return 0;
0790     }
0791 
0792     inline void reset_nrmax(gsl_integration_workspace * workspace) {
0793         workspace->nrmax = 0;
0794         workspace->i = workspace->order[0];
0795     }
0796 
0797     inline double sum_results(const gsl_integration_workspace * workspace) {
0798         const double * const rlist = workspace->rlist;
0799         const size_t n = workspace->size;
0800 
0801         size_t k;
0802         double result_sum = 0;
0803 
0804         for (k = 0; k < n; k++) {
0805             result_sum += rlist[k];
0806         }
0807 
0808         return result_sum;
0809     }
0810 
0811     int large_interval(gsl_integration_workspace * workspace) {
0812         size_t i = workspace->i;
0813         const size_t * level = workspace->level;
0814 
0815         if (level[i] < workspace->maximum_level) {
0816             return 1;
0817         } else {
0818             return 0;
0819         }
0820     }
0821 
0822     inline void set_initial_result(gsl_integration_workspace * workspace,
0823             double result, double error) {
0824         workspace->size = 1;
0825         workspace->rlist[0] = result;
0826         workspace->elist[0] = error;
0827     }
0828 
0829     void initialise_table(struct extrapolation_table *table) {
0830         table->n = 0;
0831         table->nres = 0;
0832     }
0833 
0834     void append_table(struct extrapolation_table *table, double y) {
0835         size_t n;
0836         n = table->n;
0837         table->rlist2[n] = y;
0838         table->n++;
0839     }
0840 
0841     inline void qelg(struct extrapolation_table *table, double &result,
0842             double &abserr) {
0843         double *epstab = table->rlist2;
0844         double *res3la = table->res3la;
0845         const size_t n = table->n - 1;
0846 
0847         const double current = epstab[n];
0848 
0849         double absolute = std::numeric_limits<double>::max();
0850         double relative = 5 * std::numeric_limits<double>::epsilon()
0851                 * fabs(current);
0852 
0853         const size_t newelm = n / 2;
0854         const size_t n_orig = n;
0855         size_t n_final = n;
0856         size_t i;
0857 
0858         const size_t nres_orig = table->nres;
0859 
0860         result = current;
0861         abserr = std::numeric_limits<double>::max();
0862 
0863         if (n < 2) {
0864             result = current;
0865             abserr = GSL_MAX_DBL(absolute, relative);
0866             return;
0867         }
0868 
0869         epstab[n + 2] = epstab[n];
0870         epstab[n] = std::numeric_limits<double>::max();
0871 
0872         for (i = 0; i < newelm; i++) {
0873             double res = epstab[n - 2 * i + 2];
0874             double e0 = epstab[n - 2 * i - 2];
0875             double e1 = epstab[n - 2 * i - 1];
0876             double e2 = res;
0877 
0878             double e1abs = fabs(e1);
0879             double delta2 = e2 - e1;
0880             double err2 = fabs(delta2);
0881             double tol2 = GSL_MAX_DBL(fabs(e2), e1abs)
0882                     * std::numeric_limits<double>::epsilon();
0883             double delta3 = e1 - e0;
0884             double err3 = fabs(delta3);
0885             double tol3 = GSL_MAX_DBL(e1abs, fabs(e0))
0886                     * std::numeric_limits<double>::epsilon();
0887 
0888             double e3, delta1, err1, tol1, ss;
0889 
0890             if (err2 <= tol2 && err3 <= tol3) {
0891                 /* If e0, e1 and e2 are equal to within machine accuracy,
0892                  convergence is assumed.  */
0893 
0894                 result = res;
0895                 absolute = err2 + err3;
0896                 relative = 5 * std::numeric_limits<double>::epsilon()
0897                         * fabs(res);
0898                 abserr = GSL_MAX_DBL(absolute, relative);
0899                 return;
0900             }
0901 
0902             e3 = epstab[n - 2 * i];
0903             epstab[n - 2 * i] = e1;
0904             delta1 = e1 - e3;
0905             err1 = fabs(delta1);
0906             tol1 = GSL_MAX_DBL(e1abs, fabs(e3))
0907                     * std::numeric_limits<double>::epsilon();
0908 
0909             /* If two elements are very close to each other, omit a part of
0910              the table by adjusting the value of n */
0911 
0912             if (err1 <= tol1 || err2 <= tol2 || err3 <= tol3) {
0913                 n_final = 2 * i;
0914                 break;
0915             }
0916 
0917             ss = (1 / delta1 + 1 / delta2) - 1 / delta3;
0918 
0919             /* Test to detect irregular behaviour in the table, and
0920              eventually omit a part of the table by adjusting the value of
0921              n. */
0922 
0923             if (fabs(ss * e1) <= 0.0001) {
0924                 n_final = 2 * i;
0925                 break;
0926             }
0927 
0928             /* Compute a new element and eventually adjust the value of
0929              result. */
0930 
0931             res = e1 + 1 / ss;
0932             epstab[n - 2 * i] = res;
0933 
0934             {
0935                 const double error = err2 + fabs(res - e2) + err3;
0936 
0937                 if (error <= abserr) {
0938                     abserr = error;
0939                     result = res;
0940                 }
0941             }
0942         }
0943 
0944         /* Shift the table */
0945 
0946         {
0947             const size_t limexp = 50 - 1;
0948 
0949             if (n_final == limexp) {
0950                 n_final = 2 * (limexp / 2);
0951             }
0952         }
0953 
0954         if (n_orig % 2 == 1) {
0955             for (i = 0; i <= newelm; i++) {
0956                 epstab[1 + i * 2] = epstab[i * 2 + 3];
0957             }
0958         } else {
0959             for (i = 0; i <= newelm; i++) {
0960                 epstab[i * 2] = epstab[i * 2 + 2];
0961             }
0962         }
0963 
0964         if (n_orig != n_final) {
0965             for (i = 0; i <= n_final; i++) {
0966                 epstab[i] = epstab[n_orig - n_final + i];
0967             }
0968         }
0969 
0970         table->n = n_final + 1;
0971 
0972         if (nres_orig < 3) {
0973             res3la[nres_orig] = result;
0974             abserr = std::numeric_limits<double>::max();
0975         } else { /* Compute error estimate */
0976             abserr = (fabs(result - res3la[2]) + fabs(result - res3la[1])
0977                     + fabs(result - res3la[0]));
0978 
0979             res3la[0] = res3la[1];
0980             res3la[1] = res3la[2];
0981             res3la[2] = result;
0982         }
0983 
0984         /* In QUADPACK the variable table->nres is incremented at the top of
0985          qelg, so it increases on every call. This leads to the array
0986          res3la being accessed when its elements are still undefined, so I
0987          have moved the update to this point so that its value more
0988          useful. */
0989 
0990         table->nres = nres_orig + 1;
0991 
0992         abserr = GSL_MAX_DBL(abserr,
0993                 5 * std::numeric_limits<double>::epsilon() * fabs(result));
0994 
0995         return;
0996     }
0997 
0998     inline int test_positivity(double result, double resabs) {
0999         int status = (fabs(result)
1000                 >= (1 - 50 * std::numeric_limits<double>::epsilon()) * resabs);
1001 
1002         return status;
1003     }
1004 
1005     inline int subinterval_too_small(double a1, double a2, double b2) {
1006         const double e = std::numeric_limits<double>::epsilon();
1007         const double u = std::numeric_limits<double>::min();
1008 
1009         double tmp = (1 + 100 * e) * (fabs(a2) + 1000 * u);
1010 
1011         int status = fabs(a1) <= tmp && fabs(b2) <= tmp;
1012 
1013         return status;
1014     }
1015 
1016     inline double GSL_MAX_DBL(double a, double b) {
1017         return GSL_MAX(a, b);
1018     }
1019 
1020     void gsl_integration_21qk(FunctionType1D* pFunction, double a, double b,
1021             double &result, double &abserr, double &resabs, double &resasc,
1022             std::vector<double> &parameters) {
1023 
1024         double x = 0.;
1025         const int n = 11;
1026         double fv1[11], fv2[11];
1027 
1028         const double center = 0.5 * (a + b);
1029         const double half_length = 0.5 * (b - a);
1030         const double abs_half_length = fabs(half_length);
1031 
1032         const double f_center = (*pFunction)(center, parameters);
1033 
1034         double result_gauss = 0;
1035         double result_kronrod = f_center * wgk[n - 1];
1036 
1037         double result_abs = fabs(result_kronrod);
1038         double result_asc = 0;
1039         double mean = 0, err = 0;
1040 
1041         int j;
1042 
1043         if (n % 2 == 0) {
1044             result_gauss = f_center * wg[n / 2 - 1];
1045         }
1046 
1047         for (j = 0; j < (n - 1) / 2; j++) {
1048             const int jtw = j * 2 + 1; /* in original fortran j=1,2,3 jtw=2,4,6 */
1049             const double abscissa = half_length * xgk[jtw];
1050 
1051             x = center - abscissa;
1052             const double fval1 = (*pFunction)(x, parameters);
1053 
1054             x = center + abscissa;
1055             const double fval2 = (*pFunction)(x, parameters);
1056 
1057             const double fsum = fval1 + fval2;
1058             fv1[jtw] = fval1;
1059             fv2[jtw] = fval2;
1060             result_gauss += wg[j] * fsum;
1061             result_kronrod += wgk[jtw] * fsum;
1062             result_abs += wgk[jtw] * (fabs(fval1) + fabs(fval2));
1063         }
1064 
1065         for (j = 0; j < n / 2; j++) {
1066             int jtwm1 = j * 2;
1067             const double abscissa = half_length * xgk[jtwm1];
1068 
1069             x = center - abscissa;
1070             const double fval1 = (*pFunction)(x, parameters);
1071 
1072             x = center + abscissa;
1073             const double fval2 = (*pFunction)(x, parameters);
1074             fv1[jtwm1] = fval1;
1075             fv2[jtwm1] = fval2;
1076             result_kronrod += wgk[jtwm1] * (fval1 + fval2);
1077             result_abs += wgk[jtwm1] * (fabs(fval1) + fabs(fval2));
1078         };
1079 
1080         mean = result_kronrod * 0.5;
1081 
1082         result_asc = wgk[n - 1] * fabs(f_center - mean);
1083 
1084         for (j = 0; j < n - 1; j++) {
1085             result_asc += wgk[j] * (fabs(fv1[j] - mean) + fabs(fv2[j] - mean));
1086         }
1087 
1088         /* scale by the width of the integration region */
1089 
1090         err = (result_kronrod - result_gauss) * half_length;
1091 
1092         result_kronrod *= half_length;
1093         result_abs *= abs_half_length;
1094         result_asc *= abs_half_length;
1095 
1096         result = result_kronrod;
1097         resabs = result_abs;
1098         resasc = result_asc;
1099         abserr = rescale_error(err, result_abs, result_asc);
1100     }
1101 
1102     double rescale_error(double err, const double result_abs,
1103             const double result_asc) {
1104         err = fabs(err);
1105 
1106         if (result_asc != 0 && err != 0) {
1107             double scale = pow((200 * err / result_asc), 1.5);
1108 
1109             if (scale < 1) {
1110                 err = result_asc * scale;
1111             } else {
1112                 err = result_asc;
1113             }
1114         }
1115         if (result_abs
1116                 > std::numeric_limits<double>::min()
1117                         / (50 * std::numeric_limits<double>::epsilon())) {
1118             double min_err = 50 * std::numeric_limits<double>::epsilon()
1119                     * result_abs;
1120 
1121             if (min_err > err) {
1122                 err = min_err;
1123             }
1124         }
1125 
1126         return err;
1127     }
1128 
1129     double GSL_MAX(double a, double b) {
1130         return (a > b) ? a : b;
1131     }
1132 
1133     static const std::vector<double> xgk;
1134     static const std::vector<double> wg;
1135     static const std::vector<double> wgk;
1136 
1137     static const std::vector<double> make_xgk_21();
1138     static const std::vector<double> make_wg_21();
1139     static const std::vector<double> make_wgk_21();
1140 
1141     virtual GaussKronrodAdaptive* clone() const {
1142         return new GaussKronrodAdaptive(*this);
1143     }
1144 
1145 protected:
1146     GaussKronrodAdaptive(const GaussKronrodAdaptive &other) :
1147             Integrator1D(other) {
1148     }
1149 };
1150 
1151 } // namespace NumA
1152 
1153 #endif /* GAUSS_KRONROD_ADAPTIVE_H */