Scythe-1.0.3
distributions.h
Go to the documentation of this file.
00001 /* 
00002  * Scythe Statistical Library Copyright (C) 2000-2002 Andrew D. Martin
00003  * and Kevin M. Quinn; 2002-present Andrew D. Martin, Kevin M. Quinn,
00004  * and Daniel Pemstein.  All Rights Reserved.
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify under the terms of the GNU General Public License as
00008  * published by Free Software Foundation; either version 2 of the
00009  * License, or (at your option) any later version.  See the text files
00010  * COPYING and LICENSE, distributed with this source code, for further
00011  * information.
00012  * --------------------------------------------------------------------
00013  *  scythestat/distributions.h
00014  *
00015  */
00016 
00069 /* TODO: Figure out how to get doxygen to stop listing erroneous
00070  * variables at the end of the doc for this file.  They stem from it
00071  * misreading the nested macro calls used to generate matrix procs.
00072  */
00073 
00074 /* TODO: Full R-style versions of these function including arbitrary
00075  * recycling of matrix arguments.  This is going to have to wait for
00076  * variadic templates to be doable without a complete mess.  There is
00077  * currently a variadic patch available for g++, perhaps we can add a
00078  * SCYTHE_VARIADIC flag and include these as option until they become
00079  * part of the standard in 2009.  Something to come back to after 1.0.
00080  */
00081 
00082 #ifndef SCYTHE_DISTRIBUTIONS_H
00083 #define SCYTHE_DISTRIBUTIONS_H
00084 
00085 #include <iostream>
00086 #include <cmath>
00087 #include <cfloat>
00088 #include <climits>
00089 #include <algorithm>
00090 #include <limits>
00091 
00092 #ifdef HAVE_IEEEFP_H
00093 #include <ieeefp.h>
00094 #endif
00095 
00096 #ifdef SCYTHE_COMPILE_DIRECT
00097 #include "matrix.h"
00098 #include "ide.h"
00099 #include "error.h"
00100 #else
00101 #include "scythestat/matrix.h"
00102 #include "scythestat/ide.h"
00103 #include "scythestat/error.h"
00104 #endif
00105 
00106 /* Fill in some defs from R that aren't in math.h */
00107 #ifndef M_PI
00108 #define M_PI 3.141592653589793238462643383280
00109 #endif
00110 #define M_LN_SQRT_2PI 0.918938533204672741780329736406
00111 #define M_LN_SQRT_PId2  0.225791352644727432363097614947
00112 #define M_1_SQRT_2PI  0.39894228040143267793994605993
00113 #define M_2PI   6.28318530717958647692528676655
00114 #define M_SQRT_32 5.656854249492380195206754896838
00115 
00116 #ifndef HAVE_TRUNC
00117 
00118 inline double trunc(double x) throw ()
00119 {
00120     if (x >= 0) 
00121       return std::floor(x);
00122     else
00123       return std::ceil(x);
00124 }
00126 #endif
00127 
00128 /* Many random number generators, pdfs, cdfs, and functions (gamma,
00129  * etc) in this file are based on code from the R Project, version
00130  * 1.6.0-1.7.1.  This code is available under the terms of the GNU
00131  * GPL.  Original copyright:
00132  *
00133  * Copyright (C) 1998      Ross Ihaka
00134  * Copyright (C) 2000-2002 The R Development Core Team
00135  * Copyright (C) 2003      The R Foundation
00136  */
00137 
00138 namespace scythe {
00139   
00142   /* Forward declarations */
00143   double gammafn (double);
00144   double lngammafn (double);
00145   double lnbetafn (double, double);
00146   double pgamma (double, double, double);
00147   double dgamma(double, double, double);
00148   double pnorm (double, double, double);
00149 
00152   /********************
00153    * Helper Functions *
00154    ********************/
00155   namespace {
00156 
00157     /* Evaluate a Chebysheve series at a given point */
00158     double
00159     chebyshev_eval (double x, const double *a, int n)
00160     {
00161       SCYTHE_CHECK_10(n < 1 || n > 1000, scythe_invalid_arg,
00162           "n not on [1, 1000]");
00163   
00164       SCYTHE_CHECK_10(x < -1.1 || x > 1.1, scythe_invalid_arg,
00165           "x not on [-1.1, 1.1]");
00166       
00167       double b0, b1, b2;
00168       b0 = b1 = b2 = 0;
00169   
00170       double twox = x * 2;
00171   
00172       for (int i = 1; i <= n; ++i) {
00173         b2 = b1;
00174         b1 = b0;
00175         b0 = twox * b1 - b2 + a[n - i];
00176       }
00177   
00178       return (b0 - b2) * 0.5;
00179     }
00180 
00181     /* Computes the log gamma correction factor for x >= 10 */
00182     double
00183     lngammacor(double x)
00184     {
00185       const double algmcs[15] = {
00186         +.1666389480451863247205729650822e+0,
00187         -.1384948176067563840732986059135e-4,
00188         +.9810825646924729426157171547487e-8,
00189         -.1809129475572494194263306266719e-10,
00190         +.6221098041892605227126015543416e-13,
00191       };
00192     
00193       SCYTHE_CHECK_10(x < 10, scythe_invalid_arg,
00194           "This function requires x >= 10");  
00195       SCYTHE_CHECK_10(x >= 3.745194030963158e306, scythe_range_error,
00196           "Underflow");
00197       
00198       if (x < 94906265.62425156) {
00199         double tmp = 10 / x;
00200         return chebyshev_eval(tmp * tmp * 2 - 1, algmcs, 5) / x;
00201       }
00202       
00203       return 1 / (x * 12);
00204     }
00205 
00206     /* Evaluates the "deviance part" */
00207     double
00208     bd0(double x, double np)
00209     {
00210       
00211       if(std::fabs(x - np) < 0.1 * (x + np)) {
00212         double v = (x - np) / (x + np);
00213         double s = (x - np) * v;
00214         double ej = 2 * x * v;
00215         v = v * v;
00216         for (int j = 1; ; j++) {
00217           ej *= v;
00218           double s1 = s + ej / ((j << 1) + 1);
00219           if (s1 == s)
00220             return s1;
00221           s = s1;
00222         }
00223       }
00224       
00225       return x * std::log(x / np) + np - x;
00226     }
00227   
00228     /* Computes the log of the error term in Stirling's formula */
00229     double
00230     stirlerr(double n)
00231     {
00232 #define S0 0.083333333333333333333       /* 1/12 */
00233 #define S1 0.00277777777777777777778     /* 1/360 */
00234 #define S2 0.00079365079365079365079365  /* 1/1260 */
00235 #define S3 0.000595238095238095238095238 /* 1/1680 */
00236 #define S4 0.0008417508417508417508417508/* 1/1188 */
00237       
00238       /* error for 0, 0.5, 1.0, 1.5, ..., 14.5, 15.0 */
00239       const double sferr_halves[31] = {
00240         0.0, /* n=0 - wrong, place holder only */
00241         0.1534264097200273452913848,  /* 0.5 */
00242         0.0810614667953272582196702,  /* 1.0 */
00243         0.0548141210519176538961390,  /* 1.5 */
00244         0.0413406959554092940938221,  /* 2.0 */
00245         0.03316287351993628748511048, /* 2.5 */
00246         0.02767792568499833914878929, /* 3.0 */
00247         0.02374616365629749597132920, /* 3.5 */
00248         0.02079067210376509311152277, /* 4.0 */
00249         0.01848845053267318523077934, /* 4.5 */
00250         0.01664469118982119216319487, /* 5.0 */
00251         0.01513497322191737887351255, /* 5.5 */
00252         0.01387612882307074799874573, /* 6.0 */
00253         0.01281046524292022692424986, /* 6.5 */
00254         0.01189670994589177009505572, /* 7.0 */
00255         0.01110455975820691732662991, /* 7.5 */
00256         0.010411265261972096497478567, /* 8.0 */
00257         0.009799416126158803298389475, /* 8.5 */
00258         0.009255462182712732917728637, /* 9.0 */
00259         0.008768700134139385462952823, /* 9.5 */
00260         0.008330563433362871256469318, /* 10.0 */
00261         0.007934114564314020547248100, /* 10.5 */
00262         0.007573675487951840794972024, /* 11.0 */
00263         0.007244554301320383179543912, /* 11.5 */
00264         0.006942840107209529865664152, /* 12.0 */
00265         0.006665247032707682442354394, /* 12.5 */
00266         0.006408994188004207068439631, /* 13.0 */
00267         0.006171712263039457647532867, /* 13.5 */
00268         0.005951370112758847735624416, /* 14.0 */
00269         0.005746216513010115682023589, /* 14.5 */
00270         0.005554733551962801371038690  /* 15.0 */
00271       };
00272       double nn;
00273       
00274       if (n <= 15.0) {
00275         nn = n + n;
00276         if (nn == (int)nn)
00277           return(sferr_halves[(int)nn]);
00278         return (scythe::lngammafn(n + 1.) - (n + 0.5) * std::log(n) + n -
00279             std::log(std::sqrt(2 * M_PI)));
00280       }
00281       
00282       nn = n*n;
00283       if (n > 500)
00284         return((S0 - S1 / nn) / n);
00285       if (n > 80)
00286         return((S0 - (S1 - S2 / nn) / nn) / n);
00287       if (n > 35)
00288         return((S0 - (S1 - (S2 - S3 / nn) / nn) / nn) / n);
00289       /* 15 < n <= 35 : */
00290       return((S0 - (S1 - (S2 - (S3 - S4 / nn) / nn) / nn) / nn) / n);
00291 #undef S1
00292 #undef S2
00293 #undef S3
00294 #undef S4
00295     }
00296 
00297 
00298     /* Helper for dpois and dgamma */
00299     double
00300     dpois_raw (double x, double lambda)
00301     {
00302       if (lambda == 0)
00303         return ( (x == 0) ? 1.0 : 0.0);
00304 
00305       if (x == 0)
00306         return std::exp(-lambda);
00307 
00308       if (x < 0)
00309         return 0.0;
00310 
00311       return std::exp(-stirlerr(x) - bd0(x, lambda))
00312         / std::sqrt(2 * M_PI * x);
00313     }
00314 
00315   
00316     /* helper for pbeta */
00317     double
00318     pbeta_raw(double x, double pin, double qin)
00319     {
00320       double ans, c, finsum, p, ps, p1, q, term, xb, xi, y;
00321       int n, i, ib, swap_tail;
00322       
00323       const double eps = .5 * DBL_EPSILON;
00324       const double sml = DBL_MIN;
00325       const double lneps = std::log(eps);
00326       const double lnsml = std::log(eps);
00327       
00328       if (pin / (pin + qin) < x) {
00329         swap_tail = 1;
00330         y = 1 - x;
00331         p = qin;
00332         q = pin;
00333       } else {
00334         swap_tail=0;
00335         y = x;
00336         p = pin;
00337         q = qin;
00338       }
00339       
00340       if ((p + q) * y / (p + 1) < eps) {
00341         ans = 0;
00342         xb = p * std::log(std::max(y,sml)) - std::log(p) - lnbetafn(p,q);
00343         if (xb > lnsml && y != 0)
00344           ans = std::exp(xb);
00345         if (swap_tail)
00346           ans = 1-ans;
00347       } else {
00348         ps = q - std::floor(q);
00349         if (ps == 0)
00350           ps = 1;
00351         xb = p * std::log(y) - lnbetafn(ps, p) - std::log(p);
00352         ans = 0;
00353         if (xb >= lnsml) {
00354           ans = std::exp(xb);
00355           term = ans * p;
00356           if (ps != 1) {
00357             n = (int)std::max(lneps/std::log(y), 4.0);
00358             for(i = 1; i <= n; i++){
00359               xi = i;
00360               term *= (xi-ps)*y/xi;
00361               ans += term/(p+xi);
00362             }
00363           }
00364         }
00365         if (q > 1) {
00366           xb = p * std::log(y) + q * std::log(1 - y)
00367             - lnbetafn(p, q) - std::log(q);
00368           ib = (int) std::max(xb / lnsml, 0.0);
00369           term = std::exp(xb - ib * lnsml);
00370           c = 1 / (1 - y);
00371           p1 = q * c / (p + q - 1);
00372               
00373           finsum = 0;
00374           n = (int) q;
00375           if(q == n)
00376             n--;
00377           for (i = 1; i <= n; i++) {
00378             if(p1 <= 1 && term / eps <= finsum)
00379               break;
00380             xi = i;
00381             term = (q -xi + 1) * c * term / (p + q - xi);
00382             if (term > 1) {
00383               ib--;
00384               term *= sml;
00385             }
00386             if (ib == 0)
00387               finsum += term;
00388           }
00389           ans += finsum;
00390         }
00391         
00392         if(swap_tail)
00393           ans = 1-ans;
00394         ans = std::max(std::min(ans,1.),0.);
00395       }
00396       return ans;
00397     }
00398   
00399    /* Helper for dbinom */
00400     double
00401     dbinom_raw (double x, double n, double p, double q)
00402     { 
00403       double f, lc;
00404 
00405       if (p == 0)
00406         return((x == 0) ? 1.0 : 0.0);
00407       if (q == 0)
00408         return((x == n) ? 1.0 : 0.0);
00409 
00410       if (x == 0) { 
00411         if(n == 0)
00412           return 1.0;
00413         
00414         lc = (p < 0.1) ? -bd0(n, n * q) - n * p : n * std::log(q);
00415         return(std::exp(lc));
00416       }
00417       if (x == n) { 
00418         lc = (q < 0.1) ? -bd0(n,n * p) - n * q : n * std::log(p);
00419         return(std::exp(lc));
00420       }
00421 
00422       if (x < 0 || x > n)
00423         return 0.0;
00424 
00425       lc = stirlerr(n) - stirlerr(x) - stirlerr(n-x) - bd0(x,n*p) -
00426         bd0(n - x, n * q);
00427       
00428       f = (M_2PI * x * (n-x)) / n;
00429 
00430       return (std::exp(lc) / std::sqrt(f));
00431     }
00432 
00433     /* The normal probability density function implementation. */
00434 
00435 #define SIXTEN 16
00436 #define do_del(X)              \
00437     xsq = trunc(X * SIXTEN) / SIXTEN;        \
00438     del = (X - xsq) * (X + xsq);          \
00439     if(log_p) {              \
00440         *cum = (-xsq * xsq * 0.5) + (-del * 0.5) + std::log(temp);  \
00441         if((lower && x > 0.) || (upper && x <= 0.))      \
00442         *ccum = ::log1p(-std::exp(-xsq * xsq * 0.5) *     \
00443           std::exp(-del * 0.5) * temp);    \
00444     }                \
00445     else {                \
00446         *cum = std::exp(-xsq * xsq * 0.5) * std::exp(-del * 0.5) * temp;  \
00447         *ccum = 1.0 - *cum;            \
00448     }
00449 
00450 #define swap_tail            \
00451     if (x > 0.) {/* swap  ccum <--> cum */      \
00452         temp = *cum; if(lower) *cum = *ccum; *ccum = temp;  \
00453     }
00454 
00455     void
00456     pnorm_both(double x, double *cum, double *ccum, int i_tail,
00457                 bool log_p)
00458     {
00459       const double a[5] = {
00460         2.2352520354606839287,
00461         161.02823106855587881,
00462         1067.6894854603709582,
00463         18154.981253343561249,
00464         0.065682337918207449113
00465       };
00466       const double b[4] = {
00467         47.20258190468824187,
00468         976.09855173777669322,
00469         10260.932208618978205,
00470         45507.789335026729956
00471       };
00472       const double c[9] = {
00473         0.39894151208813466764,
00474         8.8831497943883759412,
00475         93.506656132177855979,
00476         597.27027639480026226,
00477         2494.5375852903726711,
00478         6848.1904505362823326,
00479         11602.651437647350124,
00480         9842.7148383839780218,
00481         1.0765576773720192317e-8
00482       };
00483       const double d[8] = {
00484         22.266688044328115691,
00485         235.38790178262499861,
00486         1519.377599407554805,
00487         6485.558298266760755,
00488         18615.571640885098091,
00489         34900.952721145977266,
00490         38912.003286093271411,
00491         19685.429676859990727
00492       };
00493       const double p[6] = {
00494         0.21589853405795699,
00495         0.1274011611602473639,
00496         0.022235277870649807,
00497         0.001421619193227893466,
00498         2.9112874951168792e-5,
00499         0.02307344176494017303
00500       };
00501       const double q[5] = {
00502         1.28426009614491121,
00503         0.468238212480865118,
00504         0.0659881378689285515,
00505         0.00378239633202758244,
00506         7.29751555083966205e-5
00507       };
00508       
00509       double xden, xnum, temp, del, eps, xsq, y;
00510       int i, lower, upper;
00511 
00512       /* Consider changing these : */
00513       eps = DBL_EPSILON * 0.5;
00514 
00515       /* i_tail in {0,1,2} =^= {lower, upper, both} */
00516       lower = i_tail != 1;
00517       upper = i_tail != 0;
00518 
00519       y = std::fabs(x);
00520       if (y <= 0.67448975) {
00521         /* qnorm(3/4) = .6744.... -- earlier had 0.66291 */
00522         if (y > eps) {
00523           xsq = x * x;
00524           xnum = a[4] * xsq;
00525           xden = xsq;
00526           for (i = 0; i < 3; ++i) {
00527             xnum = (xnum + a[i]) * xsq;
00528             xden = (xden + b[i]) * xsq;
00529           }
00530         } else xnum = xden = 0.0;
00531         
00532         temp = x * (xnum + a[3]) / (xden + b[3]);
00533         if(lower)  *cum = 0.5 + temp;
00534         if(upper) *ccum = 0.5 - temp;
00535         if(log_p) {
00536           if(lower)  *cum = std::log(*cum);
00537           if(upper) *ccum = std::log(*ccum);
00538         }
00539       } else if (y <= M_SQRT_32) {
00540         /* Evaluate pnorm for 0.674.. = qnorm(3/4) < |x| <= sqrt(32) 
00541          * ~= 5.657 */
00542 
00543         xnum = c[8] * y;
00544         xden = y;
00545         for (i = 0; i < 7; ++i) {
00546           xnum = (xnum + c[i]) * y;
00547           xden = (xden + d[i]) * y;
00548         }
00549         temp = (xnum + c[7]) / (xden + d[7]);
00550         do_del(y);
00551         swap_tail;
00552       } else if (log_p
00553                 || (lower && -37.5193 < x && x < 8.2924)
00554                 || (upper && -8.2929 < x && x < 37.5193)
00555           ) {
00556         /* Evaluate pnorm for x in (-37.5, -5.657) union (5.657, 37.5) */
00557         xsq = 1.0 / (x * x);
00558         xnum = p[5] * xsq;
00559         xden = xsq;
00560         for (i = 0; i < 4; ++i) {
00561           xnum = (xnum + p[i]) * xsq;
00562           xden = (xden + q[i]) * xsq;
00563         }
00564         temp = xsq * (xnum + p[4]) / (xden + q[4]);
00565         temp = (M_1_SQRT_2PI - temp) / y;
00566         do_del(x);
00567         swap_tail;
00568       } else {
00569         if (x > 0) {
00570           *cum = 1.;
00571           *ccum = 0.;
00572         } else {
00573           *cum = 0.;
00574           *ccum = 1.;
00575         }
00576         SCYTHE_THROW_10(scythe_convergence_error, "Did not converge");
00577       }
00578 
00579       return;
00580     }
00581 #undef SIXTEN
00582 #undef do_del
00583 #undef swap_tail
00584 
00585     /* The standard normal distribution function */
00586     double
00587     pnorm1 (double x, bool lower_tail, bool log_p)
00588     {
00589       SCYTHE_CHECK_10(! finite(x), scythe_invalid_arg,
00590           "Quantile x is inifinte (+/-Inf) or NaN");
00591 
00592       double p, cp;
00593       pnorm_both(x, &p, &cp, (lower_tail ? 0 : 1), log_p);
00594 
00595       return (lower_tail ? p : cp);
00596     }
00597   } // anonymous namespace
00598 
00599   /*************
00600    * Functions *
00601    *************/
00602   
00603   /* The gamma function */
00604 
00619   inline double 
00620   gammafn (double x)
00621   {
00622     const double gamcs[22] = {
00623       +.8571195590989331421920062399942e-2,
00624       +.4415381324841006757191315771652e-2,
00625       +.5685043681599363378632664588789e-1,
00626       -.4219835396418560501012500186624e-2,
00627       +.1326808181212460220584006796352e-2,
00628       -.1893024529798880432523947023886e-3,
00629       +.3606925327441245256578082217225e-4,
00630       -.6056761904460864218485548290365e-5,
00631       +.1055829546302283344731823509093e-5,
00632       -.1811967365542384048291855891166e-6,
00633       +.3117724964715322277790254593169e-7,
00634       -.5354219639019687140874081024347e-8,
00635       +.9193275519859588946887786825940e-9,
00636       -.1577941280288339761767423273953e-9,
00637       +.2707980622934954543266540433089e-10,
00638       -.4646818653825730144081661058933e-11,
00639       +.7973350192007419656460767175359e-12,
00640       -.1368078209830916025799499172309e-12,
00641       +.2347319486563800657233471771688e-13,
00642       -.4027432614949066932766570534699e-14,
00643       +.6910051747372100912138336975257e-15,
00644       -.1185584500221992907052387126192e-15,
00645     };
00646 
00647 
00648     double y = std::fabs(x);
00649 
00650     if (y <= 10) {
00651 
00652       /* Compute gamma(x) for -10 <= x <= 10
00653        * Reduce the interval and find gamma(1 + y) for 0 <= y < 1
00654        * first of all. */
00655 
00656       int n = (int) x;
00657       if (x < 0)
00658         --n;
00659       
00660       y = x - n;/* n = floor(x)  ==>  y in [ 0, 1 ) */
00661       --n;
00662       double value = chebyshev_eval(y * 2 - 1, gamcs, 22) + .9375;
00663       
00664       if (n == 0)
00665         return value;/* x = 1.dddd = 1+y */
00666 
00667       if (n < 0) {
00668         /* compute gamma(x) for -10 <= x < 1 */
00669 
00670         /* If the argument is exactly zero or a negative integer */
00671         /* then return NaN. */
00672         SCYTHE_CHECK_10(x == 0 || (x < 0 && x == n + 2),
00673             scythe_range_error, "x is 0 or a negative integer");
00674 
00675         /* The answer is less than half precision */
00676         /* because x too near a negative integer. */
00677         SCYTHE_CHECK_10(x < -0.5 && 
00678             std::fabs(x - (int)(x - 0.5) / x) < 67108864.0,
00679             scythe_precision_error,
00680             "Answer < 1/2 precision because x is too near" <<
00681             " a negative integer");
00682 
00683         /* The argument is so close to 0 that the result
00684          * * would overflow. */
00685         SCYTHE_CHECK_10(y < 2.2474362225598545e-308, scythe_range_error,
00686             "x too close to 0");
00687 
00688         n = -n;
00689 
00690         for (int i = 0; i < n; i++)
00691           value /= (x + i);
00692         
00693         return value;
00694       } else {
00695         /* gamma(x) for 2 <= x <= 10 */
00696 
00697         for (int i = 1; i <= n; i++) {
00698           value *= (y + i);
00699         }
00700         return value;
00701       }
00702     } else {
00703       /* gamma(x) for   y = |x| > 10. */
00704 
00705       /* Overflow */
00706       SCYTHE_CHECK_10(x > 171.61447887182298, 
00707           scythe_range_error,"Overflow");
00708 
00709       /* Underflow */
00710       SCYTHE_CHECK_10(x < -170.5674972726612,
00711           scythe_range_error, "Underflow");
00712 
00713       double value = std::exp((y - 0.5) * std::log(y) - y 
00714           + M_LN_SQRT_2PI + lngammacor(y));
00715 
00716       if (x > 0)
00717         return value;
00718 
00719       SCYTHE_CHECK_10(std::fabs((x - (int)(x - 0.5))/x) < 67108864.0,
00720           scythe_precision_error, 
00721           "Answer < 1/2 precision because x is " <<
00722             "too near a negative integer");
00723 
00724       double sinpiy = std::sin(M_PI * y);
00725 
00726       /* Negative integer arg - overflow */
00727       SCYTHE_CHECK_10(sinpiy == 0, scythe_range_error, "Overflow");
00728 
00729       return -M_PI / (y * sinpiy * value);
00730     }
00731   }
00732 
00733   /* The natural log of the absolute value of the gamma function */
00750   inline double
00751   lngammafn(double x)
00752   {
00753     SCYTHE_CHECK_10(x <= 0 && x == (int) x, scythe_range_error,
00754         "x is 0 or a negative integer");
00755 
00756     double y = std::fabs(x);
00757 
00758     if (y <= 10)
00759       return std::log(std::fabs(gammafn(x)));
00760 
00761     SCYTHE_CHECK_10(y > 2.5327372760800758e+305, scythe_range_error,
00762         "Overflow");
00763 
00764     if (x > 0) /* i.e. y = x > 10 */
00765       return M_LN_SQRT_2PI + (x - 0.5) * std::log(x) - x
00766         + lngammacor(x);
00767     
00768     /* else: x < -10; y = -x */
00769     double sinpiy = std::fabs(std::sin(M_PI * y));
00770 
00771     if (sinpiy == 0) /* Negative integer argument */
00772       throw scythe_exception("UNEXPECTED ERROR",
00773            __FILE__, __func__, __LINE__,
00774            "ERROR:  Should never happen!");
00775 
00776     double ans = M_LN_SQRT_PId2 + (x - 0.5) * std::log(y) - x - std::log(sinpiy)
00777       - lngammacor(y);
00778 
00779     SCYTHE_CHECK_10(std::fabs((x - (int)(x - 0.5)) * ans / x) 
00780         < 1.490116119384765696e-8, scythe_precision_error, 
00781         "Answer < 1/2 precision because x is " 
00782         << "too near a negative integer");
00783     
00784     return ans;
00785   }
00786 
00787   /* The beta function */
00804   inline double
00805   betafn(double a, double b)
00806   {
00807     SCYTHE_CHECK_10(a <= 0 || b <= 0, scythe_invalid_arg, "a or b < 0");
00808 
00809     if (a + b < 171.61447887182298) /* ~= 171.61 for IEEE */
00810       return gammafn(a) * gammafn(b) / gammafn(a+b);
00811 
00812     double val = lnbetafn(a, b);
00813     SCYTHE_CHECK_10(val < -708.39641853226412, scythe_range_error,
00814         "Underflow");
00815     
00816     return std::exp(val);
00817   }
00818 
00819   /* The natural log of the beta function */
00837   inline double
00838   lnbetafn (double a, double b)
00839   {
00840     double p, q;
00841 
00842     p = q = a;
00843     if(b < p) p = b;/* := min(a,b) */
00844     if(b > q) q = b;/* := max(a,b) */
00845 
00846     SCYTHE_CHECK_10(p <= 0 || q <= 0,scythe_invalid_arg, "a or b <= 0");
00847 
00848     if (p >= 10) {
00849       /* p and q are big. */
00850       double corr = lngammacor(p) + lngammacor(q) - lngammacor(p + q);
00851       return std::log(q) * -0.5 + M_LN_SQRT_2PI + corr
00852         + (p - 0.5) * std::log(p / (p + q)) + q * std::log(1 + (-p / (p + q)));
00853     } else if (q >= 10) {
00854       /* p is small, but q is big. */
00855       double corr = lngammacor(q) - lngammacor(p + q);
00856       return lngammafn(p) + corr + p - p * std::log(p + q)
00857         + (q - 0.5) * std::log(1 + (-p / (p + q)));
00858     }
00859     
00860     /* p and q are small: p <= q > 10. */
00861     return std::log(gammafn(p) * (gammafn(q) / gammafn(p + q)));
00862   }
00863 
00864   /* Compute the factorial of a non-negative integer */
00874   inline int
00875   factorial (unsigned int n)
00876   {
00877     if (n == 0)
00878       return 1;
00879 
00880     return n * factorial(n - 1);
00881   }
00882 
00883   /* Compute the natural log of the factorial of a non-negative
00884    * integer
00885    */
00895   inline double
00896   lnfactorial (unsigned int n)
00897   {
00898     double x = n+1;
00899     double cof[6] = {
00900       76.18009172947146, -86.50532032941677,
00901       24.01409824083091, -1.231739572450155,
00902       0.1208650973866179e-2, -0.5395239384953e-5
00903     };
00904     double y = x;
00905     double tmp = x + 5.5 - (x + 0.5) * std::log(x + 5.5);
00906     double ser = 1.000000000190015;
00907     for (int j = 0; j <= 5; j++) {
00908       ser += (cof[j] / ++y);
00909     }
00910     return(std::log(2.5066282746310005 * ser / x) - tmp);
00911   }
00912 
00913   /*********************************
00914    * Fully Specified Distributions * 
00915    *********************************/
00916 
00917   /* These macros provide a nice shorthand for the matrix versions of
00918    * the pdf and cdf functions.
00919    */
00920  
00921 #define SCYTHE_ARGSET(...) __VA_ARGS__
00922 
00923 #define SCYTHE_DISTFUN_MATRIX(NAME, XTYPE, ARGNAMES, ...)             \
00924   template <matrix_order RO, matrix_style RS,                         \
00925             matrix_order PO, matrix_style PS>                         \
00926   Matrix<double, RO, RS>                                              \
00927   NAME (const Matrix<XTYPE, PO, PS>& X, __VA_ARGS__)                  \
00928   {                                                                   \
00929     Matrix<double, RO, Concrete> ret(X.rows(), X.cols(), false);      \
00930     const_matrix_forward_iterator<XTYPE,RO,PO,PS> xit;                \
00931     const_matrix_forward_iterator<XTYPE,RO,PO,PS> xlast               \
00932       = X.template end_f<RO>();                                       \
00933     typename Matrix<double,RO,Concrete>::forward_iterator rit         \
00934       = ret.begin_f();                                                \
00935     for (xit = X.template begin_f<RO>(); xit != xlast; ++xit) {       \
00936       *rit = NAME (*xit, ARGNAMES);                                   \
00937       ++rit;                                                          \
00938     }                                                                 \
00939     SCYTHE_VIEW_RETURN(double, RO, RS, ret)                           \
00940   }                                                                   \
00941                                                                       \
00942   template <matrix_order O, matrix_style S>                           \
00943   Matrix<double, O, Concrete>                                         \
00944   NAME (const Matrix<XTYPE, O, S>& X, __VA_ARGS__)                    \
00945   {                                                                   \
00946     return NAME <O, Concrete, O, S> (X, ARGNAMES);                    \
00947   }
00948 
00949   /**** The Beta Distribution ****/
00950 
00951   /* CDFs */
00952 
00981   inline double
00982   pbeta(double x, double a, double b)
00983   {
00984     SCYTHE_CHECK_10(a <= 0 || b <= 0,scythe_invalid_arg, "a or b <= 0");
00985     
00986     if (x <= 0)
00987       return 0.;
00988     if (x >= 1)
00989       return 1.;
00990     
00991     return pbeta_raw(x,a,b);
00992   }
00993 
00994   SCYTHE_DISTFUN_MATRIX(pbeta, double, SCYTHE_ARGSET(a, b), double a, double b)
00995 
00996   /* PDFs */
01025   inline double
01026   dbeta(double x, double a, double b)
01027   {
01028     SCYTHE_CHECK_10((x < 0.0) || (x > 1.0), scythe_invalid_arg,
01029         "x not in [0,1]");
01030     SCYTHE_CHECK_10(a < 0.0, scythe_invalid_arg, "a < 0");
01031     SCYTHE_CHECK_10(b < 0.0, scythe_invalid_arg, "b < 0");
01032 
01033     return (std::pow(x, (a-1.0)) * std::pow((1.0-x), (b-1.0)) )
01034       / betafn(a,b);
01035   }
01036 
01037   SCYTHE_DISTFUN_MATRIX(dbeta, double, SCYTHE_ARGSET(a, b), double a, double b)
01038 
01039   /* Returns the natural log of the ordinate of the Beta density
01040    * evaluated at x with Shape1 a, and Shape2 b
01041    */
01042 
01043   
01070   inline double
01071   lndbeta1(double x, double a, double b)
01072   { 
01073     SCYTHE_CHECK_10((x < 0.0) || (x > 1.0), scythe_invalid_arg,
01074         "x not in [0,1]");
01075     SCYTHE_CHECK_10(a < 0.0, scythe_invalid_arg, "a < 0");
01076     SCYTHE_CHECK_10(b < 0.0, scythe_invalid_arg, "b < 0");
01077 
01078     return (a-1.0) * std::log(x) + (b-1) * std::log(1.0-x)
01079       - lnbetafn(a,b);
01080   }
01081 
01082   SCYTHE_DISTFUN_MATRIX(lndbeta1, double, SCYTHE_ARGSET(a, b), double a, double b)
01083 
01084 
01085   /**** The Binomial Distribution ****/
01086 
01087   /* CDFs */
01088 
01089   
01115   inline double
01116   pbinom(double x, unsigned int n, double p)
01117   {
01118       
01119     SCYTHE_CHECK_10(p < 0 || p > 1, scythe_invalid_arg, "p not in [0,1]");
01120     double X = std::floor(x);
01121       
01122     if (X < 0.0)
01123       return 0;
01124     
01125     if (n <= X)
01126       return 1;
01127       
01128     return pbeta(1 - p, n - X, X + 1);
01129   }
01130 
01131   SCYTHE_DISTFUN_MATRIX(pbinom, double, SCYTHE_ARGSET(n, p), unsigned int n, double p)
01132 
01133   /* PDFs */
01160   inline double
01161   dbinom(double x, unsigned int n, double p)
01162   {
01163     SCYTHE_CHECK_10(p < 0 || p > 1, scythe_invalid_arg, "p not in [0, 1]");
01164     double X = std::floor(x + 0.5);
01165     return dbinom_raw(X, n, p, 1 - p);
01166   }
01167 
01168   SCYTHE_DISTFUN_MATRIX(dbinom, double, SCYTHE_ARGSET(n, p), unsigned int n, double p)
01169 
01170   /**** The Chi Squared Distribution ****/
01171   
01172   /* CDFs */
01200   inline double
01201   pchisq(double x, double df)
01202   {
01203     return pgamma(x, df/2.0, 2.0);
01204   }
01205 
01206   SCYTHE_DISTFUN_MATRIX(pchisq, double, df, double df)
01207 
01208   /* PDFs */
01236   inline double
01237   dchisq(double x, double df)
01238   {
01239     return dgamma(x, df / 2.0, 2.0);
01240   }
01241 
01242   SCYTHE_DISTFUN_MATRIX(dchisq, double, df, double df)
01243 
01244   /**** The Exponential Distribution ****/
01245 
01246   /* CDFs */
01270   inline double
01271   pexp(double x, double scale)
01272   {
01273     SCYTHE_CHECK_10(scale <= 0, scythe_invalid_arg, "scale <= 0");
01274     
01275     if (x <= 0)
01276       return 0;
01277     
01278     return (1 - std::exp(-x*scale));
01279   }
01280 
01281   SCYTHE_DISTFUN_MATRIX(pexp, double, scale, double scale)
01282 
01283   /* PDFs */
01307   inline double
01308   dexp(double x, double scale)
01309   {
01310     SCYTHE_CHECK_10(scale <= 0, scythe_invalid_arg, "scale <= 0");
01311     
01312     if (x < 0)
01313       return 0;
01314       
01315     return std::exp(-x * scale) * scale;
01316   }
01317 
01318   SCYTHE_DISTFUN_MATRIX(dexp, double, scale, double scale)
01319 
01320   /**** The f Distribution ****/
01321 
01322   /* CDFs */
01353   inline double
01354   pf(double x, double df1, double df2)
01355   {
01356     SCYTHE_CHECK_10(df1 <= 0 || df2 <= 0, scythe_invalid_arg, 
01357         "df1 or df2 <= 0");
01358   
01359     if (x <= 0)
01360       return 0;
01361     
01362     if (df2 > 4e5)
01363       return pchisq(x*df1,df1);
01364     if (df1 > 4e5)
01365       return 1-pchisq(df2/x,df2);
01366     
01367     return (1-pbeta(df2 / (df2 + df1 * x), df2 / 2.0, df1 / 2.0));
01368   }
01369 
01370   SCYTHE_DISTFUN_MATRIX(pf, double, SCYTHE_ARGSET(df1, df2), double df1, double df2)
01371 
01372   /* PDFs */
01373 
01374   
01403   inline double
01404   df(double x, double df1, double df2)
01405   {
01406     double dens;
01407     
01408     SCYTHE_CHECK_10(df1 <= 0 || df2 <= 0, scythe_invalid_arg, 
01409         "df1 or df2 <= 0");
01410     
01411     if (x <= 0)
01412       return 0;
01413       
01414     double f = 1 / (df2 + x * df1);
01415     double q = df2 * f;
01416     double p = x * df1 * f;
01417     
01418     if (df1 >= 2) {
01419       f = df1 * q / 2;
01420       dens = dbinom_raw((df1 - 2) / 2,(df1 + df2 - 2) / 2, p, q);
01421     } else {
01422       f = (df1 * df1 * q) /(2 * p * (df1 + df2));
01423       dens = dbinom_raw(df1 / 2,(df1 + df2)/ 2, p, q);
01424     }
01425     
01426     return f*dens;
01427   }
01428 
01429   SCYTHE_DISTFUN_MATRIX(df, double, SCYTHE_ARGSET(df1, df2), double df1, double df2)
01430 
01431   /**** The Gamma Distribution ****/
01432 
01433   /* CDFs */
01463   inline double
01464   pgamma (double x, double shape, double scale)
01465   {
01466     const double xbig = 1.0e+8, xlarge = 1.0e+37, 
01467       alphlimit = 1000.;/* normal approx. for shape > alphlimit */
01468       
01469     int lower_tail = 1;
01470 
01471     double pn1, pn2, pn3, pn4, pn5, pn6, arg, a, b, c, an, osum, sum;
01472     long n;
01473     int pearson;
01474 
01475     /* check that we have valid values for x and shape */
01476 
01477     SCYTHE_CHECK_10(shape <= 0. || scale <= 0., scythe_invalid_arg,
01478         "shape or scale <= 0");
01479 
01480     x /= scale;
01481     
01482     if (x <= 0.)
01483       return 0.0;
01484 
01485     /* use a normal approximation if shape > alphlimit */
01486 
01487     if (shape > alphlimit) {
01488       pn1 = std::sqrt(shape) * 3. * (std::pow(x/shape, 1./3.) + 1.
01489             / (9. * shape) - 1.);
01490       return pnorm(pn1, 0., 1.);
01491     }
01492 
01493     /* if x is extremely large __compared to shape__ then return 1 */
01494 
01495     if (x > xbig * shape)
01496       return 1.0;
01497 
01498     if (x <= 1. || x < shape) {
01499       pearson = 1;/* use pearson's series expansion. */
01500       arg = shape * std::log(x) - x - lngammafn(shape + 1.);
01501       c = 1.;
01502       sum = 1.;
01503       a = shape;
01504       do {
01505         a += 1.;
01506         c *= x / a;
01507         sum += c;
01508       } while (c > DBL_EPSILON);
01509       arg += std::log(sum);
01510     }
01511     else { /* x >= max( 1, shape) */
01512       pearson = 0;/* use a continued fraction expansion */
01513       arg = shape * std::log(x) - x - lngammafn(shape);
01514       a = 1. - shape;
01515       b = a + x + 1.;
01516       pn1 = 1.;
01517       pn2 = x;
01518       pn3 = x + 1.;
01519       pn4 = x * b;
01520       sum = pn3 / pn4;
01521       for (n = 1; ; n++) {
01522         a += 1.;/* =   n+1 -shape */
01523         b += 2.;/* = 2(n+1)-shape+x */
01524         an = a * n;
01525         pn5 = b * pn3 - an * pn1;
01526         pn6 = b * pn4 - an * pn2;
01527         if (std::fabs(pn6) > 0.) {
01528           osum = sum;
01529           sum = pn5 / pn6;
01530           if (std::fabs(osum - sum) <= DBL_EPSILON * std::min(1., sum))
01531             break;
01532         }
01533         pn1 = pn3;
01534         pn2 = pn4;
01535         pn3 = pn5;
01536         pn4 = pn6;
01537         if (std::fabs(pn5) >= xlarge) {
01538           /* re-scale terms in continued fraction if they are large */
01539           pn1 /= xlarge;
01540           pn2 /= xlarge;
01541           pn3 /= xlarge;
01542           pn4 /= xlarge;
01543         }
01544       }
01545       arg += std::log(sum);
01546     }
01547 
01548     lower_tail = (lower_tail == pearson);
01549 
01550     sum = std::exp(arg);
01551 
01552     return (lower_tail) ? sum : 1 - sum;
01553   }
01554 
01555   SCYTHE_DISTFUN_MATRIX(pgamma, double, SCYTHE_ARGSET(shape, scale), double shape, double scale)
01556 
01557   /* PDFs */
01587   inline double
01588   dgamma(double x, double shape, double scale)
01589   {
01590     SCYTHE_CHECK_10(shape <= 0 || scale <= 0,scythe_invalid_arg,
01591         "shape or scale <= 0");
01592 
01593     if (x < 0)
01594       return 0.0;
01595     
01596     if (x == 0) {
01597       SCYTHE_CHECK_10(shape < 1,scythe_invalid_arg, 
01598           "x == 0 and shape < 1");
01599       
01600       if (shape > 1)
01601         return 0.0;
01602       
01603       return 1 / scale;
01604     }
01605     
01606     if (shape < 1) { 
01607       double pr = dpois_raw(shape, x/scale);
01608       return pr * shape / x;
01609     }
01610     
01611     /* else  shape >= 1 */
01612     double pr = dpois_raw(shape - 1, x / scale);
01613     return pr / scale;
01614   }
01615 
01616   SCYTHE_DISTFUN_MATRIX(dgamma, double, SCYTHE_ARGSET(shape, scale), double shape, double scale)
01617 
01618   /**** The Logistic Distribution ****/
01619 
01620   /* CDFs */
01645   inline double
01646   plogis (double x, double location, double scale)
01647   {
01648     SCYTHE_CHECK_10(scale <= 0.0, scythe_invalid_arg, "scale <= 0");
01649     
01650     double X = (x-location) / scale;
01651       
01652     X = std::exp(-X);
01653       
01654     return 1 / (1+X);
01655   }
01656 
01657   SCYTHE_DISTFUN_MATRIX(plogis, double, SCYTHE_ARGSET(location, scale), double location, double scale)
01658 
01659   /* PDFs */
01684   inline double
01685   dlogis(double x, double location, double scale)
01686   {
01687     SCYTHE_CHECK_10(scale <= 0.0, scythe_invalid_arg, "scale <= 0");
01688     
01689     double X = (x - location) / scale;
01690     double e = std::exp(-X);
01691     double f = 1.0 + e;
01692       
01693     return e / (scale * f * f);
01694   }
01695 
01696   SCYTHE_DISTFUN_MATRIX(dlogis, double, SCYTHE_ARGSET(location, scale), double location, double scale)
01697 
01698   /**** The Log Normal Distribution ****/
01699 
01700   /* CDFs */
01727   inline double
01728   plnorm (double x, double logmean, double logsd)
01729   {
01730     SCYTHE_CHECK_10(logsd <= 0, scythe_invalid_arg, "logsd <= 0");
01731     
01732     if (x > 0)
01733       return pnorm(std::log(x), logmean, logsd);
01734     
01735     return 0;
01736   }
01737 
01738   SCYTHE_DISTFUN_MATRIX(plnorm, double, SCYTHE_ARGSET(logmean, logsd), double logmean, double logsd)
01739 
01740   /* PDFs */
01766   inline double
01767   dlnorm(double x, double logmean, double logsd)
01768   {
01769     SCYTHE_CHECK_10(logsd <= 0, scythe_invalid_arg, "logsd <= 0");
01770     
01771     if (x == 0)
01772       return 0;
01773     
01774     double y = (std::log(x) - logmean) / logsd;
01775     
01776     return (1 / (std::sqrt(2 * M_PI))) * std::exp(-0.5 * y * y) / (x * logsd);
01777   }
01778 
01779   SCYTHE_DISTFUN_MATRIX(dlnorm, double, SCYTHE_ARGSET(logmean, logsd), double logmean, double logsd)
01780 
01781   /**** The Negative Binomial Distribution ****/
01782 
01783   /* CDFs */
01812   inline double
01813   pnbinom(unsigned int x, double n, double p)
01814   {
01815     SCYTHE_CHECK_10(n == 0 || p <= 0 || p >= 1, scythe_invalid_arg,
01816         "n == 0 or p not in (0,1)");
01817     
01818     return pbeta(p, n, x + 1);
01819   }
01820 
01821   SCYTHE_DISTFUN_MATRIX(pnbinom, unsigned int, SCYTHE_ARGSET(n, p), double n, double p)
01822 
01823   /* PDFs */
01852   inline double
01853   dnbinom(unsigned int x, double n, double p)
01854   {
01855     SCYTHE_CHECK_10(n == 0 || p <= 0 || p >= 1, scythe_invalid_arg,
01856         "n == 0 or p not in (0,1)");
01857     
01858     double prob = dbinom_raw(n, x + n, p, 1 - p);
01859     double P = (double) n / (n + x);
01860     
01861     return P * prob;
01862   }
01863 
01864   SCYTHE_DISTFUN_MATRIX(dnbinom, unsigned int, SCYTHE_ARGSET(n, p), double n, double p)
01865 
01866   /**** The Normal Distribution ****/
01867   
01868   /* CDFs */
01894   inline double
01895   pnorm (double x, double mean, double sd)
01896   
01897   {
01898     SCYTHE_CHECK_10(sd <= 0, scythe_invalid_arg,
01899         "negative standard deviation");
01900 
01901     return pnorm1((x - mean) / sd, true, false);
01902   }
01903 
01904   SCYTHE_DISTFUN_MATRIX(pnorm, double, SCYTHE_ARGSET(mean, sd), double mean, double sd)
01905   
01906 
01907   /* PDFs */
01932   inline double
01933   dnorm(double x, double mean, double sd)
01934   {
01935     SCYTHE_CHECK_10(sd <= 0, scythe_invalid_arg,
01936         "negative standard deviation");
01937     
01938     double X = (x - mean) / sd;
01939     
01940     return (M_1_SQRT_2PI * std::exp(-0.5 * X * X) / sd);
01941   }
01942 
01943   SCYTHE_DISTFUN_MATRIX(dnorm, double, SCYTHE_ARGSET(mean, sd), double mean, double sd)
01944  
01945 
01946   /* Return the natural log of the normal PDF */
01972   inline double
01973   lndnorm (double x, double mean, double sd)
01974   {
01975     SCYTHE_CHECK_10(sd <= 0, scythe_invalid_arg,
01976         "negative standard deviation");
01977     
01978     double X = (x - mean) / sd;
01979     
01980     return -(M_LN_SQRT_2PI  +  0.5 * X * X + std::log(sd));
01981   }
01982 
01983   SCYTHE_DISTFUN_MATRIX(lndnorm, double, SCYTHE_ARGSET(mean, sd), double mean, double sd)
01984 
01985   /* Quantile functions */
02008   inline double
02009   qnorm1 (double in_p)
02010   {
02011     double p0 = -0.322232431088;
02012     double q0 = 0.0993484626060;
02013     double p1 = -1.0;
02014     double q1 = 0.588581570495;
02015     double p2 = -0.342242088547;
02016     double q2 = 0.531103462366;
02017     double p3 = -0.0204231210245;
02018     double q3 = 0.103537752850;
02019     double p4 = -0.453642210148e-4;
02020     double q4 = 0.38560700634e-2;
02021     double xp = 0.0;
02022     double p = in_p;
02023       
02024     if (p > 0.5)
02025       p = 1 - p;
02026         
02027     SCYTHE_CHECK_10(p < 10e-20, scythe_range_error,
02028         "p outside accuracy limit");
02029       
02030     if (p == 0.5)
02031       return xp;
02032       
02033     double y = std::sqrt (std::log (1.0 / std::pow (p, 2)));
02034     xp = y + ((((y * p4 + p3) * y + p2) * y + p1) * y + p0) /
02035       ((((y * q4 + q3) * y + q2) * y + q1) * y + q0);
02036       
02037     if (in_p < 0.5)
02038       xp = -1 * xp;
02039     
02040     return xp;
02041   }
02042 
02043   SCYTHE_DISTFUN_MATRIX(qnorm1, double, in_p, double in_p)
02044 
02045   /**** The Poisson Distribution ****/
02046 
02047   /* CDFs */
02074   inline double
02075   ppois(unsigned int x, double lambda)
02076   {
02077     SCYTHE_CHECK_10(lambda<=0.0, scythe_invalid_arg, "lambda <= 0");
02078     
02079     if (lambda == 1)
02080       return 1;
02081     
02082     return 1 - pgamma(lambda, x + 1, 1.0);
02083   }
02084 
02085   SCYTHE_DISTFUN_MATRIX(ppois, unsigned int, lambda, double lambda)
02086 
02087   /* PDFs */
02111   inline double
02112   dpois(unsigned int x, double lambda)
02113   {
02114     SCYTHE_CHECK_10(lambda<=0.0, scythe_invalid_arg, "lambda <= 0");
02115     
02116     // compute log(x!)
02117     double xx = x+1;
02118     double cof[6] = {
02119       76.18009172947146, -86.50532032941677,
02120       24.01409824083091, -1.231739572450155,
02121       0.1208650973866179e-2, -0.5395239384953e-5
02122     };
02123     double y = xx;
02124     double tmp = xx + 5.5 - (xx + 0.5) * std::log(xx + 5.5);
02125     double ser = 1.000000000190015;
02126     for (int j = 0; j <= 5; j++) {
02127       ser += (cof[j] / ++y);
02128     }
02129     double lnfactx = std::log(2.5066282746310005 * ser / xx) - tmp;
02130       
02131     return (std::exp( -1*lnfactx + x * std::log(lambda) - lambda));
02132   }
02133 
02134   SCYTHE_DISTFUN_MATRIX(dpois, unsigned int, lambda, double lambda)
02135 
02136   /**** The t Distribution ****/
02137 
02138   /* CDFs */
02165   inline double
02166   pt(double x, double n)
02167   {
02168     double val;
02169     
02170     SCYTHE_CHECK_10(n <= 0, scythe_invalid_arg, "n <= 0");
02171     
02172     if (n > 4e5) {
02173       val = 1/(4*n);
02174       return pnorm1(x * (1 - val) / ::sqrt(1 + x * x * 2. * val), 
02175           true, false);
02176     }
02177     
02178     val = pbeta(n / (n + x * x), n / 2.0, 0.5);
02179     
02180     val /= 2;
02181     
02182     if (x <= 0)
02183       return val;
02184     else
02185       return 1 - val;
02186   }
02187 
02188   SCYTHE_DISTFUN_MATRIX(pt, double, n, double n)
02189   
02190   /* PDFs */
02216   inline double
02217   dt(double x, double n)
02218   {
02219     double u;
02220 
02221     SCYTHE_CHECK_10(n <= 0, scythe_invalid_arg, "n <= 0");
02222     
02223     double t = -bd0(n/2., (n + 1) / 2.)
02224       + stirlerr((n + 1) / 2.)
02225       - stirlerr(n / 2.);
02226     if(x*x > 0.2*n)
02227       u = std::log(1+x*x/n)*n/2;
02228     else
02229       u = -bd0(n/2., (n+x*x)/2.) + x*x/2;
02230     
02231     return std::exp(t-u)/std::sqrt(2*M_PI*(1+x*x/n));
02232   }
02233 
02234   SCYTHE_DISTFUN_MATRIX(dt, double, n, double n)
02235   
02236   /* Returns the univariate Student-t density evaluated at x 
02237    * with mean mu, scale sigma^2, and nu degrees of freedom.  
02238    *
02239    * TODO:  Do we want a pt for this distribution?
02240    */
02241 
02242   
02270   inline double
02271   dt1(double x, double mu, double sigma2, double nu)
02272   {
02273     double logdens =   lngammafn((nu + 1.0) /2.0)
02274       - std::log(std::sqrt(nu * M_PI))
02275       - lngammafn(nu / 2.0) - std::log(std::sqrt(sigma2))
02276       - (nu + 1.0) / 2.0 * std::log(1.0 + (std::pow((x - mu), 2.0))
02277             / (nu * sigma2));
02278     
02279     return(std::exp(logdens));
02280   }
02281 
02282   SCYTHE_DISTFUN_MATRIX(dt1, double, SCYTHE_ARGSET(mu, sigma2, nu), double mu, double sigma2, double nu)
02283 
02284   /* Returns the natural log of the univariate Student-t density 
02285    * evaluated at x with mean mu, scale sigma^2, and nu 
02286    * degrees of freedom
02287    */
02288    
02289   
02318   inline double 
02319   lndt1(double x, double mu, double sigma2, double nu)
02320   {
02321     double logdens = lngammafn((nu+1.0)/2.0)
02322       - std::log(std::sqrt(nu*M_PI))
02323       - lngammafn(nu/2.0) - std::log(std::sqrt(sigma2))
02324       - (nu+1.0)/2.0 * std::log(1.0 + (std::pow((x-mu),2.0))
02325         /(nu * sigma2));
02326     
02327     return(logdens);
02328   }
02329 
02330   SCYTHE_DISTFUN_MATRIX(lndt1, double, SCYTHE_ARGSET(mu, sigma2, nu), double mu, double sigma2, double nu)
02331 
02332   /**** The Uniform Distribution ****/
02333 
02334   /* CDFs */
02359   inline double
02360   punif(double x, double a, double b)
02361   {
02362     SCYTHE_CHECK_10(b <= a, scythe_invalid_arg, "b <= a");
02363       
02364     if (x <= a)
02365       return 0.0;
02366         
02367     if (x >= b)
02368       return 1.0;
02369       
02370     return (x - a) / (b - a);
02371   }
02372 
02373   SCYTHE_DISTFUN_MATRIX(punif, double, SCYTHE_ARGSET(a, b), double a, double b)
02374 
02375   /* PDFs */
02400   inline double
02401   dunif(double x, double a, double b)
02402   {
02403     SCYTHE_CHECK_10(b <= a, scythe_invalid_arg, "b <= a");
02404     
02405     if (a <= x && x <= b)
02406       return 1.0 / (b - a);
02407     
02408     return 0.0;
02409   }
02410 
02411   SCYTHE_DISTFUN_MATRIX(dunif, double, SCYTHE_ARGSET(a, b), double a, double b)
02412 
02413   /**** The Weibull Distribution ****/
02414 
02415   /* CDFs */
02440   inline double
02441   pweibull(double x, double shape, double scale)
02442   {
02443     SCYTHE_CHECK_10(shape <= 0 || scale <= 0, scythe_invalid_arg,
02444         "shape or scale <= 0");
02445     
02446     if (x <= 0)
02447       return 0.0;
02448     
02449     return 1 - std::exp(-std::pow(x / scale, shape));
02450   }
02451 
02452   SCYTHE_DISTFUN_MATRIX(pweibull, double, SCYTHE_ARGSET(shape, scale), double shape, double scale)
02453 
02454   /* PDFs */
02479   inline double
02480   dweibull(double x, double shape, double scale)
02481   {
02482     SCYTHE_CHECK_10(shape <= 0 || scale <= 0, scythe_invalid_arg,
02483         "shape or scale <= 0");
02484 
02485     if (x < 0)
02486       return 0.;
02487       
02488     double tmp1 = std::pow(x / scale, shape - 1);
02489     double tmp2 = tmp1*(x / scale);
02490       
02491     return shape * tmp1 * std::exp(-tmp2) / scale;
02492   }
02493 
02494   SCYTHE_DISTFUN_MATRIX(dweibull, double, SCYTHE_ARGSET(shape, scale), double shape, double scale)
02495 
02496   /* Multivariate Normal */
02497 
02498   // TODO: distribution function.  Plain old (non-logged) dmvnorm.
02499 
02500   
02518   template <matrix_order O1, matrix_style S1,
02519             matrix_order O2, matrix_style S2,
02520             matrix_order O3, matrix_style S3>
02521   double lndmvn (const Matrix<double, O1, S1>& x,
02522                  const Matrix<double, O2, S2>& mu,
02523                  const Matrix<double, O3, S3>& Sigma)
02524   {
02525     SCYTHE_CHECK_10(! x.isColVector(), scythe_dimension_error,
02526         "x is not a column vector");
02527     SCYTHE_CHECK_10(! mu.isColVector(), scythe_dimension_error,
02528         "mu is not a column vector");
02529     SCYTHE_CHECK_10(! Sigma.isSquare(), scythe_dimension_error,
02530         "Sigma is not square");
02531     SCYTHE_CHECK_10(mu.rows()!=Sigma.rows() || x.rows()!=Sigma.rows(), 
02532                     scythe_conformation_error,
02533                     "mu, x and Sigma have mismatched row lengths")
02534     int k = (int) mu.rows();
02535     return ( (-k/2.0)*std::log(2*M_PI) -0.5 * std::log(det(Sigma)) 
02536        -0.5 * (t(x - mu)) * invpd(Sigma) * (x-mu) )[0];
02537   }
02538 
02539 } // end namespace scythe
02540 
02541 
02542 #endif /* SCYTHE_DISTRIBUTIONS_H */