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.qagp; 9 10 11 import std.conv; 12 13 import scid.core.fortran; 14 import scid.core.testing; 15 import scid.ports.quadpack.qagpe; 16 17 version(unittest) 18 { 19 import std.math; 20 import scid.core.testing; 21 } 22 23 24 25 26 /// 27 void qagp(Real, Func)(Func f, Real a, Real b, int npts2, const Real* points, 28 Real epsabs, Real epsrel, out Real result, out Real abserr, 29 out int neval, out int ier, int leniw, int lenw, out int last, 30 int* iwork, Real* work) 31 { 32 //***begin prologue dqagp 33 //***date written 800101 (yymmdd) 34 //***revision date 830518 (yymmdd) 35 //***category no. h2a2a1 36 //***keywords automatic integrator, general-purpose, 37 // singularities at user specified points, 38 // extrapolation, globally adaptive 39 //***author piessens,robert,appl. math. & progr. div - k.u.leuven 40 // de doncker,elise,appl. math. & progr. div. - k.u.leuven 41 //***purpose the routine calculates an approximation result to a given 42 // definite integral i = integral of f over (a,b), 43 // hopefully satisfying following claim for accuracy 44 // break points of the integration interval, where local 45 // difficulties of the integrand may occur (e.g. 46 // singularities, discontinuities), are provided by the user. 47 //***description 48 // 49 // computation of a definite integral 50 // standard fortran subroutine 51 // double precision version 52 // 53 // parameters 54 // on entry 55 // f - double precision 56 // function subprogram defining the integrand 57 // function f(x). the actual name for f needs to be 58 // declared e x t e r n a l in the driver program. 59 // 60 // a - double precision 61 // lower limit of integration 62 // 63 // b - double precision 64 // upper limit of integration 65 // 66 // npts2 - integer 67 // number equal to two more than the number of 68 // user-supplied break points within the integration 69 // range, npts.ge.2. 70 // if npts2.lt.2, the routine will end with ier = 6. 71 // 72 // points - double precision 73 // vector of dimension npts2, the first (npts2-2) 74 // elements of which are the user provided break 75 // points. if these points do not constitute an 76 // ascending sequence there will be an automatic 77 // sorting. 78 // 79 // epsabs - double precision 80 // absolute accuracy requested 81 // epsrel - double precision 82 // relative accuracy requested 83 // if epsabs.le.0 84 // and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), 85 // the routine will end with ier = 6. 86 // 87 // on return 88 // result - double precision 89 // approximation to the integral 90 // 91 // abserr - double precision 92 // estimate of the modulus of the absolute error, 93 // which should equal or exceed abs(i-result) 94 // 95 // neval - integer 96 // number of integrand evaluations 97 // 98 // ier - integer 99 // ier = 0 normal and reliable termination of the 100 // routine. it is assumed that the requested 101 // accuracy has been achieved. 102 // ier.gt.0 abnormal termination of the routine. 103 // the estimates for integral and error are 104 // less reliable. it is assumed that the 105 // requested accuracy has not been achieved. 106 // error messages 107 // ier = 1 maximum number of subdivisions allowed 108 // has been achieved. one can allow more 109 // subdivisions by increasing the value of 110 // limit (and taking the according dimension 111 // adjustments into account). however, if 112 // this yields no improvement it is advised 113 // to analyze the integrand in order to 114 // determine the integration difficulties. if 115 // the position of a local difficulty can be 116 // determined (i.e. singularity, 117 // discontinuity within the interval), it 118 // should be supplied to the routine as an 119 // element of the vector points. if necessary 120 // an appropriate special-purpose integrator 121 // must be used, which is designed for 122 // handling the type of difficulty involved. 123 // = 2 the occurrence of roundoff error is 124 // detected, which prevents the requested 125 // tolerance from being achieved. 126 // the error may be under-estimated. 127 // = 3 extremely bad integrand behaviour occurs 128 // at some points of the integration 129 // interval. 130 // = 4 the algorithm does not converge. 131 // roundoff error is detected in the 132 // extrapolation table. 133 // it is presumed that the requested 134 // tolerance cannot be achieved, and that 135 // the returned result is the best which 136 // can be obtained. 137 // = 5 the integral is probably divergent, or 138 // slowly convergent. it must be noted that 139 // divergence can occur with any other value 140 // of ier.gt.0. 141 // = 6 the input is invalid because 142 // npts2.lt.2 or 143 // break points are specified outside 144 // the integration range or 145 // (epsabs.le.0 and 146 // epsrel.lt.max(50*rel.mach.acc.,0.5d-28)) 147 // result, abserr, neval, last are set to 148 // zero. exept when leniw or lenw or npts2 is 149 // invalid, iwork(1), iwork(limit+1), 150 // work(limit*2+1) and work(limit*3+1) 151 // are set to zero. 152 // work(1) is set to a and work(limit+1) 153 // to b (where limit = (leniw-npts2)/2). 154 // 155 // dimensioning parameters 156 // leniw - integer 157 // dimensioning parameter for iwork 158 // leniw determines limit = (leniw-npts2)/2, 159 // which is the maximum number of subintervals in the 160 // partition of the given integration interval (a,b), 161 // leniw.ge.(3*npts2-2). 162 // if leniw.lt.(3*npts2-2), the routine will end with 163 // ier = 6. 164 // 165 // lenw - integer 166 // dimensioning parameter for work 167 // lenw must be at least leniw*2-npts2. 168 // if lenw.lt.leniw*2-npts2, the routine will end 169 // with ier = 6. 170 // 171 // last - integer 172 // on return, last equals the number of subintervals 173 // produced in the subdivision process, which 174 // determines the number of significant elements 175 // actually in the work arrays. 176 // 177 // work arrays 178 // iwork - integer 179 // vector of dimension at least leniw. on return, 180 // the first k elements of which contain 181 // pointers to the error estimates over the 182 // subintervals, such that work(limit*3+iwork(1)),..., 183 // work(limit*3+iwork(k)) form a decreasing 184 // sequence, with k = last if last.le.(limit/2+2), and 185 // k = limit+1-last otherwise 186 // iwork(limit+1), ...,iwork(limit+last) contain the 187 // subdivision levels of the subintervals, i.e. 188 // if (aa,bb) is a subinterval of (p1,p2) 189 // where p1 as well as p2 is a user-provided 190 // break point or integration limit, then (aa,bb) has 191 // level l if abs(bb-aa) = abs(p2-p1)*2**(-l), 192 // iwork(limit*2+1), ..., iwork(limit*2+npts2) have 193 // no significance for the user, 194 // note that limit = (leniw-npts2)/2. 195 // 196 // work - double precision 197 // vector of dimension at least lenw 198 // on return 199 // work(1), ..., work(last) contain the left 200 // end points of the subintervals in the 201 // partition of (a,b), 202 // work(limit+1), ..., work(limit+last) contain 203 // the right end points, 204 // work(limit*2+1), ..., work(limit*2+last) contain 205 // the integral approximations over the subintervals, 206 // work(limit*3+1), ..., work(limit*3+last) 207 // contain the corresponding error estimates, 208 // work(limit*4+1), ..., work(limit*4+npts2) 209 // contain the integration limits and the 210 // break points sorted in an ascending sequence. 211 // note that limit = (leniw-npts2)/2. 212 // 213 //***references (none) 214 //***routines called dqagpe,xerror 215 //***end prologue dqagp 216 // 217 int limit,l1,l2,l3,l4; 218 // 219 // check validity of limit and lenw. 220 // 221 //***first executable statement dqagp 222 ier = 6; 223 neval = 0; 224 last = 0; 225 result = 0.0; 226 abserr = 0.0; 227 if(leniw < (3*npts2-2) || lenw < (leniw*2-npts2) || npts2 < 2) 228 goto l10; 229 // 230 // prepare call for dqagpe. 231 // 232 limit = (leniw-npts2)/2; 233 l1 = limit; 234 l2 = limit+l1; 235 l3 = limit+l2; 236 l4 = limit+l3; 237 // 238 qagpe!(Real, Func)(f,a,b,npts2,points,epsabs,epsrel,limit,result,abserr, 239 neval,ier,work,work+l1,work+l2,work+l3,work+l4, 240 iwork,iwork+l1,iwork+l2,last); 241 // 242 // call error handler if necessary. 243 // 244 l10: if(ier != 0) 245 throw new Exception("abnormal return from qagp: "~to!string(ier)); 246 return; 247 } 248 249 unittest 250 { 251 alias qagp!(float, float delegate(float)) fqagp; 252 alias qagp!(double, double delegate(double)) dqagp; 253 alias qagp!(double, double function(double)) dfqagp; 254 alias qagp!(real, real delegate(real)) rqagp; 255 } 256 257 unittest 258 { 259 260 double f(double x) 261 { 262 return (x^^3)*log(fabs(((x^^2)-1) * ((x^^2)-2))); 263 } 264 265 enum : double 266 { 267 a = 0.0, 268 b = 3.0, 269 epsabs = 0.0, 270 epsrel = 1e-10, 271 } 272 double[] points = [1.0, sqrt(2.0)]; // Singularities 273 double result, abserr; 274 int neval, ier, last; 275 enum 276 { 277 leniw = 1000, 278 lenw = leniw*2, 279 } 280 int[leniw] iwork; 281 double[lenw] work; 282 283 qagp(&f, a, b, toInt(points.length), points.ptr, epsabs, epsrel, 284 result, abserr, neval, ier, leniw, lenw, last, iwork.ptr, work.ptr); 285 286 double ans = 61*log(2.0) + 77*log(7.0)/4 - 27; 287 assert (isAccurate(result, abserr, ans, epsrel, epsabs)); 288 }