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.qagie; 9 10 11 import std.algorithm: max, min; 12 import std.math: fabs; 13 14 import scid.core.fortran; 15 import scid.ports.quadpack.qk15i; 16 import scid.ports.quadpack.qpsrt; 17 import scid.ports.quadpack.qelg; 18 19 20 21 22 /// 23 void qagie(Real, Func)(Func f, Real bound, int inf, Real epsabs, 24 Real epsrel, int limit, out Real result, out Real abserr, 25 out int neval, out int ier, Real* alist_, Real* blist_, 26 Real* rlist_, Real* elist_, int* iord_, out int last) 27 { 28 //***begin prologue dqagie 29 //***date written 800101 (yymmdd) 30 //***revision date 830518 (yymmdd) 31 //***category no. h2a3a1,h2a4a1 32 //***keywords automatic integrator, infinite intervals, 33 // general-purpose, transformation, extrapolation, 34 // globally adaptive 35 //***author piessens,robert,appl. math & progr. div - k.u.leuven 36 // de doncker,elise,appl. math & progr. div - k.u.leuven 37 //***purpose the routine calculates an approximation result to a given 38 // integral i = integral of f over (bound,+infinity) 39 // or i = integral of f over (-infinity,bound) 40 // or i = integral of f over (-infinity,+infinity), 41 // hopefully satisfying following claim for accuracy 42 // abs(i-result).le.max(epsabs,epsrel*abs(i)) 43 //***description 44 // 45 // integration over infinite intervals 46 // standard fortran subroutine 47 // 48 // f - double precision 49 // function subprogram defining the integrand 50 // function f(x). the actual name for f needs to be 51 // declared e x t e r n a l in the driver program. 52 // 53 // bound - double precision 54 // finite bound of integration range 55 // (has no meaning if interval is doubly-infinite) 56 // 57 // inf - double precision 58 // indicating the kind of integration range involved 59 // inf = 1 corresponds to (bound,+infinity), 60 // inf = -1 to (-infinity,bound), 61 // inf = 2 to (-infinity,+infinity). 62 // 63 // epsabs - double precision 64 // absolute accuracy requested 65 // epsrel - double precision 66 // relative accuracy requested 67 // if epsabs.le.0 68 // and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), 69 // the routine will end with ier = 6. 70 // 71 // limit - integer 72 // gives an upper bound on the number of subintervals 73 // in the partition of (a,b), limit.ge.1 74 // 75 // on return 76 // result - double precision 77 // approximation to the integral 78 // 79 // abserr - double precision 80 // estimate of the modulus of the absolute error, 81 // which should equal or exceed abs(i-result) 82 // 83 // neval - integer 84 // number of integrand evaluations 85 // 86 // ier - integer 87 // ier = 0 normal and reliable termination of the 88 // routine. it is assumed that the requested 89 // accuracy has been achieved. 90 // - ier.gt.0 abnormal termination of the routine. the 91 // estimates for result and error are less 92 // reliable. it is assumed that the requested 93 // accuracy has not been achieved. 94 // error messages 95 // ier = 1 maximum number of subdivisions allowed 96 // has been achieved. one can allow more 97 // subdivisions by increasing the value of 98 // limit (and taking the according dimension 99 // adjustments into account). however,if 100 // this yields no improvement it is advised 101 // to analyze the integrand in order to 102 // determine the integration difficulties. 103 // if the position of a local difficulty can 104 // be determined (e.g. singularity, 105 // discontinuity within the interval) one 106 // will probably gain from splitting up the 107 // interval at this point and calling the 108 // integrator on the subranges. if possible, 109 // an appropriate special-purpose integrator 110 // should be used, which is designed for 111 // handling the type of difficulty involved. 112 // = 2 the occurrence of roundoff error is 113 // detected, which prevents the requested 114 // tolerance from being achieved. 115 // the error may be under-estimated. 116 // = 3 extremely bad integrand behaviour occurs 117 // at some points of the integration 118 // interval. 119 // = 4 the algorithm does not converge. 120 // roundoff error is detected in the 121 // extrapolation table. 122 // it is assumed that the requested tolerance 123 // cannot be achieved, and that the returned 124 // result is the best which can be obtained. 125 // = 5 the integral is probably divergent, or 126 // slowly convergent. it must be noted that 127 // divergence can occur with any other value 128 // of ier. 129 // = 6 the input is invalid, because 130 // (epsabs.le.0 and 131 // epsrel.lt.max(50*rel.mach.acc.,0.5d-28), 132 // result, abserr, neval, last, rlist(1), 133 // elist(1) and iord(1) are set to zero. 134 // alist(1) and blist(1) are set to 0 135 // and 1 respectively. 136 // 137 // alist - double precision 138 // vector of dimension at least limit, the first 139 // last elements of which are the left 140 // end points of the subintervals in the partition 141 // of the transformed integration range (0,1). 142 // 143 // blist - double precision 144 // vector of dimension at least limit, the first 145 // last elements of which are the right 146 // end points of the subintervals in the partition 147 // of the transformed integration range (0,1). 148 // 149 // rlist - double precision 150 // vector of dimension at least limit, the first 151 // last elements of which are the integral 152 // approximations on the subintervals 153 // 154 // elist - double precision 155 // vector of dimension at least limit, the first 156 // last elements of which are the moduli of the 157 // absolute error estimates on the subintervals 158 // 159 // iord - integer 160 // vector of dimension limit, the first k 161 // elements of which are pointers to the 162 // error estimates over the subintervals, 163 // such that elist(iord(1)), ..., elist(iord(k)) 164 // form a decreasing sequence, with k = last 165 // if last.le.(limit/2+2), and k = limit+1-last 166 // otherwise 167 // 168 // last - integer 169 // number of subintervals actually produced 170 // in the subdivision process 171 // 172 //***references (none) 173 //***routines called d1mach,dqelg,dqk15i,dqpsrt 174 //***end prologue dqagie 175 Real abseps,area,area1,area12,area2,a1, 176 a2,boun,b1,b2,correc,defabs,defab1,defab2, 177 dres,epmach,erlarg,erlast, 178 errbnd,errmax,error1,error2,erro12,errsum,ertest,oflow,resabs, 179 reseps,small,uflow; 180 Real[3] res3la_; 181 Real[52] rlist2_; 182 int id=1,ierro=1,iroff1=1,iroff2=1,iroff3=1,jupbnd=1,k=1,ksgn=1, 183 ktmin=1,maxerr=1,nres=1,nrmax=1,numrl2=1; 184 bool extrap,noext; 185 // 186 auto alist = dimension(alist_, limit); 187 auto blist = dimension(blist_, limit); 188 auto elist = dimension(elist_, limit); 189 auto iord = dimension(iord_, limit); 190 auto res3la = dimension(res3la_.ptr, 3); 191 auto rlist = dimension(rlist_, limit); 192 auto rlist2 = dimension(rlist2_.ptr, 52); 193 // 194 // the dimension of rlist2 is determined by the value of 195 // limexp in subroutine dqelg. 196 // 197 // 198 // list of major variables 199 // ----------------------- 200 // 201 // alist - list of left end points of all subintervals 202 // considered up to now 203 // blist - list of right end points of all subintervals 204 // considered up to now 205 // rlist(i) - approximation to the integral over 206 // (alist(i),blist(i)) 207 // rlist2 - array of dimension at least (limexp+2), 208 // containing the part of the epsilon table 209 // wich is still needed for further computations 210 // elist(i) - error estimate applying to rlist(i) 211 // maxerr - pointer to the interval with largest error 212 // estimate 213 // errmax - elist(maxerr) 214 // erlast - error on the interval currently subdivided 215 // (before that subdivision has taken place) 216 // area - sum of the integrals over the subintervals 217 // errsum - sum of the errors over the subintervals 218 // errbnd - requested accuracy max(epsabs,epsrel* 219 // abs(result)) 220 // *****1 - variable for the left subinterval 221 // *****2 - variable for the right subinterval 222 // last - index for subdivision 223 // nres - number of calls to the extrapolation routine 224 // numrl2 - number of elements currently in rlist2. if an 225 // appropriate approximation to the compounded 226 // integral has been obtained, it is put in 227 // rlist2(numrl2) after numrl2 has been increased 228 // by one. 229 // small - length of the smallest interval considered up 230 // to now, multiplied by 1.5 231 // erlarg - sum of the errors over the intervals larger 232 // than the smallest interval considered up to now 233 // extrap - logical variable denoting that the routine 234 // is attempting to perform extrapolation. i.e. 235 // before subdividing the smallest interval we 236 // try to decrease the value of erlarg. 237 // noext - logical variable denoting that extrapolation 238 // is no longer allowed (true-value) 239 // 240 // machine dependent constants 241 // --------------------------- 242 // 243 // epmach is the largest relative spacing. 244 // uflow is the smallest positive magnitude. 245 // oflow is the largest positive magnitude. 246 // 247 //***first executable statement dqagie 248 epmach = Real.epsilon; 249 // 250 // test on validity of parameters 251 // ----------------------------- 252 // 253 ier = 0; 254 neval = 0; 255 last = 0; 256 result = 0.0; 257 abserr = 0.0; 258 alist[1] = 0.0; 259 blist[1] = 0.1e1; 260 rlist[1] = 0.0; 261 elist[1] = 0.0; 262 iord[1] = 0; 263 if(epsabs <= 0.0 && epsrel < max(0.5e2*epmach,0.5e-28)) 264 ier = 6; 265 if(ier == 6) goto l999; 266 // 267 // 268 // first approximation to the integral 269 // ----------------------------------- 270 // 271 // determine the interval to be mapped onto (0,1). 272 // if inf = 2 the integral is computed as i = i1+i2, where 273 // i1 = integral of f over (-infinity,0), 274 // i2 = integral of f over (0,+infinity). 275 // 276 boun = bound; 277 if(inf == 2) boun = 0.0; 278 qk15i!(Real, Func)(f,boun,inf,0.0,1.0,result,abserr, 279 defabs,resabs); 280 // 281 // test on accuracy 282 // 283 last = 1; 284 rlist[1] = result; 285 elist[1] = abserr; 286 iord[1] = 1; 287 dres = fabs(result); 288 errbnd = max(epsabs,epsrel*dres); 289 if(abserr <= 1.0e2*epmach*defabs && abserr > errbnd) ier = 2; 290 if(limit == 1) ier = 1; 291 if(ier != 0 || (abserr <= errbnd && abserr != resabs) || 292 abserr == 0.0) goto l130; 293 // 294 // initialization 295 // -------------- 296 // 297 uflow = Real.min_normal; 298 oflow = Real.max; 299 rlist2[1] = result; 300 errmax = abserr; 301 maxerr = 1; 302 area = result; 303 errsum = abserr; 304 abserr = oflow; 305 nrmax = 1; 306 nres = 0; 307 ktmin = 0; 308 numrl2 = 2; 309 extrap = false; 310 noext = false; 311 ierro = 0; 312 iroff1 = 0; 313 iroff2 = 0; 314 iroff3 = 0; 315 ksgn = -1; 316 if(dres >= (0.1e1-0.5e2*epmach)*defabs) ksgn = 1; 317 // 318 // main do-loop 319 // ------------ 320 // 321 for (last=2; last<=limit; last++) { // end: 90 322 // 323 // bisect the subinterval with nrmax-th largest error estimate. 324 // 325 a1 = alist[maxerr]; 326 b1 = 0.5*(alist[maxerr]+blist[maxerr]); 327 a2 = b1; 328 b2 = blist[maxerr]; 329 erlast = errmax; 330 qk15i(f,boun,inf,a1,b1,area1,error1,resabs,defab1); 331 qk15i(f,boun,inf,a2,b2,area2,error2,resabs,defab2); 332 // 333 // improve previous approximations to integral 334 // and error and test for accuracy. 335 // 336 area12 = area1+area2; 337 erro12 = error1+error2; 338 errsum = errsum+erro12-errmax; 339 area = area+area12-rlist[maxerr]; 340 if(defab1 == error1 || defab2 == error2)goto l15; 341 if(fabs(rlist[maxerr]-area12) > 0.1e-4*fabs(area12) 342 || erro12 < 0.99*errmax) goto l10; 343 if(extrap) iroff2 = iroff2+1; 344 if(!extrap) iroff1 = iroff1+1; 345 l10: if(last > 10 && erro12 > errmax) iroff3 = iroff3+1; 346 l15: rlist[maxerr] = area1; 347 rlist[last] = area2; 348 errbnd = max(epsabs,epsrel*fabs(area)); 349 // 350 // test for roundoff error and eventually set error flag. 351 // 352 if(iroff1+iroff2 >= 10 || iroff3 >= 20) ier = 2; 353 if(iroff2 >= 5) ierro = 3; 354 // 355 // set error flag in the case that the number of 356 // subintervals equals limit. 357 // 358 if(last == limit) ier = 1; 359 // 360 // set error flag in the case of bad integrand behaviour 361 // at some points of the integration range. 362 // 363 if(max(fabs(a1),fabs(b2)) <= (0.1e1+0.1e3*epmach)* 364 (fabs(a2)+0.1e4*uflow)) ier = 4; 365 // 366 // append the newly-created intervals to the list. 367 // 368 if(error2 > error1) goto l20; 369 alist[last] = a2; 370 blist[maxerr] = b1; 371 blist[last] = b2; 372 elist[maxerr] = error1; 373 elist[last] = error2; 374 goto l30; 375 l20: alist[maxerr] = a2; 376 alist[last] = a1; 377 blist[last] = b1; 378 rlist[maxerr] = area2; 379 rlist[last] = area1; 380 elist[maxerr] = error2; 381 elist[last] = error1; 382 // 383 // call subroutine dqpsrt to maintain the descending ordering 384 // in the list of error estimates and select the subinterval 385 // with nrmax-th largest error estimate (to be bisected next). 386 // 387 l30: qpsrt!Real(limit,last,maxerr,errmax,elist.ptr,iord.ptr,nrmax); 388 if(errsum <= errbnd) goto l115; 389 if(ier != 0) goto l100; 390 if(last == 2) goto l80; 391 if(noext) goto l90; 392 erlarg = erlarg-erlast; 393 if(fabs(b1-a1) > small) erlarg = erlarg+erro12; 394 if(extrap) goto l40; 395 // 396 // test whether the interval to be bisected next is the 397 // smallest interval. 398 // 399 if(fabs(blist[maxerr]-alist[maxerr]) > small) goto l90; 400 extrap = true; 401 nrmax = 2; 402 l40: if(ierro == 3 || erlarg <= ertest) goto l60; 403 // 404 // the smallest interval has the largest error. 405 // before bisecting decrease the sum of the errors over the 406 // larger intervals (erlarg) and perform extrapolation. 407 // 408 id = nrmax; 409 jupbnd = last; 410 if(last > (2+limit/2)) jupbnd = limit+3-last; 411 for(k=id; k<=jupbnd; k++) { // end: 50 412 maxerr = iord[nrmax]; 413 errmax = elist[maxerr]; 414 if(fabs(blist[maxerr]-alist[maxerr]) > small) goto l90; 415 nrmax = nrmax+1; 416 l50: ;} 417 // 418 // perform extrapolation. 419 // 420 l60: numrl2 = numrl2+1; 421 rlist2[numrl2] = area; 422 qelg!Real(numrl2,rlist2.ptr,reseps,abseps,res3la.ptr,nres); 423 ktmin = ktmin+1; 424 if(ktmin > 5 && abserr < 0.1e-2*errsum) ier = 5; 425 if(abseps >= abserr) goto l70; 426 ktmin = 0; 427 abserr = abseps; 428 result = reseps; 429 correc = erlarg; 430 ertest = max(epsabs,epsrel*fabs(reseps)); 431 if(abserr <= ertest) goto l100; 432 // 433 // prepare bisection of the smallest interval. 434 // 435 l70: if(numrl2 == 1) noext = true; 436 if(ier == 5) goto l100; 437 maxerr = iord[1]; 438 errmax = elist[maxerr]; 439 nrmax = 1; 440 extrap = false; 441 small = small*0.5; 442 erlarg = errsum; 443 goto l90; 444 l80: small = 0.375; 445 erlarg = errsum; 446 ertest = errbnd; 447 rlist2[2] = area; 448 l90: ;} 449 // 450 // set final result and error estimate. 451 // ------------------------------------ 452 // 453 l100: if(abserr == oflow) goto l115; 454 if((ier+ierro) == 0) goto l110; 455 if(ierro == 3) abserr = abserr+correc; 456 if(ier == 0) ier = 3; 457 if(result != 0.0 && area != 0.0)goto l105; 458 if(abserr > errsum)goto l115; 459 if(area == 0.0) goto l130; 460 goto l110; 461 l105: if(abserr/fabs(result) > errsum/fabs(area))goto l115; 462 // 463 // test on divergence 464 // 465 l110: if(ksgn == (-1) && max(fabs(result),fabs(area)) <= 466 defabs*0.1e-1) goto l130; 467 if(0.1e-1 > (result/area) || (result/area) > 0.1e3 468 || errsum > fabs(area)) ier = 6; 469 goto l130; 470 // 471 // compute global integral sum. 472 // 473 l115: result = 0.0; 474 for (k=1; k<=last; k++) { // end: 120 475 result = result+rlist[k]; 476 l120: ;} 477 abserr = errsum; 478 l130: neval = 30*last-15; 479 if(inf == 2) neval = 2*neval; 480 if(ier > 2) ier=ier-1; 481 l999: return; 482 } 483 484 485 unittest 486 { 487 alias qagie!(float, float delegate(float)) fqagie; 488 alias qagie!(double, double delegate(double)) dqagie; 489 alias qagie!(double, double function(double)) dfqagie; 490 alias qagie!(real, real delegate(real)) rqagie; 491 }