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