1 /*
2    (mutation) rates following a Gamma distribution
3    using orthogonal polynomials for finding rates and
4    LOG(probabilities)
5    [based on initgammacat of Joe Felsenstein]
6 
7    - Generalized Laguerre (routine by Joe Felsenstein 2000)
8      defining points for a Gamma distribution with
9      shape parameter alpha and location parameter beta=1/alpha
10      [mean=1, std = 1/alpha^2]
11    - Hermite (approximates a normal and is activated when
12      the shape parameter alpha is > 100.)
13 
14    Part of Migrate
15    http://popgen.csit.fsu.edu/migrate.html
16 
17    Peter Beerli, Seattle 2001
18 
19 Copyright 1996-2002 Peter Beerli and Joseph Felsenstein, Seattle WA
20 Copyright 2003-2005 Peter Beerli, Tallahassee FL
21 
22 Permission is hereby granted, free of charge, to any person obtaining a copy
23 of this software and associated documentation files (the "Software"), to deal
24 in the Software without restriction, including without limitation the rights
25 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
26 of the Software, and to permit persons to whom the Software is furnished to do
27 so, subject to the following conditions:
28 
29 The above copyright notice and this permission notice shall be included in all copies
30 or substantial portions of the Software.
31 
32 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
33 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
34 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
35 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
36 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
37 OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 
39 $Id: laguerre.c 2067 2012-07-27 20:59:32Z beerli $
40 */
41 /* \file laguerre.c
42 Calculates the Laguerre Quadrature points, used for gamma deviated site rate variation
43 
44 */
45 #include "migration.h"
46 #include "laguerre.h"
47 #include "tools.h"
48 #include "sighandler.h"
49 
50 #define SQRTPI 1.7724538509055160273
51 #define SQRT2  1.4142135623730950488
52 
53 
54 /*this triggers the test  main()
55 and is called with
56 gcc -DLAGUERRE_TEST -g laguerre.c -o laguerre -lm*/
57 
58 #ifdef LAGUERRE_TEST
59 /* at the end is a test main to help test if the root/weights finding
60    is OK*/
61 
62 /* if machine has lgamma() use it otherwise use lgamma from
63    tools.h*/
64 #undef LGAMMA
65 #define LGAMMA lgamma
66 
67 
68 /* for migrate this is defined in tools.h */
69 MYREAL
logfac(long n)70 logfac (long n)
71 {
72     /* log(n!) values were calculated with Mathematica
73        with a precision of 30 digits */
74     switch (n)
75     {
76     case 0:
77         return 0.;
78     case 1:
79         return 0.;
80     case 2:
81         return 0.693147180559945309417232121458;
82     case 3:
83         return 1.791759469228055000812477358381;
84     case 4:
85         return 3.1780538303479456196469416013;
86     case 5:
87         return 4.78749174278204599424770093452;
88     case 6:
89         return 6.5792512120101009950601782929;
90     case 7:
91         return 8.52516136106541430016553103635;
92     case 8:
93         return 10.60460290274525022841722740072;
94     case 9:
95         return 12.80182748008146961120771787457;
96     case 10:
97         return 15.10441257307551529522570932925;
98     case 11:
99         return 17.50230784587388583928765290722;
100     case 12:
101         return 19.98721449566188614951736238706;
102     default:
103         return LGAMMA (n + 1.);
104     }
105 }
106 #endif
107 
108 /* prototypes */
109 MYREAL hermite (long n, MYREAL x);
110 void root_hermite (long n, MYREAL *hroot);
111 MYREAL halfroot (MYREAL (*func) (long m, MYREAL x),
112                  long n, MYREAL startx, MYREAL delta);
113 void hermite_weight (long n, MYREAL *hroot, MYREAL *weights);
114 void inithermitcat (long categs, MYREAL alpha, MYREAL theta1,
115                     MYREAL *rate, MYREAL *probcat);
116 
117 MYREAL glaguerre (long m, MYREAL b, MYREAL x);
118 void initlaguerrecat (long categs, MYREAL alpha, MYREAL theta1,
119                       MYREAL *rate, MYREAL *probcat);
120 void roots_laguerre (long m, MYREAL b, MYREAL **lgroot);
121 
122 void initgammacat (long categs, MYREAL alpha, MYREAL theta1,
123                    MYREAL *rate, MYREAL *probcat);
124 
125 void integrate_laguerre (long categs, MYREAL *rate,
126                          MYREAL *probcat,
127                          MYREAL (*func) (MYREAL theta, helper_fmt * b),
128                          helper_fmt * helper, MYREAL *result, MYREAL *rmax);
129 
130 
131 /*------------------------------------------------------
132   Generalized Laguerre polynomial computed recursively.
133   For use by initgammacat
134 */
135 MYREAL
glaguerre(long m,MYREAL b,MYREAL x)136 glaguerre (long m, MYREAL b, MYREAL x)
137 {
138     long i;
139     MYREAL gln, glnm1, glnp1; /* L_n, L_(n-1), L_(n+1) */
140 
141     if (m == 0)
142         return 1.0;
143     else
144     {
145         if (m == 1)
146             return 1.0 + b - x;
147         else
148         {
149             gln = 1.0 + b - x;
150             glnm1 = 1.0;
151             for (i = 2; i <= m; i++)
152             {
153                 glnp1 =
154                     ((2 * (i - 1) + b + 1.0 - x) * gln - (i - 1 + b) * glnm1) / i;
155                 glnm1 = gln;
156                 gln = glnp1;
157             }
158             return gln;
159         }
160     }
161 }    /* glaguerre */
162 
163 
164 /* calculates hermite polynomial with degree n and parameter x */
165 /* seems to be unprecise for n>13 -> root finder does not converge*/
166 MYREAL
hermite(long n,MYREAL x)167 hermite (long n, MYREAL x)
168 {
169     MYREAL h1 = 1.;
170     MYREAL h2 = 2. * x;
171     MYREAL xx = 2. * x;
172     long i;
173     for (i = 1; i < n; i++)
174     {
175         xx = 2. * x * h2 - 2. * (i) * h1;
176         h1 = h2;
177         h2 = xx;
178     }
179     return xx;
180 }
181 
182 void
root_hermite(long n,MYREAL * hroot)183 root_hermite (long n, MYREAL *hroot)
184 {
185     long z = 0;
186     long ii;
187     long start;
188     if (n % 2 == 0)
189     {
190         start = n / 2;
191         z = 1;
192     }
193     else
194     {
195         start = n / 2 + 1;
196         z = 2;
197         hroot[start - 1] = 0.0;
198     }
199     for (ii = start; ii < n; ii++)
200     {
201         /* search only upwards */
202         hroot[ii] = halfroot (hermite, n, hroot[ii - 1] + EPSILON, 1. / n);
203         hroot[start - z] = -hroot[ii];
204         z++;
205     }
206 }
207 
208 /*searches from the bound (startx) only in one direction
209   (by positive or negative delta, which results in
210   other-bound=startx+delta)
211   delta should be small.
212   (*func) is a function with two arguments
213 */
214 MYREAL
halfroot(MYREAL (* func)(long m,MYREAL x),long n,MYREAL startx,MYREAL delta)215 halfroot (MYREAL (*func) (long m, MYREAL x),
216           long n, MYREAL startx, MYREAL delta)
217 {
218     MYREAL xl;
219     MYREAL xu;
220     MYREAL xm = 0.;
221     MYREAL fu;
222     MYREAL fl;
223     MYREAL fm = 100000.;
224     MYREAL gradient;
225     boolean down = FALSE;
226     /* decide if we search above or below startx and escapes to trace back
227        to the starting point that most often will be
228        the root from the previous calculation */
229     if (delta < 0)
230     {
231         xu = startx;
232         xl = xu + delta;
233     }
234     else
235     {
236         xl = startx;
237         xu = xl + delta;
238     }
239     delta = fabs (delta);
240     fu = (*func) (n, xu);
241     fl = (*func) (n, xl);
242     gradient = (fl - fu) / (xl - xu);
243 
244     while (fabs (fm) > EPSILON)
245     {
246         /* is root outside of our bracket? */
247         if ((fu < 0.0 && fl < 0.0) || (fu > 0.0 && fl > 0.0))
248         {
249             xu += delta;
250             fu = (*func) (n, xu);
251             fl = (*func) (n, xl);
252             gradient = (fl - fu) / (xl - xu);
253             down = gradient < 0 ? TRUE : FALSE;
254         }
255         else
256         {
257             xm = xl - fl / gradient;
258             fm = (*func) (n, xm);
259             if (down)
260             {
261                 if (fm > 0.)
262                 {
263                     xl = xm;
264                     fl = fm;
265                 }
266                 else
267                 {
268                     xu = xm;
269                     fu = fm;
270                 }
271             }
272             else
273             {
274                 if (fm > 0.)
275                 {
276                     xu = xm;
277                     fu = fm;
278                 }
279                 else
280                 {
281                     xl = xm;
282                     fl = fm;
283                 }
284             }
285             gradient = (fl - fu) / (xl - xu);
286         }
287     }
288     return xm;
289 }
290 
291 
292 // calculate the weights for the hermite polynomial
293 // at the roots
294 // using formula Abramowitz and Stegun chapter 25.4.46 p.890
295 void
hermite_weight(long n,MYREAL * hroot,MYREAL * weights)296 hermite_weight (long n, MYREAL *hroot, MYREAL *weights)
297 {
298     long i;
299     MYREAL hr2;
300     MYREAL nominator = EXP (LOG2 * (n - 1.) + logfac (n)) * SQRTPI / (n * n);
301     for (i = 0; i < n; i++)
302     {
303         hr2 = hermite (n - 1, hroot[i]);
304         weights[i] = nominator / (hr2 * hr2);
305     }
306 }
307 
308 /* calculates rates and LOG(probabilities) */
309 void
inithermitcat(long categs,MYREAL alpha,MYREAL theta1,MYREAL * rate,MYREAL * probcat)310 inithermitcat (long categs, MYREAL alpha, MYREAL theta1,
311                MYREAL *rate, MYREAL *probcat)
312 {
313     long i;
314     MYREAL *hroot;
315     MYREAL std = SQRT2 * theta1 / sqrt (alpha);
316     hroot = (MYREAL *) mycalloc (categs + 1, sizeof (MYREAL));
317     root_hermite (categs, hroot); // calculate roots
318     hermite_weight (categs, hroot, probcat); // set weights
319     for (i = 0; i < categs; i++) // set rates
320     {
321         rate[i] = theta1 + std * hroot[i];
322         probcat[i] = LOG (probcat[i]);
323     }
324     myfree(hroot);
325 }
326 
327 ///
328 /// For use by initgammacat().
329 /// Get roots of m-th Generalized Laguerre polynomial, given roots
330 /// of (m-1)-th, these are to be stored in lgroot[m][]
331 void
roots_laguerre(long m,MYREAL b,MYREAL ** lgroot)332 roots_laguerre (long m, MYREAL b, MYREAL **lgroot)
333 {
334     long i;
335     long count=0;
336     MYREAL upperl, lower, x, y;
337     boolean dwn = FALSE;
338     //MYREAL tmp;
339     /* is function declining in this interval? */
340     if (m == 1)
341     {
342         lgroot[1][1] = 1.0 + b;
343     }
344     else
345     {
346         dwn = TRUE;
347         for (i = 1; i <= m; i++)
348         {
349             if (i < m)
350             {
351                 if (i == 1)
352                     lower = 0.0;
353                 else
354                     lower = lgroot[m - 1][i - 1];
355                 upperl = lgroot[m - 1][i];
356             }
357             else
358             {   /* i == m, must search above */
359                 lower = lgroot[m - 1][i - 1];
360                 x = lgroot[m - 1][m - 1];
361                 do
362                 {
363                     x = 2.0 * x;
364                     y = glaguerre (m, b, x);
365                 }
366                 while ((dwn && (y > 0.0)) || ((!dwn) && (y < 0.0)));
367                 upperl = x;
368             }
369             count = 0;
370             while (upperl - lower > 0.000000001 && count++  < 1000)
371             {
372                 x = (upperl + lower) / 2.0;
373                 if (glaguerre (m, b, x) > 0.0)
374                 {
375                     if (dwn)
376                         lower = x;
377                     else
378                         upperl = x;
379                 }
380                 else
381                 {
382                     if (dwn)
383                         upperl = x;
384                     else
385                         lower = x;
386                 }
387             }
388             lgroot[m][i] = (lower + upperl) / 2.0;
389             dwn = !dwn;  /* switch for next one */
390         }
391     }
392 }    /* root_laguerre */
393 
394 
395 void
initgammacat(long categs,MYREAL alpha,MYREAL theta1,MYREAL * rate,MYREAL * probcat)396 initgammacat (long categs, MYREAL alpha, MYREAL theta1,
397               MYREAL *rate, MYREAL *probcat)
398 {
399     /* calculate rates and probabilities to approximate Gamma distribution
400        of rates with "categs" categories and shape parameter "alpha" using
401        rates and weights from Generalized Laguerre quadrature */
402 
403     if (alpha >= 100.)
404     {
405         inithermitcat (categs, alpha, theta1, rate, probcat);
406     }
407     else
408     {
409         initlaguerrecat (categs, alpha, theta1, rate, probcat);
410     }
411 }
412 
413 void
initlaguerrecat(long categs,MYREAL alpha,MYREAL theta1,MYREAL * rate,MYREAL * probcat)414 initlaguerrecat (long categs, MYREAL alpha, MYREAL theta1, MYREAL *rate,
415                  MYREAL *probcat)
416 {
417     long i;
418     MYREAL **lgroot;  /* roots of GLaguerre polynomials */
419     MYREAL f, x, xi, y;
420 
421     lgroot = (MYREAL **) mycalloc (categs + 1, sizeof (MYREAL *));
422     lgroot[0] =
423         (MYREAL *) mycalloc ((categs + 1) * (categs + 1), sizeof (MYREAL));
424     for (i = 1; i < categs + 1; i++)
425     {
426         lgroot[i] = lgroot[0] + i * (categs + 1);
427     }
428     lgroot[1][1] = 1.0 + alpha;
429     for (i = 2; i <= categs; i++)
430         roots_laguerre (i, alpha, lgroot); /* get roots for L^(a)_n */
431     /* here get weights */
432     /* Gamma weights are
433        (1+a)(1+a/2) ... (1+a/n)*x_i/((n+1)^2 [L_{n+1}^a(x_i)]^2)  */
434     f = 1;
435     for (i = 1; i <= categs; i++)
436         f *= (1.0 + alpha / i);
437     for (i = 1; i <= categs; i++)
438     {
439         xi = lgroot[categs][i];
440         y = glaguerre (categs + 1, alpha, xi);
441         x = f * xi / ((categs + 1) * (categs + 1) * y * y);
442         rate[i - 1] = xi / (1.0 + alpha);
443         probcat[i - 1] = x;
444     }
445     for (i = 0; i < categs; i++)
446     {
447         probcat[i] = LOG (probcat[i]);
448         rate[i] *= theta1;
449     }
450     myfree(lgroot[0]);
451     myfree(lgroot);
452 }    /* initgammacat */
453 
454 
455 void
integrate_laguerre(long categs,MYREAL * rate,MYREAL * probcat,MYREAL (* func)(MYREAL theta,helper_fmt * b),helper_fmt * helper,MYREAL * result,MYREAL * rmax)456 integrate_laguerre (long categs, MYREAL *rate,
457                     MYREAL *probcat,
458                     MYREAL (*func) (MYREAL theta, helper_fmt * b),
459                     helper_fmt * helper, MYREAL *result, MYREAL *rmax)
460 {
461     MYREAL summ = 0.;
462     long i;
463     MYREAL *temp;
464     int *stemp;
465     *rmax = -MYREAL_MAX;
466 
467     temp = (MYREAL *) mycalloc (categs, sizeof (MYREAL));
468     stemp = (int *) mycalloc (categs, sizeof (int));
469     for (i = 0; i < categs; i++)
470     {
471         temp[i] = (*func) (rate[i], /*(void *)*/ helper);
472         stemp[i] = (int) helper->sign;
473         if (temp[i] > *rmax)
474             *rmax = temp[i];
475     }
476     for (i = 0; i < categs; i++)
477     {
478         summ += ((MYREAL) stemp[i]) * probcat[i] * EXP (temp[i] - *rmax);
479     }
480     myfree(temp);
481     myfree(stemp);
482     *result = summ;
483 }
484 
485 
486 /* initgammacat test function*/
487 #ifdef LAGUERRE_TEST
488 int
main()489 main ()
490 {
491     long categs = 10;
492     MYREAL alpha;
493     MYREAL theta1;
494     MYREAL *rate;
495     MYREAL *probcat;
496     long i;
497     long retval;
498     printf ("Enter alpha, theta1,  and categs\n");
499     retval = fscanf (stdin, "%lf%lf%li", &alpha, &theta1, &categs);
500     rate = (MYREAL *) mycalloc (categs + 1, sizeof (MYREAL));
501     probcat = (MYREAL *) mycalloc (categs + 1, sizeof (MYREAL));
502     initgammacat (categs, alpha, theta1, rate, probcat);
503     printf ("Rate                   Log(prob)              Prob\n");
504     for (i = 0; i < categs; i++)
505     {
506       printf ("%20.20f %20.20f %20.20f\n", rate[i], probcat[i], exp(probcat[i]));
507     }
508     return 0;
509 }
510 #endif
511 
512 
513 
514