Scythe-1.0.3
rng.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/rng.h
00014  *
00015  * The code for many of the RNGs defined in this file and implemented
00016  * in rng.cc is based on that in the R project, version 1.6.0-1.7.1.
00017  * This code is available under the terms of the GNU GPL.  Original
00018  * copyright:
00019  * 
00020  * Copyright (C) 1998      Ross Ihaka
00021  * Copyright (C) 2000-2002 The R Development Core Team
00022  * Copyright (C) 2003      The R Foundation
00023  */
00024 
00032 /* Doxygen doesn't deal well with the macros that we use to make
00033  * matrix versions of rngs easy to define.
00034  */
00035 
00036 #ifndef SCYTHE_RNG_H
00037 #define SCYTHE_RNG_H
00038 
00039 #include <iostream>
00040 #include <cmath>
00041 
00042 #ifdef HAVE_IEEEFP_H
00043 #include <ieeefp.h>
00044 #endif
00045 
00046 #ifdef SCYTHE_COMPILE_DIRECT
00047 #include "matrix.h"
00048 #include "error.h"
00049 #include "algorithm.h"
00050 #include "distributions.h"
00051 #include "ide.h"
00052 #include "la.h"
00053 #else
00054 #include "scythestat/matrix.h"
00055 #include "scythestat/error.h"
00056 #include "scythestat/algorithm.h"
00057 #include "scythestat/distributions.h"
00058 #include "scythestat/ide.h"
00059 #include "scythestat/la.h"
00060 #endif
00061 
00062 namespace scythe {
00063 
00064 /* Shorthand for the matrix versions of the various distributions'
00065  * random number generators.
00066  */
00067   
00068 #define SCYTHE_RNGMETH_MATRIX(NAME, RTYPE, ARGNAMES, ...)             \
00069   template <matrix_order O, matrix_style S>                           \
00070   Matrix<RTYPE, O, S>                                                 \
00071   NAME (unsigned int rows, unsigned int cols, __VA_ARGS__)            \
00072   {                                                                   \
00073     Matrix<RTYPE, O, Concrete> ret(rows, cols, false);                \
00074     typename Matrix<RTYPE,O,Concrete>::forward_iterator it;           \
00075     typename Matrix<RTYPE,O,Concrete>::forward_iterator last          \
00076       = ret.end_f();                                                  \
00077     for (it = ret.begin_f(); it != last; ++it)                        \
00078       *it = NAME (ARGNAMES);                                          \
00079     SCYTHE_VIEW_RETURN(RTYPE, O, S, ret)                              \
00080   }                                                                   \
00081                                                                       \
00082   Matrix<RTYPE, Col, Concrete>                                        \
00083   NAME (unsigned int rows, unsigned int cols, __VA_ARGS__)            \
00084   {                                                                   \
00085     return NAME <Col,Concrete> (rows, cols, ARGNAMES);                \
00086   }
00087 
00127   template <class RNGTYPE>
00128   class rng
00129   {
00130     public:
00131 
00132       /* This declaration allows users to treat rng objects like
00133        * functors that generate random uniform numbers.  This can be
00134        * quite convenient.
00135        */
00143       double operator() ()
00144       {
00145         return runif();
00146       }
00147 
00148       /* Returns random uniform numbers on (0, 1).  This function must
00149        * be implemented by extending classes */
00159       double runif ()
00160       {
00161         return as_derived().runif();
00162       }
00163 
00164 
00165       /* No point in declaring these virtual because we have to
00166        * override them anyway because C++ isn't too bright.  Also, it
00167        * is illegal to make template methods virtual
00168        */
00169       template <matrix_order O, matrix_style S>
00170       Matrix<double,O,S> runif(unsigned int rows, 
00171                                unsigned int cols) 
00172       {
00173         Matrix<double, O, S> ret(rows, cols, false);
00174         typename Matrix<double,O,S>::forward_iterator it;
00175         typename Matrix<double,O,S>::forward_iterator last=ret.end_f();
00176         for (it = ret.begin_f(); it != last; ++it)
00177           *it = runif();
00178 
00179         return ret;
00180       }
00181 
00182       Matrix<double,Col,Concrete> runif(unsigned int rows, 
00183                                         unsigned int cols)
00184       {
00185         return runif<Col,Concrete>(rows, cols);
00186       }
00187 
00204       double
00205       rbeta (double alpha, double beta)
00206       {
00207         double report;
00208         double xalpha, xbeta;
00209         
00210         // Check for allowable parameters
00211         SCYTHE_CHECK_10(alpha <= 0, scythe_invalid_arg, "alpha <= 0");
00212         SCYTHE_CHECK_10(beta <= 0, scythe_invalid_arg, "beta <= 0");
00213         
00214         xalpha = rchisq (2 * alpha);
00215         xbeta = rchisq (2 * beta);
00216         report = xalpha / (xalpha + xbeta);
00217         
00218         return (report);
00219       }
00220 
00221       SCYTHE_RNGMETH_MATRIX(rbeta, double, SCYTHE_ARGSET(alpha, beta),
00222           double alpha, double beta);
00223 
00240       double 
00241       rnchypgeom(double m1, double n1, double n2, double psi,
00242                  double delta)
00243       {
00244         // Calculate mode of mass function
00245         double a = psi - 1;
00246         double b = -1 * ((n1+m1+2)*psi + n2 - m1);
00247         double c = psi * (n1+1) * (m1+1);
00248         double q = -0.5 * ( b + sgn(b) * 
00249             std::sqrt(std::pow(b,2) - 4*a*c));
00250         double root1 = c/q;
00251         double root2 = q/a;
00252         double el = std::max(0.0, m1-n2);
00253         double u = std::min(n1,m1);
00254         double mode = std::floor(root1);
00255         int exactcheck = 0;
00256         if (u<mode || mode<el) {
00257           mode = std::floor(root2);
00258           exactcheck = 1;
00259         }
00260      
00261 
00262         int size = static_cast<int>(u+1);
00263 
00264         double *fvec = new double[size];
00265         fvec[static_cast<int>(mode)] = 1.0;
00266         double s;
00267         // compute the mass function at y
00268         if (delta <= 0 || exactcheck==1){  //exact evaluation 
00269           // sum from mode to u
00270           double f = 1.0;
00271           s = 1.0;
00272           for (double i=(mode+1); i<=u; ++i){
00273             double r = ((n1-i+1)*(m1-i+1))/(i*(n2-m1+i)) * psi;
00274             f = f*r;
00275             s += f;
00276             fvec[static_cast<int>(i)] = f;
00277           }
00278          
00279           // sum from mode to el
00280           f = 1.0;
00281           for (double i=(mode-1); i>=el; --i){
00282             double r = ((n1-i)*(m1-i))/((i+1)*(n2-m1+i+1)) * psi;
00283             f = f/r;
00284             s += f;
00285             fvec[static_cast<int>(i)] = f;
00286           }
00287         } else { // approximation
00288           double epsilon = delta/10.0;
00289           // sum from mode to ustar
00290           double f = 1.0;
00291           s = 1.0;
00292           double i = mode+1;
00293           double r;
00294           do {
00295             if (i>u) break;
00296             r = ((n1-i+1)*(m1-i+1))/(i*(n2-m1+i)) * psi;
00297             f = f*r;
00298             s += f;
00299             fvec[static_cast<int>(i)] = f;
00300             ++i;
00301           } while(f>=epsilon || r>=5.0/6.0);
00302          
00303           // sum from mode to elstar
00304           f = 1.0;
00305           i = mode-1;
00306           do {
00307             if (i<el) break;
00308             r = ((n1-i)*(m1-i))/((i+1)*(n2-m1+i+1)) * psi;
00309             f = f/r;
00310             s += f;
00311             fvec[static_cast<int>(i)] = f;
00312             --i;
00313           } while(f>=epsilon || r <=6.0/5.0);         
00314         }
00315 
00316         double udraw = runif();
00317         double psum = fvec[static_cast<int>(mode)]/s;
00318         if (udraw<=psum)
00319           return mode;
00320         double lower = mode-1;
00321         double upper = mode+1;
00322 
00323         do{
00324           double fl;
00325           double fu;
00326           if (lower >= el)
00327             fl = fvec[static_cast<int>(lower)];
00328           else 
00329             fl = 0.0;
00330 
00331           if (upper <= u)
00332             fu = fvec[static_cast<int>(upper)];
00333           else
00334             fu = 0.0;
00335 
00336           if (fl > fu) {
00337             psum += fl/s;
00338             if (udraw<=psum)
00339               return lower;
00340             --lower;
00341           } else {
00342             psum += fu/s;
00343             if (udraw<=psum)
00344               return upper;
00345             ++upper;
00346           }
00347         } while(udraw>psum);
00348        
00349         delete [] fvec;
00350         SCYTHE_THROW(scythe_convergence_error,
00351           "Algorithm did not converge");
00352       }
00353 
00354       SCYTHE_RNGMETH_MATRIX(rnchypgeom, double,
00355           SCYTHE_ARGSET(m1, n1, n2, psi, delta), double m1, double n1,
00356           double n2, double psi, double delta);
00357 
00367       unsigned int
00368       rbern (double p)
00369       {
00370         unsigned int report;
00371         double unif;
00372           
00373         // Check for allowable paramters
00374         SCYTHE_CHECK_10(p < 0 || p > 1, scythe_invalid_arg,
00375             "p parameter not in[0,1]");
00376         
00377         unif = runif ();
00378         if (unif < p)
00379           report = 1;
00380         else
00381           report = 0;
00382         
00383         return (report);
00384       }
00385 
00386       SCYTHE_RNGMETH_MATRIX(rbern, unsigned int, p, double p);
00387       
00402       unsigned int
00403       rbinom (unsigned int n, double p)
00404       {
00405         unsigned int report;
00406         unsigned int count = 0;
00407         double hold;
00408           
00409         // Check for allowable parameters
00410         SCYTHE_CHECK_10(n == 0, scythe_invalid_arg, "n == 0");
00411         SCYTHE_CHECK_10(p < 0 || p > 1, scythe_invalid_arg, 
00412             "p not in [0,1]");
00413           
00414         // Loop and count successes
00415         for (unsigned int i = 0; i < n; i++) {
00416           hold = runif ();
00417           if (hold < p)
00418             ++count;
00419         }
00420         report = count;
00421         
00422         return (report);
00423       }
00424 
00425       SCYTHE_RNGMETH_MATRIX(rbinom, unsigned int, SCYTHE_ARGSET(n, p),
00426           unsigned int n, double p);
00427 
00440       double
00441       rchisq (double df)
00442       {
00443         double report;
00444           
00445         // Check for allowable paramter
00446         SCYTHE_CHECK_10(df <= 0, scythe_invalid_arg,
00447             "Degrees of freedom <= 0");
00448       
00449         // Return Gamma(nu/2, 1/2) variate
00450         report = rgamma (df / 2, .5);
00451         
00452         return (report);
00453       }
00454 
00455       SCYTHE_RNGMETH_MATRIX(rchisq, double, df, double df);
00456 
00470       double
00471       rexp (double invscale)
00472       {
00473         double report;
00474         
00475         // Check for allowable parameter
00476         SCYTHE_CHECK_10(invscale <= 0, scythe_invalid_arg,
00477             "Inverse scale parameter <= 0");
00478         
00479         report = -std::log (runif ()) / invscale;
00480         
00481         return (report);
00482       }
00483 
00484       SCYTHE_RNGMETH_MATRIX(rexp, double, invscale, double invscale);
00485     
00501       double
00502       rf (double df1, double df2)
00503       {
00504         SCYTHE_CHECK_10(df1 <= 0 || df2 <= 0, scythe_invalid_arg,
00505             "n1 or n2 <= 0");
00506 
00507         return ((rchisq(df1) / df1) / (rchisq(df2) / df2));
00508       }
00509 
00510       SCYTHE_RNGMETH_MATRIX(rf, double, SCYTHE_ARGSET(df1, df2),
00511           double df1, double df2);
00512 
00528       double
00529       rgamma (double shape, double rate)
00530       {
00531         double report;
00532 
00533         // Check for allowable parameters
00534         SCYTHE_CHECK_10(shape <= 0, scythe_invalid_arg, "shape <= 0");
00535         SCYTHE_CHECK_10(rate <= 0, scythe_invalid_arg, "rate <= 0");
00536 
00537         if (shape > 1)
00538           report = rgamma1 (shape) / rate;
00539         else if (shape == 1)
00540           report = -std::log (runif ()) / rate;
00541         else
00542           report = rgamma1 (shape + 1) 
00543             * std::pow (runif (), 1 / shape) / rate;
00544 
00545         return (report);
00546       }
00547 
00548       SCYTHE_RNGMETH_MATRIX(rgamma, double, SCYTHE_ARGSET(shape, rate),
00549           double shape, double rate);
00550 
00565       double
00566       rlogis (double location, double scale)
00567       {
00568         double report;
00569         double unif;
00570           
00571         // Check for allowable paramters
00572         SCYTHE_CHECK_10(scale <= 0, scythe_invalid_arg, "scale <= 0");
00573         
00574         unif = runif ();
00575         report = location + scale * std::log (unif / (1 - unif));
00576         
00577         return (report);
00578       }
00579 
00580       SCYTHE_RNGMETH_MATRIX(rlogis, double, 
00581           SCYTHE_ARGSET(location, scale),
00582           double location, double scale);
00583 
00599       double
00600       rlnorm (double logmean, double logsd)
00601       {
00602         SCYTHE_CHECK_10(logsd < 0.0, scythe_invalid_arg,
00603             "standard deviation < 0");
00604 
00605         return std::exp(rnorm(logmean, logsd));
00606       }
00607 
00608       SCYTHE_RNGMETH_MATRIX(rlnorm, double, 
00609           SCYTHE_ARGSET(logmean, logsd),
00610           double logmean, double logsd);
00611 
00628       unsigned int
00629       rnbinom (double n, double p)
00630       {
00631         SCYTHE_CHECK_10(n == 0 || p <= 0 || p > 1, scythe_invalid_arg,
00632             "n == 0, p <= 0, or p > 1");
00633 
00634         return rpois(rgamma(n, (1 - p) / p));
00635       }
00636 
00637       SCYTHE_RNGMETH_MATRIX(rnbinom, unsigned int,
00638           SCYTHE_ARGSET(n, p), double n, double p);
00639 
00654       double
00655       rnorm (double mean = 0, double sd = 1)
00656       {
00657         SCYTHE_CHECK_10(sd <= 0, scythe_invalid_arg, 
00658             "Negative standard deviation");
00659         
00660         return (mean + rnorm1 () * sd);
00661       }
00662 
00663       SCYTHE_RNGMETH_MATRIX(rnorm, double, SCYTHE_ARGSET(mean, sd),
00664           double mean, double sd);
00665 
00680       unsigned int
00681       rpois(double lambda)
00682       {
00683         SCYTHE_CHECK_10(lambda <= 0, scythe_invalid_arg, "lambda <= 0");
00684         unsigned int n;
00685         
00686         if (lambda < 33) {
00687           double cutoff = std::exp(-lambda);
00688           n = -1;
00689           double t = 1.0;
00690           do {
00691             ++n;
00692             t *= runif();
00693           } while (t > cutoff);    
00694         } else {
00695           bool accept = false;
00696           double c = 0.767 - 3.36/lambda;
00697           double beta = M_PI/std::sqrt(3*lambda);
00698           double alpha = lambda*beta;
00699           double k = std::log(c) - lambda - std::log(beta);
00700             
00701           while (! accept){
00702             double u1 = runif();
00703             double x = (alpha - std::log((1-u1)/u1))/beta;
00704             while (x <= -0.5){
00705               u1 = runif();
00706               x = (alpha - std::log((1-u1)/u1))/beta;
00707             } 
00708             n = static_cast<int>(x + 0.5);
00709             double u2 = runif();
00710             double lhs = alpha - beta*x +
00711               std::log(u2/std::pow(1+std::exp(alpha-beta*x),2));
00712             double rhs = k + n*std::log(lambda) - lnfactorial(n);
00713             if (lhs <= rhs)
00714               accept = true;
00715           }
00716         }
00717         
00718         return n;
00719       }
00720 
00721       SCYTHE_RNGMETH_MATRIX(rpois, unsigned int, lambda, double lambda);
00722 
00723       /* There is a naming issue here, with respect to the p- and d-
00724        * functions in distributions.  This is really analagous to rt1-
00725        * and dt1- XXX Clear up.  Also, we should probably have a
00726        * random number generator for both versions of the student t.
00727        */
00728 
00743       double
00744       rt (double mu, double sigma2, double nu)
00745       {
00746         double report;
00747         double x, z;
00748           
00749         // Check for allowable paramters
00750         SCYTHE_CHECK_10(sigma2 <= 0, scythe_invalid_arg,
00751             "Variance parameter sigma2 <= 0");
00752         SCYTHE_CHECK_10(nu <= 0, scythe_invalid_arg,
00753             "D.O.F parameter nu <= 0");
00754         
00755         z = rnorm1 ();
00756         x = rchisq (nu);
00757         report = mu + std::sqrt (sigma2) * z 
00758           * std::sqrt (nu) / std::sqrt (x);
00759         
00760         return (report);
00761       }
00762 
00763       SCYTHE_RNGMETH_MATRIX(rt1, double, SCYTHE_ARGSET(mu, sigma2, nu),
00764           double mu, double sigma2, double nu);
00765 
00779       double
00780       rweibull (double shape, double scale)
00781       {
00782         SCYTHE_CHECK_10(shape <= 0 || scale <= 0, scythe_invalid_arg,
00783             "shape or scale <= 0");
00784 
00785         return scale * std::pow(-std::log(runif()), 1.0 / shape);
00786       }
00787 
00788       SCYTHE_RNGMETH_MATRIX(rweibull, double,
00789           SCYTHE_ARGSET(shape, scale), double shape, double scale);
00790 
00804       double
00805       richisq (double nu)
00806       {
00807         double report;
00808           
00809         // Check for allowable parameter
00810         SCYTHE_CHECK_10(nu <= 0, scythe_invalid_arg,
00811             "Degrees of freedom <= 0");
00812           
00813         // Return Inverse-Gamma(nu/2, 1/2) variate
00814         report = rigamma (nu / 2, .5);
00815         return (report);
00816       }
00817 
00818       SCYTHE_RNGMETH_MATRIX(richisq, double, nu, double nu);
00819 
00832       double
00833       rigamma (double alpha, double beta)
00834       {
00835         double report;
00836         
00837         // Check for allowable parameters
00838         SCYTHE_CHECK_10(alpha <= 0, scythe_invalid_arg, "alpha <= 0");
00839         SCYTHE_CHECK_10(beta <= 0, scythe_invalid_arg, "beta <= 0");
00840 
00841         // Return reciprocal of gamma variate
00842         report = std::pow (rgamma (alpha, beta), -1);
00843 
00844         return (report);
00845       }
00846 
00847       SCYTHE_RNGMETH_MATRIX(rigamma, double, SCYTHE_ARGSET(alpha, beta),
00848           double alpha, double beta);
00849 
00850       /* Truncated Distributions */
00851 
00874       double 
00875       rtnorm(double mean, double variance, double below, double above)
00876       {  
00877         SCYTHE_CHECK_10(below >= above, scythe_invalid_arg,
00878             "Truncation bound not logically consistent");
00879         SCYTHE_CHECK_10(variance <= 0, scythe_invalid_arg,
00880             "Variance <= 0");
00881         
00882         double sd = std::sqrt(variance);
00883         double FA = 0.0;
00884         double FB = 0.0;
00885         if ((std::fabs((above-mean)/sd) < 8.2) 
00886             && (std::fabs((below-mean)/sd) < 8.2)){
00887           FA = pnorm1((above-mean)/sd, true, false);
00888           FB = pnorm1((below-mean)/sd, true, false);
00889         }
00890         if ((((above-mean)/sd) < 8.2)  && (((below-mean)/sd) <= -8.2) ){ 
00891           FA = pnorm1((above-mean)/sd, true, false);
00892           FB = 0.0;
00893         }
00894         if ( (((above-mean)/sd) >= 8.2)  && (((below-mean)/sd) > -8.2) ){ 
00895           FA = 1.0;
00896           FB = pnorm1((below-mean)/sd, true, false);
00897         } 
00898         if ( (((above-mean)/sd) >= 8.2) && (((below-mean)/sd) <= -8.2)){
00899           FA = 1.0;
00900           FB = 0.0;
00901         }
00902         double term = runif()*(FA-FB)+FB;
00903         if (term < 5.6e-17)
00904           term = 5.6e-17;
00905         if (term > (1 - 5.6e-17))
00906           term = 1 - 5.6e-17;
00907         double draw = mean + sd * qnorm1(term);
00908         if (draw > above)
00909           draw = above;
00910         if (draw < below)
00911           draw = below;
00912          
00913         return draw;
00914       }
00915 
00916       SCYTHE_RNGMETH_MATRIX(rtnorm, double, 
00917           SCYTHE_ARGSET(mean, variance, above, below), double mean,
00918           double variance, double above, double below);
00919 
00944       double
00945       rtnorm_combo(double mean, double variance, double below, 
00946                    double above)
00947       {
00948         SCYTHE_CHECK_10(below >= above, scythe_invalid_arg,
00949             "Truncation bound not logically consistent");
00950         SCYTHE_CHECK_10(variance <= 0, scythe_invalid_arg,
00951             "Variance <= 0");
00952         
00953         double sd = std::sqrt(variance);
00954         if ((((above-mean)/sd > 0.5) && ((mean-below)/sd > 0.5))
00955             ||
00956             (((above-mean)/sd > 2.0) && ((below-mean)/sd < 0.25))
00957             ||
00958             (((mean-below)/sd > 2.0) && ((above-mean)/sd > -0.25))) { 
00959           double x = rnorm(mean, sd);
00960           while ((x > above) || (x < below))
00961             x = rnorm(mean,sd);
00962           return x;
00963         } else {
00964           // use the inverse cdf method
00965           double FA = 0.0;
00966           double FB = 0.0;
00967           if ((std::fabs((above-mean)/sd) < 8.2) 
00968               && (std::fabs((below-mean)/sd) < 8.2)){
00969             FA = pnorm1((above-mean)/sd, true, false);
00970             FB = pnorm1((below-mean)/sd, true, false);
00971           }
00972           if ((((above-mean)/sd) < 8.2)  && (((below-mean)/sd) <= -8.2) ){ 
00973             FA = pnorm1((above-mean)/sd, true, false);
00974             FB = 0.0;
00975           }
00976           if ( (((above-mean)/sd) >= 8.2)  && (((below-mean)/sd) > -8.2) ){ 
00977             FA = 1.0;
00978             FB = pnorm1((below-mean)/sd, true, false);
00979           } 
00980           if ( (((above-mean)/sd) >= 8.2) && (((below-mean)/sd) <= -8.2)){
00981             FA = 1.0;
00982             FB = 0.0;
00983           }
00984           double term = runif()*(FA-FB)+FB;
00985           if (term < 5.6e-17)
00986             term = 5.6e-17;
00987           if (term > (1 - 5.6e-17))
00988             term = 1 - 5.6e-17;
00989           double x = mean + sd * qnorm1(term);
00990           if (x > above)
00991             x = above;
00992           if (x < below)
00993             x = below;
00994           return x;
00995         }    
00996       }
00997 
00998       SCYTHE_RNGMETH_MATRIX(rtnorm_combo, double, 
00999           SCYTHE_ARGSET(mean, variance, above, below), double mean,
01000           double variance, double above, double below);
01001 
01024       double
01025       rtbnorm_slice (double mean, double variance, double below,
01026                      unsigned int iter = 10)
01027       {
01028         SCYTHE_CHECK_10(below < mean, scythe_invalid_arg,
01029             "Truncation point < mean");
01030         SCYTHE_CHECK_10(variance <= 0, scythe_invalid_arg,
01031             "Variance <= 0");
01032          
01033         double z = 0;
01034         double x = below + .00001;
01035          
01036         for (unsigned int i=0; i<iter; ++i){
01037           z = runif()*std::exp(-1*std::pow((x-mean),2)/(2*variance));
01038           x = runif()*
01039             ((mean + std::sqrt(-2*variance*std::log(z))) - below) + below;
01040         }
01041 
01042         if (! finite(x)) {
01043           SCYTHE_WARN("Mean extremely far from truncation point. "
01044               << "Returning truncation point");
01045           return below; 
01046         }
01047 
01048         return x;
01049       }
01050 
01051       SCYTHE_RNGMETH_MATRIX(rtbnorm_slice, double, 
01052           SCYTHE_ARGSET(mean, variance, below, iter), double mean, 
01053           double variance, double below, unsigned int iter = 10);
01054 
01077       double
01078       rtanorm_slice (double mean, double variance, double above, 
01079           unsigned int iter = 10)
01080       {
01081         SCYTHE_CHECK_10(above > mean, scythe_invalid_arg,
01082             "Truncation point > mean");
01083         SCYTHE_CHECK_10(variance <= 0, scythe_invalid_arg,
01084             "Variance <= 0");
01085       
01086         double below = -1*above;
01087         double newmu = -1*mean;
01088         double z = 0;
01089         double x = below + .00001;
01090          
01091         for (unsigned int i=0; i<iter; ++i){
01092           z = runif()*std::exp(-1*std::pow((x-newmu),2)
01093               /(2*variance));
01094           x = runif()
01095             *( (newmu + std::sqrt(-2*variance*std::log(z))) - below) 
01096             + below;
01097         }
01098         if (! finite(x)) {
01099           SCYTHE_WARN("Mean extremely far from truncation point. "
01100               << "Returning truncation point");
01101           return above; 
01102         }
01103         
01104         return -1*x;
01105       }
01106 
01107       SCYTHE_RNGMETH_MATRIX(rtanorm_slice, double, 
01108           SCYTHE_ARGSET(mean, variance, above, iter), double mean, 
01109           double variance, double above, unsigned int iter = 10);
01110 
01136       double
01137       rtbnorm_combo (double mean, double variance, double below, 
01138           unsigned int iter = 10)
01139       {
01140         SCYTHE_CHECK_10(variance <= 0, scythe_invalid_arg,
01141             "Variance <= 0");
01142         
01143         double s = std::sqrt(variance);
01144         // do rejection sampling and return value
01145         //if (m >= below){
01146         if ((mean/s - below/s ) > -0.5){
01147           double x = rnorm(mean, s);
01148           while (x < below)
01149             x = rnorm(mean,s);
01150           return x; 
01151         } else if ((mean/s - below/s ) > -5.0 ){
01152           // use the inverse cdf method
01153           double above =  std::numeric_limits<double>::infinity();
01154           double x = rtnorm(mean, variance, below, above);
01155           return x;
01156         } else {
01157           // do slice sampling and return value
01158           double z = 0;
01159           double x = below + .00001;
01160           for (unsigned int i=0; i<iter; ++i){
01161             z = runif() * std::exp(-1 * std::pow((x - mean), 2)
01162                 / (2 * variance));
01163             x = runif() 
01164               * ((mean + std::sqrt(-2 * variance * std::log(z))) 
01165                 - below) + below;
01166           }
01167           if (! finite(x)) {
01168             SCYTHE_WARN("Mean extremely far from truncation point. "
01169                 << "Returning truncation point");
01170             return below; 
01171           }
01172           return x;
01173         }
01174       }
01175 
01176       SCYTHE_RNGMETH_MATRIX(rtbnorm_combo, double, 
01177           SCYTHE_ARGSET(mean, variance, below, iter), double mean, 
01178           double variance, double below, unsigned int iter = 10);
01179 
01204       double
01205       rtanorm_combo (double mean, double variance, double above, 
01206           const unsigned int iter = 10)
01207       {
01208         SCYTHE_CHECK_10(variance <= 0, scythe_invalid_arg,
01209             "Variance <= 0");
01210 
01211         double s = std::sqrt(variance);
01212         // do rejection sampling and return value
01213         if ((mean/s - above/s ) < 0.5){ 
01214           double x = rnorm(mean, s);
01215           while (x > above)
01216             x = rnorm(mean,s);
01217           return x;
01218         } else if ((mean/s - above/s ) < 5.0 ){
01219           // use the inverse cdf method
01220           double below =  -std::numeric_limits<double>::infinity();
01221           double x = rtnorm(mean, variance, below, above);
01222           return x;
01223         } else {
01224           // do slice sampling and return value
01225           double below = -1*above;
01226           double newmu = -1*mean;
01227           double z = 0;
01228           double x = below + .00001;
01229              
01230           for (unsigned int i=0; i<iter; ++i){
01231             z = runif() * std::exp(-1 * std::pow((x-newmu), 2)
01232                 /(2 * variance));
01233             x = runif() 
01234               * ((newmu + std::sqrt(-2 * variance * std::log(z)))
01235                   - below) + below;
01236           }
01237           if (! finite(x)) {
01238             SCYTHE_WARN("Mean extremely far from truncation point. "
01239                 << "Returning truncation point");
01240             return above; 
01241           }
01242           return -1*x;
01243         }
01244       }
01245 
01246       SCYTHE_RNGMETH_MATRIX(rtanorm_combo, double, 
01247           SCYTHE_ARGSET(mean, variance, above, iter), double mean, 
01248           double variance, double above, unsigned int iter = 10);
01249 
01250       /* Multivariate Distributions */
01251       
01264       template <matrix_order O, matrix_style S>
01265       Matrix<double, O, Concrete>
01266       rwish(unsigned int v, const Matrix<double, O, S> &Sigma)
01267       {
01268         SCYTHE_CHECK_10(! Sigma.isSquare(), scythe_dimension_error,
01269             "Sigma not square");
01270         SCYTHE_CHECK_10(v < Sigma.rows(), scythe_invalid_arg, 
01271             "v < Sigma.rows()");
01272           
01273         Matrix<double,O,Concrete> 
01274           A(Sigma.rows(), Sigma.rows());
01275         Matrix<double,O,Concrete> C = cholesky<O,Concrete>(Sigma);
01276         Matrix<double,O,Concrete> alpha;
01277           
01278         for (unsigned int i = 0; i < v; ++i) {
01279           alpha = C * rnorm(Sigma.rows(), 1, 0, 1);
01280           A += (alpha * (t(alpha)));
01281         }
01282 
01283         return A;
01284       }
01285 
01297       template <matrix_order O, matrix_style S>
01298       Matrix<double, O, Concrete>
01299       rdirich(const Matrix<double, O, S>& alpha) 
01300       { 
01301         // Check for allowable parameters
01302         SCYTHE_CHECK_10(std::min(alpha) <= 0, scythe_invalid_arg,
01303             "alpha has elements < 0");
01304         SCYTHE_CHECK_10(! alpha.isColVector(), scythe_dimension_error,
01305             "alpha not column vector");
01306      
01307         Matrix<double, O, Concrete> y(alpha.rows(), 1);
01308         double ysum = 0;
01309 
01310         // We would use std::transform here but rgamma is a function
01311         // and wouldn't get inlined.
01312         const_matrix_forward_iterator<double,O,O,S> ait;
01313         const_matrix_forward_iterator<double,O,O,S> alast
01314           = alpha.template end_f();
01315         typename Matrix<double,O,Concrete>::forward_iterator yit 
01316           = y.begin_f();
01317         for (ait = alpha.begin_f(); ait != alast; ++ait) {
01318           *yit = rgamma(*ait, 1);
01319           ysum += *yit;
01320           ++yit;
01321         }
01322 
01323         y /= ysum;
01324 
01325         return y;
01326       }
01327 
01341       template <matrix_order PO1, matrix_style PS1,
01342                 matrix_order PO2, matrix_style PS2>
01343       Matrix<double, PO1, Concrete>
01344       rmvnorm(const Matrix<double, PO1, PS1>& mu, 
01345               const Matrix<double, PO2, PS2>& sigma)
01346       {  
01347         unsigned int dim = mu.rows();
01348         SCYTHE_CHECK_10(! mu.isColVector(), scythe_dimension_error,
01349             "mu not column vector");
01350         SCYTHE_CHECK_10(! sigma.isSquare(), scythe_dimension_error,
01351             "sigma not square");
01352         SCYTHE_CHECK_10(sigma.rows() != dim, scythe_conformation_error,
01353             "mu and sigma not conformable");
01354         
01355         return(mu + cholesky(sigma) * rnorm(dim, 1, 0, 1));
01356       }
01357 
01372       template <matrix_order O, matrix_style S>
01373       Matrix<double, O, Concrete>
01374       rmvt (const Matrix<double, O, S>& sigma, double nu)
01375       {
01376         Matrix<double, O, Concrete> result;
01377         SCYTHE_CHECK_10(nu <= 0, scythe_invalid_arg,
01378             "D.O.F parameter nu <= 0");
01379 
01380         result = 
01381           rmvnorm(Matrix<double, O>(sigma.rows(), 1, true, 0), sigma);
01382         result /= std::sqrt(rchisq(nu) / nu);
01383         return result;
01384       }
01385 
01386     protected:
01387       /* Default (and only) constructor */
01392       rng() 
01393         : rnorm_count_ (1) // Initialize the normal counter
01394       {}
01395 
01396       /* For Barton and Nackman trick. */
01397       RNGTYPE& as_derived()
01398       {
01399         return static_cast<RNGTYPE&>(*this);
01400       }
01401 
01402 
01403       /* Generate Standard Normal variates */
01404 
01405       /* These instance variables were static in the old
01406        * implementation.  Making them instance variables provides
01407        * thread safety, as long as two threads don't access the same
01408        * rng at the same time w/out precautions.  Fixes possible
01409        * previous issues with lecuyer.  See the similar approach in
01410        * rgamma1 below.
01411        */
01412       int rnorm_count_;
01413       double x2_;
01414 
01415       double
01416       rnorm1 ()
01417       {
01418         double nu1, nu2, rsquared, sqrt_term;
01419         if (rnorm_count_ == 1){ // odd numbered passses
01420           do {
01421             nu1 = -1 +2*runif();
01422             nu2 = -1 +2*runif();
01423             rsquared = ::pow(nu1,2) + ::pow(nu2,2);
01424           } while (rsquared >= 1 || rsquared == 0.0);
01425           sqrt_term = std::sqrt(-2*std::log(rsquared)/rsquared);
01426           x2_ = nu2*sqrt_term;
01427           rnorm_count_ = 2;
01428           return nu1*sqrt_term;
01429         } else { // even numbered passes
01430           rnorm_count_ = 1;
01431           return x2_;
01432         } 
01433       }
01434 
01435       /* Generate standard gamma variates */
01436       double accept_;
01437 
01438       double
01439       rgamma1 (double alpha)
01440       {
01441         int test;
01442         double u, v, w, x, y, z, b, c;
01443 
01444         // Check for allowable parameters
01445         SCYTHE_CHECK_10(alpha <= 1, scythe_invalid_arg, "alpha <= 1");
01446 
01447         // Implement Best's (1978) simulator
01448         b = alpha - 1;
01449         c = 3 * alpha - 0.75;
01450         test = 0;
01451         while (test == 0) {
01452           u = runif ();
01453           v = runif ();
01454 
01455           w = u * (1 - u);
01456           y = std::sqrt (c / w) * (u - .5);
01457           x = b + y;
01458 
01459           if (x > 0) {
01460             z = 64 * std::pow (v, 2) * std::pow (w, 3);
01461             if (z <= (1 - (2 * std::pow (y, 2) / x))) {
01462               test = 1;
01463               accept_ = x;
01464             } else if ((2 * (b * std::log (x / b) - y)) >= ::log (z)) {
01465               test = 1;
01466               accept_ = x;
01467             } else {
01468               test = 0;
01469             }
01470           }
01471         }
01472         
01473         return (accept_);
01474       }
01475 
01476   };
01477 
01478   
01479 } // end namespace scythe    
01480 #endif /* RNG_H */