1 // This code has been mechanically translated from the original FORTRAN
2 // code at http://netlib.org/quadpack.
3 
4 /** Authors:    Lars Tandle Kyllingstad
5     Copyright:  Copyright (c) 2009, Lars T. Kyllingstad. All rights reserved.
6     License:    Boost License 1.0
7 */
8 module scid.ports.quadpack.qagpe;
9 
10 
11 import std.algorithm: min, max;
12 import std.math: fabs;
13 
14 import scid.ports.quadpack.qelg;
15 import scid.ports.quadpack.qk21;
16 import scid.ports.quadpack.qpsrt;
17 
18 import scid.core.fortran;
19 
20 
21 
22 
23 ///
24 void qagpe(Real, Func) (Func f, Real a, Real b, int npts2, const Real* points_,
25     Real epsabs, Real epsrel, int limit, out Real result, out Real abserr,
26     out int neval, out int ier, Real* alist_, Real* blist_, Real* rlist_,
27     Real* elist_, Real* pts_, int* iord_, int* level_, int* ndin_,
28     out int last)
29 {
30 //***begin prologue  dqagpe
31 //***date written   800101   (yymmdd)
32 //***revision date  830518   (yymmdd)
33 //***category no.  h2a2a1
34 //***keywords  automatic integrator, general-purpose,
35 //             singularities at user specified points,
36 //             extrapolation, globally adaptive.
37 //***author  piessens,robert ,appl. math. & progr. div. - k.u.leuven
38 //           de doncker,elise,appl. math. & progr. div. - k.u.leuven
39 //***purpose  the routine calculates an approximation result to a given
40 //            definite integral i = integral of f over (a,b), hopefully
41 //            satisfying following claim for accuracy abs(i-result).le.
42 //            max(epsabs,epsrel*abs(i)). break points of the integration
43 //            interval, where local difficulties of the integrand may
44 //            occur(e.g. singularities,discontinuities),provided by user.
45 //***description
46 //
47 //        computation of a definite integral
48 //        standard fortran subroutine
49 //        double precision version
50 //
51 //        parameters
52 //         on entry
53 //            f      - double precision
54 //                     function subprogram defining the integrand
55 //                     function f(x). the actual name for f needs to be
56 //                     declared e x t e r n a l in the driver program.
57 //
58 //            a      - double precision
59 //                     lower limit of integration
60 //
61 //            b      - double precision
62 //                     upper limit of integration
63 //
64 //            npts2  - integer
65 //                     number equal to two more than the number of
66 //                     user-supplied break points within the integration
67 //                     range, npts2.ge.2.
68 //                     if npts2.lt.2, the routine will end with ier = 6.
69 //
70 //            points - double precision
71 //                     vector of dimension npts2, the first (npts2-2)
72 //                     elements of which are the user provided break
73 //                     points. if these points do not constitute an
74 //                     ascending sequence there will be an automatic
75 //                     sorting.
76 //
77 //            epsabs - double precision
78 //                     absolute accuracy requested
79 //            epsrel - double precision
80 //                     relative accuracy requested
81 //                     if  epsabs.le.0
82 //                     and epsrel.lt.max(50*rel.mach.acc.,0.5d-28),
83 //                     the routine will end with ier = 6.
84 //
85 //            limit  - integer
86 //                     gives an upper bound on the number of subintervals
87 //                     in the partition of (a,b), limit.ge.npts2
88 //                     if limit.lt.npts2, the routine will end with
89 //                     ier = 6.
90 //
91 //         on return
92 //            result - double precision
93 //                     approximation to the integral
94 //
95 //            abserr - double precision
96 //                     estimate of the modulus of the absolute error,
97 //                     which should equal or exceed abs(i-result)
98 //
99 //            neval  - integer
100 //                     number of integrand evaluations
101 //
102 //            ier    - integer
103 //                     ier = 0 normal and reliable termination of the
104 //                             routine. it is assumed that the requested
105 //                             accuracy has been achieved.
106 //                     ier.gt.0 abnormal termination of the routine.
107 //                             the estimates for integral and error are
108 //                             less reliable. it is assumed that the
109 //                             requested accuracy has not been achieved.
110 //            error messages
111 //                     ier = 1 maximum number of subdivisions allowed
112 //                             has been achieved. one can allow more
113 //                             subdivisions by increasing the value of
114 //                             limit (and taking the according dimension
115 //                             adjustments into account). however, if
116 //                             this yields no improvement it is advised
117 //                             to analyze the integrand in order to
118 //                             determine the integration difficulties. if
119 //                             the position of a local difficulty can be
120 //                             determined (i.e. singularity,
121 //                             discontinuity within the interval), it
122 //                             should be supplied to the routine as an
123 //                             element of the vector points. if necessary
124 //                             an appropriate special-purpose integrator
125 //                             must be used, which is designed for
126 //                             handling the type of difficulty involved.
127 //                         = 2 the occurrence of roundoff error is
128 //                             detected, which prevents the requested
129 //                             tolerance from being achieved.
130 //                             the error may be under-estimated.
131 //                         = 3 extremely bad integrand behaviour occurs
132 //                             at some points of the integration
133 //                             interval.
134 //                         = 4 the algorithm does not converge.
135 //                             roundoff error is detected in the
136 //                             extrapolation table. it is presumed that
137 //                             the requested tolerance cannot be
138 //                             achieved, and that the returned result is
139 //                             the best which can be obtained.
140 //                         = 5 the integral is probably divergent, or
141 //                             slowly convergent. it must be noted that
142 //                             divergence can occur with any other value
143 //                             of ier.gt.0.
144 //                         = 6 the input is invalid because
145 //                             npts2.lt.2 or
146 //                             break points are specified outside
147 //                             the integration range or
148 //                             (epsabs.le.0 and
149 //                              epsrel.lt.max(50*rel.mach.acc.,0.5d-28))
150 //                             or limit.lt.npts2.
151 //                             result, abserr, neval, last, rlist(1),
152 //                             and elist(1) are set to zero. alist(1) and
153 //                             blist(1) are set to a and b respectively.
154 //
155 //            alist  - double precision
156 //                     vector of dimension at least limit, the first
157 //                      last  elements of which are the left end points
158 //                     of the subintervals in the partition of the given
159 //                     integration range (a,b)
160 //
161 //            blist  - double precision
162 //                     vector of dimension at least limit, the first
163 //                      last  elements of which are the right end points
164 //                     of the subintervals in the partition of the given
165 //                     integration range (a,b)
166 //
167 //            rlist  - double precision
168 //                     vector of dimension at least limit, the first
169 //                      last  elements of which are the integral
170 //                     approximations on the subintervals
171 //
172 //            elist  - double precision
173 //                     vector of dimension at least limit, the first
174 //                      last  elements of which are the moduli of the
175 //                     absolute error estimates on the subintervals
176 //
177 //            pts    - double precision
178 //                     vector of dimension at least npts2, containing the
179 //                     integration limits and the break points of the
180 //                     interval in ascending sequence.
181 //
182 //            level  - integer
183 //                     vector of dimension at least limit, containing the
184 //                     subdivision levels of the subinterval, i.e. if
185 //                     (aa,bb) is a subinterval of (p1,p2) where p1 as
186 //                     well as p2 is a user-provided break point or
187 //                     integration limit, then (aa,bb) has level l if
188 //                     abs(bb-aa) = abs(p2-p1)*2**(-l).
189 //
190 //            ndin   - integer
191 //                     vector of dimension at least npts2, after first
192 //                     integration over the intervals (pts(i)),pts(i+1),
193 //                     i = 0,1, ..., npts2-2, the error estimates over
194 //                     some of the intervals may have been increased
195 //                     artificially, in order to put their subdivision
196 //                     forward. if this happens for the subinterval
197 //                     numbered k, ndin(k) is put to 1, otherwise
198 //                     ndin(k) = 0.
199 //
200 //            iord   - integer
201 //                     vector of dimension at least limit, the first k
202 //                     elements of which are pointers to the
203 //                     error estimates over the subintervals,
204 //                     such that elist(iord(1)), ..., elist(iord(k))
205 //                     form a decreasing sequence, with k = last
206 //                     if last.le.(limit/2+2), and k = limit+1-last
207 //                     otherwise
208 //
209 //            last   - integer
210 //                     number of subintervals actually produced in the
211 //                     subdivisions process
212 //
213 //***references  (none)
214 //***routines called  d1mach,dqelg,dqk21,dqpsrt
215 //***end prologue  dqagpe
216       Real abseps,area,area1,area12,area2,a1,
217         a2,b1,b2,correc,defabs,defab1,defab2,
218         dres,epmach,erlarg,erlast,errbnd,
219         errmax,error1,erro12,error2,errsum,ertest,oflow,
220         resa,resabs,reseps,sign,temp,uflow;
221       Real[3] res3la_;
222       Real[52] rlist2_;
223       int i,id,ierro,ind1,ind2,ip1,iroff1,iroff2,iroff3,j,
224         jlow,jupbnd,k,ksgn,ktmin,levcur,levmax,maxerr,
225         nint,nintp1,npts,nres,nrmax,numrl2;
226       bool extrap,noext;
227 //
228 //
229       auto alist = dimension(alist_, limit);
230       auto blist = dimension(blist_, limit);
231       auto elist = dimension(elist_, limit);
232       auto iord = dimension(iord_, limit);
233       auto level = dimension(level_, limit);
234       auto ndin = dimension(ndin_, npts2);
235       auto points = dimension(points_, npts2);
236       auto pts = dimension(pts_, npts2);
237       auto res3la = dimension(res3la_.ptr, 3);
238       auto rlist = dimension(rlist_, limit);
239       auto rlist2 = dimension(rlist2_.ptr, 52);
240 //
241 //            the dimension of rlist2 is determined by the value of
242 //            limexp in subroutine epsalg (rlist2 should be of dimension
243 //            (limexp+2) at least).
244 //
245 //
246 //            list of major variables
247 //            -----------------------
248 //
249 //           alist     - list of left end points of all subintervals
250 //                       considered up to now
251 //           blist     - list of right end points of all subintervals
252 //                       considered up to now
253 //           rlist(i)  - approximation to the integral over
254 //                       (alist(i),blist(i))
255 //           rlist2    - array of dimension at least limexp+2
256 //                       containing the part of the epsilon table which
257 //                       is still needed for further computations
258 //           elist(i)  - error estimate applying to rlist(i)
259 //           maxerr    - pointer to the interval with largest error
260 //                       estimate
261 //           errmax    - elist(maxerr)
262 //           erlast    - error on the interval currently subdivided
263 //                       (before that subdivision has taken place)
264 //           area      - sum of the integrals over the subintervals
265 //           errsum    - sum of the errors over the subintervals
266 //           errbnd    - requested accuracy max(epsabs,epsrel*
267 //                       abs(result))
268 //           *****1    - variable for the left subinterval
269 //           *****2    - variable for the right subinterval
270 //           last      - index for subdivision
271 //           nres      - number of calls to the extrapolation routine
272 //           numrl2    - number of elements in rlist2. if an appropriate
273 //                       approximation to the compounded integral has
274 //                       been obtained, it is put in rlist2(numrl2) after
275 //                       numrl2 has been increased by one.
276 //           erlarg    - sum of the errors over the intervals larger
277 //                       than the smallest interval considered up to now
278 //           extrap    - logical variable denoting that the routine
279 //                       is attempting to perform extrapolation. i.e.
280 //                       before subdividing the smallest interval we
281 //                       try to decrease the value of erlarg.
282 //           noext     - logical variable denoting that extrapolation is
283 //                       no longer allowed (true-value)
284 //
285 //            machine dependent constants
286 //            ---------------------------
287 //
288 //           epmach is the largest relative spacing.
289 //           uflow is the smallest positive magnitude.
290 //           oflow is the largest positive magnitude.
291 //
292 //***first executable statement  dqagpe
293       epmach = Real.epsilon;
294 //
295 //            test on validity of parameters
296 //            -----------------------------
297 //
298       ier = 0;
299       neval = 0;
300       last = 0;
301       result = 0.0;
302       abserr = 0.0;
303       alist[1] = a;
304       blist[1] = b;
305       rlist[1] = 0.0;
306       elist[1] = 0.0;
307       iord[1] = 0;
308       level[1] = 0;
309       npts = npts2-2;
310       if(npts2 < 2 || limit <= npts || (epsabs <= 0.0 && 
311         epsrel < max(0.5e2*epmach,0.5e-28))) ier = 6;
312       if(ier == 6) goto l999;
313 //
314 //            if any break points are provided, sort them into an
315 //            ascending sequence.
316 //
317       sign = 1.0;
318       if(a > b) sign = -1.0;
319       pts[1] = min(a,b);
320       if(npts == 0) goto l15;
321       for (i=1; i<=npts; i++) { //do 10 i = 1,npts
322         pts[i+1] = points[i];
323  l10: ;}
324  l15: pts[npts+2] = max(a,b);
325       nint = npts+1;
326       a1 = pts[1];
327       if(npts == 0) goto l40;
328       nintp1 = nint+1;
329       for (i=1; i<=nint; i++) { //do 20 i = 1,nint
330         ip1 = i+1;
331         for (j=ip1; j<=nintp1; j++) { //do 20 j = ip1,nintp1
332           if(pts[i] <= pts[j]) goto l20;
333           temp = pts[i];
334           pts[i] = pts[j];
335           pts[j] = temp;
336  l20: ;}}
337       if(pts[1] != min(a,b) || pts[nintp1] != max(a,b)) ier = 6;
338       if(ier == 6) goto l999;
339 //
340 //            compute first integral and error approximations.
341 //            ------------------------------------------------
342 //
343  l40: resabs = 0.0;
344       for (i=1; i<=nint; i++) { //do 50 i = 1,nint
345         b1 = pts[i+1];
346         qk21!(Real,Func)(f,a1,b1,area1,error1,defabs,resa);
347         abserr = abserr+error1;
348         result = result+area1;
349         ndin[i] = 0;
350         if(error1 == resa && error1 != 0.0) ndin[i] = 1;
351         resabs = resabs+defabs;
352         level[i] = 0;
353         elist[i] = error1;
354         alist[i] = a1;
355         blist[i] = b1;
356         rlist[i] = area1;
357         iord[i] = i;
358         a1 = b1;
359  l50: ;}
360       errsum = 0.0;
361       for (i=1; i<=nint; i++) { //do 55 i = 1,nint
362         if(ndin[i] == 1) elist[i] = abserr;
363         errsum = errsum+elist[i];
364  l55: ;}
365 //
366 //           test on accuracy.
367 //
368       last = nint;
369       neval = 21*nint;
370       dres = fabs(result);
371       errbnd = max(epsabs,epsrel*dres);
372       if(abserr <= 0.1e3*epmach*resabs && abserr > errbnd) ier = 2;
373       if(nint == 1) goto l80;
374       for (i=1; i<=npts; i++) { //do 70 i = 1,npts
375         jlow = i+1;
376         ind1 = iord[i];
377         for (j=jlow; j<=nint; j++) { //do 60 j = jlow,nint
378           ind2 = iord[j];
379           if(elist[ind1] > elist[ind2]) goto l60;
380           ind1 = ind2;
381           k = j;
382  l60:   ;}
383         if(ind1 == iord[i]) goto l70;
384         iord[k] = iord[i];
385         iord[i] = ind1;
386  l70: ;}
387       if(limit < npts2) ier = 1;
388  l80: if(ier != 0 || abserr <= errbnd) goto l210;
389 //
390 //           initialization
391 //           --------------
392 //
393       rlist2[1] = result;
394       maxerr = iord[1];
395       errmax = elist[maxerr];
396       area = result;
397       nrmax = 1;
398       nres = 0;
399       numrl2 = 1;
400       ktmin = 0;
401       extrap = false;
402       noext = false;
403       erlarg = errsum;
404       ertest = errbnd;
405       levmax = 1;
406       iroff1 = 0;
407       iroff2 = 0;
408       iroff3 = 0;
409       ierro = 0;
410       uflow = Real.min_normal;
411       oflow = Real.max;
412       abserr = oflow;
413       ksgn = -1;
414       if(dres >= (0.1e1-0.5e2*epmach)*resabs) ksgn = 1;
415 //
416 //           main do-loop
417 //           ------------
418 //
419       for (last=npts2; last<=limit; last++) { //do 160 last = npts2,limit
420 //
421 //           bisect the subinterval with the nrmax-th largest error
422 //           estimate.
423 //
424         levcur = level[maxerr]+1;
425         a1 = alist[maxerr];
426         b1 = 0.5*(alist[maxerr]+blist[maxerr]);
427         a2 = b1;
428         b2 = blist[maxerr];
429         erlast = errmax;
430         qk21!(Real,Func)(f,a1,b1,area1,error1,resa,defab1);
431         qk21!(Real,Func)(f,a2,b2,area2,error2,resa,defab2);
432 //
433 //           improve previous approximations to integral
434 //           and error and test for accuracy.
435 //
436         neval = neval+42;
437         area12 = area1+area2;
438         erro12 = error1+error2;
439         errsum = errsum+erro12-errmax;
440         area = area+area12-rlist[maxerr];
441         if(defab1 == error1 || defab2 == error2) goto l95;
442         if(fabs(rlist[maxerr]-area12) > 0.1e-4*fabs(area12)
443          || erro12 < 0.99*errmax) goto l90;
444         if(extrap) iroff2 = iroff2+1;
445         if(!extrap) iroff1 = iroff1+1;
446  l90:   if(last > 10 && erro12 > errmax) iroff3 = iroff3+1;
447  l95:   level[maxerr] = levcur;
448         level[last] = levcur;
449         rlist[maxerr] = area1;
450         rlist[last] = area2;
451         errbnd = max(epsabs,epsrel*fabs(area));
452 //
453 //           test for roundoff error and eventually set error flag.
454 //
455         if(iroff1+iroff2 >= 10 || iroff3 >= 20) ier = 2;
456         if(iroff2 >= 5) ierro = 3;
457 //
458 //           set error flag in the case that the number of
459 //           subintervals equals limit.
460 //
461         if(last == limit) ier = 1;
462 //
463 //           set error flag in the case of bad integrand behaviour
464 //           at a point of the integration range
465 //
466         if(max(fabs(a1),fabs(b2)) <= (0.1e1+0.1e3*epmach)*
467           (fabs(a2)+0.1e4*uflow)) ier = 4;
468 //
469 //           append the newly-created intervals to the list.
470 //
471         if(error2 > error1) goto l100;
472         alist[last] = a2;
473         blist[maxerr] = b1;
474         blist[last] = b2;
475         elist[maxerr] = error1;
476         elist[last] = error2;
477         goto l110;
478 l100:   alist[maxerr] = a2;
479         alist[last] = a1;
480         blist[last] = b1;
481         rlist[maxerr] = area2;
482         rlist[last] = area1;
483         elist[maxerr] = error2;
484         elist[last] = error1;
485 //
486 //           call subroutine dqpsrt to maintain the descending ordering
487 //           in the list of error estimates and select the subinterval
488 //           with nrmax-th largest error estimate (to be bisected next).
489 //
490 l110:   qpsrt!Real(limit,last,maxerr,errmax,elist.ptr,iord.ptr,nrmax);
491 // ***jump out of do-loop
492         if(errsum <= errbnd) goto l190;
493 // ***jump out of do-loop
494         if(ier != 0) goto l170;
495         if(noext) goto l160;
496         erlarg = erlarg-erlast;
497         if(levcur+1 <= levmax) erlarg = erlarg+erro12;
498         if(extrap) goto l120;
499 //
500 //           test whether the interval to be bisected next is the
501 //           smallest interval.
502 //
503         if(level[maxerr]+1 <= levmax) goto l160;
504         extrap = true;
505         nrmax = 2;
506 l120:   if(ierro == 3 || erlarg <= ertest) goto l140;
507 //
508 //           the smallest interval has the largest error.
509 //           before bisecting decrease the sum of the errors over
510 //           the larger intervals (erlarg) and perform extrapolation.
511 //
512         id = nrmax;
513         jupbnd = last;
514         if(last > (2+limit/2)) jupbnd = limit+3-last;
515         for (k=id; k<=jupbnd; k++) { //do 130 k = id,jupbnd
516           maxerr = iord[nrmax];
517           errmax = elist[maxerr];
518 // ***jump out of do-loop
519           if(level[maxerr]+1 <= levmax) goto l160;
520           nrmax = nrmax+1;
521 l130:   ;}
522 //
523 //           perform extrapolation.
524 //
525 l140:   numrl2 = numrl2+1;
526         rlist2[numrl2] = area;
527         if(numrl2 <= 2) goto l155;
528         qelg!Real(numrl2,rlist2.ptr,reseps,abseps,res3la.ptr,nres);
529         ktmin = ktmin+1;
530         if(ktmin > 5 && abserr < 0.1e-2*errsum) ier = 5;
531         if(abseps >= abserr) goto l150;
532         ktmin = 0;
533         abserr = abseps;
534         result = reseps;
535         correc = erlarg;
536         ertest = max(epsabs,epsrel*fabs(reseps));
537 // ***jump out of do-loop
538         if(abserr < ertest) goto l170;
539 //
540 //           prepare bisection of the smallest interval.
541 //
542 l150:   if(numrl2 == 1) noext = true;
543         if(ier >= 5) goto l170;
544 l155:   maxerr = iord[1];
545         errmax = elist[maxerr];
546         nrmax = 1;
547         extrap = false;
548         levmax = levmax+1;
549         erlarg = errsum;
550 l160: ;}
551 //
552 //           set the final result.
553 //           ---------------------
554 //
555 //
556 l170: if(abserr == oflow) goto l190;
557       if((ier+ierro) == 0) goto l180;
558       if(ierro == 3) abserr = abserr+correc;
559       if(ier == 0) ier = 3;
560       if(result != 0.0 && area != 0.0)goto l175;
561       if(abserr > errsum)goto l190;
562       if(area == 0.0) goto l210;
563       goto l180;
564 l175: if(abserr/fabs(result) > errsum/fabs(area))goto l190;
565 //
566 //           test on divergence.
567 //
568 l180: if(ksgn == (-1) && max(fabs(result),fabs(area)) <= 
569         resabs*0.1e-1) goto l210;
570       if(0.1e-1 > (result/area) || (result/area) > 0.1e3 || 
571         errsum > fabs(area)) ier = 6;
572       goto l210;
573 //
574 //           compute global integral sum.
575 //
576 l190: result = 0.0;
577       for (k=1; k<=last; k++) { //do 200 k = 1,last
578         result = result+rlist[k];
579 l200: ;}
580       abserr = errsum;
581 l210: if(ier > 2) ier = ier-1;
582       result = result*sign;
583 l999: return;
584 }
585 
586 unittest
587 {
588     alias qagpe!(float, float delegate(float)) fqagpe;
589     alias qagpe!(double, double delegate(double)) dqagpe;
590     alias qagpe!(double, double function(double)) dfqagpe;
591     alias qagpe!(real, real delegate(real)) rqagpe;
592 }