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 }