Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
TwoSpectSpecFunc.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2011 Evan Goetz
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19
20//Based on GSL functions to determine chi-squared inversions
21//Some functions based from Matab 2012a functions, but optimized for TwoSpect analysis
22
23#include <math.h>
24#include <gsl/gsl_math.h>
25#include <gsl/gsl_sf_log.h>
26#include <lal/LALConstants.h>
27
28#include "TwoSpectSpecFunc.h"
29
30/**
31 * Compute the Dirichlet kernel for large N values
32 * \param [in] delta The delta value as the arguement
33 * \return Complex valued Dirichlet kernel
34 */
36{
37 if ( fabs( delta ) < 1.0e-6 ) {
38 return crect( 1.0, 0.0 );
39 }
40
41 COMPLEX16 val = crect( 0.0, LAL_TWOPI * delta );
42 return ( cexp( val ) - 1.0 ) / val;
43}
44
45/**
46 * Compute the Dirichlet kernel for large N values and the Hann window
47 * \param [in] delta The delta value as the arguement
48 * \return Complex valued Dirichlet kernel
49 */
51{
52 //return DirichletKernelLargeN(delta) - 0.5*DirichletKernelLargeN(delta+1.0) - 0.5*DirichletKernelLargeN(delta-1.0);
53 if ( fabs( delta ) < 1.0e-6 ) {
54 return crect( 0.5, 0.0 );
55 } else if ( fabs( delta * delta - 1.0 ) < 1.0e-6 ) {
56 return crect( -0.25, 0.0 );
57 } else {
58 return crect( 0.0, 1.0 ) * ( cpolar( 1.0, LAL_TWOPI * delta ) - 1.0 ) / ( 2.0 * LAL_TWOPI * delta * ( delta * delta - 1.0 ) );
59 }
60}
61
62/**
63 * Compute the argument of the ratio of Dirichlet kernels for large N values and the Hann window
64 * \param [out] ratio The complex ratio
65 * \param [in] delta0 The delta0 value (denominator)
66 * \param [in] delta1 The delta1 value (numerator)
67 * \param [in] scaling The real-valued scaling
68 * \return Error code: 0 = no error, 1 = divergent value
69 */
70INT4 DirichletKernalLargeNHannRatio( COMPLEX8 *ratio, const REAL4 delta0, const REAL4 delta1, const REAL4 scaling )
71{
72 //if (fabsf((REAL4)delta1)<(REAL4)1.0e-6 || fabsf((REAL4)(delta1*delta1-1.0))<(REAL4)1.0e-6 || fabsf((REAL4)(delta0-roundf(delta0)))<(REAL4)1.0e-6) return 1;
73 //else *ratio = scaling*(cpolarf(1.0, (REAL4)(LAL_TWOPI*delta1))-1.0)/(cpolarf(1.0, (REAL4)(LAL_TWOPI*delta0))-1.0);
74 *ratio = crectf( 0.0, 0.0 );
75 if ( fabsf( delta1 ) < ( REAL4 )1.0e-6 ) {
76 if ( fabsf( delta0 ) < ( REAL4 )1.0e-6 ) {
77 *ratio = crectf( 1.0, 0.0 );
78 } else if ( fabsf( ( REAL4 )( delta0 * delta0 - 1.0 ) ) < ( REAL4 )1.0e-6 ) {
79 *ratio = crectf( -2.0, 0.0 );
80 } else if ( fabsf( delta0 - roundf( delta0 ) ) < ( REAL4 )1.0e-6 ) {
81 return 1;
82 } else {
83 *ratio = 0.5 / ( crectf( 0.0, 1.0 ) * ( cpolarf( 1.0, LAL_TWOPI * delta0 ) - 1.0 ) / ( 2.0 * LAL_TWOPI * delta0 * ( delta0 * delta0 - 1.0 ) ) );
84 }
85 } else if ( fabsf( ( REAL4 )( delta1 * delta1 - 1.0 ) ) < ( REAL4 )1.0e-6 ) {
86 if ( fabsf( delta0 ) < ( REAL4 )1.0e-6 ) {
87 *ratio = crectf( -0.5, 0.0 );
88 } else if ( fabsf( ( REAL4 )( delta0 * delta0 - 1.0 ) ) < ( REAL4 )1.0e-6 ) {
89 *ratio = crectf( 1.0, 0.0 );
90 } else if ( fabsf( delta0 - roundf( delta0 ) ) < ( REAL4 )1.0e-6 ) {
91 return 1;
92 } else {
93 *ratio = -0.25 / ( crectf( 0.0, 1.0 ) * ( cpolarf( 1.0, LAL_TWOPI * delta0 ) - 1.0 ) / ( 2.0 * LAL_TWOPI * delta0 * ( delta0 * delta0 - 1.0 ) ) );
94 }
95 } else if ( fabsf( delta0 - roundf( delta0 ) ) < ( REAL4 )1.0e-6 ) {
96 return 1;
97 } else {
98 *ratio = scaling * sinf( ( REAL4 )LAL_PI * delta1 ) / sinf( ( REAL4 )LAL_PI * delta0 ) * cpolarf( 1.0, ( REAL4 )( LAL_PI * ( delta1 - delta0 ) ) );
99 }
100 return 0;
101}
102
103/* Chebyshev coefficients for Gamma*(3/4(t+1)+1/2), -1<t<1
104 */
105static REAL8 gstar_a_data[30] = {
106 2.16786447866463034423060819465,
107 -0.05533249018745584258035832802,
108 0.01800392431460719960888319748,
109 -0.00580919269468937714480019814,
110 0.00186523689488400339978881560,
111 -0.00059746524113955531852595159,
112 0.00019125169907783353925426722,
113 -0.00006124996546944685735909697,
114 0.00001963889633130842586440945,
115 -6.3067741254637180272515795142e-06,
116 2.0288698405861392526872789863e-06,
117 -6.5384896660838465981983750582e-07,
118 2.1108698058908865476480734911e-07,
119 -6.8260714912274941677892994580e-08,
120 2.2108560875880560555583978510e-08,
121 -7.1710331930255456643627187187e-09,
122 2.3290892983985406754602564745e-09,
123 -7.5740371598505586754890405359e-10,
124 2.4658267222594334398525312084e-10,
125 -8.0362243171659883803428749516e-11,
126 2.6215616826341594653521346229e-11,
127 -8.5596155025948750540420068109e-12,
128 2.7970831499487963614315315444e-12,
129 -9.1471771211886202805502562414e-13,
130 2.9934720198063397094916415927e-13,
131 -9.8026575909753445931073620469e-14,
132 3.2116773667767153777571410671e-14,
133 -1.0518035333878147029650507254e-14,
134 3.4144405720185253938994854173e-15,
135 -1.0115153943081187052322643819e-15
136};
137static cheb_series gstar_a_cs = {
139 29,
140 -1, 1,
141 17
142};
143/* Chebyshev coefficients for
144 * x^2(Gamma*(x) - 1 - 1/(12x)), x = 4(t+1)+2, -1 < t < 1
145 */
146static REAL8 gstar_b_data[] = {
147 0.0057502277273114339831606096782,
148 0.0004496689534965685038254147807,
149 -0.0001672763153188717308905047405,
150 0.0000615137014913154794776670946,
151 -0.0000223726551711525016380862195,
152 8.0507405356647954540694800545e-06,
153 -2.8671077107583395569766746448e-06,
154 1.0106727053742747568362254106e-06,
155 -3.5265558477595061262310873482e-07,
156 1.2179216046419401193247254591e-07,
157 -4.1619640180795366971160162267e-08,
158 1.4066283500795206892487241294e-08,
159 -4.6982570380537099016106141654e-09,
160 1.5491248664620612686423108936e-09,
161 -5.0340936319394885789686867772e-10,
162 1.6084448673736032249959475006e-10,
163 -5.0349733196835456497619787559e-11,
164 1.5357154939762136997591808461e-11,
165 -4.5233809655775649997667176224e-12,
166 1.2664429179254447281068538964e-12,
167 -3.2648287937449326771785041692e-13,
168 7.1528272726086133795579071407e-14,
169 -9.4831735252566034505739531258e-15,
170 -2.3124001991413207293120906691e-15,
171 2.8406613277170391482590129474e-15,
172 -1.7245370321618816421281770927e-15,
173 8.6507923128671112154695006592e-16,
174 -3.9506563665427555895391869919e-16,
175 1.6779342132074761078792361165e-16,
176 -6.0483153034414765129837716260e-17
177};
178static cheb_series gstar_b_cs = {
180 29,
181 -1, 1,
182 18
183};
184
185
187{
188 const REAL8 a[8] = { 3.387132872796366608, 133.14166789178437745,
189 1971.5909503065514427, 13731.693765509461125,
190 45921.953931549871457, 67265.770927008700853,
191 33430.575583588128105, 2509.0809287301226727
192 };
193
194 const REAL8 b[8] = { 1.0, 42.313330701600911252,
195 687.1870074920579083, 5394.1960214247511077,
196 21213.794301586595867, 39307.89580009271061,
197 28729.085735721942674, 5226.495278852854561
198 };
199
200 REAL8 r = 0.180625 - q * q;
201
202 REAL8 x = q * rat_eval( a, 8, b, 8, r );
203
204 return x;
205}
207{
208 const REAL8 a[] = { 1.42343711074968357734, 4.6303378461565452959,
209 5.7694972214606914055, 3.64784832476320460504,
210 1.27045825245236838258, 0.24178072517745061177,
211 0.0227238449892691845833, 7.7454501427834140764e-4
212 };
213
214 const REAL8 b[] = { 1.0, 2.05319162663775882187,
215 1.6763848301838038494, 0.68976733498510000455,
216 0.14810397642748007459, 0.0151986665636164571966,
217 5.475938084995344946e-4, 1.05075007164441684324e-9
218 };
219
220 REAL8 x = rat_eval( a, 8, b, 8, ( r - 1.6 ) );
221
222 return x;
223}
225{
226 const REAL8 a[] = { 6.6579046435011037772, 5.4637849111641143699,
227 1.7848265399172913358, 0.29656057182850489123,
228 0.026532189526576123093, 0.0012426609473880784386,
229 2.71155556874348757815e-5, 2.01033439929228813265e-7
230 };
231
232 const REAL8 b[] = { 1.0, 0.59983220655588793769,
233 0.13692988092273580531, 0.0148753612908506148525,
234 7.868691311456132591e-4, 1.8463183175100546818e-5,
235 1.4215117583164458887e-7, 2.04426310338993978564e-15
236 };
237
238 REAL8 x = rat_eval( a, 8, b, 8, ( r - 5.0 ) );
239
240 return x;
241}
242REAL8 rat_eval( const REAL8 a[], const size_t na, const REAL8 b[], const size_t nb, const REAL8 x )
243{
244 size_t i, j;
245 REAL8 u, v, r;
246
247 u = a[na - 1];
248
249 for ( i = na - 1; i > 0; i-- ) {
250 u = x * u + a[i - 1];
251 }
252
253 v = b[nb - 1];
254
255 for ( j = nb - 1; j > 0; j-- ) {
256 v = x * v + b[j - 1];
257 }
258
259 r = u / v;
260
261 return r;
262}
263
265{
266 if ( x < 0.0 ) {
267 return 0.0;
268 } else if ( x == 0.0 ) {
269 if ( a == 1.0 ) {
270 return 1.0 / b ;
271 } else {
272 return 0.0;
273 }
274 } else if ( a == 1.0 ) {
275 return ( exp( -x / b ) / b );
276 } else {
277 return ( exp( ( a - 1.0 ) * log( x / b ) - x / b - lgamma( a ) ) / b );
278 }
279}
281{
282 const REAL8 amax = 1048576.0;
283 const REAL8 amaxthird = amax - 1.0 / 3.0;
284 REAL8 xint = x;
285 REAL8 aint = a;
286 if ( aint > amax ) {
287 xint = fmax( amaxthird + sqrt( amax / a ) * ( xint - ( aint - 1.0 / 3.0 ) ), 0.0 );
288 aint = amax;
289 }
290 if ( aint == 0.0 ) {
291 if ( upper == 0 ) {
292 return 1.0;
293 } else {
294 return 0.0;
295 }
296 } else if ( xint == 0.0 ) {
297 if ( upper == 0 ) {
298 return 0.0;
299 } else {
300 return 1.0;
301 }
302 } else if ( xint < aint + 1.0 ) {
303 REAL8 ap = aint;
304 REAL8 del = 1.0;
305 REAL8 sum = del;
306 while ( fabs( del ) >= 100.0 * epsval( fabs( sum ) ) ) {
307 ap += 1.0;
308 del = xint * del / ap;
309 sum += del;
310 }
311 REAL8 b = sum * exp( -xint + aint * log( xint ) - lgamma( aint + 1.0 ) );
312 if ( xint > 0.0 && b > 1.0 ) {
313 b = 1.0;
314 }
315 if ( upper == 0 ) {
316 return b;
317 } else {
318 return 1.0 - b;
319 }
320 } else {
321 REAL8 a0 = 1.0;
322 REAL8 a1 = xint;
323 REAL8 b0 = 0.0;
324 REAL8 b1 = a0;
325 REAL8 fac = 1.0 / a1;
326 INT8 n = 1;
327 REAL8 g = b1 * fac;
328 REAL8 gold = b0;
329 while ( fabs( g - gold ) >= 100 * epsval( fabs( g ) ) ) {
330 gold = g;
331 REAL8 ana = n - a;
332 a0 = ( a1 + a0 * ana ) * fac;
333 b0 = ( b1 + b0 * ana ) * fac;
334 REAL8 anf = n * fac;
335 a1 = xint * a0 + anf * a1;
336 b1 = xint * b0 + anf * b1;
337 fac = 1.0 / a1;
338 g = b1 * fac;
339 n++;
340 }
341 REAL8 b = exp( -xint + aint * log( xint ) - lgamma( aint ) ) * g;
342 if ( upper == 0 ) {
343 return 1.0 - b;
344 } else {
345 return b;
346 }
347 }
348
349}
351{
352 XLAL_CHECK( a > 0.0 && x >= 0.0, XLAL_EINVAL, "Invalid input of zero (a = %f), or less than zero (x = %f)\n", a, x );
353
354 if ( x == 0.0 ) {
355 *out = 0.0;
356 } else if ( x < 20.0 || x < 0.5 * a ) {
357 REAL8 val;
359 *out = val;
360 } else if ( a > 1.0e+06 && ( x - a ) * ( x - a ) < a ) {
361 /* Crossover region. Note that Q and P are
362 * roughly the same order of magnitude here,
363 * so the subtraction is stable.
364 */
365 *out = 1.0 - gamma_inc_Q_asymp_unif( a, x );
366 } else if ( a <= x ) {
367 /* Q <~ P in this area, so the
368 * subtractions are stable.
369 */
370 REAL8 Q;
371 if ( a > 0.2 * x ) {
373 } else {
374 Q = gamma_inc_Q_large_x( a, x );
376 }
377 *out = 1.0 - Q;
378 } else {
379 if ( ( x - a ) * ( x - a ) < a ) {
380 /* This condition is meant to insure
381 * that Q is not very close to 1,
382 * so the subtraction is stable.
383 */
384 REAL8 Q;
386 *out = 1.0 - Q;
387 } else {
388 REAL8 val;
390 *out = val;
391 }
392 }
393 return XLAL_SUCCESS;
394}
396{
397 XLAL_CHECK( a >= 0.0 && x >= 0.0, XLAL_EINVAL, "Invalid input of less than zero (a = %f), or less than zero (x = %f)\n", a, x );
398 if ( x == 0.0 ) {
399 *out = 1.0;
400 } else if ( a == 0.0 ) {
401 *out = 0.0;
402 } else if ( x <= 0.5 * a ) {
403 /* If the series is quick, do that. It is
404 * robust and simple.
405 */
406 REAL8 P;
408 *out = 1.0 - P;
409 } else if ( a >= 1.0e+06 && ( x - a ) * ( x - a ) < a ) {
410 /* Then try the difficult asymptotic regime.
411 * This is the only way to do this region.
412 */
414 } else if ( a < 0.2 && x < 5.0 ) {
415 /* Cancellations at small a must be handled
416 * analytically; x should not be too big
417 * either since the series terms grow
418 * with x and log(x).
419 */
420 REAL8 val;
422 *out = val;
423 } else if ( a <= x ) {
424 if ( x <= 1.0e+06 ) {
425 /* Continued fraction is excellent for x >~ a.
426 * We do not let x be too large when x > a since
427 * it is somewhat pointless to try this there;
428 * the function is rapidly decreasing for
429 * x large and x > a, and it will just
430 * underflow in that region anyway. We
431 * catch that case in the standard
432 * large-x method.
433 */
434 REAL8 val;
436 *out = val;
437 } else {
438 REAL8 val = gamma_inc_Q_large_x( a, x );
440 *out = val;
441 }
442 } else {
443 if ( x > a - sqrt( a ) ) {
444 /* Continued fraction again. The convergence
445 * is a little slower here, but that is fine.
446 * We have to trade that off against the slow
447 * convergence of the series, which is the
448 * only other option.
449 */
450 REAL8 val;
452 *out = val;
453 } else {
454 REAL8 P;
456 *out = 1.0 - P;
457 }
458 }
459 return XLAL_SUCCESS;
460}
462{
463
464 INT4 nmax = 10000;
465
466 REAL8 D;
468
469 /* Approximating the terms of the series using Stirling's
470 approximation gives t_n = (x/a)^n * exp(-n(n+1)/(2a)), so the
471 convergence condition is n^2 / (2a) + (1-(x/a) + (1/2a)) n >>
472 -log(GSL_DBL_EPS) if we want t_n < O(1e-16) t_0. The condition
473 below detects cases where the minimum value of n is > 5000 */
474
475 if ( x > 0.995 * a && a > 1.0e5 ) { /* Difficult case: try continued fraction */
476 REAL8 cf_res = sf_exprel_n_CF( a, x );
478 *out = D * cf_res;
479 return XLAL_SUCCESS;
480 }
481
482 /* Series would require excessive number of terms */
483
484 XLAL_CHECK( x <= ( a + nmax ), XLAL_EMAXITER, "gamma_inc_P_series x>>a exceeds range\n" );
485
486 /* Normal case: sum the series */
487 REAL8 sum = 1.0;
488 REAL8 term = 1.0;
489 REAL8 remainderval;
490 INT4 n;
491
492 /* Handle lower part of the series where t_n is increasing, |x| > a+n */
493
494 INT4 nlow = ( x > a ) ? ( x - a ) : 0;
495
496 for ( n = 1; n < nlow; n++ ) {
497 term *= x / ( a + n );
498 sum += term;
499 }
500
501 /* Handle upper part of the series where t_n is decreasing, |x| < a+n */
502
503 for ( /* n = previous n */ ; n < nmax; n++ ) {
504 term *= x / ( a + n );
505 sum += term;
506 if ( fabs( term / sum ) < LAL_REAL4_EPS ) {
507 break;
508 }
509 }
510
511 /* Estimate remainder of series ~ t_(n+1)/(1-x/(a+n+1)) */
512 REAL8 tnp1 = ( x / ( a + n ) ) * term;
513 remainderval = tnp1 / ( 1.0 - x / ( a + n + 1.0 ) );
514
515 REAL8 val = D * sum;
516
517 XLAL_CHECK( !( n == nmax && fabs( remainderval / sum ) > sqrt( LAL_REAL4_EPS ) ), XLAL_EMAXITER, "gamma_inc_P_series_float failed to converge\n" );
518
519 *out = val;
520 return XLAL_SUCCESS;
521
522}
524{
525 REAL8 term1; /* 1 - x^a/Gamma(a+1) */
526 REAL8 sum; /* 1 + (a+1)/(a+2)(-x)/2! + (a+1)/(a+3)(-x)^2/3! + ... */
527 REAL8 term2; /* a temporary variable used at the end */
528
529 {
530 /* Evaluate series for 1 - x^a/Gamma(a+1), small a
531 */
532 const REAL8 pg21 = -2.404113806319188570799476; /* PolyGamma[2,1] */
533 const REAL8 lnx = log( x );
534 const REAL8 el = M_EULER + lnx;
535 const REAL8 c1 = -el;
536 const REAL8 c2 = M_PI * M_PI / 12.0 - 0.5 * el * el;
537 const REAL8 c3 = el * ( M_PI * M_PI / 12.0 - el * el / 6.0 ) + pg21 / 6.0;
538 const REAL8 c4 = -0.04166666666666666667
539 * ( -1.758243446661483480 + lnx )
540 * ( -0.764428657272716373 + lnx )
541 * ( 0.723980571623507657 + lnx )
542 * ( 4.107554191916823640 + lnx );
543 const REAL8 c5 = -0.0083333333333333333
544 * ( -2.06563396085715900 + lnx )
545 * ( -1.28459889470864700 + lnx )
546 * ( -0.27583535756454143 + lnx )
547 * ( 1.33677371336239618 + lnx )
548 * ( 5.17537282427561550 + lnx );
549 const REAL8 c6 = -0.0013888888888888889
550 * ( -2.30814336454783200 + lnx )
551 * ( -1.65846557706987300 + lnx )
552 * ( -0.88768082560020400 + lnx )
553 * ( 0.17043847751371778 + lnx )
554 * ( 1.92135970115863890 + lnx )
555 * ( 6.22578557795474900 + lnx );
556 const REAL8 c7 = -0.00019841269841269841
557 * ( -2.5078657901291800 + lnx )
558 * ( -1.9478900888958200 + lnx )
559 * ( -1.3194837322612730 + lnx )
560 * ( -0.5281322700249279 + lnx )
561 * ( 0.5913834939078759 + lnx )
562 * ( 2.4876819633378140 + lnx )
563 * ( 7.2648160783762400 + lnx );
564 const REAL8 c8 = -0.00002480158730158730
565 * ( -2.677341544966400 + lnx )
566 * ( -2.182810448271700 + lnx )
567 * ( -1.649350342277400 + lnx )
568 * ( -1.014099048290790 + lnx )
569 * ( -0.191366955370652 + lnx )
570 * ( 0.995403817918724 + lnx )
571 * ( 3.041323283529310 + lnx )
572 * ( 8.295966556941250 + lnx );
573 const REAL8 c9 = -2.75573192239859e-6
574 * ( -2.8243487670469080 + lnx )
575 * ( -2.3798494322701120 + lnx )
576 * ( -1.9143674728689960 + lnx )
577 * ( -1.3814529102920370 + lnx )
578 * ( -0.7294312810261694 + lnx )
579 * ( 0.1299079285269565 + lnx )
580 * ( 1.3873333251885240 + lnx )
581 * ( 3.5857258865210760 + lnx )
582 * ( 9.3214237073814600 + lnx );
583 const REAL8 c10 = -2.75573192239859e-7
584 * ( -2.9540329644556910 + lnx )
585 * ( -2.5491366926991850 + lnx )
586 * ( -2.1348279229279880 + lnx )
587 * ( -1.6741881076349450 + lnx )
588 * ( -1.1325949616098420 + lnx )
589 * ( -0.4590034650618494 + lnx )
590 * ( 0.4399352987435699 + lnx )
591 * ( 1.7702236517651670 + lnx )
592 * ( 4.1231539047474080 + lnx )
593 * ( 10.342627908148680 + lnx );
594
595 term1 = a * ( c1 + a * ( c2 + a * ( c3 + a * ( c4 + a * ( c5 + a * ( c6 + a * ( c7 + a * ( c8 + a * ( c9 + a * c10 ) ) ) ) ) ) ) ) );
596 }
597
598 {
599 /* Evaluate the sum.
600 */
601 const INT4 nmax = 5000;
602 REAL8 t = 1.0;
603 INT4 n;
604 sum = 1.0;
605
606 for ( n = 1; n < nmax; n++ ) {
607 t *= -x / ( n + 1.0 );
608 sum += ( a + 1.0 ) / ( a + n + 1.0 ) * t;
609 if ( fabs( t / sum ) < LAL_REAL4_EPS ) {
610 break;
611 }
612 }
613
614 XLAL_CHECK( n != nmax, XLAL_EMAXITER, "Maximum iterations reached\n" );
615 }
616
617 term2 = ( 1.0 - term1 ) * a / ( a + 1.0 ) * x * sum;
618 *out = ( term1 + term2 );
619 return XLAL_SUCCESS;
620
621}
622REAL8 twospect_cheb_eval( const cheb_series *cs, REAL8 x )
623{
624
625 INT4 j;
626 REAL8 d = 0.0;
627 REAL8 dd = 0.0;
628
629 REAL8 y = ( 2.0 * x - cs->a - cs->b ) / ( cs->b - cs->a );
630 REAL8 y2 = 2.0 * y;
631
632 for ( j = cs->order; j >= 1; j-- ) {
633 REAL8 temp = d;
634 d = y2 * d - dd + cs->c[j];
635 dd = temp;
636 }
637
638 {
639 d = y * d - dd + 0.5 * cs->c[0];
640 }
641
642 return d;
643
644}
646{
647
648 if ( a < 10.0 ) {
649 REAL8 lnr = a * log( x ) - x - lgamma( a + 1.0 );
650 *out = exp( lnr );
651 } else {
652 REAL8 gstar;
653 REAL8 ln_term;
654 REAL8 term1;
655 if ( x < 0.5 * a ) {
656 REAL8 u = x / a;
657 REAL8 ln_u = log( u );
658 ln_term = ln_u - u + 1.0;
659 } else {
660 REAL8 mu = ( x - a ) / a;
661 //ln_term = gsl_sf_log_1plusx_mx(mu); /* log(1+mu) - mu */
662 ln_term = log1p( mu ) - mu; /* log(1+mu) - mu */
663 }
665 term1 = exp( a * ln_term ) / sqrt( 2.0 * LAL_PI * a );
666 *out = term1 / gstar;
667 }
668 return XLAL_SUCCESS;
669
670}
672{
673 XLAL_CHECK( x > 0.0, XLAL_EINVAL, "Invalid input of zero or less: %f\n", x );
674
675 if ( x < 0.5 ) {
676 REAL8 lg = lgamma( x );
677 REAL8 lx = log( x );
678 REAL8 c = 0.5 * ( LAL_LN2 + M_LNPI );
679 REAL8 lnr_val = lg - ( x - 0.5 ) * lx + x - c;
680 *out = exp( lnr_val );
681 } else if ( x < 2.0 ) {
682 REAL8 t = 4.0 / 3.0 * ( x - 0.5 ) - 1.0;
684 *out = val;
685 } else if ( x < 10.0 ) {
686 REAL8 t = 0.25 * ( x - 2.0 ) - 1.0;
688 *out = c / ( x * x ) + 1.0 + 1.0 / ( 12.0 * x );
689 } else if ( x < 1.0 / 1.2207031250000000e-04 ) {
690 REAL8 val = gammastar_ser( x );
691 *out = val;
692 } else if ( x < 1.0 / LAL_REAL8_EPS ) {
693 /* Use Stirling formula for Gamma(x).
694 */
695 REAL8 xi = 1.0 / x;
696 *out = 1.0 + xi / 12.0 * ( 1.0 + xi / 24.0 * ( 1.0 - xi * ( 139.0 / 180.0 + 571.0 / 8640.0 * xi ) ) );
697 } else {
698 *out = 1.0;
699 }
700
701 return XLAL_SUCCESS;
702}
704{
705 /* Use the Stirling series for the correction to Log(Gamma(x)),
706 * which is better behaved and easier to compute than the
707 * regular Stirling series for Gamma(x).
708 */
709 const REAL8 y = 1.0 / ( x * x );
710 const REAL8 c0 = 1.0 / 12.0;
711 const REAL8 c1 = -1.0 / 360.0;
712 const REAL8 c2 = 1.0 / 1260.0;
713 const REAL8 c3 = -1.0 / 1680.0;
714 const REAL8 c4 = 1.0 / 1188.0;
715 const REAL8 c5 = -691.0 / 360360.0;
716 const REAL8 c6 = 1.0 / 156.0;
717 const REAL8 c7 = -3617.0 / 122400.0;
718 const REAL8 ser = c0 + y * ( c1 + y * ( c2 + y * ( c3 + y * ( c4 + y * ( c5 + y * ( c6 + y * c7 ) ) ) ) ) );
719 return exp( ser / x );
720}
722{
723 const REAL8 RECUR_BIG = sqrt( LAL_REAL8_MAX );
724 INT4 maxiter = 5000;
725 INT4 n = 1;
726 REAL8 Anm2 = 1.0;
727 REAL8 Bnm2 = 0.0;
728 REAL8 Anm1 = 0.0;
729 REAL8 Bnm1 = 1.0;
730 REAL8 a1 = 1.0;
731 REAL8 b1 = 1.0;
732 REAL8 a2 = -x;
733 REAL8 b2 = N + 1;
734 REAL8 an, bn;
735
736 REAL8 fn;
737
738 REAL8 An = b1 * Anm1 + a1 * Anm2; /* A1 */
739 REAL8 Bn = b1 * Bnm1 + a1 * Bnm2; /* B1 */
740
741 /* One explicit step, before we get to the main pattern. */
742 n++;
743 Anm2 = Anm1;
744 Bnm2 = Bnm1;
745 Anm1 = An;
746 Bnm1 = Bn;
747 An = b2 * Anm1 + a2 * Anm2; /* A2 */
748 Bn = b2 * Bnm1 + a2 * Bnm2; /* B2 */
749
750 fn = An / Bn;
751
752 while ( n < maxiter ) {
753 REAL8 old_fn;
754 REAL8 del;
755 n++;
756 Anm2 = Anm1;
757 Bnm2 = Bnm1;
758 Anm1 = An;
759 Bnm1 = Bn;
760 an = ( GSL_IS_ODD( n ) ? ( ( n - 1 ) / 2 ) * x : -( N + ( n / 2 ) - 1 ) * x );
761 bn = N + n - 1;
762 An = bn * Anm1 + an * Anm2;
763 Bn = bn * Bnm1 + an * Bnm2;
764
765 if ( fabs( An ) > RECUR_BIG || fabs( Bn ) > RECUR_BIG ) {
766 An /= RECUR_BIG;
767 Bn /= RECUR_BIG;
768 Anm1 /= RECUR_BIG;
769 Bnm1 /= RECUR_BIG;
770 Anm2 /= RECUR_BIG;
771 Bnm2 /= RECUR_BIG;
772 }
773
774 old_fn = fn;
775 fn = An / Bn;
776 del = old_fn / fn;
777
778 if ( fabs( del - 1.0 ) < 2.0 * LAL_REAL4_EPS ) {
779 break;
780 }
781 }
782
783 XLAL_CHECK_REAL8( n < maxiter, XLAL_EMAXITER, "Reached maximum number of iterations (5000)\n" );
784
785 return fn;
786
787}
789{
790
791 REAL8 rta = sqrt( a );
792 REAL8 eps = ( x - a ) / a;
793
794 REAL8 ln_term = gsl_sf_log_1plusx_mx( eps ); /* log(1+eps) - eps */
795 REAL8 eta = GSL_SIGN( eps ) * sqrt( -2.0 * ln_term );
796
797 REAL8 R;
798 REAL8 c0, c1;
799
800 REAL8 erfcval = erfc( eta * rta / LAL_SQRT2 );
801
802 if ( fabs( eps ) < 7.4009597974140505e-04 ) {
803 c0 = -1.0 / 3.0 + eps * ( 1.0 / 12.0 - eps * ( 23.0 / 540.0 - eps * ( 353.0 / 12960.0 - eps * 589.0 / 30240.0 ) ) );
804 c1 = -1.0 / 540.0 - eps / 288.0;
805 } else {
806 REAL8 rt_term = sqrt( -2.0 * ln_term / ( eps * eps ) );
807 REAL8 lam = x / a;
808 c0 = ( 1.0 - 1.0 / rt_term ) / eps;
809 c1 = -( eta * eta * eta * ( lam * lam + 10.0 * lam + 1.0 ) - 12.0 * eps * eps * eps ) / ( 12.0 * eta * eta * eta * eps * eps * eps );
810 }
811
812 R = exp( -0.5 * a * eta * eta ) / ( LAL_SQRT2 * M_SQRTPI * rta ) * ( c0 + c1 / a );
813
814 return ( 0.5 * erfcval + R );
815
816}
818{
819 REAL8 D, F;
822
823 *out = ( D * ( a / x ) * F );
824
825 return XLAL_SUCCESS;
826
827}
829{
830 INT4 nmax = 5000;
831 const REAL8 smallval = LAL_REAL8_EPS * LAL_REAL8_EPS * LAL_REAL8_EPS;
832
833 REAL8 hn = 1.0; /* convergent */
834 REAL8 Cn = 1.0 / smallval;
835 REAL8 Dn = 1.0;
836 INT4 n;
837
838 /* n == 1 has a_1, b_1, b_0 independent of a,x,
839 so that has been done by hand */
840 for ( n = 2 ; n < nmax ; n++ ) {
841 REAL8 an;
842 REAL8 delta;
843
844 if ( GSL_IS_ODD( n ) ) {
845 an = 0.5 * ( n - 1 ) / x;
846 } else {
847 an = ( 0.5 * n - a ) / x;
848 }
849
850 Dn = 1.0 + an * Dn;
851 if ( fabs( Dn ) < smallval ) {
852 Dn = smallval;
853 }
854 Cn = 1.0 + an / Cn;
855 if ( fabs( Cn ) < smallval ) {
856 Cn = smallval;
857 }
858 Dn = 1.0 / Dn;
859 delta = Cn * Dn;
860 hn *= delta;
861 if ( fabs( delta - 1.0 ) < LAL_REAL4_EPS ) {
862 break;
863 }
864 }
865
867
868 *out = hn;
869
870 return XLAL_SUCCESS;
871
872}
874{
875 const INT4 nmax = 100000;
876
877 REAL8 D;
879
880 REAL8 sum = 1.0;
881 REAL8 term = 1.0;
882 REAL8 last = 1.0;
883 INT4 n;
884 for ( n = 1; n < nmax; n++ ) {
885 term *= ( a - n ) / x;
886 if ( fabs( term / last ) > 1.0 ) {
887 break;
888 }
889 if ( fabs( term / sum ) < LAL_REAL4_EPS ) {
890 break;
891 }
892 sum += term;
893 last = term;
894 }
895
897
898 return ( D * ( a / x ) * sum );
899
900}
901//Matlab's eps function for REAL8, but written in C
903{
904 //Same as matlab
905 REAL8 absval = fabs( val );
906 int exponentval = 0;
907 frexp( absval, &exponentval );
908 exponentval -= LAL_REAL8_MANT;
909 return ldexp( 1.0, exponentval );
910} /* epsval() */
911
912//Matlab's eps function for REAL4, but written in C
914{
915 //Same as matlab
916 REAL4 absval = fabsf( val );
917 int exponentval = 0;
918 frexpf( absval, &exponentval );
919 exponentval -= LAL_REAL4_MANT;
920 return ldexpf( 1.0, exponentval );
921} /* epsval_float() */
922//Matlab's sumseries function
923void sumseries( REAL8 *computedprob, REAL8 P, REAL8 C, REAL8 E, INT8 counter, REAL8 x, REAL8 dof, REAL8 halfdelta, REAL8 err, INT4 countdown )
924{
925
926 //Exit with error if halfdelta = 0.0
927 XLAL_CHECK_VOID( halfdelta != 0.0, XLAL_EINVAL );
928
929 REAL8 Pint = P, Cint = C, Eint = E;
930 INT8 counterint = counter;
931 INT8 j = 0;
932 if ( countdown != 0 ) {
933 if ( counterint >= 0 ) {
934 j = 1;
935 }
936 if ( j == 1 ) {
937 Pint *= ( counterint + 1.0 ) / halfdelta;
938 Cint += E;
939 } else {
940 counterint = -1;
941 }
942 }
943
944 while ( counterint != -1 ) {
945 REAL8 pplus = Pint * Cint;
946 *( computedprob ) += pplus;
947
948 if ( pplus > *( computedprob ) * err ) {
949 j = 1;
950 } else {
951 j = 0;
952 }
953 if ( countdown != 0 && counterint < 0 ) {
954 j = 0;
955 }
956 if ( j == 0 ) {
957 return;
958 }
959
960 if ( countdown != 0 ) {
961 counterint--;
962 Pint *= ( counterint + 1.0 ) / halfdelta;
963 Eint *= ( 0.5 * dof + counterint + 1.0 ) / ( x * 0.5 );
964 Cint += Eint;
965 } else {
966 counterint++;
967 Pint *= halfdelta / counterint;
968 Eint *= ( 0.5 * x ) / ( 0.5 * dof + counterint - 1.0 );
969 Cint -= Eint;
970 }
971 }
972
973} /* sumseries() */
974
975
976//Evan's sumseries function based on matlab's sumseries() version above, but faster
977void sumseries_eg( REAL8 *computedprob, REAL8 P, REAL8 C, REAL8 E, INT8 counter, REAL8 x, REAL8 dof, REAL8 halfdelta, REAL8 err, INT4 countdown )
978{
979
980 //If halfdelta = 0.0, then exit with error
981 XLAL_CHECK_VOID( halfdelta != 0.0, XLAL_EINVAL );
982
983 REAL8 Pint = P, Cint = C, Eint = E;
984 INT8 counterint = counter;
985 REAL8 oneoverhalfdelta = 1.0 / halfdelta; //pre-compute
986 REAL8 halfdof = 0.5 * dof; //pre-compute
987 REAL8 halfx = 0.5 * x; //pre-compute
988
989 if ( countdown != 0 ) {
990 if ( counterint >= 0 ) {
991 Pint *= ( counterint + 1.0 ) * oneoverhalfdelta;
992 Cint += E;
993 } else {
994 counterint = -1;
995 }
996 }
997
998 if ( counterint == -1 ) {
999 return;
1000 } else if ( countdown != 0 ) {
1001 REAL8 oneoverhalfx = 1.0 / halfx;
1002 while ( counterint != -1 ) {
1003 REAL8 pplus = Pint * Cint;
1004 *( computedprob ) += pplus;
1005
1006 if ( pplus <= *( computedprob ) * err || counterint < 0 ) {
1007 return;
1008 }
1009
1010 counterint--;
1011 Pint *= ( counterint + 1 ) * oneoverhalfdelta;
1012 Eint *= ( halfdof + counterint + 1 ) * oneoverhalfx;
1013 Cint += Eint;
1014 }
1015 } else {
1016 while ( counterint != -1 ) {
1017 REAL8 pplus = Pint * Cint;
1018 *( computedprob ) += pplus;
1019
1020 if ( pplus <= *( computedprob ) * err ) {
1021 return;
1022 }
1023
1024 counterint++;
1025 Pint *= halfdelta / counterint;
1026 Eint *= halfx / ( halfdof + counterint - 1 );
1027 Cint -= Eint;
1028 }
1029 }
1030
1031} /* sumseries_eg() */
1032
1033//Matlab's binodeviance, a "hidden" function
1035{
1036 if ( fabs( x - np ) < 0.1 * ( x + np ) ) {
1037 REAL8 s = ( x - np ) * ( x - np ) / ( x + np );
1038 REAL8 v = ( x - np ) / ( x + np );
1039 REAL8 ej = 2.0 * x * v;
1040 REAL8 s1 = 0.0;
1041 INT4 jj = 0;
1042 INT4 ok = 1;
1043 while ( ok == 1 ) {
1044 ej *= v * v;
1045 jj++;
1046 s1 = s + ej / ( 2.0 * jj + 1.0 );
1047 if ( s1 != s ) {
1048 s = s1;
1049 } else {
1050 ok = 0;
1051 }
1052 }
1053 return s;
1054 } else {
1055 return x * log( x / np ) + np - x;
1056 }
1057} /* binodeviance() */
const REAL8 eps
const REAL8 scaling[15]
int j
const double b1
const double c1
const double b2
const double b0
const double c2
const double c0
static double double delta
#define c
#define D(j)
void sumseries_eg(REAL8 *computedprob, REAL8 P, REAL8 C, REAL8 E, INT8 counter, REAL8 x, REAL8 dof, REAL8 halfdelta, REAL8 err, INT4 countdown)
REAL8 ran_gamma_pdf(REAL8 x, REAL8 a, REAL8 b)
static cheb_series gstar_a_cs
REAL8 twospect_intermediate(REAL8 r)
REAL8 gamma_inc_Q_asymp_unif(REAL8 a, REAL8 x)
REAL8 twospect_cheb_eval(const cheb_series *cs, REAL8 x)
REAL8 twospect_small(REAL8 q)
INT4 gamma_inc_F_CF(REAL8 *out, REAL8 a, REAL8 x)
INT4 sf_gamma_inc_Q(REAL8 *out, REAL8 a, REAL8 x)
INT4 gamma_inc_Q_CF(REAL8 *out, REAL8 a, REAL8 x)
INT4 sf_gamma_inc_P(REAL8 *out, REAL8 a, REAL8 x)
INT4 gamma_inc_Q_series(REAL8 *out, REAL8 a, REAL8 x)
void sumseries(REAL8 *computedprob, REAL8 P, REAL8 C, REAL8 E, INT8 counter, REAL8 x, REAL8 dof, REAL8 halfdelta, REAL8 err, INT4 countdown)
INT4 twospect_sf_gammastar(REAL8 *out, REAL8 x)
REAL8 gammastar_ser(REAL8 x)
static cheb_series gstar_b_cs
static REAL8 gstar_b_data[]
INT4 DirichletKernalLargeNHannRatio(COMPLEX8 *ratio, const REAL4 delta0, const REAL4 delta1, const REAL4 scaling)
Compute the argument of the ratio of Dirichlet kernels for large N values and the Hann window.
REAL8 epsval(REAL8 val)
COMPLEX16 DirichletKernelLargeNHann(const REAL8 delta)
Compute the Dirichlet kernel for large N values and the Hann window.
REAL4 epsval_float(REAL4 val)
INT4 gamma_inc_D(REAL8 *out, REAL8 a, REAL8 x)
INT4 gamma_inc_P_series(REAL8 *out, REAL8 a, REAL8 x)
REAL8 sf_exprel_n_CF(REAL8 N, REAL8 x)
REAL8 binodeviance(REAL8 x, REAL8 np)
REAL8 matlab_gamma_inc(REAL8 x, REAL8 a, INT4 upper)
REAL8 gamma_inc_Q_large_x(REAL8 a, REAL8 x)
REAL8 twospect_tail(REAL8 r)
static REAL8 gstar_a_data[30]
COMPLEX16 DirichletKernelLargeN(const REAL8 delta)
Compute the Dirichlet kernel for large N values.
REAL8 rat_eval(const REAL8 a[], const size_t na, const REAL8 b[], const size_t nb, const REAL8 x)
const double Q
const double u
const double a2
#define LAL_REAL8_MANT
#define LAL_LN2
#define LAL_REAL8_EPS
#define LAL_REAL4_MANT
#define LAL_PI
#define LAL_TWOPI
#define LAL_SQRT2
#define LAL_REAL8_MAX
#define LAL_REAL4_EPS
#define crect(re, im)
#define cpolar(r, th)
double complex COMPLEX16
#define cpolarf(r, th)
double REAL8
int64_t INT8
#define crectf(re, im)
float complex COMPLEX8
int32_t INT4
float REAL4
static const INT4 r
static const INT4 q
static const INT4 a
#define xlalErrno
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_VOID(assertion,...)
#define XLAL_CHECK_REAL8(assertion,...)
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EMAXITER
XLAL_EINVAL
list y
list mu
temp
eta
n
out
int N