1 #include "ctl.h"
2 
3 #ifdef CTL_HAS_COMPLEX_INTEGRATION
4 
5 /*
6  * Copyright (c) 2005 Steven G. Johnson
7  *
8  * Portions (see comments) based on HIntLib (also distributed under
9  * the GNU GPL, v2 or later), copyright (c) 2002-2005 Rudolf Schuerer.
10  *     (http://www.cosy.sbg.ac.at/~rschuer/hintlib/)
11  *
12  * Portions (see comments) based on GNU GSL (also distributed under
13  * the GNU GPL, v2 or later), copyright (c) 1996-2000 Brian Gough.
14  *     (http://www.gnu.org/software/gsl/)
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  *
30  */
31 
32 /* As integrator.c, but integrates complex-valued integrands */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <math.h>
37 #include <limits.h>
38 #include <float.h>
39 
40 /* Adaptive multidimensional integration on hypercubes (or, really,
41    hyper-rectangles) using cubature rules.
42 
43    A cubature rule takes a function and a hypercube and evaluates
44    the function at a small number of points, returning an estimate
45    of the integral as well as an estimate of the error, and also
46    a suggested dimension of the hypercube to subdivide.
47 
48    Given such a rule, the adaptive integration is simple:
49 
50    1) Evaluate the cubature rule on the hypercube(s).
51       Stop if converged.
52 
53    2) Pick the hypercube with the largest estimated error,
54       and divide it in two along the suggested dimension.
55 
56    3) Goto (1).
57 
58 */
59 
60 /* numeric type for integrand */
61 #include <complex.h>
62 typedef complex double num;
63 #define num_abs cabs
64 
65 typedef num (*integrand)(unsigned ndim, const double *x, void *);
66 
67 /* Integrate the function f from xmin[dim] to xmax[dim], with at most
68    maxEval function evaluations (0 for no limit), until the given
69    absolute or relative error is achieved.  val returns the integral,
70    and err returns the estimate for the absolute error in val.  The
71    return value of the function is 0 on success and non-zero if there
72    was an error. */
73 static int adapt_integrate(integrand f, void *fdata, unsigned dim, const double *xmin,
74                            const double *xmax, unsigned maxEval, double reqAbsError,
75                            double reqRelError, num *val, double *err);
76 
77 /***************************************************************************/
78 /* Basic datatypes */
79 
80 typedef struct {
81   num val;
82   double err;
83 } esterr;
84 
relError(esterr ee)85 static double relError(esterr ee) { return (ee.val == 0.0 ? HUGE_VAL : num_abs(ee.err / ee.val)); }
86 
87 typedef struct {
88   unsigned dim;
89   double *data; /* length 2*dim = center followed by half-widths */
90   double vol;   /* cache volume = product of widths */
91 } hypercube;
92 
compute_vol(const hypercube * h)93 static double compute_vol(const hypercube *h) {
94   unsigned i;
95   double vol = 1;
96   for (i = 0; i < h->dim; ++i)
97     vol *= 2 * h->data[i + h->dim];
98   return vol;
99 }
100 
make_hypercube(unsigned dim,const double * center,const double * halfwidth)101 static hypercube make_hypercube(unsigned dim, const double *center, const double *halfwidth) {
102   unsigned i;
103   hypercube h;
104   h.dim = dim;
105   h.data = (double *)malloc(sizeof(double) * dim * 2);
106   for (i = 0; i < dim; ++i) {
107     h.data[i] = center[i];
108     h.data[i + dim] = halfwidth[i];
109   }
110   h.vol = compute_vol(&h);
111   return h;
112 }
113 
make_hypercube_range(unsigned dim,const double * xmin,const double * xmax)114 static hypercube make_hypercube_range(unsigned dim, const double *xmin, const double *xmax) {
115   hypercube h = make_hypercube(dim, xmin, xmax);
116   unsigned i;
117   for (i = 0; i < dim; ++i) {
118     h.data[i] = 0.5 * (xmin[i] + xmax[i]);
119     h.data[i + dim] = 0.5 * (xmax[i] - xmin[i]);
120   }
121   h.vol = compute_vol(&h);
122   return h;
123 }
124 
destroy_hypercube(hypercube * h)125 static void destroy_hypercube(hypercube *h) {
126   free(h->data);
127   h->dim = 0;
128 }
129 
130 typedef struct {
131   hypercube h;
132   esterr ee;
133   unsigned splitDim;
134 } region;
135 
make_region(const hypercube * h)136 static region make_region(const hypercube *h) {
137   region R;
138   R.h = make_hypercube(h->dim, h->data, h->data + h->dim);
139   R.splitDim = 0;
140   return R;
141 }
142 
destroy_region(region * R)143 static void destroy_region(region *R) { destroy_hypercube(&R->h); }
144 
cut_region(region * R,region * R2)145 static void cut_region(region *R, region *R2) {
146   unsigned d = R->splitDim, dim = R->h.dim;
147   *R2 = *R;
148   R->h.data[d + dim] *= 0.5;
149   R->h.vol *= 0.5;
150   R2->h = make_hypercube(dim, R->h.data, R->h.data + dim);
151   R->h.data[d] -= R->h.data[d + dim];
152   R2->h.data[d] += R->h.data[d + dim];
153 }
154 
155 typedef struct rule_s {
156   unsigned dim;        /* the dimensionality */
157   unsigned num_points; /* number of evaluation points */
158   unsigned (*evalError)(struct rule_s *r, integrand f, void *fdata, const hypercube *h, esterr *ee);
159   void (*destroy)(struct rule_s *r);
160 } rule;
161 
destroy_rule(rule * r)162 static void destroy_rule(rule *r) {
163   if (r->destroy) r->destroy(r);
164   free(r);
165 }
166 
eval_region(region R,integrand f,void * fdata,rule * r)167 static region eval_region(region R, integrand f, void *fdata, rule *r) {
168   R.splitDim = r->evalError(r, f, fdata, &R.h, &R.ee);
169   return R;
170 }
171 
172 /***************************************************************************/
173 /* Functions to loop over points in a hypercube. */
174 
175 /* Based on orbitrule.cpp in HIntLib-0.0.10 */
176 
177 /* ls0 returns the least-significant 0 bit of n (e.g. it returns
178    0 if the LSB is 0, it returns 1 if the 2 LSBs are 01, etcetera). */
179 
180 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
181 /* use x86 bit-scan instruction, based on count_trailing_zeros()
182    macro in GNU GMP's longlong.h. */
ls0(unsigned n)183 static unsigned ls0(unsigned n) {
184   unsigned count;
185   n = ~n;
186   __asm__("bsfl %1,%0" : "=r"(count) : "rm"(n));
187   return count;
188 }
189 #else
ls0(unsigned n)190 static unsigned ls0(unsigned n) {
191   const unsigned bits[256] = {
192       0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0,
193       1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1,
194       0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0,
195       3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,
196       0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0,
197       1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1,
198       0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,
199       2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,
200       0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 8,
201   };
202   unsigned bit = 0;
203   while ((n & 0xff) == 0xff) {
204     n >>= 8;
205     bit += 8;
206   }
207   return bit + bits[n & 0xff];
208 }
209 #endif
210 
211 /**
212  *  Evaluate the integral on all 2^n points (+/-r,...+/-r)
213  *
214  *  A Gray-code ordering is used to minimize the number of coordinate updates
215  *  in p.
216  */
evalR_Rfs(integrand f,void * fdata,unsigned dim,double * p,const double * c,const double * r)217 static num evalR_Rfs(integrand f, void *fdata, unsigned dim, double *p, const double *c,
218                      const double *r) {
219   num sum = 0;
220   unsigned i;
221   unsigned signs = 0; /* 0/1 bit = +/- for corresponding element of r[] */
222 
223   /* We start with the point where r is ADDed in every coordinate
224      (this implies signs=0). */
225   for (i = 0; i < dim; ++i)
226     p[i] = c[i] + r[i];
227 
228   /* Loop through the points in Gray-code ordering */
229   for (i = 0;; ++i) {
230     unsigned mask, d;
231 
232     sum += f(dim, p, fdata);
233 
234     d = ls0(i); /* which coordinate to flip */
235     if (d >= dim) break;
236 
237     /* flip the d-th bit and add/subtract r[d] */
238     mask = 1U << d;
239     signs ^= mask;
240     p[d] = (signs & mask) ? c[d] - r[d] : c[d] + r[d];
241   }
242   return sum;
243 }
244 
evalRR0_0fs(integrand f,void * fdata,unsigned dim,double * p,const double * c,const double * r)245 static num evalRR0_0fs(integrand f, void *fdata, unsigned dim, double *p, const double *c,
246                        const double *r) {
247   unsigned i, j;
248   num sum = 0;
249 
250   for (i = 0; i < dim - 1; ++i) {
251     p[i] = c[i] - r[i];
252     for (j = i + 1; j < dim; ++j) {
253       p[j] = c[j] - r[j];
254       sum += f(dim, p, fdata);
255       p[i] = c[i] + r[i];
256       sum += f(dim, p, fdata);
257       p[j] = c[j] + r[j];
258       sum += f(dim, p, fdata);
259       p[i] = c[i] - r[i];
260       sum += f(dim, p, fdata);
261 
262       p[j] = c[j]; /* Done with j -> Restore p[j] */
263     }
264     p[i] = c[i]; /* Done with i -> Restore p[i] */
265   }
266   return sum;
267 }
268 
evalR0_0fs4d(integrand f,void * fdata,unsigned dim,double * p,const double * c,num * sum0_,const double * r1,num * sum1_,const double * r2,num * sum2_)269 static unsigned evalR0_0fs4d(integrand f, void *fdata, unsigned dim, double *p, const double *c,
270                              num *sum0_, const double *r1, num *sum1_, const double *r2,
271                              num *sum2_) {
272   double maxdiff = 0;
273   unsigned i, dimDiffMax = 0;
274   num sum0, sum1 = 0, sum2 = 0; /* copies for aliasing, performance */
275 
276   double ratio = r1[0] / r2[0];
277 
278   ratio *= ratio;
279   sum0 = f(dim, p, fdata);
280 
281   for (i = 0; i < dim; i++) {
282     num f1a, f1b, f2a, f2b;
283     double diff;
284 
285     p[i] = c[i] - r1[i];
286     sum1 += (f1a = f(dim, p, fdata));
287     p[i] = c[i] + r1[i];
288     sum1 += (f1b = f(dim, p, fdata));
289     p[i] = c[i] - r2[i];
290     sum2 += (f2a = f(dim, p, fdata));
291     p[i] = c[i] + r2[i];
292     sum2 += (f2b = f(dim, p, fdata));
293     p[i] = c[i];
294 
295     diff = num_abs(f1a + f1b - 2 * sum0 - ratio * (f2a + f2b - 2 * sum0));
296 
297     if (diff > maxdiff) {
298       maxdiff = diff;
299       dimDiffMax = i;
300     }
301   }
302 
303   *sum0_ += sum0;
304   *sum1_ += sum1;
305   *sum2_ += sum2;
306 
307   return dimDiffMax;
308 }
309 
310 #define num0_0(dim) (1U)
311 #define numR0_0fs(dim) (2 * (dim))
312 #define numRR0_0fs(dim) (2 * (dim) * (dim - 1))
313 #define numR_Rfs(dim) (1U << (dim))
314 
315 /***************************************************************************/
316 /* Based on rule75genzmalik.cpp in HIntLib-0.0.10: An embedded
317    cubature rule of degree 7 (embedded rule degree 5) due to A. C. Genz
318    and A. A. Malik.  See:
319 
320          A. C. Genz and A. A. Malik, "An imbedded [sic] family of fully
321          symmetric numerical integration rules," SIAM
322          J. Numer. Anal. 20 (3), 580-588 (1983).
323 */
324 
325 typedef struct {
326   rule parent;
327 
328   /* temporary arrays of length dim */
329   double *widthLambda, *widthLambda2, *p;
330 
331   /* dimension-dependent constants */
332   double weight1, weight3, weight5;
333   double weightE1, weightE3;
334 } rule75genzmalik;
335 
336 #define real(x) ((double)(x))
337 #define to_int(n) ((int)(n))
338 
isqr(int x)339 static int isqr(int x) { return x * x; }
340 
destroy_rule75genzmalik(rule * r_)341 static void destroy_rule75genzmalik(rule *r_) {
342   rule75genzmalik *r = (rule75genzmalik *)r_;
343   free(r->p);
344 }
345 
rule75genzmalik_evalError(rule * r_,integrand f,void * fdata,const hypercube * h,esterr * ee)346 static unsigned rule75genzmalik_evalError(rule *r_, integrand f, void *fdata, const hypercube *h,
347                                           esterr *ee) {
348   /* lambda2 = sqrt(9/70), lambda4 = sqrt(9/10), lambda5 = sqrt(9/19) */
349   const double lambda2 = 0.3585685828003180919906451539079374954541;
350   const double lambda4 = 0.9486832980505137995996680633298155601160;
351   const double lambda5 = 0.6882472016116852977216287342936235251269;
352   const double weight2 = 980. / 6561.;
353   const double weight4 = 200. / 19683.;
354   const double weightE2 = 245. / 486.;
355   const double weightE4 = 25. / 729.;
356 
357   rule75genzmalik *r = (rule75genzmalik *)r_;
358   unsigned i, dimDiffMax, dim = r_->dim;
359   num sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, sum4, sum5, result, res5th;
360   const double *center = h->data;
361   const double *halfwidth = h->data + dim;
362 
363   for (i = 0; i < dim; ++i)
364     r->p[i] = center[i];
365 
366   for (i = 0; i < dim; ++i)
367     r->widthLambda2[i] = halfwidth[i] * lambda2;
368   for (i = 0; i < dim; ++i)
369     r->widthLambda[i] = halfwidth[i] * lambda4;
370 
371   /* Evaluate function in the center, in f(lambda2,0,...,0) and
372      f(lambda3=lambda4, 0,...,0).  Estimate dimension with largest error */
373   dimDiffMax = evalR0_0fs4d(f, fdata, dim, r->p, center, &sum1, r->widthLambda2, &sum2,
374                             r->widthLambda, &sum3);
375 
376   /* Calculate sum4 for f(lambda4, lambda4, 0, ...,0) */
377   sum4 = evalRR0_0fs(f, fdata, dim, r->p, center, r->widthLambda);
378 
379   /* Calculate sum5 for f(lambda5, lambda5, ..., lambda5) */
380   for (i = 0; i < dim; ++i)
381     r->widthLambda[i] = halfwidth[i] * lambda5;
382   sum5 = evalR_Rfs(f, fdata, dim, r->p, center, r->widthLambda);
383 
384   /* Calculate fifth and seventh order results */
385 
386   result = h->vol * (r->weight1 * sum1 + weight2 * sum2 + r->weight3 * sum3 + weight4 * sum4 +
387                      r->weight5 * sum5);
388   res5th = h->vol * (r->weightE1 * sum1 + weightE2 * sum2 + r->weightE3 * sum3 + weightE4 * sum4);
389 
390   ee->val = result;
391   ee->err = num_abs(res5th - result);
392 
393   return dimDiffMax;
394 }
395 
make_rule75genzmalik(unsigned dim)396 static rule *make_rule75genzmalik(unsigned dim) {
397   rule75genzmalik *r;
398 
399   if (dim < 2) return 0; /* this rule does not support 1d integrals */
400 
401   /* Because of the use of a bit-field in evalR_Rfs, we are limited
402      to be < 32 dimensions (or however many bits are in unsigned).
403      This is not a practical limitation...long before you reach
404      32 dimensions, the Genz-Malik cubature becomes excruciatingly
405      slow and is superseded by other methods (e.g. Monte-Carlo). */
406   if (dim >= sizeof(unsigned) * 8) return 0;
407 
408   r = (rule75genzmalik *)malloc(sizeof(rule75genzmalik));
409   r->parent.dim = dim;
410 
411   r->weight1 = (real(12824 - 9120 * to_int(dim) + 400 * isqr(to_int(dim))) / real(19683));
412   r->weight3 = real(1820 - 400 * to_int(dim)) / real(19683);
413   r->weight5 = real(6859) / real(19683) / real(1U << dim);
414   r->weightE1 = (real(729 - 950 * to_int(dim) + 50 * isqr(to_int(dim))) / real(729));
415   r->weightE3 = real(265 - 100 * to_int(dim)) / real(1458);
416 
417   r->p = (double *)malloc(sizeof(double) * dim * 3);
418   r->widthLambda = r->p + dim;
419   r->widthLambda2 = r->p + 2 * dim;
420 
421   r->parent.num_points = num0_0(dim) + 2 * numR0_0fs(dim) + numRR0_0fs(dim) + numR_Rfs(dim);
422 
423   r->parent.evalError = rule75genzmalik_evalError;
424   r->parent.destroy = destroy_rule75genzmalik;
425 
426   return (rule *)r;
427 }
428 
429 /***************************************************************************/
430 /* 1d 15-point Gaussian quadrature rule, based on qk15.c and qk.c in
431    GNU GSL (which in turn is based on QUADPACK). */
432 
rule15gauss_evalError(rule * r,integrand f,void * fdata,const hypercube * h,esterr * ee)433 static unsigned rule15gauss_evalError(rule *r, integrand f, void *fdata, const hypercube *h,
434                                       esterr *ee) {
435   /* Gauss quadrature weights and kronrod quadrature abscissae and
436      weights as evaluated with 80 decimal digit arithmetic by
437      L. W. Fullerton, Bell Labs, Nov. 1981. */
438   const unsigned n = 8;
439   const double xgk[8] = {
440       /* abscissae of the 15-point kronrod rule */
441       0.991455371120812639206854697526329,
442       0.949107912342758524526189684047851,
443       0.864864423359769072789712788640926,
444       0.741531185599394439863864773280788,
445       0.586087235467691130294144838258730,
446       0.405845151377397166906606412076961,
447       0.207784955007898467600689403773245,
448       0.000000000000000000000000000000000
449       /* xgk[1], xgk[3], ... abscissae of the 7-point gauss rule.
450          xgk[0], xgk[2], ... to optimally extend the 7-point gauss rule */
451   };
452   static const double wg[4] = {
453       /* weights of the 7-point gauss rule */
454       0.129484966168869693270611432679082, 0.279705391489276667901467771423780,
455       0.381830050505118944950369775488975, 0.417959183673469387755102040816327};
456   static const double wgk[8] = {
457       /* weights of the 15-point kronrod rule */
458       0.022935322010529224963732008058970, 0.063092092629978553290700663189204,
459       0.104790010322250183839876322541518, 0.140653259715525918745189590510238,
460       0.169004726639267902826583426598550, 0.190350578064785409913256402421014,
461       0.204432940075298892414161999234649, 0.209482141084727828012999174891714};
462 
463   const double center = h->data[0];
464   const double halfwidth = h->data[1];
465   double fv1[7], fv2[7];
466   const num f_center = f(1, &center, fdata);
467   num result_gauss = f_center * wg[n / 2 - 1];
468   num result_kronrod = f_center * wgk[n - 1];
469   double result_abs = num_abs(result_kronrod);
470   num mean;
471   double result_asc, err;
472   unsigned j;
473 
474   for (j = 0; j < (n - 1) / 2; ++j) {
475     int j2 = 2 * j + 1;
476     double x, w = halfwidth * xgk[j2];
477     num f1, f2, fsum;
478     x = center - w;
479     fv1[j2] = f1 = f(1, &x, fdata);
480     x = center + w;
481     fv2[j2] = f2 = f(1, &x, fdata);
482     fsum = f1 + f2;
483     result_gauss += wg[j] * fsum;
484     result_kronrod += wgk[j2] * fsum;
485     result_abs += wgk[j2] * (num_abs(f1) + num_abs(f2));
486   }
487 
488   for (j = 0; j < n / 2; ++j) {
489     int j2 = 2 * j;
490     double x, w = halfwidth * xgk[j2];
491     num f1, f2;
492     x = center - w;
493     fv1[j2] = f1 = f(1, &x, fdata);
494     x = center + w;
495     fv2[j2] = f2 = f(1, &x, fdata);
496     result_kronrod += wgk[j2] * (f1 + f2);
497     result_abs += wgk[j2] * (num_abs(f1) + num_abs(f2));
498   }
499 
500   ee->val = result_kronrod * halfwidth;
501 
502   /* compute error estimate: */
503   mean = result_kronrod * 0.5;
504   result_asc = wgk[n - 1] * num_abs(f_center - mean);
505   for (j = 0; j < n - 1; ++j)
506     result_asc += wgk[j] * (num_abs(fv1[j] - mean) + num_abs(fv2[j] - mean));
507   err = num_abs(result_kronrod - result_gauss) * halfwidth;
508   result_abs *= halfwidth;
509   result_asc *= halfwidth;
510   if (result_asc != 0 && err != 0) {
511     double scale = pow((200 * err / result_asc), 1.5);
512     if (scale < 1)
513       err = result_asc * scale;
514     else
515       err = result_asc;
516   }
517   if (result_abs > DBL_MIN / (50 * DBL_EPSILON)) {
518     double min_err = 50 * DBL_EPSILON * result_abs;
519     if (min_err > err) err = min_err;
520   }
521   ee->err = err;
522 
523   return 0; /* no choice but to divide 0th dimension */
524 }
525 
make_rule15gauss(unsigned dim)526 static rule *make_rule15gauss(unsigned dim) {
527   rule *r;
528   if (dim != 1) return 0; /* this rule is only for 1d integrals */
529   r = (rule *)malloc(sizeof(rule));
530   r->dim = dim;
531   r->num_points = 15;
532   r->evalError = rule15gauss_evalError;
533   r->destroy = 0;
534   return r;
535 }
536 
537 /***************************************************************************/
538 /* binary heap implementation (ala _Introduction to Algorithms_ by
539    Cormen, Leiserson, and Rivest), for use as a priority queue of
540    regions to integrate. */
541 
542 typedef region heap_item;
543 #define KEY(hi) ((hi).ee.err)
544 
545 typedef struct {
546   unsigned n, nalloc;
547   heap_item *items;
548   esterr ee;
549 } heap;
550 
heap_resize(heap * h,unsigned nalloc)551 static void heap_resize(heap *h, unsigned nalloc) {
552   h->nalloc = nalloc;
553   h->items = (heap_item *)realloc(h->items, sizeof(heap_item) * nalloc);
554 }
555 
heap_alloc(unsigned nalloc)556 static heap heap_alloc(unsigned nalloc) {
557   heap h;
558   h.n = 0;
559   h.nalloc = 0;
560   h.items = 0;
561   h.ee.val = h.ee.err = 0;
562   heap_resize(&h, nalloc);
563   return h;
564 }
565 
566 /* note that heap_free does not deallocate anything referenced by the items */
heap_free(heap * h)567 static void heap_free(heap *h) {
568   h->n = 0;
569   heap_resize(h, 0);
570 }
571 
heap_push(heap * h,heap_item hi)572 static void heap_push(heap *h, heap_item hi) {
573   int insert;
574 
575   h->ee.val += hi.ee.val;
576   h->ee.err += hi.ee.err;
577   insert = h->n;
578   if (++(h->n) > h->nalloc) heap_resize(h, h->n * 2);
579 
580   while (insert) {
581     int parent = (insert - 1) / 2;
582     if (KEY(hi) <= KEY(h->items[parent])) break;
583     h->items[insert] = h->items[parent];
584     insert = parent;
585   }
586   h->items[insert] = hi;
587 }
588 
heap_pop(heap * h)589 static heap_item heap_pop(heap *h) {
590   heap_item ret;
591   int i, n, child;
592 
593   if (!(h->n)) {
594     fprintf(stderr, "attempted to pop an empty heap\n");
595     exit(EXIT_FAILURE);
596   }
597 
598   ret = h->items[0];
599   h->items[i = 0] = h->items[n = --(h->n)];
600   while ((child = i * 2 + 1) < n) {
601     int largest;
602     heap_item swap;
603 
604     if (KEY(h->items[child]) <= KEY(h->items[i]))
605       largest = i;
606     else
607       largest = child;
608     if (++child < n && KEY(h->items[largest]) < KEY(h->items[child])) largest = child;
609     if (largest == i) break;
610     swap = h->items[i];
611     h->items[i] = h->items[largest];
612     h->items[i = largest] = swap;
613   }
614 
615   h->ee.val -= ret.ee.val;
616   h->ee.err -= ret.ee.err;
617   return ret;
618 }
619 
620 /***************************************************************************/
621 
622 /* adaptive integration, analogous to adaptintegrator.cpp in HIntLib */
623 
ruleadapt_integrate(rule * r,integrand f,void * fdata,const hypercube * h,unsigned maxEval,double reqAbsError,double reqRelError,esterr * ee)624 static int ruleadapt_integrate(rule *r, integrand f, void *fdata, const hypercube *h,
625                                unsigned maxEval, double reqAbsError, double reqRelError,
626                                esterr *ee) {
627   unsigned maxIter; /* maximum number of adaptive subdivisions */
628   heap regions;
629   unsigned i;
630   int status = -1; /* = ERROR */
631 
632   if (maxEval) {
633     if (r->num_points > maxEval) return status; /* ERROR */
634     maxIter = (maxEval - r->num_points) / (2 * r->num_points);
635   }
636   else
637     maxIter = UINT_MAX;
638 
639   regions = heap_alloc(1);
640 
641   heap_push(&regions, eval_region(make_region(h), f, fdata, r));
642   /* another possibility is to specify some non-adaptive subdivisions:
643      if (initialRegions != 1)
644         partition(h, initialRegions, EQUIDISTANT, &regions, f,fdata, r); */
645 
646   for (i = 0; i < maxIter; ++i) {
647     region R, R2;
648     if (regions.ee.err <= reqAbsError || relError(regions.ee) <= reqRelError) {
649       status = 0; /* converged! */
650       break;
651     }
652     R = heap_pop(&regions); /* get worst region */
653     cut_region(&R, &R2);
654     heap_push(&regions, eval_region(R, f, fdata, r));
655     heap_push(&regions, eval_region(R2, f, fdata, r));
656   }
657 
658   ee->val = ee->err = 0; /* re-sum integral and errors */
659   for (i = 0; i < regions.n; ++i) {
660     ee->val += regions.items[i].ee.val;
661     ee->err += regions.items[i].ee.err;
662     destroy_region(&regions.items[i]);
663   }
664   /* printf("regions.nalloc = %d\n", regions.nalloc); */
665   heap_free(&regions);
666 
667   return status;
668 }
669 
adapt_integrate(integrand f,void * fdata,unsigned dim,const double * xmin,const double * xmax,unsigned maxEval,double reqAbsError,double reqRelError,num * val,double * err)670 static int adapt_integrate(integrand f, void *fdata, unsigned dim, const double *xmin,
671                            const double *xmax, unsigned maxEval, double reqAbsError,
672                            double reqRelError, num *val, double *err) {
673   rule *r;
674   hypercube h;
675   esterr ee;
676   int status;
677 
678   if (dim == 0) { /* trivial integration */
679     *val = f(0, xmin, fdata);
680     *err = 0;
681     return 0;
682   }
683   r = dim == 1 ? make_rule15gauss(dim) : make_rule75genzmalik(dim);
684   if (!r) {
685     *val = 0;
686     *err = HUGE_VAL;
687     return -2; /* ERROR */
688   }
689   h = make_hypercube_range(dim, xmin, xmax);
690   status = ruleadapt_integrate(r, f, fdata, &h, maxEval, reqAbsError, reqRelError, &ee);
691   *val = ee.val;
692   *err = ee.err;
693   destroy_hypercube(&h);
694   destroy_rule(r);
695   return status;
696 }
697 
698 /***************************************************************************/
699 
700 /* Compile with -DTEST_INTEGRATOR for a self-contained test program.
701 
702    Usage: ./integrator <dim> <tol> <integrand> <maxeval>
703 
704    where <dim> = # dimensions, <tol> = relative tolerance,
705    <integrand> is either 0/1/2 for the three test integrands (see below),
706    and <maxeval> is the maximum # function evaluations (0 for none).
707 */
708 
709 #ifdef TEST_INTEGRATOR
710 
711 int count = 0;
712 int which_integrand = 0;
713 const double radius = 0.50124145262344534123412; /* random */
714 
715 /* Simple constant function */
fconst(double x[],size_t dim,void * params)716 num fconst(double x[], size_t dim, void *params) { return 1; }
717 
718 /*** f0, f1, f2, and f3 are test functions from the Monte-Carlo
719      integration routines in GSL 1.6 (monte/test.c).  Copyright (c)
720      1996-2000 Michael Booth, GNU GPL. ****/
721 
722 /* Simple product function */
f0(unsigned dim,const double * x,void * params)723 num f0(unsigned dim, const double *x, void *params) {
724   double prod = 1.0;
725   unsigned int i;
726   for (i = 0; i < dim; ++i)
727     prod *= 2.0 * x[i];
728   return prod;
729 }
730 
731 /* Gaussian centered at 1/2. */
f1(unsigned dim,const double * x,void * params)732 num f1(unsigned dim, const double *x, void *params) {
733   double a = *(double *)params;
734   double sum = 0.;
735   unsigned int i;
736   for (i = 0; i < dim; i++) {
737     double dx = x[i] - 0.5;
738     sum += dx * dx;
739   }
740   return (pow(M_2_SQRTPI / (2. * a), (double)dim) * exp(-sum / (a * a)));
741 }
742 
743 /* double gaussian */
f2(unsigned dim,const double * x,void * params)744 num f2(unsigned dim, const double *x, void *params) {
745   double a = *(double *)params;
746   double sum1 = 0.;
747   double sum2 = 0.;
748   unsigned int i;
749   for (i = 0; i < dim; i++) {
750     double dx1 = x[i] - 1. / 3.;
751     double dx2 = x[i] - 2. / 3.;
752     sum1 += dx1 * dx1;
753     sum2 += dx2 * dx2;
754   }
755   return 0.5 * pow(M_2_SQRTPI / (2. * a), dim) * (exp(-sum1 / (a * a)) + exp(-sum2 / (a * a)));
756 }
757 
758 /* Tsuda's example */
f3(unsigned dim,const double * x,void * params)759 num f3(unsigned dim, const double *x, void *params) {
760   double c = *(double *)params;
761   double prod = 1.;
762   unsigned int i;
763   for (i = 0; i < dim; i++)
764     prod *= c / (c + 1) * pow((c + 1) / (c + x[i]), 2.0);
765   return prod;
766 }
767 
768 /*** end of GSL test functions ***/
769 
f_test(unsigned dim,const double * x,void * data)770 num f_test(unsigned dim, const double *x, void *data) {
771   double val;
772   unsigned i;
773   ++count;
774   switch (which_integrand) {
775     case 0: /* simple smooth (separable) objective: prod. cos(x[i]). */
776       val = 1;
777       for (i = 0; i < dim; ++i)
778         val *= cos(x[i]);
779       break;
780     case 1: { /* integral of exp(-x^2), rescaled to (0,infinity) limits */
781       double scale = 1.0;
782       val = 0;
783       for (i = 0; i < dim; ++i) {
784         double z = (1 - x[i]) / x[i];
785         val += z * z;
786         scale *= M_2_SQRTPI / (x[i] * x[i]);
787       }
788       val = exp(-val) * scale;
789       break;
790     }
791     case 2: /* discontinuous objective: volume of hypersphere */
792       val = 0;
793       for (i = 0; i < dim; ++i)
794         val += x[i] * x[i];
795       val = val < radius * radius;
796       break;
797     case 3: val = f0(dim, x, data); break;
798     case 4: val = f1(dim, x, data); break;
799     case 5: val = f2(dim, x, data); break;
800     case 6: val = f3(dim, x, data); break;
801     default: fprintf(stderr, "unknown integrand %d\n", which_integrand); exit(EXIT_FAILURE);
802   }
803   /* if (count < 100) printf("%d: f(%g, ...) = %g\n", count, x[0], val); */
804   return val;
805 }
806 
807 /* surface area of n-dimensional unit hypersphere */
S(unsigned n)808 static double S(unsigned n) {
809   double val;
810   int fact = 1;
811   if (n % 2 == 0) { /* n even */
812     val = 2 * pow(M_PI, n * 0.5);
813     n = n / 2;
814     while (n > 1)
815       fact *= (n -= 1);
816     val /= fact;
817   }
818   else { /* n odd */
819     val = (1 << (n / 2 + 1)) * pow(M_PI, n / 2);
820     while (n > 2)
821       fact *= (n -= 2);
822     val /= fact;
823   }
824   return val;
825 }
826 
exact_integral(unsigned dim,const double * xmax)827 static num exact_integral(unsigned dim, const double *xmax) {
828   unsigned i;
829   double val;
830   switch (which_integrand) {
831     case 0:
832       val = 1;
833       for (i = 0; i < dim; ++i)
834         val *= sin(xmax[i]);
835       break;
836     case 2: val = dim == 0 ? 1 : S(dim) * pow(radius * 0.5, dim) / dim; break;
837     default: val = 1.0;
838   }
839   return val;
840 }
841 
main(int argc,char ** argv)842 int main(int argc, char **argv) {
843   double *xmin, *xmax;
844   double tol, err;
845   num val;
846   unsigned i, dim, maxEval;
847   double fdata;
848 
849   dim = argc > 1 ? atoi(argv[1]) : 2;
850   tol = argc > 2 ? atof(argv[2]) : 1e-2;
851   which_integrand = argc > 3 ? atoi(argv[3]) : 0;
852   maxEval = argc > 4 ? atoi(argv[4]) : 0;
853 
854   fdata = which_integrand == 6 ? (1.0 + sqrt(10.0)) / 9.0 : 0.1;
855 
856   xmin = (double *)malloc(dim * sizeof(double));
857   xmax = (double *)malloc(dim * sizeof(double));
858   for (i = 0; i < dim; ++i) {
859     xmin[i] = 0;
860     xmax[i] = 1 + (which_integrand >= 1 ? 0 : 0.4 * sin(i));
861   }
862 
863   printf("%u-dim integral, tolerance = %g, integrand = %d\n", dim, tol, which_integrand);
864   adapt_integrate(f_test, &fdata, dim, xmin, xmax, maxEval, 0, tol, &val, &err);
865   printf("integration val = %g, est. err = %g, true err = %g\n", val, err,
866          num_abs(val - exact_integral(dim, xmax)));
867   printf("#evals = %d\n", count);
868 
869   free(xmax);
870   free(xmin);
871 
872   return 0;
873 }
874 
875 #else
876 
877 /*************************************************************************/
878 /* libctl interface */
879 
880 static int adapt_integrate(integrand f, void *fdata, unsigned dim, const double *xmin,
881                            const double *xmax, unsigned maxEval, double reqAbsError,
882                            double reqRelError, num *val, double *err);
883 
884 typedef struct {
885   cmultivar_func f;
886   void *fdata;
887 } cnum_wrap_data;
888 
cnum_wrap(unsigned ndim,const double * x,void * fdata_)889 static num cnum_wrap(unsigned ndim, const double *x, void *fdata_) {
890   cnum_wrap_data *fdata = (cnum_wrap_data *)fdata_;
891   cnumber val = fdata->f(ndim, (double *)x, fdata->fdata);
892   return (cnumber_re(val) + I * cnumber_im(val));
893 }
894 
cadaptive_integration(cmultivar_func f,number * xmin,number * xmax,integer n,void * fdata,number abstol,number reltol,integer maxnfe,number * esterr,integer * errflag)895 cnumber cadaptive_integration(cmultivar_func f, number *xmin, number *xmax, integer n, void *fdata,
896                               number abstol, number reltol, integer maxnfe, number *esterr,
897                               integer *errflag) {
898   num val;
899   cnum_wrap_data wdata;
900   wdata.f = f;
901   wdata.fdata = fdata;
902   *errflag =
903       adapt_integrate(cnum_wrap, &wdata, n, xmin, xmax, maxnfe, abstol, reltol, &val, esterr);
904   return make_cnumber(creal(val), cimag(val));
905 }
906 
cf_scm_wrapper(integer n,number * x,void * f_scm_p)907 static cnumber cf_scm_wrapper(integer n, number *x, void *f_scm_p) {
908   SCM *f_scm = (SCM *)f_scm_p;
909   return scm2cnumber(gh_call1(*f_scm, make_number_list(n, x)));
910 }
911 
cadaptive_integration_scm(SCM f_scm,SCM xmin_scm,SCM xmax_scm,SCM abstol_scm,SCM reltol_scm,SCM maxnfe_scm)912 SCM cadaptive_integration_scm(SCM f_scm, SCM xmin_scm, SCM xmax_scm, SCM abstol_scm, SCM reltol_scm,
913                               SCM maxnfe_scm) {
914   integer n, maxnfe, errflag, i;
915   number *xmin, *xmax, abstol, reltol;
916   cnumber integral;
917 
918   n = list_length(xmin_scm);
919   abstol = fabs(ctl_convert_number_to_c(abstol_scm));
920   reltol = fabs(ctl_convert_number_to_c(reltol_scm));
921   maxnfe = ctl_convert_integer_to_c(maxnfe_scm);
922 
923   if (list_length(xmax_scm) != n) {
924     fprintf(stderr, "adaptive_integration: xmin/xmax dimension mismatch\n");
925     return SCM_UNDEFINED;
926   }
927 
928   xmin = (number *)malloc(sizeof(number) * n);
929   xmax = (number *)malloc(sizeof(number) * n);
930   if (!xmin || !xmax) {
931     fprintf(stderr, "adaptive_integration: error, out of memory!\n");
932     exit(EXIT_FAILURE);
933   }
934 
935   for (i = 0; i < n; ++i) {
936     xmin[i] = number_list_ref(xmin_scm, i);
937     xmax[i] = number_list_ref(xmax_scm, i);
938   }
939 
940   integral = cadaptive_integration(cf_scm_wrapper, xmin, xmax, n, &f_scm, abstol, reltol, maxnfe,
941                                    &abstol, &errflag);
942 
943   free(xmax);
944   free(xmin);
945 
946   switch (errflag) {
947     case 3: fprintf(stderr, "adaptive_integration: invalid inputs\n"); return SCM_UNDEFINED;
948     case 1: fprintf(stderr, "adaptive_integration: maxnfe too small\n"); break;
949     case 2: fprintf(stderr, "adaptive_integration: lenwork too small\n"); break;
950   }
951 
952   return gh_cons(cnumber2scm(integral), ctl_convert_number_to_scm(abstol));
953 }
954 
955 #endif
956 
957 #endif /* CTL_HAS_COMPLEX_INTEGRATION */
958